Skip to content

Commit

Permalink
Shattered Space support
Browse files Browse the repository at this point in the history
- Includes blueprint update
- Add new ESM
- Reorder primary plugins
- Adapt CCC file support
- Remove obsolete CCC primary plugin fix
  • Loading branch information
Silarn committed Oct 1, 2024
1 parent 0668028 commit 2340950
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 75 deletions.
21 changes: 8 additions & 13 deletions src/game_starfield_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,42 @@
<context>
<name>GameStarfield</name>
<message>
<location filename="gamestarfield.cpp" line="143"/>
<location filename="gamestarfield.cpp" line="116"/>
<source>Starfield Support Plugin</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="153"/>
<location filename="gamestarfield.cpp" line="126"/>
<source>Adds support for the game Starfield.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="166"/>
<location filename="gamestarfield.cpp" line="139"/>
<source>Show a warning when ESP plugins are enabled in the load order.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="169"/>
<location filename="gamestarfield.cpp" line="142"/>
<source>Show a warning when plugins.txt management is invalid.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="172"/>
<source>Utilize Starfield.ccc to affix core plugin load order (will override existing file).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="429"/>
<location filename="gamestarfield.cpp" line="397"/>
<source>You have active ESP plugins in Starfield</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="431"/>
<location filename="gamestarfield.cpp" line="399"/>
<source>sTestFile entries are present</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="441"/>
<location filename="gamestarfield.cpp" line="409"/>
<source>&lt;p&gt;ESP plugins are not ideal for Starfield. In addition to being unable to sort them alongside ESM or master-flagged plugins, certain record references are always kept loaded by the game. This consumes unnecessary resources and limits the game&apos;s ability to load what it needs.&lt;/p&gt;&lt;p&gt;Ideally, plugins should be saved as ESM files upon release. It can also be released as an ESL plugin, however there are additional concerns with the way light plugins are currently handled and should only be used when absolutely certain about what you&apos;re doing.&lt;/p&gt;&lt;p&gt;Notably, xEdit does not currently support saving ESP files.&lt;/p&gt;&lt;h4&gt;Current ESPs:&lt;/h4&gt;&lt;p&gt;%1&lt;/p&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="gamestarfield.cpp" line="455"/>
<location filename="gamestarfield.cpp" line="423"/>
<source>&lt;p&gt;You have plugin managment enabled but you still have sTestFile settings in your StarfieldCustom.ini. These must be removed or the game will not read the plugins.txt file. Management is still disabled.&lt;/p&gt;</source>
<translation type="unfinished"></translation>
</message>
Expand Down
90 changes: 29 additions & 61 deletions src/gamestarfield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,36 +53,9 @@ bool GameStarfield::init(IOrganizer* moInfo)
registerFeature(std::make_shared<StarfieldUnmanagedMods>(this, localAppFolder()));
registerFeature(std::make_shared<StarfieldBSAInvalidation>(dataArchives.get(), this));

m_Organizer->pluginList()->onRefreshed([&]() {
setCCCFile();
});

return true;
}

/*
* This is used to write the primary plugins to a profile-based Starfield.ccc file. We
* map this into the game directory with the VFS. The game does not currently ship with
* this file but does still read it like SkyrimSE and Fallout 4. We can make use of it
* to correct the current behavior where core plugins are loaded after parsing
* plugins.txt leading to ambiguous load orders.
*/
void GameStarfield::setCCCFile() const
{
if (m_Organizer->profilePath().isEmpty())
return;
if (m_Organizer->pluginSetting(name(), "enable_loadorder_fix").toBool()) {
QFile cccFile(m_Organizer->profilePath() + "/Starfield.ccc");
if (cccFile.open(QIODevice::WriteOnly)) {
auto plugins = primaryPlugins();
for (auto plugin : plugins) {
cccFile.write(plugin.toUtf8());
cccFile.write("\n");
}
}
}
}

QString GameStarfield::gameName() const
{
return "Starfield";
Expand Down Expand Up @@ -167,18 +140,11 @@ QList<PluginSetting> GameStarfield::settings() const
true)
<< PluginSetting("enable_management_warnings",
tr("Show a warning when plugins.txt management is invalid."),
true)
<< PluginSetting("enable_loadorder_fix",
tr("Utilize Starfield.ccc to affix core plugin load order "
"(will override existing file)."),
true);
}

MappingType GameStarfield::mappings() const
{
if (m_Organizer->pluginSetting(name(), "enable_loadorder_fix").toBool()) {
setCCCFile();
}
MappingType result;
if (testFilePlugins().isEmpty()) {
for (const QString& profileFile : {"plugins.txt", "loadorder.txt"}) {
Expand All @@ -187,14 +153,6 @@ MappingType GameStarfield::mappings() const
false});
}
}
if (m_Organizer->pluginSetting(name(), "enable_loadorder_fix").toBool()) {
// map the Starfield.ccc from the profile to both the game folder and the My Games
// folder (used by LOOT for instance)
result.push_back({m_Organizer->profilePath() + "/" + "Starfield.ccc",
gameDirectory().absolutePath() + "/" + "Starfield.ccc", false});
result.push_back({m_Organizer->profilePath() + "/" + "Starfield.ccc",
myGamesPath() + "/" + "Starfield.ccc", false});
}
return result;
}

Expand Down Expand Up @@ -255,18 +213,22 @@ QStringList GameStarfield::testFilePlugins() const

QStringList GameStarfield::primaryPlugins() const
{
QStringList plugins = {"Starfield.esm", "Constellation.esm",
"OldMars.esm", "BlueprintShips-Starfield.esm",
"SFBGS007.esm", "SFBGS008.esm",
"SFBGS006.esm", "SFBGS003.esm",
"SFBGS004.esm"};
QStringList plugins = {"Starfield.esm", "Constellation.esm",
"ShatteredSpace.esm", "OldMars.esm",
"SFBGS003.esm", "SFBGS004.esm",
"SFBGS006.esm", "SFBGS007.esm",
"SFBGS008.esm", "BlueprintShips-Starfield.esm"};

plugins << CCCPlugins();

auto testPlugins = testFilePlugins();
if (loadOrderMechanism() == LoadOrderMechanism::None) {
plugins << enabledPlugins();
plugins << testPlugins;
}

plugins.removeDuplicates();

return plugins;
}

Expand Down Expand Up @@ -302,42 +264,48 @@ bool GameStarfield::prepareIni(const QString& exec)

QStringList GameStarfield::DLCPlugins() const
{
return {};
return {"Constellation.esm", "ShatteredSpace.esm"};
}

QStringList GameStarfield::CCPlugins() const
QStringList GameStarfield::CCCPlugins() const
{
// While the CCC file appears to be mostly legacy, we need to parse it since the game
// will still read it and there are some compatibility reason to use it for
// force-loading the core game plugins.
QStringList plugins = {};
QStringList corePlugins = primaryPlugins() + DLCPlugins();
QStringList plugins = {};
if (!testFilePresent()) {
QFile file(gameDirectory().absoluteFilePath("Starfield.ccc"));
if (m_Organizer->pluginSetting(name(), "enable_loadorder_fix").toBool() &&
!m_Organizer->profilePath().isEmpty()) {
file.setFileName(m_Organizer->profilePath() + "/Starfield.ccc");
QFile myDocsCCCFile(myGamesPath() + "\Starfield.ccc");
QFile gameCCCFile(gameDirectory().absoluteFilePath("Starfield.ccc"));
QFile* file;
if (myDocsCCCFile.exists()) {
file = &myDocsCCCFile;
} else {
file = &gameCCCFile;
}
if (file.open(QIODevice::ReadOnly)) {
if (file.size() > 0) {
while (!file.atEnd()) {
QByteArray line = file.readLine().trimmed();
if (file->open(QIODevice::ReadOnly)) {
if (file->size() > 0) {
while (!file->atEnd()) {
QByteArray line = file->readLine().trimmed();
QString modName;
if ((line.size() > 0) && (line.at(0) != '#')) {
modName = QString::fromUtf8(line.constData()).toLower();
}

if (modName.size() > 0) {
if (!plugins.contains(modName, Qt::CaseInsensitive) &&
!corePlugins.contains(modName, Qt::CaseInsensitive)) {
if (!plugins.contains(modName, Qt::CaseInsensitive)) {
plugins.append(modName);
}
}
}
}
}
}
return plugins;
}

QStringList GameStarfield::CCPlugins() const
{
QStringList plugins = {};
std::shared_ptr<StarfieldUnmanagedMods> unmanagedMods =
std::static_pointer_cast<StarfieldUnmanagedMods>(
m_Organizer->gameFeatures()->gameFeature<MOBase::UnmanagedMods>());
Expand Down
2 changes: 1 addition & 1 deletion src/gamestarfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ class GameStarfield : public GameGamebryo, public MOBase::IPluginDiagnose
QString savegameSEExtension() const override;

private:
QStringList CCCPlugins() const;
bool activeESP() const;
bool testFilePresent() const;
void setCCCFile() const;

private:
static const unsigned int PROBLEM_ESP = 1;
Expand Down
5 changes: 5 additions & 0 deletions src/starfieldgameplugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ bool StarfieldGamePlugins::mediumPluginsAreSupported()
return true;
}

bool StarfieldGamePlugins::blueprintPluginsAreSupported()
{
return true;
}

void StarfieldGamePlugins::writePluginList(const IPluginList* pluginList,
const QString& filePath)
{
Expand Down
1 change: 1 addition & 0 deletions src/starfieldgameplugins.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class StarfieldGamePlugins : public CreationGamePlugins

protected:
virtual bool mediumPluginsAreSupported() override;
virtual bool blueprintPluginsAreSupported() override;
virtual void writePluginList(const MOBase::IPluginList* pluginList,
const QString& filePath) override;
virtual QStringList readPluginList(MOBase::IPluginList* pluginList) override;
Expand Down

0 comments on commit 2340950

Please sign in to comment.