Skip to content

Commit

Permalink
More fixes
Browse files Browse the repository at this point in the history
- Pause before/after saveasync routine
- Added debug stuff
- Use Time.time to respect pauses
- Add settingchanged for relevant configs
- More null checks to be safe
  • Loading branch information
DingoDjango committed Jan 20, 2023
1 parent 09c5825 commit 0b4b607
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 33 deletions.
64 changes: 49 additions & 15 deletions AutosaveController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class AutosaveController : MonoBehaviour

private bool warningTriggered = false;

private float nextSaveTriggerTime = Time.realtimeSinceStartup + 120f;
private float nextSaveTriggerTime = Time.time + 120f;

private UserStorage GlobalUserStorage => PlatformUtils.main.GetUserStorage();

Expand Down Expand Up @@ -185,6 +185,10 @@ private bool IsSafeToSave()

private IEnumerator AutosaveCoroutine()
{
#if DEBUG
ModPlugin.LogMessage($"AutosaveCoroutine() - Beginning at {Time.time}.");
#endif

this.isSaving = true;

bool hardcoreMode = ModPlugin.ConfigHardcoreMode.Value; // Add autosave permadeath option as well? (bisa)
Expand All @@ -201,8 +205,6 @@ private IEnumerator AutosaveCoroutine()
this.DoSaveLoadManagerDateHack();
}

yield return null;

this.SetMainSlotIfAutosave(); // Make sure the main slot is set correctly. It should always be a clean slot name without _auto

string mainSaveSlot = SaveLoadManager.main.GetCurrentSlot();
Expand All @@ -216,21 +218,38 @@ private IEnumerator AutosaveCoroutine()

yield return null;

// Pause during save
IngameMenu.main.Open();
IngameMenu.main.mainPanel.SetActive(false);
FreezeTime.Begin(FreezeTime.Id.None);

#if DEBUG
ModPlugin.LogMessage("AutosaveCoroutine() - Froze time.");
#endif

yield return null;

IEnumerator saveGameAsync = (IEnumerator)typeof(IngameMenu).GetMethod("SaveGameAsync", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(IngameMenu.main, null);

yield return CoroutineHost.StartCoroutine(saveGameAsync);

#if DEBUG
ModPlugin.LogMessage("Post-saveGameAsync reached.");
ModPlugin.LogMessage("AutosaveCoroutine() - saveGameAsync executed.");
#endif

// Unpause
IngameMenu.main.Close();
FreezeTime.End(FreezeTime.Id.None);

#if DEBUG
ModPlugin.LogMessage("AutosaveCoroutine() - Unfroze time.");
#endif

yield return null;

if (!hardcoreMode)
{
SaveLoadManager.main.SetCurrentSlot(mainSaveSlot);

yield return null;
}

if (ModPlugin.ConfigAutosaveOnTimer.Value)
Expand All @@ -240,15 +259,13 @@ private IEnumerator AutosaveCoroutine()
this.ScheduleAutosave(autosaveMinutesInterval);

ErrorMessage.AddWarning("AutosaveEnding".FormatTranslate(autosaveMinutesInterval.ToString()));

yield return null;
}

this.warningTriggered = false;
this.isSaving = false;

#if DEBUG
ModPlugin.LogMessage("Reached post-autosave without crashing");
ModPlugin.LogMessage("AutosaveCoroutine() - End of routine.");
#endif

yield break;
Expand All @@ -258,14 +275,14 @@ private void Tick()
{
if (ModPlugin.ConfigAutosaveOnTimer.Value)
{
if (!this.warningTriggered && Time.realtimeSinceStartup >= this.nextSaveTriggerTime - PriorWarningSeconds)
if (!this.warningTriggered && Time.time >= this.nextSaveTriggerTime - PriorWarningSeconds)
{
ErrorMessage.AddWarning("AutosaveWarning".FormatTranslate(PriorWarningSeconds.ToString()));

this.warningTriggered = true;
}

else if (!this.isSaving && Time.realtimeSinceStartup >= this.nextSaveTriggerTime)
else if (!this.isSaving && Time.time >= this.nextSaveTriggerTime)
{
if (!this.TryExecuteAutosave())
{
Expand Down Expand Up @@ -304,15 +321,32 @@ public void SetMainSlotIfAutosave()
}
}

public void ScheduleAutosave(int addedMinutes)
public void ScheduleAutosave(int addedMinutes, bool settingsChanged = false)
{
// Time.realtimeSinceStartup returns a float in terms of seconds
this.nextSaveTriggerTime = Time.realtimeSinceStartup + (60 * addedMinutes);
#if DEBUG
ModPlugin.LogMessage($"ScheduleAutosave() - settingsChanged == {settingsChanged}");
ModPlugin.LogMessage($"ScheduleAutosave() - previous trigger time == {this.nextSaveTriggerTime}");
#endif

// Time.time returns a float in terms of seconds
this.nextSaveTriggerTime = Time.time + (60 * addedMinutes);

#if DEBUG
ModPlugin.LogMessage($"ScheduleAutosave() - new trigger time == {this.nextSaveTriggerTime}");
#endif
}

public void DelayAutosave(float addedSeconds = 10f)
public void DelayAutosave(float addedSeconds = 5f)
{
#if DEBUG
ModPlugin.LogMessage($"DelayAutosave() - previous trigger time == {this.nextSaveTriggerTime}");
#endif

this.nextSaveTriggerTime += addedSeconds;

#if DEBUG
ModPlugin.LogMessage($"DelayAutosave() - new trigger time == {this.nextSaveTriggerTime}");
#endif
}

public bool TryExecuteAutosave()
Expand Down
Binary file modified BepInEx/plugins/SubnauticaAutosave/SubnauticaAutosave.dll
Binary file not shown.
25 changes: 14 additions & 11 deletions HarmonyPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public static class HarmonyPatches
{
private static bool Patch_ManualSaveGame_Prefix()
{
AutosaveController controller = Player.main.GetComponent<AutosaveController>();
AutosaveController controller = Player.main?.GetComponent<AutosaveController>();

if (controller != null)
{
Expand Down Expand Up @@ -47,18 +47,21 @@ private static void Patch_Bed_OnHandClick_Postfix()
{
if (ModPlugin.ConfigAutosaveOnSleep.Value)
{
#if DEBUG
ModPlugin.LogMessage("Player clicked on bed. Executing save on sleep.");
#endif

Player player = Player.main;

/* [Bed.cs] private float kSleepInterval = 600f, added to timeLastSleep when sleep screen ends
* If player did indeed sleep recently, we can trigger a save after the bed click
* Could instead transpile into OnHandClick if(isValidHandTarget), but no reason to complicate things... */
if (player.timeLastSleep + 200f > DayNightCycle.main.timePassedAsFloat)
if (player != null)
{
player.GetComponent<AutosaveController>()?.TryExecuteAutosave(); // Might want to test a scheduled save instead
/* [Bed.cs] private float kSleepInterval = 600f, added to timeLastSleep when sleep screen ends
* If player did indeed sleep recently, we can trigger a save after the bed click
* Could instead transpile into OnHandClick if(isValidHandTarget), but no reason to complicate things... */
if (player.timeLastSleep + 200f > DayNightCycle.main.timePassedAsFloat)
{
#if DEBUG
ModPlugin.LogMessage("Player clicked on bed. Executing save on sleep.");
#endif

player.GetComponent<AutosaveController>()?.TryExecuteAutosave(); // Might want to test a scheduled save instead
}
}
}
}
Expand All @@ -69,7 +72,7 @@ private static void Patch_Subroot_PlayerEnteredOrExited_Postfix()
ModPlugin.LogMessage("Player entered or exited sub. Delaying autosave.");
#endif

Player.main.GetComponent<AutosaveController>()?.DelayAutosave();
Player.main?.GetComponent<AutosaveController>()?.DelayAutosave();
}

private static void Patch_SetCurrentLanguage_Postfix()
Expand Down
25 changes: 20 additions & 5 deletions ModPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class ModPlugin : BaseUnityPlugin
{
private const string modGUID = "Dingo.SN.SubnauticaAutosave";
internal const string modName = "Subnautica Autosave";
private const string modVersion = "2.0.2";
private const string modVersion = "2.0.3";

private const int MaxMinutesBetweenSaves = 9999;
private const int MaxSaveFiles = 9999;
Expand All @@ -29,6 +29,18 @@ public class ModPlugin : BaseUnityPlugin
public static ConfigEntry<KeyboardShortcut> ConfigQuicksaveKey;
public static ConfigEntry<bool> ConfigComprehensiveSaves;

private void RescheduleOnSettingChanged()
{
if (ConfigAutosaveOnTimer.Value)
{
#if DEBUG
LogMessage("RescheduleOnSettingChanged() - trying to reschedule next save.");
#endif

Player.main?.GetComponent<AutosaveController>()?.ScheduleAutosave(ConfigMinutesBetweenAutosaves.Value, true);
}
}

private void InitializeConfig()
{
/*** TODO: TEST
Expand All @@ -43,12 +55,10 @@ private void InitializeConfig()

ConfigAutosaveOnTimer.SettingChanged += delegate
{
if (ConfigAutosaveOnTimer.Value)
{
Player.main.GetComponent<AutosaveController>()?.ScheduleAutosave(ConfigMinutesBetweenAutosaves.Value);
}
RescheduleOnSettingChanged();
};


ConfigAutosaveOnSleep = Config.Bind(
configDefinition: new ConfigDefinition(section: "Autosave Conditions",
key: "Autosave On Sleep"),
Expand All @@ -62,6 +72,11 @@ private void InitializeConfig()
configDescription: new ConfigDescription(description: "Time to wait between autosaves.\nMust be at least 1.",
acceptableValues: new AcceptableValueRange<int>(1, MaxMinutesBetweenSaves)));

ConfigMinutesBetweenAutosaves.SettingChanged += delegate
{
RescheduleOnSettingChanged();
};

ConfigMinimumPlayerHealthPercent = Config.Bind(
configDefinition: new ConfigDefinition(section: "Autosave Conditions",
key: "Minimum Player Health Percent"),
Expand Down
4 changes: 2 additions & 2 deletions Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// 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("2.0.2.0")]
[assembly: AssemblyFileVersion("2.0.2.0")]
[assembly: AssemblyVersion("2.0.3.0")]
[assembly: AssemblyFileVersion("2.0.3.0")]

0 comments on commit 0b4b607

Please sign in to comment.