|
1 | 1 | #include "gamestarfield.h"
|
2 | 2 |
|
| 3 | +#include "ipluginlist.h" |
| 4 | + |
3 | 5 | #include "starfieldbsainvalidation.h"
|
4 | 6 | #include "starfielddataarchives.h"
|
5 | 7 | #include "starfieldgameplugins.h"
|
|
16 | 18 | #include <pluginsetting.h>
|
17 | 19 |
|
18 | 20 | #include <QCoreApplication>
|
| 21 | +#include <QDesktopServices> |
19 | 22 | #include <QDir>
|
20 | 23 | #include <QFileInfo>
|
21 | 24 | #include <QList>
|
|
26 | 29 | #include <memory>
|
27 | 30 |
|
28 | 31 | #include "scopeguard.h"
|
| 32 | +#include "utility.h" |
29 | 33 |
|
30 | 34 | using namespace MOBase;
|
31 | 35 |
|
@@ -131,7 +135,19 @@ QList<PluginSetting> GameStarfield::settings() const
|
131 | 135 | tr("Turn on plugin management. As of Starfield 1.7.33 this "
|
132 | 136 | "REQUIRES fixing 'plugins.txt' with a SFSE plugin. This "
|
133 | 137 | "will do nothing otherwise."),
|
134 |
| - false); |
| 138 | + false) |
| 139 | + << PluginSetting( |
| 140 | + "enable_esp_warning", |
| 141 | + tr("Show a warning when ESP plugins are enabled in the load order."), |
| 142 | + true) |
| 143 | + << PluginSetting( |
| 144 | + "enable_esl_warning", |
| 145 | + tr("Show a warning when light plugins are enabled in the load order."), |
| 146 | + true) |
| 147 | + << PluginSetting("enable_overlay_warning", |
| 148 | + tr("Show a warning when overlay-flagged plugins ar enabled " |
| 149 | + "in the load order."), |
| 150 | + true); |
135 | 151 | }
|
136 | 152 |
|
137 | 153 | MappingType GameStarfield::mappings() const
|
@@ -307,3 +323,204 @@ int GameStarfield::nexusGameID() const
|
307 | 323 | {
|
308 | 324 | return 4187;
|
309 | 325 | }
|
| 326 | + |
| 327 | +// Start Diagnose |
| 328 | +std::vector<unsigned int> GameStarfield::activeProblems() const |
| 329 | +{ |
| 330 | + std::vector<unsigned int> result; |
| 331 | + if (m_Organizer->managedGame() == this) { |
| 332 | + if (m_Organizer->pluginSetting(name(), "enable_esp_warning").toBool() && |
| 333 | + activeESP()) |
| 334 | + result.push_back(PROBLEM_ESP); |
| 335 | + if (m_Organizer->pluginSetting(name(), "enable_esl_warning").toBool() && |
| 336 | + activeESL()) |
| 337 | + result.push_back(PROBLEM_ESL); |
| 338 | + if (m_Organizer->pluginSetting(name(), "enable_overlay_warning").toBool() && |
| 339 | + activeOverlay()) |
| 340 | + result.push_back(PROBLEM_OVERLAY); |
| 341 | + if (testFilePresent()) |
| 342 | + result.push_back(PROBLEM_TEST_FILE); |
| 343 | + else if (pluginsTxtEnabler()) |
| 344 | + result.push_back(PROBLEM_PLUGINS_TXT); |
| 345 | + } |
| 346 | + return result; |
| 347 | +} |
| 348 | + |
| 349 | +bool GameStarfield::activeESP() const |
| 350 | +{ |
| 351 | + m_Active_ESPs.clear(); |
| 352 | + std::set<QString> enabledPlugins; |
| 353 | + |
| 354 | + QStringList esps = m_Organizer->findFiles("", [](const QString& fileName) -> bool { |
| 355 | + return fileName.endsWith(".esp", FileNameComparator::CaseSensitivity); |
| 356 | + }); |
| 357 | + |
| 358 | + for (const QString& esp : esps) { |
| 359 | + QString baseName = QFileInfo(esp).fileName(); |
| 360 | + if (m_Organizer->pluginList()->state(baseName) == IPluginList::STATE_ACTIVE) { |
| 361 | + m_Active_ESPs.insert(baseName); |
| 362 | + } |
| 363 | + } |
| 364 | + |
| 365 | + if (!m_Active_ESPs.empty()) |
| 366 | + return true; |
| 367 | + return false; |
| 368 | +} |
| 369 | + |
| 370 | +bool GameStarfield::activeESL() const |
| 371 | +{ |
| 372 | + m_Active_ESLs.clear(); |
| 373 | + std::set<QString> enabledPlugins; |
| 374 | + |
| 375 | + QStringList esps = m_Organizer->findFiles("", [](const QString& fileName) -> bool { |
| 376 | + return fileName.endsWith(".esp", FileNameComparator::CaseSensitivity) || |
| 377 | + fileName.endsWith(".esm", FileNameComparator::CaseSensitivity) || |
| 378 | + fileName.endsWith(".esl", FileNameComparator::CaseSensitivity); |
| 379 | + }); |
| 380 | + |
| 381 | + for (const QString& esp : esps) { |
| 382 | + QString baseName = QFileInfo(esp).fileName(); |
| 383 | + if (primaryPlugins().contains(baseName, Qt::CaseInsensitive)) |
| 384 | + continue; |
| 385 | + if (m_Organizer->pluginList()->state(baseName) == IPluginList::STATE_ACTIVE && |
| 386 | + !m_Organizer->pluginList()->hasNoRecords(baseName)) |
| 387 | + if (m_Organizer->pluginList()->hasLightExtension(baseName) || |
| 388 | + m_Organizer->pluginList()->isLightFlagged(baseName)) |
| 389 | + m_Active_ESLs.insert(baseName); |
| 390 | + } |
| 391 | + |
| 392 | + if (!m_Active_ESLs.empty()) |
| 393 | + return true; |
| 394 | + return false; |
| 395 | +} |
| 396 | + |
| 397 | +bool GameStarfield::activeOverlay() const |
| 398 | +{ |
| 399 | + m_Active_Overlays.clear(); |
| 400 | + std::set<QString> enabledPlugins; |
| 401 | + |
| 402 | + QStringList esps = m_Organizer->findFiles("", [](const QString& fileName) -> bool { |
| 403 | + return fileName.endsWith(".esp", FileNameComparator::CaseSensitivity) || |
| 404 | + fileName.endsWith(".esm", FileNameComparator::CaseSensitivity) || |
| 405 | + fileName.endsWith(".esl", FileNameComparator::CaseSensitivity); |
| 406 | + }); |
| 407 | + |
| 408 | + for (const QString& esp : esps) { |
| 409 | + QString baseName = QFileInfo(esp).fileName(); |
| 410 | + if (primaryPlugins().contains(baseName, Qt::CaseInsensitive)) |
| 411 | + continue; |
| 412 | + if (m_Organizer->pluginList()->state(baseName) == IPluginList::STATE_ACTIVE) { |
| 413 | + if (m_Organizer->pluginList()->isOverlayFlagged(baseName)) |
| 414 | + m_Active_Overlays.insert(baseName); |
| 415 | + } |
| 416 | + } |
| 417 | + |
| 418 | + if (!m_Active_Overlays.empty()) |
| 419 | + return true; |
| 420 | + return false; |
| 421 | +} |
| 422 | + |
| 423 | +bool GameStarfield::testFilePresent() const |
| 424 | +{ |
| 425 | + if (m_Organizer->pluginSetting(name(), "enable_plugin_management").toBool() && |
| 426 | + !testFilePlugins().isEmpty()) |
| 427 | + return true; |
| 428 | + return false; |
| 429 | +} |
| 430 | + |
| 431 | +bool GameStarfield::pluginsTxtEnabler() const |
| 432 | +{ |
| 433 | + if (sortMechanism() != SortMechanism::NONE) { |
| 434 | + auto files = m_Organizer->findFiles("sfse\\plugins", {"sfpluginstxtenabler.dll"}); |
| 435 | + if (files.isEmpty()) |
| 436 | + return true; |
| 437 | + } |
| 438 | + return false; |
| 439 | +} |
| 440 | + |
| 441 | +QString GameStarfield::shortDescription(unsigned int key) const |
| 442 | +{ |
| 443 | + switch (key) { |
| 444 | + case PROBLEM_ESP: |
| 445 | + return tr("You have active ESP plugins in Starfield"); |
| 446 | + case PROBLEM_ESL: |
| 447 | + return tr("You have active ESL plugins in Starfield"); |
| 448 | + case PROBLEM_OVERLAY: |
| 449 | + return tr("You have active overlay plugins"); |
| 450 | + case PROBLEM_TEST_FILE: |
| 451 | + return tr("sTestFile entries are present"); |
| 452 | + case PROBLEM_PLUGINS_TXT: |
| 453 | + return tr("Plugins.txt Enabler missing"); |
| 454 | + } |
| 455 | +} |
| 456 | + |
| 457 | +QString GameStarfield::fullDescription(unsigned int key) const |
| 458 | +{ |
| 459 | + switch (key) { |
| 460 | + case PROBLEM_ESP: { |
| 461 | + QString espInfo = SetJoin(m_Active_ESPs, ", "); |
| 462 | + return tr("<p>ESP plugins are not ideal for Starfield. In addition to being unable " |
| 463 | + "to sort them alongside ESM or master-flagged plugins, certain record " |
| 464 | + "references are always kept loaded by the game. This consumes " |
| 465 | + "unnecessary resources and limits the game's ability to load what it " |
| 466 | + "needs.</p>" |
| 467 | + "<p>Ideally, plugins should be saved as ESM files upon release. It can " |
| 468 | + "also be released as an ESL plugin, however there are additional " |
| 469 | + "concerns with the way light plugins are currently handled and should " |
| 470 | + "only be used when absolutely certain about what you're doing.</p>" |
| 471 | + "<p>Notably, xEdit does not currently support saving ESP files.</p>" |
| 472 | + "<h4>Current ESPs:</h4><p>%1</p>") |
| 473 | + .arg(espInfo); |
| 474 | + } |
| 475 | + case PROBLEM_ESL: { |
| 476 | + QString eslInfo = SetJoin(m_Active_ESLs, ", "); |
| 477 | + return tr("<p>Light plugins work differently in Starfield. They use a different " |
| 478 | + "base form ID compared with standard plugin files.</p>" |
| 479 | + "<p>What this means is that you can't just change a standard plugin to a " |
| 480 | + "light plugin at will, it can and will break any dependent plugin. If " |
| 481 | + "you do so, be absolutely certain no other plugins use that plugin as a " |
| 482 | + "master.</p>" |
| 483 | + "<p>Notably, xEdit does not currently support saving or loading ESL " |
| 484 | + "files under these conditions.<p>" |
| 485 | + "<h4>Current ESLs:</h4><p>%1</p>") |
| 486 | + .arg(eslInfo); |
| 487 | + } |
| 488 | + case PROBLEM_OVERLAY: { |
| 489 | + QString overlayInfo = SetJoin(m_Active_Overlays, ", "); |
| 490 | + return tr("<p>Overlay-flagged plugins are not currently recommended. In theory, " |
| 491 | + "they should allow you to update existing records without utilizing " |
| 492 | + "additional load order slots. Unfortunately, it appears that the game " |
| 493 | + "still allocates the slots as if these were standard plugins. Therefore, " |
| 494 | + "at the moment there is no real use for this plugin flag.</p>" |
| 495 | + "<p>Notably, xEdit does not currently support saving or loading " |
| 496 | + "overlay-flagged files under these conditions.</p>" |
| 497 | + "<h4>Current Overlays:</h4><p>%1</p>") |
| 498 | + .arg(overlayInfo); |
| 499 | + } |
| 500 | + case PROBLEM_TEST_FILE: { |
| 501 | + return tr("<p>You have plugin managment enabled but you still have sTestFile " |
| 502 | + "settings in your StarfieldCustom.ini. These must be removed or the game " |
| 503 | + "will not read the plugins.txt file. Management is still disabled.</p>"); |
| 504 | + } |
| 505 | + case PROBLEM_PLUGINS_TXT: { |
| 506 | + return tr("<p>You have plugin management turned on but do not have the Plugins.txt " |
| 507 | + "Enabler SFSE plugin installed. Plugin file management for Starfield " |
| 508 | + "will not work without this SFSE plugin.</p>"); |
| 509 | + } |
| 510 | + } |
| 511 | +} |
| 512 | + |
| 513 | +bool GameStarfield::hasGuidedFix(unsigned int key) const |
| 514 | +{ |
| 515 | + if (key == PROBLEM_PLUGINS_TXT) |
| 516 | + return true; |
| 517 | + return false; |
| 518 | +} |
| 519 | + |
| 520 | +void GameStarfield::startGuidedFix(unsigned int key) const |
| 521 | +{ |
| 522 | + if (key == PROBLEM_PLUGINS_TXT) { |
| 523 | + QDesktopServices::openUrl( |
| 524 | + QUrl("https://www.nexusmods.com/starfield/mods/4157?tab=files")); |
| 525 | + } |
| 526 | +} |
0 commit comments