steam-condenser 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +2 -0
- data/Rakefile +0 -2
- data/VERSION.yml +1 -1
- data/lib/abstract_class.rb +1 -3
- data/lib/exceptions/buffer_underflow_exception.rb +1 -3
- data/lib/exceptions/packet_format_exception.rb +1 -3
- data/lib/exceptions/rcon_no_auth_exception.rb +1 -3
- data/lib/exceptions/timeout_exception.rb +0 -2
- data/lib/steam/community/game_stats.rb +5 -3
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +143 -0
- data/lib/steam/community/l4d/abstract_l4d_weapon.rb +26 -0
- data/lib/steam/community/l4d/l4d2_map.rb +65 -0
- data/lib/steam/community/l4d/l4d2_stats.rb +125 -0
- data/lib/steam/community/l4d/l4d2_weapon.rb +21 -0
- data/lib/steam/community/l4d/l4d_map.rb +2 -0
- data/lib/steam/community/l4d/l4d_stats.rb +5 -115
- data/lib/steam/community/l4d/l4d_weapon.rb +3 -7
- data/lib/steam/community/steam_id.rb +28 -19
- data/lib/steam/community/tf2/tf2_class_factory.rb +1 -3
- data/lib/steam/community/tf2/tf2_engineer.rb +2 -4
- data/lib/steam/community/tf2/tf2_medic.rb +1 -3
- data/lib/steam/community/tf2/tf2_sniper.rb +1 -3
- data/lib/steam/community/tf2/tf2_spy.rb +1 -3
- data/lib/steam/packets/a2a_ack_packet.rb +1 -3
- data/lib/steam/packets/a2a_ping_packet.rb +1 -3
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +0 -2
- data/lib/steam/packets/a2s_info_packet.rb +0 -2
- data/lib/steam/packets/a2s_player_packet.rb +1 -3
- data/lib/steam/packets/a2s_rules_packet.rb +1 -3
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +1 -3
- data/lib/steam/packets/m2a_server_batch_packet.rb +1 -3
- data/lib/steam/packets/rcon/rcon_auth_request.rb +1 -3
- data/lib/steam/packets/rcon/rcon_auth_response.rb +1 -3
- data/lib/steam/packets/rcon/rcon_exec_request.rb +1 -3
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +1 -3
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +1 -3
- data/lib/steam/packets/rcon/rcon_packet.rb +1 -3
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +1 -3
- data/lib/steam/packets/request_with_challenge.rb +1 -3
- data/lib/steam/packets/s2a_info2_packet.rb +1 -3
- data/lib/steam/packets/s2a_info_base_packet.rb +2 -0
- data/lib/steam/packets/s2a_rules_packet.rb +1 -1
- data/lib/steam/packets/s2c_challenge_packet.rb +1 -3
- data/lib/steam/packets/steam_packet.rb +15 -16
- data/lib/steam/servers/master_server.rb +0 -2
- data/lib/steam/servers/source_server.rb +3 -1
- data/lib/steam-condenser.rb +2 -0
- metadata +21 -19
@@ -3,69 +3,17 @@
|
|
3
3
|
#
|
4
4
|
# Copyright (c) 2009, Sebastian Staudt
|
5
5
|
|
6
|
-
require 'steam/community/
|
6
|
+
require 'steam/community/l4d/abstract_l4d_stats'
|
7
7
|
require 'steam/community/l4d/l4d_explosive'
|
8
8
|
require 'steam/community/l4d/l4d_map'
|
9
9
|
require 'steam/community/l4d/l4d_weapon'
|
10
10
|
|
11
|
-
class L4DStats <
|
12
|
-
|
13
|
-
attr_reader :xml_data
|
11
|
+
class L4DStats < AbstractL4DStats
|
14
12
|
|
15
13
|
# Creates a L4DStats object by calling the super constructor with the game
|
16
|
-
# name "l4d"
|
14
|
+
# name "l4d".
|
17
15
|
def initialize(steam_id)
|
18
16
|
super steam_id, 'l4d'
|
19
|
-
|
20
|
-
if public?
|
21
|
-
@most_recent_game = {}
|
22
|
-
@most_recent_game['difficulty'] = @xml_data.elements['stats/mostrecentgame/difficulty'].text
|
23
|
-
@most_recent_game['escaped'] = (@xml_data.elements['stats/mostrecentgame/bEscaped'].text == 1)
|
24
|
-
@most_recent_game['movie'] = @xml_data.elements['stats/mostrecentgame/movie'].text
|
25
|
-
@most_recent_game['time_played'] = @xml_data.elements['stats/mostrecentgame/time'].text
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns a Hash of favorites for this user like weapons and character.
|
30
|
-
# If the favorites haven't been parsed already, parsing is done now.
|
31
|
-
def favorites
|
32
|
-
return unless public?
|
33
|
-
|
34
|
-
if @favorites.nil?
|
35
|
-
@favorites = {}
|
36
|
-
@favorites['campaign'] = @xml_data.elements['stats/favorites/campaign'].text
|
37
|
-
@favorites['campaign_percentage'] = @xml_data.elements['stats/favorites/campaignpct'].text.to_i
|
38
|
-
@favorites['character'] = @xml_data.elements['stats/favorites/character'].text
|
39
|
-
@favorites['character_percentage'] = @xml_data.elements['stats/favorites/characterpct'].text.to_i
|
40
|
-
@favorites['level1_weapon'] = @xml_data.elements['stats/favorites/weapon1'].text
|
41
|
-
@favorites['level1_weapon_percentage'] = @xml_data.elements['stats/favorites/weapon1pct'].text.to_i
|
42
|
-
@favorites['level2_weapon'] = @xml_data.elements['stats/favorites/weapon2'].text
|
43
|
-
@favorites['level2_weapon_percentage'] = @xml_data.elements['stats/favorites/weapon2pct'].text.to_i
|
44
|
-
end
|
45
|
-
|
46
|
-
@favorites
|
47
|
-
end
|
48
|
-
|
49
|
-
# Returns a Hash of lifetime statistics for this user like the time played.
|
50
|
-
# If the lifetime statistics haven't been parsed already, parsing is done now.
|
51
|
-
def lifetime_stats
|
52
|
-
return unless public?
|
53
|
-
|
54
|
-
if @lifetime_stats.nil?
|
55
|
-
@lifetime_stats = {}
|
56
|
-
@lifetime_stats['finales_survived'] = @xml_data.elements['stats/lifetime/finales'].text.to_i
|
57
|
-
@lifetime_stats['games_played'] = @xml_data.elements['stats/lifetime/gamesplayed'].text.to_i
|
58
|
-
@lifetime_stats['finales_survived_percentage'] = @lifetime_stats['finales_survived'].to_f / @lifetime_stats['games_played']
|
59
|
-
@lifetime_stats['infected_killed'] = @xml_data.elements['stats/lifetime/infectedkilled'].text.to_i
|
60
|
-
@lifetime_stats['kills_per_hour'] = @xml_data.elements['stats/lifetime/killsperhour'].text.to_f
|
61
|
-
@lifetime_stats['avg_kits_shared'] = @xml_data.elements['stats/lifetime/kitsshared'].text.to_f
|
62
|
-
@lifetime_stats['avg_kits_used'] = @xml_data.elements['stats/lifetime/kitsused'].text.to_f
|
63
|
-
@lifetime_stats['avg_pills_shared'] = @xml_data.elements['stats/lifetime/pillsshared'].text.to_f
|
64
|
-
@lifetime_stats['avg_pills_used'] = @xml_data.elements['stats/lifetime/pillsused'].text.to_f
|
65
|
-
@lifetime_stats['time_played'] = @xml_data.elements['stats/lifetime/timeplayed'].text
|
66
|
-
end
|
67
|
-
|
68
|
-
@lifetime_stats
|
69
17
|
end
|
70
18
|
|
71
19
|
# Returns a Hash of Survival statistics for this user like revived teammates.
|
@@ -74,13 +22,7 @@ class L4DStats < GameStats
|
|
74
22
|
return unless public?
|
75
23
|
|
76
24
|
if @survival_stats.nil?
|
77
|
-
|
78
|
-
@survival_stats['gold_medals'] = @xml_data.elements['stats/survival/goldmedals'].text.to_i
|
79
|
-
@survival_stats['silver_medals'] = @xml_data.elements['stats/survival/silvermedals'].text.to_i
|
80
|
-
@survival_stats['bronze_medals'] = @xml_data.elements['stats/survival/bronzemedals'].text.to_i
|
81
|
-
@survival_stats['rounds_played'] = @xml_data.elements['stats/survival/roundsplayed'].text.to_i
|
82
|
-
@survival_stats['best_time'] = @xml_data.elements['stats/survival/besttime'].text.to_f
|
83
|
-
|
25
|
+
super
|
84
26
|
@survival_stats['maps'] = {}
|
85
27
|
@xml_data.elements.each('stats/survival/maps/*') do |map_data|
|
86
28
|
@survival_stats['maps'][map_data.name] = L4DMap.new(map_data)
|
@@ -90,58 +32,6 @@ class L4DStats < GameStats
|
|
90
32
|
@survival_stats
|
91
33
|
end
|
92
34
|
|
93
|
-
# Returns a Hash of teamplay statistics for this user like revived teammates.
|
94
|
-
# If the teamplay statistics haven't been parsed already, parsing is done now.
|
95
|
-
def teamplay_stats
|
96
|
-
return unless public?
|
97
|
-
|
98
|
-
if @teamplay_stats.nil?
|
99
|
-
@teamplay_stats = {}
|
100
|
-
@teamplay_stats['revived'] = @xml_data.elements['stats/teamplay/revived'].text.to_i
|
101
|
-
@teamplay_stats['most_revived_difficulty'] = @xml_data.elements['stats/teamplay/reviveddiff'].text
|
102
|
-
@teamplay_stats['avg_revived'] = @xml_data.elements['stats/teamplay/revivedavg'].text.to_f
|
103
|
-
@teamplay_stats['avg_was_revived'] = @xml_data.elements['stats/teamplay/wasrevivedavg'].text.to_f
|
104
|
-
@teamplay_stats['protected'] = @xml_data.elements['stats/teamplay/protected'].text.to_i
|
105
|
-
@teamplay_stats['most_protected_difficulty'] = @xml_data.elements['stats/teamplay/protecteddiff'].text
|
106
|
-
@teamplay_stats['avg_protected'] = @xml_data.elements['stats/teamplay/protectedavg'].text.to_f
|
107
|
-
@teamplay_stats['avg_was_protected'] = @xml_data.elements['stats/teamplay/wasprotectedavg'].text.to_f
|
108
|
-
@teamplay_stats['friendly_fire_damage'] = @xml_data.elements['stats/teamplay/ffdamage'].text.to_i
|
109
|
-
@teamplay_stats['most_friendly_fire_difficulty'] = @xml_data.elements['stats/teamplay/ffdamagediff'].text
|
110
|
-
@teamplay_stats['avg_friendly_fire_damage'] = @xml_data.elements['stats/teamplay/ffdamageavg'].text.to_f
|
111
|
-
end
|
112
|
-
|
113
|
-
@teamplay_stats
|
114
|
-
end
|
115
|
-
|
116
|
-
# Returns a Hash of Versus statistics for this user like percentage of rounds
|
117
|
-
# won.
|
118
|
-
# If the Versus statistics haven't been parsed already, parsing is done now.
|
119
|
-
def versus_stats
|
120
|
-
return unless public?
|
121
|
-
|
122
|
-
if @versus_stats.nil?
|
123
|
-
@versus_stats = {}
|
124
|
-
@versus_stats['games_played'] = @xml_data.elements['stats/versus/gamesplayed'].text.to_i
|
125
|
-
@versus_stats['games_completed'] = @xml_data.elements['stats/versus/gamescompleted'].text.to_i
|
126
|
-
@versus_stats['finales_survived'] = @xml_data.elements['stats/versus/finales'].text.to_i
|
127
|
-
@versus_stats['finales_survived_percentage'] = @versus_stats['finales_survived'].to_f / @versus_stats['games_played']
|
128
|
-
@versus_stats['points'] = @xml_data.elements['stats/versus/points'].text.to_i
|
129
|
-
@versus_stats['most_points_infected'] = @xml_data.elements['stats/versus/pointsas'].text
|
130
|
-
@versus_stats['games_won'] = @xml_data.elements['stats/versus/gameswon'].text.to_i
|
131
|
-
@versus_stats['games_lost'] = @xml_data.elements['stats/versus/gameslost'].text.to_i
|
132
|
-
@versus_stats['highest_survivor_score'] = @xml_data.elements['stats/versus/survivorscore'].text.to_i
|
133
|
-
|
134
|
-
%w(boomer hunter smoker tank).each do |infected|
|
135
|
-
@versus_stats[infected] = {}
|
136
|
-
@versus_stats[infected]['special'] = @xml_data.elements["stats/versus/#{infected}special"].text.to_i
|
137
|
-
@versus_stats[infected]['most_damage'] = @xml_data.elements["stats/versus/#{infected}dmg"].text.to_i
|
138
|
-
@versus_stats[infected]['avg_lifespan'] = @xml_data.elements["stats/versus/#{infected}lifespan"].text.to_i
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
@versus_stats
|
143
|
-
end
|
144
|
-
|
145
35
|
# Returns a Hash of L4DWeapon for this user containing all Left4Dead weapons.
|
146
36
|
# If the weapons haven't been parsed already, parsing is done now.
|
147
37
|
def weapon_stats
|
@@ -150,7 +40,7 @@ class L4DStats < GameStats
|
|
150
40
|
if @weapon_stats.nil?
|
151
41
|
@weapon_stats = {}
|
152
42
|
@xml_data.elements.each('stats/weapons/*') do |weapon_data|
|
153
|
-
unless
|
43
|
+
unless %w{molotov pipes}.include? weapon_data.name
|
154
44
|
weapon = L4DWeapon.new(weapon_data)
|
155
45
|
else
|
156
46
|
weapon = L4DExplosive.new(weapon_data)
|
@@ -3,9 +3,9 @@
|
|
3
3
|
#
|
4
4
|
# Copyright (c) 2009, Sebastian Staudt
|
5
5
|
|
6
|
-
require 'steam/community/
|
6
|
+
require 'steam/community/l4d/abstract_l4d_weapon'
|
7
7
|
|
8
|
-
class L4DWeapon <
|
8
|
+
class L4DWeapon < AbstractL4DWeapon
|
9
9
|
|
10
10
|
attr_reader :accuracy, :headshots_percentage, :kill_percentage
|
11
11
|
|
@@ -13,11 +13,7 @@ class L4DWeapon < GameWeapon
|
|
13
13
|
def initialize(weapon_data)
|
14
14
|
super weapon_data
|
15
15
|
|
16
|
-
@
|
17
|
-
@headshots_percentage = weapon_data.elements['headshots'].text
|
18
|
-
@id = weapon_data.name
|
19
|
-
@kill_percentage = weapon_data.elements['killpct'].text
|
20
|
-
@shots = weapon_data.elements['shots'].text.to_i
|
16
|
+
@kill_percentage = weapon_data.elements['killpct'].text
|
21
17
|
end
|
22
18
|
|
23
19
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'open-uri'
|
7
7
|
require 'rexml/document'
|
@@ -23,6 +23,21 @@ class SteamId
|
|
23
23
|
:real_name, :state_message, :steam_id64, :steam_rating,
|
24
24
|
:steam_rating_text, :summary, :vac_banned, :visibility_state
|
25
25
|
|
26
|
+
# Converts the 64bit SteamID +community_id+ as used and reported by the Steam
|
27
|
+
# Community to a SteamID reported by game servers
|
28
|
+
def self.convert_community_id_to_steam_id(community_id)
|
29
|
+
steam_id1 = community_id % 2
|
30
|
+
steam_id2 = community_id - 76561197960265728
|
31
|
+
|
32
|
+
unless steam_id2 > 0
|
33
|
+
raise SteamCondenserException.new("SteamID #{community_id} is too small.")
|
34
|
+
end
|
35
|
+
|
36
|
+
steam_id2 = (steam_id2 - steam_id1) / 2
|
37
|
+
|
38
|
+
"STEAM_0:#{steam_id1}:#{steam_id2}"
|
39
|
+
end
|
40
|
+
|
26
41
|
# Converts the SteamID +steam_id+ as reported by game servers to a 64bit
|
27
42
|
# SteamID
|
28
43
|
def self.convert_steam_id_to_community_id(steam_id)
|
@@ -79,6 +94,10 @@ class SteamId
|
|
79
94
|
raise SteamCondenserException.new(profile.elements['error'].text)
|
80
95
|
end
|
81
96
|
|
97
|
+
unless REXML::XPath.first(profile, 'privacyMessage').nil?
|
98
|
+
raise SteamCondenserException.new(profile.elements['privacyMessage'].text)
|
99
|
+
end
|
100
|
+
|
82
101
|
@image_url = profile.elements['avatarIcon'].text[0..-5]
|
83
102
|
@online_state = profile.elements['onlineState'].text
|
84
103
|
@privacy_state = profile.elements['privacyState'].text
|
@@ -91,6 +110,7 @@ class SteamId
|
|
91
110
|
# Only public profiles can be scanned for further information
|
92
111
|
if @privacy_state == 'public'
|
93
112
|
@custom_url = profile.elements['customURL'].text.downcase
|
113
|
+
@custom_url = nil if @custom_url.empty?
|
94
114
|
|
95
115
|
# The favorite game cannot be set since 10/10/2008, but old profiles
|
96
116
|
# still have this. May be removed in a future version.
|
@@ -147,28 +167,17 @@ class SteamId
|
|
147
167
|
|
148
168
|
# Fetches the games this user owns
|
149
169
|
def fetch_games
|
150
|
-
|
151
|
-
require 'hpricot'
|
152
|
-
|
153
|
-
url = "#{base_url}/games"
|
170
|
+
url = "#{base_url}/games?xml=1"
|
154
171
|
|
155
172
|
@games = {}
|
156
|
-
games_data =
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
stats = game.next_sibling
|
161
|
-
if stats.name == 'br'
|
173
|
+
games_data = REXML::Document.new(open(url, {:proxy => true}).read).root
|
174
|
+
games_data.elements.each('games/game') do |game|
|
175
|
+
game_name = game.elements['name'].text
|
176
|
+
if game.elements['globalStatsLink'].nil?
|
162
177
|
@games[game_name] = false
|
163
178
|
else
|
164
|
-
|
165
|
-
|
166
|
-
@games[game_name] = false
|
167
|
-
else
|
168
|
-
stats = stats.siblings_at(2)[0]
|
169
|
-
friendly_name = stats['href'].match(/http:\/\/steamcommunity.com\/stats\/([0-9a-zA-Z:]+)\/achievements\//)[1]
|
170
|
-
@games[game_name] = friendly_name.downcase
|
171
|
-
end
|
179
|
+
friendly_name = game.elements['globalStatsLink'].text.match(/http:\/\/steamcommunity.com\/stats\/([0-9a-zA-Z:]+)\/achievements\//)[1]
|
180
|
+
@games[game_name] = friendly_name.downcase
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "abstract_class"
|
9
7
|
require "steam/community/tf2/tf2_class"
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/community/tf2/tf2_class"
|
9
7
|
|
10
8
|
# Represents the stats for the Team Fortress 2 engineer class for a specific
|
11
9
|
# user
|
12
10
|
class TF2Engineer < TF2Class
|
13
|
-
|
11
|
+
|
14
12
|
attr_reader :max_buildings_built, :max_teleports, :max_sentry_kills
|
15
13
|
|
16
14
|
# Creates a new instance of TF2Engineer based on the assigned XML data
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/community/tf2/tf2_class"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/community/tf2/tf2_class"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/community/tf2/tf2_class"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/request_with_challenge"
|
9
7
|
require "steam/packets/steam_packet"
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/request_with_challenge"
|
9
7
|
require "steam/packets/steam_packet"
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/rcon/rcon_packet"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/rcon/rcon_packet"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/rcon/rcon_packet"
|
9
7
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "abstract_class"
|
9
7
|
require "steam/packets/steam_packet"
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "abstract_class"
|
9
7
|
require "byte_buffer"
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
# This module implements a to_s method for request packets which send a challenge number
|
9
7
|
module RequestWithChallenge
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2009, Sebastian Staudt
|
7
5
|
|
8
6
|
require "steam/packets/s2a_info_base_packet"
|
9
7
|
|
@@ -1,48 +1,47 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under the
|
2
2
|
# terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008, Sebastian Staudt
|
5
|
-
#
|
6
|
-
# $Id$
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
7
5
|
|
8
6
|
# This class represents a packet used by the Source query protocol
|
9
7
|
class SteamPacket
|
10
|
-
|
11
|
-
A2S_INFO_HEADER = 0x54
|
12
|
-
S2A_INFO2_HEADER = 0x49
|
13
|
-
A2A_PING_HEADER = 0x69
|
8
|
+
|
14
9
|
A2A_ACK_HEADER = 0x6A
|
10
|
+
A2A_PING_HEADER = 0x69
|
11
|
+
A2M_GET_SERVERS_BATCH2_HEADER = 0x31
|
12
|
+
A2S_INFO_HEADER = 0x54
|
15
13
|
A2S_PLAYER_HEADER = 0x55
|
16
|
-
S2A_PLAYER_HEADER = 0x44
|
17
14
|
A2S_RULES_HEADER = 0x56
|
18
|
-
S2A_RULES_HEADER = 0x45
|
19
15
|
A2S_SERVERQUERY_GETCHALLENGE_HEADER = 0x57
|
20
|
-
S2C_CHALLENGE_HEADER = 0x41
|
21
|
-
A2M_GET_SERVERS_BATCH2_HEADER = 0x31
|
22
16
|
M2A_SERVER_BATCH_HEADER = 0x66
|
23
|
-
S2C_CONNREJECT_HEADER = 0x39
|
24
17
|
RCON_GOLDSRC_CHALLENGE_HEADER = 0x63
|
25
18
|
RCON_GOLDSRC_NO_CHALLENGE_HEADER = 0x39
|
26
19
|
RCON_GOLDSRC_RESPONSE_HEADER = 0x6c
|
20
|
+
S2A_INFO_DETAILED_HEADER = 0x6D
|
21
|
+
S2A_INFO2_HEADER = 0x49
|
22
|
+
S2A_PLAYER_HEADER = 0x44
|
23
|
+
S2A_RULES_HEADER = 0x45
|
24
|
+
S2C_CONNREJECT_HEADER = 0x39
|
25
|
+
S2C_CHALLENGE_HEADER = 0x41
|
27
26
|
|
28
27
|
# Creates a new SteamPacket object with given header and content data
|
29
28
|
def initialize(header_data, content_data = "")
|
30
29
|
@content_data = ByteBuffer.new content_data
|
31
30
|
@header_data = header_data
|
32
31
|
end
|
33
|
-
|
32
|
+
|
34
33
|
# Returns a packed string representing the packet's data
|
35
34
|
#
|
36
35
|
# TODO Has to automatically split packets greater than 1400 bytes
|
37
36
|
def to_s
|
38
37
|
packet_data = [0xFF, 0xFF, 0xFF].pack("ccc")
|
39
|
-
|
38
|
+
|
40
39
|
unless @split_packet
|
41
40
|
packet_data << [0xFF].pack("c")
|
42
41
|
else
|
43
42
|
packet_data << [0xFE].pack("c")
|
44
43
|
end
|
45
|
-
|
44
|
+
|
46
45
|
return packet_data << [@header_data, @content_data.array].pack("ca*")
|
47
|
-
end
|
46
|
+
end
|
48
47
|
end
|
@@ -17,7 +17,9 @@ class SourceServer < GameServer
|
|
17
17
|
def self.split_player_status(player_status)
|
18
18
|
player_data = player_status.match(/# *(\d+) +"(.*)" +(.*)/).to_a[1..-1]
|
19
19
|
player_data[2] = player_data[2].split
|
20
|
-
player_data.flatten
|
20
|
+
player_data.flatten!
|
21
|
+
player_data.delete_at(3)
|
22
|
+
player_data
|
21
23
|
end
|
22
24
|
|
23
25
|
def initialize(ip_address, port_number = 27015)
|