Fixed Steam multiplayer save and Lan multiplayer save were shared issue
This commit is contained in:
@@ -15,6 +15,7 @@ using MegaCrit.Sts2.Core.Platform;
|
|||||||
using MegaCrit.Sts2.Core.Runs;
|
using MegaCrit.Sts2.Core.Runs;
|
||||||
using MegaCrit.Sts2.Core.Saves;
|
using MegaCrit.Sts2.Core.Saves;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
// ReSharper disable UnusedType.Global
|
// ReSharper disable UnusedType.Global
|
||||||
// ReSharper disable ClassNeverInstantiated.Global
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers
|
|||||||
ushort port, int maxPlayers)
|
ushort port, int maxPlayers)
|
||||||
{
|
{
|
||||||
var readSaveResult =
|
var readSaveResult =
|
||||||
SaveManager.Instance.LoadAndCanonicalizeMultiplayerRunSave(
|
LanRunSaveManagerHelper.LoadAndCanonicalizeMultiplayerRunSave(
|
||||||
PlatformUtil.GetLocalPlayerId(PlatformType.None));
|
PlatformUtil.GetLocalPlayerId(PlatformType.None));
|
||||||
if (!readSaveResult.Success || readSaveResult.SaveData == null)
|
if (!readSaveResult.Success || readSaveResult.SaveData == null)
|
||||||
{
|
{
|
||||||
@@ -176,7 +177,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var readSaveResult =
|
var readSaveResult =
|
||||||
SaveManager.Instance.LoadAndCanonicalizeMultiplayerRunSave(
|
LanRunSaveManagerHelper.LoadAndCanonicalizeMultiplayerRunSave(
|
||||||
PlatformUtil.GetLocalPlayerId(PlatformType.None));
|
PlatformUtil.GetLocalPlayerId(PlatformType.None));
|
||||||
if (readSaveResult is { Success: true, SaveData: not null })
|
if (readSaveResult is { Success: true, SaveData: not null })
|
||||||
{
|
{
|
||||||
@@ -205,7 +206,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers
|
|||||||
$"ERROR: Failed to load multiplayer run save: status={readSaveResult.Status}. Deleting current run...");
|
$"ERROR: Failed to load multiplayer run save: status={readSaveResult.Status}. Deleting current run...");
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveManager.Instance.DeleteCurrentMultiplayerRun();
|
LanRunSaveManagerHelper.DeleteCurrentMultiplayerRun();
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using MegaCrit.Sts2.Core.Logging;
|
||||||
|
using MegaCrit.Sts2.Core.Runs;
|
||||||
|
using MegaCrit.Sts2.Core.Saves;
|
||||||
|
using MegaCrit.Sts2.Core.Saves.Managers;
|
||||||
|
using MegaCrit.Sts2.Core.Saves.Migrations;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
|
||||||
|
namespace SlayTheSpire2.LAN.Multiplayer.Helpers
|
||||||
|
{
|
||||||
|
internal class LanRunSaveManagerHelper
|
||||||
|
{
|
||||||
|
public static ISaveStore SaveStore =>
|
||||||
|
Traverse.Create(SaveManager.Instance).Field("_saveStore").GetValue<ISaveStore>();
|
||||||
|
|
||||||
|
public static MigrationManager MigrationManager => Traverse.Create(SaveManager.Instance)
|
||||||
|
.Field("_migrationManager").GetValue<MigrationManager>();
|
||||||
|
|
||||||
|
public static IProfileIdProvider ProfileIdProvider => SaveManager.Instance;
|
||||||
|
|
||||||
|
public static string CurrentMultiplayerRunSavePath =>
|
||||||
|
RunSaveManager.GetRunSavePath(ProfileIdProvider.CurrentProfileId, "current_lan_run_mp.save");
|
||||||
|
|
||||||
|
public static bool HasMultiplayerRunSave => SaveStore.FileExists(CurrentMultiplayerRunSavePath);
|
||||||
|
|
||||||
|
public static ReadSaveResult<SerializableRun> LoadAndCanonicalizeMultiplayerRunSave(ulong localPlayerId)
|
||||||
|
{
|
||||||
|
var readSaveResult = LoadMultiplayerRunSave();
|
||||||
|
if (readSaveResult is { Success: true, SaveData: not null })
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = RunManager.CanonicalizeSave(readSaveResult.SaveData, localPlayerId);
|
||||||
|
return new ReadSaveResult<SerializableRun>(data, ReadSaveStatus.Success);
|
||||||
|
}
|
||||||
|
catch (Exception value)
|
||||||
|
{
|
||||||
|
Log.Error($"Multiplayer run save validation failed: {value}");
|
||||||
|
RenameBrokenMultiplayerRunSave(ReadSaveStatus.ValidationFailed);
|
||||||
|
return new ReadSaveResult<SerializableRun>(ReadSaveStatus.ValidationFailed,
|
||||||
|
$"Save file validation failed: {value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return readSaveResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadSaveResult<SerializableRun> LoadMultiplayerRunSave()
|
||||||
|
{
|
||||||
|
var readSaveResult = MigrationManager.LoadSave<SerializableRun>(CurrentMultiplayerRunSavePath);
|
||||||
|
if (readSaveResult.Success)
|
||||||
|
{
|
||||||
|
return readSaveResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readSaveResult.Status == ReadSaveStatus.FileNotFound)
|
||||||
|
{
|
||||||
|
Log.Info("Multiplayer run save file not found at " + CurrentMultiplayerRunSavePath);
|
||||||
|
}
|
||||||
|
else if (!readSaveResult.Status.IsRecoverable())
|
||||||
|
{
|
||||||
|
Log.Error(
|
||||||
|
$"Failed to load multiplayer run save: status={readSaveResult.Status} msg={readSaveResult.ErrorMessage}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warn(
|
||||||
|
$"Multiplayer run save had recoverable issues: status={readSaveResult.Status} msg={readSaveResult.ErrorMessage}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return readSaveResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeleteCurrentMultiplayerRun()
|
||||||
|
{
|
||||||
|
SaveStore.DeleteFile(CurrentMultiplayerRunSavePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RenameBrokenMultiplayerRunSave(ReadSaveStatus status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (HasMultiplayerRunSave)
|
||||||
|
{
|
||||||
|
var text = CorruptFileHandler.GenerateCorruptFilePath(CurrentMultiplayerRunSavePath, status);
|
||||||
|
SaveStore.RenameFile(CurrentMultiplayerRunSavePath, text);
|
||||||
|
Log.Error(
|
||||||
|
$"Corrupt multiplayer run save detected: Renamed '{CurrentMultiplayerRunSavePath}' to '{text}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warn("Failed to rename broken multiplayer run save: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers
|
|||||||
|
|
||||||
public readonly SettingsModel SettingsModel;
|
public readonly SettingsModel SettingsModel;
|
||||||
|
|
||||||
private readonly GodotFileIo _modsDir = new($"{UserDataPathProvider.GetAccountScopedBasePath(null)}/mods");
|
private readonly GodotFileIo _modsDir =
|
||||||
|
new(Path.Combine(UserDataPathProvider.GetAccountScopedBasePath(null), "mods"));
|
||||||
|
|
||||||
private SettingsHelper()
|
private SettingsHelper()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using MegaCrit.Sts2.Core.Helpers;
|
|||||||
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
||||||
using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu;
|
using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu;
|
||||||
using MegaCrit.Sts2.Core.Runs;
|
using MegaCrit.Sts2.Core.Runs;
|
||||||
using MegaCrit.Sts2.Core.Saves;
|
|
||||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||||
|
|
||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
@@ -111,17 +110,18 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
{
|
{
|
||||||
if (NMultiplayerSubmenuButtonHelpers.LanHostButton != null)
|
if (NMultiplayerSubmenuButtonHelpers.LanHostButton != null)
|
||||||
{
|
{
|
||||||
NMultiplayerSubmenuButtonHelpers.LanHostButton.Visible = !SaveManager.Instance.HasMultiplayerRunSave;
|
NMultiplayerSubmenuButtonHelpers.LanHostButton.Visible = !LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NMultiplayerSubmenuButtonHelpers.LanLoadButton != null)
|
if (NMultiplayerSubmenuButtonHelpers.LanLoadButton != null)
|
||||||
{
|
{
|
||||||
NMultiplayerSubmenuButtonHelpers.LanLoadButton.Visible = SaveManager.Instance.HasMultiplayerRunSave;
|
NMultiplayerSubmenuButtonHelpers.LanLoadButton.Visible = LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NMultiplayerSubmenuButtonHelpers.LanAbandonButton != null)
|
if (NMultiplayerSubmenuButtonHelpers.LanAbandonButton != null)
|
||||||
{
|
{
|
||||||
NMultiplayerSubmenuButtonHelpers.LanAbandonButton.Visible = SaveManager.Instance.HasMultiplayerRunSave;
|
NMultiplayerSubmenuButtonHelpers.LanAbandonButton.Visible =
|
||||||
|
LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
[HarmonyPatch(typeof(NSettingsScreen), "_Ready")]
|
[HarmonyPatch(typeof(NSettingsScreen), "_Ready")]
|
||||||
internal class NSettingsScreenPatch
|
internal class NSettingsScreenPatch
|
||||||
{
|
{
|
||||||
public static void Prefix(NSettingsScreen __instance)
|
private static void Prefix(NSettingsScreen __instance)
|
||||||
{
|
{
|
||||||
var moddingNode = __instance.GetNode("%Modding");
|
var moddingNode = __instance.GetNode("%Modding");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MegaCrit.Sts2.Core.Helpers;
|
||||||
|
using MegaCrit.Sts2.Core.Multiplayer.Game;
|
||||||
|
using MegaCrit.Sts2.Core.Platform;
|
||||||
|
using MegaCrit.Sts2.Core.Rooms;
|
||||||
|
using MegaCrit.Sts2.Core.Runs;
|
||||||
|
using MegaCrit.Sts2.Core.Saves;
|
||||||
|
using MegaCrit.Sts2.Core.Saves.Managers;
|
||||||
|
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
// ReSharper disable UnusedType.Global
|
||||||
|
|
||||||
|
namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(RunSaveManager), "SaveRun")]
|
||||||
|
internal class RunSaveManagerSaveRunPatch
|
||||||
|
{
|
||||||
|
private static bool Prefix(RunSaveManager __instance, AbstractRoom? preFinishedRoom, bool ____forceSynchronous,
|
||||||
|
ISaveStore ____saveStore, Action? ___Saved, ref Task __result)
|
||||||
|
{
|
||||||
|
if (!RunManager.Instance.ShouldSave || (RunManager.Instance.NetService.Type != NetGameType.Singleplayer &&
|
||||||
|
RunManager.Instance.NetService.Type != NetGameType.Host))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__result = TaskHelper.RunSafely(SaveRun(__instance, preFinishedRoom, ____forceSynchronous, ____saveStore,
|
||||||
|
___Saved));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SaveRun(RunSaveManager runSaveManager, AbstractRoom? preFinishedRoom,
|
||||||
|
bool forceSynchronous,
|
||||||
|
ISaveStore saveStore, Action? saved)
|
||||||
|
{
|
||||||
|
var value = RunManager.Instance.ToSave(preFinishedRoom);
|
||||||
|
var savePath = RunManager.Instance.NetService.Type.IsMultiplayer()
|
||||||
|
? RunManager.Instance.NetService.Platform == PlatformType.None
|
||||||
|
? LanRunSaveManagerHelper.CurrentMultiplayerRunSavePath
|
||||||
|
: Traverse.Create(runSaveManager).Property("CurrentMultiplayerRunSavePath").GetValue<string>()
|
||||||
|
: Traverse.Create(runSaveManager).Property("CurrentRunSavePath").GetValue<string>();
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
if (!forceSynchronous)
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(stream, value,
|
||||||
|
JsonSerializationUtility.GetTypeInfo<SerializableRun>(), CancellationToken.None);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await JsonSerializer.SerializeAsync(stream, value,
|
||||||
|
JsonSerializationUtility.GetTypeInfo<SerializableRun>());
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Seek(0L, SeekOrigin.Begin);
|
||||||
|
await saveStore.WriteFileAsync(savePath, stream.ToArray());
|
||||||
|
|
||||||
|
saved?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<AssemblyVersion>1.1.0.0</AssemblyVersion>
|
||||||
|
<FileVersion>1.1.0.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user