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;
+}