sc2ai 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/data/sc2ai/protocol/common.proto +5 -5
  3. data/data/sc2ai/protocol/data.proto +22 -22
  4. data/data/sc2ai/protocol/debug.proto +24 -24
  5. data/data/sc2ai/protocol/error.proto +216 -215
  6. data/data/sc2ai/protocol/raw.proto +20 -20
  7. data/data/sc2ai/protocol/sc2api.proto +111 -111
  8. data/data/sc2ai/protocol/score.proto +3 -3
  9. data/data/sc2ai/protocol/spatial.proto +5 -5
  10. data/data/sc2ai/protocol/ui.proto +16 -16
  11. data/exe/sc2ai +0 -3
  12. data/lib/docker_build/Dockerfile.ruby +2 -2
  13. data/lib/sc2ai/api/data.rb +3 -3
  14. data/lib/sc2ai/connection/connection_listener.rb +3 -3
  15. data/lib/sc2ai/connection/requests.rb +31 -35
  16. data/lib/sc2ai/connection/status_listener.rb +1 -1
  17. data/lib/sc2ai/connection.rb +2 -3
  18. data/lib/sc2ai/local_play/client/configurable_options.rb +6 -7
  19. data/lib/sc2ai/local_play/client.rb +3 -3
  20. data/lib/sc2ai/local_play/match.rb +7 -2
  21. data/lib/sc2ai/paths.rb +12 -2
  22. data/lib/sc2ai/player/actions.rb +54 -35
  23. data/lib/sc2ai/player/debug.rb +21 -21
  24. data/lib/sc2ai/player/game_state.rb +11 -18
  25. data/lib/sc2ai/player/geo.rb +54 -64
  26. data/lib/sc2ai/player/units.rb +16 -16
  27. data/lib/sc2ai/player.rb +103 -41
  28. data/lib/sc2ai/ports.rb +1 -1
  29. data/lib/sc2ai/protocol/_meta_documentation.rb +265 -265
  30. data/lib/sc2ai/protocol/common_pb.rb +3865 -15
  31. data/lib/sc2ai/protocol/data_pb.rb +9109 -18
  32. data/lib/sc2ai/protocol/debug_pb.rb +10437 -26
  33. data/lib/sc2ai/protocol/error_pb.rb +1086 -10
  34. data/lib/sc2ai/protocol/extensions/ability_remapable.rb +9 -9
  35. data/lib/sc2ai/protocol/extensions/action.rb +60 -0
  36. data/lib/sc2ai/protocol/extensions/point_2_d.rb +5 -0
  37. data/lib/sc2ai/protocol/extensions/position.rb +10 -35
  38. data/lib/sc2ai/protocol/extensions/power_source.rb +3 -0
  39. data/lib/sc2ai/protocol/extensions/unit.rb +19 -35
  40. data/lib/sc2ai/protocol/query_pb.rb +5025 -17
  41. data/lib/sc2ai/protocol/raw_pb.rb +18350 -27
  42. data/lib/sc2ai/protocol/sc2api_pb.rb +48420 -93
  43. data/lib/sc2ai/protocol/score_pb.rb +5968 -12
  44. data/lib/sc2ai/protocol/spatial_pb.rb +11944 -18
  45. data/lib/sc2ai/protocol/ui_pb.rb +12927 -28
  46. data/lib/sc2ai/unit_group/action_ext.rb +0 -2
  47. data/lib/sc2ai/unit_group/filter_ext.rb +10 -9
  48. data/lib/sc2ai/unit_group/geo_ext.rb +0 -2
  49. data/lib/sc2ai/unit_group.rb +1 -1
  50. data/lib/sc2ai/version.rb +2 -3
  51. data/lib/sc2ai.rb +10 -11
  52. data/lib/templates/ladderzip/bin/ladder.tt +0 -3
  53. data/lib/templates/new/api/common.proto +6 -6
  54. data/lib/templates/new/api/data.proto +23 -20
  55. data/lib/templates/new/api/debug.proto +25 -21
  56. data/lib/templates/new/api/error.proto +217 -215
  57. data/lib/templates/new/api/query.proto +1 -1
  58. data/lib/templates/new/api/raw.proto +16 -14
  59. data/lib/templates/new/api/sc2api.proto +108 -94
  60. data/lib/templates/new/api/score.proto +4 -3
  61. data/lib/templates/new/api/spatial.proto +6 -5
  62. data/lib/templates/new/api/ui.proto +17 -14
  63. data/lib/templates/new/boot.rb.tt +1 -1
  64. data/lib/templates/new/my_bot.rb.tt +1 -1
  65. data/lib/templates/new/run_example_match.rb.tt +2 -2
  66. data/sig/sc2ai.rbs +11008 -1929
  67. metadata +25 -36
  68. data/lib/sc2ai/overrides/kernel.rb +0 -33
  69. data/sig/minaswan.rbs +0 -10323
@@ -24,7 +24,7 @@ module Sc2
24
24
  end
25
25
 
26
26
  # Send to host and all clients for game to begin.
27
- # @param race [Google::Protobuf::EnumValue] Api::Race
27
+ # @param race [Integer] see {Api::Race}
28
28
  # @param name [String] player name
29
29
  # @param server_host [String] hostname or ip of sc2 client
30
30
  # @param port_config [Sc2::PortConfig] port config auto or basic, using start port
@@ -51,16 +51,14 @@ module Sc2
51
51
  server_ports: port_config.server_port_set,
52
52
  client_ports: port_config.client_port_sets,
53
53
  options: Api::InterfaceOptions.new(
54
- {
55
- raw: true,
56
- score: false,
57
- feature_layer: feature_layer_interface_options(enable_feature_layer),
58
- show_cloaked: true,
59
- show_burrowed_shadows: true,
60
- show_placeholders: true,
61
- raw_affects_selection: Sc2.ladder?,
62
- raw_crop_to_playable_area: true
63
- }.merge!(interface_options)
54
+ raw: true,
55
+ score: false,
56
+ feature_layer: feature_layer_interface_options(enable_feature_layer),
57
+ show_cloaked: true,
58
+ show_burrowed_shadows: true,
59
+ show_placeholders: true,
60
+ raw_affects_selection: Sc2.ladder?,
61
+ raw_crop_to_playable_area: true, **interface_options
64
62
  )
65
63
  )
66
64
  end
@@ -103,7 +101,7 @@ module Sc2
103
101
  # pp observer.api.start_replay(
104
102
  # replay_path: Pathname("./replays/test.SC2Replay").realpath
105
103
  # )
106
- # while observer.status == :in_replay
104
+ # while observer.status == :IN_REPLAY
107
105
  # # Step forward
108
106
  # observer.api.step(1)
109
107
  # # fresh observation info
@@ -124,27 +122,25 @@ module Sc2
124
122
 
125
123
  interface_options ||= {}
126
124
  send_request_for start_replay: Api::RequestStartReplay.new(
127
- {
128
- replay_path: replay_path.to_s,
129
- replay_data: replay_data,
130
- map_data: map_data,
131
- realtime: false,
132
- disable_fog: true,
133
- record_replay: record_replay,
134
- observed_player_id: 0,
135
- options: Api::InterfaceOptions.new(
136
- {
137
- raw: true,
138
- score: true,
139
- feature_layer: feature_layer_interface_options(true),
140
- show_cloaked: true,
141
- show_burrowed_shadows: true,
142
- show_placeholders: true,
143
- raw_affects_selection: false,
144
- raw_crop_to_playable_area: true
145
- }.merge!(interface_options)
146
- )
147
- }.merge(options)
125
+ replay_path: replay_path.to_s,
126
+ replay_data: replay_data,
127
+ map_data: map_data,
128
+ realtime: false,
129
+ disable_fog: true,
130
+ record_replay: record_replay,
131
+ observed_player_id: 0,
132
+ options: Api::InterfaceOptions.new(
133
+ raw: true,
134
+ score: true,
135
+ feature_layer: feature_layer_interface_options(true),
136
+ show_cloaked: true,
137
+ show_burrowed_shadows: true,
138
+ show_placeholders: true,
139
+ raw_affects_selection: false,
140
+ raw_crop_to_playable_area: true,
141
+ **interface_options
142
+ ),
143
+ **options
148
144
  )
149
145
  end
150
146
 
@@ -425,8 +421,8 @@ module Sc2
425
421
  # Api::Request.new(observation: RequestObservation)
426
422
  # )[:observation]
427
423
  def send_request_for(**kwargs)
428
- response = send_request(Api::Request.new(kwargs))
429
- response[kwargs.keys.first.to_s]
424
+ response = send_request(Api::Request.new(**kwargs))
425
+ response.send(kwargs.keys.first)
430
426
  end
431
427
 
432
428
  private
@@ -5,7 +5,7 @@ module Sc2
5
5
  # Callbacks when game status changes
6
6
  module StatusListener
7
7
  # Called when game status changes
8
- # @param status [:launched, :in_game, :in_replay, :ended, :quit, :unknown] game state, i.e. :in_game, :ended, :launched
8
+ # @param status [:LAUNCHED, :IN_GAME, :IN_REPLAY, :ENDED, :QUIT, :UNKNOWN] game state, i.e. :IN_GAME, :ENDED, :LAUNCHED
9
9
  # noinspection
10
10
  def on_status_change(status)
11
11
  Sc2.logger.debug { "#{self.class}.#{__method__} #{status}" }
@@ -54,9 +54,8 @@ module Sc2
54
54
  # do initial ping to ensure status is set and connection is working
55
55
  response_ping = ping
56
56
  Sc2.logger.debug { "Game version: #{response_ping.game_version}" }
57
- rescue Errno::ECONNREFUSED, Errno::ECONNRESET
57
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EADDRNOTAVAIL
58
58
  raise Error, "Connection timeout. Max retry exceeded." unless (attempt += 1) < 30 # 30s attempts
59
-
60
59
  @listeners[ConnectionListener.name]&.each { _1.on_connection_waiting(self) }
61
60
  sleep(1)
62
61
  retry
@@ -138,7 +137,7 @@ module Sc2
138
137
 
139
138
  attr_writer :status, :listeners
140
139
 
141
- # @return [HTTP::Endpoint] websocket url for establishing protobuf connection
140
+ # @return [::Async::HTTP::Endpoint] websocket url for establishing protobuf connection
142
141
  def endpoint
143
142
  Async::HTTP::Endpoint.parse("ws://#{@host}:#{@port}/sc2api")
144
143
  end
@@ -5,9 +5,9 @@ module Sc2
5
5
  # Attributes shared by Configuration and Client
6
6
  module ConfigurableOptions
7
7
  # @!attribute host
8
- # Sc2 host param on which to listen for connections, default '0.0.0.0'
8
+ # Sc2 host param on which to listen for connections, default '127.0.0.1'
9
9
  #
10
- # Launch param: -host 0.0.0.0
10
+ # Launch param: -host 127.0.0.1
11
11
  # @return [String,nil]
12
12
  attr_accessor :host
13
13
 
@@ -88,11 +88,10 @@ module Sc2
88
88
 
89
89
  # Resets configurable launch options to their defaults
90
90
  def load_default_launch_options
91
- @host = "0.0.0.0" # -listen
92
- if Paths.wsl?
93
- @host = "#{Socket.gethostname}.mshome.net"
94
- elsif Gem.win_platform?
95
- @host = "127.0.0.1"
91
+ @host = if Paths.wsl?
92
+ "#{Socket.gethostname}.mshome.net"
93
+ else
94
+ "127.0.0.1" # -listen
96
95
  end
97
96
 
98
97
  @display_mode = 0 # -displayMode
@@ -31,7 +31,7 @@ module Sc2
31
31
  end
32
32
 
33
33
  # Initialize new Sc2 client (starts with #launch)
34
- # @param host [String] to listen on, i.e. "0.0.0.0", "127.0.0.1"
34
+ # @param host [String] to listen on, i.e. "127.0.0.1"
35
35
  # @param port [Integer] 5001
36
36
  # @param options [Hash] (see Sc2::Client::ConfigurableOptions)
37
37
  def initialize(host:, port:, **options)
@@ -115,7 +115,7 @@ module Sc2
115
115
 
116
116
  # @!attribute task
117
117
  # The async task running Sc2. Used when interrupting.
118
- # @return [Async::Task]
118
+ # @return [::Async::Task]
119
119
  attr_accessor :task
120
120
 
121
121
  # @private
@@ -151,7 +151,7 @@ module Sc2
151
151
 
152
152
  # @private
153
153
  # Reads bundled versions.json
154
- # @return [JSON] contents of versions.json
154
+ # @return [Array] JSON contents of versions.json
155
155
  def versions_json
156
156
  JSON.load_file(Paths.gem_data_versions_path)
157
157
  end
@@ -72,6 +72,11 @@ module Sc2
72
72
  ClientManager.stop(player_index) # unless keep_clients_alive
73
73
  end
74
74
  end
75
+ # Here, Api players are busy Joining and we wait for map loads
76
+ # Let's use this time for quick housekeeping before the match
77
+ run_task.async do
78
+ Process.warmup
79
+ end
75
80
  rescue
76
81
  # no op - clean exit from game may cause ws disconnection error
77
82
  end.wait
@@ -116,7 +121,7 @@ module Sc2
116
121
  # Gets a Sc2 client from Sc2::ClientManager and connects them
117
122
  def connect_players
118
123
  # Depending on number of players, api has different ready states
119
- ready_statuses = (api_players.size > 1) ? [:launched] : %i[launched ready]
124
+ ready_statuses = (api_players.size > 1) ? [:LAUNCHED] : %i[LAUNCHED READY]
120
125
 
121
126
  # For each player, attempt to connect and retry once after closing Sc2 in worst-case
122
127
  api_players.each_with_index do |player, i|
@@ -149,7 +154,7 @@ module Sc2
149
154
  api_players.each do |player|
150
155
  # Clean surrender locally. Lapizistik taught me bad things.
151
156
  def player.leave_game
152
- debug_end_game(end_result: :Surrender)
157
+ debug_end_game(end_result: :SURRENDER)
153
158
  end
154
159
  end
155
160
  end
data/lib/sc2ai/paths.rb CHANGED
@@ -12,19 +12,26 @@ module Sc2
12
12
  # Credit to Hannes, Sean and Burny for setting the standard
13
13
  class Paths
14
14
  # Platform name for Windows
15
+ # @return [String] "Windows"
15
16
  PF_WINDOWS = "Windows"
16
17
  # Platform name for WSL1
18
+ # @return [String] "WSL"
17
19
  PF_WSL1 = "WSL1"
18
20
  # Platform name for WSL2
21
+ # @return [String] "WSL2"
19
22
  PF_WSL2 = "WSL2"
20
23
  # Platform name macOS
24
+ # @return [String] "Darwin"
21
25
  PF_DARWIN = "Darwin"
22
26
  # Platform name Linux
27
+ # @return [String] "Linux"
23
28
  PF_LINUX = "Linux"
24
29
  # Platform name for Wine
30
+ # @return [String] "WineLinux"
25
31
  PF_WINE = "WineLinux"
26
32
 
27
33
  # Where within user directory to locate ExecuteInfo.txt
34
+ # @return [Hash<String, String>] PF_* => "/path/to/StarCraft II"
28
35
  BASE_DIR = {
29
36
  PF_WINDOWS => "C:/Program Files (x86)/StarCraft II",
30
37
  PF_WSL1 => "/mnt/c/Program Files (x86)/StarCraft II",
@@ -35,6 +42,7 @@ module Sc2
35
42
  }.freeze
36
43
 
37
44
  # Where within user directory to locate ExecuteInfo.txt
45
+ # @return [Hash<String, String>] PF_* => "/path/to/ExecuteInfo.txt"
38
46
  EXEC_INFO_PATH = {
39
47
  PF_WINDOWS => "Documents/StarCraft II/ExecuteInfo.txt",
40
48
  PF_WSL1 => "Documents/StarCraft II/ExecuteInfo.txt",
@@ -45,6 +53,7 @@ module Sc2
45
53
  }.freeze
46
54
 
47
55
  # Path helper for finding executable
56
+ # @return [Hash<String, String>] PF_* => "SC2_binary.exe"
48
57
  BIN_PATH = {
49
58
  PF_WINDOWS => "SC2_x64.exe",
50
59
  PF_WSL1 => "SC2_x64.exe",
@@ -56,6 +65,7 @@ module Sc2
56
65
 
57
66
  # Working directory sub-folder per platform.
58
67
  # Used when spawning client process on some platforms.
68
+ # @return [Hash<String, String>] PF_* => "Directory"
59
69
  WORKING_DIR = {
60
70
  PF_WINDOWS => "Support64",
61
71
  PF_WSL1 => "Support64",
@@ -74,7 +84,7 @@ module Sc2
74
84
 
75
85
  # Bucketed platform names follows convention
76
86
  # Uses ENV['SC2PF'] if configured. This is the only way to set "WineLinux"
77
- # @return ["Windows","WSL1","WSL2","Darwin","Linux","WineLinux"] string platform name
87
+ # @return [String] string platform name
78
88
  def platform
79
89
  return ENV.fetch("SC2PF", nil) unless ENV["SC2PF"].to_s.strip.empty?
80
90
 
@@ -252,7 +262,7 @@ module Sc2
252
262
  end
253
263
 
254
264
  # Loads version data
255
- # @return [JSON] versions.json
265
+ # @return [Array] versions.json
256
266
  def version_json
257
267
  JSON.load_file(Pathname(__dir__.to_s).join("../data/versions.json"))
258
268
  end
@@ -148,8 +148,8 @@ module Sc2
148
148
 
149
149
  # Issues spatial unit command. Target is either target_screen_coord or target_minimap_coord.
150
150
  # @param ability_id [Api::AbilityId]
151
- # @param target_screen_coord [Api::Point2I]
152
- # @param target_minimap_coord [Api::Point2I]
151
+ # @param target_screen_coord [Api::PointI]
152
+ # @param target_minimap_coord [Api::PointI]
153
153
  # @param queue_command [Boolean] shift+command
154
154
  # @return [void]
155
155
  def action_spatial_unit_command(ability_id:, target_screen_coord: nil, target_minimap_coord: nil, queue_command: false)
@@ -166,7 +166,7 @@ module Sc2
166
166
  end
167
167
 
168
168
  # Simulates a click on the minimap to move the camera.
169
- # @param center_minimap [Api::Point2I]
169
+ # @param center_minimap [Api::PointI]
170
170
  # @return [void]
171
171
  #
172
172
  def action_spatial_camera_move(center_minimap:)
@@ -182,10 +182,10 @@ module Sc2
182
182
  # Issues spatial unit select point command. Target is either target_screen_coord or target_minimap_coord.
183
183
  # @param type [Integer] 1,2,3,4 = Api::ActionSpatialUnitSelectionPoint::Type::*
184
184
  # enum Type {
185
- # Select = 1; // Equivalent to normal click. Changes selection to unit.
186
- # Toggle = 2; // Equivalent to shift+click. Toggle selection of unit.
187
- # AllType = 3; // Equivalent to control+click. Selects all units of a given type.
188
- # AddAllType = 4; // Equivalent to shift+control+click. Selects all units of a given type.
185
+ # SELECT = 1; // EQUIVALENT TO NORMAL CLICK. CHANGES SELECTION TO UNIT.
186
+ # TOGGLE = 2; // EQUIVALENT TO SHIFT+CLICK. TOGGLE SELECTION OF UNIT.
187
+ # ALL_TYPE = 3; // EQUIVALENT TO CONTROL+CLICK. SELECTS ALL UNITS OF A GIVEN TYPE.
188
+ # ADD_ALL_TYPE = 4; // EQUIVALENT TO SHIFT+CONTROL+CLICK. SELECTS ALL UNITS OF A GIVEN TYPE.
189
189
  # }
190
190
  # @param selection_screen_coord [Api::PointI]
191
191
  # @return [void]
@@ -221,11 +221,11 @@ module Sc2
221
221
  # Populated if Feature Layer or Render interface is enabled.
222
222
  # @param action [Integer] 1-5 = Api::ActionControlGroup::ControlGroupAction::*
223
223
  # enum ControlGroupAction {
224
- # Recall = 1; // Equivalent to number hotkey. Replaces current selection with control group.
225
- # Set = 2; // Equivalent to Control + number hotkey. Sets control group to current selection.
226
- # Append = 3; // Equivalent to Shift + number hotkey. Adds current selection into control group.
227
- # SetAndSteal = 4; // Equivalent to Control + Alt + number hotkey. Sets control group to current selection. Units are removed from other control groups.
228
- # AppendAndSteal = 5; // Equivalent to Shift + Alt + number hotkey. Adds current selection into control group. Units are removed from other control groups.
224
+ # RECALL = 1; // EQUIVALENT TO NUMBER HOTKEY. REPLACES CURRENT SELECTION WITH CONTROL GROUP.
225
+ # SET = 2; // EQUIVALENT TO CONTROL + NUMBER HOTKEY. SETS CONTROL GROUP TO CURRENT SELECTION.
226
+ # APPEND = 3; // EQUIVALENT TO SHIFT + NUMBER HOTKEY. ADDS CURRENT SELECTION INTO CONTROL GROUP.
227
+ # SET_AND_STEAL = 4; // EQUIVALENT TO CONTROL + ALT + NUMBER HOTKEY. SETS CONTROL GROUP TO CURRENT SELECTION. UNITS ARE REMOVED FROM OTHER CONTROL GROUPS.
228
+ # APPEND_AND_STEAL = 5; // EQUIVALENT TO SHIFT + ALT + NUMBER HOTKEY. ADDS CURRENT SELECTION INTO CONTROL GROUP. UNITS ARE REMOVED FROM OTHER CONTROL GROUPS.
229
229
  # }
230
230
  # @param control_group_index [Integer] 0-9
231
231
  # @return [void]
@@ -280,10 +280,10 @@ module Sc2
280
280
  # @param type [Integer] 1-4 = Api::ActionSelectIdleWorker::Type::*
281
281
  #
282
282
  # enum Type {
283
- # Set = 1; // Equivalent to click with no modifiers. Replaces selection with single idle worker.
284
- # Add = 2; // Equivalent to shift+click. Adds single idle worker to current selection.
285
- # All = 3; // Equivalent to control+click. Selects all idle workers.
286
- # AddAll = 4; // Equivalent to shift+control+click. Adds all idle workers to current selection.
283
+ # SET = 1; // EQUIVALENT TO CLICK WITH NO MODIFIERS. REPLACES SELECTION WITH SINGLE IDLE WORKER.
284
+ # ADD = 2; // EQUIVALENT TO SHIFT+CLICK. ADDS SINGLE IDLE WORKER TO CURRENT SELECTION.
285
+ # ALL = 3; // EQUIVALENT TO CONTROL+CLICK. SELECTS ALL IDLE WORKERS.
286
+ # ADD_ALL = 4; // EQUIVALENT TO SHIFT+CONTROL+CLICK. ADDS ALL IDLE WORKERS TO CURRENT SELECTION.
287
287
  # }
288
288
  def action_ui_select_idle_worker(type:)
289
289
  queue_action Api::Action.new(
@@ -299,15 +299,15 @@ module Sc2
299
299
  # @param type [Integer] 1-4 = Api::ActionMultiPanel::Type::*
300
300
  # @param unit_index [Integer] n'th unit on panel
301
301
  # enum Type {
302
- # SingleSelect = 1; // Click on icon
303
- # DeselectUnit = 2; // Shift Click on icon
304
- # SelectAllOfType = 3; // Control Click on icon.
305
- # DeselectAllOfType = 4; // Control+Shift Click on icon.
302
+ # SINGLE_SELECT = 1; // CLICK ON ICON
303
+ # DESELECT_UNIT = 2; // SHIFT CLICK ON ICON
304
+ # SELECT_ALL_OF_TYPE = 3; // CONTROL CLICK ON ICON.
305
+ # DESELECT_ALL_OF_TYPE = 4; // CONTROL+SHIFT CLICK ON ICON.
306
+ # }
307
+ # message ActionMultiPanel {
308
+ # optional Type type = 1;
309
+ # optional int32 unit_index = 2;
306
310
  # }
307
- # message ActionMultiPanel {
308
- # optional Type type = 1;
309
- # optional int32 unit_index = 2;
310
- # }
311
311
  def action_ui_multi_panel(type:, unit_index:)
312
312
  queue_action Api::Action.new(
313
313
  action_ui: Api::ActionUI.new(
@@ -359,8 +359,8 @@ module Sc2
359
359
 
360
360
  # Send a chat message
361
361
  # @param message [String] to send
362
- # @param channel [Integer] 1-2, default:Team Api::ActionChat::Channel::Broadcast = 1, Api::ActionChat::Channel::Team = 2
363
- def action_chat(message, channel: Api::ActionChat::Channel::Team)
362
+ # @param channel [Integer] 1-2, default:TEAM Api::ActionChat::Channel::BROADCAST = 1, Api::ActionChat::Channel::TEAM = 2
363
+ def action_chat(message, channel: Api::ActionChat::Channel::TEAM)
364
364
  queue_action Api::Action.new(
365
365
  action_chat: Api::ActionChat.new(
366
366
  channel: channel,
@@ -371,24 +371,43 @@ module Sc2
371
371
 
372
372
  private
373
373
 
374
+ # @private
375
+ # Clears action errors. The list should be empty before we
376
+ # do build the errors from our batch action of this step
377
+ def clear_action_errors
378
+ @action_errors = []
379
+ end
380
+
374
381
  # Sends actions via api and flushes action_queue
382
+ # @return [Api::ResponseAction, nil]
375
383
  def perform_actions
376
- # request_actions = []
377
- # @action_queue.each do |queue_type, actions|
378
- # request_actions.push(actions)
379
- # end
380
-
381
- @api.action(@action_queue) unless @action_queue.empty?
384
+ return nil if @action_queue.empty?
385
+
386
+ response_action = @api.action(@action_queue)
387
+ if callback_defined?(:on_action_errors)
388
+ # Clear action errors
389
+ clear_action_errors
390
+ # Loop over every executed action response
391
+ response_action.result.each_with_index do |action_result, i|
392
+ next if action_result == Api::ActionResult::SUCCESS
393
+ executed_action = @action_queue[i]
394
+ next unless [Api::ActionRaw, Api::ActionUI].include?(executed_action.action_type) # undetectable Api::ActionSpatial,
395
+
396
+ @action_errors << Api::ActionError.new(
397
+ unit_tag: executed_action.unit_tags.first,
398
+ ability_id: executed_action.ability_id,
399
+ result: action_result
400
+ )
401
+ end
402
+ end
382
403
  clear_action_queue
404
+ response_action
383
405
  end
384
406
 
385
407
  # Empties and resets @action_queue
386
408
  # @return [void]
387
409
  def clear_action_queue
388
410
  @action_queue = []
389
- # TYPES.each do |type|
390
- # @action_queue[type] = []
391
- # end
392
411
  end
393
412
 
394
413
  # Returns an array of unit tags from a variety of sources
@@ -22,7 +22,7 @@ module Sc2
22
22
 
23
23
  # Prints debug text top left corner
24
24
  # @param text [String] will respect newlines
25
- # @param size [Size] of font, default 14px
25
+ # @param size [Integer] of font, default 14px
26
26
  # @return [void]
27
27
  def debug_print(text, size: 14)
28
28
  queue_debug_command Api::DebugCommand.new(
@@ -43,7 +43,7 @@ module Sc2
43
43
  # @param left_percent [Numeric] range 0..100. percent from left of screen
44
44
  # @param top_percent [Numeric] range 0..100. percent from top of screen
45
45
  # @param color [Api::Color] default white
46
- # @param size [Size] of font, default 14px
46
+ # @param size [Integer] of font, default 14px
47
47
  # @return [void]
48
48
  def debug_text_screen(text, left_percent: 1.0, top_percent: 1.0, color: nil, size: 14)
49
49
  queue_debug_command Api::DebugCommand.new(
@@ -67,7 +67,7 @@ module Sc2
67
67
  # @param text [String] will respect newlines
68
68
  # @param point [Api::Point] point in the world, i.e. unit.pos
69
69
  # @param color [Api::Color] default white
70
- # @param size [Size] of font, default 14px
70
+ # @param size [Integer] of font, default 14px
71
71
  # @return [void]
72
72
  def debug_text_world(text, point:, color: nil, size: 14)
73
73
  queue_debug_command Api::DebugCommand.new(
@@ -152,7 +152,7 @@ module Sc2
152
152
  # Renders a block on the floor, drawn by 4 lines
153
153
  # Pass in either a pos (Position/Unit) or exact x * y coordinates
154
154
  # Optional indentation adds padding on borders inward
155
- # @param pos [Api::Unit, Api::Position]
155
+ # @param pos [Api::Unit, Sc2::Position]
156
156
  # @param x [Float, Integer]
157
157
  # @param y [Float, Integer]
158
158
  # @param color [Api::Color]
@@ -166,8 +166,8 @@ module Sc2
166
166
  x = pos.pos.x.floor
167
167
  y = pos.pos.y.floor
168
168
  elsif pos.is_a?(Sc2::Position)
169
- x = pos.pos.x.floor
170
- y = pos.pos.y.floor
169
+ x = pos.x.floor
170
+ y = pos.y.floor
171
171
  end
172
172
 
173
173
  # Raise above floor to prevent texture clipping
@@ -187,18 +187,18 @@ module Sc2
187
187
 
188
188
  # @param command [Integer] one of Api::DebugGameState::*
189
189
  # Possible values:
190
- # Api::DebugGameState::Show_map
191
- # Api::DebugGameState::Control_enemy
192
- # Api::DebugGameState::Food
193
- # Api::DebugGameState::Free
194
- # Api::DebugGameState::All_resources
195
- # Api::DebugGameState::God
196
- # Api::DebugGameState::Minerals
197
- # Api::DebugGameState::Gas
198
- # Api::DebugGameState::Cooldown
199
- # Api::DebugGameState::Tech_tree
200
- # Api::DebugGameState::Upgrade
201
- # Api::DebugGameState::Fast_build
190
+ # Api::DebugGameState::SHOW_MAP
191
+ # Api::DebugGameState::CONTROL_ENEMY
192
+ # Api::DebugGameState::FOOD
193
+ # Api::DebugGameState::FREE
194
+ # Api::DebugGameState::ALL_RESOURCES
195
+ # Api::DebugGameState::GOD
196
+ # Api::DebugGameState::MINERALS
197
+ # Api::DebugGameState::GAS
198
+ # Api::DebugGameState::COOLDOWN
199
+ # Api::DebugGameState::TECH_TREE
200
+ # Api::DebugGameState::UPGRADE
201
+ # Api::DebugGameState::FAST_BUILD
202
202
  # @return [void]
203
203
  def debug_game_state(command)
204
204
  queue_debug_command Api::DebugCommand.new(
@@ -237,7 +237,7 @@ module Sc2
237
237
 
238
238
  # @private
239
239
  # Hangs, crashes and exits the Sc2 client. DO NOT USE.
240
- # @param test [Integer] one of Api::DebugTestProcess::Test::Crash, Api::DebugTestProcess::Test::Hang, Api::DebugTestProcess::Test::Exit
240
+ # @param test [Integer] one of Api::DebugTestProcess::Test::CRASH, Api::DebugTestProcess::Test::HANG, Api::DebugTestProcess::Test::EXIT
241
241
  # @param delay_ms [Integer] default 0, how long this test is delayed
242
242
  # @return [void]
243
243
  def debug_test_process(test:, delay_ms: 0)
@@ -260,8 +260,8 @@ module Sc2
260
260
  )
261
261
  end
262
262
 
263
- # Ends game with a specified result of either Surrender or DeclareVictory
264
- # @param end_result [Integer] either 1/2. Api::DebugEndGame::EndResult::Surrender or Api::DebugEndGame::EndResult::DeclareVictory
263
+ # Ends game with a specified result of either :SURRENDER or :DECLARE_VICTORY
264
+ # @param end_result [Integer] either 1/2. Api::DebugEndGame::EndResult::SURRENDER or Api::DebugEndGame::EndResult::DECLARE_VICTORY
265
265
  # @return [void]
266
266
  def debug_end_game(end_result:)
267
267
  queue_debug_command Api::DebugCommand.new(
@@ -5,7 +5,7 @@ module Sc2
5
5
  # Holds game state
6
6
  module GameState
7
7
  # @!attribute status
8
- # @return [:launched, :in_game, :in_replay, :ended, :quit, :unknown] status
8
+ # @return [:LAUNCHED, :IN_GAME, :IN_REPLAY, :ENDED, :QUIT, :UNKNOWN] status
9
9
  attr_accessor :status
10
10
 
11
11
  include Connection::StatusListener
@@ -27,10 +27,16 @@ module Sc2
27
27
  # Access useful game information. Used in parsed pathing grid, terrain height, placement grid.
28
28
  # Holds Api::ResponseGameInfo::#start_locations.
29
29
  # @return [Api::ResponseGameInfo]
30
- attr_reader :game_info
30
+ def game_info
31
+ if @game_info_task&.running?
32
+ @game_info_task&.wait
33
+ @game_info_task = nil
34
+ end
35
+ @game_info
36
+ end
31
37
 
32
38
  def game_info=(new_info)
33
- @game_info_loop = game_loop || 0
39
+ @game_info_loop = game_loop
34
40
  @game_info = new_info
35
41
  end
36
42
 
@@ -40,19 +46,6 @@ module Sc2
40
46
  # @return [Integer]
41
47
  attr_accessor :game_info_loop
42
48
 
43
- # Determines if your game_info will be refreshed at this moment
44
- # Has a hard-capped refresh of only ever 4 steps
45
- # In general game_info is only refreshed Player::Bot reads from pathing_grid or placement_grid
46
- # @return [Boolean]
47
- def game_info_stale?
48
- return true if game_info_loop.nil? || game_info.nil?
49
- return false if game_info_loop == game_loop
50
-
51
- # Note: No minimum step count set anymore
52
- # We can do something like, only updating every 2+ frames:
53
- game_info_loop + 4 <= game_loop
54
- end
55
-
56
49
  # @!attribute data
57
50
  # @return [Api::ResponseData]
58
51
  attr_accessor :data
@@ -141,14 +134,14 @@ module Sc2
141
134
  player_id: 0,
142
135
  minerals: 50,
143
136
  vespene: 0,
144
- food_cap: ((race == Api::Race::Zerg) ? 14 : 15),
137
+ food_cap: ((race == Api::Race::ZERG) ? 14 : 15),
145
138
  food_used: 12,
146
139
  food_army: 0,
147
140
  food_workers: 12,
148
141
  idle_worker_count: 0,
149
142
  army_count: 0,
150
143
  warp_gate_count: 0,
151
- larva_count: ((race == Api::Race::Zerg) ? 3 : 0)
144
+ larva_count: ((race == Api::Race::ZERG) ? 3 : 0)
152
145
  )
153
146
  end
154
147