steam-condenser 0.12.0 → 0.13.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/README.md +3 -1
- data/lib/exceptions/web_api_exception.rb +49 -0
- data/lib/steam/community/app_news.rb +69 -0
- data/lib/steam/community/game_achievement.rb +29 -0
- data/lib/steam/community/steam_id.rb +1 -1
- data/lib/steam/community/tf2/tf2_golden_wrench.rb +43 -0
- data/lib/steam/community/tf2/tf2_inventory.rb +51 -0
- data/lib/steam/community/tf2/tf2_item.rb +106 -0
- data/lib/steam/community/tf2/tf2_stats.rb +11 -0
- data/lib/steam/community/web_api.rb +96 -0
- data/lib/steam/packets/a2s_player_packet.rb +1 -1
- data/lib/steam/packets/a2s_rules_packet.rb +3 -3
- data/lib/steam/packets/c2m_checkmd5_packet.rb +24 -0
- data/lib/steam/packets/m2c_isvalidmd5_packet.rb +25 -0
- data/lib/steam/packets/m2s_requestrestart_packet.rb +24 -0
- data/lib/steam/packets/rcon/rcon_packet.rb +1 -1
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +0 -1
- data/lib/steam/packets/rcon/rcon_terminator.rb +20 -0
- data/lib/steam/packets/s2a_info2_packet.rb +3 -3
- data/lib/steam/packets/s2a_logstring_packet.rb +24 -0
- data/lib/steam/packets/s2a_player_packet.rb +1 -1
- data/lib/steam/packets/s2a_rules_packet.rb +2 -2
- data/lib/steam/packets/s2c_challenge_packet.rb +2 -2
- data/lib/steam/packets/s2m_heartbeat2_packet.rb +57 -0
- data/lib/steam/packets/steam_packet.rb +6 -3
- data/lib/steam/packets/steam_packet_factory.rb +12 -9
- data/lib/steam/servers/game_server.rb +57 -16
- data/lib/steam/servers/goldsrc_server.rb +7 -12
- data/lib/steam/servers/master_server.rb +63 -15
- data/lib/steam/servers/server.rb +66 -0
- data/lib/steam/servers/source_server.rb +14 -20
- data/lib/steam/sockets/goldsrc_socket.rb +13 -9
- data/lib/steam/sockets/rcon_socket.rb +35 -24
- data/lib/steam/sockets/steam_socket.rb +27 -21
- data/lib/steam/steam_player.rb +30 -15
- data/lib/steam-condenser/community.rb +17 -16
- data/lib/steam-condenser/version.rb +2 -2
- metadata +39 -15
- data/lib/datagram_channel.rb +0 -67
- data/lib/socket_channel.rb +0 -55
- data/lib/steam/packets/a2a_ack_packet.rb +0 -24
- data/lib/steam/packets/a2a_ping_packet.rb +0 -19
data/README.md
CHANGED
@@ -11,7 +11,8 @@ Currently it is implemented in Java, PHP and Ruby.
|
|
11
11
|
* Ruby 1.8.6 or newer
|
12
12
|
|
13
13
|
The following gems are required:
|
14
|
-
* `bzip2-ruby
|
14
|
+
* `bzip2-ruby (for Source servers sending compressed responses)
|
15
|
+
* `json` (for the Web API features)
|
15
16
|
|
16
17
|
## License
|
17
18
|
|
@@ -22,6 +23,7 @@ included LICENSE file.
|
|
22
23
|
## Credits
|
23
24
|
|
24
25
|
* Sebastian Staudt -- koraktor(at)gmail.com
|
26
|
+
* DeFirence -- defirence(at)defirence.za.net
|
25
27
|
|
26
28
|
## See Also
|
27
29
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'exceptions/steam_condenser_exception'
|
7
|
+
|
8
|
+
# This exceptions is raised when a Steam Web API request or a related action
|
9
|
+
# fails. This can have various reasons.
|
10
|
+
class WebApiException < SteamCondenserException
|
11
|
+
|
12
|
+
# Creates a new WebApiException with an error message according to the given
|
13
|
+
# +cause+. If this cause is +:status_bad+ (which will origin from the Web API
|
14
|
+
# itself) or +:http_error+ the details about this failed request will be
|
15
|
+
# taken from +status_code+ and +status_message+.
|
16
|
+
#
|
17
|
+
# * +:http_errpr+: An error in the HTTP request itself will result in an
|
18
|
+
# exception with this reason.
|
19
|
+
# * +:invalid_key+: This occurs when trying to set a Web API key that isn't
|
20
|
+
# valid, i.e. a 128 bit integer in a hexadecimal string.
|
21
|
+
# * +:status_bad+: This is caused by a succesful request that fails for
|
22
|
+
# some Web API internal reason (e.g. a invalid argument).
|
23
|
+
# Details about this failed request will be taken from
|
24
|
+
# +status_code+ and +status_message+.
|
25
|
+
# * +:unauthorized+: This happens when a Steam Web API request is rejected as
|
26
|
+
# unauthorized. This most likely means that you did not
|
27
|
+
# specify a valid Web API key using +WebAPI.api_key=+. A
|
28
|
+
# Web API key can be obtained from
|
29
|
+
# http://steamcommunity.com/dev/apikey.
|
30
|
+
#
|
31
|
+
# Other undefined reasons will cause a generic error message.
|
32
|
+
def initialize(cause, status_code = nil, status_message = '')
|
33
|
+
case cause
|
34
|
+
when :http_error then
|
35
|
+
message = "The Web API request has failed due to an HTTP error: #{status_message} (status code: #{status_code})."
|
36
|
+
when :invalid_key then
|
37
|
+
message = 'This is not a valid Steam Web API key.'
|
38
|
+
when :status_bad then
|
39
|
+
message = "The Web API request failed with the following error: #{status_message} (status code: #{status_code})."
|
40
|
+
when :unauthorized then
|
41
|
+
message = 'Your Web API request has been rejected. You most likely did not specify a valid Web API key.'
|
42
|
+
else
|
43
|
+
message = 'An unexpected error occured while executing a Web API request.'
|
44
|
+
end
|
45
|
+
|
46
|
+
super message
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
require 'steam/community/web_api'
|
9
|
+
|
10
|
+
# The AppNews class is a representation of Steam news and can be used to load
|
11
|
+
# current news about specific games
|
12
|
+
class AppNews
|
13
|
+
|
14
|
+
attr_reader :app_id, :author, :contents, :date, :feed_label, :feed_name,
|
15
|
+
:gid, :title, :url
|
16
|
+
|
17
|
+
# Loads the news for the given game with the given restrictions
|
18
|
+
#
|
19
|
+
# [+app_id+] The unique Steam Application ID of the game (e.g. +440+ for
|
20
|
+
# Team Fortress 2). See
|
21
|
+
# http://developer.valvesoftware.com/wiki/Steam_Application_IDs
|
22
|
+
# for all application IDs
|
23
|
+
# [+count+] The maximum number of news to load (default: 5). There's no
|
24
|
+
# reliable way to load all news. Use really a really great
|
25
|
+
# number instead
|
26
|
+
# [+max_length+] The maximum content length of the news (default: nil). If a
|
27
|
+
# maximum length is defined, the content of the news will only
|
28
|
+
# be at most +max_length+ characters long plus an ellipsis
|
29
|
+
def self.news_for_app(app_id, count = 5, max_length = nil)
|
30
|
+
params = { :appid => app_id, :count => count, :maxlength => max_length }
|
31
|
+
data = WebApi.json('ISteamNews', 'GetNewsForApp', 1, params)
|
32
|
+
|
33
|
+
news_items = []
|
34
|
+
JSON.parse(data, { :symbolize_names => true })[:appnews][:newsitems][:newsitem].each do |news_data|
|
35
|
+
news_items << AppNews.new(app_id, news_data)
|
36
|
+
end
|
37
|
+
|
38
|
+
news_items
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns whether this news items originates from a source other than Steam
|
42
|
+
# itself (e.g. an external blog)
|
43
|
+
def external?
|
44
|
+
@external
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Creates a new instance of an AppNews news item with the given data
|
50
|
+
#
|
51
|
+
# [+app_id+] The unique Steam Application ID of the game (e.g. +440+ for
|
52
|
+
# Team Fortress 2). See
|
53
|
+
# http://developer.valvesoftware.com/wiki/Steam_Application_IDs
|
54
|
+
# for all application IDs
|
55
|
+
# [+news_data+] The news data extracted from JSON
|
56
|
+
def initialize(app_id, news_data)
|
57
|
+
@app_id = app_id
|
58
|
+
@author = news_data[:autor]
|
59
|
+
@contents = news_data[:contents].strip
|
60
|
+
@data = Time.at(news_data[:date])
|
61
|
+
@external = news_data[:is_external_url]
|
62
|
+
@feed_label = news_data[:feedlabel]
|
63
|
+
@feed_name = news_data[:feedname]
|
64
|
+
@gid = news_data[:gid]
|
65
|
+
@title = news_data[:title]
|
66
|
+
@url = news_data[:url]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -3,14 +3,43 @@
|
|
3
3
|
#
|
4
4
|
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
require 'steam/community/web_api'
|
9
|
+
|
6
10
|
# The GameAchievement class represents a specific achievement for a single game
|
7
11
|
# and for a single user
|
8
12
|
class GameAchievement
|
9
13
|
|
10
14
|
attr_reader :app_id, :name, :steam_id64, :timestamp
|
11
15
|
|
16
|
+
# Loads the global unlock percentages of all achievements for the given game
|
17
|
+
#
|
18
|
+
# [+app_id+] The unique Steam Application ID of the game (e.g. +440+ for
|
19
|
+
# Team Fortress 2). See
|
20
|
+
# http://developer.valvesoftware.com/wiki/Steam_Application_IDs
|
21
|
+
# for all application IDs
|
22
|
+
def self.global_percentages(app_id)
|
23
|
+
percentages = {}
|
24
|
+
|
25
|
+
data = WebApi.json('ISteamUserStats', 'GetGlobalAchievementPercentagesForApp', 1, { :gameid => app_id })
|
26
|
+
JSON.parse(data, { :symbolize_names => true })[:achievementpercentages][:achievements][:achievement].each do |percentage|
|
27
|
+
percentages[percentage[:name].to_sym] = percentage[:percent]
|
28
|
+
end
|
29
|
+
|
30
|
+
percentages
|
31
|
+
end
|
32
|
+
|
12
33
|
# Creates the achievement with the given name for the given user and game
|
13
34
|
# and achievement data
|
35
|
+
#
|
36
|
+
# [+steam_id64+] The 64bit SteamID of the player this achievement
|
37
|
+
# belongs to
|
38
|
+
# [+app_id+] The unique Steam Application ID of the game (e.g.
|
39
|
+
# +440+ for Team Fortress 2). See
|
40
|
+
# http://developer.valvesoftware.com/wiki/Steam_Application_IDs
|
41
|
+
# for all application IDs
|
42
|
+
# [+achievement_data+] The achievement data extracted from JSON
|
14
43
|
def initialize(steam_id64, app_id, achievement_data)
|
15
44
|
@app_id = app_id
|
16
45
|
@name = achievement_data.elements['name'].text
|
@@ -177,7 +177,7 @@ class SteamId
|
|
177
177
|
if game.elements['globalStatsLink'].nil?
|
178
178
|
@games[game_name] = false
|
179
179
|
else
|
180
|
-
friendly_name = game.elements['globalStatsLink'].text.match(/http:\/\/steamcommunity.com\/stats\/([
|
180
|
+
friendly_name = game.elements['globalStatsLink'].text.match(/http:\/\/steamcommunity.com\/stats\/([^?\/]+)\/achievements\//)[1]
|
181
181
|
@games[game_name] = friendly_name.downcase
|
182
182
|
end
|
183
183
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
require 'steam/community/steam_id'
|
8
|
+
require 'steam/community/web_api'
|
9
|
+
|
10
|
+
# Represents the special Team Fortress 2 item Golden Wrench. It includes the
|
11
|
+
# ID of the item, the serial number of the wrench, a reference to the SteamId
|
12
|
+
# of the owner and the date this player crafted the wrench
|
13
|
+
class TF2GoldenWrench
|
14
|
+
|
15
|
+
attr_reader :date, :id, :number, :owner
|
16
|
+
|
17
|
+
@@golden_wrenches = nil
|
18
|
+
|
19
|
+
# Returns an array of all golden wrenches (as instances of TF2GoldenWrench)
|
20
|
+
def self.golden_wrenches
|
21
|
+
if @@golden_wrenches.nil?
|
22
|
+
@@golden_wrenches = []
|
23
|
+
|
24
|
+
data = JSON.parse(WebApi.json('ITFItems_440', 'GetGoldenWrenches'), { :symbolize_names => true })
|
25
|
+
data[:results][:wrenches][:wrench].each do |wrench_data|
|
26
|
+
@@golden_wrenches << TF2GoldenWrench.new(wrench_data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@@golden_wrenches
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Creates a new instance of TF2GoldenWrench with the given data
|
36
|
+
def initialize(wrench_data)
|
37
|
+
@date = Time.at(wrench_data[:timestamp])
|
38
|
+
@id = wrench_data[:itemID]
|
39
|
+
@number = wrench_data[:wrenchNumber]
|
40
|
+
@owner = SteamId.new(wrench_data[:steamID], false)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/community/cacheable'
|
7
|
+
require 'steam/community/tf2/tf2_item'
|
8
|
+
require 'steam/community/web_api'
|
9
|
+
|
10
|
+
# Represents the inventory (aka. Backpack) of a Team Fortress 2 player
|
11
|
+
class TF2Inventory
|
12
|
+
|
13
|
+
include Cacheable
|
14
|
+
cacheable_with_ids :steam_id64
|
15
|
+
|
16
|
+
attr_reader :items, :steam_id64
|
17
|
+
|
18
|
+
# Creates a new inventory object for the given SteamID64. This calls update
|
19
|
+
# to fetch the data and create the TF2Item instances contained in this
|
20
|
+
# players backpack
|
21
|
+
def initialize(steam_id64, fetch_now = true)
|
22
|
+
@steam_id64 = steam_id64
|
23
|
+
|
24
|
+
super(fetch_now)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the item at the given position in the backpack. The positions range
|
28
|
+
# from 1 to 100 instead of the usual array indices (0 to 99).
|
29
|
+
def [](index)
|
30
|
+
@items[index - 1]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Updates the contents of the backpack using Steam Web API
|
34
|
+
def fetch
|
35
|
+
result = WebApi.json!('ITFItems_440', 'GetPlayerItems', 1, { :SteamID => @steam_id64 })
|
36
|
+
|
37
|
+
@items = []
|
38
|
+
result[:items][:item].each do |item_data|
|
39
|
+
unless item_data.nil?
|
40
|
+
item = TF2Item.new(item_data)
|
41
|
+
@items[item.backpack_position - 1] = item
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the number of items in the user's backpack
|
47
|
+
def size
|
48
|
+
@items.size
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/community/web_api'
|
7
|
+
|
8
|
+
# Represents a Team Fortress 2 item
|
9
|
+
class TF2Item
|
10
|
+
|
11
|
+
CLASSES = [ :scout, :sniper, :soldier, :demoman, :medic, :heavy, :pyro, :spy ]
|
12
|
+
|
13
|
+
attr_reader :attributes, :backpack_position, :class, :count, :defindex, :id,
|
14
|
+
:level, :name, :quality, :slot, :type
|
15
|
+
|
16
|
+
@@attribute_schema = nil
|
17
|
+
|
18
|
+
@@item_schema = nil
|
19
|
+
|
20
|
+
@@schema_language = 'en'
|
21
|
+
|
22
|
+
# Returns the attribute schema
|
23
|
+
#
|
24
|
+
# The attribute schema is fetched first if not done already
|
25
|
+
def self.attribute_schema
|
26
|
+
update_schema if @@attribute_schema.nil?
|
27
|
+
|
28
|
+
@@attribute_schema
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the item schema
|
32
|
+
#
|
33
|
+
# The item schema is fetched first if not done already
|
34
|
+
def self.item_schema
|
35
|
+
update_schema if @@item_schema.nil?
|
36
|
+
|
37
|
+
@@item_schema
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sets the language the schema should be fetched in (default is: +'en'+)
|
41
|
+
def self.schema_language=(language)
|
42
|
+
@@schema_language = language
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a new instance of a TF2Item with the given data
|
46
|
+
def initialize(item_data)
|
47
|
+
update_schema if @@item_schema.nil?
|
48
|
+
|
49
|
+
@defindex = item_data[:defindex]
|
50
|
+
|
51
|
+
@backpack_position = item_data[:inventory] & 0xffff
|
52
|
+
@class = @@item_schema[@defindex][:item_class]
|
53
|
+
@count = item_data[:quantity]
|
54
|
+
@id = item_data[:id]
|
55
|
+
@level = item_data[:level]
|
56
|
+
@name = @@item_schema[@defindex][:item_name]
|
57
|
+
@quality = @@qualities[item_data[:quality]]
|
58
|
+
@slot = @@item_schema[@defindex][:item_slot]
|
59
|
+
@type = @@item_schema[@defindex][:item_type_name]
|
60
|
+
|
61
|
+
@equipped = {}
|
62
|
+
CLASSES.each_index do |class_id|
|
63
|
+
@equipped[CLASSES[class_id]] = (item_data[:inventory] & (1 << 16 + class_id) != 0)
|
64
|
+
end
|
65
|
+
|
66
|
+
unless @@item_schema[@defindex][:attributes].nil?
|
67
|
+
@attributes = @@item_schema[@defindex][:attributes][:attribute]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the class symbols for each class this player has equipped this item
|
72
|
+
def classes_equipped?
|
73
|
+
@equipped.reject { |class_id, equipped| !equipped }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns whether this item is equipped by this player at all
|
77
|
+
def equipped?
|
78
|
+
@equipped.has_value? true
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
# Updates the item schema (this includes attributes and qualities) using the
|
84
|
+
# +GetSchema+ method of interface +ITFItems_440+
|
85
|
+
def update_schema
|
86
|
+
params = {}
|
87
|
+
params[:language] = @@schema_language unless @@schema_language.nil?
|
88
|
+
result = WebApi.json!('ITFItems_440', 'GetSchema', 1, params)
|
89
|
+
|
90
|
+
@@attribute_schema = {}
|
91
|
+
result[:attributes][:attribute].each do |attribute_data|
|
92
|
+
@@attribute_schema[attribute_data[:name]] = attribute_data
|
93
|
+
end
|
94
|
+
|
95
|
+
@@item_schema = []
|
96
|
+
result[:items][:item].each do |item_data|
|
97
|
+
@@item_schema[item_data[:defindex]] = item_data
|
98
|
+
end
|
99
|
+
|
100
|
+
@@qualities = []
|
101
|
+
result[:qualities].each do |quality, id|
|
102
|
+
@@qualities[id] = quality
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
require 'steam/community/game_stats'
|
7
7
|
require 'steam/community/tf2/tf2_class_factory'
|
8
|
+
require 'steam/community/tf2/tf2_inventory'
|
8
9
|
|
9
10
|
# The TF2Stats class represents the game statistics for a single user in Team
|
10
11
|
# Fortress 2
|
@@ -22,6 +23,16 @@ class TF2Stats < GameStats
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
26
|
+
# Returns the current Team Fortress 2 inventory (a.k.a. backpack) of this
|
27
|
+
# player
|
28
|
+
def inventory
|
29
|
+
if @inventory.nil?
|
30
|
+
@inventory = TF2Inventory.new(steam_id64)
|
31
|
+
end
|
32
|
+
|
33
|
+
@inventory
|
34
|
+
end
|
35
|
+
|
25
36
|
# Returns a Hash of TF2Class for this user containing all Team Fortress 2
|
26
37
|
# classes. If the classes haven't been parsed already, parsing is done now.
|
27
38
|
def class_stats
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'json'
|
7
|
+
require 'open-uri'
|
8
|
+
|
9
|
+
require 'exceptions/web_api_exception'
|
10
|
+
|
11
|
+
# This adds support for Steam Web API to classes needing this functionality.
|
12
|
+
# The Web API requires you to register a domain with your Steam account to
|
13
|
+
# acquire an API key. See http://steamcommunity.com/dev for further details.
|
14
|
+
module WebApi
|
15
|
+
|
16
|
+
@@api_key = nil
|
17
|
+
|
18
|
+
# Returns the Steam Web API key
|
19
|
+
def self.api_key
|
20
|
+
@@api_key
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sets the Steam Web API key.
|
24
|
+
#
|
25
|
+
# [+api_key+] The 128bit API key that has to be requested from
|
26
|
+
# http://steamcommunity.com/dev
|
27
|
+
def self.api_key=(api_key)
|
28
|
+
unless api_key.nil? || api_key.match(/^[0-9A-F]{32}$/)
|
29
|
+
raise WebApiException.new(:invalid_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
@@api_key = api_key
|
33
|
+
end
|
34
|
+
|
35
|
+
# Fetches JSON data from Steam Web API using the specified interface, method
|
36
|
+
# and version. Additional parameters are supplied via HTTP GET.
|
37
|
+
# Data is returned as a JSON-encoded string.
|
38
|
+
#
|
39
|
+
# [+interface+] The Web API interface to call, e.g. +ISteamUser+
|
40
|
+
# [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
|
41
|
+
# [+version+] The API method version to use (default: 1)
|
42
|
+
# [+params+] A Hash of additional parameters to supply via HTTP GET
|
43
|
+
def self.json(interface, method, version = 1, params = nil)
|
44
|
+
load(:json, interface, method, version, params)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Fetches JSON data from Steam Web API using the specified interface, method
|
48
|
+
# and version. Additional parameters are supplied via HTTP GET.
|
49
|
+
# Data is returned as a Hash containing the JSON data.
|
50
|
+
#
|
51
|
+
# [+interface+] The Web API interface to call, e.g. +ISteamUser+
|
52
|
+
# [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
|
53
|
+
# [+version+] The API method version to use (default: 1)
|
54
|
+
# [+params+] A Hash of additional parameters to supply via HTTP GET
|
55
|
+
def self.json!(interface, method, version = 1, params = nil)
|
56
|
+
data = json(interface, method, version, params)
|
57
|
+
result = JSON.parse(data, { :symbolize_names => true })[:result]
|
58
|
+
|
59
|
+
status = result[:status]
|
60
|
+
if status != 1
|
61
|
+
raise WebApiException.new(:status_bad, status, result[:statusDetail])
|
62
|
+
end
|
63
|
+
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
# Fetches data from Steam Web API using the specified interface, method and
|
68
|
+
# version. Additional parameters are supplied via HTTP GET.
|
69
|
+
# Data is returned as a String in the given format.
|
70
|
+
#
|
71
|
+
# [+format+] The format to load from the API ('json', 'vdf', or 'xml')
|
72
|
+
# [+interface+] The Web API interface to call, e.g. +ISteamUser+
|
73
|
+
# [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
|
74
|
+
# [+version+] The API method version to use (default: 1)
|
75
|
+
# [+params+] A Hash of additional parameters to supply via HTTP GET
|
76
|
+
def self.load(format, interface, method, version = 1, params = nil)
|
77
|
+
version = version.to_s.rjust(4, '0')
|
78
|
+
url = "http://api.steampowered.com/#{interface}/#{method}/v#{version}/"
|
79
|
+
params = {} unless params.is_a?(Hash)
|
80
|
+
params[:format] = format
|
81
|
+
params[:key] = WebApi.api_key
|
82
|
+
|
83
|
+
unless params.nil? && params.empty?
|
84
|
+
url += '?' + params.map { |k,v| "#{k}=#{v}" }.join('&')
|
85
|
+
end
|
86
|
+
|
87
|
+
begin
|
88
|
+
open(url, { :proxy => true }).read
|
89
|
+
rescue OpenURI::HTTPError
|
90
|
+
status = $!.io.status[0]
|
91
|
+
raise WebApiException.new(:unauthorized) if status[0].to_i == 401
|
92
|
+
raise WebApiException.new(:http_error, status[0].to_i, status[1])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -10,8 +10,8 @@ require 'steam/packets/steam_packet'
|
|
10
10
|
# server.
|
11
11
|
class A2S_PLAYER_Packet
|
12
12
|
|
13
|
-
include RequestWithChallenge
|
14
13
|
include SteamPacket
|
14
|
+
include RequestWithChallenge
|
15
15
|
|
16
16
|
# Creates a new A2S_PLAYER request object including the challenge_number
|
17
17
|
def initialize(challenge_number = -1)
|
@@ -1,16 +1,16 @@
|
|
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-2011, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/packets/request_with_challenge'
|
7
7
|
require 'steam/packets/steam_packet'
|
8
8
|
|
9
|
-
# Creates a new
|
9
|
+
# Creates a new A2S_RULES request object including the challenge_number
|
10
10
|
class A2S_RULES_Packet
|
11
11
|
|
12
|
-
include RequestWithChallenge
|
13
12
|
include SteamPacket
|
13
|
+
include RequestWithChallenge
|
14
14
|
|
15
15
|
# Creates a new A2S_RULES request object including the challenge_number
|
16
16
|
def initialize(challenge_number = -1)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010-2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/packets/steam_packet'
|
7
|
+
|
8
|
+
# The C2M_CHECKMD5 packet type is used to initialize (challenge) master server
|
9
|
+
# communication.
|
10
|
+
class C2M_CHECKMD5_Packet
|
11
|
+
|
12
|
+
include SteamPacket
|
13
|
+
|
14
|
+
# Creates a new challenge request packet for master server communication
|
15
|
+
def initialize
|
16
|
+
super C2M_CHECKMD5_HEADER
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a byte array representation of the packet data
|
20
|
+
def to_s
|
21
|
+
[@header_data, 0xFF].pack('c2')
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/packets/steam_packet'
|
7
|
+
|
8
|
+
# A packet of type M2S_ISVALIDMD5 is used by the master server to provide a
|
9
|
+
# challenge number to a game server
|
10
|
+
class M2C_ISVALIDMD5_Packet
|
11
|
+
|
12
|
+
include SteamPacket
|
13
|
+
|
14
|
+
# Returns the challenge number to use for master server communication
|
15
|
+
attr_reader :challenge
|
16
|
+
|
17
|
+
# Creates a new response packet with the data from the master server
|
18
|
+
def initialize(data)
|
19
|
+
super M2C_ISVALIDMD5_HEADER, data
|
20
|
+
|
21
|
+
@content_data.byte
|
22
|
+
@challenge = @content_data.long
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under the
|
2
|
+
# terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/packets/steam_packet'
|
7
|
+
|
8
|
+
# The M2S_REQUESTRESTART packet type is used to by master servers to request a
|
9
|
+
# game server restart, e.g. when using outdated versions.
|
10
|
+
class M2S_REQUESTRESTART_Packet
|
11
|
+
|
12
|
+
include SteamPacket
|
13
|
+
|
14
|
+
# Returns the challenge number used for master server communication
|
15
|
+
attr_reader :challenge
|
16
|
+
|
17
|
+
# Creates a new server restart request packet sent by a master server
|
18
|
+
def initialize(data)
|
19
|
+
super C2M_CHECKMD5_HEADER, data
|
20
|
+
|
21
|
+
@challenge = @content_data.long
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'steam/packets/rcon/rcon_packet'
|
7
|
+
|
8
|
+
# This class is used to determine the end of a RCON response from Source
|
9
|
+
# servers. Packets of this type are sent after the actual RCON command and the
|
10
|
+
# empty response packet from the server will indicate the end of the response.
|
11
|
+
class RCONTerminator
|
12
|
+
|
13
|
+
include RCONPacket
|
14
|
+
|
15
|
+
# Creates a new RCONTerminator instance for the given request ID
|
16
|
+
def initialize(request_id)
|
17
|
+
super request_id, RCONPacket::SERVERDATA_RESPONSE_VALUE, nil
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -1,12 +1,12 @@
|
|
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-2011, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/packets/s2a_info_base_packet'
|
7
7
|
|
8
|
-
# The S2A_INFO2_Packet class represents the response to a
|
9
|
-
#
|
8
|
+
# The S2A_INFO2_Packet class represents the response to a A2S_INFO request sent
|
9
|
+
# to a Source server.
|
10
10
|
class S2A_INFO2_Packet
|
11
11
|
|
12
12
|
include S2A_INFO_BasePacket
|