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
Constant Summary collapse
- REQUEST_CHALLENGE =
0
- REQUEST_INFO =
1
- REQUEST_PLAYER =
2
- REQUEST_RULES =
3
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
-
#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`
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/steam/servers/game_server.rb', line 37 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`
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/steam/servers/game_server.rb', line 57 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.
199 200 201 202 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 199 def handle_response_for_request(request_type, repeat_on_failure = true) begin case request_type when GameServer::REQUEST_CHALLENGE then request_packet = A2S_SERVERQUERY_GETCHALLENGE_Packet.new expected_response = S2C_CHALLENGE_Packet when GameServer::REQUEST_INFO then request_packet = A2S_INFO_Packet.new expected_response = S2A_INFO_BasePacket when GameServer::REQUEST_PLAYER then request_packet = A2S_PLAYER_Packet.new(@challenge_number) expected_response = S2A_PLAYER_Packet when GameServer::REQUEST_RULES then request_packet = A2S_RULES_Packet.new(@challenge_number) expected_response = S2A_RULES_Packet else raise SteamCondenserException.new("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_hash 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 SteamCondenserException.new("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 rescue TimeoutException puts "Expected #{expected_response}, but timed out." if $DEBUG 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
91 92 93 |
# File 'lib/steam/servers/game_server.rb', line 91 def initialize(address, port = 27015) super 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.
105 106 107 108 |
# File 'lib/steam/servers/game_server.rb', line 105 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.
124 125 126 127 |
# File 'lib/steam/servers/game_server.rb', line 124 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
136 137 |
# File 'lib/steam/servers/game_server.rb', line 136 def rcon_auth(password) end |
#rcon_authenticated? ⇒ Boolean
139 140 141 |
# File 'lib/steam/servers/game_server.rb', line 139 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
150 151 |
# File 'lib/steam/servers/game_server.rb', line 150 def rcon_exec(command) 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.
165 166 167 168 |
# File 'lib/steam/servers/game_server.rb', line 165 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.
182 183 184 185 |
# File 'lib/steam/servers/game_server.rb', line 182 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
344 345 346 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 |
# File 'lib/steam/servers/game_server.rb', line 344 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.
320 321 322 |
# File 'lib/steam/servers/game_server.rb', line 320 def update_challenge_number handle_response_for_request GameServer::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.
332 333 334 335 336 337 338 |
# File 'lib/steam/servers/game_server.rb', line 332 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 |
# File 'lib/steam/servers/game_server.rb', line 265 def update_players(rcon_password = nil) handle_response_for_request GameServer::REQUEST_PLAYER unless rcon_password.nil? || @player_hash.nil? || @player_hash.empty? rcon_auth rcon_password 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) if @player_hash.key? player_data[:name] @player_hash[player_data[:name]].add_info player_data end 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.
294 295 296 |
# File 'lib/steam/servers/game_server.rb', line 294 def update_rules handle_response_for_request GameServer::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.
307 308 309 |
# File 'lib/steam/servers/game_server.rb', line 307 def update_server_info handle_response_for_request GameServer::REQUEST_INFO end |