From 49aaac74360627ac99dadae329c471fc3ab1a449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Wed, 24 Feb 2021 21:52:02 +0100 Subject: [PATCH] Initial commit. --- .gitignore | 5 + CMakeLists.txt | 12 ++ appveyor.yml | 40 +++++ src/CMakeLists.txt | 7 + src/enderalsebsainvalidation.cpp | 16 ++ src/enderalsebsainvalidation.h | 23 +++ src/enderalsedataarchives.cpp | 66 ++++++++ src/enderalsedataarchives.h | 29 ++++ src/enderalsemoddatachecker.h | 30 ++++ src/enderalsemoddatacontent.h | 20 +++ src/enderalsesavegame.cpp | 116 +++++++++++++ src/enderalsesavegame.h | 29 ++++ src/enderalsescriptextender.cpp | 19 +++ src/enderalsescriptextender.h | 18 ++ src/enderalseunmanagedmods.cpp | 32 ++++ src/enderalseunmanagedmods.h | 19 +++ src/game_enderalse_en.ts | 17 ++ src/gameenderalse.cpp | 281 +++++++++++++++++++++++++++++++ src/gameenderalse.h | 75 +++++++++ src/gameenderalse.json | 1 + 20 files changed, 855 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 appveyor.yml create mode 100644 src/CMakeLists.txt create mode 100644 src/enderalsebsainvalidation.cpp create mode 100644 src/enderalsebsainvalidation.h create mode 100644 src/enderalsedataarchives.cpp create mode 100644 src/enderalsedataarchives.h create mode 100644 src/enderalsemoddatachecker.h create mode 100644 src/enderalsemoddatacontent.h create mode 100644 src/enderalsesavegame.cpp create mode 100644 src/enderalsesavegame.h create mode 100644 src/enderalsescriptextender.cpp create mode 100644 src/enderalsescriptextender.h create mode 100644 src/enderalseunmanagedmods.cpp create mode 100644 src/enderalseunmanagedmods.h create mode 100644 src/game_enderalse_en.ts create mode 100644 src/gameenderalse.cpp create mode 100644 src/gameenderalse.h create mode 100644 src/gameenderalse.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf71be7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +edit +CMakeLists.txt.user +/msbuild.log +/*std*.log +/*build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..feaf7fd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.16) + +project(game_enderalse) +set(project_type plugin) +set(enable_warnings OFF) + +if(DEFINED DEPENDENCIES_DIR) + include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/project.cmake) +else() + include(../cmake_common/project.cmake) +endif() +add_subdirectory(src) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..2faa4a1 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,40 @@ +version: 1.0.{build} +skip_branch_with_pr: true +image: Visual Studio 2019 +environment: + WEBHOOK_URL: + secure: gOKbXaZM9ImtMD5XrYITvdyZUW/az082G9OIN1EC1Vbg57wBaeLhi49uGjxPw5GVujHku6kxN6ab89zhbS5GVeluR76GM83IbKV4Sh7udXzoYZZdg6YudtYHzdhCgUeiedpswbuczTq9ceIkkfSEWZuh/lMAAVVwvcGsJAnoPFw= +build_script: +- pwsh: >- + $ErrorActionPreference = 'Stop' + + git clone --depth=1 --no-single-branch https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella + + New-Item -ItemType Directory -Path c:\projects\modorganizer-build + + cd c:\projects\modorganizer-umbrella + + ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH -eq $null) ? ($branch = $env:APPVEYOR_REPO_BRANCH) : ($branch = $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH) + + git checkout $(git show-ref --verify --quiet refs/remotes/origin/${branch} || echo '-b') ${branch} + + C:\Python37-x64\python.exe unimake.py -d c:\projects\modorganizer-build -s Appveyor_Build=True ${env:APPVEYOR_PROJECT_NAME} + + if($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode ) } +artifacts: +- path: vsbuild\src\RelWithDebInfo\game_skyrimse.dll + name: game_skyrimse_dll +- path: vsbuild\src\RelWithDebInfo\game_skyrimse.pdb + name: game_skyrimse_pdb +- path: vsbuild\src\RelWithDebInfo\game_skyrimse.lib + name: game_skyrimse_lib +on_success: + - ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER + - ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1 + - ps: ./send.ps1 success $env:WEBHOOK_URL +on_failure: + - ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER + - ps: Push-AppveyorArtifact ${env:APPVEYOR_BUILD_FOLDER}\stdout.log + - ps: Push-AppveyorArtifact ${env:APPVEYOR_BUILD_FOLDER}\stderr.log + - ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1 + - ps: ./send.ps1 failure $env:WEBHOOK_URL \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..1f12c52 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.16) +if(DEFINED DEPENDENCIES_DIR) + include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/src.cmake) +else() + include(../../cmake_common/src.cmake) +endif() +requires_project(game_gamebryo game_features) diff --git a/src/enderalsebsainvalidation.cpp b/src/enderalsebsainvalidation.cpp new file mode 100644 index 0000000..523c2de --- /dev/null +++ b/src/enderalsebsainvalidation.cpp @@ -0,0 +1,16 @@ +#include "enderalsebsainvalidation.h" + +EnderalSEBSAInvalidation::EnderalSEBSAInvalidation(DataArchives* dataArchives, MOBase::IPluginGame const* game) + : GamebryoBSAInvalidation(dataArchives, "skyrim.ini", game) +{ +} + +QString EnderalSEBSAInvalidation::invalidationBSAName() const +{ + return "Enderal - Invalidation.bsa"; +} + +unsigned long EnderalSEBSAInvalidation::bsaVersion() const +{ + return 0x69; +} \ No newline at end of file diff --git a/src/enderalsebsainvalidation.h b/src/enderalsebsainvalidation.h new file mode 100644 index 0000000..0ce5361 --- /dev/null +++ b/src/enderalsebsainvalidation.h @@ -0,0 +1,23 @@ +#ifndef ENDERALSEBSAINVALIDATION_H +#define ENDERALSEBSAINVALIDATION_H + + +#include "gamebryobsainvalidation.h" +#include "enderalsedataarchives.h" + +#include + +class EnderalSEBSAInvalidation : public GamebryoBSAInvalidation +{ +public: + + EnderalSEBSAInvalidation(DataArchives* dataArchives, MOBase::IPluginGame const* game); + +private: + + virtual QString invalidationBSAName() const override; + virtual unsigned long bsaVersion() const override; + +}; + +#endif // ENDERALSEBSAINVALIDATION_H \ No newline at end of file diff --git a/src/enderalsedataarchives.cpp b/src/enderalsedataarchives.cpp new file mode 100644 index 0000000..dcb0b20 --- /dev/null +++ b/src/enderalsedataarchives.cpp @@ -0,0 +1,66 @@ +#include "enderalSEdataarchives.h" + +#include "iprofile.h" +#include + +EnderalSEDataArchives::EnderalSEDataArchives(const QDir &myGamesDir) : + GamebryoDataArchives(myGamesDir) +{} + +QStringList EnderalSEDataArchives::vanillaArchives() const +{ + return { + "Skyrim - Textures0.bsa", + "Skyrim - Textures1.bsa", + "Skyrim - Textures2.bsa", + "Skyrim - Textures3.bsa", + "Skyrim - Textures4.bsa", + "Skyrim - Textures5.bsa", + "Skyrim - Textures6.bsa", + "Skyrim - Textures7.bsa", + "Skyrim - Textures8.bsa", + "Skyrim - Meshes0.bsa", + "Skyrim - Meshes1.bsa", + "Skyrim - Voices_en0.bsa", + "Skyrim - Sounds.bsa", + "Skyrim - Interface.bsa", + "Skyrim - Animations.bsa", + "Skyrim - Shaders.bsa", + "Skyrim - Misc.bsa", + "E - Meshes.bsa", + "E - SE.bsa", + "E - Scripts.bsa", + "E - Sounds.bsa", + "E - Textures1.bsa", + "E - Textures2.bsa", + "E - Textures3.bsa", + "L - Textures.bsa", + "L - Voices.bsa" + }; +} + + +QStringList EnderalSEDataArchives::archives(const MOBase::IProfile *profile) const +{ + QStringList result; + + QString iniFile = profile->localSettingsEnabled() ? QDir(profile->absolutePath()).absoluteFilePath("skyrim.ini") : m_LocalGameDir.absoluteFilePath("skyrim.ini"); + result.append(getArchivesFromKey(iniFile, "SResourceArchiveList")); + result.append(getArchivesFromKey(iniFile, "SResourceArchiveList2")); + + return result; +} + +void EnderalSEDataArchives::writeArchiveList(MOBase::IProfile *profile, const QStringList &before) +{ + QString list = before.join(", "); + + QString iniFile = profile->localSettingsEnabled() ? QDir(profile->absolutePath()).absoluteFilePath("skyrim.ini") : m_LocalGameDir.absoluteFilePath("skyrim.ini"); + if (list.length() > 255) { + int splitIdx = list.lastIndexOf(",", 256); + setArchivesToKey(iniFile, "SResourceArchiveList", list.mid(0, splitIdx)); + setArchivesToKey(iniFile, "SResourceArchiveList2", list.mid(splitIdx + 2)); + } else { + setArchivesToKey(iniFile, "SResourceArchiveList", list); + } +} diff --git a/src/enderalsedataarchives.h b/src/enderalsedataarchives.h new file mode 100644 index 0000000..b6954db --- /dev/null +++ b/src/enderalsedataarchives.h @@ -0,0 +1,29 @@ +#ifndef ENDERALSEDATAARCHIVES_H +#define ENDERALSEDATAARCHIVES_H + +#include "gamebryodataarchives.h" +#include +#include + +namespace MOBase { class IProfile; } + + +class EnderalSEDataArchives : public GamebryoDataArchives +{ + +public: + + EnderalSEDataArchives(const QDir &myGamesDir); + +public: + + virtual QStringList vanillaArchives() const override; + virtual QStringList archives(const MOBase::IProfile *profile) const override; + +private: + + virtual void writeArchiveList(MOBase::IProfile *profile, const QStringList &before) override; + +}; + +#endif // _SKYRIMSEDATAARCHIVES_H diff --git a/src/enderalsemoddatachecker.h b/src/enderalsemoddatachecker.h new file mode 100644 index 0000000..1a2c8ff --- /dev/null +++ b/src/enderalsemoddatachecker.h @@ -0,0 +1,30 @@ +#ifndef ENDERALSE_MODATACHECKER_H +#define ENDERALSE_MODATACHECKER_H + +#include + +class EnderalSEModDataChecker : public GamebryoModDataChecker +{ +public: + using GamebryoModDataChecker::GamebryoModDataChecker; + +protected: + virtual const FileNameSet& possibleFolderNames() const override { + static FileNameSet result{ + "fonts", "interface", "menus", "meshes", "music", "scripts", "shaders", + "sound", "strings", "textures", "trees", "video", "facegen", "materials", + "skse", "distantlod", "asi", "Tools", "MCM", "distantland", "mits", + "dllplugins", "CalienteTools", "NetScriptFramework", "shadersfx", + "Nemesis_Engine" + }; + return result; + } + virtual const FileNameSet& possibleFileExtensions() const override { + static FileNameSet result{ + "esp", "esm", "esl", "bsa", "modgroups" + }; + return result; + } +}; + +#endif // SKYRIMSE_MODATACHECKER_H diff --git a/src/enderalsemoddatacontent.h b/src/enderalsemoddatacontent.h new file mode 100644 index 0000000..d158291 --- /dev/null +++ b/src/enderalsemoddatacontent.h @@ -0,0 +1,20 @@ +#ifndef ENDERALSE_MODDATACONTENT_H +#define ENDERALSE_MODDATACONTENT_H + +#include +#include + +class EnderalSEModDataContent : public GamebryoModDataContent { +public: + + /** + * + */ + EnderalSEModDataContent(GameGamebryo const* gamePlugin) : GamebryoModDataContent(gamePlugin) { + // Just need to disable some contents: + m_Enabled[CONTENT_SKYPROC] = false; + } + +}; + +#endif // SKYRIMSE_MODDATACONTENT_H diff --git a/src/enderalsesavegame.cpp b/src/enderalsesavegame.cpp new file mode 100644 index 0000000..955c84a --- /dev/null +++ b/src/enderalsesavegame.cpp @@ -0,0 +1,116 @@ +#include "enderalsesavegame.h" + +#include + +EnderalSESaveGame::EnderalSESaveGame(QString const &fileName, GameEnderalSE const *game) : + GamebryoSaveGame(fileName, game, true) +{ + FileWrapper file(fileName, "TESV_SAVEGAME"); //10bytes + + unsigned long version; + FILETIME ftime; + fetchInformationFields(file, version, m_PCName, m_PCLevel, m_PCLocation, m_SaveNumber, ftime); + + //A file time is a 64-bit value that represents the number of 100-nanosecond + //intervals that have elapsed since 12:00 A.M. January 1, 1601 Coordinated Universal Time (UTC). + //So we need to convert that to something useful + + //For some reason, the file time is off by about 6 hours. + //So we need to subtract those 6 hours from the filetime. + _ULARGE_INTEGER time; + time.LowPart = ftime.dwLowDateTime; + time.HighPart = ftime.dwHighDateTime; + time.QuadPart -= 2.16e11; + ftime.dwHighDateTime = time.HighPart; + ftime.dwLowDateTime = time.LowPart; + + SYSTEMTIME ctime; + ::FileTimeToSystemTime(&ftime, &ctime); + + setCreationTime(ctime); +} + +void EnderalSESaveGame::fetchInformationFields( + FileWrapper& file, + unsigned long& version, + QString& playerName, + unsigned short& playerLevel, + QString& playerLocation, + unsigned long& saveNumber, + FILETIME& creationTime) const +{ + unsigned long headerSize; + file.read(headerSize); // header size "TESV_SAVEGAME" + file.read(version); + file.read(saveNumber); + file.read(playerName); + + unsigned long temp; + file.read(temp); + playerLevel = static_cast(temp); + file.read(playerLocation); + + QString timeOfDay; + file.read(timeOfDay); + + QString race; + file.read(race); // race name (i.e. BretonRace) + + file.skip(); // Player gender (0 = male) + file.skip(2); // experience gathered, experience required + + file.read(creationTime); //filetime +} + +std::unique_ptr EnderalSESaveGame::fetchDataFields() const +{ + FileWrapper file(getFilepath(), "TESV_SAVEGAME"); //10bytes + + unsigned long version = 0; + { + QString dummyName, dummyLocation; + unsigned short dummyLevel; + unsigned long dummySaveNumber; + FILETIME dummyTime; + + fetchInformationFields(file, version, dummyName, dummyLevel, + dummyLocation, dummySaveNumber, dummyTime); + } + + std::unique_ptr fields = std::make_unique(); + + unsigned long width; + unsigned long height; + file.read(width); + file.read(height); + + bool alpha = false; + + // compatibility between LE and SE: + // SE has an additional uin16_t for compression + // SE uses an alpha channel, whereas LE does not + if (version == 12) { + uint16_t compressionType; + file.read(compressionType); + file.setCompressionType(compressionType); + alpha = true; + } + + fields->Screenshot = file.readImage(width, height, 320, alpha); + + file.openCompressedData(); + + uint8_t saveGameVersion = file.readChar(); + uint8_t pluginInfoSize = file.readChar(); + uint16_t other = file.readShort(); //Unknown + + fields->Plugins = file.readPlugins(1); // Just empty data + + if (saveGameVersion >= 78) { + fields->LightPlugins = file.readLightPlugins(); + } + + file.closeCompressedData(); + + return fields; +} \ No newline at end of file diff --git a/src/enderalsesavegame.h b/src/enderalsesavegame.h new file mode 100644 index 0000000..f92a12d --- /dev/null +++ b/src/enderalsesavegame.h @@ -0,0 +1,29 @@ +#ifndef ENDERALSESAVEGAME_H +#define ENDERALSESAVEGAME_H + +#include "gamebryosavegame.h" +#include "gameenderalse.h" + +namespace MOBase { class IPluginGame; } + +class EnderalSESaveGame : public GamebryoSaveGame +{ +public: + EnderalSESaveGame(QString const &fileName, GameEnderalSE const *game); + +protected: + + // Fetch easy-to-access information. + void fetchInformationFields(FileWrapper& wrapper, + unsigned long& version, + QString& playerName, + unsigned short& playerLevel, + QString& playerLocation, + unsigned long& saveNumber, + FILETIME& creationTime) const; + + std::unique_ptr fetchDataFields() const override; + +}; + +#endif // _SKYRIMSESAVEGAME_H diff --git a/src/enderalsescriptextender.cpp b/src/enderalsescriptextender.cpp new file mode 100644 index 0000000..6c073f3 --- /dev/null +++ b/src/enderalsescriptextender.cpp @@ -0,0 +1,19 @@ +#include "enderalsescriptextender.h" + +#include +#include + +EnderalSEScriptExtender::EnderalSEScriptExtender(GameGamebryo const *game) : + GamebryoScriptExtender(game) +{ +} + +QString EnderalSEScriptExtender::BinaryName() const +{ + return "skse64_loader.exe"; +} + +QString EnderalSEScriptExtender::PluginPath() const +{ + return "skse/plugins"; +} diff --git a/src/enderalsescriptextender.h b/src/enderalsescriptextender.h new file mode 100644 index 0000000..a410e5d --- /dev/null +++ b/src/enderalsescriptextender.h @@ -0,0 +1,18 @@ +#ifndef ENDERALSESCRIPTEXTENDER_H +#define ENDERALESCRIPTEXTENDER_H + +#include "gamebryoscriptextender.h" + +class GameGamebryo; + +class EnderalSEScriptExtender : public GamebryoScriptExtender +{ +public: + EnderalSEScriptExtender(GameGamebryo const *game); + + virtual QString BinaryName() const override; + virtual QString PluginPath() const override; + +}; + +#endif // _SKYRIMSESCRIPTEXTENDER_H diff --git a/src/enderalseunmanagedmods.cpp b/src/enderalseunmanagedmods.cpp new file mode 100644 index 0000000..c6a4e71 --- /dev/null +++ b/src/enderalseunmanagedmods.cpp @@ -0,0 +1,32 @@ +#include "enderalseunmanagedmods.h" + + +EnderalSEUnmangedMods::EnderalSEUnmangedMods(const GameGamebryo *game) + : GamebryoUnmangedMods(game) +{} + +EnderalSEUnmangedMods::~EnderalSEUnmangedMods() +{} + +QStringList EnderalSEUnmangedMods::mods(bool onlyOfficial) const { + QStringList result; + + QStringList pluginList = game()->primaryPlugins(); + QStringList otherPlugins = game()->DLCPlugins(); + otherPlugins.append(game()->CCPlugins()); + for (QString plugin : otherPlugins) { + pluginList.removeAll(plugin); + } + QDir dataDir(game()->dataDirectory()); + for (const QString &fileName : dataDir.entryList({ "*.esp", "*.esl", "*.esm" })) { + if (!pluginList.contains(fileName, Qt::CaseInsensitive)) { + if (!onlyOfficial || pluginList.contains(fileName, Qt::CaseInsensitive)) { + QFileInfo file(fileName); + result.append(file.baseName()); + } + } + } + + return result; +} + diff --git a/src/enderalseunmanagedmods.h b/src/enderalseunmanagedmods.h new file mode 100644 index 0000000..f8102d5 --- /dev/null +++ b/src/enderalseunmanagedmods.h @@ -0,0 +1,19 @@ +#ifndef ENDERALSEUNMANAGEDMODS_H +#define ENDERALSEUNMANAGEDMODS_H + + +#include "gamebryounmanagedmods.h" +#include + + +class EnderalSEUnmangedMods : public GamebryoUnmangedMods { +public: + EnderalSEUnmangedMods(const GameGamebryo *game); + ~EnderalSEUnmangedMods(); + + virtual QStringList mods(bool onlyOfficial) const override; +}; + + + +#endif // _SKYRIMSEUNMANAGEDMODS_H diff --git a/src/game_enderalse_en.ts b/src/game_enderalse_en.ts new file mode 100644 index 0000000..4ec02c0 --- /dev/null +++ b/src/game_enderalse_en.ts @@ -0,0 +1,17 @@ + + + + + GameEnderalSE + + + Enderal Special Edition Support Plugin + + + + + Adds support for the game Enderal Special Edition. + + + + diff --git a/src/gameenderalse.cpp b/src/gameenderalse.cpp new file mode 100644 index 0000000..d1e34c5 --- /dev/null +++ b/src/gameenderalse.cpp @@ -0,0 +1,281 @@ +#include "gameenderalse.h" + +#include "enderalsebsainvalidation.h" +#include "enderalsedataarchives.h" +#include "enderalsescriptextender.h" +#include "enderalseunmanagedmods.h" +#include "enderalsemoddatachecker.h" +#include "enderalsemoddatacontent.h" +#include "enderalsesavegame.h" + +#include +#include +#include +#include +#include +#include "versioninfo.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "scopeguard.h" + +using namespace MOBase; + +GameEnderalSE::GameEnderalSE() +{ +} + +void GameEnderalSE::setGamePath(const QString &path) +{ + m_GamePath = path; +} + +QDir GameEnderalSE::documentsDirectory() const +{ + return m_MyGamesPath; +} + +QString GameEnderalSE::identifyGamePath() const +{ + QString path = "Software\\Bethesda Softworks\\Skyrim Special Edition"; + return findInRegistry(HKEY_LOCAL_MACHINE, path.toStdWString().c_str(), L"Installed Path"); +} + +QDir GameEnderalSE::savesDirectory() const +{ + return QDir(m_MyGamesPath + "/Saves"); +} + +QString GameEnderalSE::myGamesPath() const +{ + return m_MyGamesPath; +} + +bool GameEnderalSE::isInstalled() const +{ + return !m_GamePath.isEmpty(); +} + +void GameEnderalSE::detectGame() +{ + m_GamePath = identifyGamePath(); + m_MyGamesPath = determineMyGamesPath("Skyrim Special Edition"); +} + +bool GameEnderalSE::init(IOrganizer *moInfo) +{ + if (!GameGamebryo::init(moInfo)) { + return false; + } + + registerFeature(new EnderalSEScriptExtender(this)); + registerFeature(new EnderalSEDataArchives(myGamesPath())); + registerFeature(new EnderalSEBSAInvalidation(feature(), this)); + registerFeature(new GamebryoLocalSavegames(myGamesPath(), "skyrimcustom.ini")); + registerFeature(new EnderalSEModDataChecker(this)); + registerFeature(new EnderalSEModDataContent(this)); + registerFeature(new GamebryoSaveGameInfo(this)); + registerFeature(new CreationGamePlugins(moInfo)); + registerFeature(new EnderalSEUnmangedMods(this)); + + return true; +} + +QString GameEnderalSE::gameName() const +{ + return "Enderal Special Edition"; +} + +QList GameEnderalSE::executables() const +{ + return QList() + << ExecutableInfo("Enderal Special Edition (SKSE)", findInGameFolder(feature()->loaderName())) + // << ExecutableInfo("Enderal Special Edition Launcher", findInGameFolder(getLauncherName())) + // << ExecutableInfo("LOOT", getLootPath()).withArgument("--game=\"Skyrim Special Edition\"") + << ExecutableInfo("Creation Kit", findInGameFolder("CreationKit.exe")) + ; +} + +QList GameEnderalSE::executableForcedLoads() const +{ + return QList(); +} + +QString GameEnderalSE::binaryName() const +{ + return "skse64_loader.exe"; +} + +QString GameEnderalSE::getLauncherName() const +{ + return ""; +} + + +QFileInfo GameEnderalSE::findInGameFolder(const QString &relativePath) const +{ + return QFileInfo(m_GamePath + "/" + relativePath); +} + +QString GameEnderalSE::name() const +{ + return "Enderal Special Edition Support Plugin"; +} + +QString GameEnderalSE::localizedName() const +{ + return tr("Enderal Special Edition Support Plugin"); +} + +QString GameEnderalSE::author() const +{ + return "Holt59 & Archost & ZachHaber"; +} + +QString GameEnderalSE::description() const +{ + return tr("Adds support for the game Enderal Special Edition."); +} + +MOBase::VersionInfo GameEnderalSE::version() const +{ + return VersionInfo(1, 0, 0, VersionInfo::RELEASE_BETA); +} + +QList GameEnderalSE::settings() const +{ + return QList(); +} + +void GameEnderalSE::initializeProfile(const QDir &path, ProfileSettings settings) const +{ + if (settings.testFlag(IPluginGame::MODS)) { + copyToProfile(localAppFolder() + "/Enderal Special Edition", path, "plugins.txt"); + copyToProfile(localAppFolder() + "/Enderal Special Edition", path, "loadorder.txt"); + } + + if (settings.testFlag(IPluginGame::CONFIGURATION)) { + if (settings.testFlag(IPluginGame::PREFER_DEFAULTS) + || !QFileInfo(myGamesPath() + "/skyrim.ini").exists()) { + copyToProfile(gameDirectory().absolutePath(), path, "skyrim_default.ini", "skyrim.ini"); + } + else { + copyToProfile(myGamesPath(), path, "skyrim.ini"); + } + + copyToProfile(myGamesPath(), path, "skyrimprefs.ini"); + copyToProfile(myGamesPath(), path, "skyrimcustom.ini"); + } +} + +QString GameEnderalSE::savegameExtension() const +{ + return "ess"; +} + +QString GameEnderalSE::savegameSEExtension() const +{ + return "skse"; +} + +std::shared_ptr GameEnderalSE::makeSaveGame(QString filePath) const +{ + return std::make_shared(filePath, this); +} + +QString GameEnderalSE::steamAPPId() const +{ + return "976620"; +} + +QStringList GameEnderalSE::primaryPlugins() const +{ + return { + "skyrim.esm", + "Enderal - Forgotten Stories.esm", + "update.esm" + }; +} + +QStringList GameEnderalSE::gameVariants() const +{ + return{ "Regular" }; +} + +QString GameEnderalSE::gameShortName() const +{ + return "EnderalSE"; +} + +QStringList GameEnderalSE::validShortNames() const +{ + return { "Skyrim", "SkyrimSE", "Enderal" }; +} + +QString GameEnderalSE::gameNexusName() const +{ + return "enderalspecialedition"; +} + +QStringList GameEnderalSE::iniFiles() const +{ + return{ "skyrim.ini", "skyrimprefs.ini", "skyrimcustom.ini" }; +} + +QStringList GameEnderalSE::DLCPlugins() const +{ + return {}; +} + +QStringList GameEnderalSE::CCPlugins() const +{ + return {}; +} + +MOBase::IPluginGame::SortMechanism GameEnderalSE::sortMechanism() const +{ + return SortMechanism::NONE; +} + +IPluginGame::LoadOrderMechanism GameEnderalSE::loadOrderMechanism() const +{ + return IPluginGame::LoadOrderMechanism::PluginsTxt; +} + +int GameEnderalSE::nexusModOrganizerID() const +{ + return 0; +} + +int GameEnderalSE::nexusGameID() const +{ + return 3685; +} + +QDir GameEnderalSE::gameDirectory() const +{ + return QDir(m_GamePath); +} + +// Not to delete all the spaces... +MappingType GameEnderalSE::mappings() const +{ + MappingType result; + + for (const QString &profileFile : { "plugins.txt", "loadorder.txt" }) { + result.push_back({ m_Organizer->profilePath() + "/" + profileFile, + localAppFolder() + "/" + gameName() + "/" + profileFile, + false }); + } + + return result; +} + diff --git a/src/gameenderalse.h b/src/gameenderalse.h new file mode 100644 index 0000000..2e56634 --- /dev/null +++ b/src/gameenderalse.h @@ -0,0 +1,75 @@ +#ifndef GAMEENDERALSE_H +#define GAMEENDERALSE_H + + +#include "gamegamebryo.h" + +#include +#include + +class GameEnderalSE : public GameGamebryo +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "com.soundcontactstudio.GameEnderalSE" FILE "gameenderalse.json") + +public: + + GameEnderalSE(); + + virtual bool init(MOBase::IOrganizer *moInfo) override; + +public: // IPluginGame interface + + virtual void detectGame() override; + virtual QString gameName() const override; + virtual QList executables() const override; + virtual QList executableForcedLoads() const override; + virtual void initializeProfile(const QDir &path, ProfileSettings settings) const override; + virtual QString steamAPPId() const override; + virtual QStringList primaryPlugins() const override; + virtual QStringList gameVariants() const override; + virtual QString binaryName() const override; + virtual QString getLauncherName() const override; + virtual QString gameShortName() const override; + virtual QString gameNexusName() const override; + virtual QStringList validShortNames() const override; + virtual QStringList iniFiles() const override; + virtual QStringList DLCPlugins() const override; + virtual QStringList CCPlugins() const override; + SortMechanism sortMechanism() const override; + virtual LoadOrderMechanism loadOrderMechanism() const override; + virtual int nexusModOrganizerID() const override; + virtual int nexusGameID() const override; + + virtual bool isInstalled() const override; + virtual void setGamePath(const QString &path) override; + virtual QDir gameDirectory() const override; + +public: // IPlugin interface + + virtual QString name() const override; + virtual QString localizedName() const override; + virtual QString author() const override; + virtual QString description() const override; + virtual MOBase::VersionInfo version() const override; + virtual QList settings() const override; + virtual MappingType mappings() const override; + + +protected: + + std::shared_ptr makeSaveGame(QString filePath) const override; + QString savegameExtension() const override; + QString savegameSEExtension() const override; + + QDir documentsDirectory() const; + QDir savesDirectory() const; + QFileInfo findInGameFolder(const QString &relativePath) const; + QString myGamesPath() const; + + virtual QString identifyGamePath() const override; + +}; + +#endif // _GAMESKYRIMSE_H diff --git a/src/gameenderalse.json b/src/gameenderalse.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/src/gameenderalse.json @@ -0,0 +1 @@ +{}