sc2ai 0.0.0.pre → 0.0.2

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/data/data.json +1 -0
  3. data/data/data_readable.json +22842 -0
  4. data/data/sc2ai/protocol/common.proto +59 -0
  5. data/data/sc2ai/protocol/data.proto +120 -0
  6. data/data/sc2ai/protocol/debug.proto +127 -0
  7. data/data/sc2ai/protocol/error.proto +221 -0
  8. data/data/sc2ai/protocol/query.proto +55 -0
  9. data/data/sc2ai/protocol/raw.proto +202 -0
  10. data/data/sc2ai/protocol/sc2api.proto +718 -0
  11. data/data/sc2ai/protocol/score.proto +108 -0
  12. data/data/sc2ai/protocol/spatial.proto +115 -0
  13. data/data/sc2ai/protocol/ui.proto +145 -0
  14. data/data/setup/setup.SC2Map +0 -0
  15. data/data/setup/setup.SC2Replay +0 -0
  16. data/data/stableid.json +35730 -0
  17. data/data/versions.json +554 -0
  18. data/exe/sc2ai +35 -0
  19. data/lib/docker_build/Dockerfile.ruby +74 -0
  20. data/lib/docker_build/docker-compose-base-image.yml +10 -0
  21. data/lib/docker_build/docker-compose-ladderzip.yml +9 -0
  22. data/lib/sc2ai/api/ability_id.rb +1644 -0
  23. data/lib/sc2ai/api/buff_id.rb +306 -0
  24. data/lib/sc2ai/api/data.rb +101 -0
  25. data/lib/sc2ai/api/effect_id.rb +20 -0
  26. data/lib/sc2ai/api/tech_tree.rb +83 -0
  27. data/lib/sc2ai/api/tech_tree_data.rb +2338 -0
  28. data/lib/sc2ai/api/unit_type_id.rb +2022 -0
  29. data/lib/sc2ai/api/upgrade_id.rb +310 -0
  30. data/lib/sc2ai/cli/cli.rb +175 -0
  31. data/lib/sc2ai/cli/ladderzip.rb +154 -0
  32. data/lib/sc2ai/cli/new.rb +88 -0
  33. data/lib/sc2ai/configuration.rb +145 -0
  34. data/lib/sc2ai/connection/connection_listener.rb +30 -0
  35. data/lib/sc2ai/connection/requests.rb +417 -0
  36. data/lib/sc2ai/connection/status_listener.rb +15 -0
  37. data/lib/sc2ai/connection.rb +146 -0
  38. data/lib/sc2ai/local_play/client/configurable_options.rb +115 -0
  39. data/lib/sc2ai/local_play/client.rb +159 -0
  40. data/lib/sc2ai/local_play/client_manager.rb +70 -0
  41. data/lib/sc2ai/local_play/map_file.rb +48 -0
  42. data/lib/sc2ai/local_play/match.rb +184 -0
  43. data/lib/sc2ai/overrides/array.rb +14 -0
  44. data/lib/sc2ai/overrides/async/process/child.rb +31 -0
  45. data/lib/sc2ai/overrides/kernel.rb +33 -0
  46. data/lib/sc2ai/paths.rb +294 -0
  47. data/lib/sc2ai/player/actions.rb +386 -0
  48. data/lib/sc2ai/player/debug.rb +224 -0
  49. data/lib/sc2ai/player/game_state.rb +131 -0
  50. data/lib/sc2ai/player/geometry.rb +766 -0
  51. data/lib/sc2ai/player/previous_state.rb +49 -0
  52. data/lib/sc2ai/player/units.rb +337 -0
  53. data/lib/sc2ai/player.rb +661 -0
  54. data/lib/sc2ai/ports.rb +152 -0
  55. data/lib/sc2ai/protocol/_meta_documentation.rb +39 -0
  56. data/lib/sc2ai/protocol/common_pb.rb +43 -0
  57. data/lib/sc2ai/protocol/data_pb.rb +47 -0
  58. data/lib/sc2ai/protocol/debug_pb.rb +56 -0
  59. data/lib/sc2ai/protocol/error_pb.rb +36 -0
  60. data/lib/sc2ai/protocol/extensions/color.rb +20 -0
  61. data/lib/sc2ai/protocol/extensions/point.rb +23 -0
  62. data/lib/sc2ai/protocol/extensions/point_2_d.rb +26 -0
  63. data/lib/sc2ai/protocol/extensions/position.rb +202 -0
  64. data/lib/sc2ai/protocol/extensions/power_source.rb +19 -0
  65. data/lib/sc2ai/protocol/extensions/unit.rb +489 -0
  66. data/lib/sc2ai/protocol/query_pb.rb +47 -0
  67. data/lib/sc2ai/protocol/raw_pb.rb +57 -0
  68. data/lib/sc2ai/protocol/sc2api_pb.rb +130 -0
  69. data/lib/sc2ai/protocol/score_pb.rb +40 -0
  70. data/lib/sc2ai/protocol/spatial_pb.rb +48 -0
  71. data/lib/sc2ai/protocol/ui_pb.rb +56 -0
  72. data/lib/sc2ai/unit_group/action_ext.rb +74 -0
  73. data/lib/sc2ai/unit_group/filter_ext.rb +379 -0
  74. data/lib/sc2ai/unit_group.rb +277 -0
  75. data/lib/sc2ai/version.rb +2 -1
  76. data/lib/sc2ai.rb +93 -2
  77. data/lib/templates/ladderzip/bin/ladder.tt +23 -0
  78. data/lib/templates/new/.ladderignore +20 -0
  79. data/lib/templates/new/Gemfile.tt +7 -0
  80. data/lib/templates/new/api/common.proto +59 -0
  81. data/lib/templates/new/api/data.proto +120 -0
  82. data/lib/templates/new/api/debug.proto +127 -0
  83. data/lib/templates/new/api/error.proto +221 -0
  84. data/lib/templates/new/api/query.proto +55 -0
  85. data/lib/templates/new/api/raw.proto +202 -0
  86. data/lib/templates/new/api/sc2api.proto +718 -0
  87. data/lib/templates/new/api/score.proto +108 -0
  88. data/lib/templates/new/api/spatial.proto +115 -0
  89. data/lib/templates/new/api/ui.proto +145 -0
  90. data/lib/templates/new/boot.rb.tt +6 -0
  91. data/lib/templates/new/my_bot.rb.tt +23 -0
  92. data/lib/templates/new/run_example_match.rb.tt +14 -0
  93. data/sc2ai.gemspec +80 -0
  94. metadata +344 -13
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sc2
4
+ class Player
5
+ # Container for the previous game state, based on current bot state
6
+ # Keep to one instance, but with variables to prevent large memory leaks
7
+ # @see Sc2::Player::GameState for current state
8
+ class PreviousState
9
+ include GameState
10
+ include Units
11
+
12
+ # Sets the previous state of the bot using the last frame
13
+ # @param bot [Sc2::Player::Bot]
14
+ def reset(bot)
15
+ before_reset(bot)
16
+ @all_units = bot.all_units
17
+ @units = bot.units
18
+ @structures = bot.structures
19
+ @neutral = bot.neutral
20
+ @effects = bot.effects
21
+ @power_sources = bot.power_sources
22
+ @radar_rings = bot.radar_rings
23
+
24
+ @status = bot.status
25
+ @game_info = bot.game_info
26
+ @observation = bot.observation
27
+
28
+ @spent_minerals = bot.spent_minerals
29
+ @spent_vespene = bot.spent_vespene
30
+ @spent_supply = bot.spent_supply
31
+ # Skipping unnecessary bloat: event_*, chats_received, ...
32
+
33
+ after_reset(bot)
34
+ end
35
+
36
+ # Override to modify the previous frame before being set to current
37
+ # @param bot [Sc2::Player::Bot]
38
+ def before_reset(bot)
39
+ # pp "### before_reset"
40
+ end
41
+
42
+ # Override to modify previous frame after reset is complete
43
+ # @param bot [Sc2::Player::Bot]
44
+ def after_reset(bot)
45
+ # pp "### after_reset"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sc2
4
+ class Player
5
+ # Helper methods for working with units
6
+ module Units
7
+ # @!attribute all_units
8
+ # @return [Sc2::UnitGroup]
9
+ attr_accessor :all_units
10
+
11
+ # A full list of all your units (non-structure)
12
+ # @!attribute units
13
+ # @return [Sc2::UnitGroup] a group of units
14
+ attr_accessor :units
15
+
16
+ # A full list of all your structures (non-units)
17
+ # @!attribute units
18
+ # @return [Sc2::UnitGroup] a group of units
19
+ attr_accessor :structures
20
+
21
+ # All units with alliance :Neutral
22
+ # @!attribute neutral
23
+ # @return [Sc2::UnitGroup] a group of neutral units
24
+ attr_accessor :neutral
25
+
26
+ # An array of effects such as Scan, Storm, Corrosive Bile, Lurker Spike, etc.
27
+ # They typically have a position on the map and may be persistent or temporary.
28
+ # Shorthand for observation.raw_data.effects
29
+ # @!attribute effects
30
+ # @return [Sc2::UnitGroup] a group of neutral units
31
+ attr_accessor :effects # not a unit
32
+
33
+ # An array of Protoss power sources, which have a point, radius and unit tag
34
+ # @!attribute power_sources
35
+ # @return [Array<Api::PowerSource>] an array of power sources
36
+ attr_accessor :power_sources # not a unit but has a tag
37
+
38
+ # An array of Sensor tower rings as per minimap. It has a `pos` and a `radius`
39
+ # @!attribute power_sources
40
+ # @return [Array<Api::RadarRing>] an array of power sources
41
+ attr_accessor :radar_rings # not a unit but has a tag
42
+
43
+ # @private
44
+ # @!attribute all_seen_unit_tags
45
+ # Privately keep track of all seen Unit tags (excl structures) in order to detect new created units
46
+ attr_accessor :_all_seen_unit_tags
47
+
48
+ # Event-driven unit groups ---
49
+
50
+ # Units created since last frame (visible only, units not structures)
51
+ # Read this on_step. Alternative to callback on_unit_created
52
+ # Note: Morphed units should watch #event_units_type_changed
53
+ # @!attribute event_units_created
54
+ # @return [Sc2::UnitGroup] group of created units
55
+ attr_accessor :event_units_created
56
+
57
+ # Units which had their type changed since last frame
58
+ # Read this on_step. Alternative to callback on_unit_type_changed
59
+ # @!attribute event_units_type_changed
60
+ # @return [Sc2::UnitGroup] group effected
61
+ attr_accessor :event_units_type_changed
62
+
63
+ # Structures seen since last frame with building not completed (< 1.0)
64
+ # Read this on_step. Alternative to callback on_structure_started
65
+ # @!attribute event_structures_started
66
+ # @return [Sc2::UnitGroup] a group of structures started
67
+ attr_accessor :event_structures_started
68
+
69
+ # Structures which had their building completed (==1.0) since last frame
70
+ # Read this on_step. Alternative to callback on_structure_completed
71
+ # @!attribute event_structures_completed
72
+ # @return [Sc2::UnitGroup] a group of structures started
73
+ attr_accessor :event_structures_completed
74
+
75
+ # Units and Structures which had their health/shields reduced since last frame
76
+ # Read this on_step. Alternative to callback on_unit_damaged
77
+ # @!attribute event_units_damaged
78
+ # @return [Sc2::UnitGroup] group of Units and Structures effected
79
+ attr_accessor :event_units_damaged
80
+
81
+ # Units destroyed since last frame (known units only, i.e. not projectiles)
82
+ # Read this on_step. Alternative to callback on_unit_destroyed
83
+ # @!attribute event_units_destroyed
84
+ # @return [Sc2::UnitGroup] group of dead units
85
+ attr_accessor :event_units_destroyed
86
+
87
+ # TODO: Unit buff disabled, because it calls back too often (mineral in hand). Put back if useful
88
+ # @private
89
+ # Units (Unit/Structure) on which a new buff_ids appeared this frame
90
+ # See which buffs via: unit.buff_ids - unit.previous.buff_ids
91
+ # Read this on_step. Alternative to callback on_unit_buffed
92
+ # @!attribute event_units_destroyed
93
+ # attr_accessor :event_units_buffed
94
+
95
+ # Returns static [Api::UnitTypeData] for a unit
96
+ # @param unit [Integer,Api::Unit] Api::UnitTypeId or Api::Unit
97
+ # @return [Api::UnitTypeData]
98
+ def unit_data(unit)
99
+ id = unit.is_a?(Integer) ? unit : unit.unit_type
100
+ data.units[id]
101
+ end
102
+
103
+ # Returns static [Api::AbilityData] for an ability
104
+ # @param ability_id [Integer] Api::AbilityId::*
105
+ # @return [Api::AbilityData]
106
+ def ability_data(ability_id)
107
+ data.abilities[ability_id]
108
+ end
109
+
110
+ # Checks unit data for an attribute value
111
+ # @param unit [Integer,Api::Unit] Api::UnitTypeId or Api::Unit
112
+ # @param attribute [Symbol] Api::Attribute, i.e. Api::Attribute::Mechanical or :Mechanical
113
+ # @return [Boolean] whether unit has attribute
114
+ # @example
115
+ # unit_has_attribute?(Api::UnitTypeId::SCV, Api::Attribute::Mechanical)
116
+ # unit_has_attribute?(units.workers.first, :Mechanical)
117
+ # unit_has_attribute?(Api::UnitTypeId::SCV, :Mechanical)
118
+ def unit_has_attribute?(unit, attribute)
119
+ unit_data(unit).attributes.include? attribute
120
+ end
121
+
122
+ # Creates a unit group from all_units with matching tag
123
+ # @param tags [Array<Integer>] array of unit tags
124
+ # @return [Sc2::UnitGroup]
125
+ def unit_group_from_tags(tags)
126
+ return unless tags.is_a? Array
127
+
128
+ ug = UnitGroup.new
129
+ tags.each do |tag|
130
+ ug.add(@all_units[tag])
131
+ end
132
+ ug
133
+ end
134
+
135
+ # Geo/Map/Macro ------
136
+
137
+ # @private
138
+ # Sums the cost (mineral/vespene/supply) of unit type used for internal spend trackers
139
+ # This is called internally when building/morphing/training
140
+ # @return [void]
141
+ def subtract_cost(unit_type_id)
142
+ unit_type_data = unit_data(unit_type_id)
143
+
144
+ # food_required is a float. ensure half units are counted as full
145
+ # TODO: Extend UnitTypeData message. def food_required = unit_id == Api::UnitTypeId::ZERGLING ? 1 : send("method_missing", :food_required)
146
+ supply_cost = unit_type_data.food_required
147
+ supply_cost = 1 if unit_type_id == Api::UnitTypeId::ZERGLING
148
+
149
+ @spent_minerals += unit_type_data.mineral_cost
150
+ @spent_vespene += unit_type_data.vespene_cost
151
+ @spent_supply += supply_cost
152
+ end
153
+
154
+ # Checks whether you have the resources to construct quantity of unit type
155
+ def can_afford?(unit_type_id:, quantity: 1)
156
+ unit_type_data = unit_data(unit_type_id)
157
+ return false if unit_type_data.nil?
158
+
159
+ mineral_cost = unit_type_data.mineral_cost * quantity
160
+ if common.minerals - spent_minerals < mineral_cost
161
+ return false # not enough minerals
162
+ end
163
+
164
+ vespene_cost = unit_type_data.vespene_cost * quantity
165
+ if common.vespene - spent_vespene < vespene_cost
166
+ return false # you require more vespene gas
167
+ end
168
+
169
+ supply_cost = unit_type_data.food_required
170
+ supply_cost = 1 if unit_type_id == Api::UnitTypeId::ZERGLING
171
+ supply_cost *= quantity
172
+
173
+ free_supply = common.food_cap - common.food_used
174
+ if free_supply - spent_supply < supply_cost
175
+ return false # you must construct additional pylons
176
+ end
177
+
178
+ true
179
+ end
180
+
181
+ private
182
+
183
+ # @private
184
+ # Divides raw data units into various attributes on every step
185
+ # Note, this needs to be fast.
186
+ # @param observation [Api::Observation]
187
+ def parse_observation_units(observation)
188
+ @all_units = UnitGroup.new(observation.raw_data.units)
189
+ # Clear previous units and prep for categorization
190
+ @units = UnitGroup.new
191
+ @structures = UnitGroup.new
192
+ @enemy.units = UnitGroup.new
193
+ @enemy.structures = UnitGroup.new
194
+ @neutral = UnitGroup.new
195
+ @effects = observation.raw_data.effects # not a unit
196
+ @power_sources = observation.raw_data.player.power_sources # not a unit
197
+ @radar_rings = observation.raw_data.radar
198
+ @blips = UnitGroup.new
199
+
200
+ # Unit tag tracking
201
+ @_all_seen_unit_tags ||= Set.new(@units.tags)
202
+
203
+ # Event-driven unit groups as callback alternatives
204
+ @event_units_created = UnitGroup.new
205
+ @event_structures_started = UnitGroup.new
206
+ @event_structures_completed = UnitGroup.new
207
+ @event_units_type_changed = UnitGroup.new
208
+ @event_units_damaged = UnitGroup.new
209
+ # @event_units_buffed = UnitGroup.new
210
+
211
+ # Categorization of self/enemy, structure/unit ---
212
+ own_alliance = self.own_alliance
213
+ enemy_alliance = self.enemy_alliance
214
+
215
+ # To prevent several loops over all units per frame, use this single loop for all checks
216
+ all_unit_size = observation.raw_data.units.size
217
+ i = 0
218
+ while i < all_unit_size
219
+ unit = observation.raw_data.units[i]
220
+ tag = unit.tag
221
+ tag = unit.tag = unit.hash if tag.zero?
222
+ # Reluctantly assigning player to unit
223
+ unit.bot = self
224
+
225
+ # Categorize own units/structures, enemy units/structures, neutral
226
+ if unit.is_blip
227
+ @blips[tag] = unit
228
+ elsif unit.alliance == own_alliance || unit.alliance == enemy_alliance
229
+ if unit.alliance == own_alliance
230
+ structure_collection = @structures
231
+ unit_collection = @units
232
+ else
233
+ structure_collection = @enemy.structures
234
+ unit_collection = @enemy.units
235
+ end
236
+
237
+ unit_data = unit_data(unit.unit_type)
238
+ if unit_data.attributes.include? :Structure
239
+ structure_collection[tag] = unit
240
+ else
241
+ unit_collection[tag] = unit
242
+ end
243
+ else
244
+ @neutral[tag] = unit
245
+ end
246
+
247
+ # Dont parse callbacks on first loop or for neutral units
248
+ if !game_loop.zero? &&
249
+ unit.alliance != :Neutral &&
250
+ unit.display_type != :Placeholder &&
251
+ unit.is_blip == false
252
+
253
+ previous_unit = @previous.all_units[unit.tag]
254
+
255
+ # Unit created/changed/damage modifiers ---
256
+ if previous_unit.nil?
257
+ issue_new_unit_callbacks(unit)
258
+ else
259
+ issue_existing_unit_callbacks(unit, previous_unit)
260
+ end
261
+ end
262
+
263
+ # Allow user to fiddle with unit
264
+ on_parse_observation_unit(unit)
265
+
266
+ i += 1
267
+ end
268
+ end
269
+
270
+ # @private
271
+ # Returns alliance based on whether you are a player or an enemy
272
+ # @return [:Symbol] :Self or :Enemy from Api::Alliance
273
+ def own_alliance
274
+ if is_a? Sc2::Player::Enemy
275
+ Api::Alliance.lookup(Api::Alliance::Enemy)
276
+ else
277
+ Api::Alliance.lookup(Api::Alliance::Self)
278
+ end
279
+ end
280
+
281
+ # @private
282
+ # Returns enemy alliance based on whether you are a player or an enemy
283
+ # @return [:Symbol] :Self or :Enemy from Api::Alliance
284
+ def enemy_alliance
285
+ if is_a? Sc2::Player::Enemy
286
+ Api::Alliance.lookup(Api::Alliance::Self)
287
+ else
288
+ Api::Alliance.lookup(Api::Alliance::Enemy)
289
+ end
290
+ end
291
+
292
+ # @private
293
+ # Issues units/structure callbacks for units which are new
294
+ def issue_new_unit_callbacks(unit)
295
+ return if @_all_seen_unit_tags.include?(unit.tag)
296
+
297
+ if unit.is_structure?
298
+ if unit.build_progress < 1
299
+ @event_structures_started.add(unit)
300
+ on_structure_started(unit)
301
+ else
302
+ @event_structures_completed.add(unit)
303
+ on_structure_completed(unit)
304
+ end
305
+ else
306
+ @event_units_created.add(unit)
307
+ on_unit_created(unit)
308
+ end
309
+ @_all_seen_unit_tags.add(unit.tag)
310
+ end
311
+
312
+ # @private
313
+ # Issues callbacks for units over time, such as damaged or type changed
314
+ def issue_existing_unit_callbacks(unit, previous_unit)
315
+ # Check if a unit type has changed
316
+ if unit.unit_type != previous_unit.unit_type
317
+ @event_units_type_changed.add(unit)
318
+ on_unit_type_changed(unit, previous_unit.unit_type)
319
+ end
320
+
321
+ # Check if a unit type has changed
322
+ if unit.health < previous_unit.health || unit.shield < previous_unit.shield
323
+ damage_amount = previous_unit.health - unit.health + previous_unit.shield - unit.shield
324
+ @event_units_damaged.add(unit)
325
+ on_unit_damaged(unit, damage_amount)
326
+ end
327
+
328
+ if unit.is_structure?
329
+ if previous_unit.build_progress < 1 && unit.build_progress == 1
330
+ @event_structures_completed.add(unit)
331
+ on_structure_completed(unit)
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end