Module: Manufactured::RJR

Includes:
Manufactured, Omega, Omega::Server::DSL
Defined in:
lib/manufactured/rjr/stop.rb,
lib/manufactured/rjr/get.rb,
lib/manufactured/rjr/dock.rb,
lib/manufactured/rjr/init.rb,
lib/manufactured/rjr/loot.rb,
lib/manufactured/rjr/move.rb,
lib/manufactured/rjr/state.rb,
lib/manufactured/rjr/create.rb,
lib/manufactured/rjr/attack.rb,
lib/manufactured/rjr/mining.rb,
lib/manufactured/rjr/follow.rb,
lib/manufactured/rjr/inspect.rb,
lib/manufactured/rjr/resources.rb,
lib/manufactured/rjr/subscribe_to.rb,
lib/manufactured/rjr/remove_callbacks.rb,
lib/manufactured/rjr/move/ship_in_system.rb,
lib/manufactured/rjr/subscribe_to/helpers.rb,
lib/manufactured/rjr/move/entity_in_system.rb,
lib/manufactured/rjr/move/station_in_system.rb,
lib/manufactured/rjr/subscribe_to/entity_events.rb,
lib/manufactured/rjr/move/entity_between_systems.rb,
lib/manufactured/rjr/subscribe_to/subsystem_events.rb

Overview

manufactured::subscribe_to entity_event helpers

Copyright (C) 2013-2014 Mohammed Morsi <[email protected]> Licensed under the AGPLv3+ www.gnu.org/licenses/agpl.txt

Constant Summary collapse

GET_METHODS =
{ :get_entities => get_entities }
STOP_METHODS =
{:stop_entity => stop_entity}
DOCK_METHODS =
{ :dock   => dock,
:undock => undock }
PRIVILEGES =

Manufactured::RJR data

[['view',   'cosmos_entities'],
['modify', 'cosmos_entities'],
['view',   'users'          ],
['view',   'user_attributes'],
['modify', 'user_attributes'],
['create', 'locations'      ],
['view',   'locations'      ],
['modify', 'locations'      ],
['delete', 'locations'      ],
['create', 'manufactured_entities']]
CALLBACK_METHODS =
{ :motel_event => motel_event }
LOOT_METHODS =
{ :collect_loot   => collect_loot }
MOVE_METHODS =
{:move_entity => move_entity}
STATE_METHODS =
{ :save_state    => save_state,
:restore_state => restore_state }
CREATE_METHODS =
{ :validate_user_attributes  => validate_user_attributes,
:create_entity    => create_entity,
:construct_entity => construct_entity }
ATTACK_METHODS =
{ :attack_entity   => attack_entity }
MINING_METHODS =
{ :start_mining   => start_mining }
FOLLOW_METHODS =
{:follow_entity => follow_entity}
INSPECT_METHODS =
{ :get_cmd => get_cmd,
:get_status => get_status }
RESOURCES_METHODS =
{ :add_resource      => add_resource,
:transfer_resource => transfer_resource}
SUBSCRIBE_TO_METHODS =
{:subscribe_to => subscribe_to}
REMOVE_CALLBACKS_METHODS =
{:remove_callbacks => remove_callbacks}

Config options collapse

Config options collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Omega::Server::DSL

#check_attribute, #check_privilege, #cosmos_entity?, #current_session, #current_user, #delete_event_handler_for, #filter_properties, #filters_from_args, #from_valid_source?, #handle_node_closed, #in_subsystem, #is_cmd?, #is_node?, #login, #matching, #persistent_transport?, #remove_callbacks_for, #require_attribute, #require_persistent_transport!, #require_privilege, #require_state, #require_valid_source!, #subsystem, #subsystem_entity?, #subsystem_event?, #validate_session_source!, #with, #with_id

Class Attribute Details

.manufactured_rjr_passwordObject

Password to use to communicate w/ other modules over the local rjr node


28
29
30
# File 'lib/manufactured/rjr/init.rb', line 28

def manufactured_rjr_password
  @manufactured_rjr_password
end

.manufactured_rjr_usernameObject

User to use to communicate w/ other modules over the local rjr node


25
26
27
# File 'lib/manufactured/rjr/init.rb', line 25

def manufactured_rjr_username
  @manufactured_rjr_username
end

Class Method Details

.nodeObject


76
77
78
# File 'lib/manufactured/rjr/init.rb', line 76

def self.node
  @node ||= ::RJR::Nodes::Local.new :node_id => self.user.id
end

.registryObject


92
93
94
# File 'lib/manufactured/rjr/init.rb', line 92

def self.registry
  @registry ||= Manufactured::Registry.new
end

.resetObject


100
101
102
# File 'lib/manufactured/rjr/init.rb', line 100

def self.reset
  Manufactured::RJR.registry.clear!
end

.set_config(config) ⇒ Object

Set config options using Omega::Config instance

Parameters:


33
34
35
36
# File 'lib/manufactured/rjr/init.rb', line 33

def set_config(config)
  self.manufactured_rjr_username  = config.manufactured_rjr_user
  self.manufactured_rjr_password  = config.manufactured_rjr_pass
end

.userObject


66
67
68
69
70
# File 'lib/manufactured/rjr/init.rb', line 66

def self.user
  @user ||= Users::User.new(:id       => Manufactured::RJR::manufactured_rjr_username,
                            :password => Manufactured::RJR::manufactured_rjr_password,
                            :registration_code => nil)
end

.user_registryObject


84
85
86
# File 'lib/manufactured/rjr/init.rb', line 84

def self.user_registry
  Users::RJR.registry
end

Instance Method Details

#move_entity_between_systems(entity, sys) ⇒ Object

Move an entity between systems


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/manufactured/rjr/move/entity_between_systems.rb', line 12

def move_entity_between_systems(entity, sys)

  # if moving ship ensure
  # - a jump gate within trigger distance is nearby
  # - ship is not docked
  #
  # (TODO optional transport delay / jump time)
  # (TODO optional skipping this check if user has sufficient
  #       privs modify-manufactured_entities ?)
  if entity.is_a?(Manufactured::Ship)
    near_jg =
      !entity.solar_system.jump_gates.find { |jg|
        jg.endpoint_id == sys.id &&
        (jg.location - entity.location) < jg.trigger_distance
       }.nil?
    raise OperationError, "#{entity} not by jump gate" unless near_jg
    raise OperationError, "#{entity} docked"           if entity.docked?
  end

  # set parent and location
  # TODO set loc x, y, z to vicinity of reverse jump gate
  #       (gate to current system in destination system) if it exists ?
  orig_parent = entity.parent
  entity.parent = sys
  entity.location.movement_strategy =
    Motel::MovementStrategies::Stopped.instance

  # update location and remove movement callbacks
  node.invoke('motel::update_location',  entity.location)
  node.invoke('motel::remove_callbacks', entity.location.id, 'movement')
  node.invoke('motel::remove_callbacks', entity.location.id, 'rotation')

  if !sys.proxy_to.nil?
    proxy = Omega::Server::ProxyNode.with_id(sys.proxy_to).

    # TODO invoke users::get with_id entity.user_id &
    # if not present users::create_user ?
    # or perhaps err out ('user not authorized to jump to remote system')?

    proxy.invoke 'manufactured::create_entity', entity

    # XXX remove entity from local registry
    registry.delete &with_id(entity.id)
    node.invoke('motel::delete_location', entity.location.id)

    # also remove related privs
    user_role = "user_role_#{entity.user_id}"
    owner_permissions_for(entity).each { |p,e|
      node.invoke('users::remove_privilege', user_role, p, e)
    }

  else
    # update registry entity
    registry.update entity, &with_id(entity.id)
  end

  # run new system_jump event in registry
  event = Manufactured::Events::SystemJump.new :old_system => orig_parent,
                                               :entity => entity
  registry << event

  nil
end

#move_entity_in_system(entity, loc) ⇒ Object

Move entity in single system


11
12
13
14
# File 'lib/manufactured/rjr/move/entity_in_system.rb', line 11

def move_entity_in_system(entity, loc)
  entity.is_a?(Ship) ?    move_ship_in_system(entity, loc) :
                       move_station_in_system(entity, loc)
end

#move_ship_in_system(entity, loc) ⇒ Object

Move a ship in a single system

Raises:


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/manufactured/rjr/move/ship_in_system.rb', line 8

def move_ship_in_system(entity, loc)
  # TODO may want to incorporate fuel into this at some point

  # verify we are processing ships here, also ensure not docked
  raise OperationError, "#{entity} not ship" unless entity.is_a?(Ship)
  raise OperationError, "#{entity} docked"   unless !entity.docked?

  # calculate distance to move along each access
  dx = loc.x - entity.location.x
  dy = loc.y - entity.location.y
  dz = loc.z - entity.location.z
  distance = loc - entity.location
  raise OperationError, "#{entity} at location" if distance < 1

  # Create linear movement strategy w/ movement trajectory
  linear =
    Motel::MovementStrategies::Linear.new :dx => dx/distance,
                                          :dy => dy/distance,
                                          :dz => dz/distance,
                                          :speed => entity.movement_speed

  # calculate the orientation difference
  od = entity.location.orientation_difference(*loc.coordinates)

  # TODO introduce point_to_target flag in Linear movement strategy
  # (similar to Follow) & use here, removing the need for the follow distinction

  # if we are close enough to correct orientation,
  # register linear movement strategy with entity
  if od.first.abs < (Math::PI / 32)
    entity.location.movement_strategy = linear

  # if we need to adjust orientation before moving,
  # register rotation movement strategy w/ entity
  else
    # create the rotation movement strategy
    rotate =
      Motel::MovementStrategies::Rotate.new \
        :rot_theta => (od[0] * entity.rotation_speed),
        :rot_x     =>  od[1],
        :rot_y     =>  od[2],
        :rot_z     =>  od[3]

    # register rotation w/ location, linear as next movement strategy
    entity.location.movement_strategy = rotate
    entity.location.next_movement_strategy = linear

    # track location rotation
    node.invoke('motel::track_rotation', entity.location.id, *od)
  end

  # track location movement and update location
  node.invoke('motel::track_movement', entity.location.id, distance)
  node.invoke('motel::update_location', entity.location)
  nil
end

#move_station_in_system(station, loc) ⇒ Object

Move station in single system

Raises:


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/manufactured/rjr/move/station_in_system.rb', line 8

def move_station_in_system(station, loc)
  # Verify we are processing stations here
  raise OperationError, "#{station} not a station" unless station.is_a?(Station)

  # When moving station, we only permit orbiting around system's star
  is_orbiting = loc.ms.is_a?(Motel::MovementStrategies::Elliptical)
  on_orbit    = is_orbiting ? loc.ms.intersects?(loc) : false
  raise OperationError, "#{station} must orbit star" unless is_orbiting
  raise OperationError,
    "station location #{station.location.coords} not on orbit" unless on_orbit

  # update movement strategy
  station.location.movement_strategy = loc.ms
  node.invoke('motel::update_location', station.location)

  # TODO update dock'd ship movement strategies?

  nil
end

#nodeObject


80
81
82
# File 'lib/manufactured/rjr/init.rb', line 80

def node
  Manufactured::RJR.node
end

#owner_permissions_for(entity) ⇒ Object

Helper method to generate the permissions granted to the owner of a manufactured entity upon creation


57
58
59
60
61
62
63
64
# File 'lib/manufactured/rjr/init.rb', line 57

def owner_permissions_for(entity)
  entity_id   = entity.id
  location_id = entity.location.id

  [["view",   "manufactured_entity-#{entity_id}"],
   ['modify', "manufactured_entity-#{entity_id}"],
   ['view',            "location-#{location_id}"]]
end

#registryObject


96
97
98
# File 'lib/manufactured/rjr/init.rb', line 96

def registry
  Manufactured::RJR.registry
end

#subscribable_entity?(entity) ⇒ Boolean

Bool indicating if user can subscribe to events on specified entity

Returns:

  • (Boolean)

8
9
10
# File 'lib/manufactured/rjr/subscribe_to/helpers.rb', line 8

def subscribable_entity?(entity)
  subsystem_entity?(entity) && !entity.is_a?(Loot)
end

#subscribe_to_entity_event(entity_id, event_type, endpoint_id) ⇒ Object


7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/manufactured/rjr/subscribe_to/entity_events.rb', line 7

def subscribe_to_entity_event(entity_id, event_type, endpoint_id)
  cb = Omega::Server::Callback.new :event_type  => event_type,
                                   :endpoint_id => endpoint_id,
                                   :rjr_event => 'manufactured::event_occurred'
  cb.handler = proc { |entity, *args|
    err = false

    begin
      # ensure user has access to view entity
      require_privilege :registry => user_registry, :any =>
        [{:privilege => 'view', :entity => "manufactured_entity-#{entity.id}"},
         {:privilege => 'view', :entity => 'manufactured_entities'}]

      # invoke method via rjr callback notification
      #
      # args does not include event/entity at this point, just simply has any
      # remaining event arguments
      #
      # XXX args transformation between server callbacks being
      # invoked (in manufactured::commands) and here is somewhat
      # convoluted, would be nice to simplify
      @rjr_callback.notify 'manufactured::event_occurred', event_type, entity, *args

    rescue Omega::PermissionError => e
      ::RJR::Logger.warn "entity #{entity.id} callback permission error #{e}"
      err = true

    rescue Omega::ConnectionError => e
      ::RJR::Logger.warn "entity #{entity.id} client disconnected #{e}"
      err = true
      # also entity.callbacks associated w/ @rjr_headers['session_id'] ?

    rescue Exception => e
      ::RJR::Logger.warn "exception during #{entity.id} callback #{e} #{e.backtrace}"
      err = true

    ensure
      remove_callbacks_for entity, :type     => event_type,
                                   :endpoint => endpoint_id   if err
    end
  }

  registry.safe_exec { |entities|
    rentity = entities.find &with_id(entity_id)

    # important need to atomically delete callbacks w/ same endpoint_id:
    remove_callbacks_for entities, :class    => rentity.class,
                                   :id       => rentity.id,
                                   :type     => cb.event_type,
                                   :endpoint => cb.endpoint_id
    rentity.callbacks << cb
  }

  nil
end

#subscribe_to_subsystem_event(event_type, endpoint_id, *event_args) ⇒ Object


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/manufactured/rjr/subscribe_to/subsystem_events.rb', line 10

def subscribe_to_subsystem_event(event_type, endpoint_id, *event_args)
  handler = Manufactured::EventHandler.new :event_type  => event_type,
                                           :endpoint_id => endpoint_id,
                                           :event_args  => event_args,
                                           :persist     => true
  handler.exec do |manu_event|
    err,err_msg = false,nil
    begin
      # run through event args, running permission
      # checks on restricted entities
      # XXX hacky, would be nice to do this in a more structured manner
      manu_event.event_args.each { |arg|
        if subsystem_entity?(arg)
          require_privilege :registry  => user_registry, :any =>
            [{:privilege => 'view', :entity => "manufactured_entity-#{arg.id}"},
             {:privilege => 'view', :entity => 'manufactured_entities'}]
        elsif cosmos_entity?(arg)
          require_privilege :registry  => user_registry, :any =>
            [{:privilege => 'view', :entity => "cosmos_entity-#{arg.id}"},
             {:privilege => 'view', :entity => 'cosmos_entities'}]
        elsif arg.is_a?(Motel::Location)
          require_privilege :registry  => user_registry, :any =>
            [{:privilege => 'view', :entity => "location-#{arg.id}"},
             {:privilege => 'view', :entity => 'locations'}] if arg.restrict_view
        end
      }

      @rjr_callback.notify 'manufactured::event_occurred',
                            event_type, *manu_event.event_args

    rescue Omega::PermissionError => e
          err = true
      err_msg = "manufactured event #{event_type} " \
                "handler permission error #{e}"

    rescue Omega::ConnectionError => e
          err = true
      err_msg = "manufactured event #{event_type} " \
                "client disconnected #{e}"

    rescue Exception => e
          err = true
      err_msg = "exception during manufactured #{event_type} " \
                "callback #{e} #{e.backtrace}"

    ensure
      if err
        ::RJR::Logger.warn err_msg
        delete_event_handler_for(:event_type  => event_type,
                                 :endpoint_id => endpoint_id,
                                 :registry    => registry)
      end
    end
  end

  # registry event handler checks ensures endpoint/event_type uniqueness
  registry << handler

  nil
end

#userObject


72
73
74
# File 'lib/manufactured/rjr/init.rb', line 72

def user
  Manufactured::RJR.user
end

#user_registryObject


88
89
90
# File 'lib/manufactured/rjr/init.rb', line 88

def user_registry
  Manufactured::RJR.user_registry
end

#validate_user_attributes(entities, entity) ⇒ Object

helper to validate use attributes upon entity creation


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/manufactured/rjr/create.rb', line 15

def validate_user_attributes(entities, entity)
  # only applies to ships / stations
  # TODO skip this requirement if entity belongs to a npc user
  if entity.is_a?(Ship) || entity.is_a?(Station)
    # retrieve alive entities belonging to user
    n = entities.count { |e| (e.is_a?(Ship) || e.is_a?(Station)) &&
                              e.user_id == entity.user_id        &&
                            (!e.is_a?(Ship) || e.alive?)            }

    require_attribute :node => Manufactured::RJR.node,
      :user_id => entity.user_id,
      :attribute_id => Users::Attributes::EntityManagementLevel.id,
      :level => n+1

    # TODO also ensure user has attribute enabling them to
    # create entity of the specified type
  end
end