openra 1.8.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/lib/openra/cli.rb +1 -2
- data/lib/openra/cli/command_registry.rb +0 -1
- data/lib/openra/cli/formatters.rb +33 -0
- data/lib/openra/cli/utils.rb +1 -1
- data/lib/openra/replays/file.rb +5 -3
- data/lib/openra/version.rb +1 -1
- data/openra.gemspec +11 -9
- metadata +5 -23
- data/.gitignore +0 -50
- data/Gemfile +0 -5
- data/Rakefile +0 -3
- data/lib/openra/cli/commands/detect_production_macros.rb +0 -141
- data/lib/openra/cli/commands/formatters.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d50772fdfb058a097600d6739787d971d4181ea94f889f463f5790d87cae0df
|
4
|
+
data.tar.gz: 325f6d9fae9516003c127b7ea580e69d4fdb45c70183a30e4b2ab35598ff2996
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b7591e6daa6aa379d36f990a01f873826e133a9c5cffacb7bcf63f935148410c67e2936a875da5507b7c14ad1c7c1f4389136fbfb19672fb8028306a3500ade
|
7
|
+
data.tar.gz: 2304fa6ca53e18438a18c213fff87157a7835b4937e391af64cabd4202a2b9aa974e208cda17bbbf7bc2a51dba29585bcfd68c6f973d9fbc671b6ebd4bc758da
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
## Unreleased
|
2
2
|
|
3
|
-
[Compare
|
3
|
+
[Compare v2.0.0...HEAD](https://github.com/AMHOL/openra-ruby/compare/v2.0.0...HEAD)
|
4
|
+
|
5
|
+
## v2.0.0
|
6
|
+
|
7
|
+
### Removed
|
8
|
+
|
9
|
+
* [detect-production-macros] Remove command because it's garbage ([AMHOL](https://github.com/AMHOL))
|
10
|
+
|
11
|
+
[Compare v1.8.2...v2.0.0](https://github.com/AMHOL/openra-ruby/compare/v1.8.2...v2.0.0)
|
4
12
|
|
5
13
|
## v1.8.2
|
6
14
|
|
data/lib/openra/cli.rb
CHANGED
@@ -8,8 +8,7 @@ require 'openra/version'
|
|
8
8
|
require 'openra/constants'
|
9
9
|
require 'openra/replays'
|
10
10
|
require 'openra/cli/utils'
|
11
|
-
require 'openra/cli/
|
12
|
-
require 'openra/cli/commands/detect_production_macros'
|
11
|
+
require 'openra/cli/formatters'
|
13
12
|
require 'openra/cli/commands/replay_data'
|
14
13
|
require 'openra/cli/commands/version'
|
15
14
|
require 'openra/cli/command_registry'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Openra
|
4
|
+
class CLI
|
5
|
+
module Formatters
|
6
|
+
class JSON
|
7
|
+
def call(data)
|
8
|
+
::JSON.dump(data)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class PrettyJSON
|
13
|
+
def call(data)
|
14
|
+
::JSON.pretty_generate(data)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class YAML
|
19
|
+
def call(data)
|
20
|
+
::YAML.dump(
|
21
|
+
Openra::Struct::Functions[:deep_stringify_keys].(data)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
FORMATTERS = {
|
28
|
+
'json' => Formatters::JSON.new,
|
29
|
+
'pretty-json' => Formatters::PrettyJSON.new,
|
30
|
+
'yaml' => Formatters::YAML.new,
|
31
|
+
}.freeze
|
32
|
+
end
|
33
|
+
end
|
data/lib/openra/cli/utils.rb
CHANGED
data/lib/openra/replays/file.rb
CHANGED
@@ -16,9 +16,11 @@ module Openra
|
|
16
16
|
template = Packet.new(fields: Packet.fields)
|
17
17
|
|
18
18
|
loop do
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
begin
|
20
|
+
template.new.read(file).orders.each(&block)
|
21
|
+
rescue EOFError, IOError
|
22
|
+
break
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
data/lib/openra/version.rb
CHANGED
data/openra.gemspec
CHANGED
@@ -10,13 +10,16 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.homepage = 'https://github.com/AMHOL/openra-ruby'
|
11
11
|
spec.license = 'MIT'
|
12
12
|
|
13
|
-
spec.files =
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
spec.files = Dir[
|
14
|
+
'CHANGELOG.md',
|
15
|
+
'LICENSE',
|
16
|
+
'README.md',
|
17
|
+
'openra.gemspec',
|
18
|
+
'lib/**/*',
|
19
|
+
'bin/openra'
|
20
|
+
]
|
21
|
+
spec.bindir = 'bin'
|
22
|
+
spec.executables = ['openra']
|
20
23
|
spec.require_paths = ['lib']
|
21
24
|
|
22
25
|
spec.add_dependency 'bundler'
|
@@ -27,7 +30,6 @@ Gem::Specification.new do |spec|
|
|
27
30
|
spec.add_dependency 'dry-cli'
|
28
31
|
|
29
32
|
spec.add_development_dependency 'rake'
|
33
|
+
spec.add_development_dependency 'rspec'
|
30
34
|
spec.add_development_dependency 'pry'
|
31
|
-
spec.add_development_dependency 'memory_profiler'
|
32
|
-
spec.add_development_dependency 'stackprof'
|
33
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Holland
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -123,21 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: stackprof
|
126
|
+
name: pry
|
141
127
|
requirement: !ruby/object:Gem::Requirement
|
142
128
|
requirements:
|
143
129
|
- - ">="
|
@@ -158,12 +144,9 @@ executables:
|
|
158
144
|
extensions: []
|
159
145
|
extra_rdoc_files: []
|
160
146
|
files:
|
161
|
-
- ".gitignore"
|
162
147
|
- CHANGELOG.md
|
163
|
-
- Gemfile
|
164
148
|
- LICENSE
|
165
149
|
- README.md
|
166
|
-
- Rakefile
|
167
150
|
- bin/openra
|
168
151
|
- lib/bindata/big_integer.rb
|
169
152
|
- lib/bindata/pascal_string.rb
|
@@ -175,10 +158,9 @@ files:
|
|
175
158
|
- lib/openra.rb
|
176
159
|
- lib/openra/cli.rb
|
177
160
|
- lib/openra/cli/command_registry.rb
|
178
|
-
- lib/openra/cli/commands/detect_production_macros.rb
|
179
|
-
- lib/openra/cli/commands/formatters.rb
|
180
161
|
- lib/openra/cli/commands/replay_data.rb
|
181
162
|
- lib/openra/cli/commands/version.rb
|
163
|
+
- lib/openra/cli/formatters.rb
|
182
164
|
- lib/openra/cli/utils.rb
|
183
165
|
- lib/openra/constants.rb
|
184
166
|
- lib/openra/replays.rb
|
@@ -226,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
208
|
- !ruby/object:Gem::Version
|
227
209
|
version: '0'
|
228
210
|
requirements: []
|
229
|
-
rubygems_version: 3.
|
211
|
+
rubygems_version: 3.1.2
|
230
212
|
signing_key:
|
231
213
|
specification_version: 4
|
232
214
|
summary: Openra Rubygem
|
data/.gitignore
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
/.config
|
4
|
-
/coverage/
|
5
|
-
/InstalledFiles
|
6
|
-
/pkg/
|
7
|
-
/spec/reports/
|
8
|
-
/spec/examples.txt
|
9
|
-
/test/tmp/
|
10
|
-
/test/version_tmp/
|
11
|
-
/tmp/
|
12
|
-
|
13
|
-
# Used by dotenv library to load environment variables.
|
14
|
-
# .env
|
15
|
-
|
16
|
-
## Specific to RubyMotion:
|
17
|
-
.dat*
|
18
|
-
.repl_history
|
19
|
-
build/
|
20
|
-
*.bridgesupport
|
21
|
-
build-iPhoneOS/
|
22
|
-
build-iPhoneSimulator/
|
23
|
-
|
24
|
-
## Specific to RubyMotion (use of CocoaPods):
|
25
|
-
#
|
26
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
-
#
|
30
|
-
# vendor/Pods/
|
31
|
-
|
32
|
-
## Documentation cache and generated files:
|
33
|
-
/.yardoc/
|
34
|
-
/_yardoc/
|
35
|
-
/doc/
|
36
|
-
/rdoc/
|
37
|
-
|
38
|
-
## Environment normalization:
|
39
|
-
/.bundle/
|
40
|
-
/vendor/bundle
|
41
|
-
/lib/bundler/man/
|
42
|
-
|
43
|
-
# for a library or gem, you might want to ignore these files since the code is
|
44
|
-
# intended to run in multiple environments; otherwise, check them in:
|
45
|
-
Gemfile.lock
|
46
|
-
.ruby-version
|
47
|
-
.ruby-gemset
|
48
|
-
|
49
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
-
.rvmrc
|
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Openra
|
4
|
-
class CLI
|
5
|
-
module Commands
|
6
|
-
class DetectProductionMacros < Dry::CLI::Command
|
7
|
-
ARRAY_HASH = ->(hash, key) { hash[key] = [] }
|
8
|
-
|
9
|
-
desc 'Detect whether players are using production macros'
|
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
|
-
commands = Hash.new(&ARRAY_HASH)
|
17
|
-
sync_info = nil
|
18
|
-
|
19
|
-
replay.each_order do |order|
|
20
|
-
case order.command
|
21
|
-
when 'StartGame'
|
22
|
-
game_started = true
|
23
|
-
when 'SyncInfo'
|
24
|
-
sync_info = Openra::Struct::SyncInfo.new(
|
25
|
-
Openra::YAML.load(order.target)
|
26
|
-
) unless game_started
|
27
|
-
when 'StartProduction'
|
28
|
-
commands[order.client_index.to_s] << {
|
29
|
-
target: utf8(order.target),
|
30
|
-
msec: order.frame * sync_info.global_settings.frametime_multiplier
|
31
|
-
}
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
data = {
|
36
|
-
players: replay.players.select(&:is_human).map { |player|
|
37
|
-
player_commands = commands_with_delay(commands[player.index])
|
38
|
-
production_stats = production_stats(player_commands)
|
39
|
-
sequences = detect_sequences(player_commands)
|
40
|
-
|
41
|
-
{
|
42
|
-
index: player.index,
|
43
|
-
name: utf8(player.name),
|
44
|
-
team: player.team,
|
45
|
-
outcome: player.outcome,
|
46
|
-
production_stats: production_stats,
|
47
|
-
sequences: sequences,
|
48
|
-
suspected_macros: suspected_macros(production_stats, sequences)
|
49
|
-
}
|
50
|
-
}
|
51
|
-
}
|
52
|
-
|
53
|
-
puts FORMATTERS.fetch(options[:format]).call(data)
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def commands_with_delay(commands)
|
59
|
-
commands.inject do |last_command, command|
|
60
|
-
command[:delay] = command[:msec] - last_command[:msec]
|
61
|
-
command
|
62
|
-
end
|
63
|
-
|
64
|
-
# Drop the first command, as we don't have a delay for that
|
65
|
-
commands.drop(1)
|
66
|
-
end
|
67
|
-
|
68
|
-
def detect_sequences(player_commands)
|
69
|
-
sequences = []
|
70
|
-
groups = player_commands.each_with_object(
|
71
|
-
Hash.new(&ARRAY_HASH)
|
72
|
-
).with_index do |(command, hash), index|
|
73
|
-
hash[command[:delay]] << command.merge(index: index)
|
74
|
-
end
|
75
|
-
|
76
|
-
groups.each_pair do |delay, commands|
|
77
|
-
sequence = []
|
78
|
-
|
79
|
-
commands.inject do |last_command, command|
|
80
|
-
if last_command[:index].next == command[:index]
|
81
|
-
sequence << command
|
82
|
-
elsif sequence.length > 1
|
83
|
-
sequences << {
|
84
|
-
delay: delay,
|
85
|
-
sequence: sequence.map { |c| c[:target] }
|
86
|
-
}
|
87
|
-
sequence = []
|
88
|
-
end
|
89
|
-
|
90
|
-
command
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
sequences = sequences.uniq.map do |sequence|
|
95
|
-
sequence.merge(
|
96
|
-
occurences: sequences.count { |current| current == sequence }
|
97
|
-
)
|
98
|
-
end
|
99
|
-
|
100
|
-
sequences.select { |sequence| sequence[:occurences] > 1 }.sort do |a, b|
|
101
|
-
b[:occurences] <=> a[:occurences]
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def production_stats(player_commands)
|
106
|
-
order_delays = player_commands.map { |command| command[:delay] }
|
107
|
-
|
108
|
-
{
|
109
|
-
order_delay: {
|
110
|
-
min: order_delays.min,
|
111
|
-
max: order_delays.max,
|
112
|
-
mean: mean(order_delays),
|
113
|
-
median: median(order_delays)
|
114
|
-
}
|
115
|
-
}
|
116
|
-
end
|
117
|
-
|
118
|
-
def suspected_macros(production_stats, sequences)
|
119
|
-
suspicious_sequences = sequences.count do |sequence|
|
120
|
-
sequence[:delay] < 100 &&
|
121
|
-
sequence[:sequence].length > 3 &&
|
122
|
-
sequence[:sequence].uniq.length > 2
|
123
|
-
end
|
124
|
-
|
125
|
-
production_stats[:order_delay][:min] < 50 || suspicious_sequences > 0
|
126
|
-
end
|
127
|
-
|
128
|
-
def mean(ints)
|
129
|
-
ints.sum / ints.length
|
130
|
-
end
|
131
|
-
|
132
|
-
def median(ints)
|
133
|
-
ints = ints.sort
|
134
|
-
middle_index = (ints.length - 1) / 2.0
|
135
|
-
|
136
|
-
(ints[middle_index.floor] + ints[middle_index.ceil]) / 2
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Openra
|
4
|
-
class CLI
|
5
|
-
module Commands
|
6
|
-
module Formatters
|
7
|
-
class JSON
|
8
|
-
def call(data)
|
9
|
-
::JSON.dump(data)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class PrettyJSON
|
14
|
-
def call(data)
|
15
|
-
::JSON.pretty_generate(data)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class YAML
|
20
|
-
def call(data)
|
21
|
-
::YAML.dump(
|
22
|
-
Openra::Struct::Functions[:deep_stringify_keys].(data)
|
23
|
-
)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
FORMATTERS = {
|
29
|
-
'json' => Formatters::JSON.new,
|
30
|
-
'pretty-json' => Formatters::PrettyJSON.new,
|
31
|
-
'yaml' => Formatters::YAML.new,
|
32
|
-
}.freeze
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|