mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 00:13:36 +08:00
cleanup codes
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user