modsvaskr 0.2.1 → 1.1.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 +4 -4
- data/bin/modsvaskr +2 -1
- data/lib/modsvaskr/config.rb +14 -0
- data/lib/modsvaskr/game.rb +23 -0
- data/lib/modsvaskr/ui.rb +129 -1
- data/lib/modsvaskr/version.rb +1 -1
- data/lib/modsvaskr/xedit.rb +20 -0
- metadata +38 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b3bda4db035df3b3289829342c1a70a47be0191de49f35e72c2e25f6e8aaada
|
4
|
+
data.tar.gz: bed82e160e1310241b870e8545a08913b81caf210f5388121afd1fc465ad01c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35e165ef5571a0a54c47393aea22ec848e42be1d6d27940f8a23e24fba00b35da00677049b474d1370ba7b4fadf4de9088089ec8cb582ceb8c2c1de489490cf5
|
7
|
+
data.tar.gz: '08ade008d6263b3bef50df32efeda147e409e2f9c7644177ccaa03c112a9aafdb4f54e3102eb98b56814e6fbe42210d72df176d7e4feb0cb2341f3117faf72aa'
|
data/bin/modsvaskr
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
require 'English'
|
3
3
|
require 'modsvaskr/config'
|
4
4
|
require 'modsvaskr/ui'
|
5
5
|
|
6
6
|
begin
|
7
7
|
Modsvaskr::Ui.new(config: Modsvaskr::Config.new('./modsvaskr.yaml')).run
|
8
8
|
rescue
|
9
|
+
puts "An exception has occurred: #{$ERROR_INFO}\n#{$ERROR_INFO.backtrace.join("\n")}"
|
9
10
|
puts 'Press Enter to exit.'
|
10
11
|
$stdin.gets
|
11
12
|
end
|
data/lib/modsvaskr/config.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'mod_organizer'
|
1
2
|
require 'yaml'
|
2
3
|
require 'modsvaskr/game'
|
3
4
|
require 'modsvaskr/xedit'
|
@@ -73,6 +74,19 @@ module Modsvaskr
|
|
73
74
|
@config['no_prompt'] || false
|
74
75
|
end
|
75
76
|
|
77
|
+
# Return the ModOrganizer instance, if configured.
|
78
|
+
#
|
79
|
+
# Result::
|
80
|
+
# * ModOrganizer or nil: The ModOrganizer instance, or nil if none
|
81
|
+
def mod_organizer
|
82
|
+
return nil unless @config['mod_organizer']
|
83
|
+
|
84
|
+
ModOrganizer.new(
|
85
|
+
@config['mod_organizer']['installation_dir'],
|
86
|
+
instance_name: @config['mod_organizer']['instance_name']
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
76
90
|
end
|
77
91
|
|
78
92
|
end
|
data/lib/modsvaskr/game.rb
CHANGED
@@ -203,6 +203,29 @@ module Modsvaskr
|
|
203
203
|
[load_order[form_id / 16_777_216], form_id % 16_777_216]
|
204
204
|
end
|
205
205
|
|
206
|
+
# Clean a list plugins.
|
207
|
+
# Make sure they are cleaned in the right order, according to the load order.
|
208
|
+
# Put the cleaned plugins in a cleaned_plugins subfolder.
|
209
|
+
# Make sure that subsequent plugins to be cleaned are cleaned with the previously cleaned plugins in the list.
|
210
|
+
#
|
211
|
+
# Parameters::
|
212
|
+
# * *plugins* (Array<String>): List of plugins to be cleaned
|
213
|
+
def clean_plugins(plugins)
|
214
|
+
return if plugins.empty?
|
215
|
+
|
216
|
+
esp = (load_order & plugins).first
|
217
|
+
log "Clean #{esp}"
|
218
|
+
FileUtils.cp "#{path}/Data/#{esp}", "#{path}/Data/#{esp}.backup"
|
219
|
+
begin
|
220
|
+
xedit.quick_auto_clean(esp)
|
221
|
+
clean_plugins(plugins - [esp])
|
222
|
+
FileUtils.mkdir_p "#{path}/Data/cleaned_plugins"
|
223
|
+
FileUtils.mv "#{path}/Data/#{esp}", "#{path}/Data/cleaned_plugins/#{esp}"
|
224
|
+
ensure
|
225
|
+
FileUtils.mv "#{path}/Data/#{esp}.backup", "#{path}/Data/#{esp}"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
206
229
|
end
|
207
230
|
|
208
231
|
end
|
data/lib/modsvaskr/ui.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'English'
|
2
2
|
require 'curses_menu'
|
3
|
+
require 'launchy'
|
3
4
|
require 'modsvaskr/logger'
|
4
5
|
require 'modsvaskr/tests_runner'
|
5
6
|
require 'modsvaskr/run_cmd'
|
@@ -20,8 +21,12 @@ module Modsvaskr
|
|
20
21
|
def initialize(config:)
|
21
22
|
log "Launch Modsvaskr UI v#{Modsvaskr::VERSION} - Logs in #{Logger.log_file}"
|
22
23
|
@config = config
|
24
|
+
@mod_organizer = @config.mod_organizer
|
23
25
|
end
|
24
26
|
|
27
|
+
# Time that should be before any file time of mods (used for sorting)
|
28
|
+
TIME_BEGIN = Time.parse('2000-01-01')
|
29
|
+
|
25
30
|
# Run the UI
|
26
31
|
def run
|
27
32
|
last_modsvaskr_version = nil
|
@@ -44,7 +49,13 @@ module Modsvaskr
|
|
44
49
|
end
|
45
50
|
end
|
46
51
|
CursesMenu.new(
|
47
|
-
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods#{
|
52
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods#{
|
53
|
+
if !last_modsvaskr_version.nil? && last_modsvaskr_version != Modsvaskr::VERSION
|
54
|
+
" - !!! New version available: #{last_modsvaskr_version}"
|
55
|
+
else
|
56
|
+
''
|
57
|
+
end
|
58
|
+
}",
|
48
59
|
key_presses:
|
49
60
|
) do |main_menu|
|
50
61
|
@config.games.each do |game|
|
@@ -53,6 +64,27 @@ module Modsvaskr
|
|
53
64
|
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name}",
|
54
65
|
key_presses:
|
55
66
|
) do |game_menu|
|
67
|
+
game_menu.item 'Plugins' do
|
68
|
+
selected_esps = {}
|
69
|
+
CursesMenu.new(
|
70
|
+
"Modsvaskr v#{Modsvaskr::VERSION} - Stronghold of Mods > #{game.name} > Plugins",
|
71
|
+
key_presses:
|
72
|
+
) do |plugins_menu|
|
73
|
+
game.load_order.each.with_index do |esp, idx|
|
74
|
+
plugins_menu.item "[#{selected_esps.key?(esp) ? '*' : ' '}] #{idx} - #{esp}" do
|
75
|
+
if selected_esps.key?(esp)
|
76
|
+
selected_esps.delete(esp)
|
77
|
+
else
|
78
|
+
selected_esps[esp] = nil
|
79
|
+
end
|
80
|
+
:menu_refresh
|
81
|
+
end
|
82
|
+
end
|
83
|
+
plugins_menu.item "Clean #{selected_esps.size} selected plugins" do
|
84
|
+
game.clean_plugins(selected_esps.keys)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
56
88
|
game_menu.item 'Testing' do
|
57
89
|
# Read tests info
|
58
90
|
tests_runner = TestsRunner.new(@config, game)
|
@@ -176,6 +208,102 @@ module Modsvaskr
|
|
176
208
|
end
|
177
209
|
end
|
178
210
|
end
|
211
|
+
unless @mod_organizer.nil?
|
212
|
+
main_menu.item 'Mods Organizer' do
|
213
|
+
CursesMenu.new(
|
214
|
+
'Modsvaskr - Stronghold of Mods > Mods Organizer',
|
215
|
+
key_presses:
|
216
|
+
) do |mo_menu|
|
217
|
+
# Show status
|
218
|
+
mo_menu.item 'Run Mod Organizer' do
|
219
|
+
@mod_organizer.run
|
220
|
+
end
|
221
|
+
mo_menu.item "#{@mod_organizer.mod_names.size} mods (#{@mod_organizer.mod_names.select { |mod_name| @mod_organizer.mod(name: mod_name).enabled? }.size} enabled)" do
|
222
|
+
CursesMenu.new(
|
223
|
+
'Modsvaskr - Stronghold of Mods > Mods Organizer > Mods',
|
224
|
+
key_presses:
|
225
|
+
) do |mods_menu|
|
226
|
+
mod_names = @mod_organizer.mods_list
|
227
|
+
idx_size = (mod_names.size - 1).to_s.size
|
228
|
+
mod_names.each.with_index do |mod_name, idx|
|
229
|
+
mod = @mod_organizer.mod(name: mod_name)
|
230
|
+
# need_update = false
|
231
|
+
mods_menu.item(
|
232
|
+
proc do
|
233
|
+
sections = {
|
234
|
+
enabled_cell: {
|
235
|
+
text: mod.enabled? ? 'X' : ' ',
|
236
|
+
begin_with: '[',
|
237
|
+
end_with: ']',
|
238
|
+
fixed_size: 3
|
239
|
+
},
|
240
|
+
idx_cell: {
|
241
|
+
text: idx.to_s,
|
242
|
+
fixed_size: idx_size
|
243
|
+
},
|
244
|
+
name_cell: {
|
245
|
+
text: mod_name,
|
246
|
+
color_pair: CursesMenu::COLORS_GREEN,
|
247
|
+
fixed_size: 64
|
248
|
+
},
|
249
|
+
categories_cell: {
|
250
|
+
text: mod.categories.map { |category| "[#{category}]" }.join(' '),
|
251
|
+
fixed_size: 16
|
252
|
+
},
|
253
|
+
esps_cell: {
|
254
|
+
text: "#{mod.plugins.size} plugins",
|
255
|
+
fixed_size: 10
|
256
|
+
}
|
257
|
+
}
|
258
|
+
mod.sources.sort_by { |source| source.download.nil? ? TIME_BEGIN : source.download.downloaded_date }.each.with_index do |source, src_idx|
|
259
|
+
source_name = src_idx.zero? ? '' : '+ '
|
260
|
+
source_name <<
|
261
|
+
case source.type
|
262
|
+
when :nexus_mods
|
263
|
+
"Nexus Mod #{source.nexus_mod_id}/" +
|
264
|
+
if source.download&.nexus_file_name
|
265
|
+
source.download&.nexus_file_name
|
266
|
+
elsif source.file_name
|
267
|
+
source.file_name
|
268
|
+
else
|
269
|
+
'<Unknown file>'
|
270
|
+
end
|
271
|
+
when :unknown
|
272
|
+
source.file_name || '<Unknown source>'
|
273
|
+
else
|
274
|
+
raise "Unknown source type: #{source.type} for #{mod.name}"
|
275
|
+
end
|
276
|
+
sections["source_#{src_idx}".to_sym] = {
|
277
|
+
text: source_name,
|
278
|
+
color_pair: CursesMenu::COLORS_WHITE
|
279
|
+
}
|
280
|
+
end
|
281
|
+
CursesMenu::CursesRow.new(sections)
|
282
|
+
end,
|
283
|
+
actions: proc do
|
284
|
+
actions = {}
|
285
|
+
# TODO: Use downloads' URL instead of mod's URL as it is very often more accurate
|
286
|
+
if mod.url
|
287
|
+
actions['v'] = {
|
288
|
+
name: 'Visit',
|
289
|
+
execute: proc { Launchy.open(mod.url) }
|
290
|
+
}
|
291
|
+
end
|
292
|
+
actions
|
293
|
+
end
|
294
|
+
)
|
295
|
+
end
|
296
|
+
mods_menu.item 'Back' do
|
297
|
+
:menu_exit
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
mo_menu.item 'Back' do
|
302
|
+
:menu_exit
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
179
307
|
main_menu.item 'See logs' do
|
180
308
|
CursesMenu.new(
|
181
309
|
'Modsvaskr - Stronghold of Mods > Logs',
|
data/lib/modsvaskr/version.rb
CHANGED
data/lib/modsvaskr/xedit.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'modsvaskr/encoding'
|
3
|
+
require 'modsvaskr/logger'
|
3
4
|
require 'modsvaskr/run_cmd'
|
4
5
|
|
5
6
|
module Modsvaskr
|
@@ -7,6 +8,7 @@ module Modsvaskr
|
|
7
8
|
# Helper to use an instance of xEdit
|
8
9
|
class Xedit
|
9
10
|
|
11
|
+
include Logger
|
10
12
|
include RunCmd
|
11
13
|
|
12
14
|
# String: Installation path
|
@@ -49,6 +51,24 @@ module Modsvaskr
|
|
49
51
|
@runs[script] = nil
|
50
52
|
end
|
51
53
|
|
54
|
+
# Run a QuickAutoClean of a given plugin
|
55
|
+
#
|
56
|
+
# Parameters::
|
57
|
+
# * *esp* (String): Plugin to autoclean
|
58
|
+
def quick_auto_clean(esp)
|
59
|
+
# TODO: Find a way to select the right esp automatically
|
60
|
+
out "Please double-click on the following plugin: #{esp}"
|
61
|
+
run_cmd(
|
62
|
+
{
|
63
|
+
dir: @install_path,
|
64
|
+
exe: 'SSEEdit.exe'
|
65
|
+
},
|
66
|
+
args: %w[
|
67
|
+
-quickautoclean
|
68
|
+
]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
52
72
|
# Parse a CSV that has been dumped by a previous run of xEdit
|
53
73
|
#
|
54
74
|
# Parameters::
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: modsvaskr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muriel Salvan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses_menu
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: elder_scrolls_plugin
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +38,48 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: launchy
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.5'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mod_organizer
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: nokogiri
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
75
|
+
version: '1.14'
|
48
76
|
type: :runtime
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
82
|
+
version: '1.14'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rspec
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,28 +128,28 @@ dependencies:
|
|
100
128
|
requirements:
|
101
129
|
- - "~>"
|
102
130
|
- !ruby/object:Gem::Version
|
103
|
-
version: '1.
|
131
|
+
version: '1.47'
|
104
132
|
type: :development
|
105
133
|
prerelease: false
|
106
134
|
version_requirements: !ruby/object:Gem::Requirement
|
107
135
|
requirements:
|
108
136
|
- - "~>"
|
109
137
|
- !ruby/object:Gem::Version
|
110
|
-
version: '1.
|
138
|
+
version: '1.47'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: rubocop-rspec
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
114
142
|
requirements:
|
115
143
|
- - "~>"
|
116
144
|
- !ruby/object:Gem::Version
|
117
|
-
version: '2.
|
145
|
+
version: '2.18'
|
118
146
|
type: :development
|
119
147
|
prerelease: false
|
120
148
|
version_requirements: !ruby/object:Gem::Requirement
|
121
149
|
requirements:
|
122
150
|
- - "~>"
|
123
151
|
- !ruby/object:Gem::Version
|
124
|
-
version: '2.
|
152
|
+
version: '2.18'
|
125
153
|
description: Command-line UI handling a full Mods' ecosystem for Bethesda's games.
|
126
154
|
email:
|
127
155
|
- muriel@x-aeon.com
|