sc2ai 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|