modsvaskr 0.1.8 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/modsvaskr +11 -11
- data/lib/modsvaskr/config.rb +78 -79
- data/lib/modsvaskr/encoding.rb +31 -0
- data/lib/modsvaskr/game.rb +208 -179
- data/lib/modsvaskr/games/skyrim_se.rb +106 -92
- data/lib/modsvaskr/in_game_tests_runner.rb +348 -348
- data/lib/modsvaskr/logger.rb +45 -44
- data/lib/modsvaskr/run_cmd.rb +23 -22
- data/lib/modsvaskr/tests_runner.rb +204 -205
- data/lib/modsvaskr/tests_suite.rb +70 -69
- data/lib/modsvaskr/tests_suites/exterior_cell.rb +120 -117
- data/lib/modsvaskr/tests_suites/interior_cell.rb +63 -63
- data/lib/modsvaskr/tests_suites/npc.rb +67 -39
- data/lib/modsvaskr/tests_suites/npc_head.rb +6 -10
- data/lib/modsvaskr/ui.rb +205 -205
- data/lib/modsvaskr/version.rb +5 -5
- data/lib/modsvaskr/xedit.rb +65 -52
- data/xedit_scripts/Modsvaskr_DumpInfo.pas +13 -0
- metadata +39 -10
@@ -1,39 +1,67 @@
|
|
1
|
-
require 'modsvaskr/in_game_tests_suite'
|
2
|
-
|
3
|
-
module Modsvaskr
|
4
|
-
|
5
|
-
module TestsSuites
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
1
|
+
require 'modsvaskr/in_game_tests_suite'
|
2
|
+
|
3
|
+
module Modsvaskr
|
4
|
+
|
5
|
+
module TestsSuites
|
6
|
+
|
7
|
+
# Test NPCs by taking screenshots
|
8
|
+
class Npc < TestsSuite
|
9
|
+
|
10
|
+
include InGameTestsSuite
|
11
|
+
|
12
|
+
# Return the in-game tests suite to which we forward the tests to be run
|
13
|
+
#
|
14
|
+
# Result::
|
15
|
+
# * Symbol: In-game tests suite
|
16
|
+
def in_game_tests_suite
|
17
|
+
:npcs
|
18
|
+
end
|
19
|
+
|
20
|
+
# Discover the list of tests information that could be run.
|
21
|
+
# [API] - This method is mandatory
|
22
|
+
#
|
23
|
+
# Result::
|
24
|
+
# * Hash< String, Hash<Symbol,Object> >: Ordered hash of test information, per test name
|
25
|
+
def discover_tests
|
26
|
+
tests = {}
|
27
|
+
@game.xedit.run_script('DumpInfo', only_once: true)
|
28
|
+
# Keep track of masters, per plugin
|
29
|
+
# Hash<String, Array<String> >
|
30
|
+
masters = {}
|
31
|
+
# Keep track of NPCs
|
32
|
+
# Array< [String, Integer, String] >
|
33
|
+
# Array< [Plugin, FormID, NPC ] >
|
34
|
+
npcs = []
|
35
|
+
@game.xedit.parse_csv('Modsvaskr_ExportedDumpInfo') do |row|
|
36
|
+
case row[1].downcase
|
37
|
+
when 'npc_'
|
38
|
+
npcs << [row[0].downcase, row[2].to_i(16), row[3]]
|
39
|
+
when 'tes4'
|
40
|
+
masters[row[0].downcase] = row[3..].map(&:downcase)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
npcs.each do |(esp, form_id, npc_name)|
|
44
|
+
raise "Esp #{esp} declares NPC FormID #{form_id} (#{npc_name}) but its masters could not be parsed" unless masters.key?(esp)
|
45
|
+
|
46
|
+
# Know from which mod this ID comes from
|
47
|
+
mod_idx = form_id / 16_777_216
|
48
|
+
raise "NPC FormID #{form_id} (#{npc_name}) from #{esp} references an unknown master (known masters: #{masters[esp].join(', ')})" if mod_idx > masters[esp].size
|
49
|
+
|
50
|
+
test_name = "#{mod_idx == masters[esp].size ? esp : masters[esp][mod_idx]}/#{form_id % 16_777_216}"
|
51
|
+
if tests.key?(test_name)
|
52
|
+
# Add the name of the mod to the description, so that we know which mod modifies which NPC.
|
53
|
+
tests[test_name][:name] << "/#{esp}"
|
54
|
+
else
|
55
|
+
tests[test_name] = {
|
56
|
+
name: "Take screenshot of #{npc_name} - #{esp}"
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
tests
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
|
-
require 'modsvaskr/
|
1
|
+
require 'modsvaskr/tests_suites/npc'
|
2
2
|
|
3
3
|
module Modsvaskr
|
4
4
|
|
5
5
|
module TestsSuites
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
include InGameTestsSuite
|
7
|
+
# Test NPCs by taking head screenshots
|
8
|
+
class NpcHead < TestsSuites::Npc
|
10
9
|
|
11
10
|
# Return the in-game tests suite to which we forward the tests to be run
|
12
11
|
#
|
@@ -22,12 +21,9 @@ module Modsvaskr
|
|
22
21
|
# Result::
|
23
22
|
# * Hash< String, Hash<Symbol,Object> >: Ordered hash of test information, per test name
|
24
23
|
def discover_tests
|
25
|
-
tests =
|
26
|
-
|
27
|
-
|
28
|
-
tests["#{row[0].downcase}/#{row[2].to_i(16)}"] = {
|
29
|
-
name: "Take head screenshot of #{row[0]} - #{row[3]}"
|
30
|
-
} if row[1].downcase == 'npc_'
|
24
|
+
tests = super
|
25
|
+
tests.each_value do |test_info|
|
26
|
+
test_info[:name].gsub!('Take screenshot', 'Take head screenshot')
|
31
27
|
end
|
32
28
|
tests
|
33
29
|
end
|
data/lib/modsvaskr/ui.rb
CHANGED
@@ -1,205 +1,205 @@
|
|
1
|
-
require '
|
2
|
-
require 'curses_menu'
|
3
|
-
require 'modsvaskr/logger'
|
4
|
-
require 'modsvaskr/tests_runner'
|
5
|
-
require 'modsvaskr/run_cmd'
|
6
|
-
require 'modsvaskr/version'
|
7
|
-
|
8
|
-
module Modsvaskr
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
}
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
204
|
-
|
205
|
-
end
|
1
|
+
require 'English'
|
2
|
+
require 'curses_menu'
|
3
|
+
require 'modsvaskr/logger'
|
4
|
+
require 'modsvaskr/tests_runner'
|
5
|
+
require 'modsvaskr/run_cmd'
|
6
|
+
require 'modsvaskr/version'
|
7
|
+
|
8
|
+
module Modsvaskr
|
9
|
+
|
10
|
+
# Main UI, using ncurses
|
11
|
+
class Ui
|
12
|
+
|
13
|
+
include RunCmd
|
14
|
+
include Logger
|
15
|
+
|
16
|
+
# Constructor
|
17
|
+
#
|
18
|
+
# Parameters::
|
19
|
+
# * *config* (Config): Configuration object
|
20
|
+
def initialize(config:)
|
21
|
+
log "Launch Modsvaskr UI v#{Modsvaskr::VERSION} - Logs in #{Logger.log_file}"
|
22
|
+
@config = config
|
23
|
+
end
|
24
|
+
|
25
|
+
# Run the UI
|
26
|
+
def run
|
27
|
+
last_modsvaskr_version = nil
|
28
|
+
gem_list_stdout = `gem list modsvaskr --remote`
|
29
|
+
gem_list_stdout.split("\n").each do |line|
|
30
|
+
if line =~ /^modsvaskr \((.+?)\)/
|
31
|
+
last_modsvaskr_version = Regexp.last_match(1)
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
log "!!! Could not get latest Modsvaskr version. Output of gem list modsvaskr --remote:\n#{gem_list_stdout}" if last_modsvaskr_version.nil?
|
36
|
+
key_presses = @config.auto_keys.map do |key_str|
|
37
|
+
case key_str
|
38
|
+
when 'KEY_ENTER', 'KEY_ESCAPE'
|
39
|
+
CursesMenu.const_get(key_str.to_sym)
|
40
|
+
when /^KEY_\w+$/
|
41
|
+
Curses.const_get(key_str.to_sym)
|
42
|
+
else
|
43
|
+
key_str
|
44
|
+
end
|
45
|
+
end
|
46
|
+
CursesMenu.new(
|
47
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods#{!last_modsvaskr_version.nil? && last_modsvaskr_version != Modsvaskr::VERSION ? " - !!! New version available: #{last_modsvaskr_version}" : ''}",
|
48
|
+
key_presses: key_presses
|
49
|
+
) do |main_menu|
|
50
|
+
@config.games.each do |game|
|
51
|
+
main_menu.item "#{game.name} (#{game.path})" do
|
52
|
+
CursesMenu.new(
|
53
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name}",
|
54
|
+
key_presses: key_presses
|
55
|
+
) do |game_menu|
|
56
|
+
game_menu.item 'Testing' do
|
57
|
+
# Read tests info
|
58
|
+
tests_runner = TestsRunner.new(@config, game)
|
59
|
+
# Selected test names, per test type
|
60
|
+
# Hash< Symbol, Hash< String, nil > >
|
61
|
+
selected_tests_suites = {}
|
62
|
+
CursesMenu.new(
|
63
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing",
|
64
|
+
key_presses: key_presses
|
65
|
+
) do |test_menu|
|
66
|
+
tests_runner.tests_suites.each do |tests_suite|
|
67
|
+
statuses_for_suite = tests_runner.statuses_for(tests_suite)
|
68
|
+
all_tests_selected = selected_tests_suites.key?(tests_suite) &&
|
69
|
+
selected_tests_suites[tests_suite].keys.sort == statuses_for_suite.map { |(test_name, _test_status)| test_name }.sort
|
70
|
+
test_menu.item(
|
71
|
+
"[#{
|
72
|
+
if all_tests_selected
|
73
|
+
'*'
|
74
|
+
elsif selected_tests_suites.key?(tests_suite)
|
75
|
+
'+'
|
76
|
+
else
|
77
|
+
' '
|
78
|
+
end
|
79
|
+
}] #{tests_suite} - #{statuses_for_suite.select { |(_name, status)| status == 'ok' }.size} / #{statuses_for_suite.size}",
|
80
|
+
actions: {
|
81
|
+
'd' => {
|
82
|
+
name: 'Details',
|
83
|
+
execute: proc do
|
84
|
+
CursesMenu.new(
|
85
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Testing > Tests #{tests_suite}",
|
86
|
+
key_presses: key_presses
|
87
|
+
) do |tests_suite_menu|
|
88
|
+
statuses_for_suite.each do |(test_name, test_status)|
|
89
|
+
test_selected = selected_tests_suites.key?(tests_suite) && selected_tests_suites[tests_suite].key?(test_name)
|
90
|
+
tests_suite_menu.item "[#{test_selected ? '*' : ' '}] #{test_name} - #{test_status} - #{tests_runner.test_info(tests_suite, test_name)[:name]}" do
|
91
|
+
if test_selected
|
92
|
+
selected_tests_suites[tests_suite].delete(test_name)
|
93
|
+
selected_tests_suites.delete(tests_suite) if selected_tests_suites[tests_suite].empty?
|
94
|
+
else
|
95
|
+
selected_tests_suites[tests_suite] = {} unless selected_tests_suites.key?(tests_suite)
|
96
|
+
selected_tests_suites[tests_suite][test_name] = nil
|
97
|
+
end
|
98
|
+
:menu_refresh
|
99
|
+
end
|
100
|
+
end
|
101
|
+
tests_suite_menu.item 'Back' do
|
102
|
+
:menu_exit
|
103
|
+
end
|
104
|
+
end
|
105
|
+
:menu_refresh
|
106
|
+
end
|
107
|
+
}
|
108
|
+
}
|
109
|
+
) do
|
110
|
+
if all_tests_selected
|
111
|
+
selected_tests_suites.delete(tests_suite)
|
112
|
+
else
|
113
|
+
selected_tests_suites[tests_suite] = statuses_for_suite.map { |(test_name, _test_status)| [test_name, nil] }.to_h
|
114
|
+
end
|
115
|
+
:menu_refresh
|
116
|
+
end
|
117
|
+
end
|
118
|
+
test_menu.item 'Select tests that are not ok' do
|
119
|
+
selected_tests_suites = {}
|
120
|
+
tests_runner.tests_suites.map do |tests_suite|
|
121
|
+
tests_not_ok = {}
|
122
|
+
tests_runner.statuses_for(tests_suite).each do |(test_name, test_status)|
|
123
|
+
tests_not_ok[test_name] = nil unless test_status == 'ok'
|
124
|
+
end
|
125
|
+
selected_tests_suites[tests_suite] = tests_not_ok unless tests_not_ok.empty?
|
126
|
+
end
|
127
|
+
:menu_refresh
|
128
|
+
end
|
129
|
+
test_menu.item 'Register tests from selected test suites' do
|
130
|
+
selected_tests_suites.each_key do |tests_suite|
|
131
|
+
tests_runner.set_statuses_for(
|
132
|
+
tests_suite,
|
133
|
+
(
|
134
|
+
tests_runner.discover_tests_for(tests_suite) -
|
135
|
+
tests_runner.statuses_for(tests_suite).map { |(test_name, _test_status)| test_name }
|
136
|
+
).map { |test_name| [test_name, ''] }
|
137
|
+
)
|
138
|
+
end
|
139
|
+
:menu_refresh
|
140
|
+
end
|
141
|
+
test_menu.item 'Unregister tests from selected test suites' do
|
142
|
+
selected_tests_suites.each_key do |tests_suite|
|
143
|
+
tests_runner.clear_tests_for(tests_suite)
|
144
|
+
end
|
145
|
+
:menu_refresh
|
146
|
+
end
|
147
|
+
test_menu.item 'Clear selected test statuses' do
|
148
|
+
selected_tests_suites.each do |tests_suite, test_names_set|
|
149
|
+
tests_runner.set_statuses_for(tests_suite, test_names_set.keys.map { |test_name| [test_name, ''] })
|
150
|
+
end
|
151
|
+
:menu_refresh
|
152
|
+
end
|
153
|
+
test_menu.item 'Run remaining selected tests' do
|
154
|
+
tests_runner.run(
|
155
|
+
selected_tests_suites.map do |selected_tests_suite, selected_test_names_set|
|
156
|
+
[
|
157
|
+
selected_tests_suite,
|
158
|
+
# Make sure tests to be run are ordered from the registered list
|
159
|
+
tests_runner.
|
160
|
+
statuses_for(selected_tests_suite).map { |(test_name, _test_status)| test_name }.
|
161
|
+
select { |test_name| selected_test_names_set.key?(test_name) }
|
162
|
+
]
|
163
|
+
end
|
164
|
+
)
|
165
|
+
:menu_refresh
|
166
|
+
end
|
167
|
+
test_menu.item 'Back' do
|
168
|
+
:menu_exit
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
game.complete_game_menu(game_menu) if game.respond_to?(:complete_game_menu)
|
173
|
+
game_menu.item 'Back' do
|
174
|
+
:menu_exit
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
main_menu.item 'See logs' do
|
180
|
+
CursesMenu.new(
|
181
|
+
'Modsvaskr - Stronghold of Mods > Logs',
|
182
|
+
key_presses: key_presses
|
183
|
+
) do |logs_menu|
|
184
|
+
File.read(Logger.log_file).split("\n").each do |line|
|
185
|
+
logs_menu.item line
|
186
|
+
end
|
187
|
+
logs_menu.item 'Back' do
|
188
|
+
:menu_exit
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
main_menu.item 'Quit' do
|
193
|
+
:menu_exit
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue
|
197
|
+
log "Unhandled exception: #{$ERROR_INFO}\n#{$ERROR_INFO.backtrace.join("\n")}"
|
198
|
+
raise
|
199
|
+
ensure
|
200
|
+
log 'Close Modsvaskr UI'
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|