sc2ai 0.0.5 → 0.0.7
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.
- checksums.yaml +4 -4
- data/data/stableid.json +424 -2562
- data/data/versions.json +8 -0
- data/lib/docker_build/Dockerfile.ruby +1 -1
- data/lib/sc2ai/api/ability_id.rb +12 -314
- data/lib/sc2ai/api/buff_id.rb +9 -16
- data/lib/sc2ai/api/data.rb +1 -4
- data/lib/sc2ai/api/tech_tree.rb +35 -0
- data/lib/sc2ai/api/tech_tree_data.rb +14 -9
- data/lib/sc2ai/api/unit_type_id.rb +6 -58
- data/lib/sc2ai/api/upgrade_id.rb +9 -9
- data/lib/sc2ai/connection/requests.rb +34 -16
- data/lib/sc2ai/data.rb +101 -0
- data/lib/sc2ai/local_play/match.rb +1 -3
- data/lib/sc2ai/player/actions.rb +8 -4
- data/lib/sc2ai/player/debug.rb +2 -3
- data/lib/sc2ai/player/game_state.rb +36 -5
- data/lib/sc2ai/player/geometry.rb +138 -55
- data/lib/sc2ai/player/previous_state.rb +2 -1
- data/lib/sc2ai/player/units.rb +66 -3
- data/lib/sc2ai/player.rb +5 -3
- data/lib/sc2ai/protocol/_meta_documentation.rb +18 -0
- data/lib/sc2ai/protocol/extensions/ability_remapable.rb +22 -0
- data/lib/sc2ai/protocol/extensions/point.rb +3 -1
- data/lib/sc2ai/protocol/extensions/point_2_d.rb +1 -1
- data/lib/sc2ai/protocol/extensions/point_distance.rb +11 -0
- data/lib/sc2ai/protocol/extensions/position.rb +48 -13
- data/lib/sc2ai/protocol/extensions/unit.rb +54 -3
- data/lib/sc2ai/protocol/extensions/unit_type.rb +9 -0
- data/lib/sc2ai/unit_group/action_ext.rb +3 -3
- data/lib/sc2ai/unit_group/filter_ext.rb +33 -7
- data/lib/sc2ai/unit_group/geo_ext.rb +28 -0
- data/lib/sc2ai/unit_group.rb +3 -0
- data/lib/sc2ai/version.rb +1 -1
- data/lib/templates/new/run_example_match.rb.tt +1 -1
- data/sig/sc2ai.rbs +653 -567
- metadata +22 -31
data/lib/sc2ai/api/upgrade_id.rb
CHANGED
@@ -299,14 +299,14 @@ module Api
|
|
299
299
|
DIGGINGCLAWS = 293
|
300
300
|
CARRIERCARRIERCAPACITY = 294
|
301
301
|
CARRIERLEASHRANGEUPGRADE = 295
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
302
|
+
HURRICANETHRUSTERS = 296
|
303
|
+
TEMPESTGROUNDATTACKUPGRADE = 297
|
304
|
+
MICROBIALSHROUD = 298
|
305
|
+
INTERFERENCEMATRIX = 299
|
306
|
+
SUNDERINGIMPACT = 300
|
307
|
+
AMPLIFIEDSHIELDING = 301
|
308
|
+
PSIONICAMPLIFIERS = 302
|
309
|
+
SECRETEDCOATING = 303
|
310
|
+
ENHANCEDSHOCKWAVES = 304
|
311
311
|
end
|
312
312
|
end
|
@@ -279,10 +279,11 @@ module Sc2
|
|
279
279
|
# Advances the game simulation by step_count. Not used in realtime mode.
|
280
280
|
# Only constant step size supported - subsequent requests use cache.
|
281
281
|
def step(step_count = 1)
|
282
|
-
@_cached_request_step ||=
|
282
|
+
@_cached_request_step ||= {}
|
283
|
+
@_cached_request_step[step_count] ||= Api::Request.new(
|
283
284
|
step: Api::RequestStep.new(count: step_count)
|
284
285
|
).to_proto
|
285
|
-
send_request_and_ignore(@_cached_request_step)
|
286
|
+
send_request_and_ignore(@_cached_request_step[step_count])
|
286
287
|
end
|
287
288
|
|
288
289
|
# Additional methods for inspecting game state. Synchronous and must wait on response
|
@@ -291,7 +292,7 @@ module Sc2
|
|
291
292
|
# @param placements [Array<Api::RequestQueryBuildingPlacement>]
|
292
293
|
# @param ignore_resource_requirements [Boolean] Ignores requirements like food, minerals and so on.
|
293
294
|
# @return [Api::ResponseQuery]
|
294
|
-
def query(pathing: nil, abilities: nil, placements: nil, ignore_resource_requirements:
|
295
|
+
def query(pathing: nil, abilities: nil, placements: nil, ignore_resource_requirements: false)
|
295
296
|
send_request_for query: Api::RequestQuery.new(
|
296
297
|
pathing:,
|
297
298
|
abilities:,
|
@@ -301,36 +302,37 @@ module Sc2
|
|
301
302
|
end
|
302
303
|
|
303
304
|
# Queries one or more pathing queries
|
304
|
-
# @param queries [Array<Api::RequestQueryPathing
|
305
|
-
# @return [Array<Api::ResponseQueryPathing
|
305
|
+
# @param queries [Array<Api::RequestQueryPathing>] one or more pathing queries
|
306
|
+
# @return [Array<Api::ResponseQueryPathing>] one or more results depending on input size
|
306
307
|
def query_pathings(queries)
|
307
308
|
arr_queries = queries.is_a?(Array) ? queries : [queries]
|
308
309
|
|
309
310
|
response = send_request_for query: Api::RequestQuery.new(
|
310
311
|
pathing: arr_queries
|
311
312
|
)
|
312
|
-
|
313
|
+
response.pathing
|
313
314
|
end
|
314
315
|
|
315
316
|
# Queries one or more ability-available checks
|
316
|
-
# @param queries [Array<Api::RequestQueryAvailableAbilities
|
317
|
+
# @param queries [Array<Api::RequestQueryAvailableAbilities>] one or more pathing queries
|
317
318
|
# @param ignore_resource_requirements [Boolean] Ignores requirements like food, minerals and so on.
|
318
|
-
# @return [Array<Api::ResponseQueryAvailableAbilities
|
319
|
-
def query_abilities(queries, ignore_resource_requirements:
|
319
|
+
# @return [Array<Api::ResponseQueryAvailableAbilities>] one or more results depending on input size
|
320
|
+
def query_abilities(queries, ignore_resource_requirements: false)
|
320
321
|
arr_queries = queries.is_a?(Array) ? queries : [queries]
|
321
322
|
|
322
323
|
response = send_request_for query: Api::RequestQuery.new(
|
323
324
|
abilities: arr_queries,
|
324
325
|
ignore_resource_requirements:
|
325
326
|
)
|
326
|
-
|
327
|
+
response.abilities
|
327
328
|
end
|
328
329
|
|
329
330
|
# Queries available abilities for units
|
330
|
-
# @param unit_tags [Array<Integer
|
331
|
+
# @param unit_tags [Array<Integer>] an array of unit tags or a single tag
|
331
332
|
# @param ignore_resource_requirements [Boolean] Ignores requirements like food, minerals and so on.
|
332
|
-
# @return [Array<Api::ResponseQueryAvailableAbilities
|
333
|
-
def query_abilities_for_unit_tags(unit_tags, ignore_resource_requirements:
|
333
|
+
# @return [Array<Api::ResponseQueryAvailableAbilities>] one or more results depending on input size
|
334
|
+
def query_abilities_for_unit_tags(unit_tags, ignore_resource_requirements: false)
|
335
|
+
return [] if unit_tags.nil?
|
334
336
|
queries = []
|
335
337
|
unit_tags = [unit_tags] unless unit_tags.is_a? Array
|
336
338
|
unit_tags.each do |unit_tag|
|
@@ -340,15 +342,31 @@ module Sc2
|
|
340
342
|
query_abilities(queries, ignore_resource_requirements:)
|
341
343
|
end
|
342
344
|
|
345
|
+
# Queries available ability ids for one unit
|
346
|
+
# Shortened response over #query_abilities_for_unit_tags, since we know the tag already
|
347
|
+
# and can just return an array of ability ids.
|
348
|
+
# Note: Querying single units are expensive and should be batched with #query_abilities_for_unit_tags
|
349
|
+
# @param unit [Api::Unit, Integer] a unit or a tag.
|
350
|
+
# @return [Array<Integer>] array of ability ids
|
351
|
+
def query_ability_ids_for_unit(unit, ignore_resource_requirements: false)
|
352
|
+
tag = unit.is_a?(Api::Unit) ? unit.tag : unit
|
353
|
+
result = query_abilities_for_unit_tags([tag], ignore_resource_requirements:)
|
354
|
+
if result.nil?
|
355
|
+
[]
|
356
|
+
else
|
357
|
+
result.first.abilities.map(&:ability_id)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
343
361
|
# Queries one or more pathing queries
|
344
|
-
# @param queries [Array<Api::RequestQueryBuildingPlacement
|
345
|
-
# @return [Array<Api::ResponseQueryBuildingPlacement
|
362
|
+
# @param queries [Array<Api::RequestQueryBuildingPlacement>] one or more placement queries
|
363
|
+
# @return [Array<Api::ResponseQueryBuildingPlacement>] one or more results depending on input size
|
346
364
|
def query_placements(queries)
|
347
365
|
arr_queries = queries.is_a?(Array) ? queries : [queries]
|
348
366
|
|
349
367
|
response = query(placements: arr_queries)
|
350
368
|
|
351
|
-
|
369
|
+
response.placements
|
352
370
|
end
|
353
371
|
|
354
372
|
# Generates a replay.
|
data/lib/sc2ai/data.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "api/ability_id"
|
4
|
+
require_relative "api/unit_type_id"
|
5
|
+
require_relative "api/upgrade_id"
|
6
|
+
require_relative "api/buff_id"
|
7
|
+
require_relative "api/effect_id"
|
8
|
+
require_relative "api/tech_tree"
|
9
|
+
|
10
|
+
module Sc2
|
11
|
+
# Holds game data from tech tree and Api::ResponseData
|
12
|
+
# Called once on game start
|
13
|
+
class Data
|
14
|
+
# @!attribute abilities
|
15
|
+
# @return [Hash<Integer, Api::AbilityData]>] AbilitId => AbilityData
|
16
|
+
attr_accessor :abilities
|
17
|
+
# @!attribute units
|
18
|
+
# @return [Hash<Integer, Api::UnitTypeData>] UnitId => UnitData
|
19
|
+
attr_accessor :units
|
20
|
+
# @!attribute upgrades
|
21
|
+
# @return [Hash<Integer, Api::UpgradeData>] UpgradeId => UpgradeData
|
22
|
+
attr_accessor :upgrades
|
23
|
+
# @!attribute buffs
|
24
|
+
# Not particularly useful data. Just use BuffId directly
|
25
|
+
# @return [Hash<Integer, Api::UpgradeData>] BuffId => BuffData
|
26
|
+
attr_accessor :buffs
|
27
|
+
# @!attribute effects
|
28
|
+
# Not particularly useful data. Just use EffectId directly
|
29
|
+
# @return [Hash<Integer, Api::UpgradeData>] EffectId => EffectData
|
30
|
+
attr_accessor :effects
|
31
|
+
|
32
|
+
# @param data [Api::ResponseData]
|
33
|
+
def initialize(data)
|
34
|
+
return unless data
|
35
|
+
|
36
|
+
@abilities = abilities_from_proto(data.abilities)
|
37
|
+
@units = units_from_proto(data.units)
|
38
|
+
@upgrades = upgrades_from_proto(data.upgrades)
|
39
|
+
@buffs = buffs_from_proto(data.buffs)
|
40
|
+
@effects = effects_from_proto(data.effects)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Indexes ability data by ability id
|
46
|
+
# @param abilities [Array<Api::AbilityData>]
|
47
|
+
# @return [Hash<Integer, Api::AbilityData] indexed data
|
48
|
+
def abilities_from_proto(abilities)
|
49
|
+
result = {}
|
50
|
+
|
51
|
+
ability_ids = Api::AbilityId.constants.map { |c| Api::AbilityId.const_get(c) }
|
52
|
+
abilities.each do |a|
|
53
|
+
next if a.ability_id.zero?
|
54
|
+
next if ability_ids.delete(a.ability_id).nil?
|
55
|
+
|
56
|
+
result[a.ability_id] = a
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
# Indexes unit data by id
|
62
|
+
# @param units [Array<Api::UnitTypeData>]
|
63
|
+
# @return [Hash<Integer, Api::UnitTypeData>] indexed data
|
64
|
+
def units_from_proto(units)
|
65
|
+
result = {}
|
66
|
+
units.each do |u|
|
67
|
+
next unless u.available
|
68
|
+
|
69
|
+
result[u.unit_id] = u
|
70
|
+
end
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
# Indexes upgrades data by id
|
75
|
+
# @param upgrades [Array<Api::UpgradeData>]
|
76
|
+
# @return [Hash<Integer, Api::UpgradeData] indexed data
|
77
|
+
def upgrades_from_proto(upgrades)
|
78
|
+
result = {}
|
79
|
+
upgrades.each do |u|
|
80
|
+
result[u.upgrade_id] = u
|
81
|
+
end
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
def effects_from_proto(effects)
|
86
|
+
result = {}
|
87
|
+
effects.each do |e|
|
88
|
+
result[e.effect_id] = e
|
89
|
+
end
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
def buffs_from_proto(buffs)
|
94
|
+
result = {}
|
95
|
+
buffs.each do |b|
|
96
|
+
result[b.buff_id] = b
|
97
|
+
end
|
98
|
+
result
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -23,8 +23,6 @@ module Sc2
|
|
23
23
|
# end
|
24
24
|
end
|
25
25
|
|
26
|
-
# TODO: DEFINE REALTIME AS A PARAM
|
27
|
-
|
28
26
|
# @!attribute players Sets the Player(s) for the match
|
29
27
|
# @return [Array<Sc2::Player>] an array of assigned players (ai,bots,humans,observers)
|
30
28
|
attr_accessor :players
|
@@ -66,7 +64,7 @@ module Sc2
|
|
66
64
|
connect_players
|
67
65
|
setup_player_hooks
|
68
66
|
|
69
|
-
player_host.create_game(map:, players: @players)
|
67
|
+
player_host.create_game(map:, players: @players, realtime: player_host.realtime)
|
70
68
|
|
71
69
|
api_players.each_with_index do |player, player_index|
|
72
70
|
run_task.async do
|
data/lib/sc2ai/player/actions.rb
CHANGED
@@ -45,9 +45,12 @@ module Sc2
|
|
45
45
|
|
46
46
|
target_pos = nil
|
47
47
|
target_unit_tag = nil
|
48
|
-
|
48
|
+
case target
|
49
|
+
when Api::Point2D
|
49
50
|
target_pos = target
|
50
|
-
|
51
|
+
when Api::Point
|
52
|
+
target_pos = target.to_p2d
|
53
|
+
when Api::Unit
|
51
54
|
target_unit_tag = target.tag
|
52
55
|
else
|
53
56
|
target_unit_tag = target
|
@@ -65,7 +68,7 @@ module Sc2
|
|
65
68
|
|
66
69
|
# Builds target unit type using units as source at optional target
|
67
70
|
# @param units [Array<Integer>,Integer,Api::Unit] can be an Api::Unit, array of Api::Unit#tag or single tag
|
68
|
-
# @param unit_type_id [Integer] Api::UnitTypeId the unit type
|
71
|
+
# @param unit_type_id [Integer] Api::UnitTypeId the unit type you wish to build
|
69
72
|
# @param target [Api::Point2D, Integer, nil] is a unit tag or a Api::Point2D. Nil for addons/orbital
|
70
73
|
# @param queue_command [Boolean] shift+command
|
71
74
|
def build(units:, unit_type_id:, target: nil, queue_command: false)
|
@@ -79,9 +82,10 @@ module Sc2
|
|
79
82
|
|
80
83
|
# Warps in unit type at target (location or pylon) with optional source units (warp gates)
|
81
84
|
# When not specifying the specific warp gate(s), all warpgates will be used
|
82
|
-
# @param unit_type_id [Integer] Api::UnitTypeId the unit type
|
85
|
+
# @param unit_type_id [Integer] Api::UnitTypeId the unit type you wish to build
|
83
86
|
# @param queue_command [Boolean] shift+command
|
84
87
|
# @param target [Api::Point2D, Integer] is a unit tag or a Api::Point2D
|
88
|
+
# @param units [Array<Integer>, Integer, Api::Unit]
|
85
89
|
def warp(unit_type_id:, target:, queue_command:, units: nil)
|
86
90
|
warp_ability = Api::TechTree.unit_type_creation_abilities(
|
87
91
|
source: Api::UnitTypeId::WARPGATE,
|
data/lib/sc2ai/player/debug.rb
CHANGED
@@ -133,7 +133,7 @@ module Sc2
|
|
133
133
|
# Debug draws a sphere at position with a radius in color
|
134
134
|
# @param point [Api::Point]
|
135
135
|
# @param radius [Float] default one tile wide, 1.0
|
136
|
-
# @param color [Api::Color] default white
|
136
|
+
# @param color [Api::Color] default white
|
137
137
|
# @return [void]
|
138
138
|
def debug_draw_sphere(point:, radius: 1.0, color: nil)
|
139
139
|
queue_debug_command Api::DebugCommand.new(
|
@@ -151,14 +151,13 @@ module Sc2
|
|
151
151
|
|
152
152
|
# Other Commands ---
|
153
153
|
|
154
|
-
# Toggles cheat commands on/off (send only once to enable)
|
155
154
|
# @param command [Integer] one of Api::DebugGameState::*
|
156
155
|
# Possible values:
|
157
156
|
# Api::DebugGameState::Show_map
|
158
157
|
# Api::DebugGameState::Control_enemy
|
159
158
|
# Api::DebugGameState::Food
|
160
159
|
# Api::DebugGameState::Free
|
161
|
-
# Api::DebugGameState::
|
160
|
+
# Api::DebugGameState::All_resources
|
162
161
|
# Api::DebugGameState::God
|
163
162
|
# Api::DebugGameState::Minerals
|
164
163
|
# Api::DebugGameState::Gas
|
@@ -16,9 +16,12 @@ module Sc2
|
|
16
16
|
|
17
17
|
extend Forwardable
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
attr_writer :game_loop
|
20
|
+
|
21
|
+
# @return [Integer] current game loop
|
22
|
+
def game_loop
|
23
|
+
@game_loop || 0
|
24
|
+
end
|
22
25
|
|
23
26
|
# @!attribute game_info [rw]
|
24
27
|
# Access useful game information. Used in parsed pathing grid, terrain height, placement grid.
|
@@ -38,7 +41,7 @@ module Sc2
|
|
38
41
|
attr_accessor :game_info_loop
|
39
42
|
|
40
43
|
# Determines if your game_info will be refreshed at this moment
|
41
|
-
# Has a hard-capped refresh of only ever
|
44
|
+
# Has a hard-capped refresh of only ever 4 steps
|
42
45
|
# In general game_info is only refreshed Player::Bot reads from pathing_grid or placement_grid
|
43
46
|
# @return [Boolean]
|
44
47
|
def game_info_stale?
|
@@ -47,7 +50,7 @@ module Sc2
|
|
47
50
|
|
48
51
|
# Note: No minimum step count set anymore
|
49
52
|
# We can do something like, only updating every 2+ frames:
|
50
|
-
game_info_loop +
|
53
|
+
game_info_loop + 4 <= game_loop
|
51
54
|
end
|
52
55
|
|
53
56
|
# @!attribute data
|
@@ -103,6 +106,34 @@ module Sc2
|
|
103
106
|
@chats_received || []
|
104
107
|
end
|
105
108
|
|
109
|
+
# @private
|
110
|
+
# @!attribute available_abilities_loop
|
111
|
+
# This is the last loop at which available_abilities was queried.
|
112
|
+
# Used to determine staleness.
|
113
|
+
# @return [Integer]
|
114
|
+
attr_accessor :available_abilities_loop
|
115
|
+
private :available_abilities_loop
|
116
|
+
|
117
|
+
# A Hash by unit tag, holding an array of available ability ids
|
118
|
+
# Synchronously calls RequestQueryAvailableAbilities and caches for this game loop.
|
119
|
+
# @return [Hash<Integer, Array<Integer>>] { unit_tag => [ability_id, ...], ... }
|
120
|
+
def available_abilities
|
121
|
+
# Save/check when last we refreshed abilities
|
122
|
+
if @available_abilities_loop != game_loop
|
123
|
+
|
124
|
+
# Query abilities for all our units + structure tags combined
|
125
|
+
abilities = api.query_abilities_for_unit_tags(units.tags + structures.tags, ignore_resource_requirements: false)
|
126
|
+
# Build the hash by unit tag
|
127
|
+
fresh_available_abilities = {}
|
128
|
+
abilities.each do |row|
|
129
|
+
fresh_available_abilities[row.unit_tag] = row.abilities.map(&:ability_id)
|
130
|
+
end
|
131
|
+
@available_abilities = fresh_available_abilities
|
132
|
+
@available_abilities_loop = game_loop
|
133
|
+
end
|
134
|
+
@available_abilities
|
135
|
+
end
|
136
|
+
|
106
137
|
# An alias for observation.player_common to allow easier access to i.e. common.minerals
|
107
138
|
# @return [Api::PlayerCommon] common info such as minerals, vespene, supply
|
108
139
|
def common
|