Skip to content

Commit

Permalink
-Initial file merge
Browse files Browse the repository at this point in the history
-SaveDataManager Init added to PLGlobalStart
  • Loading branch information
Nagord committed Aug 19, 2022
1 parent ef38f39 commit 6e43f2f
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 1 deletion.
5 changes: 4 additions & 1 deletion PulsarModLoader/Patches/PLGlobalStart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ static void Prefix()

//Modmanager GUI Init.
new GameObject("ModManager", typeof(CustomGUI.GUIMain)) { hideFlags = HideFlags.HideAndDontSave };


//SaveDataManager Init()
new SaveData.SaveDataManager();

//ModLoading
string modsDir = Path.Combine(Directory.GetCurrentDirectory(), "Mods");
ModManager.Instance.LoadModsDirectory(modsDir);
Expand Down
2 changes: 2 additions & 0 deletions PulsarModLoader/PulsarModLoader.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@
<Compile Include="ModManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Patches\HarmonyHelpers.cs" />
<Compile Include="SaveData\PMLSaveData.cs" />
<Compile Include="SaveData\SaveDataManager.cs" />
<Compile Include="Utilities\Clipboard.cs" />
<Compile Include="Utilities\HelperMethods.cs" />
<Compile Include="Utilities\ExceptionWarningPatch.cs" />
Expand Down
13 changes: 13 additions & 0 deletions PulsarModLoader/SaveData/PMLSaveData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.IO;

namespace PulsarModLoader.SaveData
{
public abstract class PMLSaveData
{
public PulsarMod MyMod;
public abstract string Identifier();
public virtual uint VersionID => 0;
public abstract MemoryStream SaveData();
public abstract void LoadData(MemoryStream dataStream, uint VersionID);
}
}
269 changes: 269 additions & 0 deletions PulsarModLoader/SaveData/SaveDataManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
using HarmonyLib;
using PulsarModLoader;
using PulsarModLoader.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace PulsarModLoader.SaveData
{
class SaveDataManager
{
public SaveDataManager()
{
ModManager.Instance.OnModSuccessfullyLoaded += OnModLoaded;
ModManager.Instance.OnModUnloaded += OnModRemoved;
Instance = this;
}
public static SaveDataManager Instance;

static public string SaveDir = Directory.GetCurrentDirectory() + "/Saves";
static public string LocalSaveDir = SaveDir + "/Local";

List<PMLSaveData> SaveConfigs = new List<PMLSaveData>();

void OnModLoaded(string modName, PulsarMod mod)
{
mod.GetType().Assembly.GetTypes().AsParallel().ForAll((type) =>
{
if (typeof(PMLSaveData).IsAssignableFrom(type) && !type.IsAbstract)
{
PMLSaveData SaveData = (PMLSaveData)Activator.CreateInstance(type);
SaveData.MyMod = mod;
SaveConfigs.Add(SaveData);
}
});
}

void OnModRemoved(PulsarMod mod)
{
List<PMLSaveData> saveConfigsToRemove = new List<PMLSaveData>();
SaveConfigs.AsParallel().ForAll((arg) =>
{
if (arg.GetType().Assembly == mod.GetType().Assembly)
{
saveConfigsToRemove.Add(arg);
}
});
for (byte s = 0; s < saveConfigsToRemove.Count; s++)
{
SaveConfigs.Remove(saveConfigsToRemove[s]);
}
}

public static string getPMLSaveFileName(string inFileName)
{
if(inFileName.EndsWith("LastRecoveredSave.plsave")) //Fix LastRecoveredSave
{
return inFileName.Replace("LastRecoveredSave.plsave", "LastRecoveredMSave.pmlsave");
}
return inFileName.Replace(".plsave", ".pmlsave");
}

public void SaveDatas(string inFileName)
{
//Stop if no save configs to save. Additionally check for older .pmlsave file under the same name and delete.
string fileName = getPMLSaveFileName(inFileName);
if (SaveConfigs.Count == 0)
{
if(File.Exists(fileName))
{
Logger.Info("Old PMLSave found with no new data to save. Deleting old data.");
File.Delete(fileName);
}
return;
}

//Start Saving, create temp file
string tempText = fileName + "_temp";
FileStream fileStream = File.Create(tempText);
BinaryWriter binaryWriter = new BinaryWriter(fileStream);

//save for mods
binaryWriter.Write(SaveConfigs.Count); //int32 representing total configs
foreach (PMLSaveData saveData in SaveConfigs)
{
try
{
PulsarModLoader.Utilities.Logger.Info($"Writing: {saveData.MyMod.HarmonyIdentifier()}::{saveData.Identifier()}");
MemoryStream dataStream = saveData.SaveData(); //Collect Save data from mod
int bytecount = (int)dataStream.Length;

//SaveDataHeader
binaryWriter.Write(saveData.MyMod.HarmonyIdentifier()); //Write Mod Identifier
binaryWriter.Write(saveData.Identifier()); //Write PMLSaveData Identifier
binaryWriter.Write(saveData.VersionID); //Write PMLSaveData VersionID
binaryWriter.Write(bytecount); //Write stream byte count
dataStream.Position = 0; //Reset position of dataStream for reading

byte[] buffer = new byte[bytecount];
dataStream.Read(buffer, 0, bytecount); //move data to filestream
binaryWriter.BaseStream.Write(buffer, 0, bytecount);

dataStream.Close();
}
catch (Exception ex)
{
Logger.Info($"Failed to save a mod data.\n{ex.Message}");
}
}

//Finish Saving, close and save file to actual location
binaryWriter.Close();
fileStream.Close();
if (File.Exists(fileName))
{
File.Delete(fileName);
}
File.Move(tempText, fileName);
string relativeFileName = PLNetworkManager.Instance.FileNameToRelative(fileName);
Logger.Info("PMLSaveManager has saved file: " + relativeFileName);


//Save to Steam
/*bool localFile = false;
if (relativeFileName.StartsWith(LocalSaveDir))
{
localFile = true;
}
if (!PLServer.Instance.IronmanModeIsActive && !localFile)
{
Logger.Info("Should be saving file to steam cloud");
PLNetworkManager.Instance.SteamCloud_WriteFileName(relativeFileName, delegate (RemoteStorageFileWriteAsyncComplete_t pCallback, bool bIOFailure)
{
OnRemoteFileWriteAsyncComplete(pCallback, bIOFailure, relativeFileName);
});
}*/
}

public void LoadDatas(string inFileName)
{
//start reading
string fileName = getPMLSaveFileName(inFileName);
if(!File.Exists(fileName))
{
return;
}
FileStream fileStream = File.OpenRead(fileName);
BinaryReader binaryReader = new BinaryReader(fileStream);

//read for mods
int count = binaryReader.ReadInt32(); //int32 representing total configs
string missingMods = "";
string VersionMismatchedMods = "";
for (int i = 0; i < count; i++)
{
//SaveDataHeader
string harmonyIdent = binaryReader.ReadString(); //HarmonyIdentifier
string SavDatIdent = binaryReader.ReadString(); //SaveDataIdentifier
uint VersionID = binaryReader.ReadUInt32(); //VersionID
int bytecount = binaryReader.ReadInt32(); //ByteCount
PulsarModLoader.Utilities.Logger.Info($"Reading SaveData: {harmonyIdent}::{SavDatIdent} SaveDataVersion: {VersionID} bytecount: {bytecount} Pos: {binaryReader.BaseStream.Position}");


bool foundReader = false;
foreach (PMLSaveData savedata in SaveConfigs)
{
if (savedata.MyMod.HarmonyIdentifier() == harmonyIdent && savedata.Identifier() == SavDatIdent)
{
if(VersionID != savedata.VersionID)
{
Logger.Info($"Mismatched SaveData VersionID. Read: {VersionID} SaveData: {savedata.VersionID}");
VersionMismatchedMods += "\n" + harmonyIdent;
}
MemoryStream stream = new MemoryStream(); //initialize new memStream

byte[] buffer = new byte[bytecount];
binaryReader.BaseStream.Read(buffer, 0, bytecount); //move data to memStream
stream.Write(buffer, 0, bytecount);

stream.Position = 0; //Reset position
try
{
savedata.LoadData(stream, VersionID); //Send memStream to PMLSaveData
}
catch (Exception ex)
{
Logger.Info($"Failed to load {harmonyIdent}::{SavDatIdent}\n{ex.Message}");
}
stream.Close();
foundReader = true;
}
}
if (!foundReader)
{
binaryReader.BaseStream.Position += bytecount;
missingMods += ("\n" + harmonyIdent);
}
}

//Finish Reading
binaryReader.Close();
fileStream.Close();
Logger.Info("PMLSaveManager has read file: " + PLNetworkManager.Instance.FileNameToRelative(fileName));

if (missingMods.Length > 0)
{
PLNetworkManager.Instance.MainMenu.AddActiveMenu(new PLErrorMessageMenu($"Warning: Found save data for following missing mods: {missingMods}"));
Logger.Info($"Warning: Found save data for following missing mods: {missingMods}");
}
if (!string.IsNullOrEmpty(VersionMismatchedMods))
{
PLNetworkManager.Instance.MainMenu.AddActiveMenu(new PLErrorMessageMenu($"Warning: The following mods used in this save have been updated: {VersionMismatchedMods}"));
Logger.Info($"Warning: The following mods used in this save have been updated: {VersionMismatchedMods}");
}
}
}
[HarmonyPatch(typeof(PLSaveGameIO), "SaveToFile")]
class SavePatch
{
static void Postfix(string inFileName)
{
SaveDataManager.Instance.SaveDatas(inFileName);
}
}
[HarmonyPatch(typeof(PLSaveGameIO), "LoadFromFile")]
class LoadPatch
{
static void Postfix(string inFileName)
{
SaveDataManager.Instance.LoadDatas(inFileName);
}
}


[HarmonyPatch(typeof(PLSaveGameIO), "DeleteSaveGame")]
class DeletePatch
{
static void Postfix(PLSaveGameIO __instance)
{
string fileName = SaveDataManager.getPMLSaveFileName(__instance.LatestSaveGameFileName);
if (fileName != "")
{
try
{
Logger.Info("DeleteSaveGame " + fileName);
File.Delete(__instance.LatestSaveGameFileName);
}
catch (Exception ex)
{
Logger.Info("DeleteSaveGame EXCEPTION: " + ex.Message + ": Could not delete save file!");
}
}
}
}

[HarmonyPatch(typeof(PLUILoadMenu), "OnClickDeleteSaveFile")]
class LoadMenuDeletePatch
{
static void Postfix(string inFileName)
{
if (inFileName.EndsWith(".plsave"))
{
string PMLname = SaveDataManager.getPMLSaveFileName(inFileName);
typeof(PLUILoadMenu).GetMethod("OnClickDeleteSaveFile", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(PLUILoadMenu.Instance, new object[] { PMLname });
}
}
}
}

0 comments on commit 6e43f2f

Please sign in to comment.