openra 2.2.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30d4d798e59b17cc3ce4e5ab7b5668eeccdf278abde065ca3d4072ce7b55d765
4
- data.tar.gz: 16a57966678839e8422cfc2cbbe4ccee109d5a6c639adc65d888cb8556f3e21a
3
+ metadata.gz: 935333ec74bcce9f22c729a66247b9adbd18c25810254b60ffaae435c51f884f
4
+ data.tar.gz: 375cd8e312984afcf9316c1a58f6292be496f4177fd582c859490ee608341cbd
5
5
  SHA512:
6
- metadata.gz: '09a36fe3464981b68d1b4ed936352fa7c060dd0b2aefe0e166088e335146818f7fc13454be60cfb6b73e36496cff8a794c10ccde05ca5c2d0d4674ffebb0b96d'
7
- data.tar.gz: 15e26c775fdffaf32d92a9f73af433576c6e119d40274abdbc6de90ed05a5d8a7c140982a4f14cef2c42f5898389898a41e84f557ee9970a6645deb56f4275e6
6
+ metadata.gz: 43037b2237e9128f250417b965282a0f3b84aca84694f32044e6f43b2221230bf327a3e066884754861b7d130315323e2afc3addc24000a555146ede6c99dbed
7
+ data.tar.gz: d31fe43a09269b77a7a10cd0b6fb0f1ad88884f45ed9f801a2b11866d83f580a89daca4b9b95b9836175399ed1d4fedf7c8a5b8d51850e2823288bd07fa45e63
@@ -1,5 +1,14 @@
1
1
  ## Unreleased
2
2
 
3
+ ### Added
4
+
5
+ * [replay-data] Add AdvancedChronoshift to Openra::SUPPORT_POWERS ([AMHOL](https://github.com/AMHOL))
6
+ * [metadata] Added metadata command ([AMHOL](https://github.com/AMHOL))
7
+
8
+ ### Fixed
9
+
10
+ * [replay-data] Store clients from SyncInfo command and keep syncing after game start ([AMHOL](https://github.com/AMHOL))
11
+
3
12
  [Compare v2.2.0...HEAD](https://github.com/AMHOL/openra-ruby/compare/v2.2.0...HEAD)
4
13
 
5
14
  ## v2.2.0
data/README.md CHANGED
@@ -25,7 +25,7 @@ gem update openra
25
25
 
26
26
  ```sh
27
27
  openra replay-data /path/to/replay.orarep [--format json|pretty-json|yaml]
28
- openra detect-production-macros /path/to/replay.orarep [--format json|pretty-json|yaml]
28
+ openra metadata /path/to/replay.orarep [--format json|pretty-json|yaml]
29
29
  ```
30
30
 
31
31
  ### Other tools
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'openra/yaml
3
+ require 'openra/mini_yaml
@@ -9,6 +9,7 @@ require 'openra/constants'
9
9
  require 'openra/replays'
10
10
  require 'openra/cli/utils'
11
11
  require 'openra/cli/formatters'
12
+ require 'openra/cli/commands/metadata'
12
13
  require 'openra/cli/commands/replay_data'
13
14
  require 'openra/cli/commands/version'
14
15
  require 'openra/cli/command_registry'
@@ -5,6 +5,7 @@ module Openra
5
5
  class CommandRegistry
6
6
  extend Dry::CLI::Registry
7
7
 
8
+ register 'metadata', Commands::Metadata
8
9
  register 'replay-data', Commands::ReplayData
9
10
  register 'version', Commands::Version
10
11
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openra
4
+ class CLI
5
+ module Commands
6
+ class Metadata < Dry::CLI::Command
7
+ include CLI::Utils
8
+
9
+ desc 'Output replay metadata to stdout'
10
+
11
+ argument :replay, required: true, desc: 'Path of the replay file to read data from'
12
+ option :format, default: 'json', values: %w(json pretty-json yaml), desc: 'Output format'
13
+
14
+ def call(replay:, **options)
15
+ replay = Openra::Replays::Replay.new(replay)
16
+
17
+ data = {
18
+ mod: replay.metadata.mod,
19
+ version: replay.metadata.version,
20
+ map: {
21
+ name: utf8(replay.metadata.map_name),
22
+ hash: replay.metadata.map_hash
23
+ },
24
+ game: {
25
+ type: replay.players.each_with_object(Hash.new(0)) { |player, hash|
26
+ if player.team.nil?
27
+ hash[SecureRandom.uuid] += 1
28
+ else
29
+ hash[player.team] += 1
30
+ end
31
+ }.values.join('v'),
32
+ start_time: replay.metadata.start_time.iso8601,
33
+ end_time: replay.metadata.end_time.iso8601,
34
+ duration: time((replay.metadata.end_time - replay.metadata.start_time) * 1000)
35
+ },
36
+ players: replay.players.map { |player|
37
+ {
38
+ player_index: player.client_index,
39
+ name: utf8(player.name),
40
+ fingerprint: player.fingerprint,
41
+ color: player.color,
42
+ spawn: {
43
+ random: player&.is_random_spawn,
44
+ point: player.spawn_point
45
+ },
46
+ faction: {
47
+ random: player&.is_random_faction,
48
+ chosen: player.faction_name.downcase,
49
+ actual: player&.faction_id
50
+ },
51
+ team: player&.team,
52
+ is_bot: player&.is_bot || false,
53
+ is_winner: player&.outcome == 'Won',
54
+ outcome_time: player.outcome_time.iso8601
55
+ }
56
+ }
57
+ }
58
+
59
+ puts FORMATTERS.fetch(options[:format]).call(data)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -40,9 +40,8 @@ module Openra
40
40
  chat: []
41
41
  }
42
42
 
43
- game_started = false
44
43
  current_sync_clients = []
45
- sync_info = nil
44
+ current_sync_info = nil
46
45
 
47
46
  replay.each_order do |order|
48
47
  client = current_sync_clients.find do |candidate|
@@ -51,9 +50,7 @@ module Openra
51
50
 
52
51
  case order.command
53
52
  when 'StartGame'
54
- game_started = true
55
-
56
- data[:clients] = sync_info.clients.map do |client|
53
+ data[:clients] = current_sync_info.clients.map do |client|
57
54
  player = replay.player(client.index)
58
55
  player_index = replay.players.index(player) + FIRST_PLAYER_INDEX if player
59
56
 
@@ -69,6 +66,7 @@ module Openra
69
66
  point: client.spawn_point
70
67
  },
71
68
  faction: {
69
+ random: player&.is_random_faction,
72
70
  chosen: client.faction_name.downcase,
73
71
  actual: player&.faction_id
74
72
  },
@@ -78,33 +76,35 @@ module Openra
78
76
  is_admin: client.is_admin,
79
77
  is_player: !player.nil?,
80
78
  is_winner: player&.outcome == 'Won',
79
+ outcome_time: player.outcome_time.iso8601,
81
80
  build: [],
82
81
  support_powers: []
83
82
  }
84
83
  end
85
84
 
86
85
  data[:game][:options] = {
87
- explored_map: sync_info.global_settings.game_options.explored_map_enabled.value,
88
- speed: sync_info.global_settings.game_options.game_speed.value,
89
- starting_cash: sync_info.global_settings.game_options.starting_cash.value,
90
- starting_units: sync_info.global_settings.game_options.starting_units.value,
91
- fog_enabled: sync_info.global_settings.game_options.fog_enabled.value,
92
- cheats_enabled: sync_info.global_settings.game_options.cheats_enabled.value,
93
- kill_bounty_enabled: sync_info.global_settings.game_options.bounties_enabled.value,
94
- allow_undeploy: sync_info.global_settings.game_options.conyard_undeploy_enabled.value,
95
- crates_enabled: sync_info.global_settings.game_options.crates_enabled.value,
96
- build_off_allies: sync_info.global_settings.game_options.build_off_allies_enabled.value,
97
- restrict_build_radius: sync_info.global_settings.game_options.restricted_build_radius_enabled.value,
98
- short_game: sync_info.global_settings.game_options.short_game_enabled.value,
99
- techlevel: sync_info.global_settings.game_options.tech_level.value
86
+ explored_map: current_sync_info.global_settings.game_options.explored_map_enabled.value,
87
+ speed: current_sync_info.global_settings.game_options.game_speed.value,
88
+ starting_cash: current_sync_info.global_settings.game_options.starting_cash.value,
89
+ starting_units: current_sync_info.global_settings.game_options.starting_units.value,
90
+ fog_enabled: current_sync_info.global_settings.game_options.fog_enabled.value,
91
+ cheats_enabled: current_sync_info.global_settings.game_options.cheats_enabled.value,
92
+ kill_bounty_enabled: current_sync_info.global_settings.game_options.bounties_enabled.value,
93
+ allow_undeploy: current_sync_info.global_settings.game_options.conyard_undeploy_enabled.value,
94
+ crates_enabled: current_sync_info.global_settings.game_options.crates_enabled.value,
95
+ build_off_allies: current_sync_info.global_settings.game_options.build_off_allies_enabled.value,
96
+ restrict_build_radius: current_sync_info.global_settings.game_options.restricted_build_radius_enabled.value,
97
+ short_game: current_sync_info.global_settings.game_options.short_game_enabled.value,
98
+ techlevel: current_sync_info.global_settings.game_options.tech_level.value
100
99
  }
101
100
  when 'SyncInfo'
102
- sync_info = Openra::Struct::SyncInfo.new(
103
- Openra::YAML.load(order.target)
104
- ) unless game_started
101
+ current_sync_info = Openra::Struct::SyncInfo.new(
102
+ Openra::MiniYAML.load(order.target)
103
+ )
104
+ current_sync_clients = current_sync_info.clients
105
105
  when 'SyncLobbyClients'
106
106
  current_sync_clients = Openra::Struct::SyncLobbyClients.new(
107
- Openra::YAML.load(order.target)
107
+ Openra::MiniYAML.load(order.target)
108
108
  ).clients
109
109
  when *support_powers.keys
110
110
  key = support_powers.fetch(utf8(order.command))
@@ -114,7 +114,7 @@ module Openra
114
114
 
115
115
  client_hash[:support_powers] << {
116
116
  type: key,
117
- game_time: time(order.frame.pred * sync_info.global_settings.frametime_multiplier),
117
+ game_time: time(order.frame.pred * current_sync_info.global_settings.frametime_multiplier),
118
118
  placement: cell(order.target_cell.to_i),
119
119
  extra_placement: cell(order.extra_cell.to_i),
120
120
  }
@@ -127,7 +127,7 @@ module Openra
127
127
 
128
128
  client_hash[:build] << {
129
129
  structure: utf8(order.target),
130
- game_time: time(order.frame.pred * sync_info.global_settings.frametime_multiplier),
130
+ game_time: time(order.frame.pred * current_sync_info.global_settings.frametime_multiplier),
131
131
  placement: cell(order.target_cell.to_i)
132
132
  }
133
133
  when 'Message'
@@ -151,7 +151,7 @@ module Openra
151
151
  end
152
152
  end
153
153
 
154
- data[:server_name] = utf8(sync_info.global_settings.server_name)
154
+ data[:server_name] = utf8(current_sync_info.global_settings.server_name)
155
155
 
156
156
  puts FORMATTERS.fetch(options[:format]).call(data)
157
157
  end
@@ -7,6 +7,7 @@ module Openra
7
7
  string.force_encoding('UTF-8')
8
8
  end
9
9
 
10
+ # https://github.com/OpenRA/OpenRA/blob/bleed/OpenRA.Game/CPos.cs#L24
10
11
  def cell(pos)
11
12
  return if pos.zero?
12
13
 
@@ -1,6 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Openra
4
+ # # https://github.com/OpenRA/OpenRA/blob/23b3c237b7071fd308c4664b0b6c5d719c0f3c74/OpenRA.Game/Map/MapPlayers.cs
5
+ # The player index is stored in the subject_id on orders to indicate which
6
+ # player issued the order, this is used because bot orders are issued by the
7
+ # host client
8
+ # I think the indices are as follows, but may differ for scripted maps:
9
+ # 0 => World
10
+ # 1 => Neutral
11
+ # 2 => Creeps
12
+ # 3 => Players@{0}
13
+ # 4 => Players@{1}
14
+ # 5 => ...
4
15
  FIRST_PLAYER_INDEX = 3
5
16
 
6
17
  SUPPORT_POWERS = {
@@ -9,6 +20,7 @@ module Openra
9
20
  'SovietParatroopers' => :paratroopers,
10
21
  'UkraineParabombs' => :parabombs,
11
22
  'Chronoshift' => :chronoshift,
23
+ 'AdvancedChronoshift' => :chronoshift,
12
24
  'NukePowerInfoOrder' => :nuke,
13
25
  'GrantExternalConditionPowerInfoOrder' => :iron_curtain
14
26
  },
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Openra
4
- class YAML
4
+ class MiniYAML
5
5
  MATCHER = /(?<indentation>\t+)?(?<key>[^\:]+)?\:?\s?(?<value>.+)?/.freeze
6
6
 
7
7
  def self.load(yaml_string)
@@ -4,7 +4,7 @@ require 'date'
4
4
  require 'bindata'
5
5
  require 'bindata/big_integer'
6
6
  require 'bindata/pascal_string'
7
- require 'openra/yaml'
7
+ require 'openra/mini_yaml'
8
8
  require 'openra/struct'
9
9
  require 'openra/replays/order_decorator'
10
10
  require 'openra/replays/order'
@@ -25,15 +25,15 @@ module Openra
25
25
  end
26
26
 
27
27
  def metadata
28
+ # https://github.com/OpenRA/OpenRA/blob/23b3c237b7071fd308c4664b0b6c5d719c0f3c74/OpenRA.Game/FileFormats/ReplayMetadata.cs#L96
28
29
  @metadata ||= begin
29
- metadata_fs = file.tap(&:rewind)
30
- offset = -(metadata_marker.data_length + 4)
31
- metadata_fs.seek(offset, IO::SEEK_END)
32
- Metadata.read(metadata_fs)
30
+ io = file.tap(&:rewind)
31
+ metadata_offset = -(metadata_marker.data_length + 4)
32
+ io.seek(metadata_offset, IO::SEEK_END)
33
+ Metadata.read(io)
33
34
  end
34
35
  end
35
36
 
36
-
37
37
  private
38
38
 
39
39
  attr_reader :filename
@@ -5,6 +5,7 @@ module Openra
5
5
  class Metadata < BinData::Record
6
6
  endian :little
7
7
  count_bytes_remaining :total_size
8
+ # -8 to remove metadata marker (int32)
8
9
  string :data, length: -> { total_size - 8 }
9
10
  end
10
11
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Openra
4
4
  module Replays
5
+ # The metadata markers is an int32 marker at the end of the file, indicating
6
+ # the offset at which the metadata MiniYAML is stored in the replay file
5
7
  class MetadataMarker < BinData::Record
6
8
  endian :little
7
9
  count_bytes_remaining :total_size
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Openra
4
4
  module Replays
5
+ # https://github.com/OpenRA/OpenRA/blob/bleed/OpenRA.Game/Network/Order.cs
5
6
  class Order < BinData::Record
6
7
  HEX_FE = ?\xFE.dup.force_encoding('ASCII-8BIT').freeze
7
8
  HEX_FF = ?\xFF.dup.force_encoding('ASCII-8BIT').freeze
@@ -11,7 +11,7 @@ module Openra
11
11
 
12
12
  def metadata
13
13
  @metadata ||= Openra::Struct::Metadata.new(
14
- Openra::YAML.load(file.metadata.data)
14
+ Openra::MiniYAML.load(file.metadata.data)
15
15
  )
16
16
  end
17
17
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Openra
4
- VERSION = '2.2.0'.freeze
4
+ VERSION = '2.3.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openra
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Holland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-13 00:00:00.000000000 Z
11
+ date: 2020-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -151,18 +151,20 @@ files:
151
151
  - lib/bindata/big_integer.rb
152
152
  - lib/bindata/pascal_string.rb
153
153
  - lib/openra-cli.rb
154
+ - lib/openra-mini_yaml.rb
154
155
  - lib/openra-replays.rb
155
156
  - lib/openra-struct.rb
156
157
  - lib/openra-types.rb
157
- - lib/openra-yaml.rb
158
158
  - lib/openra.rb
159
159
  - lib/openra/cli.rb
160
160
  - lib/openra/cli/command_registry.rb
161
+ - lib/openra/cli/commands/metadata.rb
161
162
  - lib/openra/cli/commands/replay_data.rb
162
163
  - lib/openra/cli/commands/version.rb
163
164
  - lib/openra/cli/formatters.rb
164
165
  - lib/openra/cli/utils.rb
165
166
  - lib/openra/constants.rb
167
+ - lib/openra/mini_yaml.rb
166
168
  - lib/openra/replays.rb
167
169
  - lib/openra/replays/file.rb
168
170
  - lib/openra/replays/metadata.rb
@@ -187,7 +189,6 @@ files:
187
189
  - lib/openra/struct/sync_lobby_clients.rb
188
190
  - lib/openra/types.rb
189
191
  - lib/openra/version.rb
190
- - lib/openra/yaml.rb
191
192
  - openra.gemspec
192
193
  homepage: https://github.com/AMHOL/openra-ruby
193
194
  licenses: