herostats 0.1.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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +4 -0
  4. data/CODE_OF_CONDUCT.md +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +7 -0
  7. data/README.md +34 -0
  8. data/Rakefile +10 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +7 -0
  11. data/herostats.gemspec +33 -0
  12. data/lib/heroprotocol/LICENSE +19 -0
  13. data/lib/heroprotocol/README.md +91 -0
  14. data/lib/heroprotocol/__init__.py +0 -0
  15. data/lib/heroprotocol/decoders.py +311 -0
  16. data/lib/heroprotocol/heroprotocol.py +136 -0
  17. data/lib/heroprotocol/mpyq/LICENSE +22 -0
  18. data/lib/heroprotocol/mpyq/MANIFEST.in +3 -0
  19. data/lib/heroprotocol/mpyq/README.md +202 -0
  20. data/lib/heroprotocol/mpyq/__init__.py +0 -0
  21. data/lib/heroprotocol/mpyq/mpyq.py +406 -0
  22. data/lib/heroprotocol/mpyq/setup.py +33 -0
  23. data/lib/heroprotocol/protocol29406.py +491 -0
  24. data/lib/heroprotocol/protocol30414.py +492 -0
  25. data/lib/heroprotocol/protocol30509.py +492 -0
  26. data/lib/heroprotocol/protocol30829.py +492 -0
  27. data/lib/heroprotocol/protocol30948.py +492 -0
  28. data/lib/heroprotocol/protocol31090.py +492 -0
  29. data/lib/heroprotocol/protocol31360.py +494 -0
  30. data/lib/heroprotocol/protocol31566.py +494 -0
  31. data/lib/heroprotocol/protocol31726.py +494 -0
  32. data/lib/heroprotocol/protocol31948.py +494 -0
  33. data/lib/heroprotocol/protocol32120.py +494 -0
  34. data/lib/heroprotocol/protocol32253.py +494 -0
  35. data/lib/heroprotocol/protocol32455.py +496 -0
  36. data/lib/heroprotocol/protocol32524.py +496 -0
  37. data/lib/heroprotocol/protocol33182.py +499 -0
  38. data/lib/heroprotocol/protocol33353.py +499 -0
  39. data/lib/heroprotocol/protocol33684.py +502 -0
  40. data/lib/heroprotocol/protocol34053.py +502 -0
  41. data/lib/heroprotocol/protocol34190.py +502 -0
  42. data/lib/heroprotocol/protocol34659.py +502 -0
  43. data/lib/heroprotocol/protocol34846.py +502 -0
  44. data/lib/heroprotocol/protocol35360.py +502 -0
  45. data/lib/heroprotocol/protocol35529.py +502 -0
  46. data/lib/heroprotocol/protocol35634.py +502 -0
  47. data/lib/heroprotocol/protocol35702.py +502 -0
  48. data/lib/heroprotocol/protocol36144.py +502 -0
  49. data/lib/heroprotocol/protocol36280.py +502 -0
  50. data/lib/heroprotocol/protocol36359.py +502 -0
  51. data/lib/heroprotocol/protocol36536.py +502 -0
  52. data/lib/heroprotocol/protocol36693.py +502 -0
  53. data/lib/heroprotocol/protocol37069.py +507 -0
  54. data/lib/heroprotocol/protocol37117.py +507 -0
  55. data/lib/heroprotocol/protocol37274.py +507 -0
  56. data/lib/heroprotocol/protocol37351.py +507 -0
  57. data/lib/heroprotocol/protocol37569.py +507 -0
  58. data/lib/heroprotocol/protocol37795.py +507 -0
  59. data/lib/heroprotocol/protocol38236.py +508 -0
  60. data/lib/heroprotocol/protocol38500.py +508 -0
  61. data/lib/heroprotocol/protocol38593.py +508 -0
  62. data/lib/heroprotocol/protocol38793.py +508 -0
  63. data/lib/heroprotocol/protocol39015.py +508 -0
  64. data/lib/heroprotocol/protocol39153.py +508 -0
  65. data/lib/heroprotocol/protocol39271.py +508 -0
  66. data/lib/heroprotocol/protocol39445.py +508 -0
  67. data/lib/heroprotocol/protocol39595.py +508 -0
  68. data/lib/heroprotocol/protocol39709.py +508 -0
  69. data/lib/heroprotocol/protocol39951.py +508 -0
  70. data/lib/heroprotocol/protocol40087.py +508 -0
  71. data/lib/heroprotocol/protocol40322.py +508 -0
  72. data/lib/heroprotocol/protocol40336.py +526 -0
  73. data/lib/heroprotocol/protocol40431.py +526 -0
  74. data/lib/heroprotocol/protocol40697.py +526 -0
  75. data/lib/heroprotocol/protocol40798.py +526 -0
  76. data/lib/herostats.rb +10 -0
  77. data/lib/herostats/exp_breakdown.rb +24 -0
  78. data/lib/herostats/game.rb +25 -0
  79. data/lib/herostats/init_data_parser.rb +45 -0
  80. data/lib/herostats/player.rb +25 -0
  81. data/lib/herostats/replay_parser.rb +34 -0
  82. data/lib/herostats/team.rb +10 -0
  83. data/lib/herostats/tracker_events_parser.rb +158 -0
  84. data/lib/herostats/version.rb +3 -0
  85. metadata +171 -0
@@ -0,0 +1,10 @@
1
+ require 'herostats/version'
2
+
3
+ Gem.find_files('herostats/**/*.rb').each { |path| require path }
4
+
5
+ module Herostats
6
+ def self.parse(file_path)
7
+ ReplayParser.parse(file_path)
8
+ end
9
+ end
10
+
@@ -0,0 +1,24 @@
1
+ # An ExpBreakdown represents a collection of experience sources for a given minute of game time for a team
2
+ class ExpBreakdown
3
+ #
4
+ attr_accessor :creep
5
+ attr_accessor :hero
6
+ attr_accessor :minion
7
+ attr_accessor :structure
8
+ attr_accessor :trickle
9
+ attr_accessor :time
10
+
11
+ def initialize(minion, creep, structure, hero, trickle, time)
12
+ @minion = minion
13
+ @creep = creep
14
+ @structure = structure
15
+ @hero = hero
16
+ @trickle = trickle
17
+ @time = time
18
+ end
19
+
20
+ # Returns the total experience for this breakdown
21
+ def total_exp
22
+ @minion + @creep + @structure + @hero + @trickle
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ class Game
2
+ # An Hash of Player in the current game
3
+ attr_accessor :players
4
+ # An Hash of Team in the current game
5
+ attr_accessor :teams
6
+ def initialize
7
+ @players = {}
8
+ @teams = {1 => Team.new, 2 => Team.new}
9
+ end
10
+
11
+ # Adds a player to the
12
+ # @param
13
+ def add_player(player)
14
+ @players[@players.count + 1] = player
15
+ end
16
+
17
+ # Alias for team 1
18
+ def blue_team
19
+ teams[1]
20
+ end
21
+ # Alias for team 2
22
+ def red_team
23
+ teams[2]
24
+ end
25
+ end
@@ -0,0 +1,45 @@
1
+ require 'json'
2
+
3
+ class InitDataParser
4
+ def initialize(game)
5
+ @game = game
6
+ end
7
+
8
+ def load_events(file)
9
+ file = file.read
10
+ file = file.gsub("}\n{", "},\n{")
11
+ file = file.gsub("]\n{", "],\n{")
12
+ JSON.parse("[#{file}]")
13
+ end
14
+
15
+ def parse(file)
16
+ events = load_events(file)
17
+ events.each do |event|
18
+ if event.class == Hash
19
+
20
+ event['m_syncLobbyState'].each do |k, v|
21
+ #puts v
22
+ case k
23
+ when 'm_userInitialData'
24
+ #{"m_testAuto"=>false, "m_mount"=>"", "m_observe"=>0, "m_teamPreference"=>{"m_team"=>nil}, "m_toonHandle"=>"", "m_customInterface"=>false, "m_highestLeague"=>0, "m_clanTag"=>"", "m_testMap"=>false, "m_clanLogo"=>nil, "m_examine"=>false, "m_testType"=>0, "m_combinedRaceLevels"=>4294967295, "m_randomSeed"=>0, "m_racePreference"=>{"m_race"=>nil}, "m_skin"=>"", "m_hero"=>"", "m_name"=>"Biscuit"}
25
+ v.each do |initial_data|
26
+ player = Player.new
27
+ player.name = initial_data['m_name']
28
+ puts player.name
29
+ @game.add_player(player) unless player.name.empty?
30
+ end
31
+ when 'm_lobbyState'
32
+ v['m_slots'].each_with_index do |slot, index|
33
+ @game.players[index + 1].hero = slot['m_hero'] unless index > 9
34
+ #puts "#{game.players[index].name} #{game.players[index].hero}"
35
+ #puts slot
36
+ end
37
+ when 'm_gameDescription'
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ @game
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ class Player
2
+
3
+
4
+ attr_accessor :hero, :name, :talents, :kills, :assists, :deaths, :siege_damage, :hero_damage, :damage_taken, :healing, :exp
5
+
6
+ def initialize
7
+ @talents = []
8
+ @kills = 0
9
+ @regen_globes = 0
10
+ end
11
+
12
+ def pickup_regen_globe
13
+ @regen_globes += 1
14
+ end
15
+
16
+ def select_talent(talent)
17
+ @talents.push(talent)
18
+ end
19
+
20
+ def role_stat
21
+ return healing unless healing == 0
22
+ return damage_taken unless damage_taken == 0
23
+ nil
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ require 'tempfile'
2
+
3
+ class ReplayParser
4
+ PROTOCOL_LOCATION = 'heroprotocol/heroprotocol.py'
5
+
6
+ # Returns a Game from a parse .StormReplay file
7
+ def self.parse(path)
8
+ test = File.dirname(__FILE__) + '/../heroprotocol/heroprotocol.py'
9
+
10
+
11
+ #return unless File.exist?(path)
12
+ init_data = Tempfile.new('initdata.json')
13
+ tracker_events = Tempfile.new('trackerevents.json')
14
+ system "python #{test} --initdata --json \"#{path}\" > #{init_data.path}"
15
+ system "python #{test} --trackerevents --json \"#{path}\" > #{tracker_events.path}"
16
+
17
+ game = Game.new
18
+ game = InitDataParser.new(game).parse(init_data)
19
+ game = TrackerEventsParser.new(game).parse(tracker_events)
20
+
21
+ previous = 0
22
+ points = []
23
+ #puts game.blue_team.exp_breakdowns.map { |e| e.total_exp }.join(',')
24
+ game.red_team.exp_breakdowns.each do |b|
25
+
26
+ points.push(b.total_exp - previous)
27
+ previous = b.total_exp
28
+ end
29
+
30
+ game
31
+ end
32
+ end
33
+
34
+ # ReplayParser.parse('/Users/ronaldleask/Desktop/Battlefield of Eternity (23).StormReplay')
@@ -0,0 +1,10 @@
1
+ # Represents a
2
+ class Team
3
+ # An array of ExpBreakdown for the given team
4
+ attr_accessor :exp_breakdowns
5
+
6
+ def initialize
7
+ @exp_breakdowns = []
8
+ end
9
+ end
10
+
@@ -0,0 +1,158 @@
1
+ class TrackerEventsParser
2
+ def initialize(game)
3
+ @game = game
4
+ end
5
+
6
+ def load_events(file)
7
+ file = file.read
8
+ file = file.gsub("}\n{", "},\n{")
9
+ file = file.gsub("]\n{", "],\n{")
10
+ JSON.parse("[#{file}]")
11
+ end
12
+
13
+ #
14
+ def parse(file_path)
15
+ events = load_events(file_path)
16
+
17
+ events.each do |event|
18
+ if event['_event'] == 'NNet.Replay.Tracker.SUnitBornEvent'
19
+ #u = Unit.new(event['m_unitTagIndex'],
20
+ # event['m_unitTagRecycle'],
21
+ # event['m_controlPlayerId'],
22
+ # event['_gameloop'],
23
+ # event['m_x'],
24
+ # event['m_y]'],
25
+ # event['m_upkeepPlayerId'],
26
+ # event['m_unitTypeName'])
27
+
28
+ #units[u.id] = u
29
+
30
+ #puts "#{u.name} #{u.id}"
31
+
32
+ elsif event['_event'] == 'NNet.Replay.Tracker.SStatGameEvent'
33
+
34
+ case event['m_eventName']
35
+ when 'RegenGlobePickedUp'
36
+ #game.pickup_regen_globe(event['m_intData'][0]['m_value'])
37
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"PlayerID", "m_value"=>1}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>1254, "_bits"=>472, "m_eventName"=>"RegenGlobePickedUp", "m_fixedData"=>nil}
38
+ when 'LevelUp'
39
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"PlayerID", "m_value"=>10}, {"m_key"=>"Level", "m_value"=>1}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>84, "_bits"=>512, "m_eventName"=>"LevelUp", "m_fixedData"=>nil}
40
+ #puts event
41
+
42
+ when 'PeriodicXPBreakdown'
43
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"Team", "m_value"=>1}, {"m_key"=>"TeamLevel", "m_value"=>10}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>7330, "_bits"=>1920, "m_eventName"=>"PeriodicXPBreakdown", "m_fixedData"=>[{"m_key"=>"GameTime", "m_value"=>1720320}, {"m_key"=>"PreviousGameTime", "m_value"=>1474560}, {"m_key"=>"MinionXP", "m_value"=>57368576}, {"m_key"=>"CreepXP", "m_value"=>618496}, {"m_key"=>"StructureXP", "m_value"=>3276800}, {"m_key"=>"HeroXP", "m_value"=>6882750}, {"m_key"=>"TrickleXP", "m_value"=>31539200}]}
44
+ puts event
45
+ team_number = event['m_intData'].detect { |hash| hash['m_key'] == 'Team'}['m_value']
46
+ fixed_data = event['m_fixedData']
47
+ minion_exp = 0
48
+ creep_exp = 0
49
+ structure_exp = 0
50
+ hero_exp = 0
51
+ trickle_exp = 0
52
+ time = 0
53
+
54
+ fixed_data.each do |data|
55
+ case data['m_key']
56
+ when 'MinionXP'
57
+ minion_exp = data['m_value'] / 4096
58
+ when 'CreepXP'
59
+ creep_exp = data['m_value'] / 4096
60
+ when 'StructureXP'
61
+ structure_exp = data['m_value'] / 4096
62
+ when 'HeroXP'
63
+ hero_exp = data['m_value'] / 4096
64
+ when 'TrickleXP'
65
+ trickle_exp = data['m_value'] / 4096
66
+ when 'GameTime'
67
+ time = data['m_value'] / 4096
68
+ else
69
+ puts data
70
+ end
71
+ end
72
+
73
+ @game.teams[team_number].exp_breakdowns.push(ExpBreakdown.new(minion_exp, creep_exp, structure_exp, hero_exp, trickle_exp, time))
74
+
75
+ when 'GatesOpen'
76
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>nil, "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>610, "_bits"=>240, "m_eventName"=>"GatesOpen", "m_fixedData"=>nil}
77
+ #puts event
78
+ when 'TalentChosen'
79
+ #{"_eventid"=>10, "m_stringData"=>[{"m_key"=>"PurchaseName", "m_value"=>"GenericTalentBlock"}], "m_intData"=>[{"m_key"=>"PlayerID", "m_value"=>2}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>522, "_bits"=>776, "m_eventName"=>"TalentChosen", "m_fixedData"=>nil}
80
+ player_number = event['m_intData'].detect { |hash| hash['m_key'] == 'PlayerID'}['m_value']
81
+ talent_name = event['m_stringData'].detect { |hash| hash['m_key'] == 'PurchaseName'}['m_value']
82
+ @game.players[player_number].select_talent(talent_name)
83
+ when 'PlayerDeath'
84
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"PlayerID", "m_value"=>7}, {"m_key"=>"KillingPlayer", "m_value"=>1}, {"m_key"=>"KillingPlayer", "m_value"=>4}, {"m_key"=>"KillingPlayer", "m_value"=>5}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>2692, "_bits"=>1360, "m_eventName"=>"PlayerDeath", "m_fixedData"=>[{"m_key"=>"PositionX", "m_value"=>549022}, {"m_key"=>"PositionY", "m_value"=>709147}]}
85
+ when 'TownStructureDeath'
86
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"TownID", "m_value"=>9}, {"m_key"=>"KillingPlayer", "m_value"=>1}, {"m_key"=>"KillingPlayer", "m_value"=>2}, {"m_key"=>"KillingPlayer", "m_value"=>4}, {"m_key"=>"KillingPlayer", "m_value"=>5}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>18584, "_bits"=>1224, "m_eventName"=>"TownStructureDeath", "m_fixedData"=>nil}
87
+ when 'RavenCurseActivated'
88
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"Event", "m_value"=>2}, {"m_key"=>"TeamScore", "m_value"=>3}, {"m_key"=>"OpponentScore", "m_value"=>2}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>18044, "_bits"=>968, "m_eventName"=>"RavenCurseActivated", "m_fixedData"=>[{"m_key"=>"TeamID", "m_value"=>4096}]}
89
+ when 'TributeCollected'
90
+ #{"_eventid"=>10, "m_stringData"=>nil, "m_intData"=>[{"m_key"=>"Event", "m_value"=>1}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>4221, "_bits"=>600, "m_eventName"=>"TributeCollected", "m_fixedData"=>[{"m_key"=>"TeamID", "m_value"=>8192}]}
91
+
92
+ when 'JungleCampCapture'
93
+ #{"_eventid"=>10, "m_stringData"=>[{"m_key"=>"CampType", "m_value"=>"Bruiser Camp"}], "m_intData"=>[{"m_key"=>"CampID", "m_value"=>2}], "_event"=>"NNet.Replay.Tracker.SStatGameEvent", "_gameloop"=>18252, "_bits"=>872, "m_eventName"=>"JungleCampCapture", "m_fixedData"=>[{"m_key"=>"TeamID", "m_value"=>4096}]}
94
+ else
95
+ #puts event
96
+ end
97
+ elsif event['_event'] == 'NNet.Replay.Tracker.SUnitDiedEvent'
98
+ #puts event
99
+ elsif event['_event'] == 'NNet.Replay.Tracker.SUnitOwnerChangeEvent'
100
+ elsif event['_event'] == 'NNet.Replay.Tracker.SUnitRevivedEvent'
101
+
102
+ elsif event['_event'] == 'NNet.Replay.Tracker.SScoreResultEvent'
103
+ event['m_instanceList'].each do |list|
104
+ puts list['m_name']
105
+ case list['m_name']
106
+ when 'SoloKill'
107
+ list['m_values'].each_with_index do |v, index|
108
+ @game.players[index + 1].kills = v[0]['m_value'] unless index > 9
109
+ end
110
+ when 'Deaths'
111
+ list['m_values'].each_with_index do |v, index|
112
+ @game.players[index + 1].deaths = v[0]['m_value'] unless index > 9
113
+ end
114
+ when 'Assists'
115
+ list['m_values'].each_with_index do |v, index|
116
+ @game.players[index + 1].assists = v[0]['m_value'] unless index > 9
117
+ end
118
+ when 'SiegeDamage'
119
+ list['m_values'].each_with_index do |v, index|
120
+ @game.players[index + 1].siege_damage = v[0]['m_value'] unless index > 9
121
+ end
122
+ when 'HeroDamage'
123
+ list['m_values'].each_with_index do |v, index|
124
+ @game.players[index + 1].hero_damage = v[0]['m_value'] unless index > 9
125
+ end
126
+ when 'ExperienceContribution'
127
+ list['m_values'].each_with_index do |v, index|
128
+ @game.players[index + 1].exp = v[0]['m_value'] unless index > 9
129
+ end
130
+ when 'DamageTaken'
131
+ list['m_values'].each_with_index do |v, index|
132
+ @game.players[index + 1].damage_taken = v[0]['m_value'] unless index > 9
133
+ end
134
+ when 'Healing'
135
+ list['m_values'].each_with_index do |v, index|
136
+ #puts v
137
+ @game.players[index + 1].healing = v[0]['m_value'] unless index > 9
138
+ end
139
+ when 'SelfHealing'
140
+ list['m_values'].each_with_index do |v, index|
141
+ #puts v
142
+ #@game.players[index + 1].healing = v[0]['m_value'] unless index > 9
143
+ end
144
+ else
145
+ list['m_values'].each_with_index do |v, index|
146
+ #puts v
147
+ end
148
+ end
149
+
150
+ end
151
+ #puts event
152
+ else
153
+ #puts event
154
+ end
155
+ end
156
+ @game
157
+ end
158
+ end
@@ -0,0 +1,3 @@
1
+ module Herostats
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: herostats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ronald Leask
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.8'
55
+ description: Ruby library for extracting important statistics from Heroes of the Storm
56
+ replays
57
+ email:
58
+ - ronald.leask@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".travis.yml"
65
+ - CODE_OF_CONDUCT.md
66
+ - Gemfile
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - herostats.gemspec
73
+ - lib/heroprotocol/LICENSE
74
+ - lib/heroprotocol/README.md
75
+ - lib/heroprotocol/__init__.py
76
+ - lib/heroprotocol/decoders.py
77
+ - lib/heroprotocol/heroprotocol.py
78
+ - lib/heroprotocol/mpyq/LICENSE
79
+ - lib/heroprotocol/mpyq/MANIFEST.in
80
+ - lib/heroprotocol/mpyq/README.md
81
+ - lib/heroprotocol/mpyq/__init__.py
82
+ - lib/heroprotocol/mpyq/mpyq.py
83
+ - lib/heroprotocol/mpyq/setup.py
84
+ - lib/heroprotocol/protocol29406.py
85
+ - lib/heroprotocol/protocol30414.py
86
+ - lib/heroprotocol/protocol30509.py
87
+ - lib/heroprotocol/protocol30829.py
88
+ - lib/heroprotocol/protocol30948.py
89
+ - lib/heroprotocol/protocol31090.py
90
+ - lib/heroprotocol/protocol31360.py
91
+ - lib/heroprotocol/protocol31566.py
92
+ - lib/heroprotocol/protocol31726.py
93
+ - lib/heroprotocol/protocol31948.py
94
+ - lib/heroprotocol/protocol32120.py
95
+ - lib/heroprotocol/protocol32253.py
96
+ - lib/heroprotocol/protocol32455.py
97
+ - lib/heroprotocol/protocol32524.py
98
+ - lib/heroprotocol/protocol33182.py
99
+ - lib/heroprotocol/protocol33353.py
100
+ - lib/heroprotocol/protocol33684.py
101
+ - lib/heroprotocol/protocol34053.py
102
+ - lib/heroprotocol/protocol34190.py
103
+ - lib/heroprotocol/protocol34659.py
104
+ - lib/heroprotocol/protocol34846.py
105
+ - lib/heroprotocol/protocol35360.py
106
+ - lib/heroprotocol/protocol35529.py
107
+ - lib/heroprotocol/protocol35634.py
108
+ - lib/heroprotocol/protocol35702.py
109
+ - lib/heroprotocol/protocol36144.py
110
+ - lib/heroprotocol/protocol36280.py
111
+ - lib/heroprotocol/protocol36359.py
112
+ - lib/heroprotocol/protocol36536.py
113
+ - lib/heroprotocol/protocol36693.py
114
+ - lib/heroprotocol/protocol37069.py
115
+ - lib/heroprotocol/protocol37117.py
116
+ - lib/heroprotocol/protocol37274.py
117
+ - lib/heroprotocol/protocol37351.py
118
+ - lib/heroprotocol/protocol37569.py
119
+ - lib/heroprotocol/protocol37795.py
120
+ - lib/heroprotocol/protocol38236.py
121
+ - lib/heroprotocol/protocol38500.py
122
+ - lib/heroprotocol/protocol38593.py
123
+ - lib/heroprotocol/protocol38793.py
124
+ - lib/heroprotocol/protocol39015.py
125
+ - lib/heroprotocol/protocol39153.py
126
+ - lib/heroprotocol/protocol39271.py
127
+ - lib/heroprotocol/protocol39445.py
128
+ - lib/heroprotocol/protocol39595.py
129
+ - lib/heroprotocol/protocol39709.py
130
+ - lib/heroprotocol/protocol39951.py
131
+ - lib/heroprotocol/protocol40087.py
132
+ - lib/heroprotocol/protocol40322.py
133
+ - lib/heroprotocol/protocol40336.py
134
+ - lib/heroprotocol/protocol40431.py
135
+ - lib/heroprotocol/protocol40697.py
136
+ - lib/heroprotocol/protocol40798.py
137
+ - lib/herostats.rb
138
+ - lib/herostats/exp_breakdown.rb
139
+ - lib/herostats/game.rb
140
+ - lib/herostats/init_data_parser.rb
141
+ - lib/herostats/player.rb
142
+ - lib/herostats/replay_parser.rb
143
+ - lib/herostats/team.rb
144
+ - lib/herostats/tracker_events_parser.rb
145
+ - lib/herostats/version.rb
146
+ homepage: https://github.com/Helais/herostats
147
+ licenses:
148
+ - MIT
149
+ metadata:
150
+ allowed_push_host: https://rubygems.org
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.4.5.1
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Ruby library for extracting stats from Heroes of the Storm replays
171
+ test_files: []