openra 2.2.0 → 2.3.0

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