steam-condenser 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile.lock +30 -0
- data/LICENSE +1 -1
- data/README.md +4 -3
- data/lib/steam-condenser/version.rb +2 -2
- data/lib/steam/community/alien_swarm/alien_swarm_mission.rb +24 -22
- data/lib/steam/community/alien_swarm/alien_swarm_stats.rb +66 -65
- data/lib/steam/community/alien_swarm/alien_swarm_weapon.rb +6 -6
- data/lib/steam/community/app_news.rb +2 -2
- data/lib/steam/community/css/css_map.rb +4 -4
- data/lib/steam/community/css/css_stats.rb +43 -43
- data/lib/steam/community/css/css_weapon.rb +5 -5
- data/lib/steam/community/defense_grid/defense_grid_stats.rb +36 -35
- data/lib/steam/community/dods/dods_class.rb +14 -14
- data/lib/steam/community/dods/dods_stats.rb +5 -4
- data/lib/steam/community/dods/dods_weapon.rb +6 -6
- data/lib/steam/community/game_achievement.rb +38 -31
- data/lib/steam/community/game_inventory.rb +6 -6
- data/lib/steam/community/game_leaderboard.rb +34 -32
- data/lib/steam/community/game_leaderboard_entry.rb +6 -6
- data/lib/steam/community/game_stats.rb +39 -65
- data/lib/steam/community/game_weapon.rb +2 -2
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +54 -49
- data/lib/steam/community/l4d/abstract_l4d_weapon.rb +7 -6
- data/lib/steam/community/l4d/l4d2_map.rb +10 -10
- data/lib/steam/community/l4d/l4d2_stats.rb +33 -33
- data/lib/steam/community/l4d/l4d2_weapon.rb +8 -7
- data/lib/steam/community/l4d/l4d_explosive.rb +5 -4
- data/lib/steam/community/l4d/l4d_map.rb +8 -7
- data/lib/steam/community/l4d/l4d_stats.rb +7 -7
- data/lib/steam/community/l4d/l4d_weapon.rb +5 -4
- data/lib/steam/community/portal2/portal2_stats.rb +3 -3
- data/lib/steam/community/steam_game.rb +106 -16
- data/lib/steam/community/steam_group.rb +51 -40
- data/lib/steam/community/steam_id.rb +119 -87
- data/lib/steam/community/tf2/tf2_class.rb +14 -14
- data/lib/steam/community/tf2/tf2_class_factory.rb +2 -2
- data/lib/steam/community/tf2/tf2_engineer.rb +5 -7
- data/lib/steam/community/tf2/tf2_golden_wrench.rb +1 -1
- data/lib/steam/community/tf2/tf2_medic.rb +4 -6
- data/lib/steam/community/tf2/tf2_sniper.rb +3 -5
- data/lib/steam/community/tf2/tf2_spy.rb +10 -6
- data/lib/steam/community/tf2/tf2_stats.rb +15 -7
- data/lib/steam/community/web_api.rb +15 -1
- data/lib/steam/community/xml_data.rb +17 -0
- data/lib/steam/servers/game_server.rb +4 -4
- data/lib/steam/servers/master_server.rb +2 -2
- data/lib/steam/servers/source_server.rb +0 -2
- data/lib/steam/sockets/goldsrc_socket.rb +2 -2
- data/lib/steam/steam_player.rb +2 -2
- data/steam-condenser.gemspec +3 -2
- data/test/helper.rb +10 -2
- data/test/steam/communtiy/test_steam_group.rb +4 -4
- data/test/steam/communtiy/test_steam_id.rb +28 -2
- data/test/steam/communtiy/test_web_api.rb +2 -2
- data/test/steam/packets/test_steam_packet.rb +37 -0
- data/test/steam/servers/test_game_server.rb +296 -308
- data/test/steam/servers/test_goldsrc_server.rb +59 -59
- data/test/steam/servers/test_master_server.rb +131 -131
- data/test/steam/servers/test_server.rb +72 -72
- data/test/steam/servers/test_source_server.rb +126 -140
- data/test/steam/sockets/test_master_server_socket.rb +1 -0
- metadata +39 -19
@@ -25,13 +25,14 @@ class L4D2Weapon
|
|
25
25
|
|
26
26
|
# Creates a new instance of a weapon based on the given XML data
|
27
27
|
#
|
28
|
-
# @param [
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@
|
34
|
-
@
|
28
|
+
# @param [String] weapon_name The name of this weapon
|
29
|
+
# @param [Hash<String, Object>] weapon_data The XML data of this weapon
|
30
|
+
def initialize(weapon_name, weapon_data)
|
31
|
+
super
|
32
|
+
|
33
|
+
@damage = weapon_data['damage'].to_i
|
34
|
+
@kill_percentage = weapon_data['pctkills'].to_f * 0.01
|
35
|
+
@weapon_group = weapon_data['group']
|
35
36
|
end
|
36
37
|
|
37
38
|
end
|
@@ -15,12 +15,13 @@ class L4DExplosive
|
|
15
15
|
|
16
16
|
# Creates a new instance of an explosivve based on the given XML data
|
17
17
|
#
|
18
|
-
# @param [
|
19
|
-
|
18
|
+
# @param [String] weapon_name The name of this weapon
|
19
|
+
# @param [Hash<String, Object>] weapon_data The XML data of this weapon
|
20
|
+
def initialize(weapon_name, weapon_data)
|
20
21
|
super weapon_data
|
21
22
|
|
22
|
-
@id =
|
23
|
-
@shots = weapon_data
|
23
|
+
@id = weapon_name
|
24
|
+
@shots = weapon_data['thrown'].to_i
|
24
25
|
end
|
25
26
|
|
26
27
|
# Returns the average number of killed zombies for one shot of this explosive
|
@@ -42,14 +42,15 @@ class L4DMap
|
|
42
42
|
# Creates a new instance of a Left4Dead Survival map based on the given
|
43
43
|
# XML data
|
44
44
|
#
|
45
|
-
# @param [
|
46
|
-
|
47
|
-
|
48
|
-
@
|
49
|
-
@
|
50
|
-
@
|
45
|
+
# @param [String] map_name The name of this map
|
46
|
+
# @param [Hash<String, Object>] map_data The XML data for this map
|
47
|
+
def initialize(map_name, map_data)
|
48
|
+
@best_time = map_data['besttimeseconds'].to_f
|
49
|
+
@id = map_name
|
50
|
+
@name = map_data['name']
|
51
|
+
@times_played = map_data['timesplayed'].to_i
|
51
52
|
|
52
|
-
case map_data
|
53
|
+
case map_data['medal']
|
53
54
|
when 'gold'
|
54
55
|
@medal = L4DMap::GOLD
|
55
56
|
when 'silver'
|
@@ -35,8 +35,8 @@ class L4DStats < GameStats
|
|
35
35
|
if @survival_stats.nil?
|
36
36
|
super
|
37
37
|
@survival_stats[:maps] = {}
|
38
|
-
@xml_data
|
39
|
-
@survival_stats[:maps][map_data
|
38
|
+
@xml_data['stats']['survival']['maps'].each do |map_data|
|
39
|
+
@survival_stats[:maps][map_data[0]] = L4DMap.new *map_data
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -54,14 +54,14 @@ class L4DStats < GameStats
|
|
54
54
|
|
55
55
|
if @weapon_stats.nil?
|
56
56
|
@weapon_stats = {}
|
57
|
-
@xml_data
|
58
|
-
unless %w{molotov pipes}.include? weapon_data
|
59
|
-
weapon = L4DWeapon.new
|
57
|
+
@xml_data['stats']['weapons'].each do |weapon_data|
|
58
|
+
unless %w{molotov pipes}.include? weapon_data[0]
|
59
|
+
weapon = L4DWeapon.new *weapon_data
|
60
60
|
else
|
61
|
-
weapon = L4DExplosive.new
|
61
|
+
weapon = L4DExplosive.new *weapon_data
|
62
62
|
end
|
63
63
|
|
64
|
-
@weapon_stats[weapon_data
|
64
|
+
@weapon_stats[weapon_data[0]] = weapon
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -15,11 +15,12 @@ class L4DWeapon
|
|
15
15
|
|
16
16
|
# Creates a new instance of a weapon based on the given XML data
|
17
17
|
#
|
18
|
-
# @param [
|
19
|
-
|
20
|
-
|
18
|
+
# @param [String] weapon_name The name of this weapon
|
19
|
+
# @param [Hash<String, Object>] weapon_data The XML data of this weapon
|
20
|
+
def initialize(weapon_name, weapon_data)
|
21
|
+
super
|
21
22
|
|
22
|
-
@kill_percentage = weapon_data
|
23
|
+
@kill_percentage = weapon_data['killpct'].to_f * 0.01
|
23
24
|
end
|
24
25
|
|
25
26
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2011, Sebastian Staudt
|
4
|
+
# Copyright (c) 2011-2012, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/community/game_stats'
|
7
7
|
require 'steam/community/portal2/portal2_inventory'
|
@@ -23,9 +23,9 @@ class Portal2Stats < GameStats
|
|
23
23
|
# Returns the current Portal 2 inventory (a.k.a Robot Enrichment) of this
|
24
24
|
# player
|
25
25
|
#
|
26
|
-
# @return [
|
26
|
+
# @return [Portal2Inventory] This player's Portal 2 inventory
|
27
27
|
def inventory
|
28
|
-
@inventory = Portal2Inventory.new(steam_id64) if @inventory.nil?
|
28
|
+
@inventory = Portal2Inventory.new(user.steam_id64) if @inventory.nil?
|
29
29
|
@inventory
|
30
30
|
end
|
31
31
|
|
@@ -1,23 +1,31 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2011, Sebastian Staudt
|
4
|
+
# Copyright (c) 2011-2012, Sebastian Staudt
|
5
5
|
|
6
|
+
require 'steam/community/cacheable'
|
6
7
|
require 'steam/community/game_leaderboard'
|
7
8
|
require 'steam/community/game_stats'
|
9
|
+
require 'steam/community/web_api'
|
8
10
|
|
9
11
|
# This class represents a game available on Steam
|
10
12
|
#
|
11
13
|
# @author Sebastian Staudt
|
12
14
|
class SteamGame
|
13
15
|
|
14
|
-
|
16
|
+
include Cacheable
|
17
|
+
cacheable_with_ids :app_id
|
15
18
|
|
16
19
|
# Returns the Steam application ID of this game
|
17
20
|
#
|
18
21
|
# @return [Fixnum] The Steam application ID of this game
|
19
22
|
attr_reader :app_id
|
20
23
|
|
24
|
+
# Returns the URL for the icon image of this game
|
25
|
+
#
|
26
|
+
# @return [String] The URL for the game icon
|
27
|
+
attr_reader :icon_url
|
28
|
+
|
21
29
|
# Returns the full name of this game
|
22
30
|
#
|
23
31
|
# @return [String] The full name of this game
|
@@ -28,14 +36,48 @@ class SteamGame
|
|
28
36
|
# @return [String] The short name of this game
|
29
37
|
attr_reader :short_name
|
30
38
|
|
31
|
-
#
|
32
|
-
#
|
39
|
+
# Checks if a game is up-to-date by reading information from a `steam.inf`
|
40
|
+
# file and comparing it using the Web API
|
41
|
+
#
|
42
|
+
# @param [String] path The file system path of the `steam.inf` file
|
43
|
+
# @return [Boolean] `true` if the game is up-to-date
|
44
|
+
def self.check_steam_inf(path)
|
45
|
+
steam_inf = File.read path
|
46
|
+
begin
|
47
|
+
app_id = steam_inf.match(/^\s*appID=(\d+)\s*$/im)[1].to_i
|
48
|
+
version = steam_inf.match(/^\s*PatchVersion=([\d\.]+)\s*$/im)[1].gsub('.', '').to_i
|
49
|
+
rescue
|
50
|
+
raise SteamCondenserError, "The steam.inf file at \"#{path}\" is invalid."
|
51
|
+
end
|
52
|
+
uptodate? app_id, version
|
53
|
+
end
|
54
|
+
|
55
|
+
# Creates a new instance of a game with the given data and caches it
|
56
|
+
#
|
57
|
+
# @param [Fixnum] app_id The application ID of the game
|
58
|
+
# @param [Hash<String, Object>] game_data The XML data of the game
|
59
|
+
def self.new(app_id, game_data = nil)
|
60
|
+
if cached? app_id
|
61
|
+
class_variable_get(:@@cache)[app_id]
|
62
|
+
else
|
63
|
+
game = SteamGame.allocate
|
64
|
+
game.send :initialize, app_id, game_data
|
65
|
+
game
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns whether the given version of the game with the given application ID
|
70
|
+
# is up-to-date
|
33
71
|
#
|
34
|
-
# @param [
|
35
|
-
# @
|
36
|
-
|
37
|
-
|
38
|
-
|
72
|
+
# @param [Fixnum] app_id The application ID of the game to check
|
73
|
+
# @param [Fixnum] version The version to check against the Web API
|
74
|
+
# @return [Boolean] `true` if the given version is up-to-date
|
75
|
+
def self.uptodate?(app_id, version)
|
76
|
+
params = { :appid => app_id, :version => version }
|
77
|
+
result = WebApi.json 'ISteamApps', 'UpToDateCheck', 1, params
|
78
|
+
result = MultiJson.load(result, { :symbolize_keys => true})[:response]
|
79
|
+
raise SteamCondenserError, result[:error] unless result[:success]
|
80
|
+
result[:up_to_date]
|
39
81
|
end
|
40
82
|
|
41
83
|
# Returns whether this game has statistics available
|
@@ -45,6 +87,15 @@ class SteamGame
|
|
45
87
|
!@short_name.nil?
|
46
88
|
end
|
47
89
|
|
90
|
+
# Returns a unique identifier for this game
|
91
|
+
#
|
92
|
+
# This is either the numeric application ID or the unique short name
|
93
|
+
#
|
94
|
+
# @return [Fixnum, String] The application ID or short name of the game
|
95
|
+
def id
|
96
|
+
@short_name == @app_id.to_s ? @app_id : @short_name
|
97
|
+
end
|
98
|
+
|
48
99
|
# Returns the leaderboard for this game and the given leaderboard ID or name
|
49
100
|
#
|
50
101
|
# @param [Fixnum, String] id The ID or name of the leaderboard to return
|
@@ -60,6 +111,35 @@ class SteamGame
|
|
60
111
|
GameLeaderboard.leaderboards @short_name
|
61
112
|
end
|
62
113
|
|
114
|
+
# Returns the URL for the logo image of this game
|
115
|
+
#
|
116
|
+
# @return [String] The URL for the game logo
|
117
|
+
def logo_url
|
118
|
+
"http://media.steampowered.com/steamcommunity/public/images/apps/#@app_id/#@logo_hash.jpg"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the URL for the logo thumbnail image of this game
|
122
|
+
#
|
123
|
+
# @return [String] The URL for the game logo thumbnail
|
124
|
+
def logo_thumbnail_url
|
125
|
+
"http://media.steampowered.com/steamcommunity/public/images/apps/#@app_id/#@logo_hash_thumb.jpg"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns the URL of this game's page in the Steam Store
|
129
|
+
#
|
130
|
+
# @return [String] This game's store page
|
131
|
+
def store_url
|
132
|
+
"http://store.steampowered.com/app/#@app_id"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns whether the given version of this game is up-to-date
|
136
|
+
#
|
137
|
+
# @param [Fixnum] version The version to check against the Web API
|
138
|
+
# @return [Boolean] `true` if the given version is up-to-date
|
139
|
+
def uptodate?(version)
|
140
|
+
self.class.uptodate? @app_id, version
|
141
|
+
end
|
142
|
+
|
63
143
|
# Creates a stats object for the given user and this game
|
64
144
|
#
|
65
145
|
# @param [String, Fixnum] steam_id The custom URL or the 64bit Steam ID of
|
@@ -75,18 +155,28 @@ class SteamGame
|
|
75
155
|
|
76
156
|
# Creates a new instance of a game with the given data and caches it
|
77
157
|
#
|
158
|
+
# @note The real constructor of `SteamGame` is {.new}
|
78
159
|
# @param [Fixnum] app_id The application ID of the game
|
79
|
-
# @param [
|
160
|
+
# @param [Hash<String, Object>] game_data The XML data of the game
|
80
161
|
def initialize(app_id, game_data)
|
81
|
-
@app_id
|
82
|
-
|
83
|
-
if game_data.
|
84
|
-
@
|
162
|
+
@app_id = app_id
|
163
|
+
|
164
|
+
if game_data.key? 'name'
|
165
|
+
@logo_hash = game_data['logo'].match(/\/#{app_id}\/([0-9a-f]+).jpg/)[1]
|
166
|
+
@name = game_data['name']
|
167
|
+
|
168
|
+
if game_data.key? 'globalStatsLink'
|
169
|
+
@short_name = game_data['globalStatsLink'].match(/http:\/\/steamcommunity.com\/stats\/([^?\/]+)\/achievements\//)[1].downcase
|
170
|
+
end
|
85
171
|
else
|
86
|
-
@
|
172
|
+
@icon_url = game_data['gameIcon']
|
173
|
+
@logo_hash = game_data['gameLogo'].match(/\/#{app_id}\/([0-9a-f]+).jpg/)[1]
|
174
|
+
@name = game_data['gameName']
|
175
|
+
@short_name = game_data['gameFriendlyName'].downcase
|
176
|
+
@short_name = @app_id if @short_name == @app_id.to_s
|
87
177
|
end
|
88
178
|
|
89
|
-
|
179
|
+
super()
|
90
180
|
end
|
91
181
|
|
92
182
|
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# This code is free software; you can redistribute it and/or modify it under
|
2
2
|
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
5
|
-
|
6
|
-
require 'open-uri'
|
7
|
-
require 'rexml/document'
|
4
|
+
# Copyright (c) 2008-2012, Sebastian Staudt
|
8
5
|
|
9
6
|
require 'errors/steam_condenser_error'
|
10
7
|
require 'steam/community/cacheable'
|
11
8
|
require 'steam/community/steam_id'
|
9
|
+
require 'steam/community/xml_data'
|
12
10
|
|
13
11
|
# The SteamGroup class represents a group in the Steam Community
|
14
12
|
#
|
@@ -18,6 +16,8 @@ class SteamGroup
|
|
18
16
|
include Cacheable
|
19
17
|
cacheable_with_ids :custom_url, :group_id64
|
20
18
|
|
19
|
+
include XMLData
|
20
|
+
|
21
21
|
# Returns the custom URL of this group
|
22
22
|
#
|
23
23
|
# The custom URL is a admin specified unique string that can be used instead
|
@@ -38,17 +38,14 @@ class SteamGroup
|
|
38
38
|
# @param [Boolean] fetch if `true` the groups's data is loaded into the
|
39
39
|
# object
|
40
40
|
def initialize(id, fetch = true)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@custom_url = id.downcase
|
46
|
-
end
|
47
|
-
|
48
|
-
super(fetch)
|
49
|
-
rescue REXML::ParseException
|
50
|
-
raise SteamCondenserError, 'Group could not be loaded.'
|
41
|
+
if id.is_a? Numeric
|
42
|
+
@group_id64 = id
|
43
|
+
else
|
44
|
+
@custom_url = id.downcase
|
51
45
|
end
|
46
|
+
@members = []
|
47
|
+
|
48
|
+
super fetch
|
52
49
|
end
|
53
50
|
|
54
51
|
# Returns the base URL for this group's page
|
@@ -58,9 +55,9 @@ class SteamGroup
|
|
58
55
|
# @return [String] The base URL for this group
|
59
56
|
def base_url
|
60
57
|
if @custom_url.nil?
|
61
|
-
"http://steamcommunity.com/gid
|
58
|
+
"http://steamcommunity.com/gid/#@group_id64"
|
62
59
|
else
|
63
|
-
"http://steamcommunity.com/groups
|
60
|
+
"http://steamcommunity.com/groups/#@custom_url"
|
64
61
|
end
|
65
62
|
end
|
66
63
|
|
@@ -71,24 +68,14 @@ class SteamGroup
|
|
71
68
|
#
|
72
69
|
# @see Cacheable#fetch
|
73
70
|
def fetch
|
74
|
-
@
|
75
|
-
|
71
|
+
if @member_count.nil? || @member_count == @members.size
|
72
|
+
page = 0
|
73
|
+
else
|
74
|
+
page = 1
|
75
|
+
end
|
76
76
|
|
77
77
|
begin
|
78
|
-
page += 1
|
79
|
-
url = open("#{base_url}/memberslistxml?p=#{page}", {:proxy => true})
|
80
|
-
member_data = REXML::Document.new(url.read).root
|
81
|
-
|
82
|
-
begin
|
83
|
-
@group_id64 = member_data.elements['groupID64'].text.to_i if page == 1
|
84
|
-
total_pages = member_data.elements['totalPages'].text.to_i
|
85
|
-
|
86
|
-
member_data.elements['members'].elements.each do |member|
|
87
|
-
@members << SteamId.new(member.text.to_i, false)
|
88
|
-
end
|
89
|
-
rescue
|
90
|
-
raise SteamCondenserError, 'XML data could not be parsed.'
|
91
|
-
end
|
78
|
+
total_pages = fetch_page(page += 1)
|
92
79
|
end while page < total_pages
|
93
80
|
|
94
81
|
super
|
@@ -97,17 +84,17 @@ class SteamGroup
|
|
97
84
|
# Returns the number of members this group has
|
98
85
|
#
|
99
86
|
# If the members have already been fetched the size of the member array is
|
100
|
-
# returned. Otherwise the
|
101
|
-
#
|
87
|
+
# returned. Otherwise the the first page of the member listing is fetched and
|
88
|
+
# the member count and the first batch of members is stored.
|
102
89
|
#
|
103
90
|
# @return [Fixnum] The number of this group's members
|
104
91
|
def member_count
|
105
|
-
if @
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
@members.size
|
92
|
+
if @member_count.nil?
|
93
|
+
total_pages = fetch_page(1)
|
94
|
+
@fetch_time = Time.now if total_pages == 1
|
110
95
|
end
|
96
|
+
|
97
|
+
@member_count
|
111
98
|
end
|
112
99
|
|
113
100
|
# Returns the members of this group
|
@@ -117,8 +104,32 @@ class SteamGroup
|
|
117
104
|
# @return [Array<SteamId>] The Steam ID's of the members of this group
|
118
105
|
# @see #fetch
|
119
106
|
def members
|
120
|
-
fetch if @members.
|
107
|
+
fetch if @members.size != @member_count
|
121
108
|
@members
|
122
109
|
end
|
123
110
|
|
111
|
+
private
|
112
|
+
|
113
|
+
# Fetches a specific page of the member listing of this group
|
114
|
+
#
|
115
|
+
# @param [Fixnum] page The member page to fetch
|
116
|
+
# @return [Fixnum] The total number of pages of this group's member listing
|
117
|
+
def fetch_page(page)
|
118
|
+
member_data = parse "#{base_url}/memberslistxml?p=#{page}"
|
119
|
+
|
120
|
+
begin
|
121
|
+
@group_id64 = member_data['groupID64'].to_i if page == 1
|
122
|
+
@member_count = member_data['memberCount'].to_i
|
123
|
+
total_pages = member_data['totalPages'].to_i
|
124
|
+
|
125
|
+
member_data['members']['steamID64'].each do |member|
|
126
|
+
@members << SteamId.new(member.to_i, false)
|
127
|
+
end
|
128
|
+
rescue
|
129
|
+
raise SteamCondenserError, 'XML data could not be parsed.', $!.backtrace
|
130
|
+
end
|
131
|
+
|
132
|
+
total_pages
|
133
|
+
end
|
134
|
+
|
124
135
|
end
|