steam-condenser 0.10.1 → 0.11.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/VERSION.yml +2 -2
- data/lib/datagram_channel.rb +30 -33
- data/lib/exceptions/packet_format_exception.rb +7 -3
- data/lib/exceptions/rcon_ban_exception.rb +7 -5
- data/lib/exceptions/rcon_no_auth_exception.rb +8 -6
- data/lib/exceptions/timeout_exception.rb +10 -4
- data/lib/socket_channel.rb +11 -17
- data/lib/steam/community/cacheable.rb +5 -7
- data/lib/steam/community/css/css_map.rb +31 -0
- data/lib/steam/community/css/css_stats.rb +116 -0
- data/lib/steam/community/css/css_weapon.rb +33 -0
- data/lib/steam/community/dods/dods_stats.rb +3 -3
- data/lib/steam/community/game_stats.rb +14 -13
- data/lib/steam/community/game_weapon.rb +3 -5
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +4 -2
- data/lib/steam/community/l4d/l4d_explosive.rb +2 -2
- data/lib/steam/community/l4d/l4d_map.rb +3 -3
- data/lib/steam/community/steam_group.rb +2 -4
- data/lib/steam/community/steam_id.rb +2 -2
- data/lib/steam/community/tf2/tf2_class.rb +17 -17
- data/lib/steam/community/tf2/tf2_class_factory.rb +17 -17
- data/lib/steam/community/tf2/tf2_engineer.rb +9 -9
- data/lib/steam/community/tf2/tf2_medic.rb +9 -9
- data/lib/steam/community/tf2/tf2_sniper.rb +7 -7
- data/lib/steam/community/tf2/tf2_spy.rb +9 -9
- data/lib/steam/community/tf2/tf2_stats.rb +9 -9
- data/lib/steam/packets/a2a_ack_packet.rb +11 -9
- data/lib/steam/packets/a2a_ping_packet.rb +5 -4
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +13 -12
- data/lib/steam/packets/a2s_info_packet.rb +8 -7
- data/lib/steam/packets/a2s_player_packet.rb +6 -6
- data/lib/steam/packets/a2s_rules_packet.rb +5 -5
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +4 -3
- data/lib/steam/packets/m2a_server_batch_packet.rb +20 -22
- data/lib/steam/packets/rcon/rcon_auth_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_auth_response.rb +6 -6
- data/lib/steam/packets/rcon/rcon_exec_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_exec_response.rb +2 -2
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +7 -7
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +8 -8
- data/lib/steam/packets/rcon/rcon_packet.rb +12 -16
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +19 -19
- data/lib/steam/packets/request_with_challenge.rb +5 -5
- data/lib/steam/packets/s2a_info2_packet.rb +28 -30
- data/lib/steam/packets/s2a_info_base_packet.rb +11 -16
- data/lib/steam/packets/s2a_info_detailed_packet.rb +30 -28
- data/lib/steam/packets/s2a_player_packet.rb +7 -9
- data/lib/steam/packets/s2a_rules_packet.rb +8 -12
- data/lib/steam/packets/s2c_challenge_packet.rb +7 -6
- data/lib/steam/packets/steam_packet.rb +7 -6
- data/lib/steam/packets/steam_packet_factory.rb +37 -38
- data/lib/steam/servers/game_server.rb +76 -86
- data/lib/steam/servers/goldsrc_server.rb +5 -5
- data/lib/steam/servers/master_server.rb +24 -24
- data/lib/steam/servers/source_server.rb +17 -19
- data/lib/steam/sockets/goldsrc_socket.rb +43 -46
- data/lib/steam/sockets/master_server_socket.rb +11 -13
- data/lib/steam/sockets/rcon_socket.rb +15 -17
- data/lib/steam/sockets/source_socket.rb +21 -21
- data/lib/steam/sockets/steam_socket.rb +25 -28
- data/lib/steam/steam_player.rb +3 -1
- data/lib/stringio_additions.rb +48 -0
- data/test/datagram_channel_tests.rb +8 -8
- data/test/query_tests.rb +15 -14
- data/test/rcon_tests.rb +32 -31
- data/test/socket_channel_tests.rb +7 -7
- data/test/steam/communtiy/steam_community_test_suite.rb +5 -2
- data/test/steam_community_tests.rb +4 -3
- data/test/stringio_additions_tests.rb +77 -0
- metadata +15 -8
- data/lib/byte_buffer.rb +0 -126
- data/lib/exceptions/buffer_underflow_exception.rb +0 -8
- data/test/byte_buffer_tests.rb +0 -76
data/VERSION.yml
CHANGED
data/lib/datagram_channel.rb
CHANGED
@@ -1,71 +1,68 @@
|
|
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 'ipaddr'
|
7
7
|
require 'socket'
|
8
8
|
|
9
|
-
require '
|
9
|
+
require 'stringio_additions'
|
10
10
|
|
11
11
|
class DatagramChannel
|
12
|
-
|
12
|
+
|
13
13
|
attr_reader :socket
|
14
|
-
|
14
|
+
|
15
15
|
def self.open
|
16
|
-
|
16
|
+
DatagramChannel.new
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def close
|
20
20
|
@socket.close
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def connect(*args)
|
24
24
|
if args[0].is_a? IPAddr
|
25
25
|
ip_address = args[0].to_s
|
26
26
|
elsif args[0].is_a? String
|
27
27
|
sockaddr = (Socket.gethostbyname args[0])[3]
|
28
28
|
ip_address = "#{sockaddr[0]}.#{sockaddr[1]}.#{sockaddr[2]}.#{sockaddr[3]}"
|
29
|
+
else
|
30
|
+
raise ArgumentError
|
29
31
|
end
|
30
|
-
|
32
|
+
|
31
33
|
if args[1].is_a? Numeric
|
32
34
|
port_number = args[1]
|
33
35
|
else
|
34
36
|
port_number = args[1].to_i
|
35
37
|
end
|
36
|
-
|
38
|
+
|
37
39
|
@socket.connect ip_address, port_number
|
38
|
-
|
39
|
-
|
40
|
+
|
41
|
+
self
|
40
42
|
end
|
41
|
-
|
43
|
+
|
42
44
|
def configure_blocking(do_block)
|
43
45
|
end
|
44
|
-
|
45
|
-
def read(
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
length
|
51
|
-
data = @socket.recv length
|
52
|
-
destination_buffer.put data
|
53
|
-
|
54
|
-
return data.length
|
46
|
+
|
47
|
+
def read(destination_io)
|
48
|
+
raise ArgumentError unless destination_io.is_a? StringIO
|
49
|
+
|
50
|
+
data = @socket.recv destination_io.remaining
|
51
|
+
length = destination_io.write data
|
52
|
+
destination_io.truncate length
|
55
53
|
end
|
56
|
-
|
57
|
-
def write(
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
return @socket.send(source_buffer.get, 0)
|
54
|
+
|
55
|
+
def write(source_io)
|
56
|
+
raise ArgumentError unless source_io.is_a? StringIO
|
57
|
+
|
58
|
+
@socket.send(source_io.get, 0)
|
63
59
|
end
|
64
|
-
|
60
|
+
|
65
61
|
protected
|
66
|
-
|
62
|
+
|
67
63
|
def initialize
|
68
64
|
@socket = UDPSocket.new
|
69
|
-
|
65
|
+
configure_blocking true
|
70
66
|
end
|
67
|
+
|
71
68
|
end
|
@@ -1,10 +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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
6
|
+
require 'exceptions/steam_condenser_exception'
|
7
7
|
|
8
8
|
class PacketFormatException < SteamCondenserException
|
9
9
|
|
10
|
-
|
10
|
+
def initialize
|
11
|
+
super 'The packet data received doesn\'t match the packet format.'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -1,12 +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) 2009, Sebastian Staudt
|
4
|
+
# Copyright (c) 2009-2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'exceptions/steam_condenser_exception'
|
7
|
+
|
8
|
+
class RCONBanException < SteamCondenserException
|
5
9
|
|
6
|
-
class RCONBanException < Exception
|
7
|
-
|
8
10
|
def initialize
|
9
11
|
super 'You have been banned from this server.'
|
10
12
|
end
|
11
|
-
|
12
|
-
end
|
13
|
+
|
14
|
+
end
|
@@ -1,12 +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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'exceptions/steam_condenser_exception'
|
7
|
+
|
8
|
+
class RCONNoAuthException < SteamCondenserException
|
5
9
|
|
6
|
-
class RCONNoAuthException < Exception
|
7
|
-
|
8
10
|
def initialize
|
9
|
-
super
|
11
|
+
super 'Not authenticated yet.'
|
10
12
|
end
|
11
|
-
|
12
|
-
end
|
13
|
+
|
14
|
+
end
|
@@ -1,8 +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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require 'exceptions/steam_condenser_exception'
|
7
|
+
|
8
|
+
class TimeoutException < SteamCondenserException
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super 'The operation timed out.'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/socket_channel.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
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 'ipaddr'
|
7
7
|
require 'socket'
|
8
8
|
require 'timeout'
|
9
9
|
|
10
|
-
require '
|
10
|
+
require 'stringio_additions'
|
11
11
|
|
12
12
|
class SocketChannel
|
13
13
|
|
14
14
|
attr_reader :socket
|
15
15
|
|
16
16
|
def self.open
|
17
|
-
|
17
|
+
SocketChannel.new
|
18
18
|
end
|
19
19
|
|
20
20
|
def close
|
@@ -27,7 +27,7 @@ class SocketChannel
|
|
27
27
|
@connected = true
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
self
|
31
31
|
end
|
32
32
|
|
33
33
|
def initialize
|
@@ -35,27 +35,21 @@ class SocketChannel
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def connected?
|
38
|
-
|
38
|
+
@connected
|
39
39
|
end
|
40
40
|
|
41
41
|
def read(destination_buffer)
|
42
|
-
|
43
|
-
raise ArgumentError
|
44
|
-
end
|
45
|
-
|
46
|
-
length = destination_buffer.remaining
|
47
|
-
data = @socket.recv length
|
48
|
-
destination_buffer.put data
|
42
|
+
raise ArgumentError unless destination_buffer.is_a? StringIO
|
49
43
|
|
50
|
-
|
44
|
+
data = @socket.recv destination_buffer.remaining
|
45
|
+
length = destination_buffer.write data
|
46
|
+
destination_buffer.truncate length
|
51
47
|
end
|
52
48
|
|
53
49
|
def write(source_buffer)
|
54
|
-
|
55
|
-
raise ArgumentError
|
56
|
-
end
|
50
|
+
raise ArgumentError unless source_buffer.is_a? StringIO
|
57
51
|
|
58
|
-
|
52
|
+
@socket.send(source_buffer.get, 0)
|
59
53
|
end
|
60
54
|
|
61
55
|
end
|
@@ -30,9 +30,7 @@ module Cacheable
|
|
30
30
|
|
31
31
|
# Returns whether the requested object +id+ is already cached
|
32
32
|
def cached?(id)
|
33
|
-
if id.is_a? String
|
34
|
-
id.downcase!
|
35
|
-
end
|
33
|
+
id.downcase! if id.is_a? String
|
36
34
|
class_variable_get(:@@cache).key?(id)
|
37
35
|
end
|
38
36
|
|
@@ -59,11 +57,11 @@ module Cacheable
|
|
59
57
|
attr_reader :fetch_time
|
60
58
|
|
61
59
|
# Creates a new object for the given +id+, either numeric or
|
62
|
-
# the custom URL specified by the user. If +
|
60
|
+
# the custom URL specified by the user. If +fetch_now+ is +true+ (default),
|
63
61
|
# fetch is used to load data into the object.
|
64
62
|
# This method is overridden by Cacheable::ClassMethods#new.
|
65
|
-
def initialize(
|
66
|
-
|
63
|
+
def initialize(fetch_now = true) #:notnew:
|
64
|
+
fetch if fetch_now
|
67
65
|
cache
|
68
66
|
end
|
69
67
|
|
@@ -91,5 +89,5 @@ module Cacheable
|
|
91
89
|
def fetched?
|
92
90
|
!@fetch_time.nil?
|
93
91
|
end
|
94
|
-
|
92
|
+
|
95
93
|
end
|
@@ -0,0 +1,31 @@
|
|
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
|
+
# CSSMap holds statistical information about maps played by a player in
|
7
|
+
# Counter-Strike: Source.
|
8
|
+
class CSSMap
|
9
|
+
|
10
|
+
attr_reader :name, :rounds_lost, :rounds_played, :rounds_won,
|
11
|
+
:rounds_won_percentage
|
12
|
+
|
13
|
+
# Creates a new instance of CSSMap based on the assigned map name and XML
|
14
|
+
# data
|
15
|
+
def initialize(map_name, maps_data)
|
16
|
+
@name = map_name
|
17
|
+
|
18
|
+
@favorite = (maps_data.elements['favorite'].text == @name)
|
19
|
+
@rounds_played = maps_data.elements["#{@name}_rounds"].text.to_i
|
20
|
+
@rounds_won = maps_data.elements["#{@name}_wins"].text.to_i
|
21
|
+
|
22
|
+
@rounds_lost = @rounds_played - @rounds_won
|
23
|
+
@rounds_won_percentage = (@rounds_played > 0) ? @rounds_won.to_f / @rounds_played : 0
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns whether this map is the favorite map of this player
|
27
|
+
def favorite?
|
28
|
+
@favorite
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,116 @@
|
|
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/css/css_map'
|
7
|
+
require 'steam/community/css/css_weapon'
|
8
|
+
|
9
|
+
# The CSSStats class represents the game statistics for a single user in
|
10
|
+
# Counter-Strike: Source
|
11
|
+
class CSSStats < GameStats
|
12
|
+
|
13
|
+
MAPS = [ 'cs_assault', 'cs_compound', 'cs_havana', 'cs_italy', 'cs_militia',
|
14
|
+
'cs_office', 'de_aztec', 'de_cbble', 'de_chateau', 'de_dust',
|
15
|
+
'de_dust2', 'de_inferno', 'de_nuke', 'de_piranesi', 'de_port',
|
16
|
+
'de_prodigy', 'de_tides', 'de_train' ]
|
17
|
+
|
18
|
+
WEAPONS = [ 'deagle', 'usp', 'glock', 'p228', 'elite', 'fiveseven', 'awp',
|
19
|
+
'ak47', 'm4a1', 'aug', 'sg552', 'sg550', 'galil', 'famas',
|
20
|
+
'scout', 'g3sg1', 'p90', 'mp5navy', 'tmp', 'mac10', 'ump45',
|
21
|
+
'm3', 'xm1014', 'm249', 'knife', 'grenade' ]
|
22
|
+
|
23
|
+
attr_reader :last_match_stats, :total_stats
|
24
|
+
|
25
|
+
# Creates a CSSStats object by calling the super constructor with the game
|
26
|
+
# name "cs:s"
|
27
|
+
def initialize(steam_id)
|
28
|
+
super steam_id, 'cs:s'
|
29
|
+
|
30
|
+
if public?
|
31
|
+
@last_match_stats = {}
|
32
|
+
@total_stats = {}
|
33
|
+
|
34
|
+
@last_match_stats[:cost_per_kill] = @xml_data.elements['stats/lastmatch/costkill'].text.to_f
|
35
|
+
@last_match_stats[:ct_wins] = @xml_data.elements['stats/lastmatch/ct_wins'].text.to_i
|
36
|
+
@last_match_stats[:damage] = @xml_data.elements['stats/lastmatch/dmg'].text.to_i
|
37
|
+
@last_match_stats[:deaths] = @xml_data.elements['stats/lastmatch/deaths'].text.to_i
|
38
|
+
@last_match_stats[:dominations] = @xml_data.elements['stats/lastmatch/dominations'].text.to_i
|
39
|
+
@last_match_stats[:favorite_weapon] = @xml_data.elements['stats/lastmatch/favwpn'].text
|
40
|
+
@last_match_stats[:kills] = @xml_data.elements['stats/lastmatch/kills'].text.to_i
|
41
|
+
@last_match_stats[:max_players] = @xml_data.elements['stats/lastmatch/max_players'].text.to_i
|
42
|
+
@last_match_stats[:money] = @xml_data.elements['stats/lastmatch/money'].text.to_i
|
43
|
+
@last_match_stats[:revenges] = @xml_data.elements['stats/lastmatch/revenges'].text.to_i
|
44
|
+
@last_match_stats[:stars] = @xml_data.elements['stats/lastmatch/stars'].text.to_i
|
45
|
+
@last_match_stats[:t_wins] = @xml_data.elements['stats/lastmatch/t_wins'].text.to_i
|
46
|
+
@last_match_stats[:wins] = @xml_data.elements['stats/lastmatch/wins'].text.to_i
|
47
|
+
@total_stats[:blind_kills] = @xml_data.elements['stats/lifetime/blindkills'].text.to_i
|
48
|
+
@total_stats[:bombs_defused] = @xml_data.elements['stats/lifetime/bombsdefused'].text.to_i
|
49
|
+
@total_stats[:bombs_planted] = @xml_data.elements['stats/lifetime/bombsplanted'].text.to_i
|
50
|
+
@total_stats[:damage] = @xml_data.elements['stats/lifetime/dmg'].text.to_i
|
51
|
+
@total_stats[:deaths] = @xml_data.elements['stats/summary/deaths'].text.to_i
|
52
|
+
@total_stats[:domination_overkills] = @xml_data.elements['stats/lifetime/dominationoverkills'].text.to_i
|
53
|
+
@total_stats[:dominations] = @xml_data.elements['stats/lifetime/dominations'].text.to_i
|
54
|
+
@total_stats[:earned_money] = @xml_data.elements['stats/lifetime/money'].text.to_i
|
55
|
+
@total_stats[:enemy_weapon_kills] = @xml_data.elements['stats/lifetime/enemywpnkills'].text.to_i
|
56
|
+
@total_stats[:headshots] = @xml_data.elements['stats/lifetime/headshots'].text.to_i
|
57
|
+
@total_stats[:hits] = @xml_data.elements['stats/summary/shotshit'].text.to_i
|
58
|
+
@total_stats[:hostages_rescued] = @xml_data.elements['stats/lifetime/hostagesrescued'].text.to_i
|
59
|
+
@total_stats[:kills] = @xml_data.elements['stats/summary/kills'].text.to_i
|
60
|
+
@total_stats[:knife_kills] = @xml_data.elements['stats/lifetime/knifekills'].text.to_i
|
61
|
+
@total_stats[:logos_sprayed] = @xml_data.elements['stats/lifetime/decals'].text.to_i
|
62
|
+
@total_stats[:nightvision_damage] = @xml_data.elements['stats/lifetime/nvgdmg'].text.to_i
|
63
|
+
@total_stats[:pistol_rounds_won] = @xml_data.elements['stats/lifetime/pistolrounds'].text.to_i
|
64
|
+
@total_stats[:revenges] = @xml_data.elements['stats/lifetime/revenges'].text.to_i
|
65
|
+
@total_stats[:rounds_played] = @xml_data.elements['stats/summary/rounds'].text.to_i
|
66
|
+
@total_stats[:rounds_won] = @xml_data.elements['stats/summary/wins'].text.to_i
|
67
|
+
@total_stats[:seconds_played] = @xml_data.elements['stats/summary/timeplayed'].text.to_i
|
68
|
+
@total_stats[:shots] = @xml_data.elements['stats/summary/shots'].text.to_i
|
69
|
+
@total_stats[:stars] = @xml_data.elements['stats/summary/stars'].text.to_i
|
70
|
+
@total_stats[:weapons_donated] = @xml_data.elements['stats/lifetime/wpndonated'].text.to_i
|
71
|
+
@total_stats[:windows_broken] = @xml_data.elements['stats/lifetime/winbroken'].text.to_i
|
72
|
+
@total_stats[:zoomed_sniper_kills] = @xml_data.elements['stats/lifetime/zsniperkills'].text.to_i
|
73
|
+
|
74
|
+
@last_match_stats[:kdratio] = @last_match_stats[:kills].to_f / @last_match_stats[:deaths]
|
75
|
+
@total_stats[:accuracy] = @total_stats[:hits].to_f / @total_stats[:shots]
|
76
|
+
@total_stats[:kdratio] = @total_stats[:kills].to_f / @total_stats[:deaths]
|
77
|
+
@total_stats[:rounds_lost] = @total_stats[:rounds_played] - @total_stats[:rounds_won]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns a Hash of CSSMap for this user containing all Counter-Strike:
|
82
|
+
# Source maps. If the maps haven't been parsed already, parsing is done now.
|
83
|
+
def map_stats
|
84
|
+
return unless public?
|
85
|
+
|
86
|
+
if @map_stats.nil?
|
87
|
+
@map_stats = {}
|
88
|
+
maps_data = @xml_data.elements['stats/maps']
|
89
|
+
|
90
|
+
MAPS.each do |map_name|
|
91
|
+
@map_stats[map_name] = CSSMap.new(map_name, maps_data)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
@map_stats
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns a Hash of CSSWeapon for this user containing all Counter-Strike:
|
99
|
+
# Source weapons. If the weapons haven't been parsed already, parsing is done
|
100
|
+
# now.
|
101
|
+
def weapon_stats
|
102
|
+
return unless public?
|
103
|
+
|
104
|
+
if @weapon_stats.nil?
|
105
|
+
@weapon_stats = {}
|
106
|
+
weapons_data = @xml_data.elements['stats/weapons']
|
107
|
+
|
108
|
+
WEAPONS.each do |weapon_name|
|
109
|
+
@weapon_stats[weapon_name] = CSSWeapon.new(weapon_name, weapons_data)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
@weapon_stats
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,33 @@
|
|
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
|
+
# CSSWeapon holds statistical information about weapons used by a player in
|
7
|
+
# Counter-Strike: Source.
|
8
|
+
class CSSWeapon
|
9
|
+
|
10
|
+
attr_reader :accuracy, :hits, :name, :kills, :ksratio, :shots
|
11
|
+
|
12
|
+
# Creates a new instance of CSSWeapon based on the assigned weapon name and
|
13
|
+
# XML data
|
14
|
+
def initialize(weapon_name, weapons_data)
|
15
|
+
@name = weapon_name
|
16
|
+
|
17
|
+
@favorite = (weapons_data.elements['favorite'].text == @name)
|
18
|
+
@kills = weapons_data.elements["#{@name}_kills"].text.to_i
|
19
|
+
|
20
|
+
if @name != 'grenade' && @name != 'knife'
|
21
|
+
@hits = weapons_data.elements["#{@name}_hits"].text.to_i
|
22
|
+
@shots = weapons_data.elements["#{@name}_shots"].text.to_i
|
23
|
+
@accuracy = (@shots > 0) ? @hits.to_f / @shots : 0
|
24
|
+
@ksratio = (@shots > 0) ? @kills.to_f / @shots : 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns whether this weapon is the favorite weapon of this player
|
29
|
+
def favorite?
|
30
|
+
@favorite
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|