diff --git a/CompressSave/CompressSave.cs b/CompressSave/CompressSave.cs index cd51bfe..6d98b6f 100644 --- a/CompressSave/CompressSave.cs +++ b/CompressSave/CompressSave.cs @@ -26,8 +26,8 @@ public class CompressSave : BaseUnityPlugin { case CompressionType.LZ4: return "lz4"; case CompressionType.Zstd: return "zstd"; - case CompressionType.None: - default: return "none"; + case CompressionType.None: return "none"; + default: throw new ArgumentException("Unknown compression type."); } } @@ -48,7 +48,7 @@ public class CompressSave : BaseUnityPlugin { PatchSave.CompressionTypeForSaves = CompressionTypeFromString( Config.Bind("Compression", "Type", StringFromCompresstionType(PatchSave.CompressionTypeForSaves), - new ConfigDescription("Set default compression type.", + new ConfigDescription("Set default compression type for manual saves.", new AcceptableValueList("lz4", "zstd", "none"), new { })) .Value); PatchSave.CompressionLevelForSaves = Config.Bind("Compression", "Level", PatchSave.CompressionLevelForSaves, @@ -62,7 +62,7 @@ public class CompressSave : BaseUnityPlugin } patchSave = Harmony.CreateAndPatchAll(typeof(PatchSave)); - if (PatchSave.EnableCompress && PatchSave.CompressionTypeForSaves != CompressionType.None) + if (PatchSave.EnableCompress) patchUISave = Harmony.CreateAndPatchAll(typeof(PatchUISaveGame)); patchUILoad = Harmony.CreateAndPatchAll(typeof(PatchUILoadGame)); } @@ -88,36 +88,51 @@ public class CompressSave : BaseUnityPlugin class PatchSave { - public static readonly WrapperDefines LZ4Wrapper = new LZ4API(), ZstdWrapper = new ZstdAPI(); + public static readonly WrapperDefines LZ4Wrapper = new LZ4API(), ZstdWrapper = new ZstdAPI(), NoneWrapper = new NoneAPI(); private const long SizeInMBytes = 1024 * 1024; private static CompressionStream.CompressBuffer _compressBuffer; public static bool UseCompressSave; - private static CompressionType _compressedType = CompressionType.None; - public static CompressionType CompressionTypeForSaves = CompressionType.LZ4; + private static CompressionType _compressionTypeForLoading = CompressionType.None; + public static CompressionType CompressionTypeForSaves = CompressionType.Zstd; public static int CompressionLevelForSaves; private static Stream _compressionStream; public static bool EnableCompress; public static void CreateCompressBuffer() { - _compressBuffer = - CompressionStream.CreateBuffer(CompressionTypeForSaves == CompressionType.LZ4 ? LZ4Wrapper : ZstdWrapper, - (int)SizeInMBytes); //Bigger buffer for GS2 compatible + switch (CompressionTypeForSaves) + { + case CompressionType.LZ4: + _compressBuffer = CompressionStream.CreateBuffer(LZ4Wrapper, (int)SizeInMBytes); + break; + case CompressionType.Zstd: + _compressBuffer = CompressionStream.CreateBuffer(ZstdWrapper, (int)SizeInMBytes); + break; + case CompressionType.None: + _compressBuffer = CompressionStream.CreateBuffer(NoneWrapper, (int)SizeInMBytes); + break; + default: + throw new ArgumentException("Unknown compression type."); + } } private static void WriteHeader(FileStream fileStream) { - for (int i = 0; i < 3; i++) - fileStream.WriteByte(0xCC); switch (CompressionTypeForSaves) { case CompressionType.Zstd: + for (int i = 0; i < 3; i++) + fileStream.WriteByte(0xCC); fileStream.WriteByte(0xCD); break; case CompressionType.LZ4: - default: - fileStream.WriteByte(0xCC); + for (int i = 0; i < 4; i++) + fileStream.WriteByte(0xCC); break; + case CompressionType.None: + break; + default: + throw new ArgumentException("Unknown compression type."); } } @@ -126,7 +141,7 @@ class PatchSave [HarmonyPatch(typeof(GameSave), "SaveAsLastExit")] static void BeforeAutoSave() { - UseCompressSave = EnableCompress && CompressionTypeForSaves != CompressionType.None; + UseCompressSave = EnableCompress; } [HarmonyTranspiler] @@ -160,7 +175,7 @@ class PatchSave new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IDisposable), "Dispose"))) .Advance(1) .Insert(new CodeInstruction(OpCodes.Call, - AccessTools.Method(typeof(PatchSave), "DisposecompressionStream"))); + AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream"))); EnableCompress = true; return matcher.InstructionEnumeration(); } @@ -185,9 +200,19 @@ class PatchSave { SaveUtil.logger.LogDebug("Begin compress save"); WriteHeader(fileStream); - _compressionStream = - new CompressionStream(CompressionTypeForSaves == CompressionType.LZ4 ? LZ4Wrapper : ZstdWrapper, - CompressionLevelForSaves, fileStream, _compressBuffer, true); //need to dispose after use + switch (CompressionTypeForSaves) + { + case CompressionType.LZ4: + _compressionStream = new CompressionStream(LZ4Wrapper, CompressionLevelForSaves, fileStream, _compressBuffer, true); + break; + case CompressionType.Zstd: + _compressionStream = new CompressionStream(ZstdWrapper, CompressionLevelForSaves, fileStream, _compressBuffer, true); + break; + case CompressionType.None: + _compressionStream = new CompressionStream(NoneWrapper, 0, fileStream, _compressBuffer, true); + break; + } + return ((CompressionStream)_compressionStream).BufferWriter; } @@ -198,24 +223,49 @@ class PatchSave 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() + public static void DisposeCompressionStream() { if (!UseCompressSave) return; + if (_compressionStream == null) + { + UseCompressSave = false; + return; + } var writeflag = _compressionStream.CanWrite; - _compressionStream?.Dispose(); //Dispose need to be done before fstream closed. + Stream stream = null; + if (writeflag && CompressionTypeForSaves == CompressionType.None) + { + stream = ((CompressionStream)_compressionStream).outStream; + } + _compressionStream.Dispose(); //Dispose need to be done before fstream closed. _compressionStream = null; if (writeflag) //Reset UseCompressSave after writing to file + { + 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(); + } UseCompressSave = false; + } } [HarmonyTranspiler] @@ -253,7 +303,7 @@ class PatchSave new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IDisposable), "Dispose"))) .Advance(1) .Insert(new CodeInstruction(OpCodes.Call, - AccessTools.Method(typeof(PatchSave), "DisposecompressionStream"))) + AccessTools.Method(typeof(PatchSave), "DisposeCompressionStream"))) .MatchBack(false, new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(System.IO.Stream), "Seek"))); if (matcher.IsValid) @@ -273,14 +323,15 @@ class PatchSave public static BinaryReader CreateBinaryReader(FileStream fileStream) { - switch (_compressedType = SaveUtil.SaveGetCompressType(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(_compressedType == CompressionType.LZ4 ? LZ4Wrapper : ZstdWrapper, - fileStream); + _compressionStream = new DecompressionStream(ZstdWrapper, fileStream); return new PeekableReader((DecompressionStream)_compressionStream); case CompressionType.None: UseCompressSave = false; @@ -293,21 +344,22 @@ class PatchSave public static long FileLengthRead(BinaryReader binaryReader) { - switch (_compressedType) + switch (_compressionTypeForLoading) { case CompressionType.LZ4: case CompressionType.Zstd: binaryReader.ReadInt64(); return _compressionStream.Length; case CompressionType.None: - default: return binaryReader.ReadInt64(); + default: + throw new ArgumentOutOfRangeException(); } } public static long ReadSeek(FileStream fileStream, long offset, SeekOrigin origin) { - switch (_compressedType) + switch (_compressionTypeForLoading) { case CompressionType.LZ4: case CompressionType.Zstd: @@ -315,8 +367,9 @@ class PatchSave offset -= _compressionStream.Read(_compressBuffer.outBuffer, 0, (int)offset); return _compressionStream.Position; case CompressionType.None: - default: return fileStream.Seek(offset, origin); + default: + throw new ArgumentOutOfRangeException(); } } } \ No newline at end of file diff --git a/CompressSave/LZ4WrapC/CMakeLists.txt b/CompressSave/LZ4WrapC/CMakeLists.txt index a464024..d726611 100644 --- a/CompressSave/LZ4WrapC/CMakeLists.txt +++ b/CompressSave/LZ4WrapC/CMakeLists.txt @@ -7,7 +7,7 @@ add_library(lz4wrap SHARED lz4/lz4frame.c lz4/lz4frame.h lz4/lz4frame_static.h lz4/lz4hc.c lz4/lz4hc.h lz4/xxhash.c lz4/xxhash.h - dllmain.c lz4wrap.c lz4wrap.h) + dllmain.c LZ4Wrap.c LZ4Wrap.h) target_compile_definitions(lz4wrap PRIVATE LZ4WRAP_EXPORTS) target_include_directories(lz4wrap PRIVATE lz4) diff --git a/CompressSave/LZ4WrapC/dllmain.c b/CompressSave/LZ4WrapC/dllmain.c index 52d4ad2..896c9b5 100644 --- a/CompressSave/LZ4WrapC/dllmain.c +++ b/CompressSave/LZ4WrapC/dllmain.c @@ -9,6 +9,8 @@ BOOL APIENTRY DllMain( HMODULE hModule, switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: @@ -16,4 +18,3 @@ BOOL APIENTRY DllMain( HMODULE hModule, } return TRUE; } - diff --git a/CompressSave/PatchUISaveGame.cs b/CompressSave/PatchUISaveGame.cs index 9788c1a..4cdc4f4 100644 --- a/CompressSave/PatchUISaveGame.cs +++ b/CompressSave/PatchUISaveGame.cs @@ -68,23 +68,24 @@ static class PatchUISaveGame [HarmonyPatch(typeof(UISaveGameWindow), "_OnOpen"), HarmonyPostfix] static void _OnOpen(UISaveGameWindow __instance, UIButton ___saveButton, Text ___saveButtonText) { - if (!context.buttonCompress) - { - context.saveButton = ___saveButton; - context.saveButtonText = ___saveButtonText; + if (context.buttonCompress) return; + context.saveButton = ___saveButton; + context.saveButtonText = ___saveButtonText; - context.ui = __instance; - context.buttonCompress = (__instance.transform.Find("button-compress")?.gameObject??GameObject.Instantiate(___saveButton.gameObject, ___saveButton.transform.parent)).GetComponent(); - - 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(); + context.ui = __instance; + context.buttonCompress = + (__instance.transform.Find("button-compress")?.gameObject ?? + GameObject.Instantiate(___saveButton.gameObject, ___saveButton.transform.parent)) + .GetComponent(); - context.buttonCompress.onClick += __instance.OnSaveClick; - context.saveButton.onClick -= __instance.OnSaveClick; - context.saveButton.onClick += WrapClick; - } + 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(); + + context.buttonCompress.onClick += __instance.OnSaveClick; + context.saveButton.onClick -= __instance.OnSaveClick; + context.saveButton.onClick += WrapClick; } static void WrapClick(int data) diff --git a/CompressSave/Wrapper/CompressionStream.cs b/CompressSave/Wrapper/CompressionStream.cs index 351705f..f18afb6 100644 --- a/CompressSave/Wrapper/CompressionStream.cs +++ b/CompressSave/Wrapper/CompressionStream.cs @@ -20,7 +20,7 @@ public class CompressionStream : Stream // only use for game statistics public override long Position { get => BufferWriter.WriteSum; set => new NotImplementedException(); } - readonly Stream outStream; + public readonly Stream outStream; long totalWrite = 0; bool useMultiThread; @@ -62,7 +62,7 @@ public class CompressionStream : Stream { return new CompressBuffer { - outBuffer = new byte[wrapper.CompressBufferBound(ExBufferSize) + 1], + outBuffer = new byte[wrapper.CompressBufferBound(ExBufferSize)], readBuffer = new byte[ExBufferSize], writeBuffer = new byte[ExBufferSize], }; @@ -74,19 +74,18 @@ public class CompressionStream : Stream return new CompressBuffer(); } - public BufferWriter BufferWriter => bfferWriter; - BufferWriter bfferWriter; + public BufferWriter BufferWriter { get; private set; } - public CompressionStream(WrapperDefines wrap, int compressionLevel, Stream outStream, CompressBuffer compressBuffer, bool useMultiThread) + public CompressionStream(WrapperDefines wrap, int compressionLevel, Stream outputStream, CompressBuffer compressBuffer, bool multiThread) { - this.wrapper = wrap; - this.outStream = outStream; + wrapper = wrap; + outStream = outputStream; InitBuffer(compressBuffer.readBuffer, compressBuffer.writeBuffer, compressBuffer.outBuffer); long writeSize = wrapper.CompressBegin(out cctx, compressionLevel, outBuffer, outBuffer.Length); HandleError(writeSize); - outStream.Write(outBuffer, 0, (int)writeSize); - this.useMultiThread = useMultiThread; - if(useMultiThread) + outputStream.Write(outBuffer, 0, (int)writeSize); + useMultiThread = multiThread; + if(multiThread) { stopWorker = false; compressThread = new Thread(() => CompressAsync()); @@ -98,7 +97,7 @@ public class CompressionStream : Stream { doubleBuffer = new DoubleBuffer(readBuffer ?? new byte[4 * MB], writeBuffer ?? new byte[4 * MB], Compress); this.outBuffer = outBuffer ?? new byte[wrapper.CompressBufferBound(writeBuffer.Length)]; - bfferWriter = new BufferWriter(doubleBuffer,this); + BufferWriter = new BufferWriter(doubleBuffer,this); } public override void Flush() diff --git a/CompressSave/Wrapper/DecompressionStream.cs b/CompressSave/Wrapper/DecompressionStream.cs index 3c44b73..29ed050 100644 --- a/CompressSave/Wrapper/DecompressionStream.cs +++ b/CompressSave/Wrapper/DecompressionStream.cs @@ -15,8 +15,9 @@ public class DecompressionStream : Stream public override long Length => inStream.Length; - public override long Position - { get => readPos; + public override long Position + { + get => readPos; set { if (value < readPos) @@ -28,7 +29,7 @@ public class DecompressionStream : Stream { value -= Read(tmpBuffer, 0, (int)(value < 1024 ? value : 1024)); } - } + } } public Stream inStream; @@ -41,11 +42,11 @@ public class DecompressionStream : Stream readonly long startPos = 0; long readPos = 0; //sum of readlen - public DecompressionStream(WrapperDefines wrap, Stream inStream,int extraBufferSize = 512*1024) + public DecompressionStream(WrapperDefines wrap, Stream inputStream, int extraBufferSize = 512 * 1024) { - this.wrapper = wrap; - this.inStream = inStream; - startPos = inStream.Position; + wrapper = wrap; + inStream = inputStream; + startPos = inputStream.Position; srcBuffer = new ByteSpan(new byte[extraBufferSize]); int len = Fill(); long expect = wrapper.DecompressBegin(ref dctx, srcBuffer.Buffer, ref len, out var blockSize); @@ -67,23 +68,24 @@ public class DecompressionStream : Stream public int Fill() { int suplus = srcBuffer.Length - srcBuffer.Position; - if (srcBuffer.Length> 0 && srcBuffer.Position >= suplus) + if (srcBuffer.Length > 0 && srcBuffer.Position >= suplus) { Array.Copy(srcBuffer, srcBuffer.Position, srcBuffer, 0, suplus); srcBuffer.Length -= srcBuffer.Position; srcBuffer.Position = 0; } + if (srcBuffer.IdleCapacity > 0) { var readlen = inStream.Read(srcBuffer, srcBuffer.Length, srcBuffer.IdleCapacity); srcBuffer.Length += readlen; } + return srcBuffer.Length - srcBuffer.Position; } public override void Flush() { - } protected override void Dispose(bool disposing) @@ -101,7 +103,8 @@ public class DecompressionStream : Stream var buffSize = Fill(); if (buffSize <= 0) return readlen; - var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position,buffSize); + var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position, + buffSize); if (rt.Expect < 0) throw new Exception(rt.Expect.ToString()); if (rt.Expect == 0) decompressFinish = true; @@ -109,6 +112,7 @@ public class DecompressionStream : Stream dcmpBuffer.Position = 0; dcmpBuffer.Length = (int)rt.WriteLen; } + readPos += readlen; return readlen; } @@ -120,7 +124,8 @@ public class DecompressionStream : Stream var buffSize = Fill(); if (buffSize <= 0) return -1; - var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position, buffSize); + var rt = wrapper.DecompressUpdateEx(dctx, dcmpBuffer, 0, dcmpBuffer.Capacity, srcBuffer, srcBuffer.Position, + buffSize); if (rt.Expect < 0) throw new Exception(rt.Expect.ToString()); if (rt.Expect == 0) decompressFinish = true; @@ -128,6 +133,7 @@ public class DecompressionStream : Stream dcmpBuffer.Position = 0; dcmpBuffer.Length = (int)rt.WriteLen; } + return dcmpBuffer.Buffer[dcmpBuffer.Position]; } diff --git a/CompressSave/Wrapper/DoubleBuffer.cs b/CompressSave/Wrapper/DoubleBuffer.cs index f91de2f..b561448 100644 --- a/CompressSave/Wrapper/DoubleBuffer.cs +++ b/CompressSave/Wrapper/DoubleBuffer.cs @@ -77,11 +77,11 @@ public class DoubleBuffer Semaphore readEnd = new Semaphore(1, 1); Semaphore writeEnd = new Semaphore(0, 1); - public DoubleBuffer(byte[] readBuffer, byte[] writeBuffer, Action onReadBufferReady) + public DoubleBuffer(byte[] readingBuffer, byte[] writingBuffer, Action onReadBufferReadyAction) { - this.onReadBufferReady = onReadBufferReady; - this.midBuffer = new ByteSpan(readBuffer); - this.writeBuffer = new ByteSpan(writeBuffer); + onReadBufferReady = onReadBufferReadyAction; + midBuffer = new ByteSpan(readingBuffer); + writeBuffer = new ByteSpan(writingBuffer); } public ByteSpan ReadBegin() diff --git a/CompressSave/Wrapper/NoneWrapper.cs b/CompressSave/Wrapper/NoneWrapper.cs new file mode 100644 index 0000000..4d82456 --- /dev/null +++ b/CompressSave/Wrapper/NoneWrapper.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; +using MonoMod.Utils; + +namespace CompressSave.Wrapper; + +public class NoneAPI: WrapperDefines +{ + public static readonly bool Avaliable; + + static NoneAPI() + { + Avaliable = true; + string assemblyPath = System.Reflection.Assembly.GetAssembly(typeof(NoneAPI)).Location; + string root = string.Empty; + try + { + if (!string.IsNullOrEmpty(assemblyPath)) + { + root = Path.GetDirectoryName(assemblyPath) ?? string.Empty; + } + + var map = new Dictionary> + { + { + "nonewrap.dll", new List + { + "nonewrap.dll", + "X64/nonewrap.dll", + "BepInEx/scripts/x64/nonewrap.dll", + Path.Combine(root, "X64/nonewrap.dll"), + Path.Combine(root, "nonewrap.dll") + } + }, + }; + typeof(NoneAPI).ResolveDynDllImports(map); + } + catch (Exception e) + { + Avaliable = false; + Console.WriteLine($"Error: {e}"); + } + } + + public NoneAPI() + { + CompressBufferBound = CompressBufferBound_; + CompressBegin = CompressBegin_; + CompressEnd = CompressEnd_; + CompressUpdate = CompressUpdate_; + CompressContextFree = CompressContextFree_; + DecompressBegin = DecompressBegin_; + DecompressEnd = DecompressEnd_; + DecompressUpdate = DecompressUpdate_; + DecompressContextReset = DecompressContextReset_; + } + + [DynDllImport(libraryName: "nonewrap.dll", "CompressBufferBound")] protected static CompressBufferBoundFunc CompressBufferBound_; + [DynDllImport(libraryName: "nonewrap.dll", "CompressBegin")] protected static CompressBeginFunc CompressBegin_; + [DynDllImport(libraryName: "nonewrap.dll", "CompressEnd")] protected static CompressEndFunc CompressEnd_; + [DynDllImport(libraryName: "nonewrap.dll", "CompressUpdate")] protected static CompressUpdateFunc CompressUpdate_; + [DynDllImport(libraryName: "nonewrap.dll", "CompressContextFree")] protected static CompressContextFreeFunc CompressContextFree_; + [DynDllImport(libraryName: "nonewrap.dll", "DecompressBegin")] protected static DecompressBeginFunc DecompressBegin_; + [DynDllImport(libraryName: "nonewrap.dll", "DecompressEnd")] protected static DecompressEndFunc DecompressEnd_; + [DynDllImport(libraryName: "nonewrap.dll", "DecompressUpdate")] protected static DecompressUpdateFunc DecompressUpdate_; + [DynDllImport(libraryName: "nonewrap.dll", "DecompressContextReset")] protected static DecompressContextResetFunc DecompressContextReset_; +} diff --git a/CompressSave/ZstdWrapC/CMakeLists.txt b/CompressSave/ZstdWrapC/CMakeLists.txt index b5c5c27..98c364c 100644 --- a/CompressSave/ZstdWrapC/CMakeLists.txt +++ b/CompressSave/ZstdWrapC/CMakeLists.txt @@ -2,10 +2,15 @@ cmake_minimum_required(VERSION 3.2) project(zstdwrap) -add_library(LZ4 SHARED +add_library(zstdwrap SHARED dllmain.c zstdwrap.c zstdwrap.h) target_compile_definitions(zstdwrap PRIVATE ZSTDWRAP_EXPORTS ZSTDLIB_STATIC_API) +if(MSVC) + target_compile_options(zstdwrap PRIVATE /MT) +else() + target_link_options(zstdwrap PRIVATE -static) +endif() target_link_libraries(zstdwrap PRIVATE zstd) if(WIN32) set_target_properties(zstdwrap PROPERTIES PREFIX "") diff --git a/CompressSave/ZstdWrapC/dllmain.c b/CompressSave/ZstdWrapC/dllmain.c index 52d4ad2..896c9b5 100644 --- a/CompressSave/ZstdWrapC/dllmain.c +++ b/CompressSave/ZstdWrapC/dllmain.c @@ -9,6 +9,8 @@ BOOL APIENTRY DllMain( HMODULE hModule, switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: @@ -16,4 +18,3 @@ BOOL APIENTRY DllMain( HMODULE hModule, } return TRUE; } - diff --git a/CompressSave/package/plugins/x64/nonewrap.dll b/CompressSave/package/plugins/x64/nonewrap.dll new file mode 100644 index 0000000..846e38f Binary files /dev/null and b/CompressSave/package/plugins/x64/nonewrap.dll differ