Skip to content

Commit

Permalink
Merge pull request #35 from katycat5e/save_improvements
Browse files Browse the repository at this point in the history
Move save data back into main file under custom key
  • Loading branch information
katycat5e authored Aug 25, 2021
2 parents b788893 + d75181c commit 92f59ea
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 112 deletions.
5 changes: 2 additions & 3 deletions PJModSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class PJModSettings : UnityModManager.ModSettings, IDrawable
[Draw("Special/named train generation probability", Min = 0, Max = 1)]
public float NamedTrainProbability = 0.7f;

[Draw("Perform data purge for uninstall (see log for results)")]
[Draw("Perform data purge (see log for results) - leave enabled on exit to clean save")]
public bool DoPurge = false;

public override void Save( UnityModManager.ModEntry modEntry )
Expand All @@ -27,9 +27,8 @@ public override void Save( UnityModManager.ModEntry modEntry )

public void OnChange()
{
if( DoPurge )
if( PassengerJobs.Enabled && DoPurge )
{
DoPurge = false;
PurgeData();
}
}
Expand Down
177 changes: 68 additions & 109 deletions PJSaveLoadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public static class PJSaveLoadManager

public static string SaveDirectory => Path.Combine(PassengerJobs.ModEntry.Path, SAVE_FOLDER);
public static string SaveFilePath => Path.Combine(PassengerJobs.ModEntry.Path, SAVE_FOLDER, SAVE_FILE_NAME);


private const string PJ_DATA_KEY = "passengers_mod";
private const string HAS_LICENSE_P1_KEY = "pass1_obtained";
private const string VERSION_KEY = "version";

Expand All @@ -31,7 +32,7 @@ private static IEnumerable<StationProceduralJobsController> ProceduralJobsContro
get => StationController.allStations.Select(sc => sc.ProceduralJobsController);
}

public static void Save()
public static void InjectDataIntoSaveGame( SaveGameData mainGameData )
{
var pjSaveData = new JObject();

Expand All @@ -51,58 +52,64 @@ public static void Save()

pjSaveData.SetInt(VERSION_KEY, CURRENT_DATA_VERSION);

try
{
if( !Directory.Exists(SaveDirectory) ) Directory.CreateDirectory(SaveDirectory);

using( var outFile = File.CreateText(SaveFilePath) )
{
using( var jtw = new JsonTextWriter(outFile) )
{
jtw.Formatting = Formatting.Indented;
pjSaveData.WriteTo(jtw);
}
}
}
catch( Exception ex )
{
PassengerJobs.Error("Couldn't open/create save file:\n" + ex.Message);
return;
}
// add to base game data
mainGameData.SetJObject(PJ_DATA_KEY, pjSaveData);
}

private static bool IsPassengerChain( JobChainController jobChain )
{
return (jobChain is PassengerTransportChainController) || (jobChain is CommuterChainController);
}

public static void Load( JobsSaveGameData mainJobData )
private static JObject MigrateV3Data()
{
if( File.Exists(SaveFilePath) )
{
// load data off disk
PassengerJobs.Log("Found save data file, attempting to load...");
JObject data;

try
{
using( var saveFile = File.OpenText(SaveFilePath) )
{
using( var jtr = new JsonTextReader(saveFile) )
{
loadedData = JToken.ReadFrom(jtr) as JObject;
if( loadedData == null )
data = JToken.ReadFrom(jtr) as JObject;
if( data == null )
{
PassengerJobs.Error("Save file contained invalid JSON");
}
}
}

File.Delete(SaveFilePath);
return data;
}
catch( Exception ex )
{
PassengerJobs.Error("Couldn't read save file:\n" + ex.Message);
return;
PassengerJobs.Warning("Couldn't read save v3 file:\n" + ex.Message);
return null;
}
}

return null;
}

public static void OnSaveGameLoaded()
{
loadedData = SaveGameManager.data.GetJObject(PJ_DATA_KEY);
if( loadedData == null )
{
loadedData = MigrateV3Data();
if( loadedData != null ) PassengerJobs.Log("Migrated data from v3 save");
}
else
{
PurgeV3Save();
PassengerJobs.Log("Found injected save data, attempting to load...");
}

if( loadedData != null )
{
if( loadedData.GetInt(VERSION_KEY) == CURRENT_DATA_VERSION )
{
if( loadedData.GetBool(HAS_LICENSE_P1_KEY) == true )
Expand All @@ -112,16 +119,6 @@ public static void Load( JobsSaveGameData mainJobData )

Inventory.Instance.RemoveMoney(PassengerLicenseUtil.PASS1_COST);
}

// inject job chains into main game data
if( loadedData.GetObjectViaJSON<JobsSaveGameData>(SaveGameKeys.Jobs, JobSaveManager.serializeSettings) is JobsSaveGameData jobData )
{
JobChainSaveData[] combinedChains = mainJobData.jobChains
.Concat(jobData.jobChains)
.ToArray();

mainJobData.jobChains = combinedChains;
}
}
else
{
Expand All @@ -131,68 +128,33 @@ public static void Load( JobsSaveGameData mainJobData )
}
else
{
// no save file exists
PassengerJobs.Log("No save file found, skipping load");
}
}

public static void CreateSaveBackup()
{
string dateString = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
string backupFileName = string.Format(SAVE_BACKUP_FORMAT, dateString);
string backupPath = Path.Combine(SaveDirectory, backupFileName);

if( !File.Exists(SaveFilePath) || File.Exists(backupPath) )
{
PassengerJobs.Log("Skipping save backup, no existing save or backup already exists");
return;
}

try
{
File.Copy(SaveFilePath, backupPath);
}
catch( Exception ex )
{
PassengerJobs.Error("Failed to create save file backup:\n" + ex.Message);
return;
PassengerJobs.Log("No save data found");
}

PassengerJobs.Log("Successfully backed up save data");
DeleteOldBackups();
}

public static void DeleteOldBackups()
public static void InjectJobChains( JobsSaveGameData mainJobData )
{
string saveDir = SaveDirectory;

var oldBackups = Directory.EnumerateFiles(saveDir)
.Where(name => name.StartsWith(SAVE_BACKUP_PREFIX))
.Select(name => new FileInfo(Path.Combine(saveDir, name)))
.OrderByDescending(file => file.CreationTime)
.Skip(5);

int deletedCount = 0;
foreach( FileInfo file in oldBackups )
// inject job chains into main game data
if( loadedData?.GetObjectViaJSON<JobsSaveGameData>(SaveGameKeys.Jobs, JobSaveManager.serializeSettings) is JobsSaveGameData jobData )
{
file.Delete();
deletedCount++;
}
JobChainSaveData[] combinedChains = mainJobData.jobChains
.Concat(jobData.jobChains)
.ToArray();

if( deletedCount > 0 )
{
PassengerJobs.Log($"Deleted {deletedCount} old passenger saves");
mainJobData.jobChains = combinedChains;
}
}

public static void PurgeSaveData()
public static void PurgeV3Save()
{
// we'll keep the backups just in case
if( File.Exists(SaveFilePath) )
{
try
{
File.Copy(SaveFilePath, SaveFilePath + ".bak");
File.Delete(SaveFilePath);
PassengerJobs.Log("Deleted v3 save file");
}
catch( Exception ex )
{
Expand All @@ -202,43 +164,40 @@ public static void PurgeSaveData()
}
}

[HarmonyPatch(typeof(SaveGameManager), nameof(SaveGameManager.Save))]
static class SaveGameManager_Save_Patch
[HarmonyPatch(typeof(SaveGameManager))]
static class SaveGameManager_Patches
{
static void Postfix()
{
PJSaveLoadManager.Save();
}
}

[HarmonyPatch(typeof(SaveGameManager), "DoSaveIO")]
static class SaveGameManager_DoSaveIO_Patch
{
static void Prefix( SaveGameData data )
[HarmonyPatch("DoSaveIO")]
[HarmonyPrefix]
static void InjectPassengerSaveData( SaveGameData data )
{
// refund license in case mod is uninstalled
if( LicenseManager.IsJobLicenseAcquired(PassLicenses.Passengers1) )
if( !PassengerJobs.Settings.DoPurge )
{
float? money = data.GetFloat(SaveGameKeys.Player_money);
if( money.HasValue )
PJSaveLoadManager.InjectDataIntoSaveGame(data);

// refund license in case mod is uninstalled
if( LicenseManager.IsJobLicenseAcquired(PassLicenses.Passengers1) )
{
float newBalance = money.Value + PassengerLicenseUtil.PASS1_COST;
data.SetFloat(SaveGameKeys.Player_money, newBalance);
float? money = data.GetFloat(SaveGameKeys.Player_money);
if( money.HasValue )
{
float newBalance = money.Value + PassengerLicenseUtil.PASS1_COST;
data.SetFloat(SaveGameKeys.Player_money, newBalance);
}
}
}
}
}

[HarmonyPatch(typeof(SaveGameManager), "MakeBackupFile")]
static class SaveGameManager_MakeBackup_Patch
{
static void Postfix()
[HarmonyPatch("DoLoadIO")]
[HarmonyPostfix]
static void OnSaveLoaded( bool __result )
{
PJSaveLoadManager.CreateSaveBackup();
if( !__result ) return;

PJSaveLoadManager.OnSaveGameLoaded();
}
}

// Prevent regular saving of passenger job chains
[HarmonyPatch(typeof(JobChainController), nameof(JobChainController.GetJobChainSaveData))]
static class JCC_GetJobChainSaveData_Patch
{
Expand Down Expand Up @@ -277,7 +236,7 @@ static void FilterPassengerJobChains( ref JobsSaveGameData __result )
[HarmonyPrefix]
static void LoadPassengerChains( JobsSaveGameData saveData )
{
PJSaveLoadManager.Load(saveData);
PJSaveLoadManager.InjectJobChains(saveData);
}
}
}
10 changes: 10 additions & 0 deletions PassengerJobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ public static class PassengerJobs
{
public static UnityModManager.ModEntry ModEntry;
public static PJModSettings Settings { get; private set; }
public static bool Enabled { get; private set; } = false;

internal static UnityModManager.ModEntry SlicedCarsModEntry;

public static bool SmallerCoachesEnabled
{
get => (SlicedCarsModEntry != null) && SlicedCarsModEntry.Active;
}

#region Enable/Disable

public static bool Load( UnityModManager.ModEntry modEntry )
{
ModEntry = modEntry;
Expand Down Expand Up @@ -55,6 +59,8 @@ public static bool Load( UnityModManager.ModEntry modEntry )

// Initialize settings
Settings = UnityModManager.ModSettings.Load<PJModSettings>(ModEntry);
Settings.DoPurge = false;

ModEntry.OnGUI = DrawGUI;
ModEntry.OnSaveGUI = SaveGUI;

Expand All @@ -75,9 +81,13 @@ public static bool Load( UnityModManager.ModEntry modEntry )
var harmony = new Harmony("com.foxden.passenger_jobs");
harmony.PatchAll(Assembly.GetExecutingAssembly());

Enabled = true;

return true;
}

#endregion

#region Settings

static void DrawGUI( UnityModManager.ModEntry entry )
Expand Down

0 comments on commit 92f59ea

Please sign in to comment.