using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CompressSave.UI;
using CompressSave.Wrapper;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CompressSave")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("DSP MOD - CompressSave")]
[assembly: AssemblyFileVersion("1.3.8.0")]
[assembly: AssemblyInformationalVersion("1.3.8+fbad19f68f39f38deb6c16dfea5f633c7e019116")]
[assembly: AssemblyProduct("CompressSave")]
[assembly: AssemblyTitle("CompressSave")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.8.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
public static class I18N
{
private static bool _initialized;
private static bool _dirty;
private static readonly List<Tuple<string, string, int>> Keys = new List<Tuple<string, string, int>>();
private static readonly Dictionary<int, List<string>> Strings = new Dictionary<int, List<string>>();
public static void Init()
{
Harmony.CreateAndPatchAll(typeof(I18N), (string)null);
}
public static bool Initialized()
{
return _initialized;
}
public static void Add(string key, string enus, string zhcn = null)
{
if (zhcn != null || !(key == enus))
{
Keys.Add(Tuple.Create(key, enus, -1));
if (Strings.TryGetValue(2052, out var value))
{
value.Add(string.IsNullOrEmpty(zhcn) ? enus : zhcn);
}
else
{
Strings.Add(2052, new List<string>(1) { string.IsNullOrEmpty(zhcn) ? enus : zhcn });
}
_dirty = true;
}
}
private static void ApplyIndexers()
{
Dictionary<string, int> namesIndexer = Localization.namesIndexer;
int num = namesIndexer.Count;
int count = Keys.Count;
for (int i = 0; i < count; i++)
{
var (text3, item, num3) = Keys[i];
if (num3 < 0)
{
if (namesIndexer.TryGetValue(text3, out var value))
{
Keys[i] = Tuple.Create(text3, item, value);
continue;
}
namesIndexer[text3] = num;
Keys[i] = Tuple.Create(text3, item, num);
num++;
}
}
_dirty = false;
string[][] strings = Localization.strings;
if (strings == null)
{
return;
}
int num4 = strings.Length;
for (int j = 0; j < num4; j++)
{
ApplyLanguage(j);
if (j == Localization.currentLanguageIndex)
{
Localization.currentStrings = Localization.strings[j];
Localization.currentFloats = Localization.floats[j];
}
}
}
private static void ApplyLanguage(int index)
{
int count = Localization.namesIndexer.Count;
string[] array = Localization.strings[index];
if (array == null)
{
return;
}
if (array.Length < count)
{
string[] array2 = new string[count];
Array.Copy(array, array2, array.Length);
array = array2;
Localization.strings[index] = array;
}
float[] array3 = Localization.floats[index];
if (array3 != null && array3.Length < count)
{
float[] array4 = new float[count];
Array.Copy(array3, array4, array3.Length);
array3 = array4;
Localization.floats[index] = array3;
}
int count2 = Keys.Count;
if (Strings.TryGetValue(Localization.Languages[index].lcId, out var value))
{
for (int i = 0; i < count2; i++)
{
array[Keys[i].Item3] = value[i];
}
}
else
{
for (int j = 0; j < count2; j++)
{
array[Keys[j].Item3] = Keys[j].Item2;
}
}
}
public static void Apply()
{
if (_initialized && Keys.Count != 0 && _dirty)
{
ApplyIndexers();
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Localization), "LoadSettings")]
private static void Localization_LoadSettings_Postfix()
{
if (!_initialized)
{
_initialized = true;
Apply();
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
[HarmonyPatch(typeof(Localization), "LoadLanguage")]
private static void Localization_LoadLanguage_Postfix(int index)
{
if (_initialized)
{
ApplyLanguage(index);
}
}
}
namespace CompressSave
{
public enum CompressionType
{
None,
LZ4,
Zstd
}
[BepInPlugin("org.soardev.compresssave", "CompressSave", "1.3.8")]
public class CompressSave : BaseUnityPlugin
{
private Harmony _patchSave;
private Harmony _patchUISave;
private Harmony _patchUILoad;
public static string StringFromCompresstionType(CompressionType type)
{
return type switch
{
CompressionType.LZ4 => "lz4",
CompressionType.Zstd => "zstd",
CompressionType.None => "none",
_ => throw new ArgumentException("Unknown compression type."),
};
}
private static CompressionType CompressionTypeFromString(string str)
{
if (!(str == "lz4"))
{
if (str == "zstd")
{
return CompressionType.Zstd;
}
return CompressionType.None;
}
return CompressionType.LZ4;
}
public void Awake()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Expected O, but got Unknown
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
SaveUtil.Logger = ((BaseUnityPlugin)this).Logger;
if (LZ4API.Avaliable && ZstdAPI.Avaliable)
{
PatchSave.CompressionTypeForSavesConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Compression", "Type", StringFromCompresstionType(PatchSave.CompressionTypeForSaves), new ConfigDescription("Set default compression type for manual saves.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "lz4", "zstd", "none" }), new object[1]
{
new { }
}));
PatchSave.CompressionTypeForSaves = CompressionTypeFromString(PatchSave.CompressionTypeForSavesConfig.Value);
PatchSave.CompressionTypeForAutoSavesConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Compression", "TypeForAuto", StringFromCompresstionType(PatchSave.CompressionTypeForAutoSaves), new ConfigDescription("Set default compression type for auto saves and last-exit save.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "lz4", "zstd", "none" }), new object[1]
{
new { }
}));
PatchSave.CompressionTypeForAutoSaves = CompressionTypeFromString(PatchSave.CompressionTypeForAutoSavesConfig.Value);
PatchSave.CompressionLevelForSaves = ((BaseUnityPlugin)this).Config.Bind<int>("Compression", "Level", PatchSave.CompressionLevelForSaves, "Set default compression level for manual saves.\n0 for default level.\n3 ~ 12 for lz4, -5 ~ 22 for zstd.\nSmaller level leads to faster speed and less compression ratio.").Value;
PatchSave.CompressionLevelForAutoSaves = ((BaseUnityPlugin)this).Config.Bind<int>("Compression", "LevelForAuto", PatchSave.CompressionLevelForAutoSaves, "Set default compression level for auto saves and last-exit save.\n0 for default level.\n3 ~ 12 for lz4, -5 ~ 22 for zstd.\nSmaller level leads to faster speed and less compression ratio.").Value;
PatchSave.EnableForAutoSaves = ((BaseUnityPlugin)this).Config.Bind<bool>("Compression", "EnableForAutoSaves", true, "Enable the feature for auto saves and last-exit save.");
PatchSave.CreateCompressBuffer();
if (GameConfig.gameVersion != SaveUtil.VerifiedVersion)
{
SaveUtil.Logger.LogWarning((object)$"Save version mismatch. Expect:{SaveUtil.VerifiedVersion}, Current:{GameConfig.gameVersion}. MOD may not work as expected.");
}
_patchSave = Harmony.CreateAndPatchAll(typeof(PatchSave), (string)null);
if (PatchSave.EnableCompress)
{
_patchUISave = Harmony.CreateAndPatchAll(typeof(PatchUISaveGame), (string)null);
}
_patchUILoad = Harmony.CreateAndPatchAll(typeof(PatchUILoadGame), (string)null);
}
else
{
SaveUtil.Logger.LogWarning((object)"Either nonewrap.dll, lz4warp.dll or zstdwrap.dll is not avaliable.");
}
I18N.Init();
I18N.Add("Store", "Store (No Compression)", "存储(不压缩)");
I18N.Add("Decompress", "Decompress", "解压存档");
I18N.Add("Save with Compression", "Save (Compress)", "压缩保存");
I18N.Add("Compression for auto saves", "Compression for auto saves", "\u3000\u3000自动存档压缩方式");
I18N.Add("Compression for manual saves", "Compression for manual saves", "\u3000\u3000手动存档压缩方式");
I18N.Apply();
}
public void OnDestroy()
{
if (_patchUISave != null)
{
PatchUISaveGame.OnDestroy();
_patchUISave.UnpatchSelf();
_patchUISave = null;
}
if (_patchUILoad != null)
{
PatchUILoadGame.OnDestroy();
_patchUILoad.UnpatchSelf();
_patchUILoad = null;
}
Harmony patchSave = _patchSave;
if (patchSave != null)
{
patchSave.UnpatchSelf();
}
_patchSave = null;
}
}
public class PatchSave
{
public static readonly WrapperDefines LZ4Wrapper = LZ4API.Instance;
public static readonly WrapperDefines ZstdWrapper = ZstdAPI.Instance;
private static readonly WrapperDefines NoneWrapper = NoneAPI.Instance;
private static CompressionStream.CompressBuffer _compressBuffer;
public static bool UseCompressSave;
private static CompressionType _compressionTypeForLoading = CompressionType.None;
private static CompressionType _compressionTypeForSaving = CompressionType.Zstd;
private static int _compressionLevelForSaving;
public static CompressionType CompressionTypeForSaves = CompressionType.Zstd;
public static CompressionType CompressionTypeForAutoSaves = CompressionType.Zstd;
public static ConfigEntry<string> CompressionTypeForSavesConfig;
public static ConfigEntry<string> CompressionTypeForAutoSavesConfig;
public static int CompressionLevelForSaves;
public static int CompressionLevelForAutoSaves;
public static ConfigEntry<bool> EnableForAutoSaves;
private static Stream _compressionStream;
public static bool EnableCompress;
public static void CreateCompressBuffer()
{
_compressBuffer = CompressionStream.CreateBuffer((int)Math.Max(Math.Max(LZ4Wrapper.CompressBufferBound(1048576L), ZstdWrapper.CompressBufferBound(1048576L)), NoneWrapper.CompressBufferBound(1048576L)), 1048576);
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
}
private static void WriteHeader(FileStream fileStream)
{
if (fileStream == null)
{
throw new ArgumentNullException("fileStream");
}
switch (_compressionTypeForSaving)
{
case CompressionType.Zstd:
{
for (int j = 0; j < 3; j++)
{
fileStream.WriteByte(204);
}
fileStream.WriteByte(205);
break;
}
case CompressionType.LZ4:
{
for (int i = 0; i < 4; i++)
{
fileStream.WriteByte(204);
}
break;
}
default:
throw new ArgumentException("Unknown compression type.");
case CompressionType.None:
break;
}
}
public static void UseCommonSaveCompressionType()
{
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameSave), "AutoSave")]
[HarmonyPatch(typeof(GameSave), "AutoSaveAfterErrored")]
[HarmonyPatch(typeof(GameSave), "SaveAsLastExit")]
private static void BeforeAutoSave()
{
UseCompressSave = EnableForAutoSaves.Value && EnableCompress;
if (UseCompressSave)
{
_compressionTypeForSaving = CompressionTypeForAutoSaves;
_compressionLevelForSaving = CompressionLevelForAutoSaves;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameSave), "SaveCurrentGame")]
private static IEnumerable<CodeInstruction> SaveCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Expected O, but got Unknown
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Expected O, but got Unknown
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Expected O, but got Unknown
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Expected O, but got Unknown
CodeMatcher val = new CodeMatcher(instructions, generator);
try
{
val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Newobj, (object)AccessTools.Constructor(typeof(BinaryWriter), new Type[1] { typeof(FileStream) }, false), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "CreateBinaryWriter", (Type[])null, (Type[])null)).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(PerformanceMonitor), "BeginStream", (Type[])null, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "MonitorStream", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Stream), "Seek", (Type[])null, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthWrite0", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(BinaryWriter), "Write", new Type[1] { typeof(long) }, (Type[])null), (string)null)
})
.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthWrite1", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(IDisposable), "Dispose", (Type[])null, (Type[])null), (string)null)
})
.Advance(1)
.Insert((CodeInstruction[])(object)new CodeInstruction[1]
{
new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream", (Type[])null, (Type[])null))
});
EnableCompress = true;
return val.InstructionEnumeration();
}
catch (Exception ex)
{
SaveUtil.Logger.LogError((object)"SaveCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.Logger.LogError((object)ex);
}
return val.InstructionEnumeration();
}
public static void MonitorStream(Stream fileStream)
{
PerformanceMonitor.BeginStream(UseCompressSave ? _compressionStream : fileStream);
}
public static BinaryWriter CreateBinaryWriter(FileStream fileStream)
{
if (UseCompressSave)
{
WriteHeader(fileStream);
_compressionStream = _compressionTypeForSaving switch
{
CompressionType.LZ4 => new CompressionStream(LZ4Wrapper, _compressionLevelForSaving, fileStream, _compressBuffer, multiThread: true),
CompressionType.Zstd => new CompressionStream(ZstdWrapper, _compressionLevelForSaving, fileStream, _compressBuffer, multiThread: true),
CompressionType.None => new CompressionStream(NoneWrapper, 0, fileStream, _compressBuffer, multiThread: true),
_ => _compressionStream,
};
return ((CompressionStream)_compressionStream).BufferWriter;
}
SaveUtil.Logger.LogDebug((object)"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;
}
public static void FileLengthWrite1(BinaryWriter binaryWriter, long value)
{
if (!UseCompressSave)
{
binaryWriter.Write(value);
}
}
public static void DisposeCompressionStream()
{
if (!UseCompressSave)
{
return;
}
if (_compressionStream == null)
{
UseCompressSave = false;
return;
}
bool canWrite = _compressionStream.CanWrite;
Stream stream = null;
if (canWrite && _compressionTypeForSaving == CompressionType.None)
{
stream = ((CompressionStream)_compressionStream).OutStream;
}
_compressionStream.Dispose();
_compressionStream = null;
if (canWrite)
{
if (stream != null)
{
long value = stream.Seek(0L, SeekOrigin.End);
stream.Seek(6L, SeekOrigin.Begin);
BinaryWriter binaryWriter = new BinaryWriter(stream);
binaryWriter.Write(value);
binaryWriter.Dispose();
}
_compressionTypeForSaving = CompressionTypeForSaves;
_compressionLevelForSaving = CompressionLevelForSaves;
UseCompressSave = false;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(GameSave), "LoadCurrentGame")]
[HarmonyPatch(typeof(GameSave), "LoadGameDesc")]
[HarmonyPatch(typeof(GameSave), "ReadHeader")]
[HarmonyPatch(typeof(GameSave), "ReadHeaderAndDescAndProperty")]
[HarmonyPatch(typeof(GameSave), "ReadModes")]
private static IEnumerable<CodeInstruction> LoadCurrentGame_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Expected O, but got Unknown
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Expected O, but got Unknown
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Expected O, but got Unknown
CodeMatcher val = new CodeMatcher(instructions, generator);
try
{
val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Newobj, (object)AccessTools.Constructor(typeof(BinaryReader), new Type[1] { typeof(FileStream) }, false), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "CreateBinaryReader", (Type[])null, (Type[])null)).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(PerformanceMonitor), "BeginStream", (Type[])null, (Type[])null), (string)null)
});
if (val.IsValid)
{
val.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "MonitorStream", (Type[])null, (Type[])null));
}
val.Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(BinaryReader), "ReadInt64", (Type[])null, (Type[])null), (string)null)
}).Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "FileLengthRead", (Type[])null, (Type[])null))
.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(IDisposable), "Dispose", (Type[])null, (Type[])null), (string)null)
})
.Advance(1)
.Insert((CodeInstruction[])(object)new CodeInstruction[1]
{
new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream", (Type[])null, (Type[])null))
})
.MatchBack(false, (CodeMatch[])(object)new CodeMatch[1]
{
new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Stream), "Seek", (Type[])null, (Type[])null), (string)null)
});
if (val.IsValid)
{
val.Set(OpCodes.Call, (object)AccessTools.Method(typeof(PatchSave), "ReadSeek", (Type[])null, (Type[])null));
}
return val.InstructionEnumeration();
}
catch (Exception ex)
{
SaveUtil.Logger.LogError((object)"LoadCurrentGame_Transpiler failed. Mod version not compatible with game version.");
SaveUtil.Logger.LogError((object)ex);
}
return val.InstructionEnumeration();
}
public static BinaryReader CreateBinaryReader(FileStream fileStream)
{
switch (_compressionTypeForLoading = SaveUtil.SaveGetCompressType(fileStream))
{
case CompressionType.LZ4:
UseCompressSave = true;
_compressionStream = new DecompressionStream(LZ4Wrapper, fileStream);
return new PeekableReader((DecompressionStream)_compressionStream);
case CompressionType.Zstd:
UseCompressSave = true;
_compressionStream = new DecompressionStream(ZstdWrapper, fileStream);
return new PeekableReader((DecompressionStream)_compressionStream);
case CompressionType.None:
UseCompressSave = false;
fileStream.Seek(0L, SeekOrigin.Begin);
return new BinaryReader(fileStream);
default:
throw new ArgumentOutOfRangeException();
}
}
public static long FileLengthRead(BinaryReader binaryReader)
{
switch (_compressionTypeForLoading)
{
case CompressionType.LZ4:
case CompressionType.Zstd:
binaryReader.ReadInt64();
return _compressionStream.Length;
case CompressionType.None:
return binaryReader.ReadInt64();
default:
throw new ArgumentOutOfRangeException();
}
}
public static long ReadSeek(FileStream fileStream, long offset, SeekOrigin origin)
{
switch (_compressionTypeForLoading)
{
case CompressionType.LZ4:
case CompressionType.Zstd:
while (offset > 0)
{
offset -= _compressionStream.Read(_compressBuffer.OutBuffer, 0, (int)offset);
}
return _compressionStream.Position;
case CompressionType.None:
return fileStream.Seek(offset, origin);
default:
throw new ArgumentOutOfRangeException();
}
}
}
internal class PatchUILoadGame
{
private static UIButton _decompressButton;
[HarmonyPatch(typeof(UILoadGameWindow), "OnSelectedChange")]
[HarmonyPostfix]
private static void OnSelectedChange(UILoadGameWindow __instance)
{
UIGameSaveEntry selected = __instance.selected;
CompressionType compressionType = SaveUtil.SaveGetCompressType(((Object)(object)selected == (Object)null) ? null : selected._saveName);
Text prop3Text = __instance.prop3Text;
Text val = prop3Text;
val.text = compressionType switch
{
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text,
};
if (Object.op_Implicit((Object)(object)_decompressButton))
{
((Selectable)_decompressButton.button).interactable = compressionType != CompressionType.None;
((Component)_decompressButton).gameObject.SetActive(compressionType != CompressionType.None);
}
}
[HarmonyPatch(typeof(UILoadGameWindow), "_OnOpen")]
[HarmonyPostfix]
private static void _OnOpen(UILoadGameWindow __instance)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)_decompressButton))
{
return;
}
UIButton loadButton = __instance.loadButton;
bool flag = false;
Transform obj = ((Component)__instance).transform.Find("button-decompress");
GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
if ((Object)(object)val == (Object)null)
{
val = Object.Instantiate<GameObject>(((Component)loadButton).gameObject, ((Component)loadButton).transform.parent);
flag = true;
}
_decompressButton = val.GetComponent<UIButton>();
if (flag)
{
Vector3 anchoredPosition3D = ((RectTransform)__instance.loadSandboxGroup.transform).anchoredPosition3D;
((Object)((Component)_decompressButton).gameObject).name = "button-decompress";
RectTransform val2 = (RectTransform)((Component)_decompressButton).transform;
Vector3 val3 = anchoredPosition3D;
((Vector3)(ref anchoredPosition3D))..ctor(val3.x - 230f, val3.y, val3.z);
val2.anchoredPosition3D = anchoredPosition3D;
((Graphic)((Selectable)_decompressButton.button).image).color = Color32.op_Implicit(new Color32((byte)0, (byte)244, (byte)146, (byte)119));
Transform obj2 = ((Component)_decompressButton).transform.Find("button-text");
((Component)obj2).GetComponent<Text>().text = Localization.Translate("Decompress");
Localizer component = ((Component)obj2).GetComponent<Localizer>();
if (Object.op_Implicit((Object)(object)component))
{
component.stringKey = "Decompress";
component.translation = Localization.Translate("Decompress");
}
_decompressButton.onClick += delegate
{
if (SaveUtil.DecompressSave(__instance.selected._saveName, out var newfileName))
{
__instance.RefreshList();
__instance.selected = __instance.entries.First((UIGameSaveEntry e) => e._saveName == newfileName);
}
};
}
((Selectable)_decompressButton.button).interactable = false;
((Component)_decompressButton).gameObject.SetActive(false);
}
public static void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_decompressButton))
{
Object.Destroy((Object)(object)((Component)_decompressButton).gameObject);
}
_decompressButton = null;
}
}
internal static class PatchUISaveGame
{
private class UIContext
{
public UIButton ButtonCompress;
public UIButton SaveButton;
public GameObject ManualSaveTypeComboBox;
public GameObject AutoSaveTypeComboBox;
public Text ButtonCompressText;
public Text SaveButtonText;
public UISaveGameWindow Window;
}
private static UIContext _context = new UIContext();
public static void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_context.ButtonCompress))
{
Object.Destroy((Object)(object)((Component)_context.ButtonCompress).gameObject);
}
if (Object.op_Implicit((Object)(object)_context.Window))
{
_context.SaveButton.onClick -= WrapClick;
_context.SaveButton.onClick += _context.Window.OnSaveClick;
}
_OnDestroy();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSelectedChange")]
[HarmonyPostfix]
private static void OnSelectedChange(UISaveGameWindow __instance)
{
UIGameSaveEntry selected = __instance.selected;
CompressionType compressionType = SaveUtil.SaveGetCompressType(((Object)(object)selected == (Object)null) ? null : selected._saveName);
Text prop3Text = __instance.prop3Text;
Text val = prop3Text;
val.text = compressionType switch
{
CompressionType.LZ4 => "(LZ4)" + prop3Text.text,
CompressionType.Zstd => "(ZSTD)" + prop3Text.text,
_ => "(N)" + prop3Text.text,
};
}
[HarmonyPatch(typeof(UISaveGameWindow), "_OnDestroy")]
[HarmonyPostfix]
private static void _OnDestroy()
{
_context = new UIContext();
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick")]
[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
private static void OSaveGameAs(this UISaveGameWindow ui, int data)
{
}
[HarmonyPatch(typeof(UISaveGameWindow), "CheckAndSetSaveButtonEnable")]
[HarmonyPostfix]
private static void CheckAndSetSaveButtonEnable(UISaveGameWindow __instance)
{
_OnOpen(__instance);
if (Object.op_Implicit((Object)(object)_context.SaveButton))
{
((Selectable)_context.ButtonCompress.button).interactable = ((Selectable)_context.SaveButton.button).interactable;
}
}
[HarmonyPatch(typeof(UISaveGameWindow), "OnSaveClick")]
[HarmonyPrefix]
private static void OnSaveClick()
{
PatchSave.UseCompressSave = true;
PatchSave.UseCommonSaveCompressionType();
}
[HarmonyPatch(typeof(UISaveGameWindow), "_OnOpen")]
[HarmonyPostfix]
private static void _OnOpen(UISaveGameWindow __instance)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_0273: Unknown result type (might be due to invalid IL or missing references)
//IL_0288: Unknown result type (might be due to invalid IL or missing references)
//IL_029e: Unknown result type (might be due to invalid IL or missing references)
//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0305: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_0364: Unknown result type (might be due to invalid IL or missing references)
//IL_036b: Expected O, but got Unknown
//IL_038f: Unknown result type (might be due to invalid IL or missing references)
//IL_0394: Unknown result type (might be due to invalid IL or missing references)
//IL_0398: Unknown result type (might be due to invalid IL or missing references)
//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
//IL_03da: Unknown result type (might be due to invalid IL or missing references)
//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0404: Unknown result type (might be due to invalid IL or missing references)
//IL_0407: Unknown result type (might be due to invalid IL or missing references)
//IL_0411: Unknown result type (might be due to invalid IL or missing references)
//IL_0414: Unknown result type (might be due to invalid IL or missing references)
//IL_0425: Unknown result type (might be due to invalid IL or missing references)
//IL_0426: Unknown result type (might be due to invalid IL or missing references)
//IL_0432: Unknown result type (might be due to invalid IL or missing references)
//IL_043e: Unknown result type (might be due to invalid IL or missing references)
//IL_0444: Unknown result type (might be due to invalid IL or missing references)
//IL_0508: Unknown result type (might be due to invalid IL or missing references)
//IL_050f: Expected O, but got Unknown
//IL_052f: Unknown result type (might be due to invalid IL or missing references)
//IL_0534: Unknown result type (might be due to invalid IL or missing references)
//IL_0538: Unknown result type (might be due to invalid IL or missing references)
//IL_0545: Unknown result type (might be due to invalid IL or missing references)
//IL_0552: Unknown result type (might be due to invalid IL or missing references)
//IL_055c: Unknown result type (might be due to invalid IL or missing references)
//IL_0568: Unknown result type (might be due to invalid IL or missing references)
//IL_0574: Unknown result type (might be due to invalid IL or missing references)
//IL_057a: Unknown result type (might be due to invalid IL or missing references)
//IL_058a: Unknown result type (might be due to invalid IL or missing references)
//IL_058f: Unknown result type (might be due to invalid IL or missing references)
//IL_0597: Unknown result type (might be due to invalid IL or missing references)
//IL_059a: Unknown result type (might be due to invalid IL or missing references)
//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
//IL_05be: Unknown result type (might be due to invalid IL or missing references)
//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
//IL_05d7: Unknown result type (might be due to invalid IL or missing references)
//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)_context.ButtonCompress))
{
float num = ((Component)__instance.cancelButton).transform.localPosition.x - ((Component)__instance.saveButton).transform.localPosition.x - ((RectTransform)((Component)__instance.cancelButton).transform).sizeDelta.x;
RectTransform val = (RectTransform)((Component)_context.ButtonCompress).transform;
Vector3 localPosition = ((Component)__instance.saveButton).transform.localPosition;
((Transform)val).localPosition = new Vector3(localPosition.x - num - ((RectTransform)((Component)__instance.saveButton).transform).sizeDelta.x, localPosition.y, localPosition.z);
return;
}
_context.SaveButton = __instance.saveButton;
_context.SaveButtonText = __instance.saveButtonText;
_context.Window = __instance;
Transform obj = ((Component)__instance).transform.Find("button-compress");
GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null);
bool flag = false;
Transform parent = ((Component)__instance.saveButton).transform.parent;
if ((Object)(object)val2 == (Object)null)
{
val2 = Object.Instantiate<GameObject>(((Component)__instance.saveButton).gameObject, parent);
flag = true;
}
_context.ButtonCompress = val2.GetComponent<UIButton>();
if (flag)
{
((Object)((Component)_context.ButtonCompress).gameObject).name = "button-compress";
((Graphic)((Selectable)_context.ButtonCompress.button).image).color = Color32.op_Implicit(new Color32((byte)252, (byte)111, (byte)0, (byte)119));
Transform val3 = ((Component)_context.ButtonCompress).transform.Find("button-text");
_context.ButtonCompressText = ((Component)val3).GetComponent<Text>();
_context.ButtonCompress.onClick += __instance.OnSaveClick;
_context.SaveButton.onClick -= __instance.OnSaveClick;
_context.SaveButton.onClick += WrapClick;
_context.ButtonCompressText.text = Localization.Translate("Save with Compression");
Localizer component = ((Component)val3).GetComponent<Localizer>();
if (Object.op_Implicit((Object)(object)component))
{
component.stringKey = "Save with Compression";
component.translation = Localization.Translate("Save with Compression");
}
}
float num2 = ((Component)__instance.cancelButton).transform.localPosition.x - ((Component)__instance.saveButton).transform.localPosition.x - ((RectTransform)((Component)__instance.cancelButton).transform).sizeDelta.x;
RectTransform val4 = (RectTransform)((Component)_context.ButtonCompress).transform;
Vector3 localPosition2 = ((Component)__instance.saveButton).transform.localPosition;
((Transform)val4).localPosition = new Vector3(localPosition2.x - num2 - ((RectTransform)((Component)__instance.saveButton).transform).sizeDelta.x, localPosition2.y, localPosition2.z);
flag = false;
Transform obj2 = ((Component)__instance).transform.Find("manual-save-type-combobox");
val2 = ((obj2 != null) ? ((Component)obj2).gameObject : null);
if ((Object)(object)val2 == (Object)null)
{
val2 = MyComboBox.CreateComboBox("manual-save-type-combobox");
flag = true;
}
_context.ManualSaveTypeComboBox = val2;
if (flag)
{
RectTransform val5 = (RectTransform)((Component)_context.ButtonCompress).transform;
Text val6 = AddText("Compression for manual saves", 14, "manual-save-type-combobox-text");
RectTransform rectTransform = ((Graphic)val6).rectTransform;
((Transform)rectTransform).SetParent(parent, false);
localPosition2 = ((Transform)val5).localPosition;
rectTransform.anchorMin = val5.anchorMin;
rectTransform.anchorMax = val5.anchorMax;
rectTransform.pivot = val5.pivot;
((Transform)rectTransform).localPosition = new Vector3(localPosition2.x - 250f, localPosition2.y + 45f, localPosition2.z);
RectTransform val7 = (RectTransform)val2.transform;
((Transform)val7).SetParent(parent, false);
val7.anchorMin = val5.anchorMin;
val7.anchorMax = val5.anchorMax;
val7.pivot = val5.pivot;
((Graphic)val6).UpdateGeometry();
((Transform)val7).localPosition = new Vector3(localPosition2.x - 50f, localPosition2.y + 45f, localPosition2.z);
((Component)val7).GetComponent<MyComboBox>().WithItems(Localization.Translate("Store"), "LZ4", "Zstd").WithIndex((int)PatchSave.CompressionTypeForSaves)
.WithOnSelChanged(delegate(int idx)
{
PatchSave.CompressionTypeForSaves = (CompressionType)idx;
PatchSave.CompressionTypeForSavesConfig.Value = CompressSave.StringFromCompresstionType(PatchSave.CompressionTypeForSaves);
});
}
flag = false;
Transform obj3 = ((Component)__instance).transform.Find("auto-save-type-combobox");
val2 = ((obj3 != null) ? ((Component)obj3).gameObject : null);
if ((Object)(object)val2 == (Object)null)
{
val2 = MyComboBox.CreateComboBox("auto-save-type-combobox");
flag = true;
}
_context.AutoSaveTypeComboBox = val2;
if (!flag)
{
return;
}
RectTransform val8 = (RectTransform)((Component)_context.ButtonCompress).transform;
RectTransform rectTransform2 = ((Graphic)AddText("Compression for auto saves", 14, "auto-save-type-combobox-text")).rectTransform;
((Transform)rectTransform2).SetParent(parent, false);
localPosition2 = ((Transform)val8).localPosition;
rectTransform2.anchorMin = val8.anchorMin;
rectTransform2.anchorMax = val8.anchorMax;
rectTransform2.pivot = val8.pivot;
((Transform)rectTransform2).localPosition = new Vector3(localPosition2.x + 160f, localPosition2.y + 45f, localPosition2.z);
RectTransform val9 = (RectTransform)val2.transform;
((Transform)val9).SetParent(parent, false);
val9.anchorMin = val8.anchorMin;
val9.anchorMax = val8.anchorMax;
val9.pivot = val8.pivot;
((Transform)val9).localPosition = new Vector3(localPosition2.x + 360f, localPosition2.y + 45f, localPosition2.z);
((Component)val9).GetComponent<MyComboBox>().WithItems(Localization.Translate("已停用"), Localization.Translate("Store"), "LZ4", "Zstd").WithIndex((int)(PatchSave.EnableForAutoSaves.Value ? (PatchSave.CompressionTypeForAutoSaves + 1) : CompressionType.None))
.WithOnSelChanged(delegate(int idx)
{
if (idx == 0)
{
PatchSave.EnableForAutoSaves.Value = false;
}
else
{
PatchSave.EnableForAutoSaves.Value = true;
PatchSave.CompressionTypeForAutoSaves = (CompressionType)(idx - 1);
PatchSave.CompressionTypeForAutoSavesConfig.Value = CompressSave.StringFromCompresstionType(PatchSave.CompressionTypeForAutoSaves);
}
});
}
private static void WrapClick(int data)
{
PatchSave.UseCompressSave = false;
_context.Window.OSaveGameAs(data);
}
public static Text AddText(string label, int fontSize = 14, string objName = "label")
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
Text val = Object.Instantiate<Text>(UIRoot.instance.uiGame.assemblerWindow.stateText);
((Object)((Component)val).gameObject).name = objName;
val.text = Localization.Translate(label);
((Graphic)val).color = new Color(1f, 1f, 1f, 0.4f);
val.alignment = (TextAnchor)3;
val.fontSize = fontSize;
((Graphic)val).rectTransform.sizeDelta = new Vector2(val.preferredWidth + 8f, val.preferredHeight + 8f);
return val;
}
}
public static class SaveUtil
{
public static ManualLogSource Logger;
public static readonly Version VerifiedVersion = new Version
{
Major = 0,
Minor = 10,
Release = 34
};
private static string UnzipToFile(DecompressionStream lzStream, string fullPath)
{
lzStream.ResetStream();
string directoryName = Path.GetDirectoryName(fullPath);
string text = "[Recovery]-" + Path.GetFileNameWithoutExtension(fullPath);
fullPath = text + GameSave.saveExt;
if (directoryName != null)
{
fullPath = Path.Combine(directoryName, fullPath);
}
int num = 0;
while (File.Exists(fullPath))
{
fullPath = $"{text}[{num++}]{GameSave.saveExt}";
if (directoryName != null)
{
fullPath = Path.Combine(directoryName, fullPath);
}
}
byte[] array = new byte[1048576];
using (FileStream fileStream = new FileStream(fullPath, FileMode.Create))
{
using BinaryWriter binaryWriter = new BinaryWriter(fileStream);
for (int num2 = lzStream.Read(array, 0, array.Length); num2 > 0; num2 = lzStream.Read(array, 0, array.Length))
{
fileStream.Write(array, 0, num2);
}
fileStream.Seek(6L, SeekOrigin.Begin);
binaryWriter.Write(fileStream.Length);
}
return Path.GetFileNameWithoutExtension(fullPath);
}
public static bool DecompressSave(string saveName, out string newSaveName)
{
newSaveName = string.Empty;
string text = GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
try
{
using FileStream fileStream = new FileStream(text, FileMode.Open, FileAccess.Read);
CompressionType compressionType = SaveGetCompressType(fileStream);
if (compressionType != 0)
{
if ((uint)(compressionType - 1) <= 1u)
{
using (DecompressionStream lzStream = new DecompressionStream((compressionType == CompressionType.LZ4) ? PatchSave.LZ4Wrapper : PatchSave.ZstdWrapper, fileStream))
{
newSaveName = UnzipToFile(lzStream, text);
}
return true;
}
throw new ArgumentOutOfRangeException();
}
return false;
}
catch (Exception ex)
{
Logger.LogError((object)ex);
return false;
}
}
public static CompressionType SaveGetCompressType(FileStream fs)
{
for (int i = 0; i < 3; i++)
{
if (204 != fs.ReadByte())
{
return CompressionType.None;
}
}
return fs.ReadByte() switch
{
204 => CompressionType.LZ4,
205 => CompressionType.Zstd,
_ => CompressionType.None,
};
}
internal static CompressionType SaveGetCompressType(string saveName)
{
if (string.IsNullOrEmpty(saveName))
{
return CompressionType.None;
}
try
{
using FileStream fs = new FileStream(GetFullSavePath(saveName), FileMode.Open);
return SaveGetCompressType(fs);
}
catch (Exception ex)
{
Logger.LogWarning((object)ex);
return CompressionType.None;
}
}
private static string GetFullSavePath(string saveName)
{
return GameConfig.gameSaveFolder + saveName + GameSave.saveExt;
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "org.soardev.compresssave";
public const string PLUGIN_NAME = "CompressSave";
public const string PLUGIN_VERSION = "1.3.8";
}
}
namespace CompressSave.Wrapper
{
internal class BlackHoleStream : Stream
{
private long _length;
private readonly byte[] _testBuffer = new byte[1048576];
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => _length;
public override long Position { get; set; }
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
return count;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
_length = value;
}
public override void Write(byte[] buffer, int offset, int count)
{
Array.Copy(buffer, offset, _testBuffer, 0, Math.Min(count, _testBuffer.Length));
}
}
public class BufferWriter : BinaryWriter
{
private readonly DoubleBuffer _doubleBuffer;
private readonly Encoding _encoding;
private readonly int _maxBytesPerChar;
private long _swapedBytes;
private unsafe byte* _curPos;
private unsafe byte* _endPos;
private unsafe byte* _startPos;
private readonly Stream _baseStream;
private ByteSpan CurrentBuffer => _doubleBuffer.WriteBuffer;
private byte[] Buffer => CurrentBuffer.Buffer;
private unsafe long SuplusCapacity => _endPos - _curPos;
public unsafe long WriteSum => _swapedBytes + _curPos - _startPos;
public override Stream BaseStream => _baseStream;
public override void Write(char[] chars, int index, int count)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
byte[] bytes = _encoding.GetBytes(chars, index, count);
Write(bytes);
}
public BufferWriter(DoubleBuffer doubleBuffer, CompressionStream outStream)
: this(doubleBuffer, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), outStream)
{
}
private BufferWriter(DoubleBuffer buffer, UTF8Encoding encoding, CompressionStream outStream)
: base(Stream.Null, encoding)
{
_baseStream = outStream;
_swapedBytes = 0L;
_doubleBuffer = buffer;
RefreshStatus();
_encoding = encoding;
_maxBytesPerChar = _encoding.GetMaxByteCount(1);
}
private unsafe void SwapBuffer()
{
CurrentBuffer.Position = 0;
CurrentBuffer.Length = (int)(_curPos - _startPos);
_swapedBytes += CurrentBuffer.Length;
_doubleBuffer.SwapBuffer();
RefreshStatus();
}
private unsafe void RefreshStatus()
{
_startPos = (byte*)System.Runtime.CompilerServices.Unsafe.AsPointer<byte>(ref Buffer[0]);
_curPos = _startPos;
_endPos = (byte*)System.Runtime.CompilerServices.Unsafe.AsPointer<byte>(ref Buffer[Buffer.Length - 1]) + 1;
}
private void CheckCapacityAndSwap(int requiredCapacity)
{
if (SuplusCapacity < requiredCapacity)
{
SwapBuffer();
}
}
public unsafe override void Write(byte value)
{
CheckCapacityAndSwap(1);
*(_curPos++) = value;
}
public override void Write(bool value)
{
Write(value ? ((byte)1) : ((byte)0));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
SwapBuffer();
}
base.Dispose(disposing);
}
public override void Close()
{
Dispose(disposing: true);
}
public override void Flush()
{
SwapBuffer();
}
public override long Seek(int offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void Write(sbyte value)
{
Write((byte)value);
}
public override void Write(byte[] buffer)
{
Write(buffer, 0, buffer.Length);
}
public unsafe override void Write(byte[] buffer, int index, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
fixed (byte* ptr = buffer)
{
byte* ptr2 = ptr + index;
while (SuplusCapacity <= count)
{
int num = (int)SuplusCapacity;
System.Runtime.CompilerServices.Unsafe.CopyBlock((void*)_curPos, (void*)ptr2, (uint)num);
count -= num;
ptr2 += num;
_curPos = _endPos;
SwapBuffer();
}
System.Runtime.CompilerServices.Unsafe.CopyBlock((void*)_curPos, (void*)ptr2, (uint)count);
_curPos += count;
}
}
public unsafe override void Write(char ch)
{
if (char.IsSurrogate(ch))
{
throw new ArgumentException("Arg_SurrogatesNotAllowedAsSingleChar");
}
CheckCapacityAndSwap(_maxBytesPerChar);
_curPos += _encoding.GetBytes(&ch, 1, _curPos, (int)SuplusCapacity);
}
public override void Write(char[] chars)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
byte[] bytes = _encoding.GetBytes(chars, 0, chars.Length);
Write(bytes);
}
public unsafe override void Write(double value)
{
CheckCapacityAndSwap(8);
ulong num = *(ulong*)(&value);
*(_curPos++) = (byte)num;
*(_curPos++) = (byte)(num >> 8);
*(_curPos++) = (byte)(num >> 16);
*(_curPos++) = (byte)(num >> 24);
*(_curPos++) = (byte)(num >> 32);
*(_curPos++) = (byte)(num >> 40);
*(_curPos++) = (byte)(num >> 48);
*(_curPos++) = (byte)(num >> 56);
}
public override void Write(decimal d)
{
CheckCapacityAndSwap(16);
int[] bits = decimal.GetBits(d);
Write(bits[0]);
Write(bits[1]);
Write(bits[2]);
Write(bits[3]);
}
public unsafe override void Write(short value)
{
CheckCapacityAndSwap(2);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
}
public unsafe override void Write(ushort value)
{
CheckCapacityAndSwap(2);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
}
public unsafe override void Write(int value)
{
if (SuplusCapacity < 4)
{
SwapBuffer();
}
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
}
public unsafe override void Write(uint value)
{
CheckCapacityAndSwap(4);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
}
public unsafe override void Write(long value)
{
CheckCapacityAndSwap(8);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
*(_curPos++) = (byte)(value >> 32);
*(_curPos++) = (byte)(value >> 40);
*(_curPos++) = (byte)(value >> 48);
*(_curPos++) = (byte)(value >> 56);
}
public unsafe override void Write(ulong value)
{
CheckCapacityAndSwap(8);
*(_curPos++) = (byte)value;
*(_curPos++) = (byte)(value >> 8);
*(_curPos++) = (byte)(value >> 16);
*(_curPos++) = (byte)(value >> 24);
*(_curPos++) = (byte)(value >> 32);
*(_curPos++) = (byte)(value >> 40);
*(_curPos++) = (byte)(value >> 48);
*(_curPos++) = (byte)(value >> 56);
}
public unsafe override void Write(float value)
{
CheckCapacityAndSwap(4);
uint num = *(uint*)(&value);
*(_curPos++) = (byte)num;
*(_curPos++) = (byte)(num >> 8);
*(_curPos++) = (byte)(num >> 16);
*(_curPos++) = (byte)(num >> 24);
}
public override void Write(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
byte[] bytes = _encoding.GetBytes(value);
Write7BitEncodedInt(bytes.Length);
Write(bytes);
}
private new void Write7BitEncodedInt(int value)
{
uint num;
for (num = (uint)value; num >= 128; num >>= 7)
{
Write((byte)(num | 0x80u));
}
Write((byte)num);
}
}
public class CompressionStream : Stream
{
public struct CompressBuffer
{
public byte[] ReadBuffer;
public byte[] WriteBuffer;
public byte[] OutBuffer;
}
private readonly WrapperDefines _wrapper;
public const int Mb = 1048576;
public readonly Stream OutStream;
private long _totalWrite;
private readonly bool _useMultiThread;
private DoubleBuffer _doubleBuffer;
private byte[] _outBuffer;
private IntPtr _cctx;
private long _lastError;
private bool _stopWorker = true;
private bool _closed;
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => _totalWrite;
public override long Position
{
get
{
return BufferWriter.WriteSum;
}
set
{
throw new NotImplementedException();
}
}
public BufferWriter BufferWriter { get; private set; }
public bool HasError()
{
return _lastError != 0;
}
private void HandleError(long errorCode)
{
if (errorCode < 0)
{
_wrapper.CompressContextFree(_cctx);
_cctx = IntPtr.Zero;
_lastError = errorCode;
throw new Exception(errorCode.ToString());
}
}
public static CompressBuffer CreateBuffer(int outBufferSize, int exBufferSize = 4194304)
{
try
{
CompressBuffer result = default(CompressBuffer);
result.OutBuffer = new byte[outBufferSize];
result.ReadBuffer = new byte[exBufferSize];
result.WriteBuffer = new byte[exBufferSize];
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return default(CompressBuffer);
}
public CompressionStream(WrapperDefines wrap, int compressionLevel, Stream outputStream, CompressBuffer compressBuffer, bool multiThread)
{
_wrapper = wrap;
OutStream = outputStream;
InitBuffer(compressBuffer.ReadBuffer, compressBuffer.WriteBuffer, compressBuffer.OutBuffer);
long num = _wrapper.CompressBegin(out _cctx, compressionLevel, _outBuffer, _outBuffer.Length, null, 0L);
HandleError(num);
outputStream.Write(_outBuffer, 0, (int)num);
_useMultiThread = multiThread;
if (multiThread)
{
_stopWorker = false;
new Thread(CompressAsync).Start();
}
}
private void InitBuffer(byte[] readBuffer, byte[] writeBuffer, byte[] outputBuffer)
{
_doubleBuffer = new DoubleBuffer(readBuffer ?? new byte[4194304], writeBuffer ?? new byte[4194304], Compress);
_outBuffer = outputBuffer ?? new byte[_wrapper.CompressBufferBound((writeBuffer != null) ? writeBuffer.Length : 4194304)];
BufferWriter = new BufferWriter(_doubleBuffer, this);
}
public override void Flush()
{
_doubleBuffer.SwapBuffer();
if (_useMultiThread)
{
_doubleBuffer.WaitReadEnd();
}
lock (_outBuffer)
{
OutStream.Flush();
}
}
private void Compress()
{
if (!_useMultiThread)
{
Compress_Internal();
}
}
private void Compress_Internal()
{
ByteSpan byteSpan = _doubleBuffer.ReadBegin();
if (byteSpan.Length > 0)
{
lock (_outBuffer)
{
long num;
try
{
num = _wrapper.CompressUpdateEx(_cctx, _outBuffer, 0L, byteSpan.Buffer, 0L, byteSpan.Length);
HandleError(num);
}
finally
{
_doubleBuffer.ReadEnd();
}
OutStream.Write(_outBuffer, 0, (int)num);
_totalWrite += num;
return;
}
}
_doubleBuffer.ReadEnd();
}
private void CompressAsync()
{
while (!_stopWorker)
{
Compress_Internal();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
BufferWriter.Write(buffer, offset, count);
}
private void FreeContext()
{
_wrapper.CompressContextFree(_cctx);
_cctx = IntPtr.Zero;
}
public override void Close()
{
if (!_closed)
{
BufferWriter.Close();
_closed = true;
Flush();
_stopWorker = true;
_doubleBuffer.SwapBuffer();
long num = _wrapper.CompressEnd(_cctx, _outBuffer, _outBuffer.Length);
OutStream.Write(_outBuffer, 0, (int)num);
base.Close();
}
}
protected override void Dispose(bool disposing)
{
FreeContext();
base.Dispose(disposing);
}
}
public class DecompressionStream : Stream
{
private readonly WrapperDefines _wrapper;
private readonly Stream _inStream;
private IntPtr _dctx = IntPtr.Zero;
private readonly ByteSpan _srcBuffer;
private readonly ByteSpan _dcmpBuffer;
private bool _decompressFinish;
private readonly long _startPos;
private long _readPos;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => _inStream.Length;
public override long Position
{
get
{
return _readPos;
}
set
{
if (value < _readPos)
{
ResetStream();
}
else
{
value -= _readPos;
}
byte[] buffer = new byte[1024];
while (value > 0)
{
value -= Read(buffer, 0, (int)((value < 1024) ? value : 1024));
}
}
}
public DecompressionStream(WrapperDefines wrap, Stream inputStream, int extraBufferSize = 524288)
{
_wrapper = wrap;
_inStream = inputStream;
_startPos = inputStream.Position;
_srcBuffer = new ByteSpan(new byte[extraBufferSize]);
int inBufferSize = Fill();
int blockSize;
long num = _wrapper.DecompressBegin(ref _dctx, _srcBuffer.Buffer, ref inBufferSize, out blockSize, null, 0L);
_srcBuffer.Position += inBufferSize;
if (num < 0)
{
throw new Exception(num.ToString());
}
_dcmpBuffer = new ByteSpan(new byte[blockSize]);
}
public void ResetStream()
{
_inStream.Seek(_startPos, SeekOrigin.Begin);
_decompressFinish = false;
_srcBuffer.Clear();
_dcmpBuffer.Clear();
_wrapper.DecompressContextReset(_dctx);
_readPos = 0L;
}
private int Fill()
{
int num = _srcBuffer.Length - _srcBuffer.Position;
if (_srcBuffer.Length > 0 && _srcBuffer.Position >= num)
{
Array.Copy((byte[])_srcBuffer, _srcBuffer.Position, (byte[])_srcBuffer, 0, num);
_srcBuffer.Length -= _srcBuffer.Position;
_srcBuffer.Position = 0;
}
if (_srcBuffer.IdleCapacity > 0)
{
int num2 = _inStream.Read(_srcBuffer, _srcBuffer.Length, _srcBuffer.IdleCapacity);
_srcBuffer.Length += num2;
}
return _srcBuffer.Length - _srcBuffer.Position;
}
public override void Flush()
{
}
protected override void Dispose(bool disposing)
{
_wrapper.DecompressEnd(_dctx);
_dctx = IntPtr.Zero;
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count)
{
int num = 0;
while (count > (num += _dcmpBuffer.Read(buffer, offset + num, count - num)) && !_decompressFinish)
{
int num2 = Fill();
if (num2 <= 0)
{
return num;
}
DecompressStatus decompressStatus = _wrapper.DecompressUpdateEx(_dctx, _dcmpBuffer, 0, _dcmpBuffer.Capacity, _srcBuffer, _srcBuffer.Position, num2);
if (decompressStatus.Expect < 0)
{
throw new Exception(decompressStatus.Expect.ToString());
}
if (decompressStatus.Expect == 0L)
{
_decompressFinish = true;
}
_srcBuffer.Position += (int)decompressStatus.ReadLen;
_dcmpBuffer.Position = 0;
_dcmpBuffer.Length = (int)decompressStatus.WriteLen;
}
_readPos += num;
return num;
}
public int PeekByte()
{
if (_dcmpBuffer.Length <= _dcmpBuffer.Position)
{
int num = Fill();
if (num <= 0)
{
return -1;
}
DecompressStatus decompressStatus = _wrapper.DecompressUpdateEx(_dctx, _dcmpBuffer, 0, _dcmpBuffer.Capacity, _srcBuffer, _srcBuffer.Position, num);
if (decompressStatus.Expect < 0)
{
throw new Exception(decompressStatus.Expect.ToString());
}
if (decompressStatus.Expect == 0L)
{
_decompressFinish = true;
}
_srcBuffer.Position += (int)decompressStatus.ReadLen;
_dcmpBuffer.Position = 0;
_dcmpBuffer.Length = (int)decompressStatus.WriteLen;
}
return _dcmpBuffer.Buffer[_dcmpBuffer.Position];
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
public class ByteSpan
{
public int Length;
public readonly int Capacity;
public int Position;
public byte[] Buffer { get; }
public int IdleCapacity => Capacity - Length;
public ByteSpan(byte[] buffer)
{
Buffer = buffer;
Capacity = Buffer.Length;
}
public void Clear()
{
Length = 0;
Position = 0;
}
public int Write(byte[] src, int offset, int count)
{
int num = Math.Min(Capacity - Length, count);
Array.Copy(src, offset, Buffer, Length, num);
Length += num;
return num;
}
public int Read(byte[] dst, int offset, int count)
{
count = Math.Min(Length - Position, count);
Array.Copy(Buffer, Position, dst, offset, count);
Position += count;
return count;
}
public static implicit operator byte[](ByteSpan bs)
{
return bs.Buffer;
}
}
public struct ReadOnlySpan
{
[CompilerGenerated]
private int <length>P;
private readonly byte[] _buffer;
private int _position;
public ReadOnlySpan(byte[] buffer, int length)
{
<length>P = length;
_buffer = buffer;
_position = 0;
}
public int Read(byte[] dst, int offset, int count)
{
count = Math.Min(<length>P - _position, count);
Array.Copy(_buffer, _position, dst, offset, count);
_position += count;
return count;
}
public static implicit operator byte[](ReadOnlySpan s)
{
return s._buffer;
}
}
public class DoubleBuffer
{
[CompilerGenerated]
private Action <onReadBufferReadyAction>P;
public const int Mb = 1048576;
public ByteSpan WriteBuffer;
private ByteSpan _readBuffer;
private ByteSpan _midBuffer;
private readonly Semaphore _readEnd;
private readonly Semaphore _writeEnd;
public DoubleBuffer(byte[] readingBuffer, byte[] writingBuffer, Action onReadBufferReadyAction)
{
<onReadBufferReadyAction>P = onReadBufferReadyAction;
WriteBuffer = new ByteSpan(writingBuffer);
_midBuffer = new ByteSpan(readingBuffer);
_readEnd = new Semaphore(1, 1);
_writeEnd = new Semaphore(0, 1);
base..ctor();
}
public ByteSpan ReadBegin()
{
_writeEnd.WaitOne();
return _readBuffer;
}
public void ReadEnd()
{
_readBuffer.Clear();
_midBuffer = _readBuffer;
_readBuffer = null;
_readEnd.Release();
}
public ByteSpan SwapBuffer(bool triggerEvent = true)
{
ByteSpan result = SwapBegin();
SwapEnd();
Action action = <onReadBufferReadyAction>P;
if (action != null)
{
action();
return result;
}
return result;
}
public void WaitReadEnd()
{
_readEnd.WaitOne();
_readEnd.Release();
}
private ByteSpan SwapBegin()
{
_readEnd.WaitOne();
_readBuffer = WriteBuffer;
WriteBuffer = _midBuffer;
_midBuffer = null;
return WriteBuffer;
}
private void SwapEnd()
{
_writeEnd.Release();
}
}
public class LZ4API : WrapperDefines
{
public static readonly bool Avaliable;
public static readonly LZ4API Instance;
static LZ4API()
{
Instance = new LZ4API();
try
{
Avaliable = Instance.ResolveDllImports("lz4wrap.dll");
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
}
public class NoneAPI : WrapperDefines
{
public static readonly bool Avaliable;
public static readonly NoneAPI Instance;
static NoneAPI()
{
Instance = new NoneAPI();
try
{
Avaliable = Instance.ResolveDllImports("nonewrap.dll");
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
}
internal class PeekableReader : BinaryReader
{
[CompilerGenerated]
private DecompressionStream <input>P;
public PeekableReader(DecompressionStream input)
{
<input>P = input;
base..ctor(<input>P);
}
public override int PeekChar()
{
return <input>P.PeekByte();
}
}
public static class WinApi
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);
}
public struct DecompressStatus
{
public long WriteLen;
public long ReadLen;
public long Expect;
}
public class WrapperDefines
{
public delegate long CompressBufferBoundFunc(long inBufferSize);
public delegate long CompressBeginFunc(out IntPtr ctx, int compressionLevel, byte[] outBuff, long outCapacity, byte[] dictBuffer = null, long dictSize = 0L);
public delegate long CompressEndFunc(IntPtr ctx, byte[] dstBuffer, long dstCapacity);
public delegate void CompressContextFreeFunc(IntPtr ctx);
public delegate long DecompressBeginFunc(ref IntPtr pdctx, byte[] inBuffer, ref int inBufferSize, out int blockSize, byte[] dict = null, long dictSize = 0L);
public delegate long DecompressEndFunc(IntPtr dctx);
public delegate void DecompressContextResetFunc(IntPtr dctx);
protected unsafe delegate long CompressUpdateFunc(IntPtr ctx, byte* dstBuffer, long dstCapacity, byte* srcBuffer, long srcSize);
protected unsafe delegate long DecompressUpdateFunc(IntPtr dctx, byte* dstBuffer, ref long dstCapacity, byte* srcBuffer, ref long srcSize);
public CompressBufferBoundFunc CompressBufferBound;
public CompressBeginFunc CompressBegin;
public CompressEndFunc CompressEnd;
public CompressContextFreeFunc CompressContextFree;
public DecompressBeginFunc DecompressBegin;
public DecompressEndFunc DecompressEnd;
public DecompressContextResetFunc DecompressContextReset;
protected CompressUpdateFunc CompressUpdate;
protected DecompressUpdateFunc DecompressUpdate;
public bool ResolveDllImports(string dllName)
{
string location = Assembly.GetAssembly(typeof(ZstdAPI)).Location;
string[] array;
if (string.IsNullOrEmpty(location))
{
array = new string[4]
{
dllName,
"x64/" + dllName,
"plugins/x64/" + dllName,
"BepInEx/scripts/x64/" + dllName
};
}
else
{
string path = Path.GetDirectoryName(location) ?? string.Empty;
array = new string[7]
{
dllName,
"x64/" + dllName,
"plugins/x64/" + dllName,
"BepInEx/scripts/x64/" + dllName,
Path.Combine(path, dllName),
Path.Combine(path, "x64/" + dllName),
Path.Combine(path, "plugins/x64/" + dllName)
};
}
string[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
IntPtr intPtr = WinApi.LoadLibrary(array2[i]);
if (!(intPtr == IntPtr.Zero))
{
CompressBufferBound = Marshal.GetDelegateForFunctionPointer<CompressBufferBoundFunc>(WinApi.GetProcAddress(intPtr, "CompressBufferBound"));
CompressBegin = Marshal.GetDelegateForFunctionPointer<CompressBeginFunc>(WinApi.GetProcAddress(intPtr, "CompressBegin"));
CompressEnd = Marshal.GetDelegateForFunctionPointer<CompressEndFunc>(WinApi.GetProcAddress(intPtr, "CompressEnd"));
CompressUpdate = Marshal.GetDelegateForFunctionPointer<CompressUpdateFunc>(WinApi.GetProcAddress(intPtr, "CompressUpdate"));
CompressContextFree = Marshal.GetDelegateForFunctionPointer<CompressContextFreeFunc>(WinApi.GetProcAddress(intPtr, "CompressContextFree"));
DecompressBegin = Marshal.GetDelegateForFunctionPointer<DecompressBeginFunc>(WinApi.GetProcAddress(intPtr, "DecompressBegin"));
DecompressEnd = Marshal.GetDelegateForFunctionPointer<DecompressEndFunc>(WinApi.GetProcAddress(intPtr, "DecompressEnd"));
DecompressUpdate = Marshal.GetDelegateForFunctionPointer<DecompressUpdateFunc>(WinApi.GetProcAddress(intPtr, "DecompressUpdate"));
DecompressContextReset = Marshal.GetDelegateForFunctionPointer<DecompressContextResetFunc>(WinApi.GetProcAddress(intPtr, "DecompressContextReset"));
if (CompressBufferBound != null && CompressBegin != null && CompressEnd != null && CompressUpdate != null && CompressContextFree != null && DecompressBegin != null && DecompressEnd != null && DecompressUpdate != null && DecompressContextReset != null)
{
return true;
}
WinApi.FreeLibrary(intPtr);
}
}
return false;
}
public unsafe long CompressUpdateEx(IntPtr ctx, byte[] dstBuffer, long dstOffset, byte[] srcBuffer, long srcOffset, long srcLen)
{
fixed (byte* ptr = dstBuffer)
{
fixed (byte* ptr2 = srcBuffer)
{
return CompressUpdate(ctx, ptr + dstOffset, dstBuffer.Length - dstOffset, ptr2 + srcOffset, srcLen - srcOffset);
}
}
}
public unsafe DecompressStatus DecompressUpdateEx(IntPtr dctx, byte[] dstBuffer, int dstOffset, int dstCount, byte[] srcBuffer, long srcOffset, long count)
{
long dstCapacity = Math.Min(dstCount, dstBuffer.Length - dstOffset);
long expect;
fixed (byte* ptr = dstBuffer)
{
fixed (byte* ptr2 = srcBuffer)
{
expect = DecompressUpdate(dctx, ptr + dstOffset, ref dstCapacity, ptr2 + srcOffset, ref count);
}
}
DecompressStatus result = default(DecompressStatus);
result.Expect = expect;
result.ReadLen = count;
result.WriteLen = dstCapacity;
return result;
}
}
public class ZstdAPI : WrapperDefines
{
public static readonly bool Avaliable;
public static readonly ZstdAPI Instance;
static ZstdAPI()
{
Instance = new ZstdAPI();
try
{
Avaliable = Instance.ResolveDllImports("zstdwrap.dll");
}
catch (Exception arg)
{
Avaliable = false;
Console.WriteLine($"Error: {arg}");
}
}
}
}
namespace CompressSave.UI
{
public class MyComboBox : MonoBehaviour
{
private RectTransform _rectTrans;
private UIComboBox _comboBox;
public Action<int> OnSelChanged;
private static GameObject _baseObject;
private EventHandler _configChanged;
private Action<int> _selChanged;
private ConfigEntry<int> _config;
public float Width => _rectTrans.sizeDelta.x;
public float Height => _rectTrans.sizeDelta.y;
public static void InitBaseObject()
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Expected O, but got Unknown
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)_baseObject))
{
return;
}
Transform obj = ((Component)UIRoot.instance.uiGame.buildMenu.uxFacilityCheck).transform.Find("text");
Text val = ((obj != null) ? ((Component)obj).GetComponent<Text>() : null);
GameObject val2 = Object.Instantiate<GameObject>(((Component)UIRoot.instance.optionWindow.resolutionComp).gameObject);
((Object)val2).name = "my-combobox";
val2.SetActive(false);
RectTransform val3 = (RectTransform)val2.transform;
UIComboBox component = ((Component)val3).GetComponent<UIComboBox>();
foreach (Button itemButton in component.ItemButtons)
{
Object.Destroy((Object)(object)((Component)itemButton).gameObject);
}
component.Items.Clear();
component.ItemButtons.Clear();
if (Object.op_Implicit((Object)(object)val))
{
Text componentInChildren = ((Component)component.m_ListItemRes).GetComponentInChildren<Text>();
if (Object.op_Implicit((Object)(object)componentInChildren))
{
componentInChildren.font = val.font;
componentInChildren.fontSize = val.fontSize;
componentInChildren.fontStyle = val.fontStyle;
}
Transform obj2 = ((Transform)val3).Find("Main Button/Text");
componentInChildren = ((obj2 != null) ? ((Component)obj2).GetComponent<Text>() : null);
if (Object.op_Implicit((Object)(object)componentInChildren))
{
componentInChildren.font = val.font;
componentInChildren.fontSize = val.fontSize;
componentInChildren.fontStyle = val.fontStyle;
}
}
((UnityEventBase)component.onSubmit).RemoveAllListeners();
((UnityEventBase)component.onItemIndexChange).RemoveAllListeners();
_baseObject = val2;
}
public static GameObject CreateComboBox(string name)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
if ((Object)(object)_baseObject == (Object)null)
{
InitBaseObject();
}
GameObject val = Object.Instantiate<GameObject>(_baseObject);
((Object)val).name = name;
val.SetActive(true);
MyComboBox cb = val.AddComponent<MyComboBox>();
cb._rectTrans = (RectTransform)val.transform;
UIComboBox box = ((Component)cb._rectTrans).GetComponent<UIComboBox>();
cb._comboBox = box;
((UnityEvent)box.onItemIndexChange).AddListener((UnityAction)delegate
{
cb.OnSelChanged?.Invoke(box.itemIndex);
});
return val;
}
protected void OnDestroy()
{
_config.SettingChanged -= _configChanged;
}
public void SetFontSize(int size)
{
_comboBox.ItemButtons.ForEach(delegate(Button b)
{
((Component)b).GetComponentInChildren<Text>().fontSize = size;
});
((Component)_comboBox.m_ListItemRes).GetComponentInChildren<Text>().fontSize = size;
Transform obj = ((Component)_comboBox).transform.Find("Main Button");
Text val = ((obj != null) ? ((Component)obj).GetComponentInChildren<Text>() : null);
if (Object.op_Implicit((Object)(object)val))
{
val.fontSize = size;
}
}
public void SetItems(params string[] items)
{
_comboBox.Items = items.Select((string s) => Localization.Translate(s)).ToList();
_comboBox.StartItemIndex = 0;
_comboBox.DropDownCount = Math.Min(items.Length, 8);
}
public void SetIndex(int index)
{
_comboBox.itemIndex = index;
}
public void SetSize(float width, float height)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = (RectTransform)((Component)_comboBox).transform;
val.sizeDelta = new Vector2((width > 0f) ? width : val.sizeDelta.x, (height > 0f) ? height : val.sizeDelta.y);
_rectTrans.sizeDelta = new Vector2(((Transform)val).localPosition.x + val.sizeDelta.x, _rectTrans.sizeDelta.y);
}
public void AddOnSelChanged(Action<int> action)
{
OnSelChanged = (Action<int>)Delegate.Combine(OnSelChanged, action);
}
public void SetConfigEntry(ConfigEntry<int> config)
{
if (_selChanged != null)
{
OnSelChanged = (Action<int>)Delegate.Remove(OnSelChanged, _selChanged);
}
if (_configChanged != null)
{
config.SettingChanged -= _configChanged;
}
_comboBox.itemIndex = config.Value;
_config = config;
_selChanged = delegate(int value)
{
config.Value = value;
};
OnSelChanged = (Action<int>)Delegate.Combine(OnSelChanged, _selChanged);
_configChanged = delegate
{
SetIndex(config.Value);
};
config.SettingChanged += _configChanged;
}
public MyComboBox WithFontSize(int size)
{
SetFontSize(size);
return this;
}
public MyComboBox WithItems(params string[] items)
{
SetItems(items);
return this;
}
public MyComboBox WithIndex(int index)
{
SetIndex(index);
return this;
}
public MyComboBox WithSize(float width, float height)
{
SetSize(width, height);
return this;
}
public MyComboBox WithOnSelChanged(params Action<int>[] action)
{
foreach (Action<int> action2 in action)
{
AddOnSelChanged(action2);
}
return this;
}
public MyComboBox WithConfigEntry(ConfigEntry<int> config)
{
SetConfigEntry(config);
return this;
}
}
}