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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29dad9a5413e803a1980b6d0d9aa4f71e66c8c233c0398b30eacb03c3a35d563
4
- data.tar.gz: 0b9fb7f2efd87394746327fd79783717cb0871eb83f5447a395b411e8c8adfd9
3
+ metadata.gz: 3b3bda4db035df3b3289829342c1a70a47be0191de49f35e72c2e25f6e8aaada
4
+ data.tar.gz: bed82e160e1310241b870e8545a08913b81caf210f5388121afd1fc465ad01c1
5
5
  SHA512:
6
- metadata.gz: 55cc0a939035ec8dbebb92f4d2e96f168faeb81b486370122951c795933088214ec90585fb6fe2a62d2cb6be55a86a1ab4d7062c43a5a7056abe4292ecbb82d5
7
- data.tar.gz: aeb1f38ccfa4cf5f1e0362b350ad8f219e6ac92b2a3c5bf1027e4a03a3f45242d5a00fc02fc3425d420e8e72669e3c3135f415ad4b926692ef45581bb494af24
6
+ metadata.gz: 35e165ef5571a0a54c47393aea22ec848e42be1d6d27940f8a23e24fba00b35da00677049b474d1370ba7b4fadf4de9088089ec8cb582ceb8c2c1de489490cf5
7
+ data.tar.gz: '08ade008d6263b3bef50df32efeda147e409e2f9c7644177ccaa03c112a9aafdb4f54e3102eb98b56814e6fbe42210d72df176d7e4feb0cb2341f3117faf72aa'
data/bin/modsvaskr CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
- # require 'mod_organizer'
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
@@ -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
@@ -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#{!last_modsvaskr_version.nil? && last_modsvaskr_version != Modsvaskr::VERSION ? " - !!! New version available: #{last_modsvaskr_version}" : ''}",
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',
@@ -1,5 +1,5 @@
1
1
  module Modsvaskr
2
2
 
3
- VERSION = '0.2.1'
3
+ VERSION = '1.1.0'
4
4
 
5
5
  end
@@ -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: 0.2.1
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: 2022-12-31 00:00:00.000000000 Z
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.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.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.13'
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.13'
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.41'
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.41'
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.16'
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.16'
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