Module: GameServer
- Includes:
- Server
- Included in:
- GoldSrcServer, SourceServer
- Defined in:
- lib/steam/servers/game_server.rb
Overview
This module is included by classes representing different game server implementations and provides the basic functionality to communicate with them using the common query protocol
Instance Attribute Summary
Attributes included from Server
Class Method Summary collapse
-
.player_status_attributes(status_header) ⇒ Array<Symbol>
Parses the player attribute names supplied by ‘rcon status`.
-
.split_player_status(attributes, player_status) ⇒ Hash<Symbol, String>
Splits the player status obtained with ‘rcon status`.
Instance Method Summary collapse
-
#handle_response_for_request(request_type, repeat_on_failure = true) ⇒ Object
Sends the specified request to the server and handles the returned response.
-
#init ⇒ Object
Initializes this server object with basic information.
-
#initialize(address, port = 27015) ⇒ Object
Creates a new instance of a game server object.
-
#ping ⇒ Fixnum
Returns the last measured response time of this server.
-
#players(rcon_password = nil) ⇒ Hash
Returns a list of players currently playing on this server.
-
#rcon_auth(password) ⇒ Boolean
abstract
Authenticates the connection for RCON communication with the server.
-
#rcon_authenticated? ⇒ Boolean
Returns whether the RCON connection to this server is already authenticated.
-
#rcon_exec(command) ⇒ String
abstract
Remotely executes a command on the server via RCON.
-
#rules ⇒ Hash<String, String>
Returns the settings applied on the server.
-
#server_info ⇒ Hash
Returns a hash with basic information on the server.
-
#to_s ⇒ String
Returns a human-readable text representation of the server.
-
#update_challenge_number ⇒ Object
Sends a A2S_SERVERQUERY_GETCHALLENGE request to the server and updates the challenge number used to communicate with this server.
-
#update_ping ⇒ Fixnum
Sends a A2S_INFO request to the server and measures the time needed for the reply.
-
#update_players(rcon_password = nil) ⇒ Object
Sends a A2S_PLAYERS request to the server and updates the players’ data for this server.
-
#update_rules ⇒ Object
Sends a A2S_RULES request to the server and updates the rules of this server.
-
#update_server_info ⇒ Object
Sends a A2S_INFO request to the server and updates this server’s basic information.
Methods included from Server
Class Method Details
.player_status_attributes(status_header) ⇒ Array<Symbol>
Parses the player attribute names supplied by ‘rcon status`
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/steam/servers/game_server.rb', line 33 def self.player_status_attributes(status_header) status_header.split.map do |attribute| case attribute when 'connected' :time when 'frag' :score else attribute.to_sym end end end |
.split_player_status(attributes, player_status) ⇒ Hash<Symbol, String>
Splits the player status obtained with ‘rcon status`
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/steam/servers/game_server.rb', line 53 def self.split_player_status(attributes, player_status) player_status.sub! /^\d+ +/, '' if attributes.first != :userid first_quote = player_status.index '"' last_quote = player_status.rindex '"' data = [ player_status[0, first_quote], player_status[first_quote + 1..last_quote - 1], player_status[last_quote + 1..-1] ] data = [ data[0].split, data[1], data[2].split ] data.flatten! if attributes.size > data.size && attributes.include?(:state) data.insert 3, nil, nil, nil elsif attributes.size < data.size data.delete_at 1 end player_data = {} data.each_index do |i| player_data[attributes[i]] = data[i] end player_data end |
Instance Method Details
#handle_response_for_request(request_type, repeat_on_failure = true) ⇒ Object
Sends the specified request to the server and handles the returned response
Depending on the given request type this will fill the various data attributes of the server object.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/steam/servers/game_server.rb', line 203 def handle_response_for_request(request_type, repeat_on_failure = true) case request_type when :challenge then request_packet = A2S_PLAYER_Packet.new expected_response = S2C_CHALLENGE_Packet when :info then request_packet = A2S_INFO_Packet.new expected_response = S2A_INFO_BasePacket when :players then request_packet = A2S_PLAYER_Packet.new(@challenge_number) expected_response = S2A_PLAYER_Packet when :rules then request_packet = A2S_RULES_Packet.new(@challenge_number) expected_response = S2A_RULES_Packet else raise SteamCondenserError, 'Called with wrong request type.' end send_request request_packet response_packet = reply if response_packet.kind_of? S2A_INFO_BasePacket @info_hash = response_packet.info elsif response_packet.kind_of? S2A_PLAYER_Packet @player_hash = response_packet.player_hash elsif response_packet.kind_of? S2A_RULES_Packet @rules_hash = response_packet.rules_hash elsif response_packet.kind_of? S2C_CHALLENGE_Packet @challenge_number = response_packet.challenge_number else raise SteamCondenserError, "Response of type #{response_packet.class} cannot be handled by this method." end unless response_packet.kind_of? expected_response puts "Expected #{expected_response}, got #{response_packet.class}." if $DEBUG handle_response_for_request(request_type, false) if repeat_on_failure end end |
#init ⇒ Object
Initializes this server object with basic information
247 248 249 250 251 |
# File 'lib/steam/servers/game_server.rb', line 247 def init update_ping update_server_info update_challenge_number end |
#initialize(address, port = 27015) ⇒ Object
Creates a new instance of a game server object
87 88 89 90 91 |
# File 'lib/steam/servers/game_server.rb', line 87 def initialize(address, port = 27015) super @rcon_authenticated = false end |
#ping ⇒ Fixnum
Returns the last measured response time of this server
If the latency hasn’t been measured yet, it is done when calling this method for the first time.
If this information is vital to you, be sure to call #update_ping regularly to stay up-to-date.
103 104 105 106 |
# File 'lib/steam/servers/game_server.rb', line 103 def ping update_ping if @ping.nil? @ping end |
#players(rcon_password = nil) ⇒ Hash
Returns a list of players currently playing on this server
If the players haven’t been fetched yet, it is done when calling this method for the first time.
As the players and their scores change quite often be sure to update this list regularly by calling #update_players if you rely on this information.
122 123 124 125 |
# File 'lib/steam/servers/game_server.rb', line 122 def players(rcon_password = nil) update_players(rcon_password) if @player_hash.nil? @player_hash end |
#rcon_auth(password) ⇒ Boolean
Must be be implemented by including classes to handle the authentication
Authenticates the connection for RCON communication with the server
134 135 136 |
# File 'lib/steam/servers/game_server.rb', line 134 def rcon_auth(password) raise NotImplementedError end |
#rcon_authenticated? ⇒ Boolean
Returns whether the RCON connection to this server is already authenticated
142 143 144 |
# File 'lib/steam/servers/game_server.rb', line 142 def rcon_authenticated? @rcon_authenticated end |
#rcon_exec(command) ⇒ String
Must be be implemented by including classes to handle the command execution
Remotely executes a command on the server via RCON
153 154 155 |
# File 'lib/steam/servers/game_server.rb', line 153 def rcon_exec(command) raise NotImplementedError end |
#rules ⇒ Hash<String, String>
Returns the settings applied on the server. These settings are also called rules.
If the rules haven’t been fetched yet, it is done when calling this method for the first time.
As the rules usually don’t change often, there’s almost no need to update this hash. But if you need to, you can achieve this by calling #update_rules.
169 170 171 172 |
# File 'lib/steam/servers/game_server.rb', line 169 def rules update_rules if @rules_hash.nil? @rules_hash end |
#server_info ⇒ Hash
Returns a hash with basic information on the server.
If the server information haven’t been fetched yet, it is done when calling this method for the first time.
The server information usually only changes on map change and when players join or leave. As the latter changes can be monitored by calling #update_players, there’s no need to call #update_server_info very often.
186 187 188 189 |
# File 'lib/steam/servers/game_server.rb', line 186 def server_info update_server_info if @info_hash.nil? @info_hash end |
#to_s ⇒ String
Returns a human-readable text representation of the server
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/steam/servers/game_server.rb', line 347 def to_s return_string = '' return_string << "Ping: #@ping\n" return_string << "Challenge number: #@challenge_number\n" unless @info_hash.nil? return_string << "Info:\n" @info_hash.each do |key, value| return_string << " #{key}: #{value.inspect}\n" end end unless @player_hash.nil? return_string << "Players:\n" @player_hash.each_value do |player| return_string << " #{player}\n" end end unless @rules_hash.nil? return_string << "Rules:\n" @rules_hash.each do |key, value| return_string << " #{key}: #{value}\n" end end return_string end |
#update_challenge_number ⇒ Object
Sends a A2S_SERVERQUERY_GETCHALLENGE request to the server and updates the challenge number used to communicate with this server
There’s usually no need to call this method explicitly, because #handle_response_for_request will automatically get the challenge number when the server assigns a new one.
323 324 325 |
# File 'lib/steam/servers/game_server.rb', line 323 def update_challenge_number handle_response_for_request :challenge end |
#update_ping ⇒ Fixnum
Sends a A2S_INFO request to the server and measures the time needed for the reply
If this information is vital to you, be sure to call this method regularly to stay up-to-date.
335 336 337 338 339 340 341 |
# File 'lib/steam/servers/game_server.rb', line 335 def update_ping send_request A2S_INFO_Packet.new start_time = Time.now reply end_time = Time.now @ping = (end_time - start_time) * 1000 end |
#update_players(rcon_password = nil) ⇒ Object
Sends a A2S_PLAYERS request to the server and updates the players’ data for this server
As the players and their scores change quite often be sure to update this list regularly by calling this method if you rely on this information.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/steam/servers/game_server.rb', line 265 def update_players(rcon_password = nil) handle_response_for_request :players unless @rcon_authenticated return if rcon_password.nil? rcon_auth rcon_password end players = rcon_exec('status').lines.select do |line| line.start_with?('#') && line != "#end\n" end.map do |line| line[1..-1].strip end attributes = GameServer.player_status_attributes players.shift players.each do |player| player_data = GameServer.split_player_status(attributes, player) player_name = player_data[:name] if @player_hash.key? player_name @player_hash[player_name].add_info player_data end end end |
#update_rules ⇒ Object
Sends a A2S_RULES request to the server and updates the rules of this server
As the rules usually don’t change often, there’s almost no need to update this hash. But if you need to, you can achieve this by calling this method.
297 298 299 |
# File 'lib/steam/servers/game_server.rb', line 297 def update_rules handle_response_for_request :rules end |
#update_server_info ⇒ Object
Sends a A2S_INFO request to the server and updates this server’s basic information
The server information usually only changes on map change and when players join or leave. As the latter changes can be monitored by calling #update_players, there’s no need to call this method very often.
310 311 312 |
# File 'lib/steam/servers/game_server.rb', line 310 def update_server_info handle_response_for_request :info end |