sc2ai 0.1.0 → 0.3.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/data/sc2ai/protocol/common.proto +6 -6
  3. data/data/sc2ai/protocol/data.proto +23 -20
  4. data/data/sc2ai/protocol/debug.proto +25 -21
  5. data/data/sc2ai/protocol/error.proto +217 -215
  6. data/data/sc2ai/protocol/query.proto +1 -1
  7. data/data/sc2ai/protocol/raw.proto +16 -14
  8. data/data/sc2ai/protocol/sc2api.proto +108 -94
  9. data/data/sc2ai/protocol/score.proto +4 -3
  10. data/data/sc2ai/protocol/spatial.proto +6 -5
  11. data/data/sc2ai/protocol/ui.proto +17 -14
  12. data/exe/sc2ai +0 -3
  13. data/lib/docker_build/Dockerfile.ruby +4 -2
  14. data/lib/sc2ai/api/ability_id.rb +6 -1
  15. data/lib/sc2ai/api/data.rb +18 -3
  16. data/lib/sc2ai/api/tech_tree.rb +1 -1
  17. data/lib/sc2ai/api/tech_tree_data.rb +54 -3
  18. data/lib/sc2ai/connection/connection_listener.rb +3 -3
  19. data/lib/sc2ai/connection/requests.rb +31 -35
  20. data/lib/sc2ai/connection/status_listener.rb +1 -1
  21. data/lib/sc2ai/connection.rb +1 -2
  22. data/lib/sc2ai/local_play/client.rb +2 -2
  23. data/lib/sc2ai/local_play/match.rb +7 -2
  24. data/lib/sc2ai/overrides/async/process/child.rb +1 -1
  25. data/lib/sc2ai/paths.rb +12 -2
  26. data/lib/sc2ai/player/actions.rb +54 -35
  27. data/lib/sc2ai/player/debug.rb +54 -20
  28. data/lib/sc2ai/player/game_state.rb +11 -18
  29. data/lib/sc2ai/player/geo.rb +56 -66
  30. data/lib/sc2ai/player/units.rb +41 -17
  31. data/lib/sc2ai/player.rb +104 -47
  32. data/lib/sc2ai/ports.rb +1 -2
  33. data/lib/sc2ai/protocol/_meta_documentation.rb +270 -25
  34. data/lib/sc2ai/protocol/common_pb.rb +3862 -33
  35. data/lib/sc2ai/protocol/data_pb.rb +9106 -36
  36. data/lib/sc2ai/protocol/debug_pb.rb +10434 -45
  37. data/lib/sc2ai/protocol/error_pb.rb +1084 -29
  38. data/lib/sc2ai/protocol/extensions/ability_remapable.rb +9 -9
  39. data/lib/sc2ai/protocol/extensions/action.rb +60 -0
  40. data/lib/sc2ai/protocol/extensions/point_2_d.rb +9 -0
  41. data/lib/sc2ai/protocol/extensions/position.rb +11 -36
  42. data/lib/sc2ai/protocol/extensions/power_source.rb +3 -0
  43. data/lib/sc2ai/protocol/extensions/unit.rb +61 -36
  44. data/lib/sc2ai/protocol/extensions/unit_type_data.rb +8 -0
  45. data/lib/sc2ai/protocol/query_pb.rb +5022 -36
  46. data/lib/sc2ai/protocol/raw_pb.rb +18347 -46
  47. data/lib/sc2ai/protocol/sc2api_pb.rb +48424 -126
  48. data/lib/sc2ai/protocol/score_pb.rb +5965 -30
  49. data/lib/sc2ai/protocol/spatial_pb.rb +11941 -37
  50. data/lib/sc2ai/protocol/ui_pb.rb +12924 -46
  51. data/lib/sc2ai/unit_group/action_ext.rb +0 -2
  52. data/lib/sc2ai/unit_group/filter_ext.rb +24 -8
  53. data/lib/sc2ai/unit_group/geo_ext.rb +0 -2
  54. data/lib/sc2ai/unit_group.rb +1 -1
  55. data/lib/sc2ai/version.rb +2 -3
  56. data/lib/sc2ai.rb +10 -11
  57. data/lib/templates/ladderzip/bin/ladder.tt +0 -3
  58. data/lib/templates/new/.ladderignore +15 -5
  59. data/lib/templates/new/api/common.proto +6 -6
  60. data/lib/templates/new/api/data.proto +23 -20
  61. data/lib/templates/new/api/debug.proto +25 -21
  62. data/lib/templates/new/api/error.proto +217 -215
  63. data/lib/templates/new/api/query.proto +1 -1
  64. data/lib/templates/new/api/raw.proto +16 -14
  65. data/lib/templates/new/api/sc2api.proto +108 -94
  66. data/lib/templates/new/api/score.proto +4 -3
  67. data/lib/templates/new/api/spatial.proto +6 -5
  68. data/lib/templates/new/api/ui.proto +17 -14
  69. data/lib/templates/new/boot.rb.tt +1 -1
  70. data/lib/templates/new/my_bot.rb.tt +2 -2
  71. data/lib/templates/new/run_example_match.rb.tt +2 -2
  72. data/sig/sc2ai.rbs +11072 -1651
  73. metadata +31 -26
  74. data/lib/sc2ai/overrides/kernel.rb +0 -33
  75. data/lib/sc2ai/protocol/extensions/unit_type.rb +0 -9
@@ -13,7 +13,13 @@ module Api
13
13
  {ability: Api::AbilityId::UPGRADETOORBITAL_ORBITALCOMMAND,
14
14
  required_building: Api::UnitTypeId::BARRACKS}},
15
15
  Api::UnitTypeId::BARRACKS =>
16
- {Api::UnitTypeId::MARINE =>
16
+ {Api::UnitTypeId::BARRACKSTECHLAB =>
17
+ {ability: Api::AbilityId::BUILD_TECHLAB_BARRACKS,
18
+ requires_placement_position: true},
19
+ Api::UnitTypeId::BARRACKSREACTOR =>
20
+ {ability: Api::AbilityId::BUILD_REACTOR_BARRACKS,
21
+ requires_placement_position: true},
22
+ Api::UnitTypeId::MARINE =>
17
23
  {ability: Api::AbilityId::BARRACKSTRAIN_MARINE},
18
24
  Api::UnitTypeId::REAPER =>
19
25
  {ability: Api::AbilityId::BARRACKSTRAIN_REAPER},
@@ -25,7 +31,13 @@ module Api
25
31
  {ability: Api::AbilityId::BARRACKSTRAIN_MARAUDER,
26
32
  requires_techlab: true}},
27
33
  Api::UnitTypeId::FACTORY =>
28
- {Api::UnitTypeId::HELLION =>
34
+ {Api::UnitTypeId::FACTORYTECHLAB =>
35
+ {ability: Api::AbilityId::BUILD_TECHLAB_FACTORY,
36
+ requires_placement_position: true},
37
+ Api::UnitTypeId::FACTORYREACTOR =>
38
+ {ability: Api::AbilityId::BUILD_REACTOR_FACTORY,
39
+ requires_placement_position: true},
40
+ Api::UnitTypeId::HELLION =>
29
41
  {ability: Api::AbilityId::FACTORYTRAIN_HELLION},
30
42
  Api::UnitTypeId::CYCLONE => {ability: Api::AbilityId::TRAIN_CYCLONE},
31
43
  Api::UnitTypeId::WIDOWMINE =>
@@ -41,7 +53,13 @@ module Api
41
53
  {ability: Api::AbilityId::TRAIN_HELLBAT,
42
54
  required_building: Api::UnitTypeId::ARMORY}},
43
55
  Api::UnitTypeId::STARPORT =>
44
- {Api::UnitTypeId::MEDIVAC =>
56
+ {Api::UnitTypeId::STARPORTTECHLAB =>
57
+ {ability: Api::AbilityId::BUILD_TECHLAB_STARPORT,
58
+ requires_placement_position: true},
59
+ Api::UnitTypeId::STARPORTREACTOR =>
60
+ {ability: Api::AbilityId::BUILD_REACTOR_STARPORT,
61
+ requires_placement_position: true},
62
+ Api::UnitTypeId::MEDIVAC =>
45
63
  {ability: Api::AbilityId::STARPORTTRAIN_MEDIVAC},
46
64
  Api::UnitTypeId::VIKINGFIGHTER =>
47
65
  {ability: Api::AbilityId::STARPORTTRAIN_VIKINGFIGHTER},
@@ -56,6 +74,20 @@ module Api
56
74
  {ability: Api::AbilityId::STARPORTTRAIN_BATTLECRUISER,
57
75
  requires_techlab: true,
58
76
  required_building: Api::UnitTypeId::FUSIONCORE}},
77
+ Api::UnitTypeId::FACTORYFLYING =>
78
+ {Api::UnitTypeId::FACTORYTECHLAB =>
79
+ {ability: Api::AbilityId::BUILD_TECHLAB_FACTORY,
80
+ requires_placement_position: true},
81
+ Api::UnitTypeId::FACTORYREACTOR =>
82
+ {ability: Api::AbilityId::BUILD_REACTOR_FACTORY,
83
+ requires_placement_position: true}},
84
+ Api::UnitTypeId::STARPORTFLYING =>
85
+ {Api::UnitTypeId::STARPORTTECHLAB =>
86
+ {ability: Api::AbilityId::BUILD_TECHLAB_STARPORT,
87
+ requires_placement_position: true},
88
+ Api::UnitTypeId::STARPORTREACTOR =>
89
+ {ability: Api::AbilityId::BUILD_REACTOR_STARPORT,
90
+ requires_placement_position: true}},
59
91
  Api::UnitTypeId::SCV =>
60
92
  {Api::UnitTypeId::COMMANDCENTER =>
61
93
  {ability: Api::AbilityId::TERRANBUILD_COMMANDCENTER,
@@ -104,6 +136,13 @@ module Api
104
136
  Api::UnitTypeId::FUSIONCORE =>
105
137
  {ability: Api::AbilityId::TERRANBUILD_FUSIONCORE,
106
138
  required_building: Api::UnitTypeId::STARPORT,
139
+ requires_placement_position: true}},
140
+ Api::UnitTypeId::BARRACKSFLYING =>
141
+ {Api::UnitTypeId::BARRACKSTECHLAB =>
142
+ {ability: Api::AbilityId::BUILD_TECHLAB_BARRACKS,
143
+ requires_placement_position: true},
144
+ Api::UnitTypeId::BARRACKSREACTOR =>
145
+ {ability: Api::AbilityId::BUILD_REACTOR_BARRACKS,
107
146
  requires_placement_position: true}},
108
147
  Api::UnitTypeId::RAVEN =>
109
148
  {Api::UnitTypeId::AUTOTURRET =>
@@ -780,16 +819,28 @@ module Api
780
819
  Api::UnitTypeId::ORBITALCOMMAND],
781
820
  Api::UnitTypeId::PLANETARYFORTRESS => [Api::UnitTypeId::COMMANDCENTER],
782
821
  Api::UnitTypeId::ORBITALCOMMAND => [Api::UnitTypeId::COMMANDCENTER],
822
+ Api::UnitTypeId::BARRACKSTECHLAB =>
823
+ [Api::UnitTypeId::BARRACKS, Api::UnitTypeId::BARRACKSFLYING],
824
+ Api::UnitTypeId::BARRACKSREACTOR =>
825
+ [Api::UnitTypeId::BARRACKS, Api::UnitTypeId::BARRACKSFLYING],
783
826
  Api::UnitTypeId::MARINE => [Api::UnitTypeId::BARRACKS],
784
827
  Api::UnitTypeId::REAPER => [Api::UnitTypeId::BARRACKS],
785
828
  Api::UnitTypeId::GHOST => [Api::UnitTypeId::BARRACKS],
786
829
  Api::UnitTypeId::MARAUDER => [Api::UnitTypeId::BARRACKS],
830
+ Api::UnitTypeId::FACTORYTECHLAB =>
831
+ [Api::UnitTypeId::FACTORY, Api::UnitTypeId::FACTORYFLYING],
832
+ Api::UnitTypeId::FACTORYREACTOR =>
833
+ [Api::UnitTypeId::FACTORY, Api::UnitTypeId::FACTORYFLYING],
787
834
  Api::UnitTypeId::HELLION => [Api::UnitTypeId::FACTORY],
788
835
  Api::UnitTypeId::CYCLONE => [Api::UnitTypeId::FACTORY],
789
836
  Api::UnitTypeId::WIDOWMINE => [Api::UnitTypeId::FACTORY],
790
837
  Api::UnitTypeId::SIEGETANK => [Api::UnitTypeId::FACTORY],
791
838
  Api::UnitTypeId::THOR => [Api::UnitTypeId::FACTORY],
792
839
  Api::UnitTypeId::HELLIONTANK => [Api::UnitTypeId::FACTORY],
840
+ Api::UnitTypeId::STARPORTTECHLAB =>
841
+ [Api::UnitTypeId::STARPORT, Api::UnitTypeId::STARPORTFLYING],
842
+ Api::UnitTypeId::STARPORTREACTOR =>
843
+ [Api::UnitTypeId::STARPORT, Api::UnitTypeId::STARPORTFLYING],
793
844
  Api::UnitTypeId::MEDIVAC => [Api::UnitTypeId::STARPORT],
794
845
  Api::UnitTypeId::VIKINGFIGHTER => [Api::UnitTypeId::STARPORT],
795
846
  Api::UnitTypeId::LIBERATOR => [Api::UnitTypeId::STARPORT],
@@ -6,21 +6,21 @@ module Sc2
6
6
  # noinspection RubyUnusedLocalVariable
7
7
  module ConnectionListener
8
8
  # Called when connection established to application
9
- # @param connection [Sc2Ai::Connection]
9
+ # @param connection [Sc2::Connection]
10
10
  # noinspection
11
11
  def on_connected(connection)
12
12
  Sc2.logger.debug { "#{self.class}.#{__method__} #{connection}" }
13
13
  end
14
14
 
15
15
  # Called while waiting on connection to application
16
- # @param connection [Sc2Ai::Connection]
16
+ # @param connection [Sc2::Connection]
17
17
  # noinspection Lint/UnusedMethodArgument
18
18
  def on_connection_waiting(connection)
19
19
  Sc2.logger.debug { "#{self.class}.#{__method__} #{connection}" }
20
20
  end
21
21
 
22
22
  # Called when disconnected from application
23
- # @param connection [Sc2Ai::Connection]
23
+ # @param connection [Sc2::Connection]
24
24
  # noinspection Lint/UnusedMethodArgument
25
25
  def on_disconnect(connection)
26
26
  Sc2.logger.debug { "#{self.class}.#{__method__} #{connection}" }
@@ -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}" }
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "async"
4
- require "async/io/stream"
5
4
  require "async/http/endpoint"
6
5
  require "async/websocket"
7
6
  require_relative "connection/requests"
@@ -139,7 +138,7 @@ module Sc2
139
138
 
140
139
  attr_writer :status, :listeners
141
140
 
142
- # @return [HTTP::Endpoint] websocket url for establishing protobuf connection
141
+ # @return [::Async::HTTP::Endpoint] websocket url for establishing protobuf connection
143
142
  def endpoint
144
143
  Async::HTTP::Endpoint.parse("ws://#{@host}:#{@port}/sc2api")
145
144
  end
@@ -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
@@ -8,7 +8,7 @@ module Async
8
8
  def initialize(*args, **options)
9
9
  # Setup a cross-thread notification pipe - nio4r can't monitor pids unfortunately:
10
10
  pipe = ::IO.pipe
11
- @input = Async::IO::Generic.new(pipe.first)
11
+ @input = pipe.first
12
12
  @output = pipe.last
13
13
 
14
14
  @exit_status = nil
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