-
Notifications
You must be signed in to change notification settings - Fork 10
Extending
Omega may be extended / adapted to fit many purposes in various different ways. The following are some extension points which users / developers can leverage to customize Omega for their own needs.
The Omega JSON-RPC methods are defined in the rjr subdir in each subsystem. Usually each file here will correspond to one or more rjr methods that serve a particular bit of functionality which may be invoked by authenticated users over a configured transport.
Each subsystem loads its JSON-RPC methods via its rjr/init.rb module, which is responsible for requireing the modules in the rjr directory and invoking the relevant init methods, adding the json-rpc method callbacks to the dispatcher.
To add a json-rpc method 'motel::custom' to the motel subsystem for example, create the lib/motel/rjr/custom.rb file with the following contents:
require 'motel/rjr/init'
module Motel::RJR
custom = proc { |*args|
# do something
nil
}
CUSTOM_METHODS = { :custom => custom}
end
def dispatch_motel_rjr_custom(dispatcher)
m = Motel::RJR::CUSTOM_METHODS
dispatcher.handle 'motel::custom', &m[:get_location]
end
Then extend the dispatch_motel_rjr_init method in lib/motel/rjr/init.rb to include:
dispatcher.add_module('motel/rjr/custom')
And you should be good to go, next time you start up the server motel::custom will be defined w/ your custom logic and available via the Omega JSON-RPC interface.
To define a new subsystem create a new subdir w/ your logic under the 'lib' directory of the project. The register it by adding the following call to bin/omega-server
multi_node.dispatcher.add_module('subsystem/rjr/init')
From there clients can be written / expanded to invoke methods against this new subsystem.
Movement Strategies reside in the lib/motel/movement_strategies directory and are picked up by the motel subsystem when registered with locations in order to move those locations.
Developers may define a subclass Motel::MovementStrategy to implement their own custom movement, calling out to any custom backend or physics engine if desired.
require 'motel/movement_strategy'
module Motel
module MovementStrategies
class Custom < MovementStrategy
# validate movement strategy, return result
def valid?
true
end
# return bool indicating if we should change movement strategy
def change?(loc)
false
end
# move location
def move(loc, elapsed_seconds)
end
# convert movement strategy to json
def to_json(*a)
end
end
end
end
After this the developer should add a require to the new movement strategy in lib/omega.rb
require 'motel/movement_strategies/custom'
See the other movement strategies already in place for more details.
The user can pass any data to/from an Omega server that is serializable to/from JSON. The current Omega entities implement this by utilizing the Ruby json gem, defining 'to_json' generator methods on the entity classes, and accepting parameters from the json representation in class intializers.
As developers extend operations and subsystems as indicated above they may find need to extend these classes with new attributes and/or add new classes to represent new entities/concepts.
Missions are comprised of series of server side callbacks invoked on various events / states in the mission lifecycle. These callbacks need to be defined ahead of time at server startup so that missions can reference them on creation.
To add new mission callbacks, extend the module in lib/missions/dsl corresponding to the callback you are trying to create.
Mission callbacks can be defined for
- requirements - callback result indicates if user can accept mission
- assignment - run when mission is assigned
- events / event handlers - run specific sequences on subsystem and entity related events
- query - mechanisms to query for information from other callbacks
- resolution - run when missions are completed / failed
For example, the following Resolution callback would give the new user an item (a new ship) on mission completion. This should be added to the Resolution module in lib/missions/dsl/resolution.rb
def self.add_item(ship)
proc { |mission|
ship.id = Motel.gen_uuid
ship.user_id = mission.assigned_to_id
node.invoke('manufactured::create', ship)
}
end
Note the Missions DSL callbacks are invoked on mission creation but create procs invoked at the appropriate time during the mission lifecycle with the mission itself as a parameter (and others where appropriate).
The missions subsystem itself is subject to the same role base access control all Omega users are when contacting other subsystems, albeit the missions user role can be granted extended privileges to fulfill its operations.
See user roles below for more info
The Missions subsystem exposes hooks through which various operations can be run on server side subsystem and entity-specific events. Like the Missions DSL callbacks (see above) the hook callbacks need to be defined ahead of time on the server side so that they may be referenced by the end user.
See the missions::add_hook rjr method (lib/missions/rjr/hooks.rb) and the examples/hooks.rb script for more details.
The Stats subsystem defines a static registry of simulation stastics which any user w/ the appropriate privileges may access.
To extend this registry extend lib/stats/registry.rb to include the necessary logic cross-referencing and filtering out data from the various subsystems.
By default permissions on stats are fairly liberal, they can be consumed by anonymous users for a multitude of purposes.
The 'bin/util/omega-monitor.rb' util provides a mechanism to include plugable unit tests into the reporting interface to diagnose a running simulation.
To utilitze define a custom module with a 'run_tests' method which should take a single 'data' param containing the simulation data.
Run any custom validators and return an array of hash objects each containing
- success - bool indicating success (true) or failure (false)
- entity - entity which was tested by the particular test
- message - result message
def run_tests(data)
result = data.users.size > 0
message = result ? "test passed" : "test failed - simulation does not have users"
[{:success => result, :entity => data.user, :message => message}]
end
Pass the path to this module as the only param onto omega-monitor, eg
ruby -Ilib ./bin/util/omega-monitor.rb ./custom-tests.rb
See bin/util/omega-monitor.rb and examples/bot_tests.rb for more info.
Authentication is handled by the users subsystem, specifically
- The users::login rjr method (lib/users/rjr/session.rb) invokes Users::User#valid_login? (lib/users/user.rb)
- This in return invokes PasswordHelper#check which validates the user's password
- This may be overridden to validate against any custom backend
Upon validation the users subsystem creates and returns a new session via the 'create_session' operation in the User Registry (lib/users/registry.rb). The end user will need to set the 'session-id' attribute in the json of each json-rpc request from there on out authenticating the remainder of their operations.
From there on out, all authorization requests will be processed via require_privilege and check_privilege in the users registry against the session id received. These in return call dispatch to User#has_privilege? and User#has_privilege_on? (lib/users/user.rb) which may be extended / overridden to authorize the user against any backend (ldap, etc)
The admin may modify the default users / roles assignment by editing lib/omega/roles.rb
Additional users/roles/privs may be created before hand via the omega.yml config file (see Config documentation for more details)
Javascript representations of entities and overall interaction may be modified / extended via the Omega Web Frontend found in the site directory.
The web frontend aim to be as lightweight / modular as possible, querying an Omega node in real time for simulation data and periodically syncing / rendering the results.
Each entity's visual representation can be found in the site/source/javascripts/omega// directory and is broken up into indivual components and effects which are rendered in the WebGL scene at the appropriate time.
Many of the visual and audio properties of the components can be modified in the site/source/javascripts/config.js config file. The components themselves are preloaded/initialized ahead of time as well as on a per-entity basis via 'gfx.js' modules in each component directory (load_gfx and init_gfx operations respectively).
To modify the visual representation of any entity or the workflow / interaction of the web frontend the developer should look to extended / customizing these modules to render the intended appearance