Class: GamespyQuery::Parser
Constant Summary collapse
- STR_SPLIT =
STR_X0
- STR_ID =
"\x00\x04\x05\x06\a"
- RX_SPLITNUM =
/^splitnum\x00(.)/i
- RX_PLAYER_HEADER =
/\x01/
- RX_END =
/\x00\x02$/
- RX_PLAYER_EMPTY =
/^player_\x00\x00\x00/
- RX_PLAYER_INFO =
x00 from previous packet, x01 from continueing player info, (.) - should it overwrite previous value?
/\x01(team|player|score|deaths)_.(.)/
- STR_DEATHS =
"deaths_\x00\x00"
- STR_PLAYER =
"player_\x00\x00"
- STR_TEAM =
"team_\x00\x00"
- STR_SCORE =
"score_\x00\x00"
- STR_SIX =
"$SIX_OVERWRITE_PREVIOUS$"
- STR_SIX_X0 =
"\x00#{STR_SIX}\x00"
Constants included from Funcs
Funcs::RX_F, Funcs::RX_I, Funcs::RX_S
Class Method Summary collapse
-
.pretty_player_data(data) ⇒ Object
Hash of Hashes.
-
.pretty_player_data2(data) ⇒ Object
Array of Hashes.
Instance Method Summary collapse
- #clean_packet(packet) ⇒ Object
-
#initialize(packets) ⇒ Parser
constructor
packets: - Hash, key: packetID, value: packetDATA or - Array, packetDATA ordered already by packetID.
-
#parse ⇒ Object
Returns Hash with parsed data (:game and :players) :game => Hash, Key: InfoKey, Value: InfoValue :players => Hash, Key: InfoType, Value: Array of Values.
- #parse_game_data(packet) ⇒ Object
-
#parse_player_data(packet) ⇒ Object
TODO: Cleanup.
Methods included from Funcs
#clean, #clean_string, #get_string, #handle_chr, #strip_tags
Constructor Details
#initialize(packets) ⇒ Parser
packets:
- Hash, key: packetID, value: packetDATA
or
- Array, packetDATA ordered already by packetID
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/gamespy_query/parser.rb', line 25 def initialize(packets) @packets = case packets when Hash packets.keys.sort.map{|key| packets[key] } when Array packets else raise "Unsupported format" end end |
Class Method Details
.pretty_player_data(data) ⇒ Object
Hash of Hashes
186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/gamespy_query/parser.rb', line 186 def self.pretty_player_data(data) player_data = {} data[:names].each_with_index do |name, index| player_data[name] = {} player_data[name][:team] = data[:teams][index] player_data[name][:score] = data[:scores][index] player_data[name][:deaths] = data[:deaths][index] end player_data end |
.pretty_player_data2(data) ⇒ Object
Array of Hashes
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/gamespy_query/parser.rb', line 200 def self.pretty_player_data2(data) player_data = [] data[:names].each_with_index do |name, index| player = {} player[:name] = name player[:team] = data[:teams][index] player[:score] = data[:scores][index] player[:deaths] = data[:deaths][index] player_data << player end player_data end |
Instance Method Details
#clean_packet(packet) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/gamespy_query/parser.rb', line 77 def clean_packet(packet) packet = packet.clone packet.sub!(STR_ID, STR_EMPTY) # Cut off the identity packet.sub!(RX_SPLITNUM, STR_EMPTY) # Cut off the splitnum packet.sub!(RX_X0_E, STR_EMPTY) # Cut off last \x00 packet.sub!(RX_X0_S, STR_EMPTY) # Cut off first \x00 packet.sub!(RX_END, STR_EMPTY) # Cut off the last \x00\x02 # Encoding get_string(packet) end |
#parse ⇒ Object
Returns Hash with parsed data (:game and :players) :game => Hash, Key: InfoKey, Value: InfoValue :players => Hash, Key: InfoType, Value: Array of Values
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/gamespy_query/parser.rb', line 39 def parse data = {} data[:game] = {} # Key: InfoKey, Value: InfoValue data[:players] = {} # Key: InfoType, Value: Array of Values player_info = false player_data = "" # Parse the packets @packets.each do |packet| packet = clean_packet(packet) if player_info # Player header was found before, add packet to player_data player_data += packet else if packet =~ RX_PLAYER_HEADER # Found Player header, packet possibly contains partial gamedata too player_info = true packets = packet.split(RX_PLAYER_HEADER, 2) # Parse last game_data piece if available data[:game].merge!(parse_game_data(packets[0])) unless packets[0].empty? # Collect the player_data if available player_data += packets[1] else # GameData-only data[:game].merge!(parse_game_data(packet)) end end end # Parse player_data data[:players] = parse_player_data(player_data) data end |
#parse_game_data(packet) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/gamespy_query/parser.rb', line 89 def parse_game_data(packet) Tools.debug {"Game Parsing #{packet.inspect}"} key = nil game_data = {} packet.split(STR_SPLIT).each_with_index do |data, index| if (index % 2) == 0 key = clean_string data else game_data[key] = data.is_a?(String) ? clean_string(data) : data end end game_data end |
#parse_player_data(packet) ⇒ Object
TODO: Cleanup
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/gamespy_query/parser.rb', line 116 def parse_player_data(packet) Tools.debug {"Player Parsing #{packet.inspect}"} player_data = {:names => [], :teams => [], :scores => [], :deaths => []} # [[], [], [], []] return player_data if packet.nil? || packet.empty? data = packet.clone unless data =~ RX_PLAYER_EMPTY # Leave out the character or Replace character with special string later used to replace the previous value data.sub!(RX_PLAYER_INFO) { |r| str = $1 if $2 == STR_X0 # If a proper primary info header of this type was not yet found, replace this secondary header with a proper primary header # This will add the broken info header to the previous info list (name for team, team for score, score for deaths) # However the resulting arrays are limited to num_players, so the info is discared anyway. # TODO: Cleaner implementation! data =~ /(^|[^\x01])#{Regexp.escape(str)}_\x00\x00/ ? STR_X0 : :"#{str}_\x00\x00" else STR_SIX_X0 end } data, deaths = data.split(STR_DEATHS, 2) data, scores = data.split(STR_SCORE, 2) data, teams = data.split(STR_TEAM, 2) data, names = data.split(STR_PLAYER, 2) orig_data = [names, teams, scores, deaths] # TODO: Handle seperate score orig_data.each_with_index do |data, i| next if data.nil? || data.empty? str = data.clone str.sub!(RX_X0_E, STR_EMPTY) # Remove last \x00 # Parse the data - \x00 is printed after a non-nil entry, otherwise \x00 means nil (e.g empty team) until str.empty? entry = str[RX_X0_SPEC] player_data[player_data.keys[i]] << clean_string(entry.sub(STR_X0, STR_EMPTY)) str.sub!(entry, STR_EMPTY) end # Search for SIX string to overwrite last entry new_player_data = [] overwrite = false player_data[player_data.keys[i]].each do |info| if info == STR_SIX overwrite = true # tag so that the next entry will overwrite the latest entry next # ignore else if overwrite new_player_data[-1] = info # Overwrite latest entry overwrite = false # done the overwrite else #break if new_player_data.size == num_players new_player_data << info # insert entry end end end player_data[player_data.keys[i]] = new_player_data end end player_data end |