1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-08 20:53:28 +08:00

cleanup codes

This commit is contained in:
2023-09-26 16:08:52 +08:00
parent 18fca87813
commit 6311e3b9fb
4 changed files with 239 additions and 259 deletions

View File

@@ -19,31 +19,31 @@ public enum CompressionType
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
public class CompressSave : BaseUnityPlugin
{
private Harmony patchSave, patchUISave, patchUILoad;
string StringFromCompresstionType(CompressionType type)
private Harmony _patchSave, _patchUISave, _patchUILoad;
private static string StringFromCompresstionType(CompressionType type)
{
switch (type)
return type switch
{
case CompressionType.LZ4: return "lz4";
case CompressionType.Zstd: return "zstd";
case CompressionType.None: return "none";
default: throw new ArgumentException("Unknown compression type.");
}
CompressionType.LZ4 => "lz4",
CompressionType.Zstd => "zstd",
CompressionType.None => "none",
_ => throw new ArgumentException("Unknown compression type.")
};
}
CompressionType CompressionTypeFromString(string str)
private static CompressionType CompressionTypeFromString(string str)
{
switch (str)
return str switch
{
case "lz4": return CompressionType.LZ4;
case "zstd": return CompressionType.Zstd;
default: return CompressionType.None;
}
"lz4" => CompressionType.LZ4,
"zstd" => CompressionType.Zstd,
_ => CompressionType.None
};
}
public void Awake()
{
SaveUtil.logger = Logger;
SaveUtil.Logger = Logger;
if (LZ4API.Avaliable && ZstdAPI.Avaliable)
{
PatchSave.CompressionTypeForSaves = CompressionTypeFromString(
@@ -68,36 +68,36 @@ public class CompressSave : BaseUnityPlugin
PatchSave.CreateCompressBuffer();
if (GameConfig.gameVersion != SaveUtil.VerifiedVersion)
{
SaveUtil.logger.LogWarning(
SaveUtil.Logger.LogWarning(
$"Save version mismatch. Expect:{SaveUtil.VerifiedVersion}, Current:{GameConfig.gameVersion}. MOD may not work as expected.");
}
patchSave = Harmony.CreateAndPatchAll(typeof(PatchSave));
_patchSave = Harmony.CreateAndPatchAll(typeof(PatchSave));
if (PatchSave.EnableCompress)
patchUISave = Harmony.CreateAndPatchAll(typeof(PatchUISaveGame));
patchUILoad = Harmony.CreateAndPatchAll(typeof(PatchUILoadGame));
_patchUISave = Harmony.CreateAndPatchAll(typeof(PatchUISaveGame));
_patchUILoad = Harmony.CreateAndPatchAll(typeof(PatchUILoadGame));
}
else
SaveUtil.logger.LogWarning("Either lz4warp.dll or zstdwrap.dll is not avaliable.");
SaveUtil.Logger.LogWarning("Either lz4warp.dll or zstdwrap.dll is not avaliable.");
}
public void OnDestroy()
{
if (patchUISave != null)
if (_patchUISave != null)
{
PatchUISaveGame.OnDestroy();
patchUISave.UnpatchSelf();
_patchUISave.UnpatchSelf();
}
if (patchUILoad != null)
if (_patchUILoad != null)
{
PatchUILoadGame.OnDestroy();
patchUILoad.UnpatchSelf();
_patchUILoad.UnpatchSelf();
}
patchSave?.UnpatchSelf();
_patchSave?.UnpatchSelf();
}
}
class PatchSave
public class PatchSave
{
public static readonly WrapperDefines LZ4Wrapper = new LZ4API(), ZstdWrapper = new ZstdAPI();
private static readonly WrapperDefines NoneWrapper = new NoneAPI();
@@ -105,7 +105,7 @@ class PatchSave
public static bool UseCompressSave;
private static CompressionType _compressionTypeForLoading = CompressionType.None;
private static CompressionType _compressionTypeForSaving = CompressionType.Zstd;
private static int _compressionLevelForSaving = 0;
private static int _compressionLevelForSaving;
public static CompressionType CompressionTypeForSaves = CompressionType.Zstd;
public static CompressionType CompressionTypeForAutoSaves = CompressionType.Zstd;
public static int CompressionLevelForSaves;
@@ -116,7 +116,7 @@ class PatchSave
public static void CreateCompressBuffer()
{
var bufSize = CompressionStream.MB;
const int bufSize = CompressionStream.MB;
var outBufSize = LZ4Wrapper.CompressBufferBound(bufSize);
outBufSize = Math.Max(outBufSize, ZstdWrapper.CompressBufferBound(bufSize));
outBufSize = Math.Max(outBufSize, NoneWrapper.CompressBufferBound(bufSize));
@@ -127,6 +127,7 @@ class PatchSave
private static void WriteHeader(FileStream fileStream)
{
if (fileStream == null) throw new ArgumentNullException(nameof(fileStream));
switch (_compressionTypeForSaving)
{
case CompressionType.Zstd:
@@ -148,59 +149,57 @@ class PatchSave
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "AutoSave")]
[HarmonyPatch(typeof(GameSave), "SaveAsLastExit")]
static void BeforeAutoSave()
private static void BeforeAutoSave()
{
UseCompressSave = EnableForAutoSaves && EnableCompress;
if (UseCompressSave)
{
_compressionTypeForSaving = CompressionTypeForAutoSaves;
_compressionLevelForSaving = CompressionLevelForAutoSaves;
}
if (!UseCompressSave) return;
_compressionTypeForSaving = CompressionTypeForAutoSaves;
_compressionLevelForSaving = CompressionLevelForAutoSaves;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
static IEnumerable<CodeInstruction> SaveCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions,
ILGenerator generator)
private static IEnumerable<CodeInstruction> SaveCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
/* BinaryWriter binaryWriter = new BinaryWriter(fileStream); => Create compressionStream and replace binaryWriter.
* set PerformanceMonitor.BeginStream to compressionStream.
* fileStream.Seek(6L, SeekOrigin.Begin); binaryWriter.Write(position); => Disable seek&write function.
* binaryWriter.Dispose(); => Dispose compressionStream before fileStream close.
*/
var matcher = new CodeMatcher(instructions, generator);
try
{
var matcher = new CodeMatcher(instructions, generator)
.MatchForward(false,
new CodeMatch(OpCodes.Newobj,
AccessTools.Constructor(typeof(BinaryWriter), new Type[] { typeof(FileStream) })))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "CreateBinaryWriter"))
.MatchForward(false,
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), "BeginStream")))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "MonitorStream"))
.MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IO.Stream), "Seek")))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite0"))
.MatchForward(false,
new CodeMatch(OpCodes.Callvirt,
AccessTools.Method(typeof(BinaryWriter), "Write", new Type[] { typeof(long) })))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite1"))
.MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IDisposable), "Dispose")))
.Advance(1)
.Insert(new CodeInstruction(OpCodes.Call,
AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream")));
matcher.MatchForward(false,
new CodeMatch(OpCodes.Newobj, AccessTools.Constructor(typeof(BinaryWriter), new [] { typeof(FileStream) }))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "CreateBinaryWriter")
).MatchForward(false,
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), "BeginStream"))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "MonitorStream")
).MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Stream), "Seek"))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite0")
).MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BinaryWriter), "Write", new [] { typeof(long) }))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthWrite1")
).MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(IDisposable), "Dispose"))
).Advance(1).Insert(
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream"))
);
EnableCompress = true;
return matcher.InstructionEnumeration();
}
catch (Exception ex)
{
SaveUtil.logger.LogError(
SaveUtil.Logger.LogError(
"SaveCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.logger.LogError(ex);
SaveUtil.Logger.LogError(ex);
}
return instructions;
return matcher.InstructionEnumeration();
}
public static void MonitorStream(Stream fileStream)
@@ -212,43 +211,32 @@ class PatchSave
{
if (UseCompressSave)
{
SaveUtil.logger.LogDebug("Begin compress save");
SaveUtil.Logger.LogDebug("Begin compress save");
WriteHeader(fileStream);
switch (_compressionTypeForSaving)
_compressionStream = _compressionTypeForSaving switch
{
case CompressionType.LZ4:
_compressionStream = new CompressionStream(LZ4Wrapper, _compressionLevelForSaving, fileStream, _compressBuffer, true);
break;
case CompressionType.Zstd:
_compressionStream = new CompressionStream(ZstdWrapper, _compressionLevelForSaving, fileStream, _compressBuffer, true);
break;
case CompressionType.None:
_compressionStream = new CompressionStream(NoneWrapper, 0, fileStream, _compressBuffer, true);
break;
}
CompressionType.LZ4 => new CompressionStream(LZ4Wrapper, _compressionLevelForSaving, fileStream, _compressBuffer, true),
CompressionType.Zstd => new CompressionStream(ZstdWrapper, _compressionLevelForSaving, fileStream, _compressBuffer, true),
CompressionType.None => new CompressionStream(NoneWrapper, 0, fileStream, _compressBuffer, true),
_ => _compressionStream
};
return ((CompressionStream)_compressionStream).BufferWriter;
}
SaveUtil.logger.LogDebug("Begin normal save");
SaveUtil.Logger.LogDebug("Begin normal save");
return new BinaryWriter(fileStream);
}
public static long FileLengthWrite0(FileStream fileStream, long offset, SeekOrigin origin)
{
if (!UseCompressSave)
{
return fileStream.Seek(offset, origin);
}
return 0L;
return UseCompressSave ? 0L : fileStream.Seek(offset, origin);
}
public static void FileLengthWrite1(BinaryWriter binaryWriter, long value)
{
if (!UseCompressSave)
{
binaryWriter.Write(value);
}
if (UseCompressSave) return;
binaryWriter.Write(value);
}
public static void DisposeCompressionStream()
@@ -265,23 +253,23 @@ class PatchSave
{
stream = ((CompressionStream)_compressionStream).outStream;
}
_compressionStream.Dispose(); //Dispose need to be done before fstream closed.
// Dispose need to be done before fstream closed.
_compressionStream.Dispose();
_compressionStream = null;
if (writeflag) //Reset UseCompressSave after writing to file
if (!writeflag) return;
// Reset UseCompressSave after writing to file
if (stream != null)
{
if (stream != null)
{
// Ugly implementation, but it works. May find a better solution someday.
var saveLen = stream.Seek(0L, SeekOrigin.End);
stream.Seek(6L, SeekOrigin.Begin);
var writer = new BinaryWriter(stream);
writer.Write(saveLen);
writer.Dispose();
}
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
UseCompressSave = false;
// Ugly implementation, but it works. May find a better solution someday.
var saveLen = stream.Seek(0L, SeekOrigin.End);
stream.Seek(6L, SeekOrigin.Begin);
var writer = new BinaryWriter(stream);
writer.Write(saveLen);
writer.Dispose();
}
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
UseCompressSave = false;
}
[HarmonyTranspiler]
@@ -290,8 +278,7 @@ class PatchSave
[HarmonyPatch(typeof(GameSave), "ReadHeader")]
[HarmonyPatch(typeof(GameSave), "ReadHeaderAndDescAndProperty")]
[HarmonyPatch(typeof(GameSave), "ReadModes")]
static IEnumerable<CodeInstruction> LoadCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions,
ILGenerator iLGenerator)
private static IEnumerable<CodeInstruction> LoadCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
/* using (BinaryReader binaryReader = new BinaryReader(fileStream)) => Create decompressionStream and replace binaryReader.
* set PerformanceMonitor.BeginStream to decompressionStream.
@@ -299,29 +286,31 @@ class PatchSave
* fileStream.Seek((long)num2, SeekOrigin.Current); => Use decompressionStream.Read to seek forward
* binaryReader.Dispose(); => Dispose decompressionStream before fileStream close.
*/
var matcher = new CodeMatcher(instructions, generator);
try
{
var matcher = new CodeMatcher(instructions, iLGenerator)
.MatchForward(false,
new CodeMatch(OpCodes.Newobj,
AccessTools.Constructor(typeof(BinaryReader), new Type[] { typeof(FileStream) })))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "CreateBinaryReader"))
.MatchForward(false,
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), "BeginStream")));
matcher.MatchForward(false,
new CodeMatch(OpCodes.Newobj, AccessTools.Constructor(typeof(BinaryReader), new [] { typeof(FileStream) }))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "CreateBinaryReader")
).MatchForward(false,
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), "BeginStream"))
);
if (matcher.IsValid)
matcher.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "MonitorStream"));
matcher.Start().MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BinaryReader), "ReadInt64")))
.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthRead"))
.MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IDisposable), "Dispose")))
.Advance(1)
.Insert(new CodeInstruction(OpCodes.Call,
AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream")))
.MatchBack(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IO.Stream), "Seek")));
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(BinaryReader), "ReadInt64"))
).Set(
OpCodes.Call, AccessTools.Method(typeof(PatchSave), "FileLengthRead")
).MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(IDisposable), "Dispose"))
).Advance(1).Insert(
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream"))
).MatchBack(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Stream), "Seek"))
);
if (matcher.IsValid)
matcher.Set(OpCodes.Call, AccessTools.Method(typeof(PatchSave), "ReadSeek"));
@@ -329,12 +318,12 @@ class PatchSave
}
catch (Exception ex)
{
SaveUtil.logger.LogError(
SaveUtil.Logger.LogError(
"LoadCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.logger.LogError(ex);
SaveUtil.Logger.LogError(ex);
}
return instructions;
return matcher.InstructionEnumeration();
}
public static BinaryReader CreateBinaryReader(FileStream fileStream)

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using UnityEngine;
@@ -8,69 +7,65 @@ namespace CompressSave;
class PatchUILoadGame
{
static UIButton decompressButton;
static UIButton _decompressButton;
[HarmonyPatch(typeof(UILoadGameWindow), "OnSelectedChange"), HarmonyPostfix]
static void OnSelectedChange(UILoadGameWindow __instance, Text ___prop3Text)
private static void OnSelectedChange(UILoadGameWindow __instance)
{
var compressedType = SaveUtil.SaveGetCompressType(__instance.selected?.saveName);
switch (compressedType)
var selected = __instance.selected;
var compressedType = SaveUtil.SaveGetCompressType(selected == null ? null : selected.saveName);
var prop3Text = __instance.prop3Text;
prop3Text.text = compressedType switch
{
case CompressionType.LZ4:
___prop3Text.text = "(LZ4)" + ___prop3Text.text;
break;
case CompressionType.Zstd:
___prop3Text.text = "(ZSTD)" + ___prop3Text.text;
break;
default:
___prop3Text.text = "(N)" + ___prop3Text.text;
break;
}
if (!decompressButton) return;
decompressButton.button.interactable = compressedType != CompressionType.None;
decompressButton.gameObject.SetActive(compressedType != CompressionType.None);
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text
};
if (!_decompressButton) return;
_decompressButton.button.interactable = compressedType != CompressionType.None;
_decompressButton.gameObject.SetActive(compressedType != CompressionType.None);
}
[HarmonyPatch(typeof(UILoadGameWindow), "_OnOpen"), HarmonyPostfix]
static void _OnOpen(UILoadGameWindow __instance, UIButton ___loadButton, GameObject ___loadSandboxGroup, List<UIGameSaveEntry> ___entries)
static void _OnOpen(UILoadGameWindow __instance)
{
if (!decompressButton)
if (_decompressButton) return;
var loadButton = __instance.loadButton;
var gameObj = __instance.transform.Find("button-decompress")?.gameObject;
if (gameObj == null)
gameObj = Object.Instantiate(loadButton.gameObject, loadButton.transform.parent);
_decompressButton = gameObj.GetComponent<UIButton>();
__instance.loadSandboxGroup.transform.Translate(new Vector3(-2.5f, 0, 0));
_decompressButton.gameObject.name = "button-decompress";
_decompressButton.transform.Translate(new Vector3(-2.0f, 0, 0));
_decompressButton.button.image.color = new Color32(0, 0xf4, 0x92, 0x77);
var localizer = _decompressButton.transform.Find("button-text")?.GetComponent<Localizer>();
var text = _decompressButton.transform.Find("button-text")?.GetComponent<Text>();
if (localizer)
{
decompressButton = ___loadButton;
decompressButton = (__instance.transform.Find("button-decompress")?.gameObject ?? GameObject.Instantiate(___loadButton.gameObject, ___loadButton.transform.parent)).GetComponent<UIButton>();
___loadSandboxGroup.transform.Translate(new Vector3(-2.5f, 0, 0));
decompressButton.gameObject.name = "button-decompress";
decompressButton.transform.Translate(new Vector3(-2.0f, 0, 0));
decompressButton.button.image.color = new Color32(0, 0xf4, 0x92, 0x77);
var localizer = decompressButton.transform.Find("button-text")?.GetComponent<Localizer>();
var text = decompressButton.transform.Find("button-text")?.GetComponent<Text>();
if (localizer)
{
localizer.stringKey = "Decompress";
localizer.translation = "Decompress".Translate();
}
if (text)
text.text = "Decompress".Translate();
decompressButton.onClick += _ =>{
if(SaveUtil.DecompressSave(__instance.selected.saveName, out var newfileName))
{
__instance.RefreshList();
__instance.selected = ___entries.First(e => e.saveName == newfileName);
}
};
decompressButton.button.interactable = false;
decompressButton.gameObject.SetActive(false);
localizer.stringKey = "Decompress";
localizer.translation = "Decompress".Translate();
}
if (text)
text.text = "Decompress".Translate();
_decompressButton.onClick += _ =>
{
if (!SaveUtil.DecompressSave(__instance.selected.saveName, out var newfileName)) return;
__instance.RefreshList();
__instance.selected = __instance.entries.First(e => e.saveName == newfileName);
};
_decompressButton.button.interactable = false;
_decompressButton.gameObject.SetActive(false);
}
public static void OnDestroy()
{
if (decompressButton)
GameObject.Destroy(decompressButton.gameObject);
decompressButton = null;
if (_decompressButton)
Object.Destroy(_decompressButton.gameObject);
_decompressButton = null;
}
}

View File

@@ -6,104 +6,100 @@ namespace CompressSave;
static class PatchUISaveGame
{
[HarmonyPatch(typeof(UISaveGameWindow), "OnSelectedChange"), HarmonyPostfix]
static void OnSelectedChange(UISaveGameWindow __instance, Text ___prop3Text)
public static void OnDestroy()
{
var compressedType = SaveUtil.SaveGetCompressType(__instance.selected?.saveName);
switch (compressedType)
if (_context.ButtonCompress)
Object.Destroy(_context.ButtonCompress.gameObject);
if (_context.Window)
{
case CompressionType.LZ4:
___prop3Text.text = "(LZ4)" + ___prop3Text.text;
break;
case CompressionType.Zstd:
___prop3Text.text = "(ZSTD)" + ___prop3Text.text;
break;
default:
___prop3Text.text = "(N)" + ___prop3Text.text;
break;
_context.SaveButton.onClick -= WrapClick;
_context.SaveButton.onClick += _context.Window.OnSaveClick;
}
_OnDestroy();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSelectedChange"), HarmonyPostfix]
static void OnSelectedChange(UISaveGameWindow __instance)
{
var selected = __instance.selected;
var compressedType = SaveUtil.SaveGetCompressType(selected == null ? null : selected.saveName);
var prop3Text = __instance.prop3Text;
prop3Text.text = compressedType switch
{
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text
};
}
[HarmonyPatch(typeof(UISaveGameWindow), "_OnDestroy"), HarmonyPostfix]
static void _OnDestroy()
private static void _OnDestroy()
{
//Console.WriteLine("OnCreate");
context = new UIContext();
_context = new UIContext();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick"), HarmonyReversePatch]
static void OSaveGameAs(this UISaveGameWindow ui, int data) { }
private static void OSaveGameAs(this UISaveGameWindow ui, int data) { }
[HarmonyPatch(typeof(UISaveGameWindow), "CheckAndSetSaveButtonEnable"), HarmonyPostfix]
static void CheckAndSetSaveButtonEnable(UISaveGameWindow __instance, UIButton ___saveButton, Text ___saveButtonText)
private static void CheckAndSetSaveButtonEnable(UISaveGameWindow __instance)
{
_OnOpen(__instance, ___saveButton, ___saveButtonText);
if (context.saveButtonText && context.saveButton)
SetButtonState(context.saveButtonText.text, context.saveButton.button.interactable);
_OnOpen(__instance);
if (_context.SaveButtonText && _context.SaveButton)
SetButtonState(_context.SaveButtonText.text, _context.SaveButton.button.interactable);
}
static void SetButtonState(string text, bool interactable)
private static void SetButtonState(string text, bool interactable)
{
context.buttonCompress.button.interactable = interactable;
context.buttonCompressText.text = text;
_context.ButtonCompress.button.interactable = interactable;
_context.ButtonCompressText.text = text;
}
class UIContext
private class UIContext
{
public UIButton buttonCompress;
public UIButton saveButton;
public Text buttonCompressText;
public Text saveButtonText;
public UISaveGameWindow ui;
public UIButton ButtonCompress;
public UIButton SaveButton;
public Text ButtonCompressText;
public Text SaveButtonText;
public UISaveGameWindow Window;
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick"), HarmonyPrefix]
static void OnSaveClick()
private static void OnSaveClick()
{
PatchSave.UseCompressSave = true;
}
static UIContext context = new UIContext();
private static UIContext _context = new UIContext();
[HarmonyPatch(typeof(UISaveGameWindow), "_OnOpen"), HarmonyPostfix]
static void _OnOpen(UISaveGameWindow __instance, UIButton ___saveButton, Text ___saveButtonText)
private static void _OnOpen(UISaveGameWindow __instance)
{
if (context.buttonCompress) return;
context.saveButton = ___saveButton;
context.saveButtonText = ___saveButtonText;
if (_context.ButtonCompress) return;
_context.SaveButton = __instance.saveButton;
_context.SaveButtonText = __instance.saveButtonText;
context.ui = __instance;
context.buttonCompress =
(__instance.transform.Find("button-compress")?.gameObject ??
GameObject.Instantiate(___saveButton.gameObject, ___saveButton.transform.parent))
.GetComponent<UIButton>();
_context.Window = __instance;
var gameObj = __instance.transform.Find("button-compress")?.gameObject;
if (gameObj == null)
gameObj = Object.Instantiate(__instance.saveButton.gameObject, __instance.saveButton.transform.parent);
_context.ButtonCompress = gameObj.GetComponent<UIButton>();
context.buttonCompress.gameObject.name = "button-compress";
context.buttonCompress.transform.Translate(new Vector3(-2.0f, 0, 0));
context.buttonCompress.button.image.color = new Color32(0xfc, 0x6f, 00, 0x77);
context.buttonCompressText = context.buttonCompress.transform.Find("button-text")?.GetComponent<Text>();
_context.ButtonCompress.gameObject.name = "button-compress";
_context.ButtonCompress.transform.Translate(new Vector3(-2.0f, 0, 0));
_context.ButtonCompress.button.image.color = new Color32(0xfc, 0x6f, 00, 0x77);
_context.ButtonCompressText = _context.ButtonCompress.transform.Find("button-text")?.GetComponent<Text>();
context.buttonCompress.onClick += __instance.OnSaveClick;
context.saveButton.onClick -= __instance.OnSaveClick;
context.saveButton.onClick += WrapClick;
_context.ButtonCompress.onClick += __instance.OnSaveClick;
_context.SaveButton.onClick -= __instance.OnSaveClick;
_context.SaveButton.onClick += WrapClick;
}
static void WrapClick(int data)
private static void WrapClick(int data)
{
PatchSave.UseCompressSave = false;
context.ui.OSaveGameAs(data);
_context.Window.OSaveGameAs(data);
}
public static void OnDestroy()
{
if (context.buttonCompress)
GameObject.Destroy(context.buttonCompress.gameObject);
if (context.ui)
{
context.saveButton.onClick -= WrapClick;
context.saveButton.onClick += context.ui.OnSaveClick;
}
_OnDestroy();
}
}

View File

@@ -7,9 +7,9 @@ namespace CompressSave;
public static class SaveUtil
{
public static ManualLogSource logger;
public static ManualLogSource Logger;
public static readonly Version VerifiedVersion = new Version
public static readonly Version VerifiedVersion = new()
{
Major = 0,
Minor = 9,
@@ -19,19 +19,21 @@ public static class SaveUtil
private static string UnzipToFile(DecompressionStream lzStream, string fullPath)
{
lzStream.ResetStream();
string dir = Path.GetDirectoryName(fullPath);
string filename = "[Recovery]-" + Path.GetFileNameWithoutExtension(fullPath);
fullPath = Path.Combine(dir, filename + GameSave.saveExt);
int i = 0;
var dir = Path.GetDirectoryName(fullPath);
var filename = "[Recovery]-" + Path.GetFileNameWithoutExtension(fullPath);
fullPath = filename + GameSave.saveExt;
if (dir != null) fullPath = Path.Combine(dir, fullPath);
var i = 0;
while(File.Exists(fullPath))
{
fullPath = Path.Combine(dir, $"{filename}[{i++}]{GameSave.saveExt}");
fullPath = $"{filename}[{i++}]{GameSave.saveExt}";
if (dir != null) fullPath = Path.Combine(dir, fullPath);
}
var buffer = new byte[1024 * 1024];
using (var fs = new FileStream(fullPath, FileMode.Create))
using (var br = new BinaryWriter(fs))
{
for (int read = lzStream.Read(buffer, 0, buffer.Length); read > 0; read = lzStream.Read(buffer, 0, buffer.Length))
for (var read = lzStream.Read(buffer, 0, buffer.Length); read > 0; read = lzStream.Read(buffer, 0, buffer.Length))
{
fs.Write(buffer, 0, read);
}
@@ -45,37 +47,35 @@ public static class SaveUtil
public static bool DecompressSave(string saveName, out string newSaveName)
{
newSaveName = string.Empty;
string path = GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
var path = GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
try
{
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
var compressType = SaveGetCompressType(fileStream);
switch (compressType)
{
var compressType = SaveGetCompressType(fileStream);
switch (compressType)
{
case CompressionType.LZ4:
case CompressionType.Zstd:
using (var lzstream = new DecompressionStream(compressType == CompressionType.LZ4 ? PatchSave.LZ4Wrapper : PatchSave.ZstdWrapper, fileStream))
{
newSaveName = UnzipToFile(lzstream, path);
}
return true;
case CompressionType.None:
return false;
default:
throw new ArgumentOutOfRangeException();
}
case CompressionType.LZ4:
case CompressionType.Zstd:
using (var lzstream = new DecompressionStream(compressType == CompressionType.LZ4 ? PatchSave.LZ4Wrapper : PatchSave.ZstdWrapper, fileStream))
{
newSaveName = UnzipToFile(lzstream, path);
}
return true;
case CompressionType.None:
return false;
default:
throw new ArgumentOutOfRangeException();
}
}
catch (Exception e)
{
logger.LogError(e);
Logger.LogError(e);
return false;
}
}
public static CompressionType SaveGetCompressType(FileStream fs)
{
for (int i = 0; i < 3; i++)
for (var i = 0; i < 3; i++)
{
if (0xCC != fs.ReadByte())
return CompressionType.None;
@@ -94,12 +94,12 @@ public static class SaveUtil
if (string.IsNullOrEmpty(saveName)) return CompressionType.None;
try
{
using (FileStream fileStream = new FileStream(GetFullSavePath(saveName), FileMode.Open))
return SaveGetCompressType(fileStream);
using var fileStream = new FileStream(GetFullSavePath(saveName), FileMode.Open);
return SaveGetCompressType(fileStream);
}
catch (Exception e)
{
logger.LogWarning(e);
Logger.LogWarning(e);
return CompressionType.None;
}
}