openra 2.1.0 → 3.0.1
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 +4 -4
- data/CHANGELOG.md +40 -1
- data/README.md +1 -1
- data/lib/openra-commands.rb +1 -0
- data/lib/{openra-yaml.rb → openra-mini_yaml.rb} +1 -1
- data/lib/openra/cli.rb +2 -4
- data/lib/openra/cli/command_registry.rb +1 -0
- data/lib/openra/cli/commands/replay_data.rb +1 -143
- data/lib/openra/cli/commands/replay_metadata.rb +21 -0
- data/lib/openra/commands.rb +6 -0
- data/lib/openra/commands/replays/extract_data.rb +156 -0
- data/lib/openra/commands/replays/extract_metadata.rb +57 -0
- data/lib/openra/{cli → commands}/utils.rb +2 -1
- data/lib/openra/constants.rb +12 -0
- data/lib/openra/{yaml.rb → mini_yaml.rb} +1 -1
- data/lib/openra/replays.rb +1 -1
- data/lib/openra/replays/file.rb +5 -5
- data/lib/openra/replays/metadata.rb +1 -0
- data/lib/openra/replays/metadata_marker.rb +2 -0
- data/lib/openra/replays/order.rb +1 -0
- data/lib/openra/replays/replay.rb +1 -1
- data/lib/openra/struct.rb +1 -1
- data/lib/openra/struct/global_settings.rb +1 -1
- data/lib/openra/version.rb +1 -1
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f9c700154d2bb31c15ac83a1edc2ec365fb567c17a4bc2d2e37c920c67de779
|
4
|
+
data.tar.gz: 13ed839f20179328684f677211cf663bc83aad21024105baf26beaf012757b2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bd6a6092972426e71f7f885f6eaa5f56dac5310c285c4b5af80aaaf48b67618d586b861b25151edfc9fbc98fc6f5fa4642dcdca19ea4c0e7a340aee484cd3a1
|
7
|
+
data.tar.gz: 4d2ad04c37f95a9a88f9852bfe36f936f1977e5cfeb72fbc84901911d73f1c5df441569249a53c406c8df9f17430d22aeccdc70962810d432a7c25491390ed7c
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,45 @@
|
|
1
1
|
## Unreleased
|
2
2
|
|
3
|
-
[Compare
|
3
|
+
[Compare v3.0.1...HEAD](https://github.com/AMHOL/openra-ruby/compare/v3.0.0...HEAD)
|
4
|
+
|
5
|
+
## v3.0.1
|
6
|
+
|
7
|
+
* [maint] Added openra-commands file to load stand-alone commands ([AMHOL](https://github.com/AMHOL))
|
8
|
+
|
9
|
+
[Compare v3.0.0...v3.0.1](https://github.com/AMHOL/openra-ruby/compare/v3.0.0...v3.0.1)
|
10
|
+
|
11
|
+
## v3.0.0
|
12
|
+
|
13
|
+
* [replay-metadata] Renamed metadata command to replay-metadata ([AMHOL](https://github.com/AMHOL))
|
14
|
+
|
15
|
+
[Compare v2.3.1...v3.0.0](https://github.com/AMHOL/openra-ruby/compare/v2.3.0...v3.0.0)
|
16
|
+
|
17
|
+
## v2.3.1
|
18
|
+
|
19
|
+
* [replay-data] Fixed error when parsing replays with spectators ([AMHOL](https://github.com/AMHOL))
|
20
|
+
|
21
|
+
[Compare v2.3.0...v2.3.1](https://github.com/AMHOL/openra-ruby/compare/v2.3.0...v2.3.1)
|
22
|
+
|
23
|
+
## v2.3.0
|
24
|
+
|
25
|
+
### Added
|
26
|
+
|
27
|
+
* [replay-data] Add AdvancedChronoshift to Openra::SUPPORT_POWERS ([AMHOL](https://github.com/AMHOL))
|
28
|
+
* [metadata] Added metadata command ([AMHOL](https://github.com/AMHOL))
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
|
32
|
+
* [replay-data] Store clients from SyncInfo command and keep syncing after game start ([AMHOL](https://github.com/AMHOL))
|
33
|
+
|
34
|
+
[Compare v2.2.0...v2.3.0](https://github.com/AMHOL/openra-ruby/compare/v2.2.0...v2.3.0)
|
35
|
+
|
36
|
+
## v2.2.0
|
37
|
+
|
38
|
+
### Fixed
|
39
|
+
|
40
|
+
* [replay-data] Fixed timing calculations ([AMHOL](https://github.com/AMHOL))
|
41
|
+
|
42
|
+
[Compare v2.1.0...v2.2.0](https://github.com/AMHOL/openra-ruby/compare/v2.1.0...v2.2.0)
|
4
43
|
|
5
44
|
## v2.1.0
|
6
45
|
|
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
|
28
|
+
openra replay-metadata /path/to/replay.orarep [--format json|pretty-json|yaml]
|
29
29
|
```
|
30
30
|
|
31
31
|
### Other tools
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'openra/commands'
|
data/lib/openra/cli.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'securerandom'
|
4
3
|
require 'yaml'
|
5
4
|
require 'json'
|
6
5
|
require 'dry/cli'
|
7
6
|
require 'openra/version'
|
8
|
-
require 'openra/
|
9
|
-
require 'openra/replays'
|
10
|
-
require 'openra/cli/utils'
|
7
|
+
require 'openra/commands'
|
11
8
|
require 'openra/cli/formatters'
|
12
9
|
require 'openra/cli/commands/replay_data'
|
10
|
+
require 'openra/cli/commands/replay_metadata'
|
13
11
|
require 'openra/cli/commands/version'
|
14
12
|
require 'openra/cli/command_registry'
|
15
13
|
|
@@ -4,155 +4,13 @@ module Openra
|
|
4
4
|
class CLI
|
5
5
|
module Commands
|
6
6
|
class ReplayData < Dry::CLI::Command
|
7
|
-
include CLI::Utils
|
8
|
-
|
9
7
|
desc 'Output replay data to stdout'
|
10
8
|
|
11
9
|
argument :replay, required: true, desc: 'Path of the replay file to read data from'
|
12
10
|
option :format, default: 'json', values: %w(json pretty-json yaml), desc: 'Output format'
|
13
11
|
|
14
12
|
def call(replay:, **options)
|
15
|
-
|
16
|
-
support_powers = SUPPORT_POWERS.fetch(replay.metadata.mod, {})
|
17
|
-
|
18
|
-
data = {
|
19
|
-
mod: replay.metadata.mod,
|
20
|
-
version: replay.metadata.version,
|
21
|
-
server_name: nil,
|
22
|
-
map: {
|
23
|
-
name: utf8(replay.metadata.map_name),
|
24
|
-
hash: replay.metadata.map_hash
|
25
|
-
},
|
26
|
-
game: {
|
27
|
-
type: replay.players.each_with_object(Hash.new(0)) { |player, hash|
|
28
|
-
if player.team.nil?
|
29
|
-
hash[SecureRandom.uuid] += 1
|
30
|
-
else
|
31
|
-
hash[player.team] += 1
|
32
|
-
end
|
33
|
-
}.values.join('v'),
|
34
|
-
start_time: replay.metadata.start_time.iso8601,
|
35
|
-
end_time: replay.metadata.end_time.iso8601,
|
36
|
-
duration: time((replay.metadata.end_time - replay.metadata.start_time) * 1000),
|
37
|
-
options: nil
|
38
|
-
},
|
39
|
-
clients: [],
|
40
|
-
chat: []
|
41
|
-
}
|
42
|
-
|
43
|
-
game_started = false
|
44
|
-
current_sync_clients = []
|
45
|
-
sync_info = nil
|
46
|
-
|
47
|
-
replay.each_order do |order|
|
48
|
-
client = current_sync_clients.find do |candidate|
|
49
|
-
candidate.index == order.client_index.to_s
|
50
|
-
end
|
51
|
-
|
52
|
-
case order.command
|
53
|
-
when 'StartGame'
|
54
|
-
game_started = true
|
55
|
-
|
56
|
-
data[:clients] = sync_info.clients.map do |client|
|
57
|
-
player = replay.player(client.index)
|
58
|
-
player_index = replay.players.index(player) + FIRST_PLAYER_INDEX if player
|
59
|
-
|
60
|
-
{
|
61
|
-
index: client.index,
|
62
|
-
player_index: player_index,
|
63
|
-
name: utf8(client.name),
|
64
|
-
fingerprint: client.fingerprint,
|
65
|
-
preferred_color: client.preferred_color,
|
66
|
-
color: client.color,
|
67
|
-
spawn: {
|
68
|
-
random: player&.is_random_spawn,
|
69
|
-
point: client.spawn_point
|
70
|
-
},
|
71
|
-
faction: {
|
72
|
-
chosen: client.faction_name.downcase,
|
73
|
-
actual: player&.faction_id
|
74
|
-
},
|
75
|
-
ip: client.ip,
|
76
|
-
team: player&.team,
|
77
|
-
is_bot: player&.is_bot || false,
|
78
|
-
is_admin: client.is_admin,
|
79
|
-
is_player: !player.nil?,
|
80
|
-
is_winner: player&.outcome == 'Won',
|
81
|
-
build: [],
|
82
|
-
support_powers: []
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
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
|
100
|
-
}
|
101
|
-
when 'SyncInfo'
|
102
|
-
sync_info = Openra::Struct::SyncInfo.new(
|
103
|
-
Openra::YAML.load(order.target)
|
104
|
-
) unless game_started
|
105
|
-
when 'SyncLobbyClients'
|
106
|
-
current_sync_clients = Openra::Struct::SyncLobbyClients.new(
|
107
|
-
Openra::YAML.load(order.target)
|
108
|
-
).clients
|
109
|
-
when *support_powers.keys
|
110
|
-
key = support_powers.fetch(utf8(order.command))
|
111
|
-
client_hash = data[:clients].find do |candidate|
|
112
|
-
candidate[:index] == order.client_index.to_s
|
113
|
-
end
|
114
|
-
|
115
|
-
client_hash[:support_powers] << {
|
116
|
-
type: key,
|
117
|
-
game_time: time(order.frame * sync_info.global_settings.frametime_multiplier),
|
118
|
-
placement: cell(order.target_cell.to_i),
|
119
|
-
extra_placement: cell(order.extra_cell.to_i),
|
120
|
-
}
|
121
|
-
when 'PlaceBuilding'
|
122
|
-
# subject_id stores the player index here
|
123
|
-
# as bot commands are issued by the host client
|
124
|
-
client_hash = data[:clients].find do |candidate|
|
125
|
-
candidate[:player_index] == order.subject_id
|
126
|
-
end
|
127
|
-
|
128
|
-
client_hash[:build] << {
|
129
|
-
structure: utf8(order.target),
|
130
|
-
game_time: time(order.frame * sync_info.global_settings.frametime_multiplier),
|
131
|
-
placement: cell(order.target_cell.to_i)
|
132
|
-
}
|
133
|
-
when 'Message'
|
134
|
-
data[:chat] << {
|
135
|
-
channel: 'server',
|
136
|
-
name: nil,
|
137
|
-
message: utf8(order.target)
|
138
|
-
}
|
139
|
-
when 'Chat'
|
140
|
-
data[:chat] << {
|
141
|
-
channel: 'global',
|
142
|
-
name: utf8(client.name),
|
143
|
-
message: utf8(order.target)
|
144
|
-
}
|
145
|
-
when 'TeamChat'
|
146
|
-
data[:chat] << {
|
147
|
-
channel: client.team,
|
148
|
-
name: utf8(client.name),
|
149
|
-
message: utf8(order.target)
|
150
|
-
}
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
data[:server_name] = utf8(sync_info.global_settings.server_name)
|
155
|
-
|
13
|
+
data = Openra::Commands::Replays::ExtractData.new.call(replay)
|
156
14
|
puts FORMATTERS.fetch(options[:format]).call(data)
|
157
15
|
end
|
158
16
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
module Openra
|
6
|
+
class CLI
|
7
|
+
module Commands
|
8
|
+
class ReplayMetadata < Dry::CLI::Command
|
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
|
+
data = Openra::Commands::Replays::ExtractMetadata.new.call(replay)
|
16
|
+
puts FORMATTERS.fetch(options[:format]).call(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Openra
|
4
|
+
module Commands
|
5
|
+
module Replays
|
6
|
+
class ExtractData
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
def call(filepath)
|
10
|
+
replay = Openra::Replays::Replay.new(filepath)
|
11
|
+
support_powers = SUPPORT_POWERS.fetch(replay.metadata.mod, {})
|
12
|
+
|
13
|
+
data = {
|
14
|
+
mod: replay.metadata.mod,
|
15
|
+
version: replay.metadata.version,
|
16
|
+
server_name: nil,
|
17
|
+
map: {
|
18
|
+
name: utf8(replay.metadata.map_name),
|
19
|
+
hash: replay.metadata.map_hash
|
20
|
+
},
|
21
|
+
game: {
|
22
|
+
type: replay.players.each_with_object(Hash.new(0)) { |player, hash|
|
23
|
+
if player.team.nil?
|
24
|
+
hash[SecureRandom.uuid] += 1
|
25
|
+
else
|
26
|
+
hash[player.team] += 1
|
27
|
+
end
|
28
|
+
}.values.join('v'),
|
29
|
+
start_time: replay.metadata.start_time.iso8601,
|
30
|
+
end_time: replay.metadata.end_time.iso8601,
|
31
|
+
duration: time((replay.metadata.end_time - replay.metadata.start_time) * 1000),
|
32
|
+
options: nil
|
33
|
+
},
|
34
|
+
clients: [],
|
35
|
+
chat: []
|
36
|
+
}
|
37
|
+
|
38
|
+
current_sync_clients = []
|
39
|
+
current_sync_info = nil
|
40
|
+
|
41
|
+
replay.each_order do |order|
|
42
|
+
client = current_sync_clients.find do |candidate|
|
43
|
+
candidate.index == order.client_index.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
case order.command
|
47
|
+
when 'StartGame'
|
48
|
+
data[:clients] = current_sync_info.clients.map do |client|
|
49
|
+
player = replay.player(client.index)
|
50
|
+
player_index = replay.players.index(player) + FIRST_PLAYER_INDEX if player
|
51
|
+
|
52
|
+
{
|
53
|
+
index: client.index,
|
54
|
+
player_index: player_index,
|
55
|
+
name: utf8(client.name),
|
56
|
+
fingerprint: client.fingerprint,
|
57
|
+
preferred_color: client.preferred_color,
|
58
|
+
color: client.color,
|
59
|
+
spawn: {
|
60
|
+
random: player&.is_random_spawn,
|
61
|
+
point: client.spawn_point
|
62
|
+
},
|
63
|
+
faction: {
|
64
|
+
random: player&.is_random_faction,
|
65
|
+
chosen: client.faction_name.downcase,
|
66
|
+
actual: player&.faction_id
|
67
|
+
},
|
68
|
+
ip: client.ip,
|
69
|
+
team: player&.team,
|
70
|
+
is_bot: player&.is_bot || false,
|
71
|
+
is_admin: client.is_admin,
|
72
|
+
is_player: !player.nil?,
|
73
|
+
is_winner: player&.outcome == 'Won',
|
74
|
+
outcome_time: player&.outcome_time&.iso8601,
|
75
|
+
build: [],
|
76
|
+
support_powers: []
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
data[:game][:options] = {
|
81
|
+
explored_map: current_sync_info.global_settings.game_options.explored_map_enabled.value,
|
82
|
+
speed: current_sync_info.global_settings.game_options.game_speed.value,
|
83
|
+
starting_cash: current_sync_info.global_settings.game_options.starting_cash.value,
|
84
|
+
starting_units: current_sync_info.global_settings.game_options.starting_units.value,
|
85
|
+
fog_enabled: current_sync_info.global_settings.game_options.fog_enabled.value,
|
86
|
+
cheats_enabled: current_sync_info.global_settings.game_options.cheats_enabled.value,
|
87
|
+
kill_bounty_enabled: current_sync_info.global_settings.game_options.bounties_enabled.value,
|
88
|
+
allow_undeploy: current_sync_info.global_settings.game_options.conyard_undeploy_enabled.value,
|
89
|
+
crates_enabled: current_sync_info.global_settings.game_options.crates_enabled.value,
|
90
|
+
build_off_allies: current_sync_info.global_settings.game_options.build_off_allies_enabled.value,
|
91
|
+
restrict_build_radius: current_sync_info.global_settings.game_options.restricted_build_radius_enabled.value,
|
92
|
+
short_game: current_sync_info.global_settings.game_options.short_game_enabled.value,
|
93
|
+
techlevel: current_sync_info.global_settings.game_options.tech_level.value
|
94
|
+
}
|
95
|
+
when 'SyncInfo'
|
96
|
+
current_sync_info = Openra::Struct::SyncInfo.new(
|
97
|
+
Openra::MiniYAML.load(order.target)
|
98
|
+
)
|
99
|
+
current_sync_clients = current_sync_info.clients
|
100
|
+
when 'SyncLobbyClients'
|
101
|
+
current_sync_clients = Openra::Struct::SyncLobbyClients.new(
|
102
|
+
Openra::MiniYAML.load(order.target)
|
103
|
+
).clients
|
104
|
+
when *support_powers.keys
|
105
|
+
key = support_powers.fetch(utf8(order.command))
|
106
|
+
client_hash = data[:clients].find do |candidate|
|
107
|
+
candidate[:index] == order.client_index.to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
client_hash[:support_powers] << {
|
111
|
+
type: key,
|
112
|
+
game_time: time(order.frame.pred * current_sync_info.global_settings.frametime_multiplier),
|
113
|
+
placement: cell(order.target_cell.to_i),
|
114
|
+
extra_placement: cell(order.extra_cell.to_i),
|
115
|
+
}
|
116
|
+
when 'PlaceBuilding'
|
117
|
+
# subject_id stores the player index here
|
118
|
+
# as bot commands are issued by the host client
|
119
|
+
client_hash = data[:clients].find do |candidate|
|
120
|
+
candidate[:player_index] == order.subject_id
|
121
|
+
end
|
122
|
+
|
123
|
+
client_hash[:build] << {
|
124
|
+
structure: utf8(order.target),
|
125
|
+
game_time: time(order.frame.pred * current_sync_info.global_settings.frametime_multiplier),
|
126
|
+
placement: cell(order.target_cell.to_i)
|
127
|
+
}
|
128
|
+
when 'Message'
|
129
|
+
data[:chat] << {
|
130
|
+
channel: 'server',
|
131
|
+
name: nil,
|
132
|
+
message: utf8(order.target)
|
133
|
+
}
|
134
|
+
when 'Chat'
|
135
|
+
data[:chat] << {
|
136
|
+
channel: 'global',
|
137
|
+
name: utf8(client.name),
|
138
|
+
message: utf8(order.target)
|
139
|
+
}
|
140
|
+
when 'TeamChat'
|
141
|
+
data[:chat] << {
|
142
|
+
channel: client.team,
|
143
|
+
name: utf8(client.name),
|
144
|
+
message: utf8(order.target)
|
145
|
+
}
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
data[:server_name] = utf8(current_sync_info.global_settings.server_name)
|
150
|
+
|
151
|
+
data
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Openra
|
4
|
+
module Commands
|
5
|
+
module Replays
|
6
|
+
class ExtractMetadata
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
def call(filepath)
|
10
|
+
replay = Openra::Replays::Replay.new(filepath)
|
11
|
+
|
12
|
+
{
|
13
|
+
mod: replay.metadata.mod,
|
14
|
+
version: replay.metadata.version,
|
15
|
+
map: {
|
16
|
+
name: utf8(replay.metadata.map_name),
|
17
|
+
hash: replay.metadata.map_hash
|
18
|
+
},
|
19
|
+
game: {
|
20
|
+
type: replay.players.each_with_object(Hash.new(0)) { |player, hash|
|
21
|
+
if player.team.nil?
|
22
|
+
hash[SecureRandom.uuid] += 1
|
23
|
+
else
|
24
|
+
hash[player.team] += 1
|
25
|
+
end
|
26
|
+
}.values.join('v'),
|
27
|
+
start_time: replay.metadata.start_time.iso8601,
|
28
|
+
end_time: replay.metadata.end_time.iso8601,
|
29
|
+
duration: time((replay.metadata.end_time - replay.metadata.start_time) * 1000)
|
30
|
+
},
|
31
|
+
players: replay.players.map { |player|
|
32
|
+
{
|
33
|
+
player_index: player.client_index,
|
34
|
+
name: utf8(player.name),
|
35
|
+
fingerprint: player.fingerprint,
|
36
|
+
color: player.color,
|
37
|
+
spawn: {
|
38
|
+
random: player&.is_random_spawn,
|
39
|
+
point: player.spawn_point
|
40
|
+
},
|
41
|
+
faction: {
|
42
|
+
random: player&.is_random_faction,
|
43
|
+
chosen: player.faction_name.downcase,
|
44
|
+
actual: player&.faction_id
|
45
|
+
},
|
46
|
+
team: player&.team,
|
47
|
+
is_bot: player&.is_bot || false,
|
48
|
+
is_winner: player&.outcome == 'Won',
|
49
|
+
outcome_time: player.outcome_time.iso8601
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Openra
|
4
|
-
|
4
|
+
module Commands
|
5
5
|
module Utils
|
6
6
|
def utf8(string)
|
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
|
|
data/lib/openra/constants.rb
CHANGED
@@ -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
|
},
|
data/lib/openra/replays.rb
CHANGED
data/lib/openra/replays/file.rb
CHANGED
@@ -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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
Metadata.read(
|
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
|
@@ -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
|
data/lib/openra/replays/order.rb
CHANGED
data/lib/openra/struct.rb
CHANGED
data/lib/openra/version.rb
CHANGED
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:
|
4
|
+
version: 3.0.1
|
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-
|
11
|
+
date: 2020-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -151,18 +151,24 @@ files:
|
|
151
151
|
- lib/bindata/big_integer.rb
|
152
152
|
- lib/bindata/pascal_string.rb
|
153
153
|
- lib/openra-cli.rb
|
154
|
+
- lib/openra-commands.rb
|
155
|
+
- lib/openra-mini_yaml.rb
|
154
156
|
- lib/openra-replays.rb
|
155
157
|
- lib/openra-struct.rb
|
156
158
|
- lib/openra-types.rb
|
157
|
-
- lib/openra-yaml.rb
|
158
159
|
- lib/openra.rb
|
159
160
|
- lib/openra/cli.rb
|
160
161
|
- lib/openra/cli/command_registry.rb
|
161
162
|
- lib/openra/cli/commands/replay_data.rb
|
163
|
+
- lib/openra/cli/commands/replay_metadata.rb
|
162
164
|
- lib/openra/cli/commands/version.rb
|
163
165
|
- lib/openra/cli/formatters.rb
|
164
|
-
- lib/openra/
|
166
|
+
- lib/openra/commands.rb
|
167
|
+
- lib/openra/commands/replays/extract_data.rb
|
168
|
+
- lib/openra/commands/replays/extract_metadata.rb
|
169
|
+
- lib/openra/commands/utils.rb
|
165
170
|
- lib/openra/constants.rb
|
171
|
+
- lib/openra/mini_yaml.rb
|
166
172
|
- lib/openra/replays.rb
|
167
173
|
- lib/openra/replays/file.rb
|
168
174
|
- lib/openra/replays/metadata.rb
|
@@ -187,7 +193,6 @@ files:
|
|
187
193
|
- lib/openra/struct/sync_lobby_clients.rb
|
188
194
|
- lib/openra/types.rb
|
189
195
|
- lib/openra/version.rb
|
190
|
-
- lib/openra/yaml.rb
|
191
196
|
- openra.gemspec
|
192
197
|
homepage: https://github.com/AMHOL/openra-ruby
|
193
198
|
licenses:
|