steam-condenser 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|