From 279beb918d428da84d180c8c92ffb860c429cd3e Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Fri, 15 Jul 2022 20:38:08 +0200 Subject: [PATCH] rewrite SporeModManager in C++ --- 3rdParty/BuildMinizipNG.bat | 19 + 3rdParty/BuildSporeModAPI.bat | 10 + BuildRelease.bat | 22 +- SporeModLoader.sln | 138 +---- SporeModLoader/SporeModLoader.vcxproj | 26 +- SporeModManager/App.config | 6 - SporeModManager/Program.cs | 76 --- SporeModManager/Properties/AssemblyInfo.cs | 36 -- SporeModManager/SporeModManager.cpp | 177 ++++++ SporeModManager/SporeModManager.csproj | 68 --- SporeModManager/SporeModManager.hpp | 38 ++ SporeModManager/SporeModManager.vcxproj | 183 +++++++ .../SporeModManager.vcxproj.filters | 57 ++ SporeModManager/SporeModManagerHelpers.hpp | 190 +++++++ .../SporeModManagerHelpers/Path.cpp | 86 +++ .../SporeModManagerHelpers/SporeMod.cpp | 255 +++++++++ .../SporeModManagerHelpers/SporeModXml.cpp | 505 ++++++++++++++++++ SporeModManager/SporeModManagerHelpers/UI.cpp | 82 +++ .../SporeModManagerHelpers/Zip.cpp | 218 ++++++++ .../SporeMods/SporeMods.Directory.cs | 70 --- .../SporeMods/SporeMods.Installer.cs | 261 --------- SporeModManager/SporeMods/SporeMods.List.cs | 31 -- .../SporeMods/SporeMods.Uninstaller.cs | 57 -- .../SporeMods/Xml/DirectoryConfig.cs | 50 -- SporeModManager/SporeMods/Xml/InstalledMod.cs | 21 - .../SporeMods/Xml/InstalledModFile.cs | 17 - .../SporeMods/Xml/InstalledMods.cs | 49 -- SporeModManager/SporeMods/Xml/ModInfo.cs | 123 ----- .../SporeMods/Xml/ModInfoComponent.cs | 83 --- .../SporeMods/Xml/ModInfoComponentGroup.cs | 20 - .../SporeMods/Xml/ModInfoInstallLocation.cs | 18 - .../SporeMods/Xml/ModInfoPrerequisite.cs | 43 -- SporeModManager/main.cpp | 122 +++++ 33 files changed, 1982 insertions(+), 1175 deletions(-) create mode 100644 3rdParty/BuildMinizipNG.bat create mode 100644 3rdParty/BuildSporeModAPI.bat delete mode 100644 SporeModManager/App.config delete mode 100644 SporeModManager/Program.cs delete mode 100644 SporeModManager/Properties/AssemblyInfo.cs create mode 100644 SporeModManager/SporeModManager.cpp delete mode 100644 SporeModManager/SporeModManager.csproj create mode 100644 SporeModManager/SporeModManager.hpp create mode 100644 SporeModManager/SporeModManager.vcxproj create mode 100644 SporeModManager/SporeModManager.vcxproj.filters create mode 100644 SporeModManager/SporeModManagerHelpers.hpp create mode 100644 SporeModManager/SporeModManagerHelpers/Path.cpp create mode 100644 SporeModManager/SporeModManagerHelpers/SporeMod.cpp create mode 100644 SporeModManager/SporeModManagerHelpers/SporeModXml.cpp create mode 100644 SporeModManager/SporeModManagerHelpers/UI.cpp create mode 100644 SporeModManager/SporeModManagerHelpers/Zip.cpp delete mode 100644 SporeModManager/SporeMods/SporeMods.Directory.cs delete mode 100644 SporeModManager/SporeMods/SporeMods.Installer.cs delete mode 100644 SporeModManager/SporeMods/SporeMods.List.cs delete mode 100644 SporeModManager/SporeMods/SporeMods.Uninstaller.cs delete mode 100644 SporeModManager/SporeMods/Xml/DirectoryConfig.cs delete mode 100644 SporeModManager/SporeMods/Xml/InstalledMod.cs delete mode 100644 SporeModManager/SporeMods/Xml/InstalledModFile.cs delete mode 100644 SporeModManager/SporeMods/Xml/InstalledMods.cs delete mode 100644 SporeModManager/SporeMods/Xml/ModInfo.cs delete mode 100644 SporeModManager/SporeMods/Xml/ModInfoComponent.cs delete mode 100644 SporeModManager/SporeMods/Xml/ModInfoComponentGroup.cs delete mode 100644 SporeModManager/SporeMods/Xml/ModInfoInstallLocation.cs delete mode 100644 SporeModManager/SporeMods/Xml/ModInfoPrerequisite.cs create mode 100644 SporeModManager/main.cpp diff --git a/3rdParty/BuildMinizipNG.bat b/3rdParty/BuildMinizipNG.bat new file mode 100644 index 0000000..10d49ae --- /dev/null +++ b/3rdParty/BuildMinizipNG.bat @@ -0,0 +1,19 @@ +@echo off +set CUR_DIR=%~dp0 + +set MINIZIPNG_DIR=%CUR_DIR%\minizip-ng + +rmdir /S /Q "%MINIZIPNG_DIR%\build" +mkdir "%MINIZIPNG_DIR%\build" + +set PATH=%PATH%;C:\Program Files\CMake\bin + +cmake -S "%MINIZIPNG_DIR%" -B "%MINIZIPNG_DIR%\build" -A Win32 ^ + -DMZ_LZMA=OFF -DMZ_ZSTD=OFF ^ + -DMZ_BZIP2=OFF -DMZ_PKCRYPT=OFF ^ + -DMZ_WZAES=OFF -DMZ_SIGNING=OFF ^ + -DCMAKE_POLICY_DEFAULT_CMP0091=NEW ^ + -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^ + -DCMAKE_BUILD_TYPE=Release + +cmake --build "%MINIZIPNG_DIR%\build" --config Release \ No newline at end of file diff --git a/3rdParty/BuildSporeModAPI.bat b/3rdParty/BuildSporeModAPI.bat new file mode 100644 index 0000000..851a21a --- /dev/null +++ b/3rdParty/BuildSporeModAPI.bat @@ -0,0 +1,10 @@ +@echo off + +set CUR_DIR=%~dp0 + +msbuild "%CUR_DIR%\Spore-ModAPI\Spore ModAPI" ^ + /t:BuildDlls ^ + /p:BuildVer=83 ^ + /p:Config=Release ^ + /p:Platform=Win32 ^ + /m \ No newline at end of file diff --git a/BuildRelease.bat b/BuildRelease.bat index cc2f24d..daf2abb 100644 --- a/BuildRelease.bat +++ b/BuildRelease.bat @@ -1,8 +1,9 @@ @echo off -set CUR_DIR="%~dp0" -set OBJ_DIR="%CUR_DIR%\obj" -set BIN_DIR="%CUR_DIR%\bin" +set CUR_DIR=%~dp0 +set OBJ_DIR=%CUR_DIR%\obj +set BIN_DIR=%CUR_DIR%\bin +set THIRDPARTY_DIR=%CUR_DIR%\3rdParty rmdir /S /Q "%OBJ_DIR%" "%BIN_DIR%" @@ -17,20 +18,21 @@ mkdir "%OBJ_DIR%\SporeModLoader\CoreLibs\march2017" mkdir "%OBJ_DIR%\SporeModLoader\ModLibs" mkdir "%OBJ_DIR%\SporeModLoader\SporeModManager" -msbuild "Spore-ModAPI\Spore ModAPI" ^ - /t:BuildDlls ^ - /p:BuildVer=83 ^ - /p:Config=Release ^ +CALL "%THIRDPARTY_DIR%\BuildMinizipNG.bat" +CALL "%THIRDPARTY_DIR%\BuildSporeModAPI.bat" + +msbuild SporeModLoader ^ + /p:Configuration=Release ^ /p:Platform=Win32 ^ /m -msbuild SporeModLoader ^ +msbuild SporeModManager ^ /p:Configuration=Release ^ /p:Platform=Win32 ^ /m -copy Spore-ModAPI\dll\Release\SporeModAPI.disk.dll "%OBJ_DIR%\SporeModLoader\CoreLibs\disk\SporeModAPI.dll" -copy Spore-ModAPI\dll\Release\SporeModAPI.march2017.dll "%OBJ_DIR%\SporeModLoader\CoreLibs\march2017\SporeModAPI.dll" +copy "%THIRDPARTY_DIR%\Spore-ModAPI\dll\Release\SporeModAPI.disk.dll" "%OBJ_DIR%\SporeModLoader\CoreLibs\disk\SporeModAPI.dll" +copy "%THIRDPARTY_DIR%\Spore-ModAPI\dll\Release\SporeModAPI.march2017.dll" "%OBJ_DIR%\SporeModLoader\CoreLibs\march2017\SporeModAPI.dll" copy SporeModLoader\Bin\Release\dinput8.dll "%OBJ_DIR%\SporebinEP1\dinput8.dll" copy SporeModManager\Bin\Release\SporeModManager.exe "%OBJ_DIR%\SporeModLoader\SporeModManager" diff --git a/SporeModLoader.sln b/SporeModLoader.sln index c27ac01..deef7f3 100644 --- a/SporeModLoader.sln +++ b/SporeModLoader.sln @@ -8,154 +8,28 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SporeModLoader", "SporeModL {37489709-8054-4903-9C49-A79846049FC9} = {37489709-8054-4903-9C49-A79846049FC9} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "Detours\vc\Detours.vcxproj", "{37489709-8054-4903-9C49-A79846049FC9}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "3rdParty\Detours\vc\Detours.vcxproj", "{37489709-8054-4903-9C49-A79846049FC9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SporeModManager", "SporeModManager\SporeModManager.csproj", "{79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SporeModManager", "SporeModManager\SporeModManager.vcxproj", "{7D7E065A-3A61-434F-98CB-363031BE4481}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - DebugMDd|Any CPU = DebugMDd|Any CPU - DebugMDd|ARM = DebugMDd|ARM - DebugMDd|ARM64 = DebugMDd|ARM64 - DebugMDd|x64 = DebugMDd|x64 - DebugMDd|x86 = DebugMDd|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 Release|x86 = Release|x86 - ReleaseMD|Any CPU = ReleaseMD|Any CPU - ReleaseMD|ARM = ReleaseMD|ARM - ReleaseMD|ARM64 = ReleaseMD|ARM64 - ReleaseMD|x64 = ReleaseMD|x64 - ReleaseMD|x86 = ReleaseMD|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|Any CPU.ActiveCfg = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|Any CPU.Build.0 = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|ARM.ActiveCfg = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|ARM.Build.0 = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|ARM64.ActiveCfg = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|ARM64.Build.0 = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|x64.ActiveCfg = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|x64.Build.0 = Debug|x64 {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|x86.ActiveCfg = Debug|Win32 {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Debug|x86.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|Any CPU.ActiveCfg = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|Any CPU.Build.0 = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|ARM.ActiveCfg = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|ARM.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|ARM64.ActiveCfg = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|ARM64.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|x64.ActiveCfg = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|x64.Build.0 = Debug|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|x86.ActiveCfg = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.DebugMDd|x86.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|Any CPU.ActiveCfg = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|Any CPU.Build.0 = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|ARM.ActiveCfg = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|ARM.Build.0 = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|ARM64.ActiveCfg = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|ARM64.Build.0 = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|x64.ActiveCfg = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|x64.Build.0 = Release|x64 {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|x86.ActiveCfg = Release|Win32 {AD9120DA-E42B-4563-A307-B5A155CC25C0}.Release|x86.Build.0 = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|Any CPU.ActiveCfg = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|Any CPU.Build.0 = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|ARM.ActiveCfg = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|ARM.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|ARM64.ActiveCfg = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|ARM64.Build.0 = Debug|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|x64.ActiveCfg = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|x64.Build.0 = Release|x64 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|x86.ActiveCfg = Release|Win32 - {AD9120DA-E42B-4563-A307-B5A155CC25C0}.ReleaseMD|x86.Build.0 = Release|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|Any CPU.ActiveCfg = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|Any CPU.Build.0 = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|ARM.ActiveCfg = DebugMDd|ARM - {37489709-8054-4903-9C49-A79846049FC9}.Debug|ARM.Build.0 = DebugMDd|ARM - {37489709-8054-4903-9C49-A79846049FC9}.Debug|ARM64.ActiveCfg = DebugMDd|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|ARM64.Build.0 = DebugMDd|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|x64.ActiveCfg = DebugMDd|x64 - {37489709-8054-4903-9C49-A79846049FC9}.Debug|x64.Build.0 = DebugMDd|x64 {37489709-8054-4903-9C49-A79846049FC9}.Debug|x86.ActiveCfg = DebugMDd|Win32 {37489709-8054-4903-9C49-A79846049FC9}.Debug|x86.Build.0 = DebugMDd|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|Any CPU.ActiveCfg = DebugMDd|x64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|Any CPU.Build.0 = DebugMDd|x64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM.ActiveCfg = DebugMDd|ARM - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM.Build.0 = DebugMDd|ARM - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64.ActiveCfg = DebugMDd|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|ARM64.Build.0 = DebugMDd|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x64.ActiveCfg = DebugMDd|x64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x64.Build.0 = DebugMDd|x64 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x86.ActiveCfg = DebugMDd|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.DebugMDd|x86.Build.0 = DebugMDd|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Release|Any CPU.ActiveCfg = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Release|Any CPU.Build.0 = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.Release|ARM.ActiveCfg = ReleaseMD|ARM - {37489709-8054-4903-9C49-A79846049FC9}.Release|ARM.Build.0 = ReleaseMD|ARM - {37489709-8054-4903-9C49-A79846049FC9}.Release|ARM64.ActiveCfg = ReleaseMD|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.Release|ARM64.Build.0 = ReleaseMD|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.Release|x64.ActiveCfg = ReleaseMD|x64 - {37489709-8054-4903-9C49-A79846049FC9}.Release|x64.Build.0 = ReleaseMD|x64 {37489709-8054-4903-9C49-A79846049FC9}.Release|x86.ActiveCfg = ReleaseMD|Win32 {37489709-8054-4903-9C49-A79846049FC9}.Release|x86.Build.0 = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|Any CPU.ActiveCfg = ReleaseMD|x64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|Any CPU.Build.0 = ReleaseMD|x64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM.ActiveCfg = ReleaseMD|ARM - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM.Build.0 = ReleaseMD|ARM - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64.ActiveCfg = ReleaseMD|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|ARM64.Build.0 = ReleaseMD|ARM64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x64.ActiveCfg = ReleaseMD|x64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x64.Build.0 = ReleaseMD|x64 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x86.ActiveCfg = ReleaseMD|Win32 - {37489709-8054-4903-9C49-A79846049FC9}.ReleaseMD|x86.Build.0 = ReleaseMD|Win32 - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|ARM.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|ARM64.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|x64.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|x64.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|x86.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Debug|x86.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|Any CPU.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|Any CPU.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|ARM.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|ARM.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|ARM64.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|ARM64.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|x64.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|x64.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|x86.ActiveCfg = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.DebugMDd|x86.Build.0 = Debug|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|Any CPU.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|ARM.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|ARM.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|ARM64.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|ARM64.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|x64.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|x64.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|x86.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.Release|x86.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|Any CPU.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|Any CPU.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|ARM.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|ARM.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|ARM64.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|ARM64.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|x64.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|x64.Build.0 = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|x86.ActiveCfg = Release|Any CPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC}.ReleaseMD|x86.Build.0 = Release|Any CPU + {7D7E065A-3A61-434F-98CB-363031BE4481}.Debug|x86.ActiveCfg = Debug|Win32 + {7D7E065A-3A61-434F-98CB-363031BE4481}.Debug|x86.Build.0 = Debug|Win32 + {7D7E065A-3A61-434F-98CB-363031BE4481}.Release|x86.ActiveCfg = Release|Win32 + {7D7E065A-3A61-434F-98CB-363031BE4481}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SporeModLoader/SporeModLoader.vcxproj b/SporeModLoader/SporeModLoader.vcxproj index a095319..43f1558 100644 --- a/SporeModLoader/SporeModLoader.vcxproj +++ b/SporeModLoader/SporeModLoader.vcxproj @@ -75,16 +75,16 @@ dinput8 Bin\$(Configuration)\ Obj\$(Configuration)\ - $(MSBuildProjectDirectory)\..\Detours\lib.X86;$(LibraryPath) - $(MSBuildProjectDirectory)\..\Detours\include;$(IncludePath) + $(MSBuildProjectDirectory)\..\3rdParty\Detours\lib.X86;$(LibraryPath) + $(MSBuildProjectDirectory)\..\3rdParty\Detours\include;$(IncludePath) false dinput8 Bin\$(Configuration)\ Obj\$(Configuration)\ - $(MSBuildProjectDirectory)\..\Detours\lib.X86;$(LibraryPath) - $(MSBuildProjectDirectory)\..\Detours\include;$(IncludePath) + $(MSBuildProjectDirectory)\..\3rdParty\Detours\lib.X86;$(LibraryPath) + $(MSBuildProjectDirectory)\..\3rdParty\Detours\include;$(IncludePath) true @@ -107,6 +107,15 @@ dllmain.def detours.lib;%(AdditionalDependencies) + + if NOT EXIST "$(MSBuildProjectDirectory)\..\3rdParty\Spore-ModAPI\dll\Release\SporeModAPI.dll" ( + "$(MSBuildProjectDirectory)\..\3rdParty\BuildSporeModAPI.bat" +) + + + + + @@ -127,6 +136,15 @@ dllmain.def detours.lib;%(AdditionalDependencies) + + if NOT EXIST "$(MSBuildProjectDirectory)\..\3rdParty\Spore-ModAPI\dll\Release\SporeModAPI.dll" ( + "$(MSBuildProjectDirectory)\..\3rdParty\BuildSporeModAPI.bat" +) + + + + + diff --git a/SporeModManager/App.config b/SporeModManager/App.config deleted file mode 100644 index 193aecc..0000000 --- a/SporeModManager/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/SporeModManager/Program.cs b/SporeModManager/Program.cs deleted file mode 100644 index 26864e5..0000000 --- a/SporeModManager/Program.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace SporeModManager -{ - internal class Program - { - static void ShowUsage() - { - Console.WriteLine("Usage: SporeModManager.exe [OPTION]\n"); - Console.WriteLine("Options:"); - Console.WriteLine(" -l, --list-installed lists installed mods with IDs"); - Console.WriteLine(" -i, --install FILE installs FILE"); - Console.WriteLine(" -u, --uninstall ID uninstalls mod with ID\n"); - Console.WriteLine(" --help display this help and exit"); - } - - static void Main(string[] args) - { - SporeMods.Directory.ReadDirectoryConfig(); - SporeMods.Directory.EnsureDirectoriesExist(); - - if (args.Length == 0 || args[0] == "--help") - { - ShowUsage(); - return; - } - else if (args[0] == "-l" || args[0] == "--list-installed") - { - SporeMods.SporeMods.ListInstalledMods(); - return; - } - else if (args[0] == "-i" || args[0] == "--install") - { - if (args.Skip(1).Count() == 0) - { - ShowUsage(); - return; - } - - foreach (string file in args.Skip(1)) - { - SporeMods.SporeMods.InstallMod(file); - } - return; - } - else if (args[0] == "-u" || args[0] == "--uninstall") - { - List idList = new List(); - - foreach (string id in args.Skip(1)) - { - idList.Add(Int32.Parse(id)); - } - - SporeMods.SporeMods.UninstallMods(idList); - return; - } - else - { - ShowUsage(); - return; - } - } - } -} diff --git a/SporeModManager/Properties/AssemblyInfo.cs b/SporeModManager/Properties/AssemblyInfo.cs deleted file mode 100644 index 0421809..0000000 --- a/SporeModManager/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SporeModManager")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SporeModManager")] -[assembly: AssemblyCopyright("Copyright © 2022")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("79de9382-1d2d-4d7c-b1c3-4aaa0b8fd3fc")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SporeModManager/SporeModManager.cpp b/SporeModManager/SporeModManager.cpp new file mode 100644 index 0000000..d061d69 --- /dev/null +++ b/SporeModManager/SporeModManager.cpp @@ -0,0 +1,177 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +#include "SporeModManager.hpp" +#include "SporeModManagerHelpers.hpp" + +using namespace SporeModManagerHelpers; + +bool SporeModManager::ListInstalledMods(void) +{ + std::vector installedSporeMods; + + if (!SporeMod::Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "SporeMod::Xml::GetInstalledMostList() Failed!" << std::endl; + return false; + } + + for (size_t i = 0; i < installedSporeMods.size(); i++) + { + SporeMod::Xml::InstalledSporeMod installedSporeMod; + installedSporeMod = installedSporeMods[i]; + + std::cout << "[" << i << "] " << installedSporeMod.Name << std::endl; + if (!installedSporeMod.Description.empty()) + { + std::cout << " " << installedSporeMod.Description << std::endl; + } + } + + return true; +} + +bool SporeModManager::InstallMod(std::filesystem::path path) +{ + if (!std::filesystem::is_regular_file(path)) + { + std::cerr << "\"" << path.string() << "\" is not a regular file or doesn't exist!" << std::endl; + return false; + } + + std::string extension = path.extension().string(); + if (extension == ".sporemod") + { + return SporeMod::InstallSporeMod(path); + } + else if (extension == ".package") + { + return SporeMod::InstallPackage(path); + } + else + { + std::cerr << "\"" << extension << "\" is an invalid extension!" << std::endl; + return false; + } + + return true; +} + +bool SporeModManager::UpdateMod(std::filesystem::path path) +{ + Zip::ZipFile zipFile; + char* modInfoFileBuffer; + size_t modInfoFileBufferSize; + SporeMod::Xml::SporeModInfo sporeModInfo; + int installedSporeModId = 0; + std::string installedSporeModUniqueName; + + if (!std::filesystem::is_regular_file(path)) + { + std::cerr << "\"" << path.string() << "\" is not a regular file or doesn't exist!" << std::endl; + return false; + } + + std::string extension = path.extension().string(); + if (extension == ".sporemod") + { + if (!Zip::OpenFile(zipFile, path)) + { + std::cerr << "Zip::OpenFile() Failed!" << std::endl; + return false; + } + + if (!Zip::ExtractFile(zipFile, "modinfo.xml", &modInfoFileBuffer, &modInfoFileBufferSize)) + { + std::cerr << "Zip::ExtractFile() Failed!" << std::endl; + Zip::CloseFile(zipFile); + return false; + } + + if (!SporeMod::Xml::ParseSporeModInfo(modInfoFileBuffer, modInfoFileBufferSize, sporeModInfo)) + { + std::cerr << "SporeMod::Xml::ParseSporeModInfo() Failed!" << std::endl; + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + return false; + } + + installedSporeModUniqueName = sporeModInfo.UniqueName; + + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + } + else if (extension == ".package") + { + installedSporeModUniqueName = path.stem().string(); + } + else + { + std::cerr << "\"" << extension << "\" is an invalid extension!" << std::endl; + return false; + } + + if (!SporeMod::FindInstalledMod(installedSporeModUniqueName, installedSporeModId)) + { + std::cerr << "No mod found with the same unique name" << std::endl + << "Did you mean -i/--install?" << std::endl; + return false; + } + + return UninstallMod(installedSporeModId) && InstallMod(path); +} + +bool SporeModManager::UninstallMod(int id) +{ + std::vector installedSporeMods; + SporeMod::Xml::InstalledSporeMod installedSporeMod; + std::filesystem::path fullInstallPath; + + if (!SporeMod::Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "SporeMod::Xml::GetInstalledModList() Failed!" << std::endl; + return false; + } + + if (id < 0 || (size_t)id > installedSporeMods.size()) + { + std::cerr << "ID must be valid!" << std::endl; + return false; + } + + installedSporeMod = installedSporeMods.at(id); + + for (const auto& installedFile : installedSporeMod.InstalledFiles) + { + try + { + fullInstallPath = Path::GetFullInstallPath(installedFile.InstallLocation, installedFile.FileName); + + std::cout << "-> Removing " << installedFile.FileName.string() << std::endl; + + std::filesystem::remove(fullInstallPath); + } + catch (...) + { + std::cerr << "std::filesystem::remove(" << fullInstallPath << "\") Failed!" << std::endl; + return false; + } + } + + installedSporeMods.erase(installedSporeMods.begin() + id); + if (!SporeMod::Xml::SaveInstalledModList(installedSporeMods)) + { + std::cerr << "SporeMod::Xml::SaveInstalledModList() Failed!" << std::endl; + return false; + } + + return true; +} diff --git a/SporeModManager/SporeModManager.csproj b/SporeModManager/SporeModManager.csproj deleted file mode 100644 index a417ee8..0000000 --- a/SporeModManager/SporeModManager.csproj +++ /dev/null @@ -1,68 +0,0 @@ - - - - - Debug - AnyCPU - {79DE9382-1D2D-4D7C-B1C3-4AAA0B8FD3FC} - Exe - SporeModManager - SporeModManager - v4.8 - 512 - true - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SporeModManager/SporeModManager.hpp b/SporeModManager/SporeModManager.hpp new file mode 100644 index 0000000..bee4e55 --- /dev/null +++ b/SporeModManager/SporeModManager.hpp @@ -0,0 +1,38 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef SPOREMODMANAGER_HPP +#define SPOREMODMANAGER_HPP + +#include + +namespace SporeModManager +{ + /// + /// Lists Installed mods + /// + bool ListInstalledMods(void); + + /// + /// Installs mod + /// + bool InstallMod(std::filesystem::path path); + + /// + /// Updates mod + /// + bool UpdateMod(std::filesystem::path path); + + /// + /// Uninstalls mod with id + /// + bool UninstallMod(int id); +} + +#endif // SPOREMODMANAGER_HPP \ No newline at end of file diff --git a/SporeModManager/SporeModManager.vcxproj b/SporeModManager/SporeModManager.vcxproj new file mode 100644 index 0000000..24a138b --- /dev/null +++ b/SporeModManager/SporeModManager.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {7d7e065a-3a61-434f-98cb-363031be4481} + SporeModManager + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\;$(MSBuildProjectDirectory)\..\3rdParty\tinyxml2\;$(IncludePath) + $(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\Release;$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\_deps\zlib-build\Release;$(LibraryPath) + $(MSBuildProjectDirectory)\Bin\$(Configuration)\ + $(MSBuildProjectDirectory)\Obj\$(Configuration)\ + + + false + $(MSBuildProjectDirectory)\Bin\$(Configuration)\ + $(MSBuildProjectDirectory);$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\;$(MSBuildProjectDirectory)\..\3rdParty\tinyxml2\;$(IncludePath) + $(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\Release\;$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\_deps\zlib-build\Release;$(LibraryPath) + $(MSBuildProjectDirectory)\Obj\$(Configuration)\ + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + stdcpp20 + + + Console + true + zlibstatic.lib;libminizip.lib;%(AdditionalDependencies) + + + if NOT EXIST "$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\Release\libminizip.lib" ( + "$(MSBuildProjectDirectory)\..\3rdParty\BuildMinizipNG.bat" +) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + stdcpp20 + + + Console + true + true + true + zlibstatic.lib;libminizip.lib;%(AdditionalDependencies) + + + if NOT EXIST "$(MSBuildProjectDirectory)\..\3rdParty\minizip-ng\build\Release\libminizip.lib" ( + "$(MSBuildProjectDirectory)\..\3rdParty\BuildMinizipNG.bat" +) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SporeModManager/SporeModManager.vcxproj.filters b/SporeModManager/SporeModManager.vcxproj.filters new file mode 100644 index 0000000..9bb5a97 --- /dev/null +++ b/SporeModManager/SporeModManager.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {61ad4daa-3baa-44fa-a0fb-98a6919882c7} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\SporeModManagerHelpers + + + Source Files\SporeModManagerHelpers + + + Source Files\SporeModManagerHelpers + + + Source Files\SporeModManagerHelpers + + + Source Files\SporeModManagerHelpers + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/SporeModManager/SporeModManagerHelpers.hpp b/SporeModManager/SporeModManagerHelpers.hpp new file mode 100644 index 0000000..07c4353 --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers.hpp @@ -0,0 +1,190 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef SPOREMODMANAGERHELPERS_HPP +#define SPOREMODMANAGERHELPERS_HPP + +#include +#include + +namespace SporeModManagerHelpers +{ + namespace SporeMod + { + enum class InstallLocation + { + ModLibs = 0, + GalacticAdventuresData = 1, + CoreSporeData = 2 + }; + + namespace Xml + { + struct SporeModFile + { + InstallLocation InstallLocation; + std::filesystem::path FileName; + }; + + struct SporeModInfoComponent + { + std::string Name; + std::string UniqueName; + std::string Description; + bool DefaultChecked; + std::vector Files; + }; + + struct SporeModInfoComponentGroup + { + std::string Name; + std::string UniqueName; + std::vector Components; + }; + + struct SporeModInfoPrerequisite + { + std::vector Files; + }; + + struct SporeModInfo + { + std::string Name; + std::string UniqueName; + std::string Description; + + std::vector ComponentGroups; + std::vector Components; + std::vector Prerequisites; + }; + + struct InstalledSporeMod + { + std::string Name; + std::string UniqueName; + std::string Description; + + std::vector InstalledFiles; + }; + + /// + /// Parses SporeMod.xml buffer into a SporeModInfo + /// + bool ParseSporeModInfo(char* buffer, size_t bufferSize, SporeModInfo& sporeModInfo); + + /// + /// Retrieves directories + /// > + bool GetDirectories(std::filesystem::path& modLibsPath, std::filesystem::path& galacticAdventuresDataPath, std::filesystem::path& coreSporeDataPath); + + /// + /// Saves directories + /// + bool SaveDirectories(std::filesystem::path modLibsPath, std::filesystem::path galacticAdventuresDataPath, std::filesystem::path coreSporeDataPath); + + /// + /// Retrieves installed mod list + /// + bool GetInstalledModList(std::vector& installedSporeModList); + + /// + /// Saves installed mod list + /// + bool SaveInstalledModList(std::vector installedSporeModList); + } + + /// + /// Tries to find installed mod with uniqueName + /// + bool FindInstalledMod(std::string uniqueName, int& installedSporeModId); + + /// + /// Installs sporemod file + /// + bool InstallSporeMod(std::filesystem::path path); + + /// + /// Installs package file + /// + bool InstallPackage(std::filesystem::path path); + } + + namespace Path + { + /// + /// Returns wether all required paths exist + /// + bool CheckIfPathsExist(void); + + /// + /// Retrieves full installation path + /// + std::filesystem::path GetFullInstallPath(SporeMod::InstallLocation installLocation, std::filesystem::path path); + + /// + /// Returns mod libs path + /// + std::filesystem::path GetModLibsPath(void); + + /// + /// Returns Galactic Adventures data path + /// + std::filesystem::path GetGalacticAdventuresDataPath(void); + + /// + /// Returns Core Spore data path + /// + std::filesystem::path GetCoreSporeDataPath(void); + } + + namespace UI + { + /// + /// Asks user for an integer + /// + void AskUserInput(std::string text, int& number, int min, int max); + + /// + /// Asks user for an integers + /// + void AskUserInput(std::string text, char delimiter, std::vector& numbers, int min, int max); + } + + namespace Zip + { + typedef void* ZipFile; + + /// + /// Opens the given zip file + /// + bool OpenFile(ZipFile& zipFile, std::filesystem::path path); + + /// + /// Closes the given zip + /// + bool CloseFile(ZipFile zipFile); + + /// + /// Retrieves the file list of a zip file + /// + bool GetFileList(ZipFile zipFile, std::vector& fileList); + + /// + /// Extracts file to outputFile + /// + bool ExtractFile(ZipFile zipFile, std::filesystem::path file, std::filesystem::path outputFile); + + /// + /// Extracts file to buffer + /// + bool ExtractFile(ZipFile zipFile, std::filesystem::path file, char** buffer, size_t* bufferSize); + } +} + +#endif // SPOREMODMANAGERHELPERS_HPP diff --git a/SporeModManager/SporeModManagerHelpers/Path.cpp b/SporeModManager/SporeModManagerHelpers/Path.cpp new file mode 100644 index 0000000..9116d4f --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers/Path.cpp @@ -0,0 +1,86 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManagerHelpers.hpp" + +#include + +using namespace SporeModManagerHelpers; + +// +// Local Variables +// + +std::filesystem::path l_ModLibsPath; +std::filesystem::path l_GalacticAdventuresDataPath; +std::filesystem::path l_CoreSporeDataPath; + +// +// Exported Functions +// + +bool Path::CheckIfPathsExist(void) +{ + if (!SporeMod::Xml::GetDirectories(l_ModLibsPath, l_GalacticAdventuresDataPath, l_CoreSporeDataPath)) + { + std::cerr << "SporeMod::Xml::GetDirectories() Failed!" << std::endl; + } + + for (const auto& path : { l_ModLibsPath, l_GalacticAdventuresDataPath, l_CoreSporeDataPath }) + { + if (!std::filesystem::is_directory(path)) + { + std::cerr << "\"" << path.string() << "\" is not a directory or doesn't exist!" << std::endl + << "If you want to change the configured directories, see SporeModManager.xml" << std::endl; + return false; + } + } + + return true; +} + +std::filesystem::path Path::GetFullInstallPath(SporeMod::InstallLocation installLocation, std::filesystem::path path) +{ + std::filesystem::path fullPath; + + switch (installLocation) + { + default: + case SporeMod::InstallLocation::ModLibs: + fullPath = Path::GetModLibsPath(); + break; + case SporeMod::InstallLocation::GalacticAdventuresData: + fullPath = Path::GetGalacticAdventuresDataPath(); + break; + case SporeMod::InstallLocation::CoreSporeData: + fullPath = Path::GetCoreSporeDataPath(); + break; + } + + fullPath += "\\"; + fullPath += path; + + return fullPath; +} + +std::filesystem::path Path::GetModLibsPath(void) +{ + return l_ModLibsPath; +} + +std::filesystem::path Path::GetGalacticAdventuresDataPath(void) +{ + return l_GalacticAdventuresDataPath; +} + +std::filesystem::path Path::GetCoreSporeDataPath(void) +{ + return l_CoreSporeDataPath; +} + diff --git a/SporeModManager/SporeModManagerHelpers/SporeMod.cpp b/SporeModManager/SporeModManagerHelpers/SporeMod.cpp new file mode 100644 index 0000000..0feb4bb --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers/SporeMod.cpp @@ -0,0 +1,255 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManagerHelpers.hpp" + +#include + +using namespace SporeModManagerHelpers; + +// +// Helper Functions +// + +static bool IsModAlreadyInstalled(std::string uniqueName) +{ + std::vector installedSporeMods; + + if (!SporeMod::Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "SporeMod::Xml::GetInstalledModList() Failed!" << std::endl; + return true; + } + + for (const auto& installedSporeMod : installedSporeMods) + { + if (installedSporeMod.UniqueName == uniqueName) + { + std::cerr << "A mod with the same unique name (" << installedSporeMod.Name << ") has already been installed" << std::endl + << "Did you mean -u/--update?" << std::endl; + return true; + } + } + + return false; +} + +// +// Exported Functions +// + +bool SporeMod::FindInstalledMod(std::string uniqueName, int& installedSporeModId) +{ + std::vector installedSporeMods; + SporeMod::Xml::InstalledSporeMod installedSporeMod; + + if (!Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "Xml::GetInstalledModList() Failed!" << std::endl; + return true; + } + + for (size_t i = 0; i < installedSporeMods.size(); i++) + { + installedSporeMod = installedSporeMods[i]; + if (installedSporeMod.UniqueName == uniqueName) + { + installedSporeModId = i; + return true; + } + } + + return false; +} + +bool SporeMod::InstallSporeMod(std::filesystem::path path) +{ + Zip::ZipFile zipFile; + char* modInfoFileBuffer; + size_t modInfoFileBufferSize = 0; + Xml::SporeModInfo sporeModInfo; + Xml::InstalledSporeMod installedSporeMod; + Xml::SporeModInfoComponent component; + size_t componentsSize; + + if (!Zip::OpenFile(zipFile, path)) + { + std::cerr << "Zip::OpenFile() Failed!" << std::endl; + return false; + } + + if (!Zip::ExtractFile(zipFile, "modinfo.xml", &modInfoFileBuffer, &modInfoFileBufferSize)) + { + std::cerr << "Zip::ExtractFile() Failed!" << std::endl; + Zip::CloseFile(zipFile); + return false; + } + + if (!Xml::ParseSporeModInfo(modInfoFileBuffer, modInfoFileBufferSize, sporeModInfo)) + { + std::cerr << "Xml::ParseSporeModInfo() Failed!" << std::endl; + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + return false; + } + + installedSporeMod.Name = sporeModInfo.Name; + installedSporeMod.UniqueName = sporeModInfo.UniqueName; + installedSporeMod.Description = sporeModInfo.Description; + + // check if mod with the same unique name is + // already installed + if (IsModAlreadyInstalled(sporeModInfo.UniqueName)) + { + return false; + } + + for (const auto& componentGroup : sporeModInfo.ComponentGroups) + { + std::cout << "-> " << componentGroup.Name << std::endl; + + componentsSize = componentGroup.Components.size(); + + for (size_t i = 0; i < componentsSize; i++) + { + component = componentGroup.Components[i]; + std::cout << "[" << i << "] " << component.Name << std::endl; + } + + int componentId = 0; + UI::AskUserInput("-> select which component you want: ", componentId, 0, componentsSize - 1); + + component = componentGroup.Components[componentId]; + + for (const auto& file : component.Files) + { + installedSporeMod.InstalledFiles.push_back(file); + } + } + + if (!sporeModInfo.Components.empty()) + { + componentsSize = sporeModInfo.Components.size(); + + for (size_t i = 0; i < componentsSize; i++) + { + component = sporeModInfo.Components[i]; + std::cout << "[" << i << "] " << component.Name << std::endl + << " " << component.Description << std::endl; + } + + std::vector componentIds; + + UI::AskUserInput("-> select which components you want to install (comma seperated): ", ',', componentIds, 0, componentsSize); + + for (const auto& componentId : componentIds) + { + component = sporeModInfo.Components[componentId]; + + for (const auto& file : component.Files) + { + installedSporeMod.InstalledFiles.push_back(file); + } + } + } + + for (const auto& prerequisite : sporeModInfo.Prerequisites) + { + for (const auto& file : prerequisite.Files) + { + installedSporeMod.InstalledFiles.push_back(file); + } + } + + for (const auto& installedFile : installedSporeMod.InstalledFiles) + { + std::cout << "-> Installing " << installedFile.FileName.string() << std::endl; + + std::filesystem::path sourcePath = installedFile.FileName; + std::filesystem::path installPath = Path::GetFullInstallPath(installedFile.InstallLocation, installedFile.FileName); + + if (!Zip::ExtractFile(zipFile, sourcePath, installPath)) + { + std::cerr << "Zip::ExtractFile() Failed!" << std::endl; + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + return false; + } + } + + std::vector installedSporeMods; + if (!Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "Xml::GetInstalledModList() Failed!" << std::endl; + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + return false; + } + + installedSporeMods.push_back(installedSporeMod); + + Xml::SaveInstalledModList(installedSporeMods); + + free(modInfoFileBuffer); + Zip::CloseFile(zipFile); + return true; +} + +bool SporeMod::InstallPackage(std::filesystem::path path) +{ + Xml::InstalledSporeMod installedSporeMod; + Xml::SporeModFile installedFile; + + std::string baseName = path.stem().string(); + + installedFile.FileName = path.filename(); + installedFile.InstallLocation = InstallLocation::GalacticAdventuresData; + + installedSporeMod.Name = baseName; + installedSporeMod.UniqueName = baseName; + installedSporeMod.InstalledFiles.push_back(installedFile); + + // check if mod with the same unique name is + // already installed + if (IsModAlreadyInstalled(baseName)) + { + return false; + } + + for (const auto& installedFile : installedSporeMod.InstalledFiles) + { + std::cout << "-> Installing " << installedFile.FileName.string() << std::endl; + + std::filesystem::path sourcePath = installedFile.FileName; + std::filesystem::path installPath = Path::GetFullInstallPath(installedFile.InstallLocation, installedFile.FileName); + + try + { + std::filesystem::copy_file(sourcePath, installPath, std::filesystem::copy_options::overwrite_existing); + } + catch (...) + { + std::cerr << "std::filesystem::copy_file(\"" << sourcePath.string() << "\",\"" << installPath.string() << "\") Failed!" << std::endl; + return false; + } + } + + std::vector installedSporeMods; + if (!Xml::GetInstalledModList(installedSporeMods)) + { + std::cerr << "Xml::GetInstalledModList() Failed!" << std::endl; + return false; + } + + installedSporeMods.push_back(installedSporeMod); + + Xml::SaveInstalledModList(installedSporeMods); + return true; +} + diff --git a/SporeModManager/SporeModManagerHelpers/SporeModXml.cpp b/SporeModManager/SporeModManagerHelpers/SporeModXml.cpp new file mode 100644 index 0000000..0d2c7e6 --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers/SporeModXml.cpp @@ -0,0 +1,505 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManagerHelpers.hpp" + +#include +#include + +using namespace SporeModManagerHelpers; + +// +// Helper Functions +// + +static std::vector SplitString(std::string string, char delimitor) +{ + std::vector result; + std::stringstream stringStream(string); + std::string item; + + while (std::getline(stringStream, item, delimitor)) + { + result.push_back(item); + } + + return result; +} + +static std::string InstallLocationToString(SporeMod::InstallLocation installLocation) +{ + switch (installLocation) + { + default: + case SporeMod::InstallLocation::ModLibs: + return "ModLibs"; + case SporeMod::InstallLocation::GalacticAdventuresData: + return "GalacticAdventuresData"; + case SporeMod::InstallLocation::CoreSporeData: + return "CoreSporeData"; + } +} + +static SporeMod::InstallLocation ParseInstallLocation(std::string text) +{ + SporeMod::InstallLocation installLocation; + + if (text == "GalacticAdventures" || text == "GalacticAdventuresData") + { + installLocation = SporeMod::InstallLocation::GalacticAdventuresData; + } + else if (text == "CoreSpore" || text == "CoreSporeData") + { + installLocation = SporeMod::InstallLocation::CoreSporeData; + } + else + { + installLocation = SporeMod::InstallLocation::ModLibs; + } + + return installLocation; +} + +static std::string GetAttributeText(tinyxml2::XMLElement* element, std::string attributeName) +{ + const tinyxml2::XMLAttribute* xmlAttribute; + + xmlAttribute = element->FindAttribute(attributeName.c_str()); + if (xmlAttribute != nullptr) + { + if (xmlAttribute->Value() != nullptr) + { + return xmlAttribute->Value(); + } + } + + return ""; +} + +static std::string GetElementText(tinyxml2::XMLElement* element) +{ + const char* text; + + if (element == nullptr) + { + return ""; + } + + text = element->GetText(); + if (text != nullptr) + { + return text; + } + + return ""; +} + +static std::string GetElementName(tinyxml2::XMLElement* element) +{ + if (element->Name() != nullptr) + { + return element->Name(); + } + + return ""; +} + +static tinyxml2::XMLElement* FindElement(tinyxml2::XMLElement* rootElement, std::string name) +{ + tinyxml2::XMLElement* xmlElement; + std::string xmlElementName; + + xmlElement = rootElement->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + if (xmlElementName == name) + { + return xmlElement; + } + + xmlElement = xmlElement->NextSiblingElement(); + } + + return nullptr; +} + +static std::vector ParseFiles(tinyxml2::XMLElement* element) +{ + std::vector files; + + std::vector installLocations; + std::vector installFiles; + + installLocations = SplitString(GetAttributeText(element, "game"), '?'); + installFiles = SplitString(GetElementText(element), '?'); + + for (size_t i = 0; i < installFiles.size(); i++) + { + SporeMod::Xml::SporeModFile file; + + if (installLocations.size() > i) + { + file.InstallLocation = ParseInstallLocation(installLocations[i]); + } + else + { + file.InstallLocation = SporeMod::InstallLocation::ModLibs; + } + file.FileName = installFiles[i]; + + files.push_back(file); + } + + return files; +} + +static SporeMod::Xml::SporeModInfoComponent ParseComponentElement(tinyxml2::XMLElement* element) +{ + SporeMod::Xml::SporeModInfoComponent component; + + component.Name = GetAttributeText(element, "displayName"); + component.UniqueName = GetAttributeText(element, "unique"); + component.Description = GetAttributeText(element, "description"); + component.Files = ParseFiles(element); + + return component; +} + + +static SporeMod::Xml::SporeModInfoComponentGroup ParseComponentGroupElement(tinyxml2::XMLElement* element) +{ + SporeMod::Xml::SporeModInfoComponentGroup componentGroup; + tinyxml2::XMLElement* xmlElement; + std::string xmlElementName; + + componentGroup.Name = GetAttributeText(element, "displayName"); + componentGroup.UniqueName = GetAttributeText(element, "unique"); + + xmlElement = element->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + + if (xmlElementName == "component") + { + componentGroup.Components.push_back(ParseComponentElement(xmlElement)); + } + + xmlElement = xmlElement->NextSiblingElement(); + } + + return componentGroup; +} + +static SporeMod::Xml::SporeModInfoPrerequisite ParsePrerequisiteElement(tinyxml2::XMLElement* element) +{ + SporeMod::Xml::SporeModInfoPrerequisite prerequisite; + + prerequisite.Files = ParseFiles(element); + + return prerequisite; +} + +static std::vector ParseInstalledSporeModFilesElement(tinyxml2::XMLElement* element) +{ + std::vector sporeModFiles; + tinyxml2::XMLElement* xmlElement; + std::string xmlElementName; + + if (element == nullptr) + { + return sporeModFiles; + } + + xmlElement = element->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + + if (xmlElementName == "InstalledModFile") + { + SporeMod::Xml::SporeModFile sporeModFile; + + sporeModFile.FileName = GetElementText(FindElement(xmlElement, "FileName")); + sporeModFile.InstallLocation = ParseInstallLocation(GetElementText(FindElement(xmlElement, "InstallLocation"))); + + sporeModFiles.push_back(sporeModFile); + } + + xmlElement = xmlElement->NextSiblingElement(); + } + + return sporeModFiles; +} + +static SporeMod::Xml::InstalledSporeMod ParseInstalledSporeModElement(tinyxml2::XMLElement* element) +{ + SporeMod::Xml::InstalledSporeMod installedSporeMod; + tinyxml2::XMLElement* xmlElement; + std::string xmlElementName; + + xmlElement = element->FirstChildElement(); + installedSporeMod.Name = GetElementText(FindElement(element, "Name")); + installedSporeMod.UniqueName = GetElementText(FindElement(element, "UniqueName")); + installedSporeMod.Description = GetElementText(FindElement(element, "Description")); + installedSporeMod.InstalledFiles = ParseInstalledSporeModFilesElement(FindElement(element, "Files")); + + return installedSporeMod; +} + +// +// Exported Functions +// + +bool SporeMod::Xml::ParseSporeModInfo(char* buffer, size_t bufferSize, SporeModInfo& sporeModInfo) +{ + tinyxml2::XMLDocument xmlDocument; + tinyxml2::XMLElement* xmlElement; + tinyxml2::XMLError error; + std::string xmlElementName; + + error = xmlDocument.Parse(buffer, bufferSize); + if (error != tinyxml2::XMLError::XML_SUCCESS) + { + std::cerr << "XmlDocument.Parse() Failed!" << std::endl; + return false; + } + + xmlElement = xmlDocument.RootElement(); + if (xmlElement == nullptr) + { + std::cerr << "XDocument.RootElement() Failed!" << std::endl; + return false; + } + + sporeModInfo.Name = GetAttributeText(xmlElement, "displayName"); + sporeModInfo.UniqueName = GetAttributeText(xmlElement, "unique"); + sporeModInfo.Description = GetAttributeText(xmlElement, "description"); + + xmlElement = xmlElement->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + + if (xmlElementName == "componentGroup") + { + sporeModInfo.ComponentGroups.push_back(ParseComponentGroupElement(xmlElement)); + } + else if (xmlElementName == "component") + { + sporeModInfo.Components.push_back(ParseComponentElement(xmlElement)); + } + else if (xmlElementName == "prerequisite") + { + sporeModInfo.Prerequisites.push_back(ParsePrerequisiteElement(xmlElement)); + } + + xmlElement = xmlElement->NextSiblingElement(); + } + return true; +} + +bool SporeMod::Xml::GetDirectories(std::filesystem::path& modLibsPath, std::filesystem::path& galacticAdventuresDataPath, std::filesystem::path& coreSporeDataPath) +{ + tinyxml2::XMLDocument xmlDocument; + tinyxml2::XMLElement* xmlElement; + tinyxml2::XMLElement* childXmlElement; + tinyxml2::XMLError error; + std::string xmlElementName; + + if (!std::filesystem::is_regular_file("SporeModManager.xml")) + { + if (!Xml::SaveDirectories("..\\ModLibs", "..\\..\\DataEP1", "..\\..\\Data")) + { + std::cerr << "Xml::SaveDirectories() Failed!" << std::endl; + return false; + } + } + + error = xmlDocument.LoadFile("SporeModManager.xml"); + if (error != tinyxml2::XMLError::XML_SUCCESS) + { + std::cerr << "XmlDocument.LoadFile() Failed!" << std::endl; + return false; + } + + xmlElement = xmlDocument.RootElement(); + if (xmlElement == nullptr) + { + std::cerr << "XDocument.RootElement() Failed!" << std::endl; + return false; + } + + xmlElement = xmlElement->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + if (xmlElementName == "Directories") + { + childXmlElement = xmlElement->FirstChildElement(); + while (childXmlElement != nullptr) + { + xmlElementName = GetElementName(childXmlElement); + if (xmlElementName == "ModLibsDirectory") + { + modLibsPath = GetElementText(childXmlElement); + } + else if (xmlElementName == "GalacticAdventuresDataDirectory") + { + galacticAdventuresDataPath = GetElementText(childXmlElement); + } + else if (xmlElementName == "CoreSporeDataDirectory") + { + coreSporeDataPath = GetElementText(childXmlElement); + } + + childXmlElement = childXmlElement->NextSiblingElement(); + } + } + + xmlElement = xmlElement->NextSiblingElement(); + } + + return true; +} + +bool SporeMod::Xml::SaveDirectories(std::filesystem::path modLibsPath, std::filesystem::path galacticAdventuresDataPath, std::filesystem::path coreSporeDataPath) +{ + tinyxml2::XMLDocument xmlDocument; + tinyxml2::XMLElement* rootXmlElement; + tinyxml2::XMLElement* directoriesElement; + + rootXmlElement = xmlDocument.NewElement("SporeModManager"); + xmlDocument.InsertFirstChild(rootXmlElement); + + directoriesElement = rootXmlElement->InsertNewChildElement("Directories"); + directoriesElement->InsertNewChildElement("ModLibsDirectory")->SetText(modLibsPath.string().c_str()); + directoriesElement->InsertNewChildElement("GalacticAdventuresDataDirectory")->SetText(galacticAdventuresDataPath.string().c_str()); + directoriesElement->InsertNewChildElement("CoreSporeDataDirectory")->SetText(coreSporeDataPath.string().c_str()); + + xmlDocument.SaveFile("SporeModManager.xml"); + return true; +} + +bool SporeMod::Xml::GetInstalledModList(std::vector& installedSporeModList) +{ + tinyxml2::XMLDocument xmlDocument; + tinyxml2::XMLElement* xmlElement; + tinyxml2::XMLElement* childXmlElement; + tinyxml2::XMLError error; + std::string xmlElementName; + + if (!std::filesystem::is_regular_file("SporeModManager.xml")) + { + return true; + } + + error = xmlDocument.LoadFile("SporeModManager.xml"); + if (error != tinyxml2::XMLError::XML_SUCCESS) + { + std::cerr << "XmlDocument.LoadFile() Failed!" << std::endl; + return false; + } + + xmlElement = xmlDocument.RootElement(); + if (xmlElement == nullptr) + { + std::cerr << "XDocument.RootElement() Failed!" << std::endl; + return false; + } + + xmlElement = xmlElement->FirstChildElement(); + while (xmlElement != nullptr) + { + xmlElementName = GetElementName(xmlElement); + if (xmlElementName == "InstalledSporeMods") + { + childXmlElement = xmlElement->FirstChildElement(); + while (childXmlElement != nullptr) + { + xmlElementName = GetElementName(childXmlElement); + if (xmlElementName == "InstalledSporeMod") + { + installedSporeModList.push_back(ParseInstalledSporeModElement(childXmlElement)); + } + + childXmlElement = childXmlElement->NextSiblingElement(); + } + } + + xmlElement = xmlElement->NextSiblingElement(); + } + + // sort list by alphabet + std::sort(installedSporeModList.begin(), installedSporeModList.end(), + [](const InstalledSporeMod& a, const InstalledSporeMod& b) + { + return a.Name < b.Name; + } + ); + + return true; +} + +bool SporeMod::Xml::SaveInstalledModList(std::vector installedSporeModList) +{ + tinyxml2::XMLDocument xmlDocument; + tinyxml2::XMLElement* rootXmlElement; + tinyxml2::XMLElement* installedSporeModsElement; + tinyxml2::XMLElement* xmlElement; + tinyxml2::XMLElement* filesXmlElement; + tinyxml2::XMLElement* installedModFileElement; + tinyxml2::XMLError error; + std::string xmlElementName; + + error = xmlDocument.LoadFile("SporeModManager.xml"); + if (error != tinyxml2::XMLError::XML_SUCCESS) + { + std::cerr << "XmlDocument.LoadFile() Failed!" << std::endl; + return false; + } + + rootXmlElement = xmlDocument.RootElement(); + xmlDocument.InsertFirstChild(rootXmlElement); + + installedSporeModsElement = FindElement(rootXmlElement, "InstalledSporeMods"); + if (installedSporeModsElement != nullptr) + { // element exists, so remove all children + installedSporeModsElement->DeleteChildren(); + } + else + { // element doesn't exist, so insert it + installedSporeModsElement = rootXmlElement->InsertNewChildElement("InstalledSporeMods"); + } + + for (const auto& installedSporeMod : installedSporeModList) + { + xmlElement = installedSporeModsElement->InsertNewChildElement("InstalledSporeMod"); + xmlElement->InsertNewChildElement("Name")->SetText(installedSporeMod.Name.c_str()); + xmlElement->InsertNewChildElement("UniqueName")->SetText(installedSporeMod.UniqueName.c_str()); + xmlElement->InsertNewChildElement("Description")->SetText(installedSporeMod.Description.c_str()); + + filesXmlElement = xmlElement->InsertNewChildElement("Files"); + + for (const auto& installedFile : installedSporeMod.InstalledFiles) + { + std::string fileName = installedFile.FileName.string(); + std::string installLocation = InstallLocationToString(installedFile.InstallLocation); + + installedModFileElement = filesXmlElement->InsertNewChildElement("InstalledModFile"); + installedModFileElement->InsertNewChildElement("FileName")->SetText(fileName.c_str()); + installedModFileElement->InsertNewChildElement("InstallLocation")->SetText(installLocation.c_str()); + } + } + + xmlDocument.SaveFile("SporeModManager.xml"); + return true; +} + diff --git a/SporeModManager/SporeModManagerHelpers/UI.cpp b/SporeModManager/SporeModManagerHelpers/UI.cpp new file mode 100644 index 0000000..a00075d --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers/UI.cpp @@ -0,0 +1,82 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManagerHelpers.hpp" + +#include + +using namespace SporeModManagerHelpers; + +void UI::AskUserInput(std::string text, int& number, int min, int max) +{ + do + { + if (std::cin.fail()) + { + std::cin.clear(); + std::cin.ignore(); + } + + std::cout << text; + std::cin >> number; + + if (std::cin.fail() || number < min || number > max) + { + std::cerr << "invalid input" << std::endl; + continue; + } + else + { + std::cin.clear(); + std::cin.ignore(); + break; + } + } while (true); +} + +void UI::AskUserInput(std::string text, char delimiter, std::vector& numbers, int min, int max) +{ + std::string inputLine; + std::stringstream stringStream; + std::string inputItem; + int number; + bool validInput = false; + do + { + numbers.clear(); + + std::cout << text; + + std::getline(std::cin, inputLine); + stringStream = std::stringstream(inputLine); + while (std::getline(stringStream, inputItem, delimiter)) + { + try + { + number = std::stoi(inputItem); + if (number < min || number > max) + { + throw std::exception(); + } + else + { + numbers.push_back(number); + validInput = true; + } + } + catch (...) + { + std::cout << "invalid input" << std::endl; + validInput = false; + break; + } + } + } while (!validInput); +} + diff --git a/SporeModManager/SporeModManagerHelpers/Zip.cpp b/SporeModManager/SporeModManagerHelpers/Zip.cpp new file mode 100644 index 0000000..a9ac7ec --- /dev/null +++ b/SporeModManager/SporeModManagerHelpers/Zip.cpp @@ -0,0 +1,218 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManagerHelpers.hpp" + +#include +#include + +#include + +using namespace SporeModManagerHelpers; + +// +// Local Defines +// + +#define UNZIP_READ_SIZE 67108860 /* 64 MiB */ + +// +// Exported Functions +// + +bool Zip::OpenFile(ZipFile& zipFile, std::filesystem::path path) +{ + zipFile = unzOpen(path.string().c_str()); + return zipFile != nullptr; +} + +bool Zip::CloseFile(ZipFile zipFile) +{ + return unzClose(zipFile) == UNZ_OK; +} + +bool Zip::GetFileList(ZipFile zipFile, std::vector& fileList) +{ + unz_global_info zipInfo; + + if (unzGetGlobalInfo(zipFile, &zipInfo) != UNZ_OK) + { + std::cerr << "unzGetGlobalInfo() Failed!" << std::endl; + return false; + } + + for (uint32_t i = 0; i < zipInfo.number_entry; i++) + { + unz_file_info fileInfo; + char fileName[2048]; + + // skip the file when we can't retrieve file info + if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, 2048, nullptr, 0, nullptr, 0) != UNZ_OK) + { + continue; + } + + fileList.push_back(fileName); + + // break when we've iterated over all entries + if ((uint32_t)(i + 1) >= zipInfo.number_entry) + { + break; + } + + // move to next file + if (unzGoToNextFile(zipFile) != UNZ_OK) + { + unzClose(zipFile); + std::cerr << "unzGoToNextFile() Failed!" << std::endl; + return false; + } + } + + return true; +} + +bool Zip::ExtractFile(ZipFile zipFile, std::filesystem::path file, std::filesystem::path outputFile) +{ + char* buffer; + size_t dataSize = UNZIP_READ_SIZE; + size_t bytesRead = 0; + std::ofstream outputFileStream; + + // try to find file in zip + if (unzLocateFile(zipFile, file.string().c_str(), nullptr) != UNZ_OK) + { + std::cerr << "Failed to find \"" << file << "\" in zip file!" << std::endl; + return false; + } + + buffer = (char*)malloc(UNZIP_READ_SIZE); + if (buffer == nullptr) + { + std::cerr << "malloc() Failed!" << std::endl; + return false; + } + + outputFileStream.open(outputFile, std::ofstream::trunc | std::ofstream::binary); + if (!outputFileStream.is_open()) + { + free(buffer); + std::cerr << "ofstream.open() Failed!" << std::endl; + return false; + } + + if (unzOpenCurrentFile(zipFile) != UNZ_OK) + { + free(buffer); + std::cerr << "unzOpenCurrentFile() Failed!" << std::endl; + return false; + } + + do + { + bytesRead = unzReadCurrentFile(zipFile, buffer, UNZIP_READ_SIZE); + if (bytesRead < 0) + { + unzCloseCurrentFile(zipFile); + free(buffer); + std::cerr << "unzReadCurrentFile() Failed: " << std::to_string(bytesRead) << std::endl; + return false; + } + + outputFileStream.write(buffer, bytesRead); + } while (bytesRead > 0); + + unzCloseCurrentFile(zipFile); + outputFileStream.flush(); + outputFileStream.close(); + free(buffer); + return true; +} + +bool Zip::ExtractFile(ZipFile zipFile, std::filesystem::path file, char** outBuffer, size_t* bufferSize) +{ + char* buffer; + char* tmpBuffer; + size_t dataSize = UNZIP_READ_SIZE; + size_t totalBytesRead = 0; + size_t bytesRead = 0; + + // try to find file in zip + if (unzLocateFile(zipFile, file.string().c_str(), nullptr) != UNZ_OK) + { + std::cerr << "Failed to find \"" << file << "\" in zip file!" << std::endl; + return false; + } + + buffer = (char*)malloc(UNZIP_READ_SIZE); + if (buffer == nullptr) + { + std::cerr << "malloc() Failed!" << std::endl; + return false; + } + + *outBuffer = (char*)malloc(UNZIP_READ_SIZE); + if (*outBuffer == nullptr) + { + free(buffer); + std::cerr << "malloc() Failed!" << std::endl; + return false; + } + + if (unzOpenCurrentFile(zipFile) != UNZ_OK) + { + free(buffer); + std::cerr << "unzOpenCurrentFile() Failed!" << std::endl; + return false; + } + + do + { + bytesRead = unzReadCurrentFile(zipFile, buffer, UNZIP_READ_SIZE); + if (bytesRead < 0) + { + unzCloseCurrentFile(zipFile); + free(buffer); + std::cerr << "unzReadCurrentFile() Failed: " << std::to_string(bytesRead) << std::endl; + return false; + } + + if (bytesRead > 0) + { + if (totalBytesRead + bytesRead > dataSize) + { + tmpBuffer = (char*)realloc(*outBuffer, totalBytesRead + bytesRead); + dataSize += bytesRead; + if (tmpBuffer == nullptr) + { + unzCloseCurrentFile(zipFile); + free(buffer); + free(*outBuffer); + std::cerr << "realloc() Failed!" << std::endl; + return false; + } + else + { + *outBuffer = tmpBuffer; + } + } + + memcpy((*outBuffer + totalBytesRead), buffer, bytesRead); + totalBytesRead += bytesRead; + } + } while (bytesRead > 0); + + unzCloseCurrentFile(zipFile); + *bufferSize = totalBytesRead; + free(buffer); + return true; + + +} + diff --git a/SporeModManager/SporeMods/SporeMods.Directory.cs b/SporeModManager/SporeMods/SporeMods.Directory.cs deleted file mode 100644 index 3105fd1..0000000 --- a/SporeModManager/SporeMods/SporeMods.Directory.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using SporeModManager.SporeMods.Xml; -using System.IO; - -namespace SporeModManager.SporeMods -{ - internal class Directory - { - private static DirectoryConfig directoryConfig; - - public static string GetModLibsDirectory() - { - return directoryConfig.ModLibsDirectory; - } - - public static string GetGalacticAdventuresDataDirectory() - { - return directoryConfig.GalacticAdventuresDataDirectory; - } - - public static string GetCoreSporeDataDirectory() - { - return directoryConfig.CoreSporeDataDirectory; - } - - public static string GetDirectoryFromInstallLocation(ModInfoInstallLocation modInfoInstallLocation) - { - switch (modInfoInstallLocation) - { - default: - case ModInfoInstallLocation.ModLibs: - return GetModLibsDirectory(); - - case ModInfoInstallLocation.GalacticAdventuresData: - return GetGalacticAdventuresDataDirectory(); - - case ModInfoInstallLocation.CoreSporeData: - return GetCoreSporeDataDirectory(); - } - } - - public static void ReadDirectoryConfig() - { - directoryConfig = DirectoryConfig.ReadFromXml(); - } - - public static void EnsureDirectoriesExist() - { - foreach (var directory in new string[] { Directory.GetModLibsDirectory(), - Directory.GetGalacticAdventuresDataDirectory(), - Directory.GetCoreSporeDataDirectory()}) - { - string fullPath = Path.GetFullPath(directory); - if (!System.IO.Directory.Exists(fullPath)) - { - throw new DirectoryNotFoundException(fullPath); - } - } - } - - } -} diff --git a/SporeModManager/SporeMods/SporeMods.Installer.cs b/SporeModManager/SporeMods/SporeMods.Installer.cs deleted file mode 100644 index 86f845c..0000000 --- a/SporeModManager/SporeMods/SporeMods.Installer.cs +++ /dev/null @@ -1,261 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using SporeModManager.SporeMods.Xml; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; - -namespace SporeModManager.SporeMods -{ - internal partial class SporeMods - { - private static void InstallFileFromZip(ref ZipArchive zipArchive, InstalledModFile installedModFile) - { - ZipArchiveEntry zipArchiveEntry = null; - - zipArchiveEntry = zipArchive.Entries.FirstOrDefault(e => e.Name.ToLower() == installedModFile.FileName.ToLower()); - if (zipArchiveEntry == default) - { - throw new Exception($"SporeMod archive doesn't contain {installedModFile.FileName}!"); - } - - Console.WriteLine($"-> installing {installedModFile.FileName}"); - - string directory = Directory.GetDirectoryFromInstallLocation(installedModFile.InstallLocation); - - using (var zipEntryStream = zipArchiveEntry.Open()) - { - string outputFileName = Path.Combine(directory, installedModFile.FileName); - var outputFileStream = File.OpenWrite(outputFileName); - - zipEntryStream.CopyTo(outputFileStream); - outputFileStream.Close(); - } - } - - private static void InstallSporeMod(ref InstalledMods installedMods, string filename) - { - FileStream fileStream = File.OpenRead(filename); - ZipArchive zipArchive = new ZipArchive(fileStream); - ZipArchiveEntry zipArchiveEntry = null; - - zipArchiveEntry = zipArchive.Entries.FirstOrDefault(e => e.Name.ToLower() == "modinfo.xml"); - if (zipArchiveEntry == default) - { - throw new Exception("SporeMod archive doesn't contain a modinfo.xml!"); - } - - var zipEntryStream = zipArchiveEntry.Open(); - var modInfo = ModInfo.DeserializeFromStream(zipEntryStream); - - var installedMod = new InstalledMod - { - Name = modInfo.DisplayName, - UniqueName = modInfo.UniqueName, - Description = modInfo.Description, - Files = new List() - }; - - foreach (var componentGroup in modInfo.ComponentGroups) - { - ModInfoComponent component; - Console.WriteLine($"-> {componentGroup.DisplayName}"); - - for (int i = 0; i < componentGroup.Components.Count(); i++) - { - component = componentGroup.Components[i]; - Console.WriteLine($"[{i}] {component.DisplayName}"); - if (!String.IsNullOrEmpty(component.Description.Trim())) - { - Console.WriteLine($" {component.DisplayName}"); - } - } - - // request what component the user wants installed - int id = -1; - while (id == -1) - { - Console.Write("-> select which component you want: "); - if (Int32.TryParse(Console.ReadLine(), out int userIndex)) - { - if (userIndex >= 0 && userIndex < componentGroup.Components.Count()) - { - id = userIndex; - } - } - - if (id == -1) - { - Console.WriteLine("Invalid input, try again"); - } - } - - component = componentGroup.Components[id]; - - if (component.FileNames.Count() != component.InstallLocations.Count()) - { - throw new Exception("component.FileNames.Count() != component.InstallLocations.Count()"); - } - - for (int i = 0; i < component.InstallLocations.Count(); i++) - { - installedMod.Files.Add(new InstalledModFile() - { - FileName = component.FileNames[i], - InstallLocation = component.InstallLocations[i] - }); - } - } - - if (modInfo.Components.Count() != 0) - { - for (int i = 0; i < modInfo.Components.Count(); i++) - { - Console.WriteLine($"[{i}] {modInfo.Components[i].DisplayName}"); - Console.WriteLine($" {modInfo.Components[i].Description}"); - } - - // ask the user what components they want to install - List componentIds = new List(); - bool userHasSelected = false; - bool userHasInvalidSelection = false; - while (!userHasSelected) - { - Console.Write("-> select which components you want to install (comma seperated): "); - string userInputString = Console.ReadLine(); - if (String.IsNullOrEmpty(userInputString)) - { - break; - } - - foreach (string num in userInputString.Split(',')) - { - if (Int32.TryParse(num, out int userIndex)) - { - if (userIndex >= 0 && userIndex < modInfo.Components.Count()) - { - componentIds.Add(userIndex); - } - else - { - userHasInvalidSelection = true; - } - } - } - - if (userHasInvalidSelection) - { - continue; - } - else - { - userHasSelected = true; - } - } - - foreach (var componentId in componentIds) - { - var component = modInfo.Components[componentId]; - - if (component.FileNames.Count() != component.InstallLocations.Count()) - { - throw new Exception("component.FileNames.Count() != component.InstallLocations.Count()"); - } - - for (int i = 0; i < component.InstallLocations.Count(); i++) - { - installedMod.Files.Add(new InstalledModFile() - { - FileName = component.FileNames[i], - InstallLocation = component.InstallLocations[i] - }); - } - } - } - - foreach (var prerequisite in modInfo.Prerequisites) - { - installedMod.Files.Add(new InstalledModFile() - { - FileName = prerequisite.FileName, - InstallLocation = prerequisite.InstallLocation - }); - } - - zipEntryStream.Close(); - - int index = installedMods.InstalledModList.FindIndex(delegate (InstalledMod a) { return a.UniqueName == installedMod.UniqueName; }); - if (index != -1) - { - SporeMods.UninstallMods(new List(index)); - installedMods.InstalledModList.RemoveAt(index); - installedMods.InstalledModList.Insert(index, installedMod); - } - else - { - installedMods.InstalledModList.Add(installedMod); - } - - foreach (var installedModFile in installedMod.Files) - { - InstallFileFromZip(ref zipArchive, installedModFile); - } - } - - private static void InstallPackageMod(ref InstalledMods installedMods, string filename) - { - string baseFileName = Path.GetFileName(filename); - - var installedMod = new InstalledMod() - { - Name = Path.GetFileNameWithoutExtension(filename), - UniqueName = Path.GetFileNameWithoutExtension(filename), - Files = new List() - { - new InstalledModFile() - { - InstallLocation = ModInfoInstallLocation.GalacticAdventuresData, - FileName = baseFileName - } - } - }; - - Console.WriteLine($"-> installing {baseFileName}"); - - File.Copy(filename, Path.Combine(Directory.GetGalacticAdventuresDataDirectory(), baseFileName), true); - installedMods.InstalledModList.Add(installedMod); - } - - public static void InstallMod(string filename) - { - var installedMods = InstalledMods.ReadFromXml(); - - Console.WriteLine($"> installing {filename}"); - - string extension = Path.GetExtension(filename).ToLower(); - if (extension == ".sporemod") - { - InstallSporeMod(ref installedMods, filename); - } else if (extension == ".package") - { - InstallPackageMod(ref installedMods, filename); - } else - { - throw new InvalidOperationException("mod type not supported!"); - } - - InstalledMods.SaveToXml(installedMods); - - Console.WriteLine($"> successfully installed {filename}"); - } - } -} diff --git a/SporeModManager/SporeMods/SporeMods.List.cs b/SporeModManager/SporeMods/SporeMods.List.cs deleted file mode 100644 index 169403a..0000000 --- a/SporeModManager/SporeMods/SporeMods.List.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using SporeModManager.SporeMods.Xml; -using System; -using System.Linq; - -namespace SporeModManager.SporeMods -{ - internal partial class SporeMods - { - public static void ListInstalledMods() - { - var installedMods = InstalledMods.ReadFromXml(); - - for (int i = 0; i < installedMods.InstalledModList.Count(); i++) - { - var installedMod = installedMods.InstalledModList[i]; - - Console.WriteLine($"[{i}] {installedMod.Name}"); - Console.WriteLine($" {installedMod.Description}"); - } - } - } -} diff --git a/SporeModManager/SporeMods/SporeMods.Uninstaller.cs b/SporeModManager/SporeMods/SporeMods.Uninstaller.cs deleted file mode 100644 index 6248002..0000000 --- a/SporeModManager/SporeMods/SporeMods.Uninstaller.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using SporeModManager.SporeMods.Xml; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace SporeModManager.SporeMods -{ - internal partial class SporeMods - { - public static void UninstallMods(List ids) - { - var installedMods = InstalledMods.ReadFromXml(); - - int installedModListCount = installedMods.InstalledModList.Count(); - foreach (var id in ids) - { - if (id < 0 || id > installedModListCount || installedModListCount == 0) - { - throw new Exception("Invalid mod ID!"); - } - } - - var installedModsList = new List(); - foreach (var id in ids) - { - installedModsList.Add(installedMods.InstalledModList[id]); - } - - foreach (var installedMod in installedModsList) - { - Console.WriteLine($"> uninstalling {installedMod.Name}"); - - foreach (var installedModFile in installedMod.Files) - { - Console.WriteLine($"-> removing {installedModFile.FileName}"); - string directory = Directory.GetDirectoryFromInstallLocation(installedModFile.InstallLocation); - File.Delete(Path.Combine(directory, installedModFile.FileName)); - } - - installedMods.InstalledModList.Remove(installedMod); - InstalledMods.SaveToXml(installedMods); - - Console.WriteLine($"> successfully uninstalled {installedMod.Name}"); - } - } - } -} diff --git a/SporeModManager/SporeMods/Xml/DirectoryConfig.cs b/SporeModManager/SporeMods/Xml/DirectoryConfig.cs deleted file mode 100644 index 7f08625..0000000 --- a/SporeModManager/SporeMods/Xml/DirectoryConfig.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.IO; -using System.Xml.Serialization; - -namespace SporeModManager.SporeMods.Xml -{ - public class DirectoryConfig - { - public string ModLibsDirectory { get; set; } - public string GalacticAdventuresDataDirectory { get; set; } - public string CoreSporeDataDirectory { get; set; } - - public static DirectoryConfig ReadFromXml() - { - var directoryConfig = new DirectoryConfig(); - - if (File.Exists("DirectoryConfig.xml")) - { - using (var fileStream = File.OpenRead("DirectoryConfig.xml")) - { - var xmlSerializer = new XmlSerializer(typeof(DirectoryConfig)); - directoryConfig = (DirectoryConfig)xmlSerializer.Deserialize(fileStream); - fileStream.Close(); - } - } - else - { - directoryConfig.ModLibsDirectory = @"..\ModLibs"; - directoryConfig.GalacticAdventuresDataDirectory = @"..\..\DataEP1"; - directoryConfig.CoreSporeDataDirectory = @"..\..\Data"; - - using (var textWriter = new StreamWriter("DirectoryConfig.xml")) - { - var serializer = new XmlSerializer(typeof(DirectoryConfig)); - serializer.Serialize(textWriter, directoryConfig); - } - } - - return directoryConfig; - } - } -} diff --git a/SporeModManager/SporeMods/Xml/InstalledMod.cs b/SporeModManager/SporeMods/Xml/InstalledMod.cs deleted file mode 100644 index 8f47055..0000000 --- a/SporeModManager/SporeMods/Xml/InstalledMod.cs +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.Collections.Generic; - -namespace SporeModManager.SporeMods.Xml -{ - public class InstalledMod - { - public string Name { get; set; } - public string UniqueName { get; set; } - public string Description { get; set; } - public List Files { get; set; } - } -} diff --git a/SporeModManager/SporeMods/Xml/InstalledModFile.cs b/SporeModManager/SporeMods/Xml/InstalledModFile.cs deleted file mode 100644 index e560d41..0000000 --- a/SporeModManager/SporeMods/Xml/InstalledModFile.cs +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace SporeModManager.SporeMods.Xml -{ - public class InstalledModFile - { - public string FileName { get; set; } - public ModInfoInstallLocation InstallLocation { get; set; } - } -} diff --git a/SporeModManager/SporeMods/Xml/InstalledMods.cs b/SporeModManager/SporeMods/Xml/InstalledMods.cs deleted file mode 100644 index 37771fa..0000000 --- a/SporeModManager/SporeMods/Xml/InstalledMods.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.Collections.Generic; -using System.IO; -using System.Xml.Serialization; - -namespace SporeModManager.SporeMods.Xml -{ - public class InstalledMods - { - public List InstalledModList { get; set; } - - public static InstalledMods ReadFromXml() - { - var installedMods = new InstalledMods(); - - if (File.Exists("InstalledMods.xml")) - { - using (var fileStream = File.OpenRead("InstalledMods.xml")) - { - var xmlSerializer = new XmlSerializer(typeof(InstalledMods)); - installedMods = (InstalledMods)xmlSerializer.Deserialize(fileStream); - } - } - else - { - installedMods.InstalledModList = new List(); - } - - return installedMods; - } - - public static void SaveToXml(InstalledMods installedMods) - { - using (var textWriter = new StreamWriter("InstalledMods.xml")) - { - var serializer = new XmlSerializer(typeof(InstalledMods)); - serializer.Serialize(textWriter, installedMods); - } - } - } -} diff --git a/SporeModManager/SporeMods/Xml/ModInfo.cs b/SporeModManager/SporeMods/Xml/ModInfo.cs deleted file mode 100644 index 2bb7204..0000000 --- a/SporeModManager/SporeMods/Xml/ModInfo.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Xml; - -namespace SporeModManager.SporeMods.Xml -{ - internal class ModInfo - { - public string DisplayName { get; set; } - public string UniqueName { get; set; } - public string Description { get; set; } - public bool IsExperimental { get; set; } - public bool RequiresGalaxyReset { get; set; } - public bool CausesSaveDependency { get; set; } - - public Version InstallerSystemVersion { get; set; } - public Version ModAPIDllsBuildVersion { get; set; } - - public List ComponentGroups { get; set; } - public List Components { get; set; } - public List Prerequisites { get; set; } - public static ModInfo DeserializeFromStream(Stream stream) - { - var modInfo = new ModInfo(); - - modInfo.ComponentGroups = new List(); - modInfo.Components = new List(); - modInfo.Prerequisites = new List(); - - var xmlDocument = new XmlDocument(); - - xmlDocument.Load(stream); - - var modElement = xmlDocument.DocumentElement; - - if (modElement.HasAttribute("displayName")) - { - modInfo.DisplayName = modElement.GetAttribute("displayName"); - } - - if (modElement.HasAttribute("unique")) - { - modInfo.UniqueName = modElement.GetAttribute("unique"); - } - - if (modElement.HasAttribute("description")) - { - modInfo.Description = modElement.GetAttribute("description"); - } - - if (modElement.HasAttribute("isExperimental")) - { - modInfo.IsExperimental = Boolean.Parse(modElement.GetAttribute("isExperimental")); - } - - if (modElement.HasAttribute("requiresGalaxyReset")) - { - modInfo.RequiresGalaxyReset = Boolean.Parse(modElement.GetAttribute("requiresGalaxyReset")); - } - - if (modElement.HasAttribute("causesSaveDataDependency")) - { - modInfo.CausesSaveDependency = Boolean.Parse(modElement.GetAttribute("causesSaveDataDependency")); - } - - if (modElement.HasAttribute("installerSystemVersion")) - { - modInfo.InstallerSystemVersion = new Version(modElement.GetAttribute("installerSystemVersion")); - } - - if (modElement.HasAttribute("dllsBuild")) - { - modInfo.ModAPIDllsBuildVersion = new Version(modElement.GetAttribute("dllsBuild")); - } - - foreach (XmlElement componentGroupElement in modElement.SelectNodes("componentGroup")) - { - var componentGroup = new ModInfoComponentGroup(); - componentGroup.Components = new List(); - - if (componentGroupElement.HasAttribute("displayName")) - { - componentGroup.DisplayName = componentGroupElement.GetAttribute("displayName"); - } - - if (componentGroupElement.HasAttribute("unique")) - { - componentGroup.UniqueName = componentGroupElement.GetAttribute("unique"); - } - - foreach (XmlElement componentElement in componentGroupElement.SelectNodes("component")) - { - componentGroup.Components.Add(ModInfoComponent.ParseXmlElement(componentElement)); - } - - modInfo.ComponentGroups.Add(componentGroup); - } - - foreach (XmlElement componentElement in modElement.SelectNodes("component")) - { - modInfo.Components.Add(ModInfoComponent.ParseXmlElement(componentElement)); - } - - foreach (XmlElement prerequisiteElement in modElement.SelectNodes("prerequisite")) - { - modInfo.Prerequisites.Add(ModInfoPrerequisite.ParseXmlElement(prerequisiteElement)); - } - - return modInfo; - } - - } -} diff --git a/SporeModManager/SporeMods/Xml/ModInfoComponent.cs b/SporeModManager/SporeMods/Xml/ModInfoComponent.cs deleted file mode 100644 index 30b2e33..0000000 --- a/SporeModManager/SporeMods/Xml/ModInfoComponent.cs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Xml; - -namespace SporeModManager.SporeMods.Xml -{ - internal class ModInfoComponent - { - public string DisplayName { get; set; } - public string UniqueName { get; set; } - public string Description { get; set; } - public bool DefaultChecked { get; set; } - public List InstallLocations; - public List FileNames { get; set; } - - - public static ModInfoComponent ParseXmlElement(XmlElement element) - { - var modInfoComponent = new ModInfoComponent(); - modInfoComponent.InstallLocations = new List(); - modInfoComponent.FileNames = new List(); - - if (element.HasAttribute("displayName")) - { - modInfoComponent.DisplayName = element.GetAttribute("displayName"); - } - - if (element.HasAttribute("unique")) - { - modInfoComponent.UniqueName = element.GetAttribute("unique"); - } - - if (element.HasAttribute("description")) - { - modInfoComponent.Description = element.GetAttribute("description"); - } - - if (element.HasAttribute("defaultChecked")) - { - modInfoComponent.DefaultChecked = Boolean.Parse(element.GetAttribute("defaultChecked")); - } - - if (element.HasAttribute("game")) - { - string gameElementString = element.GetAttribute("game").ToLower(); - - foreach (var game in gameElementString.Split('?')) - { - ModInfoInstallLocation installLocation = ModInfoInstallLocation.ModLibs; - if (game == "galacticadventures") - { - installLocation = ModInfoInstallLocation.GalacticAdventuresData; - } - else if (game == "spore") - { - installLocation = ModInfoInstallLocation.CoreSporeData; - } - - modInfoComponent.InstallLocations.Add(installLocation); - } - } - - if (!String.IsNullOrEmpty(element.InnerText)) - { - foreach (var fileName in element.InnerText.Split('?')) - { - modInfoComponent.FileNames.Add(fileName); - } - } - - return modInfoComponent; - } - } -} diff --git a/SporeModManager/SporeMods/Xml/ModInfoComponentGroup.cs b/SporeModManager/SporeMods/Xml/ModInfoComponentGroup.cs deleted file mode 100644 index 7a76fd7..0000000 --- a/SporeModManager/SporeMods/Xml/ModInfoComponentGroup.cs +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.Collections.Generic; - -namespace SporeModManager.SporeMods.Xml -{ - internal class ModInfoComponentGroup - { - public string DisplayName { get; set; } - public string UniqueName { get; set; } - public List Components { get; set; } - } -} diff --git a/SporeModManager/SporeMods/Xml/ModInfoInstallLocation.cs b/SporeModManager/SporeMods/Xml/ModInfoInstallLocation.cs deleted file mode 100644 index b6ab818..0000000 --- a/SporeModManager/SporeMods/Xml/ModInfoInstallLocation.cs +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace SporeModManager.SporeMods.Xml -{ - public enum ModInfoInstallLocation - { - ModLibs, - GalacticAdventuresData, - CoreSporeData - } -} diff --git a/SporeModManager/SporeMods/Xml/ModInfoPrerequisite.cs b/SporeModManager/SporeMods/Xml/ModInfoPrerequisite.cs deleted file mode 100644 index b0c6f1c..0000000 --- a/SporeModManager/SporeMods/Xml/ModInfoPrerequisite.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SporeModLoader - https://github.com/Rosalie241/SporeModLoader - * Copyright (C) 2022 Rosalie Wanders - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.Xml; - -namespace SporeModManager.SporeMods.Xml -{ - internal class ModInfoPrerequisite - { - public ModInfoInstallLocation InstallLocation { get; set; } - public string FileName { get; set; } - - public static ModInfoPrerequisite ParseXmlElement(XmlElement element) - { - var modInfoPrerequisite = new ModInfoPrerequisite(); - - modInfoPrerequisite.InstallLocation = ModInfoInstallLocation.ModLibs; - if (element.HasAttribute("game")) - { - string game = element.GetAttribute("game").ToLower(); - - if (game == "galacticadventures") - { - modInfoPrerequisite.InstallLocation = ModInfoInstallLocation.GalacticAdventuresData; - } - else if (game == "spore") - { - modInfoPrerequisite.InstallLocation = ModInfoInstallLocation.CoreSporeData; - } - } - - modInfoPrerequisite.FileName = element.InnerText; - - return modInfoPrerequisite; - } - } -} diff --git a/SporeModManager/main.cpp b/SporeModManager/main.cpp new file mode 100644 index 0000000..785328c --- /dev/null +++ b/SporeModManager/main.cpp @@ -0,0 +1,122 @@ +/* + * SporeModLoader - https://github.com/Rosalie241/SporeModLoader + * Copyright (C) 2022 Rosalie Wanders + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "SporeModManager.hpp" +#include "SporeModManagerHelpers.hpp" + +#include + +using namespace SporeModManagerHelpers; + +static void ShowUsage() +{ + std::cout << "Usage: SporeModManager [OPTION]" << std::endl + << std::endl + << "Options:" << std::endl + << " -l, --list-installed lists installed mods with IDs" << std::endl + << " -i, --install FILE installs FILE" << std::endl + << " -u, --update FILE updates mod using FILE" << std::endl + << " -r, --uninstall ID uninstalls mod with ID" << std::endl + << std::endl + << " --help display this help and exit" << std::endl; +} + +int main(int argc, char** argv) +{ + if (!Path::CheckIfPathsExist()) + { + return 1; + } + + if (argc < 2) + { + ShowUsage(); + return 1; + } + + char* action = argv[1]; + if (std::strcmp(action, "--help") == 0) + { + ShowUsage(); + return 0; + } + else if (std::strcmp(action, "-l") == 0 || + std::strcmp(action, "--list-installed") == 0) + { + if (argc != 2) + { + ShowUsage(); + return 1; + } + + SporeModManager::ListInstalledMods(); + return 0; + } + else if (std::strcmp(action, "-i") == 0 || + std::strcmp(action, "--install") == 0) + { + if (argc != 3) + { + ShowUsage(); + return 1; + } + + if (!SporeModManager::InstallMod(argv[2])) + { + return 1; + } + } + else if (std::strcmp(action, "-u") == 0 || + std::strcmp(action, "--update") == 0) + { + if (argc != 3) + { + ShowUsage(); + return 1; + } + + if (!SporeModManager::UpdateMod(argv[2])) + { + return 1; + } + } + else if (std::strcmp(action, "-r") == 0 || + std::strcmp(action, "--uninstall") == 0) + { + if (argc != 3) + { + ShowUsage(); + return 1; + } + + int id = 0; + + try + { + id = std::stoi(argv[2]); + } + catch (...) + { + std::cerr << "ID must be a number!" << std::endl; + return 1; + } + + if (!SporeModManager::UninstallMod(id)) + { + return 1; + } + } + else + { + ShowUsage(); + return 1; + } + + return 0; +}