Force-enable "Enderal - Forgotten Stories.esm" with EnderalSE.dll
This commit is contained in:
parent
0769eeba5c
commit
e19b182ac1
@ -6,7 +6,13 @@ static bool bMessageShown = false;
|
||||
|
||||
static std::unordered_set<std::string> aModNames;
|
||||
|
||||
inline bool DataFileExists(std::string filename, int maxSize = 1000000)
|
||||
inline bool DataFileExists(std::string filename)
|
||||
{
|
||||
const auto path = std::format("Data\\{}", filename);
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
inline bool DLCExists(std::string filename, int maxSize = 1000000)
|
||||
{
|
||||
const auto path = std::format("Data\\{}", filename);
|
||||
return std::filesystem::exists(path) && std::filesystem::file_size(path) > maxSize;
|
||||
@ -745,13 +751,13 @@ inline void CheckCCMods()
|
||||
};
|
||||
|
||||
for (short i = 0; i < 73; i++) {
|
||||
if (DataFileExists(filenames[i], 800)) {
|
||||
if (DLCExists(filenames[i], 800)) {
|
||||
MessageBoxW(NULL, L"Creation Club mods are incompatible with Enderal.", L"Error", MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (DataFileExists("ccBGSSSE001-Fish.esm", 1200000)) {
|
||||
if (DLCExists("ccBGSSSE001-Fish.esm", 1200000)) {
|
||||
MessageBoxW(NULL, L"Fishing CC are incompatible with Enderal without a patch.", L"Error", MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -158,17 +158,17 @@ SKSEPluginLoad(const LoadInterface* skse) {
|
||||
}
|
||||
}
|
||||
|
||||
if (DataFileExists("Dawnguard.esm") || DataFileExists("Dragonborn.esm") || DataFileExists("HearthFires.esm") || DataFileExists("Update.esm")) {
|
||||
if (DLCExists("Dawnguard.esm") || DLCExists("Dragonborn.esm") || DLCExists("HearthFires.esm") || DLCExists("Update.esm")) {
|
||||
MessageBoxW(NULL, L"Skyrim DLCs are incompatible with Enderal.", L"Enderal SE Error", MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (DataFileExists("Unofficial Skyrim Special Edition Patch.esp")) {
|
||||
if (DLCExists("Unofficial Skyrim Special Edition Patch.esp")) {
|
||||
MessageBoxW(NULL, L"Unofficial Skyrim Special Edition Patch is incompatible with Enderal.", L"Enderal SE Error", MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!DataFileExists("Enderal - Forgotten Stories.esm")) {
|
||||
if (!DLCExists("Enderal - Forgotten Stories.esm")) {
|
||||
MessageBoxW(NULL, L"Enderal - Forgotten Stories.esm is not loaded!", L"Enderal SE Error", MB_OK | MB_ICONERROR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -178,6 +178,7 @@ SKSEPluginLoad(const LoadInterface* skse) {
|
||||
GetLoadInterface(skse);
|
||||
|
||||
InitializeLogging();
|
||||
EnsurePluginsTxt();
|
||||
|
||||
auto* plugin = PluginDeclaration::GetSingleton();
|
||||
auto version = plugin->GetVersion();
|
||||
|
||||
@ -331,3 +331,186 @@ inline RE::BSFixedString StringToHex(RE::BSFixedString a_string)
|
||||
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
inline std::filesystem::path GetPluginsTxtPath()
|
||||
{
|
||||
wchar_t* buffer{ nullptr };
|
||||
const auto result = ::SHGetKnownFolderPath(::FOLDERID_LocalAppData, ::KNOWN_FOLDER_FLAG::KF_FLAG_DEFAULT, nullptr, std::addressof(buffer));
|
||||
std::unique_ptr<wchar_t[], decltype(&::CoTaskMemFree)> knownPath(buffer, ::CoTaskMemFree);
|
||||
|
||||
if (!knownPath || result != S_OK) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::filesystem::path path = knownPath.get();
|
||||
|
||||
bool hasRedirector = GetLoadInterface()->GetPluginInfo("Skyrim Redirector") != nullptr;
|
||||
bool isGOG = GetModuleHandle(L"Galaxy64.dll") != NULL;
|
||||
|
||||
if (hasRedirector) {
|
||||
path /= isGOG ? "Enderal Special Edition GOG"sv : "Enderal Special Edition"sv;
|
||||
} else {
|
||||
path /= isGOG ? "Skyrim Special Edition GOG"sv : "Skyrim Special Edition"sv;
|
||||
}
|
||||
|
||||
path /= "plugins.txt"sv;
|
||||
return path;
|
||||
}
|
||||
|
||||
// Reads plugins.txt and returns the lines
|
||||
inline std::vector<std::string> ReadPluginsTxt(const std::filesystem::path& pluginsPath)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
if (std::filesystem::exists(pluginsPath)) {
|
||||
std::ifstream inFile(pluginsPath);
|
||||
if (inFile.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(inFile, line)) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
inFile.close();
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Writes lines to plugins.txt
|
||||
inline bool WritePluginsTxt(const std::filesystem::path& pluginsPath, const std::vector<std::string>& lines)
|
||||
{
|
||||
std::filesystem::create_directories(pluginsPath.parent_path());
|
||||
std::ofstream outFile(pluginsPath);
|
||||
if (outFile.is_open()) {
|
||||
for (const auto& line : lines) {
|
||||
outFile << line << "\n";
|
||||
}
|
||||
outFile.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gets the plugin name from a line (strips asterisk if present)
|
||||
inline std::string GetPluginNameFromLine(const std::string& line)
|
||||
{
|
||||
if (!line.empty() && line[0] == '*') {
|
||||
return line.substr(1);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
// Checks if a line is a comment or empty
|
||||
inline bool IsCommentOrEmpty(const std::string& line)
|
||||
{
|
||||
return line.empty() || line[0] == '#';
|
||||
}
|
||||
|
||||
// Ensures a plugin is enabled in plugins.txt (adds asterisk if missing, adds to file if not present)
|
||||
// Only operates if the plugin file exists in Data folder
|
||||
// Returns true if plugins.txt was modified
|
||||
inline bool EnsurePluginEnabled(std::vector<std::string>& lines, const char* pluginName)
|
||||
{
|
||||
if (!DataFileExists(pluginName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string enabledEntry = std::string("*") + pluginName;
|
||||
|
||||
for (auto& line : lines) {
|
||||
if (IsCommentOrEmpty(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = GetPluginNameFromLine(line);
|
||||
if (name == pluginName) {
|
||||
if (line[0] != '*') {
|
||||
logger::info("{} found but not enabled, enabling it", pluginName);
|
||||
line = enabledEntry;
|
||||
return true;
|
||||
}
|
||||
// Already enabled
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin not found in plugins.txt, add it at the end
|
||||
logger::info("{} not found in plugins.txt, adding it", pluginName);
|
||||
lines.push_back(enabledEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Moves a plugin to the first position (after comments)
|
||||
// Returns true if plugins.txt was modified
|
||||
inline bool EnsurePluginFirst(std::vector<std::string>& lines, const char* pluginName)
|
||||
{
|
||||
int pluginIndex = -1;
|
||||
int firstPluginIndex = -1;
|
||||
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
if (IsCommentOrEmpty(lines[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (firstPluginIndex == -1) {
|
||||
firstPluginIndex = static_cast<int>(i);
|
||||
}
|
||||
|
||||
std::string name = GetPluginNameFromLine(lines[i]);
|
||||
if (name == pluginName) {
|
||||
pluginIndex = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pluginIndex == -1) {
|
||||
// Plugin not in list
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pluginIndex == firstPluginIndex) {
|
||||
// Already first
|
||||
return false;
|
||||
}
|
||||
|
||||
logger::info("{} found but not first plugin (at index {}, first plugin at {}), moving to first position",
|
||||
pluginName, pluginIndex, firstPluginIndex);
|
||||
|
||||
// Save the plugin line and remove it from current position
|
||||
std::string pluginLine = lines[pluginIndex];
|
||||
lines.erase(lines.begin() + pluginIndex);
|
||||
|
||||
// Insert at first plugin position
|
||||
lines.insert(lines.begin() + firstPluginIndex, pluginLine);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void EnsurePluginsTxt()
|
||||
{
|
||||
auto pluginsPath = GetPluginsTxtPath();
|
||||
if (pluginsPath.empty()) {
|
||||
logger::error("Failed to get plugins.txt path");
|
||||
return;
|
||||
}
|
||||
|
||||
logger::info("Checking plugins.txt at: {}", pluginsPath.string());
|
||||
|
||||
std::vector<std::string> lines = ReadPluginsTxt(pluginsPath);
|
||||
bool modified = false;
|
||||
|
||||
// Ensure required plugins are enabled
|
||||
modified |= EnsurePluginEnabled(lines, "Enderal - Forgotten Stories.esm");
|
||||
modified |= EnsurePluginEnabled(lines, "SkyUI_SE.esp");
|
||||
|
||||
// Ensure Enderal ESM is first
|
||||
modified |= EnsurePluginFirst(lines, "Enderal - Forgotten Stories.esm");
|
||||
|
||||
if (modified) {
|
||||
if (WritePluginsTxt(pluginsPath, lines)) {
|
||||
logger::info("Successfully updated plugins.txt");
|
||||
} else {
|
||||
logger::error("Failed to write plugins.txt");
|
||||
}
|
||||
} else {
|
||||
logger::info("plugins.txt is correctly configured");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user