Class: RuneRb::System::Controller

Inherits:
Object
  • Object
show all
Includes:
Log, Singleton
Defined in:
app/system/controller.rb

Overview

Handles the launching, processing, and shutdown of RuneRb::Network::Endpoints and RuneRb::Game::World::Instance objects.

Since:

  • 0.9.3

Instance Method Summary collapse

Methods included from Log

#class_name, #err, #err!, #log, #log!, #symbolize_file

Constructor Details

#initializeController

Constructs a new Controller object

Since:

  • 0.9.3


37
38
39
40
41
42
43
# File 'app/system/controller.rb', line 37

def initialize
  @sessions = []
  @worlds = []
  @endpoints = []
  @start = { time: Process.clock_gettime(Process::CLOCK_MONOTONIC), stamp: Time.now }
  load_configs
end

Instance Method Details

#aboutObject

Logs information about the controller and it's assets.

Since:

  • 0.9.3


127
128
129
130
131
132
# File 'app/system/controller.rb', line 127

def about
  log! RuneRb::GLOBAL[:COLOR].green("[Endpoints]: #{@endpoints.length}")
  log! RuneRb::GLOBAL[:COLOR].green("[Worlds]: #{@worlds.length}")
  log! RuneRb::GLOBAL[:COLOR].green("[Endpoints]: #{@endpoints.each(&:inspect)}")
  log! RuneRb::GLOBAL[:COLOR].green("[Worlds]: #{@worlds.each(&:inspect)}")
end

#deploy_endpointObject

Deploys a single endpoint instance

Since:

  • 0.9.3


102
103
104
105
106
# File 'app/system/controller.rb', line 102

def deploy_endpoint
  sig = EventMachine.start_server(@configs[:endpoint][:HOST], @configs[:endpoint][:PORT], RuneRb::Network::Session) { |session| @sessions << session }
  @endpoints << sig
  sig
end

#deploy_worldObject

Deploys a single world

Since:

  • 0.9.3


95
96
97
98
99
# File 'app/system/controller.rb', line 95

def deploy_world
  inst = RuneRb::Game::World::Instance.new(@configs[:world])
  @worlds << inst
  inst
end

#load_configsObject

Deserializes and attempts to parse configuration files located in `assets/config`.

Since:

  • 0.9.3


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/system/controller.rb', line 135

def load_configs
  raw_ep_data = Oj.safe_load(File.read('assets/config/endpoint.json'))
  raw_world_data = Oj.safe_load(File.read('assets/config/world.json'))

  @configs = {}.tap do |hash|
    hash[:world] = {}
    hash[:world][:label] = raw_world_data['LABEL'] || "WORLD_" + Druuid.gen
    hash[:world][:max_players] = raw_world_data['MAX_PLAYERS'].to_i
    hash[:world][:max_mobs] = raw_world_data['MAX_MOBS'].to_i
    hash[:world][:default_mob_x] = raw_world_data['DEFAULT_MOB_X'].to_i
    hash[:world][:default_mob_y] = raw_world_data['DEFAULT_MOB_Y'].to_i
    hash[:world][:default_mob_z] = raw_world_data['DEFAULT_MOB_Z'].to_i
    hash[:world][:private?] = raw_world_data['PRIVATE'] ? true : false

    hash[:endpoint] = {}
    hash[:endpoint][:HOST] = raw_ep_data['HOST']
    hash[:endpoint][:PORT] = raw_ep_data['PORT']
  end
  log! "Loaded configuration."
rescue StandardError => e
  err "An error occurred while loading config files.", e, e.backtrace.join("\n")
end

#run(&block) ⇒ Object

Launches the controller, deploying world insstances and endpoint instances within the EventMachine reactor.

Since:

  • 0.9.3


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'app/system/controller.rb', line 46

def run(&block)
  EventMachine.run do
    # TODO: read more into what can be done while in trap context
    Signal.trap('INT') { shutdown }

    # Deploy world instances
    deploy_world

    # Deploy an endpoint to accept sessions
    deploy_endpoint

    # Construct tick loop to process sessions
    setup_session_loop

    block.call if block_given?

    log RuneRb::GLOBAL[:COLOR].green.bold('Controller ready!')
  end
end

#setup_session_loopObject

Each tick this function ensures sessions whose <status> is equal to `:PENDING_WORLD` are logged into the next available world instance which can accept the player. This function also disconnects any lingering sessions which are no longer active.

Since:

  • 0.9.3


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'app/system/controller.rb', line 109

def setup_session_loop
  EventMachine.tick_loop do
    transfer_batch = @sessions.select { |session| session.status[:auth] == :PENDING_WORLD }
    destination = @worlds.detect { |world| world.entities[:players].length + transfer_batch.length <= world.settings[:max_players] }

    unless destination.nil?
      transfer_batch.each do |session|
        session.status[:auth] = :TRANSFERRING
        destination.receive(session)
      end
    end

    inactive_batch = @sessions.select { |session| session.status[:active] == false || session.status[:active].nil? }
    inactive_batch.each { |session| @sessions.delete(session) }
  end
end

#shutdown(params = {}) ⇒ Object

Closes endpoints, shuts down worlds and stops the EventMachine reactor.

Since:

  • 0.9.3


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/system/controller.rb', line 67

def shutdown(params = {})
  case params[:type]
  when :WORLD
    results = @worlds.select { |world| world.settings[:LABEL] = params[:label] || params[:title] }
    results.each(&:shutdown)
    log "Shutdown #{results.size} world instance(s)!"
  when :SERVER
    if @endpoints.include?(params[:sig])
      EventMachine.stop_server(params[:sig])
      log "Shutdown server with signature: #{params[:sig]}!"
    else
      err "Could not locate server with signature: #{params[:sig]}!"
    end
  else
    begin
      @endpoints.each { |ep| EventMachine.stop_server(ep) }
      @worlds.each(&:shutdown)
    rescue StandardError => e
      puts "An error occurred during shutdown!"
      puts e
      puts e.backtrace.join("\n")
    ensure
      EventMachine.stop
    end
  end
end