diff --git a/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40.meta b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40.meta new file mode 100644 index 0000000..e7f046c --- /dev/null +++ b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1cd43f2247d29084fa2b393c30648e64 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Mac.dll b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Mac.dll new file mode 100644 index 0000000..2cce7a7 Binary files /dev/null and b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Mac.dll differ diff --git a/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Win.dll b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Win.dll new file mode 100644 index 0000000..17135a1 Binary files /dev/null and b/Assets/01.HybridCLR/Data~/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP-Win.dll differ diff --git a/Assets/01.HybridCLR/Data~/Templates/AssemblyManifest.cpp.tpl b/Assets/01.HybridCLR/Data~/Templates/AssemblyManifest.cpp.tpl new file mode 100644 index 0000000..d43977d --- /dev/null +++ b/Assets/01.HybridCLR/Data~/Templates/AssemblyManifest.cpp.tpl @@ -0,0 +1,12 @@ +#include "../Il2CppCompatibleDef.h" + +namespace hybridclr +{ + const char* g_placeHolderAssemblies[] = + { + //!!!{{PLACE_HOLDER + + //!!!}}PLACE_HOLDER + nullptr, + }; +} diff --git a/Assets/01.HybridCLR/Data~/Templates/MethodBridge.cpp.tpl b/Assets/01.HybridCLR/Data~/Templates/MethodBridge.cpp.tpl new file mode 100644 index 0000000..b723a16 --- /dev/null +++ b/Assets/01.HybridCLR/Data~/Templates/MethodBridge.cpp.tpl @@ -0,0 +1,32 @@ +#include +#if HYBRIDCLR_UNITY_2023_OR_NEW +#include +#elif HYBRIDCLR_UNITY_2022 +#include +#elif HYBRIDCLR_UNITY_2020 || HYBRIDCLR_UNITY_2021 +#include +#else +#include +#endif + +#include "vm/ClassInlines.h" +#include "vm/Object.h" +#include "vm/Class.h" +#include "vm/ScopedThreadAttacher.h" + +#include "../metadata/MetadataUtil.h" + + +#include "../interpreter/InterpreterModule.h" +#include "../interpreter/MethodBridge.h" +#include "../interpreter/Interpreter.h" +#include "../interpreter/MemoryUtil.h" +#include "../interpreter/InstrinctDef.h" + +using namespace hybridclr::interpreter; +using namespace hybridclr::metadata; + +//!!!{{CODE + + +//!!!}}CODE diff --git a/Assets/01.HybridCLR/Data~/Templates/UnityVersion.h.tpl b/Assets/01.HybridCLR/Data~/Templates/UnityVersion.h.tpl new file mode 100644 index 0000000..f0fddb8 --- /dev/null +++ b/Assets/01.HybridCLR/Data~/Templates/UnityVersion.h.tpl @@ -0,0 +1,6 @@ +#pragma once + +//!!!{{UNITY_VERSION + + +//!!!}}UNITY_VERSION \ No newline at end of file diff --git a/Assets/01.HybridCLR/Data~/hybridclr_version.json b/Assets/01.HybridCLR/Data~/hybridclr_version.json index 6a1e92e..9216c45 100644 --- a/Assets/01.HybridCLR/Data~/hybridclr_version.json +++ b/Assets/01.HybridCLR/Data~/hybridclr_version.json @@ -1,19 +1,39 @@ { "versions": [ + { + "unity_version":"2019", + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2019-8.1.0"} + }, { "unity_version":"2020", - "hybridclr" : { "branch":"v4.0.10"}, - "il2cpp_plus": { "branch":"v2020-4.0.8"} + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2020-8.1.0"} }, { "unity_version":"2021", - "hybridclr" : { "branch":"v4.0.10"}, - "il2cpp_plus": { "branch":"v2021-4.0.8"} + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2021-8.1.0"} }, { "unity_version":"2022", - "hybridclr" : { "branch":"v4.0.10"}, - "il2cpp_plus": { "branch":"v2022-4.0.8"} + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2022-8.2.0"} + }, + { + "unity_version":"2022-tuanjie", + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2022-tuanjie-8.1.0"} + }, + { + "unity_version":"2023", + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v2023-8.1.0"} + }, + { + "unity_version":"6000", + "hybridclr" : { "branch":"v8.2.0"}, + "il2cpp_plus": { "branch":"v6000-8.1.0"} } ] } \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/3rds.meta b/Assets/01.HybridCLR/Editor/3rds.meta index cc657ec..5f5d553 100644 --- a/Assets/01.HybridCLR/Editor/3rds.meta +++ b/Assets/01.HybridCLR/Editor/3rds.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f86d53f7465f6e9479871eb3d74d16b2 +guid: daa1e09af240aae4da0741843cb2b3f3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip.meta b/Assets/01.HybridCLR/Editor/3rds/7zip.meta new file mode 100644 index 0000000..48fedff --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08f44f6e8bfbc2c45afae7bdd2d7f21f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Common.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Common.meta new file mode 100644 index 0000000..0e4cc9e --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5cedddbfa873eb94496b496e2a3ce8aa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs new file mode 100644 index 0000000..d03fcec --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs @@ -0,0 +1,55 @@ +// Common/CRC.cs + +namespace SevenZip +{ + public class CRC + { + public static readonly uint[] Table; + + static CRC() + { + Table = new uint[256]; + const uint kPoly = 0xEDB88320; + for (uint i = 0; i < 256; i++) + { + uint r = i; + for (int j = 0; j < 8; j++) + if ((r & 1) != 0) + r = (r >> 1) ^ kPoly; + else + r >>= 1; + Table[i] = r; + } + } + + uint _value = 0xFFFFFFFF; + + public void Init() { _value = 0xFFFFFFFF; } + + public void UpdateByte(byte b) + { + _value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8); + } + + public void Update(byte[] data, uint offset, uint size) + { + for (uint i = 0; i < size; i++) + _value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8); + } + + public uint GetDigest() { return _value ^ 0xFFFFFFFF; } + + static uint CalculateDigest(byte[] data, uint offset, uint size) + { + CRC crc = new CRC(); + // crc.Init(); + crc.Update(data, offset, size); + return crc.GetDigest(); + } + + static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) + { + return (CalculateDigest(data, offset, size) == digest); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs.meta similarity index 83% rename from Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs.meta rename to Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs.meta index 92a9e71..e366fdf 100644 --- a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CRC.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f89249210a6c2bc45bb99608657b6af6 +guid: d0bb58ecc915d9d47b8567adaa2d0ca6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs new file mode 100644 index 0000000..8eabf59 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs @@ -0,0 +1,274 @@ +// CommandLineParser.cs + +using System; +using System.Collections; + +namespace SevenZip.CommandLineParser +{ + public enum SwitchType + { + Simple, + PostMinus, + LimitedPostString, + UnLimitedPostString, + PostChar + } + + public class SwitchForm + { + public string IDString; + public SwitchType Type; + public bool Multi; + public int MinLen; + public int MaxLen; + public string PostCharSet; + + public SwitchForm(string idString, SwitchType type, bool multi, + int minLen, int maxLen, string postCharSet) + { + IDString = idString; + Type = type; + Multi = multi; + MinLen = minLen; + MaxLen = maxLen; + PostCharSet = postCharSet; + } + public SwitchForm(string idString, SwitchType type, bool multi, int minLen): + this(idString, type, multi, minLen, 0, "") + { + } + public SwitchForm(string idString, SwitchType type, bool multi): + this(idString, type, multi, 0) + { + } + } + + public class SwitchResult + { + public bool ThereIs; + public bool WithMinus; + public ArrayList PostStrings = new ArrayList(); + public int PostCharIndex; + public SwitchResult() + { + ThereIs = false; + } + } + + public class Parser + { + public ArrayList NonSwitchStrings = new ArrayList(); + SwitchResult[] _switches; + + public Parser(int numSwitches) + { + _switches = new SwitchResult[numSwitches]; + for (int i = 0; i < numSwitches; i++) + _switches[i] = new SwitchResult(); + } + + bool ParseString(string srcString, SwitchForm[] switchForms) + { + int len = srcString.Length; + if (len == 0) + return false; + int pos = 0; + if (!IsItSwitchChar(srcString[pos])) + return false; + while (pos < len) + { + if (IsItSwitchChar(srcString[pos])) + pos++; + const int kNoLen = -1; + int matchedSwitchIndex = 0; + int maxLen = kNoLen; + for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++) + { + int switchLen = switchForms[switchIndex].IDString.Length; + if (switchLen <= maxLen || pos + switchLen > len) + continue; + if (String.Compare(switchForms[switchIndex].IDString, 0, + srcString, pos, switchLen, true) == 0) + { + matchedSwitchIndex = switchIndex; + maxLen = switchLen; + } + } + if (maxLen == kNoLen) + throw new Exception("maxLen == kNoLen"); + SwitchResult matchedSwitch = _switches[matchedSwitchIndex]; + SwitchForm switchForm = switchForms[matchedSwitchIndex]; + if ((!switchForm.Multi) && matchedSwitch.ThereIs) + throw new Exception("switch must be single"); + matchedSwitch.ThereIs = true; + pos += maxLen; + int tailSize = len - pos; + SwitchType type = switchForm.Type; + switch (type) + { + case SwitchType.PostMinus: + { + if (tailSize == 0) + matchedSwitch.WithMinus = false; + else + { + matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus); + if (matchedSwitch.WithMinus) + pos++; + } + break; + } + case SwitchType.PostChar: + { + if (tailSize < switchForm.MinLen) + throw new Exception("switch is not full"); + string charSet = switchForm.PostCharSet; + const int kEmptyCharValue = -1; + if (tailSize == 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + int index = charSet.IndexOf(srcString[pos]); + if (index < 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + matchedSwitch.PostCharIndex = index; + pos++; + } + } + break; + } + case SwitchType.LimitedPostString: + case SwitchType.UnLimitedPostString: + { + int minLen = switchForm.MinLen; + if (tailSize < minLen) + throw new Exception("switch is not full"); + if (type == SwitchType.UnLimitedPostString) + { + matchedSwitch.PostStrings.Add(srcString.Substring(pos)); + return true; + } + String stringSwitch = srcString.Substring(pos, minLen); + pos += minLen; + for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++) + { + char c = srcString[pos]; + if (IsItSwitchChar(c)) + break; + stringSwitch += c; + } + matchedSwitch.PostStrings.Add(stringSwitch); + break; + } + } + } + return true; + + } + + public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings) + { + int numCommandStrings = commandStrings.Length; + bool stopSwitch = false; + for (int i = 0; i < numCommandStrings; i++) + { + string s = commandStrings[i]; + if (stopSwitch) + NonSwitchStrings.Add(s); + else + if (s == kStopSwitchParsing) + stopSwitch = true; + else + if (!ParseString(s, switchForms)) + NonSwitchStrings.Add(s); + } + } + + public SwitchResult this[int index] { get { return _switches[index]; } } + + public static int ParseCommand(CommandForm[] commandForms, string commandString, + out string postString) + { + for (int i = 0; i < commandForms.Length; i++) + { + string id = commandForms[i].IDString; + if (commandForms[i].PostStringMode) + { + if (commandString.IndexOf(id) == 0) + { + postString = commandString.Substring(id.Length); + return i; + } + } + else + if (commandString == id) + { + postString = ""; + return i; + } + } + postString = ""; + return -1; + } + + static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, + string commandString, ArrayList indices) + { + indices.Clear(); + int numUsedChars = 0; + for (int i = 0; i < numForms; i++) + { + CommandSubCharsSet charsSet = forms[i]; + int currentIndex = -1; + int len = charsSet.Chars.Length; + for (int j = 0; j < len; j++) + { + char c = charsSet.Chars[j]; + int newIndex = commandString.IndexOf(c); + if (newIndex >= 0) + { + if (currentIndex >= 0) + return false; + if (commandString.IndexOf(c, newIndex + 1) >= 0) + return false; + currentIndex = j; + numUsedChars++; + } + } + if (currentIndex == -1 && !charsSet.EmptyAllowed) + return false; + indices.Add(currentIndex); + } + return (numUsedChars == commandString.Length); + } + const char kSwitchID1 = '-'; + const char kSwitchID2 = '/'; + + const char kSwitchMinus = '-'; + const string kStopSwitchParsing = "--"; + + static bool IsItSwitchChar(char c) + { + return (c == kSwitchID1 || c == kSwitchID2); + } + } + + public class CommandForm + { + public string IDString = ""; + public bool PostStringMode = false; + public CommandForm(string idString, bool postStringMode) + { + IDString = idString; + PostStringMode = postStringMode; + } + } + + class CommandSubCharsSet + { + public string Chars = ""; + public bool EmptyAllowed = false; + } +} diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs.meta similarity index 83% rename from Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta rename to Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs.meta index d8c9050..a35c292 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/CommandLineParser.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ce6d8497dc69ee944af5bc17e8b05ed6 +guid: dc0b3921c07ef224cb3656391f4317c3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs new file mode 100644 index 0000000..7c51f0b --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs @@ -0,0 +1,72 @@ +// InBuffer.cs + +namespace SevenZip.Buffer +{ + public class InBuffer + { + byte[] m_Buffer; + uint m_Pos; + uint m_Limit; + uint m_BufferSize; + System.IO.Stream m_Stream; + bool m_StreamWasExhausted; + ulong m_ProcessedSize; + + public InBuffer(uint bufferSize) + { + m_Buffer = new byte[bufferSize]; + m_BufferSize = bufferSize; + } + + public void Init(System.IO.Stream stream) + { + m_Stream = stream; + m_ProcessedSize = 0; + m_Limit = 0; + m_Pos = 0; + m_StreamWasExhausted = false; + } + + public bool ReadBlock() + { + if (m_StreamWasExhausted) + return false; + m_ProcessedSize += m_Pos; + int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize); + m_Pos = 0; + m_Limit = (uint)aNumProcessedBytes; + m_StreamWasExhausted = (aNumProcessedBytes == 0); + return (!m_StreamWasExhausted); + } + + + public void ReleaseStream() + { + // m_Stream.Close(); + m_Stream = null; + } + + public bool ReadByte(byte b) // check it + { + if (m_Pos >= m_Limit) + if (!ReadBlock()) + return false; + b = m_Buffer[m_Pos++]; + return true; + } + + public byte ReadByte() + { + // return (byte)m_Stream.ReadByte(); + if (m_Pos >= m_Limit) + if (!ReadBlock()) + return 0xFF; + return m_Buffer[m_Pos++]; + } + + public ulong GetProcessedSize() + { + return m_ProcessedSize + m_Pos; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs.meta similarity index 83% rename from Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs.meta rename to Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs.meta index 798e9d7..843e5cf 100644 --- a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/InBuffer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b5a46bd6d4c947744a9bbc6ad439ae9f +guid: 6ea025f5b275726479ba55e956574898 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs new file mode 100644 index 0000000..2da16e1 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs @@ -0,0 +1,47 @@ +// OutBuffer.cs + +namespace SevenZip.Buffer +{ + public class OutBuffer + { + byte[] m_Buffer; + uint m_Pos; + uint m_BufferSize; + System.IO.Stream m_Stream; + ulong m_ProcessedSize; + + public OutBuffer(uint bufferSize) + { + m_Buffer = new byte[bufferSize]; + m_BufferSize = bufferSize; + } + + public void SetStream(System.IO.Stream stream) { m_Stream = stream; } + public void FlushStream() { m_Stream.Flush(); } + public void CloseStream() { m_Stream.Close(); } + public void ReleaseStream() { m_Stream = null; } + + public void Init() + { + m_ProcessedSize = 0; + m_Pos = 0; + } + + public void WriteByte(byte b) + { + m_Buffer[m_Pos++] = b; + if (m_Pos >= m_BufferSize) + FlushData(); + } + + public void FlushData() + { + if (m_Pos == 0) + return; + m_Stream.Write(m_Buffer, 0, (int)m_Pos); + m_Pos = 0; + } + + public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; } + } +} diff --git a/Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs.meta similarity index 83% rename from Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta rename to Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs.meta index ef93871..38af8c8 100644 --- a/Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Common/OutBuffer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b5b6fd817e50470408462a9703bfe7ef +guid: 5d61847c152e7384ab15aea89a942f54 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress.meta new file mode 100644 index 0000000..b67e6ba --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b6765bf0d03fd243b47d74c9b73c38b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ.meta new file mode 100644 index 0000000..c303414 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a83572c42056f474db56e761a4f35e38 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs new file mode 100644 index 0000000..10ca2b3 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs @@ -0,0 +1,24 @@ +// IMatchFinder.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + interface IInWindowStream + { + void SetStream(System.IO.Stream inStream); + void Init(); + void ReleaseStream(); + Byte GetIndexByte(Int32 index); + UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit); + UInt32 GetNumAvailableBytes(); + } + + interface IMatchFinder : IInWindowStream + { + void Create(UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter); + UInt32 GetMatches(UInt32[] distances); + void Skip(UInt32 num); + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs.meta new file mode 100644 index 0000000..88c6d3d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/IMatchFinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfd1ee430d8108042a2607d92d7f58ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs new file mode 100644 index 0000000..c1c006b --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs @@ -0,0 +1,367 @@ +// LzBinTree.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + public class BinTree : InWindow, IMatchFinder + { + UInt32 _cyclicBufferPos; + UInt32 _cyclicBufferSize = 0; + UInt32 _matchMaxLen; + + UInt32[] _son; + UInt32[] _hash; + + UInt32 _cutValue = 0xFF; + UInt32 _hashMask; + UInt32 _hashSizeSum = 0; + + bool HASH_ARRAY = true; + + const UInt32 kHash2Size = 1 << 10; + const UInt32 kHash3Size = 1 << 16; + const UInt32 kBT2HashSize = 1 << 16; + const UInt32 kStartMaxLen = 1; + const UInt32 kHash3Offset = kHash2Size; + const UInt32 kEmptyHashValue = 0; + const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1; + + UInt32 kNumHashDirectBytes = 0; + UInt32 kMinMatchCheck = 4; + UInt32 kFixHashSize = kHash2Size + kHash3Size; + + public void SetType(int numHashBytes) + { + HASH_ARRAY = (numHashBytes > 2); + if (HASH_ARRAY) + { + kNumHashDirectBytes = 0; + kMinMatchCheck = 4; + kFixHashSize = kHash2Size + kHash3Size; + } + else + { + kNumHashDirectBytes = 2; + kMinMatchCheck = 2 + 1; + kFixHashSize = 0; + } + } + + public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); } + public new void ReleaseStream() { base.ReleaseStream(); } + + public new void Init() + { + base.Init(); + for (UInt32 i = 0; i < _hashSizeSum; i++) + _hash[i] = kEmptyHashValue; + _cyclicBufferPos = 0; + ReduceOffsets(-1); + } + + public new void MovePos() + { + if (++_cyclicBufferPos >= _cyclicBufferSize) + _cyclicBufferPos = 0; + base.MovePos(); + if (_pos == kMaxValForNormalize) + Normalize(); + } + + public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); } + + public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) + { return base.GetMatchLen(index, distance, limit); } + + public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); } + + public void Create(UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter) + { + if (historySize > kMaxValForNormalize - 256) + throw new Exception(); + _cutValue = 16 + (matchMaxLen >> 1); + + UInt32 windowReservSize = (historySize + keepAddBufferBefore + + matchMaxLen + keepAddBufferAfter) / 2 + 256; + + base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); + + _matchMaxLen = matchMaxLen; + + UInt32 cyclicBufferSize = historySize + 1; + if (_cyclicBufferSize != cyclicBufferSize) + _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2]; + + UInt32 hs = kBT2HashSize; + + if (HASH_ARRAY) + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) + hs >>= 1; + _hashMask = hs; + hs++; + hs += kFixHashSize; + } + if (hs != _hashSizeSum) + _hash = new UInt32[_hashSizeSum = hs]; + } + + public UInt32 GetMatches(UInt32[] distances) + { + UInt32 lenLimit; + if (_pos + _matchMaxLen <= _streamPos) + lenLimit = _matchMaxLen; + else + { + lenLimit = _streamPos - _pos; + if (lenLimit < kMinMatchCheck) + { + MovePos(); + return 0; + } + } + + UInt32 offset = 0; + UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + UInt32 cur = _bufferOffset + _pos; + UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize; + UInt32 hashValue, hash2Value = 0, hash3Value = 0; + + if (HASH_ARRAY) + { + UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + hash2Value = temp & (kHash2Size - 1); + temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); + hash3Value = temp & (kHash3Size - 1); + hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; + } + else + hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); + + UInt32 curMatch = _hash[kFixHashSize + hashValue]; + if (HASH_ARRAY) + { + UInt32 curMatch2 = _hash[hash2Value]; + UInt32 curMatch3 = _hash[kHash3Offset + hash3Value]; + _hash[hash2Value] = _pos; + _hash[kHash3Offset + hash3Value] = _pos; + if (curMatch2 > matchMinPos) + if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) + { + distances[offset++] = maxLen = 2; + distances[offset++] = _pos - curMatch2 - 1; + } + if (curMatch3 > matchMinPos) + if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) + { + if (curMatch3 == curMatch2) + offset -= 2; + distances[offset++] = maxLen = 3; + distances[offset++] = _pos - curMatch3 - 1; + curMatch2 = curMatch3; + } + if (offset != 0 && curMatch2 == curMatch) + { + offset -= 2; + maxLen = kStartMaxLen; + } + } + + _hash[kFixHashSize + hashValue] = _pos; + + UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; + UInt32 ptr1 = (_cyclicBufferPos << 1); + + UInt32 len0, len1; + len0 = len1 = kNumHashDirectBytes; + + if (kNumHashDirectBytes != 0) + { + if (curMatch > matchMinPos) + { + if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] != + _bufferBase[cur + kNumHashDirectBytes]) + { + distances[offset++] = maxLen = kNumHashDirectBytes; + distances[offset++] = _pos - curMatch - 1; + } + } + } + + UInt32 count = _cutValue; + + while(true) + { + if(curMatch <= matchMinPos || count-- == 0) + { + _son[ptr0] = _son[ptr1] = kEmptyHashValue; + break; + } + UInt32 delta = _pos - curMatch; + UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? + (_cyclicBufferPos - delta) : + (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + + UInt32 pby1 = _bufferOffset + curMatch; + UInt32 len = Math.Min(len0, len1); + if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) + { + while(++len != lenLimit) + if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) + break; + if (maxLen < len) + { + distances[offset++] = maxLen = len; + distances[offset++] = delta - 1; + if (len == lenLimit) + { + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; + } + } + } + if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) + { + _son[ptr1] = curMatch; + ptr1 = cyclicPos + 1; + curMatch = _son[ptr1]; + len1 = len; + } + else + { + _son[ptr0] = curMatch; + ptr0 = cyclicPos; + curMatch = _son[ptr0]; + len0 = len; + } + } + MovePos(); + return offset; + } + + public void Skip(UInt32 num) + { + do + { + UInt32 lenLimit; + if (_pos + _matchMaxLen <= _streamPos) + lenLimit = _matchMaxLen; + else + { + lenLimit = _streamPos - _pos; + if (lenLimit < kMinMatchCheck) + { + MovePos(); + continue; + } + } + + UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + UInt32 cur = _bufferOffset + _pos; + + UInt32 hashValue; + + if (HASH_ARRAY) + { + UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + UInt32 hash2Value = temp & (kHash2Size - 1); + _hash[hash2Value] = _pos; + temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); + UInt32 hash3Value = temp & (kHash3Size - 1); + _hash[kHash3Offset + hash3Value] = _pos; + hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; + } + else + hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); + + UInt32 curMatch = _hash[kFixHashSize + hashValue]; + _hash[kFixHashSize + hashValue] = _pos; + + UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; + UInt32 ptr1 = (_cyclicBufferPos << 1); + + UInt32 len0, len1; + len0 = len1 = kNumHashDirectBytes; + + UInt32 count = _cutValue; + while (true) + { + if (curMatch <= matchMinPos || count-- == 0) + { + _son[ptr0] = _son[ptr1] = kEmptyHashValue; + break; + } + + UInt32 delta = _pos - curMatch; + UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? + (_cyclicBufferPos - delta) : + (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + + UInt32 pby1 = _bufferOffset + curMatch; + UInt32 len = Math.Min(len0, len1); + if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) + { + while (++len != lenLimit) + if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) + break; + if (len == lenLimit) + { + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; + } + } + if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) + { + _son[ptr1] = curMatch; + ptr1 = cyclicPos + 1; + curMatch = _son[ptr1]; + len1 = len; + } + else + { + _son[ptr0] = curMatch; + ptr0 = cyclicPos; + curMatch = _son[ptr0]; + len0 = len; + } + } + MovePos(); + } + while (--num != 0); + } + + void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) + { + for (UInt32 i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } + } + + void Normalize() + { + UInt32 subValue = _pos - _cyclicBufferSize; + NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); + NormalizeLinks(_hash, _hashSizeSum, subValue); + ReduceOffsets((Int32)subValue); + } + + public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs.meta new file mode 100644 index 0000000..49637e8 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzBinTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ba8015d2d5df3a459615ffc06635e6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs new file mode 100644 index 0000000..52d23ce --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs @@ -0,0 +1,132 @@ +// LzInWindow.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + public class InWindow + { + public Byte[] _bufferBase = null; // pointer to buffer with data + System.IO.Stream _stream; + UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done + bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream + + UInt32 _pointerToLastSafePosition; + + public UInt32 _bufferOffset; + + public UInt32 _blockSize; // Size of Allocated memory block + public UInt32 _pos; // offset (from _buffer) of curent byte + UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos + UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos + public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream + + public void MoveBlock() + { + UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore; + // we need one additional byte, since MovePos moves on 1 byte. + if (offset > 0) + offset--; + + UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset; + + // check negative offset ???? + for (UInt32 i = 0; i < numBytes; i++) + _bufferBase[i] = _bufferBase[offset + i]; + _bufferOffset -= offset; + } + + public virtual void ReadBlock() + { + if (_streamEndWasReached) + return; + while (true) + { + int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos); + if (size == 0) + return; + int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size); + if (numReadBytes == 0) + { + _posLimit = _streamPos; + UInt32 pointerToPostion = _bufferOffset + _posLimit; + if (pointerToPostion > _pointerToLastSafePosition) + _posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset); + + _streamEndWasReached = true; + return; + } + _streamPos += (UInt32)numReadBytes; + if (_streamPos >= _pos + _keepSizeAfter) + _posLimit = _streamPos - _keepSizeAfter; + } + } + + void Free() { _bufferBase = null; } + + public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv) + { + _keepSizeBefore = keepSizeBefore; + _keepSizeAfter = keepSizeAfter; + UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; + if (_bufferBase == null || _blockSize != blockSize) + { + Free(); + _blockSize = blockSize; + _bufferBase = new Byte[_blockSize]; + } + _pointerToLastSafePosition = _blockSize - keepSizeAfter; + } + + public void SetStream(System.IO.Stream stream) { _stream = stream; } + public void ReleaseStream() { _stream = null; } + + public void Init() + { + _bufferOffset = 0; + _pos = 0; + _streamPos = 0; + _streamEndWasReached = false; + ReadBlock(); + } + + public void MovePos() + { + _pos++; + if (_pos > _posLimit) + { + UInt32 pointerToPostion = _bufferOffset + _pos; + if (pointerToPostion > _pointerToLastSafePosition) + MoveBlock(); + ReadBlock(); + } + } + + public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; } + + // index + limit have not to exceed _keepSizeAfter; + public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) + { + if (_streamEndWasReached) + if ((_pos + index) + limit > _streamPos) + limit = _streamPos - (UInt32)(_pos + index); + distance++; + // Byte *pby = _buffer + (size_t)_pos + index; + UInt32 pby = _bufferOffset + _pos + (UInt32)index; + + UInt32 i; + for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++); + return i; + } + + public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; } + + public void ReduceOffsets(Int32 subValue) + { + _bufferOffset += (UInt32)subValue; + _posLimit -= (UInt32)subValue; + _pos -= (UInt32)subValue; + _streamPos -= (UInt32)subValue; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs.meta new file mode 100644 index 0000000..f1e45d6 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzInWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 333112c3785a6ec4cbbfec8515081cac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs new file mode 100644 index 0000000..c998584 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs @@ -0,0 +1,110 @@ +// LzOutWindow.cs + +namespace SevenZip.Compression.LZ +{ + public class OutWindow + { + byte[] _buffer = null; + uint _pos; + uint _windowSize = 0; + uint _streamPos; + System.IO.Stream _stream; + + public uint TrainSize = 0; + + public void Create(uint windowSize) + { + if (_windowSize != windowSize) + { + // System.GC.Collect(); + _buffer = new byte[windowSize]; + } + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + } + + public void Init(System.IO.Stream stream, bool solid) + { + ReleaseStream(); + _stream = stream; + if (!solid) + { + _streamPos = 0; + _pos = 0; + TrainSize = 0; + } + } + + public bool Train(System.IO.Stream stream) + { + long len = stream.Length; + uint size = (len < _windowSize) ? (uint)len : _windowSize; + TrainSize = size; + stream.Position = len - size; + _streamPos = _pos = 0; + while (size > 0) + { + uint curSize = _windowSize - _pos; + if (size < curSize) + curSize = size; + int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize); + if (numReadBytes == 0) + return false; + size -= (uint)numReadBytes; + _pos += (uint)numReadBytes; + _streamPos += (uint)numReadBytes; + if (_pos == _windowSize) + _streamPos = _pos = 0; + } + return true; + } + + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + uint size = _pos - _streamPos; + if (size == 0) + return; + _stream.Write(_buffer, (int)_streamPos, (int)size); + if (_pos >= _windowSize) + _pos = 0; + _streamPos = _pos; + } + + public void CopyBlock(uint distance, uint len) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + for (; len > 0; len--) + { + if (pos >= _windowSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + if (_pos >= _windowSize) + Flush(); + } + } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + if (_pos >= _windowSize) + Flush(); + } + + public byte GetByte(uint distance) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + return _buffer[pos]; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs.meta new file mode 100644 index 0000000..7b3f534 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZ/LzOutWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb296a6e14ab7c44cb6388693d581a62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA.meta new file mode 100644 index 0000000..5c45968 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5fcd2f5c8b724164a8a01cee73896d1a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs new file mode 100644 index 0000000..c7bca86 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs @@ -0,0 +1,76 @@ +// LzmaBase.cs + +namespace SevenZip.Compression.LZMA +{ + internal abstract class Base + { + public const uint kNumRepDistances = 4; + public const uint kNumStates = 12; + + // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; + // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; + // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; + // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + + public struct State + { + public uint Index; + public void Init() { Index = 0; } + public void UpdateChar() + { + if (Index < 4) Index = 0; + else if (Index < 10) Index -= 3; + else Index -= 6; + } + public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); } + public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); } + public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); } + public bool IsCharState() { return Index < 7; } + } + + public const int kNumPosSlotBits = 6; + public const int kDicLogSizeMin = 0; + // public const int kDicLogSizeMax = 30; + // public const uint kDistTableSizeMax = kDicLogSizeMax * 2; + + public const int kNumLenToPosStatesBits = 2; // it's for speed optimization + public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits; + + public const uint kMatchMinLen = 2; + + public static uint GetLenToPosState(uint len) + { + len -= kMatchMinLen; + if (len < kNumLenToPosStates) + return len; + return (uint)(kNumLenToPosStates - 1); + } + + public const int kNumAlignBits = 4; + public const uint kAlignTableSize = 1 << kNumAlignBits; + public const uint kAlignMask = (kAlignTableSize - 1); + + public const uint kStartPosModelIndex = 4; + public const uint kEndPosModelIndex = 14; + public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; + + public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2); + + public const uint kNumLitPosStatesBitsEncodingMax = 4; + public const uint kNumLitContextBitsMax = 8; + + public const int kNumPosStatesBitsMax = 4; + public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax); + public const int kNumPosStatesBitsEncodingMax = 4; + public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); + + public const int kNumLowLenBits = 3; + public const int kNumMidLenBits = 3; + public const int kNumHighLenBits = 8; + public const uint kNumLowLenSymbols = 1 << kNumLowLenBits; + public const uint kNumMidLenSymbols = 1 << kNumMidLenBits; + public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + + (1 << kNumHighLenBits); + public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs.meta new file mode 100644 index 0000000..10b16ed --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62f365191077342479f8227edadf57e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs new file mode 100644 index 0000000..a9be39f --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs @@ -0,0 +1,398 @@ +// LzmaDecoder.cs + +using System; + +namespace SevenZip.Compression.LZMA +{ + using RangeCoder; + + public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream + { + class LenDecoder + { + BitDecoder m_Choice = new BitDecoder(); + BitDecoder m_Choice2 = new BitDecoder(); + BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); + uint m_NumPosStates = 0; + + public void Create(uint numPosStates) + { + for (uint posState = m_NumPosStates; posState < numPosStates; posState++) + { + m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits); + m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits); + } + m_NumPosStates = numPosStates; + } + + public void Init() + { + m_Choice.Init(); + for (uint posState = 0; posState < m_NumPosStates; posState++) + { + m_LowCoder[posState].Init(); + m_MidCoder[posState].Init(); + } + m_Choice2.Init(); + m_HighCoder.Init(); + } + + public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) + { + if (m_Choice.Decode(rangeDecoder) == 0) + return m_LowCoder[posState].Decode(rangeDecoder); + else + { + uint symbol = Base.kNumLowLenSymbols; + if (m_Choice2.Decode(rangeDecoder) == 0) + symbol += m_MidCoder[posState].Decode(rangeDecoder); + else + { + symbol += Base.kNumMidLenSymbols; + symbol += m_HighCoder.Decode(rangeDecoder); + } + return symbol; + } + } + } + + class LiteralDecoder + { + struct Decoder2 + { + BitDecoder[] m_Decoders; + public void Create() { m_Decoders = new BitDecoder[0x300]; } + public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) + { + uint symbol = 1; + do + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); + while (symbol < 0x100); + return (byte)symbol; + } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) + { + uint symbol = 1; + do + { + uint matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + if (matchBit != bit) + { + while (symbol < 0x100) + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); + break; + } + } + while (symbol < 0x100); + return (byte)symbol; + } + } + + Decoder2[] m_Coders; + int m_NumPrevBits; + int m_NumPosBits; + uint m_PosMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (m_Coders != null && m_NumPrevBits == numPrevBits && + m_NumPosBits == numPosBits) + return; + m_NumPosBits = numPosBits; + m_PosMask = ((uint)1 << numPosBits) - 1; + m_NumPrevBits = numPrevBits; + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new Decoder2[numStates]; + for (uint i = 0; i < numStates; i++) + m_Coders[i].Create(); + } + + public void Init() + { + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + for (uint i = 0; i < numStates; i++) + m_Coders[i].Init(); + } + + uint GetState(uint pos, byte prevByte) + { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) + { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) + { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } + }; + + LZ.OutWindow m_OutWindow = new LZ.OutWindow(); + RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder(); + + BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; + BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + + BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits); + + LenDecoder m_LenDecoder = new LenDecoder(); + LenDecoder m_RepLenDecoder = new LenDecoder(); + + LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); + + uint m_DictionarySize; + uint m_DictionarySizeCheck; + + uint m_PosStateMask; + + public Decoder() + { + m_DictionarySize = 0xFFFFFFFF; + for (int i = 0; i < Base.kNumLenToPosStates; i++) + m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); + } + + void SetDictionarySize(uint dictionarySize) + { + if (m_DictionarySize != dictionarySize) + { + m_DictionarySize = dictionarySize; + m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1); + uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12)); + m_OutWindow.Create(blockSize); + } + } + + void SetLiteralProperties(int lp, int lc) + { + if (lp > 8) + throw new InvalidParamException(); + if (lc > 8) + throw new InvalidParamException(); + m_LiteralDecoder.Create(lp, lc); + } + + void SetPosBitsProperties(int pb) + { + if (pb > Base.kNumPosStatesBitsMax) + throw new InvalidParamException(); + uint numPosStates = (uint)1 << pb; + m_LenDecoder.Create(numPosStates); + m_RepLenDecoder.Create(numPosStates); + m_PosStateMask = numPosStates - 1; + } + + bool _solid = false; + void Init(System.IO.Stream inStream, System.IO.Stream outStream) + { + m_RangeDecoder.Init(inStream); + m_OutWindow.Init(outStream, _solid); + + uint i; + for (i = 0; i < Base.kNumStates; i++) + { + for (uint j = 0; j <= m_PosStateMask; j++) + { + uint index = (i << Base.kNumPosStatesBitsMax) + j; + m_IsMatchDecoders[index].Init(); + m_IsRep0LongDecoders[index].Init(); + } + m_IsRepDecoders[i].Init(); + m_IsRepG0Decoders[i].Init(); + m_IsRepG1Decoders[i].Init(); + m_IsRepG2Decoders[i].Init(); + } + + m_LiteralDecoder.Init(); + for (i = 0; i < Base.kNumLenToPosStates; i++) + m_PosSlotDecoder[i].Init(); + // m_PosSpecDecoder.Init(); + for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++) + m_PosDecoders[i].Init(); + + m_LenDecoder.Init(); + m_RepLenDecoder.Init(); + m_PosAlignDecoder.Init(); + } + + public void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress) + { + Init(inStream, outStream); + + Base.State state = new Base.State(); + state.Init(); + uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; + + UInt64 nowPos64 = 0; + UInt64 outSize64 = (UInt64)outSize; + if (nowPos64 < outSize64) + { + if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0) + throw new DataErrorException(); + state.UpdateChar(); + byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0); + m_OutWindow.PutByte(b); + nowPos64++; + } + while (nowPos64 < outSize64) + { + // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); + // while(nowPos64 < next) + { + uint posState = (uint)nowPos64 & m_PosStateMask; + if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) + { + byte b; + byte prevByte = m_OutWindow.GetByte(0); + if (!state.IsCharState()) + b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, + (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0)); + else + b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte); + m_OutWindow.PutByte(b); + state.UpdateChar(); + nowPos64++; + } + else + { + uint len; + if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1) + { + if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0) + { + if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) + { + state.UpdateShortRep(); + m_OutWindow.PutByte(m_OutWindow.GetByte(rep0)); + nowPos64++; + continue; + } + } + else + { + UInt32 distance; + if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0) + { + distance = rep1; + } + else + { + if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen; + state.UpdateRep(); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); + state.UpdateMatch(); + uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder); + if (posSlot >= Base.kStartPosModelIndex) + { + int numDirectBits = (int)((posSlot >> 1) - 1); + rep0 = ((2 | (posSlot & 1)) << numDirectBits); + if (posSlot < Base.kEndPosModelIndex) + rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders, + rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); + else + { + rep0 += (m_RangeDecoder.DecodeDirectBits( + numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); + rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); + } + } + else + rep0 = posSlot; + } + if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck) + { + if (rep0 == 0xFFFFFFFF) + break; + throw new DataErrorException(); + } + m_OutWindow.CopyBlock(rep0, len); + nowPos64 += len; + } + } + } + m_OutWindow.Flush(); + m_OutWindow.ReleaseStream(); + m_RangeDecoder.ReleaseStream(); + } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 5) + throw new InvalidParamException(); + int lc = properties[0] % 9; + int remainder = properties[0] / 9; + int lp = remainder % 5; + int pb = remainder / 5; + if (pb > Base.kNumPosStatesBitsMax) + throw new InvalidParamException(); + UInt32 dictionarySize = 0; + for (int i = 0; i < 4; i++) + dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); + SetDictionarySize(dictionarySize); + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + } + + public bool Train(System.IO.Stream stream) + { + _solid = true; + return m_OutWindow.Train(stream); + } + + /* + public override bool CanRead { get { return true; }} + public override bool CanWrite { get { return true; }} + public override bool CanSeek { get { return true; }} + public override long Length { get { return 0; }} + public override long Position + { + get { return 0; } + set { } + } + public override void Flush() { } + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + public override void Write(byte[] buffer, int offset, int count) + { + } + public override long Seek(long offset, System.IO.SeekOrigin origin) + { + return 0; + } + public override void SetLength(long value) {} + */ + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs.meta new file mode 100644 index 0000000..2725167 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaDecoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c60a9ce2c6df6774498e337ad69a356b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs new file mode 100644 index 0000000..0237c51 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs @@ -0,0 +1,1480 @@ +// LzmaEncoder.cs + +using System; + +namespace SevenZip.Compression.LZMA +{ + using RangeCoder; + + public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties + { + enum EMatchFinderType + { + BT2, + BT4, + }; + + const UInt32 kIfinityPrice = 0xFFFFFFF; + + static Byte[] g_FastPos = new Byte[1 << 11]; + + static Encoder() + { + const Byte kFastSlots = 22; + int c = 2; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++) + { + UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1)); + for (UInt32 j = 0; j < k; j++, c++) + g_FastPos[c] = slotFast; + } + } + + static UInt32 GetPosSlot(UInt32 pos) + { + if (pos < (1 << 11)) + return g_FastPos[pos]; + if (pos < (1 << 21)) + return (UInt32)(g_FastPos[pos >> 10] + 20); + return (UInt32)(g_FastPos[pos >> 20] + 40); + } + + static UInt32 GetPosSlot2(UInt32 pos) + { + if (pos < (1 << 17)) + return (UInt32)(g_FastPos[pos >> 6] + 12); + if (pos < (1 << 27)) + return (UInt32)(g_FastPos[pos >> 16] + 32); + return (UInt32)(g_FastPos[pos >> 26] + 52); + } + + Base.State _state = new Base.State(); + Byte _previousByte; + UInt32[] _repDistances = new UInt32[Base.kNumRepDistances]; + + void BaseInit() + { + _state.Init(); + _previousByte = 0; + for (UInt32 i = 0; i < Base.kNumRepDistances; i++) + _repDistances[i] = 0; + } + + const int kDefaultDictionaryLogSize = 22; + const UInt32 kNumFastBytesDefault = 0x20; + + class LiteralEncoder + { + public struct Encoder2 + { + BitEncoder[] m_Encoders; + + public void Create() { m_Encoders = new BitEncoder[0x300]; } + + public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); } + + public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol) + { + uint context = 1; + for (int i = 7; i >= 0; i--) + { + uint bit = (uint)((symbol >> i) & 1); + m_Encoders[context].Encode(rangeEncoder, bit); + context = (context << 1) | bit; + } + } + + public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) + { + uint context = 1; + bool same = true; + for (int i = 7; i >= 0; i--) + { + uint bit = (uint)((symbol >> i) & 1); + uint state = context; + if (same) + { + uint matchBit = (uint)((matchByte >> i) & 1); + state += ((1 + matchBit) << 8); + same = (matchBit == bit); + } + m_Encoders[state].Encode(rangeEncoder, bit); + context = (context << 1) | bit; + } + } + + public uint GetPrice(bool matchMode, byte matchByte, byte symbol) + { + uint price = 0; + uint context = 1; + int i = 7; + if (matchMode) + { + for (; i >= 0; i--) + { + uint matchBit = (uint)(matchByte >> i) & 1; + uint bit = (uint)(symbol >> i) & 1; + price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit); + context = (context << 1) | bit; + if (matchBit != bit) + { + i--; + break; + } + } + } + for (; i >= 0; i--) + { + uint bit = (uint)(symbol >> i) & 1; + price += m_Encoders[context].GetPrice(bit); + context = (context << 1) | bit; + } + return price; + } + } + + Encoder2[] m_Coders; + int m_NumPrevBits; + int m_NumPosBits; + uint m_PosMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) + return; + m_NumPosBits = numPosBits; + m_PosMask = ((uint)1 << numPosBits) - 1; + m_NumPrevBits = numPrevBits; + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new Encoder2[numStates]; + for (uint i = 0; i < numStates; i++) + m_Coders[i].Create(); + } + + public void Init() + { + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + for (uint i = 0; i < numStates; i++) + m_Coders[i].Init(); + } + + public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte) + { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; } + } + + class LenEncoder + { + RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder(); + RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder(); + RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits); + + public LenEncoder() + { + for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++) + { + _lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits); + _midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits); + } + } + + public void Init(UInt32 numPosStates) + { + _choice.Init(); + _choice2.Init(); + for (UInt32 posState = 0; posState < numPosStates; posState++) + { + _lowCoder[posState].Init(); + _midCoder[posState].Init(); + } + _highCoder.Init(); + } + + public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + { + if (symbol < Base.kNumLowLenSymbols) + { + _choice.Encode(rangeEncoder, 0); + _lowCoder[posState].Encode(rangeEncoder, symbol); + } + else + { + symbol -= Base.kNumLowLenSymbols; + _choice.Encode(rangeEncoder, 1); + if (symbol < Base.kNumMidLenSymbols) + { + _choice2.Encode(rangeEncoder, 0); + _midCoder[posState].Encode(rangeEncoder, symbol); + } + else + { + _choice2.Encode(rangeEncoder, 1); + _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols); + } + } + } + + public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st) + { + UInt32 a0 = _choice.GetPrice0(); + UInt32 a1 = _choice.GetPrice1(); + UInt32 b0 = a1 + _choice2.GetPrice0(); + UInt32 b1 = a1 + _choice2.GetPrice1(); + UInt32 i = 0; + for (i = 0; i < Base.kNumLowLenSymbols; i++) + { + if (i >= numSymbols) + return; + prices[st + i] = a0 + _lowCoder[posState].GetPrice(i); + } + for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++) + { + if (i >= numSymbols) + return; + prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols); + } + for (; i < numSymbols; i++) + prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols); + } + }; + + const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; + + class LenPriceTableEncoder : LenEncoder + { + UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax]; + UInt32 _tableSize; + UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax]; + + public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; } + + public UInt32 GetPrice(UInt32 symbol, UInt32 posState) + { + return _prices[posState * Base.kNumLenSymbols + symbol]; + } + + void UpdateTable(UInt32 posState) + { + SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols); + _counters[posState] = _tableSize; + } + + public void UpdateTables(UInt32 numPosStates) + { + for (UInt32 posState = 0; posState < numPosStates; posState++) + UpdateTable(posState); + } + + public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + { + base.Encode(rangeEncoder, symbol, posState); + if (--_counters[posState] == 0) + UpdateTable(posState); + } + } + + const UInt32 kNumOpts = 1 << 12; + class Optimal + { + public Base.State State; + + public bool Prev1IsChar; + public bool Prev2; + + public UInt32 PosPrev2; + public UInt32 BackPrev2; + + public UInt32 Price; + public UInt32 PosPrev; + public UInt32 BackPrev; + + public UInt32 Backs0; + public UInt32 Backs1; + public UInt32 Backs2; + public UInt32 Backs3; + + public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; } + public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; } + public bool IsShortRep() { return (BackPrev == 0); } + }; + Optimal[] _optimum = new Optimal[kNumOpts]; + LZ.IMatchFinder _matchFinder = null; + RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); + + RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates]; + + RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits); + + LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); + LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); + + LiteralEncoder _literalEncoder = new LiteralEncoder(); + + UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2]; + + UInt32 _numFastBytes = kNumFastBytesDefault; + UInt32 _longestMatchLength; + UInt32 _numDistancePairs; + + UInt32 _additionalOffset; + + UInt32 _optimumEndIndex; + UInt32 _optimumCurrentIndex; + + bool _longestMatchWasFound; + + UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)]; + UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits]; + UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize]; + UInt32 _alignPriceCount; + + UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2); + + int _posStateBits = 2; + UInt32 _posStateMask = (4 - 1); + int _numLiteralPosStateBits = 0; + int _numLiteralContextBits = 3; + + UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize); + UInt32 _dictionarySizePrev = 0xFFFFFFFF; + UInt32 _numFastBytesPrev = 0xFFFFFFFF; + + Int64 nowPos64; + bool _finished; + System.IO.Stream _inStream; + + EMatchFinderType _matchFinderType = EMatchFinderType.BT4; + bool _writeEndMark = false; + + bool _needReleaseMFStream; + + void Create() + { + if (_matchFinder == null) + { + LZ.BinTree bt = new LZ.BinTree(); + int numHashBytes = 4; + if (_matchFinderType == EMatchFinderType.BT2) + numHashBytes = 2; + bt.SetType(numHashBytes); + _matchFinder = bt; + } + _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits); + + if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) + return; + _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1); + _dictionarySizePrev = _dictionarySize; + _numFastBytesPrev = _numFastBytes; + } + + public Encoder() + { + for (int i = 0; i < kNumOpts; i++) + _optimum[i] = new Optimal(); + for (int i = 0; i < Base.kNumLenToPosStates; i++) + _posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits); + } + + void SetWriteEndMarkerMode(bool writeEndMarker) + { + _writeEndMark = writeEndMarker; + } + + void Init() + { + BaseInit(); + _rangeEncoder.Init(); + + uint i; + for (i = 0; i < Base.kNumStates; i++) + { + for (uint j = 0; j <= _posStateMask; j++) + { + uint complexState = (i << Base.kNumPosStatesBitsMax) + j; + _isMatch[complexState].Init(); + _isRep0Long[complexState].Init(); + } + _isRep[i].Init(); + _isRepG0[i].Init(); + _isRepG1[i].Init(); + _isRepG2[i].Init(); + } + _literalEncoder.Init(); + for (i = 0; i < Base.kNumLenToPosStates; i++) + _posSlotEncoder[i].Init(); + for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++) + _posEncoders[i].Init(); + + _lenEncoder.Init((UInt32)1 << _posStateBits); + _repMatchLenEncoder.Init((UInt32)1 << _posStateBits); + + _posAlignEncoder.Init(); + + _longestMatchWasFound = false; + _optimumEndIndex = 0; + _optimumCurrentIndex = 0; + _additionalOffset = 0; + } + + void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs) + { + lenRes = 0; + numDistancePairs = _matchFinder.GetMatches(_matchDistances); + if (numDistancePairs > 0) + { + lenRes = _matchDistances[numDistancePairs - 2]; + if (lenRes == _numFastBytes) + lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1], + Base.kMatchMaxLen - lenRes); + } + _additionalOffset++; + } + + + void MovePos(UInt32 num) + { + if (num > 0) + { + _matchFinder.Skip(num); + _additionalOffset += num; + } + } + + UInt32 GetRepLen1Price(Base.State state, UInt32 posState) + { + return _isRepG0[state.Index].GetPrice0() + + _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0(); + } + + UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState) + { + UInt32 price; + if (repIndex == 0) + { + price = _isRepG0[state.Index].GetPrice0(); + price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + } + else + { + price = _isRepG0[state.Index].GetPrice1(); + if (repIndex == 1) + price += _isRepG1[state.Index].GetPrice0(); + else + { + price += _isRepG1[state.Index].GetPrice1(); + price += _isRepG2[state.Index].GetPrice(repIndex - 2); + } + } + return price; + } + + UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState) + { + UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState); + return price + GetPureRepPrice(repIndex, state, posState); + } + + UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) + { + UInt32 price; + UInt32 lenToPosState = Base.GetLenToPosState(len); + if (pos < Base.kNumFullDistances) + price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos]; + else + price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] + + _alignPrices[pos & Base.kAlignMask]; + return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState); + } + + UInt32 Backward(out UInt32 backRes, UInt32 cur) + { + _optimumEndIndex = cur; + UInt32 posMem = _optimum[cur].PosPrev; + UInt32 backMem = _optimum[cur].BackPrev; + do + { + if (_optimum[cur].Prev1IsChar) + { + _optimum[posMem].MakeAsChar(); + _optimum[posMem].PosPrev = posMem - 1; + if (_optimum[cur].Prev2) + { + _optimum[posMem - 1].Prev1IsChar = false; + _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2; + _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2; + } + } + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = _optimum[posPrev].BackPrev; + posMem = _optimum[posPrev].PosPrev; + + _optimum[posPrev].BackPrev = backCur; + _optimum[posPrev].PosPrev = cur; + cur = posPrev; + } + while (cur > 0); + backRes = _optimum[0].BackPrev; + _optimumCurrentIndex = _optimum[0].PosPrev; + return _optimumCurrentIndex; + } + + UInt32[] reps = new UInt32[Base.kNumRepDistances]; + UInt32[] repLens = new UInt32[Base.kNumRepDistances]; + + + UInt32 GetOptimum(UInt32 position, out UInt32 backRes) + { + if (_optimumEndIndex != _optimumCurrentIndex) + { + UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex; + backRes = _optimum[_optimumCurrentIndex].BackPrev; + _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev; + return lenRes; + } + _optimumCurrentIndex = _optimumEndIndex = 0; + + UInt32 lenMain, numDistancePairs; + if (!_longestMatchWasFound) + { + ReadMatchDistances(out lenMain, out numDistancePairs); + } + else + { + lenMain = _longestMatchLength; + numDistancePairs = _numDistancePairs; + _longestMatchWasFound = false; + } + + UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1; + if (numAvailableBytes < 2) + { + backRes = 0xFFFFFFFF; + return 1; + } + if (numAvailableBytes > Base.kMatchMaxLen) + numAvailableBytes = Base.kMatchMaxLen; + + UInt32 repMaxIndex = 0; + UInt32 i; + for (i = 0; i < Base.kNumRepDistances; i++) + { + reps[i] = _repDistances[i]; + repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen); + if (repLens[i] > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= _numFastBytes) + { + backRes = repMaxIndex; + UInt32 lenRes = repLens[repMaxIndex]; + MovePos(lenRes - 1); + return lenRes; + } + + if (lenMain >= _numFastBytes) + { + backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances; + MovePos(lenMain - 1); + return lenMain; + } + + Byte currentByte = _matchFinder.GetIndexByte(0 - 1); + Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1)); + + if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2) + { + backRes = (UInt32)0xFFFFFFFF; + return 1; + } + + _optimum[0].State = _state; + + UInt32 posState = (position & _posStateMask); + + _optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() + + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte); + _optimum[1].MakeAsChar(); + + UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1(); + + if (matchByte == currentByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState); + if (shortRepPrice < _optimum[1].Price) + { + _optimum[1].Price = shortRepPrice; + _optimum[1].MakeAsShortRep(); + } + } + + UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]); + + if(lenEnd < 2) + { + backRes = _optimum[1].BackPrev; + return 1; + } + + _optimum[1].PosPrev = 0; + + _optimum[0].Backs0 = reps[0]; + _optimum[0].Backs1 = reps[1]; + _optimum[0].Backs2 = reps[2]; + _optimum[0].Backs3 = reps[3]; + + UInt32 len = lenEnd; + do + _optimum[len--].Price = kIfinityPrice; + while (len >= 2); + + for (i = 0; i < Base.kNumRepDistances; i++) + { + UInt32 repLen = repLens[i]; + if (repLen < 2) + continue; + UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState); + do + { + UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); + Optimal optimum = _optimum[repLen]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = 0; + optimum.BackPrev = i; + optimum.Prev1IsChar = false; + } + } + while (--repLen >= 2); + } + + UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0(); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= lenMain) + { + UInt32 offs = 0; + while (len > _matchDistances[offs]) + offs += 2; + for (; ; len++) + { + UInt32 distance = _matchDistances[offs + 1]; + UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState); + Optimal optimum = _optimum[len]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = 0; + optimum.BackPrev = distance + Base.kNumRepDistances; + optimum.Prev1IsChar = false; + } + if (len == _matchDistances[offs]) + { + offs += 2; + if (offs == numDistancePairs) + break; + } + } + } + + UInt32 cur = 0; + + while (true) + { + cur++; + if (cur == lenEnd) + return Backward(out backRes, cur); + UInt32 newLen; + ReadMatchDistances(out newLen, out numDistancePairs); + if (newLen >= _numFastBytes) + { + _numDistancePairs = numDistancePairs; + _longestMatchLength = newLen; + _longestMatchWasFound = true; + return Backward(out backRes, cur); + } + position++; + UInt32 posPrev = _optimum[cur].PosPrev; + Base.State state; + if (_optimum[cur].Prev1IsChar) + { + posPrev--; + if (_optimum[cur].Prev2) + { + state = _optimum[_optimum[cur].PosPrev2].State; + if (_optimum[cur].BackPrev2 < Base.kNumRepDistances) + state.UpdateRep(); + else + state.UpdateMatch(); + } + else + state = _optimum[posPrev].State; + state.UpdateChar(); + } + else + state = _optimum[posPrev].State; + if (posPrev == cur - 1) + { + if (_optimum[cur].IsShortRep()) + state.UpdateShortRep(); + else + state.UpdateChar(); + } + else + { + UInt32 pos; + if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2) + { + posPrev = _optimum[cur].PosPrev2; + pos = _optimum[cur].BackPrev2; + state.UpdateRep(); + } + else + { + pos = _optimum[cur].BackPrev; + if (pos < Base.kNumRepDistances) + state.UpdateRep(); + else + state.UpdateMatch(); + } + Optimal opt = _optimum[posPrev]; + if (pos < Base.kNumRepDistances) + { + if (pos == 0) + { + reps[0] = opt.Backs0; + reps[1] = opt.Backs1; + reps[2] = opt.Backs2; + reps[3] = opt.Backs3; + } + else if (pos == 1) + { + reps[0] = opt.Backs1; + reps[1] = opt.Backs0; + reps[2] = opt.Backs2; + reps[3] = opt.Backs3; + } + else if (pos == 2) + { + reps[0] = opt.Backs2; + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs3; + } + else + { + reps[0] = opt.Backs3; + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs2; + } + } + else + { + reps[0] = (pos - Base.kNumRepDistances); + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs2; + } + } + _optimum[cur].State = state; + _optimum[cur].Backs0 = reps[0]; + _optimum[cur].Backs1 = reps[1]; + _optimum[cur].Backs2 = reps[2]; + _optimum[cur].Backs3 = reps[3]; + UInt32 curPrice = _optimum[cur].Price; + + currentByte = _matchFinder.GetIndexByte(0 - 1); + matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1)); + + posState = (position & _posStateMask); + + UInt32 curAnd1Price = curPrice + + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() + + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)). + GetPrice(!state.IsCharState(), matchByte, currentByte); + + Optimal nextOptimum = _optimum[cur + 1]; + + bool nextIsChar = false; + if (curAnd1Price < nextOptimum.Price) + { + nextOptimum.Price = curAnd1Price; + nextOptimum.PosPrev = cur; + nextOptimum.MakeAsChar(); + nextIsChar = true; + } + + matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1(); + + if (matchByte == currentByte && + !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); + if (shortRepPrice <= nextOptimum.Price) + { + nextOptimum.Price = shortRepPrice; + nextOptimum.PosPrev = cur; + nextOptimum.MakeAsShortRep(); + nextIsChar = true; + } + } + + UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1; + numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull); + numAvailableBytes = numAvailableBytesFull; + + if (numAvailableBytes < 2) + continue; + if (numAvailableBytes > _numFastBytes) + numAvailableBytes = _numFastBytes; + if (!nextIsChar && matchByte != currentByte) + { + // try Literal + rep0 + UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateChar(); + UInt32 posStateNext = (position + 1) & _posStateMask; + UInt32 nextRepMatchPrice = curAnd1Price + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() + + _isRep[state2.Index].GetPrice1(); + { + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice( + 0, lenTest2, state2, posStateNext); + Optimal optimum = _optimum[offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = false; + } + } + } + } + + UInt32 startLen = 2; // speed optimization + + for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++) + { + UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes); + if (lenTest < 2) + continue; + UInt32 lenTestTemp = lenTest; + do + { + while (lenEnd < cur + lenTest) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); + Optimal optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur; + optimum.BackPrev = repIndex; + optimum.Prev1IsChar = false; + } + } + while(--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + // if (_maxMode) + if (lenTest < numAvailableBytesFull) + { + UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateRep(); + UInt32 posStateNext = (position + lenTest) & _posStateMask; + UInt32 curAndLenCharPrice = + repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() + + _literalEncoder.GetSubCoder(position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true, + _matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))), + _matchFinder.GetIndexByte((Int32)lenTest - 1)); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1(); + UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1(); + + // for(; lenTest2 >= 2; lenTest2--) + { + UInt32 offset = lenTest + 1 + lenTest2; + while(lenEnd < cur + offset) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + Optimal optimum = _optimum[cur + offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + lenTest + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = true; + optimum.PosPrev2 = cur; + optimum.BackPrev2 = repIndex; + } + } + } + } + } + + if (newLen > numAvailableBytes) + { + newLen = numAvailableBytes; + for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ; + _matchDistances[numDistancePairs] = newLen; + numDistancePairs += 2; + } + if (newLen >= startLen) + { + normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0(); + while (lenEnd < cur + newLen) + _optimum[++lenEnd].Price = kIfinityPrice; + + UInt32 offs = 0; + while (startLen > _matchDistances[offs]) + offs += 2; + + for (UInt32 lenTest = startLen; ; lenTest++) + { + UInt32 curBack = _matchDistances[offs + 1]; + UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); + Optimal optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur; + optimum.BackPrev = curBack + Base.kNumRepDistances; + optimum.Prev1IsChar = false; + } + + if (lenTest == _matchDistances[offs]) + { + if (lenTest < numAvailableBytesFull) + { + UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateMatch(); + UInt32 posStateNext = (position + lenTest) & _posStateMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() + + _literalEncoder.GetSubCoder(position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)). + GetPrice(true, + _matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1), + _matchFinder.GetIndexByte((Int32)lenTest - 1)); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1(); + UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1(); + + UInt32 offset = lenTest + 1 + lenTest2; + while (lenEnd < cur + offset) + _optimum[++lenEnd].Price = kIfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + optimum = _optimum[cur + offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + lenTest + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = true; + optimum.PosPrev2 = cur; + optimum.BackPrev2 = curBack + Base.kNumRepDistances; + } + } + } + offs += 2; + if (offs == numDistancePairs) + break; + } + } + } + } + } + + bool ChangePair(UInt32 smallDist, UInt32 bigDist) + { + const int kDif = 7; + return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); + } + + void WriteEndMarker(UInt32 posState) + { + if (!_writeEndMark) + return; + + _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1); + _isRep[_state.Index].Encode(_rangeEncoder, 0); + _state.UpdateMatch(); + UInt32 len = Base.kMatchMinLen; + _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1; + UInt32 lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + int footerBits = 30; + UInt32 posReduced = (((UInt32)1) << footerBits) - 1; + _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); + _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); + } + + void Flush(UInt32 nowPos) + { + ReleaseMFStream(); + WriteEndMarker(nowPos & _posStateMask); + _rangeEncoder.FlushData(); + _rangeEncoder.FlushStream(); + } + + public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished) + { + inSize = 0; + outSize = 0; + finished = true; + + if (_inStream != null) + { + _matchFinder.SetStream(_inStream); + _matchFinder.Init(); + _needReleaseMFStream = true; + _inStream = null; + if (_trainSize > 0) + _matchFinder.Skip(_trainSize); + } + + if (_finished) + return; + _finished = true; + + + Int64 progressPosValuePrev = nowPos64; + if (nowPos64 == 0) + { + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + UInt32 len, numDistancePairs; // it's not used + ReadMatchDistances(out len, out numDistancePairs); + UInt32 posState = (UInt32)(nowPos64) & _posStateMask; + _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0); + _state.UpdateChar(); + Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); + _literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte); + _previousByte = curByte; + _additionalOffset--; + nowPos64++; + } + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + while (true) + { + UInt32 pos; + UInt32 len = GetOptimum((UInt32)nowPos64, out pos); + + UInt32 posState = ((UInt32)nowPos64) & _posStateMask; + UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState; + if (len == 1 && pos == 0xFFFFFFFF) + { + _isMatch[complexState].Encode(_rangeEncoder, 0); + Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); + LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte); + if (!_state.IsCharState()) + { + Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset)); + subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); + } + else + subCoder.Encode(_rangeEncoder, curByte); + _previousByte = curByte; + _state.UpdateChar(); + } + else + { + _isMatch[complexState].Encode(_rangeEncoder, 1); + if (pos < Base.kNumRepDistances) + { + _isRep[_state.Index].Encode(_rangeEncoder, 1); + if (pos == 0) + { + _isRepG0[_state.Index].Encode(_rangeEncoder, 0); + if (len == 1) + _isRep0Long[complexState].Encode(_rangeEncoder, 0); + else + _isRep0Long[complexState].Encode(_rangeEncoder, 1); + } + else + { + _isRepG0[_state.Index].Encode(_rangeEncoder, 1); + if (pos == 1) + _isRepG1[_state.Index].Encode(_rangeEncoder, 0); + else + { + _isRepG1[_state.Index].Encode(_rangeEncoder, 1); + _isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2); + } + } + if (len == 1) + _state.UpdateShortRep(); + else + { + _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + _state.UpdateRep(); + } + UInt32 distance = _repDistances[pos]; + if (pos != 0) + { + for (UInt32 i = pos; i >= 1; i--) + _repDistances[i] = _repDistances[i - 1]; + _repDistances[0] = distance; + } + } + else + { + _isRep[_state.Index].Encode(_rangeEncoder, 0); + _state.UpdateMatch(); + _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + pos -= Base.kNumRepDistances; + UInt32 posSlot = GetPosSlot(pos); + UInt32 lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + + if (posSlot >= Base.kStartPosModelIndex) + { + int footerBits = (int)((posSlot >> 1) - 1); + UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - baseVal; + + if (posSlot < Base.kEndPosModelIndex) + RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders, + baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced); + else + { + _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); + _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); + _alignPriceCount++; + } + } + UInt32 distance = pos; + for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--) + _repDistances[i] = _repDistances[i - 1]; + _repDistances[0] = distance; + _matchPriceCount++; + } + _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset)); + } + _additionalOffset -= len; + nowPos64 += len; + if (_additionalOffset == 0) + { + // if (!_fastMode) + if (_matchPriceCount >= (1 << 7)) + FillDistancesPrices(); + if (_alignPriceCount >= Base.kAlignTableSize) + FillAlignPrices(); + inSize = nowPos64; + outSize = _rangeEncoder.GetProcessedSizeAdd(); + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + + if (nowPos64 - progressPosValuePrev >= (1 << 12)) + { + _finished = false; + finished = false; + return; + } + } + } + } + + void ReleaseMFStream() + { + if (_matchFinder != null && _needReleaseMFStream) + { + _matchFinder.ReleaseStream(); + _needReleaseMFStream = false; + } + } + + void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); } + void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); } + + void ReleaseStreams() + { + ReleaseMFStream(); + ReleaseOutStream(); + } + + void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize) + { + _inStream = inStream; + _finished = false; + Create(); + SetOutStream(outStream); + Init(); + + // if (!_fastMode) + { + FillDistancesPrices(); + FillAlignPrices(); + } + + _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen); + _lenEncoder.UpdateTables((UInt32)1 << _posStateBits); + _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen); + _repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits); + + nowPos64 = 0; + } + + + public void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress) + { + _needReleaseMFStream = false; + try + { + SetStreams(inStream, outStream, inSize, outSize); + while (true) + { + Int64 processedInSize; + Int64 processedOutSize; + bool finished; + CodeOneBlock(out processedInSize, out processedOutSize, out finished); + if (finished) + return; + if (progress != null) + { + progress.SetProgress(processedInSize, processedOutSize); + } + } + } + finally + { + ReleaseStreams(); + } + } + + const int kPropSize = 5; + Byte[] properties = new Byte[kPropSize]; + + public void WriteCoderProperties(System.IO.Stream outStream) + { + properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits); + for (int i = 0; i < 4; i++) + properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF); + outStream.Write(properties, 0, kPropSize); + } + + UInt32[] tempPrices = new UInt32[Base.kNumFullDistances]; + UInt32 _matchPriceCount; + + void FillDistancesPrices() + { + for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot(i); + int footerBits = (int)((posSlot >> 1) - 1); + UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, + baseVal - posSlot - 1, footerBits, i - baseVal); + } + + for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState]; + + UInt32 st = (lenToPosState << Base.kNumPosSlotBits); + for (posSlot = 0; posSlot < _distTableSize; posSlot++) + _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot); + for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++) + _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits); + + UInt32 st2 = lenToPosState * Base.kNumFullDistances; + UInt32 i; + for (i = 0; i < Base.kStartPosModelIndex; i++) + _distancesPrices[st2 + i] = _posSlotPrices[st + i]; + for (; i < Base.kNumFullDistances; i++) + _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i]; + } + _matchPriceCount = 0; + } + + void FillAlignPrices() + { + for (UInt32 i = 0; i < Base.kAlignTableSize; i++) + _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); + _alignPriceCount = 0; + } + + + static string[] kMatchFinderIDs = + { + "BT2", + "BT4", + }; + + static int FindMatchFinder(string s) + { + for (int m = 0; m < kMatchFinderIDs.Length; m++) + if (s == kMatchFinderIDs[m]) + return m; + return -1; + } + + public void SetCoderProperties(CoderPropID[] propIDs, object[] properties) + { + for (UInt32 i = 0; i < properties.Length; i++) + { + object prop = properties[i]; + switch (propIDs[i]) + { + case CoderPropID.NumFastBytes: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 numFastBytes = (Int32)prop; + if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen) + throw new InvalidParamException(); + _numFastBytes = (UInt32)numFastBytes; + break; + } + case CoderPropID.Algorithm: + { + /* + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 maximize = (Int32)prop; + _fastMode = (maximize == 0); + _maxMode = (maximize >= 2); + */ + break; + } + case CoderPropID.MatchFinder: + { + if (!(prop is String)) + throw new InvalidParamException(); + EMatchFinderType matchFinderIndexPrev = _matchFinderType; + int m = FindMatchFinder(((string)prop).ToUpper()); + if (m < 0) + throw new InvalidParamException(); + _matchFinderType = (EMatchFinderType)m; + if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) + { + _dictionarySizePrev = 0xFFFFFFFF; + _matchFinder = null; + } + break; + } + case CoderPropID.DictionarySize: + { + const int kDicLogSizeMaxCompress = 30; + if (!(prop is Int32)) + throw new InvalidParamException(); ; + Int32 dictionarySize = (Int32)prop; + if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) || + dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress)) + throw new InvalidParamException(); + _dictionarySize = (UInt32)dictionarySize; + int dicLogSize; + for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++) + if (dictionarySize <= ((UInt32)(1) << dicLogSize)) + break; + _distTableSize = (UInt32)dicLogSize * 2; + break; + } + case CoderPropID.PosStateBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax) + throw new InvalidParamException(); + _posStateBits = (int)v; + _posStateMask = (((UInt32)1) << (int)_posStateBits) - 1; + break; + } + case CoderPropID.LitPosBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax) + throw new InvalidParamException(); + _numLiteralPosStateBits = (int)v; + break; + } + case CoderPropID.LitContextBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax) + throw new InvalidParamException(); ; + _numLiteralContextBits = (int)v; + break; + } + case CoderPropID.EndMarker: + { + if (!(prop is Boolean)) + throw new InvalidParamException(); + SetWriteEndMarkerMode((Boolean)prop); + break; + } + default: + throw new InvalidParamException(); + } + } + } + + uint _trainSize = 0; + public void SetTrainSize(uint trainSize) + { + _trainSize = trainSize; + } + + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs.meta new file mode 100644 index 0000000..fedcb56 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/LZMA/LzmaEncoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37dcefc9d952dc34f9fba085a160a968 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder.meta new file mode 100644 index 0000000..cf24bb3 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73c80167cede90a4a8fc4938bab053c8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs new file mode 100644 index 0000000..949c6bb --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs @@ -0,0 +1,234 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + class Encoder + { + public const uint kTopValue = (1 << 24); + + System.IO.Stream Stream; + + public UInt64 Low; + public uint Range; + uint _cacheSize; + byte _cache; + + long StartPosition; + + public void SetStream(System.IO.Stream stream) + { + Stream = stream; + } + + public void ReleaseStream() + { + Stream = null; + } + + public void Init() + { + StartPosition = Stream.Position; + + Low = 0; + Range = 0xFFFFFFFF; + _cacheSize = 1; + _cache = 0; + } + + public void FlushData() + { + for (int i = 0; i < 5; i++) + ShiftLow(); + } + + public void FlushStream() + { + Stream.Flush(); + } + + public void CloseStream() + { + Stream.Close(); + } + + public void Encode(uint start, uint size, uint total) + { + Low += start * (Range /= total); + Range *= size; + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + public void ShiftLow() + { + if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1) + { + byte temp = _cache; + do + { + Stream.WriteByte((byte)(temp + (Low >> 32))); + temp = 0xFF; + } + while (--_cacheSize != 0); + _cache = (byte)(((uint)Low) >> 24); + } + _cacheSize++; + Low = ((uint)Low) << 8; + } + + public void EncodeDirectBits(uint v, int numTotalBits) + { + for (int i = numTotalBits - 1; i >= 0; i--) + { + Range >>= 1; + if (((v >> i) & 1) == 1) + Low += Range; + if (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + } + + public void EncodeBit(uint size0, int numTotalBits, uint symbol) + { + uint newBound = (Range >> numTotalBits) * size0; + if (symbol == 0) + Range = newBound; + else + { + Low += newBound; + Range -= newBound; + } + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + public long GetProcessedSizeAdd() + { + return _cacheSize + + Stream.Position - StartPosition + 4; + // (long)Stream.GetProcessedSize(); + } + } + + class Decoder + { + public const uint kTopValue = (1 << 24); + public uint Range; + public uint Code; + // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); + public System.IO.Stream Stream; + + public void Init(System.IO.Stream stream) + { + // Stream.Init(stream); + Stream = stream; + + Code = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 5; i++) + Code = (Code << 8) | (byte)Stream.ReadByte(); + } + + public void ReleaseStream() + { + // Stream.ReleaseStream(); + Stream = null; + } + + public void CloseStream() + { + Stream.Close(); + } + + public void Normalize() + { + while (Range < kTopValue) + { + Code = (Code << 8) | (byte)Stream.ReadByte(); + Range <<= 8; + } + } + + public void Normalize2() + { + if (Range < kTopValue) + { + Code = (Code << 8) | (byte)Stream.ReadByte(); + Range <<= 8; + } + } + + public uint GetThreshold(uint total) + { + return Code / (Range /= total); + } + + public void Decode(uint start, uint size, uint total) + { + Code -= start * Range; + Range *= size; + Normalize(); + } + + public uint DecodeDirectBits(int numTotalBits) + { + uint range = Range; + uint code = Code; + uint result = 0; + for (int i = numTotalBits; i > 0; i--) + { + range >>= 1; + /* + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + */ + uint t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < kTopValue) + { + code = (code << 8) | (byte)Stream.ReadByte(); + range <<= 8; + } + } + Range = range; + Code = code; + return result; + } + + public uint DecodeBit(uint size0, int numTotalBits) + { + uint newBound = (Range >> numTotalBits) * size0; + uint symbol; + if (Code < newBound) + { + symbol = 0; + Range = newBound; + } + else + { + symbol = 1; + Code -= newBound; + Range -= newBound; + } + Normalize(); + return symbol; + } + + // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs.meta new file mode 100644 index 0000000..fdbc75b --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a855cbfe314340a43b3d71672dcbb058 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs new file mode 100644 index 0000000..4f0346d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs @@ -0,0 +1,117 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + struct BitEncoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + const int kNumMoveBits = 5; + const int kNumMoveReducingBits = 2; + public const int kNumBitPriceShiftBits = 6; + + uint Prob; + + public void Init() { Prob = kBitModelTotal >> 1; } + + public void UpdateModel(uint symbol) + { + if (symbol == 0) + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + else + Prob -= (Prob) >> kNumMoveBits; + } + + public void Encode(Encoder encoder, uint symbol) + { + // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); + // UpdateModel(symbol); + uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob; + if (symbol == 0) + { + encoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + } + else + { + encoder.Low += newBound; + encoder.Range -= newBound; + Prob -= (Prob) >> kNumMoveBits; + } + if (encoder.Range < Encoder.kTopValue) + { + encoder.Range <<= 8; + encoder.ShiftLow(); + } + } + + private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits]; + + static BitEncoder() + { + const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits); + for (int i = kNumBits - 1; i >= 0; i--) + { + UInt32 start = (UInt32)1 << (kNumBits - i - 1); + UInt32 end = (UInt32)1 << (kNumBits - i); + for (UInt32 j = start; j < end; j++) + ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) + + (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1)); + } + } + + public uint GetPrice(uint symbol) + { + return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; + } + public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; } + public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; } + } + + struct BitDecoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + const int kNumMoveBits = 5; + + uint Prob; + + public void UpdateModel(int numMoveBits, uint symbol) + { + if (symbol == 0) + Prob += (kBitModelTotal - Prob) >> numMoveBits; + else + Prob -= (Prob) >> numMoveBits; + } + + public void Init() { Prob = kBitModelTotal >> 1; } + + public uint Decode(RangeCoder.Decoder rangeDecoder) + { + uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob; + if (rangeDecoder.Code < newBound) + { + rangeDecoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 0; + } + else + { + rangeDecoder.Range -= newBound; + rangeDecoder.Code -= newBound; + Prob -= (Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 1; + } + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs.meta new file mode 100644 index 0000000..2a0f148 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3fd3305ff6e02448a7b0470cfe65b77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs new file mode 100644 index 0000000..4b4506f --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs @@ -0,0 +1,157 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + struct BitTreeEncoder + { + BitEncoder[] Models; + int NumBitLevels; + + public BitTreeEncoder(int numBitLevels) + { + NumBitLevels = numBitLevels; + Models = new BitEncoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + + public void Encode(Encoder rangeEncoder, UInt32 symbol) + { + UInt32 m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; ) + { + bitIndex--; + UInt32 bit = (symbol >> bitIndex) & 1; + Models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + } + } + + public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) + { + UInt32 m = 1; + for (UInt32 i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; + } + } + + public UInt32 GetPrice(UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; ) + { + bitIndex--; + UInt32 bit = (symbol >> bitIndex) & 1; + price += Models[m].GetPrice(bit); + m = (m << 1) + bit; + } + return price; + } + + public UInt32 ReverseGetPrice(UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int i = NumBitLevels; i > 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[m].GetPrice(bit); + m = (m << 1) | bit; + } + return price; + } + + public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex, + int NumBitLevels, UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int i = NumBitLevels; i > 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[startIndex + m].GetPrice(bit); + m = (m << 1) | bit; + } + return price; + } + + public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex, + Encoder rangeEncoder, int NumBitLevels, UInt32 symbol) + { + UInt32 m = 1; + for (int i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[startIndex + m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; + } + } + } + + struct BitTreeDecoder + { + BitDecoder[] Models; + int NumBitLevels; + + public BitTreeDecoder(int numBitLevels) + { + NumBitLevels = numBitLevels; + Models = new BitDecoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + + public uint Decode(RangeCoder.Decoder rangeDecoder) + { + uint m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--) + m = (m << 1) + Models[m].Decode(rangeDecoder); + return m - ((uint)1 << NumBitLevels); + } + + public uint ReverseDecode(RangeCoder.Decoder rangeDecoder) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + uint bit = Models[m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + + public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex, + RangeCoder.Decoder rangeDecoder, int NumBitLevels) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + uint bit = Models[startIndex + m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs.meta new file mode 100644 index 0000000..df4ba12 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/Compress/RangeCoder/RangeCoderBitTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef79f786b772db344a4792a5cba382ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs b/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs new file mode 100644 index 0000000..c8b95c8 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs @@ -0,0 +1,157 @@ +// ICoder.h + +using System; + +namespace SevenZip +{ + /// + /// The exception that is thrown when an error in input stream occurs during decoding. + /// + class DataErrorException : ApplicationException + { + public DataErrorException(): base("Data Error") { } + } + + /// + /// The exception that is thrown when the value of an argument is outside the allowable range. + /// + class InvalidParamException : ApplicationException + { + public InvalidParamException(): base("Invalid Parameter") { } + } + + public interface ICodeProgress + { + /// + /// Callback progress. + /// + /// + /// input size. -1 if unknown. + /// + /// + /// output size. -1 if unknown. + /// + void SetProgress(Int64 inSize, Int64 outSize); + }; + + public interface ICoder + { + /// + /// Codes streams. + /// + /// + /// input Stream. + /// + /// + /// output Stream. + /// + /// + /// input Size. -1 if unknown. + /// + /// + /// output Size. -1 if unknown. + /// + /// + /// callback progress reference. + /// + /// + /// if input stream is not valid + /// + void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress); + }; + + /* + public interface ICoder2 + { + void Code(ISequentialInStream []inStreams, + const UInt64 []inSizes, + ISequentialOutStream []outStreams, + UInt64 []outSizes, + ICodeProgress progress); + }; + */ + + /// + /// Provides the fields that represent properties idenitifiers for compressing. + /// + public enum CoderPropID + { + /// + /// Specifies default property. + /// + DefaultProp = 0, + /// + /// Specifies size of dictionary. + /// + DictionarySize, + /// + /// Specifies size of memory for PPM*. + /// + UsedMemorySize, + /// + /// Specifies order for PPM methods. + /// + Order, + /// + /// Specifies Block Size. + /// + BlockSize, + /// + /// Specifies number of postion state bits for LZMA (0 <= x <= 4). + /// + PosStateBits, + /// + /// Specifies number of literal context bits for LZMA (0 <= x <= 8). + /// + LitContextBits, + /// + /// Specifies number of literal position bits for LZMA (0 <= x <= 4). + /// + LitPosBits, + /// + /// Specifies number of fast bytes for LZ*. + /// + NumFastBytes, + /// + /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". + /// + MatchFinder, + /// + /// Specifies the number of match finder cyckes. + /// + MatchFinderCycles, + /// + /// Specifies number of passes. + /// + NumPasses, + /// + /// Specifies number of algorithm. + /// + Algorithm, + /// + /// Specifies the number of threads. + /// + NumThreads, + /// + /// Specifies mode with end marker. + /// + EndMarker + }; + + + public interface ISetCoderProperties + { + void SetCoderProperties(CoderPropID[] propIDs, object[] properties); + }; + + public interface IWriteCoderProperties + { + void WriteCoderProperties(System.IO.Stream outStream); + } + + public interface ISetDecoderProperties + { + void SetDecoderProperties(byte[] properties); + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs.meta b/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs.meta new file mode 100644 index 0000000..f4ca52a --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/7zip/ICoder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f4fba00efa28594ea18888f574d028a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS.meta new file mode 100644 index 0000000..bee3c03 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 59ab7ccacd9a9944bb9456da235d6760 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs new file mode 100644 index 0000000..6f46f5d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs @@ -0,0 +1,14 @@ +using System; + +namespace UnityFS +{ + [Flags] + public enum ArchiveFlags + { + CompressionTypeMask = 0x3f, + BlocksAndDirectoryInfoCombined = 0x40, + BlocksInfoAtTheEnd = 0x80, + OldWebPluginCompatibility = 0x100, + BlockInfoNeedPaddingAtStart = 0x200 + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs.meta new file mode 100644 index 0000000..95b0a25 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ArchiveFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 099de05eebdffaf4baeed3290dc98aaf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs new file mode 100644 index 0000000..848d820 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace UnityFS +{ + public static class BinaryReaderExtensions + { + + public static void AlignStream(this BinaryReader reader, int alignment) + { + var pos = reader.BaseStream.Position; + var mod = pos % alignment; + if (mod != 0) + { + reader.BaseStream.Position += alignment - mod; + } + } + + public static string ReadAlignedString(this BinaryReader reader) + { + var length = reader.ReadInt32(); + if (length > 0 && length <= reader.BaseStream.Length - reader.BaseStream.Position) + { + var stringData = reader.ReadBytes(length); + var result = Encoding.UTF8.GetString(stringData); + reader.AlignStream(4); + return result; + } + return ""; + } + + public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767) + { + var bytes = new List(); + int count = 0; + while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength) + { + var b = reader.ReadByte(); + if (b == 0) + { + break; + } + bytes.Add(b); + count++; + } + return Encoding.UTF8.GetString(bytes.ToArray()); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs.meta new file mode 100644 index 0000000..224d27e --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryReaderExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a84e427dd05adde44b4345b3fd49007a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs new file mode 100644 index 0000000..8015515 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; +using System.Text; + +namespace UnityFS +{ + public static class BinaryWriterExtensions + { + public static void AlignStream(this BinaryWriter writer, int alignment) + { + var pos = writer.BaseStream.Position; + var mod = pos % alignment; + if (mod != 0) + { + writer.Write(new byte[alignment - mod]); + } + } + + public static void WriteAlignedString(this BinaryWriter writer, string str) + { + var bytes = Encoding.UTF8.GetBytes(str); + writer.Write(bytes.Length); + writer.Write(bytes); + writer.AlignStream(4); + } + + public static void WriteNullEndString(this BinaryWriter writer, string str) + { + writer.Write(Encoding.UTF8.GetBytes(str)); + writer.Write((byte)0); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs.meta new file mode 100644 index 0000000..053416c --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BinaryWriterExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02eda21769c083346a5bd9b7dca49427 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs new file mode 100644 index 0000000..d2a9eab --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnityFS +{ + public class BundleSubFile + { + public string file; + public byte[] data; + } + + public class BundleFileInfo + { + public string signature; + public uint version; + public string unityVersion; + public string unityRevision; + public ArchiveFlags flags; + public List files; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs.meta new file mode 100644 index 0000000..b33b9b2 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a72550a949e322419b9c5d6e4fe495d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs new file mode 100644 index 0000000..1804cf4 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs @@ -0,0 +1,212 @@ +using LZ4; +using System; +using System.IO; +using System.Linq; +using UnityEngine; + +namespace UnityFS +{ + + public class BundleFileReader + { + + private Header m_Header; + private StorageBlock[] m_BlocksInfo; + private Node[] m_DirectoryInfo; + + private StreamFile[] fileList; + + public BundleFileReader() + { + + } + + public void Load(EndianBinaryReader reader) + { + Debug.Log($"reader. pos:{reader.Position} length:{reader.BaseStream.Length}"); + m_Header = new Header(); + m_Header.signature = reader.ReadStringToNull(); + m_Header.version = reader.ReadUInt32(); + m_Header.unityVersion = reader.ReadStringToNull(); + m_Header.unityRevision = reader.ReadStringToNull(); + System.Diagnostics.Debug.Assert(m_Header.signature == "UnityFS"); + + + m_Header.size = reader.ReadInt64(); + Debug.Log($"header size:{m_Header.size}"); + m_Header.compressedBlocksInfoSize = reader.ReadUInt32(); + m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32(); + m_Header.flags = (ArchiveFlags)reader.ReadUInt32(); + if (m_Header.signature != "UnityFS") + { + reader.ReadByte(); + } + + ReadMetadata(reader); + using (var blocksStream = CreateBlocksStream()) + { + ReadBlocks(reader, blocksStream); + ReadFiles(blocksStream); + } + } + + public BundleFileInfo CreateBundleFileInfo() + { + return new BundleFileInfo + { + signature = m_Header.signature, + version = m_Header.version, + unityVersion = m_Header.unityVersion, + unityRevision = m_Header.unityRevision, + files = fileList.Select(f => new BundleSubFile { file = f.path, data = f.stream.ReadAllBytes() }).ToList(), + }; + } + + private byte[] ReadBlocksInfoAndDirectoryMetadataUnCompressedBytes(EndianBinaryReader reader) + { + byte[] metadataUncompressBytes; + if (m_Header.version >= 7) + { + reader.AlignStream(16); + } + if ((m_Header.flags & ArchiveFlags.BlocksInfoAtTheEnd) != 0) + { + var position = reader.Position; + reader.Position = reader.BaseStream.Length - m_Header.compressedBlocksInfoSize; + metadataUncompressBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize); + reader.Position = position; + } + else //0x40 BlocksAndDirectoryInfoCombined + { + metadataUncompressBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize); + } + return metadataUncompressBytes; + } + + private byte[] DecompressBytes(CompressionType compressionType, byte[] compressedBytes, uint uncompressedSize) + { + switch (compressionType) + { + case CompressionType.None: + { + return compressedBytes; + } + case CompressionType.Lzma: + { + var uncompressedStream = new MemoryStream((int)(uncompressedSize)); + using (var compressedStream = new MemoryStream(compressedBytes)) + { + ComparessHelper.Decompress7Zip(compressedStream, uncompressedStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize); + } + return uncompressedStream.ReadAllBytes(); + } + case CompressionType.Lz4: + case CompressionType.Lz4HC: + { + var uncompressedBytes = new byte[uncompressedSize]; + var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedBytes.Length, uncompressedBytes, 0, uncompressedBytes.Length, true); + if (numWrite != uncompressedSize) + { + throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); + } + return uncompressedBytes; + } + default: + throw new IOException($"Unsupported compression type {compressionType}"); + } + } + + private void ReadMetadata(EndianBinaryReader reader) + { + byte[] compressMetadataBytes = ReadBlocksInfoAndDirectoryMetadataUnCompressedBytes(reader); + MemoryStream metadataStream = new MemoryStream(DecompressBytes((CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask), compressMetadataBytes, m_Header.uncompressedBlocksInfoSize)); + using (var blocksInfoReader = new EndianBinaryReader(metadataStream)) + { + var uncompressedDataHash = blocksInfoReader.ReadBytes(16); + var blocksInfoCount = blocksInfoReader.ReadInt32(); + m_BlocksInfo = new StorageBlock[blocksInfoCount]; + for (int i = 0; i < blocksInfoCount; i++) + { + m_BlocksInfo[i] = new StorageBlock + { + uncompressedSize = blocksInfoReader.ReadUInt32(), + compressedSize = blocksInfoReader.ReadUInt32(), + flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16() + }; + } + + var nodesCount = blocksInfoReader.ReadInt32(); + m_DirectoryInfo = new Node[nodesCount]; + for (int i = 0; i < nodesCount; i++) + { + m_DirectoryInfo[i] = new Node + { + offset = blocksInfoReader.ReadInt64(), + size = blocksInfoReader.ReadInt64(), + flags = blocksInfoReader.ReadUInt32(), + path = blocksInfoReader.ReadStringToNull(), + }; + } + } + if (m_Header.flags.HasFlag(ArchiveFlags.BlockInfoNeedPaddingAtStart)) + { + reader.AlignStream(16); + } + } + + + private Stream CreateBlocksStream() + { + Stream blocksStream; + var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize); + if (uncompressedSizeSum >= int.MaxValue) + { + throw new Exception($"too fig file"); + } + else + { + blocksStream = new MemoryStream((int)uncompressedSizeSum); + } + return blocksStream; + } + + public void ReadFiles(Stream blocksStream) + { + fileList = new StreamFile[m_DirectoryInfo.Length]; + for (int i = 0; i < m_DirectoryInfo.Length; i++) + { + var node = m_DirectoryInfo[i]; + var file = new StreamFile(); + fileList[i] = file; + file.path = node.path; + file.fileName = Path.GetFileName(node.path); + if (node.size >= int.MaxValue) + { + throw new Exception($"exceed max file size"); + /*var memoryMappedFile = MemoryMappedFile.CreateNew(null, entryinfo_size); + file.stream = memoryMappedFile.CreateViewStream();*/ + //var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar; + //Directory.CreateDirectory(extractPath); + //file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); + } + file.stream = new MemoryStream((int)node.size); + blocksStream.Position = node.offset; + blocksStream.CopyTo(file.stream, node.size); + file.stream.Position = 0; + } + } + + private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream) + { + foreach (var blockInfo in m_BlocksInfo) + { + var compressedSize = (int)blockInfo.compressedSize; + byte[] compressedBlockBytes = reader.ReadBytes(compressedSize); + var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask); + byte[] uncompressedBlockBytes = DecompressBytes(compressionType, compressedBlockBytes, blockInfo.uncompressedSize); + blocksStream.Write(uncompressedBlockBytes, 0, uncompressedBlockBytes.Length); + } + blocksStream.Position = 0; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs.meta new file mode 100644 index 0000000..8b3cfae --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9b938458cc610e4d8a910c4499693cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs new file mode 100644 index 0000000..7e039cb --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs @@ -0,0 +1,112 @@ +using LZ4; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace UnityFS +{ + public class BundleFileWriter + { + private readonly BundleFileInfo _bundle; + + private readonly List _files = new List(); + private readonly List _blocks = new List(); + + private readonly EndianBinaryWriter _blockDirectoryMetadataStream = new EndianBinaryWriter(new MemoryStream()); + private byte[] _blockBytes; + + public BundleFileWriter(BundleFileInfo bundle) + { + _bundle = bundle; + } + + public void Write(EndianBinaryWriter output) + { + InitBlockAndDirectories(); + + output.WriteNullEndString(_bundle.signature); + output.Write(_bundle.version); + output.WriteNullEndString(_bundle.unityVersion); + output.WriteNullEndString(_bundle.unityRevision); + + BuildBlockDirectoryMetadata(); + + + long sizePos = output.Position; + output.Write(0L); + output.Write((uint)_blockDirectoryMetadataStream.Length); + output.Write((uint)_blockDirectoryMetadataStream.Length); + ArchiveFlags flags = ArchiveFlags.BlocksAndDirectoryInfoCombined | (uint)CompressionType.None; + output.Write((uint)flags); + + if (_bundle.version >= 7) + { + output.AlignStream(16); + } + byte[] metadataBytes = _blockDirectoryMetadataStream.BaseStream.ReadAllBytes(); + output.Write(metadataBytes, 0, metadataBytes.Length); + + byte[] dataBytes = _blockBytes; + output.Write(dataBytes, 0, dataBytes.Length); + + output.Position = sizePos; + output.Write(output.Length); + } + + private void InitBlockAndDirectories() + { + var dataStream = new MemoryStream(); + foreach(var file in _bundle.files) + { + byte[] data = file.data; + _files.Add(new Node { path = file.file, flags = 0, offset = dataStream.Length, size = data.LongLength }); + dataStream.Write(data, 0, data.Length); + } + byte[] dataBytes = dataStream.ToArray(); + + var compressedBlockStream = new MemoryStream(dataBytes.Length / 2); + int blockByteSize = 128 * 1024; + long dataSize = dataBytes.Length; + byte[] tempCompressBlock = new byte[blockByteSize * 2]; + for(long i = 0, blockNum = (dataSize + blockByteSize - 1) / blockByteSize; i < blockNum; i++) + { + long curBlockSize = Math.Min(dataSize, blockByteSize); + dataSize -= curBlockSize; + + int compressedSize = LZ4Codec.Encode(dataBytes, (int)(i * blockByteSize), (int)curBlockSize, tempCompressBlock, 0, tempCompressBlock.Length); + compressedBlockStream.Write(tempCompressBlock, 0, compressedSize); + _blocks.Add(new StorageBlock { flags = (StorageBlockFlags)(int)CompressionType.Lz4, compressedSize = (uint)compressedSize, uncompressedSize = (uint)curBlockSize }); + //Debug.Log($"== block[{i}] uncompressedSize:{curBlockSize} compressedSize:{compressedSize} totalblocksize:{compressedBlockStream.Length}"); + } + _blockBytes = compressedBlockStream.ToArray(); + } + + private void BuildBlockDirectoryMetadata() + { + var hash = new byte[16]; + _blockDirectoryMetadataStream.Write(hash, 0, 16); + + _blockDirectoryMetadataStream.Write((uint)_blocks.Count); + foreach(var b in _blocks) + { + _blockDirectoryMetadataStream.Write(b.uncompressedSize); + _blockDirectoryMetadataStream.Write(b.compressedSize); + _blockDirectoryMetadataStream.Write((ushort)b.flags); + } + + _blockDirectoryMetadataStream.Write((uint)_files.Count); + foreach(var f in _files) + { + _blockDirectoryMetadataStream.Write(f.offset); + _blockDirectoryMetadataStream.Write(f.size); + _blockDirectoryMetadataStream.Write(f.flags); + _blockDirectoryMetadataStream.WriteNullEndString(f.path); + } + //Debug.Log($"block and directory metadata size:{_blockDirectoryMetadataStream.Length}"); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs.meta new file mode 100644 index 0000000..98d7466 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/BundleFileWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6705163b267de54a868f5e84f6c7024 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs new file mode 100644 index 0000000..032103b --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs @@ -0,0 +1,11 @@ +namespace UnityFS +{ + public enum CompressionType + { + None, + Lzma, + Lz4, + Lz4HC, + Lzham + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs.meta new file mode 100644 index 0000000..ce8a30f --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/CompressionType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ddcd6644c83d2a94f9668d6e913bd80e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs new file mode 100644 index 0000000..d6716a8 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; + +namespace UnityFS +{ + public class EndianBinaryReader : BinaryReader + { + private readonly byte[] buffer; + + public EndianType Endian; + + public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream) + { + Endian = endian; + buffer = new byte[8]; + } + + public long Position + { + get => BaseStream.Position; + set => BaseStream.Position = value; + } + + private unsafe void ReadBufferBigEndian(byte* dst, byte[] src, int size) + { + System.Diagnostics.Debug.Assert(BitConverter.IsLittleEndian); + for (int i = 0; i < size; i++) + { + dst[i] = src[size - i - 1]; + } + } + + public override short ReadInt16() + { + return (short)ReadUInt16(); + } + + public unsafe override ushort ReadUInt16() + { + if (Endian == EndianType.BigEndian) + { + Read(buffer, 0, 2); + ushort x = 0; + ReadBufferBigEndian((byte*)&x, buffer, 2); + return x; + } + return base.ReadUInt16(); + } + + public override int ReadInt32() + { + return (int)ReadUInt32(); + } + + public unsafe override uint ReadUInt32() + { + if (Endian == EndianType.BigEndian) + { + Read(buffer, 0, 4); + uint x = 0; + ReadBufferBigEndian((byte*)&x, buffer, 4); + return x; + } + return base.ReadUInt32(); + } + + public override long ReadInt64() + { + return (long)ReadUInt64(); + } + + public unsafe override ulong ReadUInt64() + { + if (Endian == EndianType.BigEndian) + { + Read(buffer, 0, 8); + + ulong x = 0; + ReadBufferBigEndian((byte*)&x, buffer, 8); + return x; + } + return base.ReadUInt64(); + } + + public override float ReadSingle() + { + if (Endian == EndianType.BigEndian) + { + Read(buffer, 0, 4); + Array.Reverse(buffer, 0, 4); + return BitConverter.ToSingle(buffer, 0); + } + return base.ReadSingle(); + } + + public override double ReadDouble() + { + if (Endian == EndianType.BigEndian) + { + Read(buffer, 0, 8); + Array.Reverse(buffer); + return BitConverter.ToDouble(buffer, 0); + } + return base.ReadDouble(); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs.meta new file mode 100644 index 0000000..53183c0 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b02c037f0fa1014da65773804248d8d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs new file mode 100644 index 0000000..03938a9 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; + +namespace UnityFS +{ + public class EndianBinaryWriter : BinaryWriter + { + private readonly byte[] buffer; + + public EndianType Endian; + + public EndianBinaryWriter(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream) + { + Endian = endian; + buffer = new byte[8]; + } + + public long Position + { + get => BaseStream.Position; + set => BaseStream.Position = value; + } + + public long Length => BaseStream.Length; + + public override void Write(short x) + { + Write((ushort)x); + } + + private unsafe void WriteBufferBigEndian(byte[] dst, byte* src, int size) + { + System.Diagnostics.Debug.Assert(BitConverter.IsLittleEndian); + for(int i = 0; i < size; i++) + { + dst[i] = src[size - i - 1]; + } + } + + public unsafe override void Write(ushort x) + { + if (Endian == EndianType.BigEndian) + { + WriteBufferBigEndian(buffer, (byte*)&x, 2); + Write(buffer, 0, 2); + return; + } + base.Write(x); + } + + public override void Write(int x) + { + Write((uint)x); + } + + public unsafe override void Write(uint x) + { + if (Endian == EndianType.BigEndian) + { + WriteBufferBigEndian(buffer, (byte*)&x, 4); + Write(buffer, 0, 4); + return; + } + base.Write(x); + } + + public override void Write(long x) + { + Write((ulong)x); + } + + public unsafe override void Write(ulong x) + { + if (Endian == EndianType.BigEndian) + { + WriteBufferBigEndian(buffer, (byte*)&x, 8); + Write(buffer, 0, 8); + return; + } + base.Write(x); + } + + public override void Write(float x) + { + if (Endian == EndianType.BigEndian) + { + var buf = BitConverter.GetBytes(x); + Array.Reverse(buf, 0, 4); + Write(buf, 0, 4); + return; + } + base.Write(x); + } + + public override void Write(double x) + { + if (Endian == EndianType.BigEndian) + { + var buf = BitConverter.GetBytes(x); + Array.Reverse(buf, 0, 8); + Write(buf, 0, 8); + return; + } + base.Write(x); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs.meta new file mode 100644 index 0000000..cff8503 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianBinaryWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4107364c7434b2042ad647b28e322513 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs new file mode 100644 index 0000000..53e740f --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnityFS +{ + public enum EndianType + { + LittleEndian, + BigEndian + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs.meta new file mode 100644 index 0000000..c878edc --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/EndianType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f6cbab4506c18248b410a164be891d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs new file mode 100644 index 0000000..193b1f2 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityFS; + +namespace HybridCLR.Editor.UnityBinFileReader +{ + public class Dataunity3dPatcher + { + + public void ApplyPatch(string dataunity3dFile, List hotUpdateAssemblies) + { + var reader = new BundleFileReader(); + using (var fs = new EndianBinaryReader(new MemoryStream(File.ReadAllBytes(dataunity3dFile)))) + { + reader.Load(fs); + } + + var info = reader.CreateBundleFileInfo(); + //Debug.Log($"name:{info.signature} version:{info.version} files:{info.files.Count}"); + //foreach (var file in info.files) + //{ + // Debug.Log($"file:{file.file} size:{file.data.Length}"); + //} + + var globalgamemanagersFile = info.files.Find(f => f.file == "globalgamemanagers"); + //Debug.LogFormat("gobalgamemanagers origin size:{0}", globalgamemanagersFile.data.Length); + + var ggdBinFile = new UnityBinFile(); + ggdBinFile.LoadFromStream(new MemoryStream(globalgamemanagersFile.data)); + ggdBinFile.AddScriptingAssemblies(hotUpdateAssemblies); + byte[] patchedGlobalgamedatasBytes = ggdBinFile.CreatePatchedBytes(); + //Debug.LogFormat("gobalgamemanagers post patche size:{0}", patchedGlobalgamedatasBytes.Length); + globalgamemanagersFile.data = patchedGlobalgamedatasBytes; + + var writer = new BundleFileWriter(info); + var output = new MemoryStream(); + writer.Write(new EndianBinaryWriter(output)); + Debug.Log($"patch file:{dataunity3dFile} size:{output.Length}"); + + //string bakFile = dataunity3dFile + ".bak"; + //if (!File.Exists(bakFile)) + //{ + // File.Copy(dataunity3dFile, bakFile); + //} + File.WriteAllBytes(dataunity3dFile, output.ToArray()); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs.meta new file mode 100644 index 0000000..b33d83c --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/GlobalgamedatasPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 653a22d285c79f44a8113c5571b2d26b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs new file mode 100644 index 0000000..2715cce --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs @@ -0,0 +1,14 @@ +namespace UnityFS +{ + public class Header + { + public string signature; + public uint version; + public string unityVersion; + public string unityRevision; + public long size; + public uint compressedBlocksInfoSize; + public uint uncompressedBlocksInfoSize; + public ArchiveFlags flags; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs.meta new file mode 100644 index 0000000..e5a516a --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Header.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f121e0520fa65c240884d43fd00b3c2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs new file mode 100644 index 0000000..d9cfd97 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs @@ -0,0 +1,10 @@ +namespace UnityFS +{ + public class Node + { + public long offset; + public long size; + public uint flags; + public string path; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs.meta new file mode 100644 index 0000000..0736374 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/Node.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3eea8a6a32b6ac4ba609b39715e25e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs new file mode 100644 index 0000000..71b9ab3 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace UnityFS +{ + public class ScriptingAssembliesJsonPatcher + { + [Serializable] + private class ScriptingAssemblies + { + public List names; + public List types; + } + + private string _file; + ScriptingAssemblies _scriptingAssemblies; + + public void Load(string file) + { + _file = file; + string content = File.ReadAllText(file); + _scriptingAssemblies = JsonUtility.FromJson(content); + } + + public void AddScriptingAssemblies(List assemblies) + { + foreach (string name in assemblies) + { + if (!_scriptingAssemblies.names.Contains(name)) + { + _scriptingAssemblies.names.Add(name); + _scriptingAssemblies.types.Add(16); // user dll type + Debug.Log($"[PatchScriptAssembliesJson] add hotfix assembly:{name} to {_file}"); + } + } + } + + public void Save(string jsonFile) + { + string content = JsonUtility.ToJson(_scriptingAssemblies); + + File.WriteAllText(jsonFile, content); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs.meta new file mode 100644 index 0000000..b1d4449 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/ScriptingAssembliesJsonPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f2dd29d56a640d4ebd1c2fd374b7638 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs new file mode 100644 index 0000000..2d17669 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; +using SevenZip.Compression.LZMA; + + +namespace UnityFS +{ + public static class ComparessHelper + { + public static MemoryStream Decompress7Zip(MemoryStream inStream) + { + var decoder = new Decoder(); + + inStream.Seek(0, SeekOrigin.Begin); + var newOutStream = new MemoryStream(); + + var properties = new byte[5]; + if (inStream.Read(properties, 0, 5) != 5) + throw new Exception("input .lzma is too short"); + long outSize = 0; + for (var i = 0; i < 8; i++) + { + var v = inStream.ReadByte(); + if (v < 0) + throw new Exception("Can't Read 1"); + outSize |= ((long)(byte)v) << (8 * i); + } + decoder.SetDecoderProperties(properties); + + var compressedSize = inStream.Length - inStream.Position; + decoder.Code(inStream, newOutStream, compressedSize, outSize, null); + + newOutStream.Position = 0; + return newOutStream; + } + + public static void Decompress7Zip(Stream compressedStream, Stream decompressedStream, long compressedSize, long decompressedSize) + { + var basePosition = compressedStream.Position; + var decoder = new Decoder(); + var properties = new byte[5]; + if (compressedStream.Read(properties, 0, 5) != 5) + throw new Exception("input .lzma is too short"); + decoder.SetDecoderProperties(properties); + decoder.Code(compressedStream, decompressedStream, compressedSize - 5, decompressedSize, null); + compressedStream.Position = basePosition + compressedSize; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs.meta new file mode 100644 index 0000000..77f375b --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/SevenZipHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6606a654e10b3ba48b76b566b903b353 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs new file mode 100644 index 0000000..148c4d1 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs @@ -0,0 +1,9 @@ +namespace UnityFS +{ + public class StorageBlock + { + public uint compressedSize; + public uint uncompressedSize; + public StorageBlockFlags flags; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs.meta new file mode 100644 index 0000000..e1e8ad9 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40dc58bec5631f14c9c17c8a486496d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs new file mode 100644 index 0000000..619fcac --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace UnityFS +{ + [Flags] + public enum StorageBlockFlags + { + CompressionTypeMask = 0x3f, + Streamed = 0x40 + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs.meta new file mode 100644 index 0000000..d3f199d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StorageBlockFlags.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79b9ed6799d3caf459cf2dfae5765a23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs new file mode 100644 index 0000000..ecffd07 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs @@ -0,0 +1,32 @@ +using System.IO; + +namespace UnityFS +{ + public static class StreamExtensions + { + private const int BufferSize = 81920; + + public static void CopyTo(this Stream source, Stream destination, long size) + { + var buffer = new byte[BufferSize]; + for (var left = size; left > 0; left -= BufferSize) + { + int toRead = BufferSize < left ? BufferSize : (int)left; + int read = source.Read(buffer, 0, toRead); + destination.Write(buffer, 0, read); + if (read != toRead) + { + return; + } + } + } + + public static byte[] ReadAllBytes(this Stream source) + { + source.Position = 0; + var bytes = new byte[source.Length]; + source.Read(bytes, 0, bytes.Length); + return bytes; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs.meta new file mode 100644 index 0000000..a06440e --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2262fbf5672028a48b0c63821d7ff0c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs new file mode 100644 index 0000000..0fffc06 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs @@ -0,0 +1,11 @@ +using System.IO; + +namespace UnityFS +{ + public class StreamFile + { + public string path; + public string fileName; + public Stream stream; + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs.meta new file mode 100644 index 0000000..7c14e8d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/StreamFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fad7df04825c947489aad0d5d0c191a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs new file mode 100644 index 0000000..ad4ad5f --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs @@ -0,0 +1,124 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using System.Text; +using System.Reflection; +using System; +using System.Linq; + +namespace UnityFS +{ + /// + /// Unity 生成的二进制文件(本代码不支持5.x之前的版本) + /// + public unsafe class UnityBinFile + { + /* + * MonoManager: idx: 6; + * type: metaData.types[objects[6].typeID] + */ + public const int kMonoManagerIdx = 6; + + public FileHeader header; + public MetaData metaData; + public ScriptsData scriptsData; + + private Stream _originStream; + + public void LoadFromStream(Stream source) + { + _originStream = source; + using (var br = new BinaryReader(source, Encoding.UTF8, true)) + { + header.LoadFromStream(br); + // 按理说 metaData 应该新开一个buffer来避免加载时的对齐逻辑问题,但由于 sizeof(Header) = 20,已经对齐到4了,所以可以连续读 + metaData.LoadFromStream(br, header.dataOffset); + scriptsData = metaData.GetScriptData(br); + } + } + + public void Load(string path) + { + LoadFromStream(new MemoryStream(File.ReadAllBytes(path))); + } + + public void AddScriptingAssemblies(List assemblies) + { + foreach (string name in assemblies) + { + if (!scriptsData.dllNames.Contains(name)) + { + scriptsData.dllNames.Add(name); + scriptsData.dllTypes.Add(16); // user dll type + Debug.Log($"[PatchScriptAssembliesJson] add dll:{name} to globalgamemanagers"); + } + } + } + + public byte[] CreatePatchedBytes() + { + var fsR = _originStream; + fsR.Position = 0; + var brR = new BinaryReader(fsR, Encoding.UTF8, true); + + var ms = new MemoryStream((int)(header.fileSize * 1.5f)); + var bw = new BinaryWriter(ms, Encoding.UTF8, true); + + /* + * 开始写入data + * dll名称列表存储于 data 区段,修改其数据并不会影响 MetaData 大小,因此 dataOffset 不会改变 + */ + ms.Position = header.dataOffset; + + Dictionary newObjInfos = new Dictionary(); + foreach (var kv in metaData.objects) + { + long objID = kv.Key; + ObjectInfo objInfo = kv.Value; + + byte[] buff = new byte[objInfo.size]; + fsR.Position = objInfo.realPos; + brR.Read(buff, 0, buff.Length); + + + {// unity 的数据偏移貌似会对齐到 8 + int newPos = (((int)ms.Position + 7) >> 3) << 3; + int gapSize = newPos - (int)ms.Position; + + for (int i = 0; i < gapSize; i++) + bw.Write((byte)0); + + objInfo.dataPos = (uint)ms.Position - header.dataOffset; // 重定位数据偏移 + } + + if (objID != kMonoManagerIdx) + bw.Write(buff, 0, buff.Length); + else + objInfo.size = (uint)scriptsData.SaveToStream(bw); + + newObjInfos.Add(objID, objInfo); + } + + metaData.objects = newObjInfos; + header.fileSize = (uint)ms.Position; + + ms.Position = 0; + header.SaveToStream(bw); + metaData.SaveToStream(bw); + + brR.Close(); + + // 写入新文件 + ms.Position = 0; + return ms.ToArray(); + } + + public void Save(string newPath) + { + byte[] patchedBytes = CreatePatchedBytes(); + File.WriteAllBytes(newPath, patchedBytes); + } + } + +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs.meta new file mode 100644 index 0000000..457dbb7 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f9902041e9a1ff4c9f2d65d6384530d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs new file mode 100644 index 0000000..637dc4e --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs @@ -0,0 +1,397 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using static UnityFS.UnityBinUtils; + +namespace UnityFS +{ + public struct FileHeader + { + public const int kSize = 20; + + public uint dataSize => fileSize - metadataSize; + + public uint metadataSize; + public uint fileSize; + public uint version; + public uint dataOffset; + public byte endianess; + + public void LoadFromStream(BinaryReader br) + { + long startPos = br.BaseStream.Position; + metadataSize = br.ReadUInt32(); + fileSize = br.ReadUInt32(); + version = br.ReadUInt32(); + dataOffset = br.ReadUInt32(); + endianess = br.ReadByte(); + br.BaseStream.Position = startPos + kSize; + + SwapEndianess(); + } + + public long SaveToStream(BinaryWriter bw) + { + SwapEndianess(); + + long startPos = bw.BaseStream.Position; + bw.Write(metadataSize); + bw.Write(fileSize); + bw.Write(version); + bw.Write(dataOffset); + bw.Write(endianess); + bw.BaseStream.Position = startPos + kSize; + return kSize; + } + + void SwapEndianess() + { + SwapUInt(ref metadataSize); + SwapUInt(ref fileSize); + SwapUInt(ref version); + SwapUInt(ref dataOffset); + } + } + + public struct MetaData + { + public long dataStartPos; + + public string version; + public uint platform; + public bool enableTypeTree; + public int typeCount; + public ObjectType[] types; + public int objectCount; + public Dictionary objects; + public int scriptTypeCount; + public ScriptType[] scriptTypes; + public int externalsCount; + public ExternalInfo[] externals; + +#if UNITY_2019_2_OR_NEWER + public int refTypeCount; + public ObjectType[] refTypes; +#endif + public string dummyStr; + + public void LoadFromStream(BinaryReader br, uint dataOffset) + { + long startPos = br.BaseStream.Position; + dataStartPos = startPos; + + version = br.ReadRawString(); + platform = br.ReadUInt32(); + enableTypeTree = br.ReadBoolean(); + typeCount = br.ReadInt32(); + types = new ObjectType[typeCount]; + + for (int i = 0; i < typeCount; i++) + { + types[i].LoadFromStream(br); + } + + objectCount = br.ReadInt32(); + objects = new Dictionary(); + for(int i = 0; i < objectCount; i++) + { + long id = br.AlignedReadInt64(); + ObjectInfo objInfo = new ObjectInfo(); + objInfo.LoadFromStream(br); + objInfo.realPos = objInfo.dataPos + dataOffset; + + objects.Add(id, objInfo); + } + + scriptTypeCount = br.ReadInt32(); + scriptTypes = new ScriptType[scriptTypeCount]; + for(int i = 0; i < scriptTypeCount; i++) + { + scriptTypes[i].LoadFromStream(br); + } + + externalsCount = br.ReadInt32(); + externals = new ExternalInfo[externalsCount]; + for(int i = 0; i < externalsCount; i++) + { + externals[i].LoadFromStream(br); + } + +#if UNITY_2019_2_OR_NEWER + refTypeCount = br.ReadInt32(); + refTypes = new ObjectType[refTypeCount]; + for(int i = 0; i < refTypeCount; i++) + { + refTypes[i].LoadFromStream(br); + } +#endif + dummyStr = br.ReadRawString(); + } + + public long SaveToStream(BinaryWriter bw) + { + long startPos = bw.BaseStream.Position; + bw.WriteRawString(version); + bw.Write(platform); + bw.Write(enableTypeTree); + + bw.Write(typeCount); + foreach(var type in types) + type.SaveToStream(bw); + + bw.Write(objectCount); + foreach (var kv in objects) + { + bw.AlignedWriteInt64(kv.Key); + kv.Value.SaveToStream(bw); + } + + bw.Write(scriptTypeCount); + foreach(var st in scriptTypes) + st.SaveToStream(bw); + + bw.Write(externalsCount); + foreach(var external in externals) + external.SaveToStream(bw); + +#if UNITY_2019_2_OR_NEWER + bw.Write(refTypeCount); + foreach(var refT in refTypes) + refT.SaveToStream(bw); +#endif + + bw.WriteRawString(dummyStr); + + return bw.BaseStream.Position - startPos; + } + + public ScriptsData GetScriptData(BinaryReader br) + { + ObjectInfo objInfo = objects[UnityBinFile.kMonoManagerIdx]; + br.BaseStream.Seek(objInfo.realPos, SeekOrigin.Begin); + + ScriptsData data = new ScriptsData(); + data.LoadFromStream(br); + return data; + } + } + + public struct ObjectType + { + public int typeID; + public bool isStriped; + public short scriptTypeIndex; + + public bool needReadScriptHash; // dont save + + public Hash scriptSigHash; + public Hash typeHash; + + public void LoadFromStream(BinaryReader br) + { + typeID = br.ReadInt32(); + isStriped = br.ReadBoolean(); + scriptTypeIndex = br.ReadInt16(); + + needReadScriptHash = typeID == -1 || typeID == 0x72; + if(needReadScriptHash) + scriptSigHash.LoadFromStream(br); + + typeHash.LoadFromStream(br); + + // GlobalManagers does not has TypeTrees + } + + public long SaveToStream(BinaryWriter bw) + { + long startPos = bw.BaseStream.Position; + bw.Write(typeID); + bw.Write(isStriped); + bw.Write(scriptTypeIndex); + + if(needReadScriptHash) + scriptSigHash.SaveToStream(bw); + + typeHash.SaveToStream(bw); + return bw.BaseStream.Position - startPos; + } + + public int Size() + { + int ret = 0; + ret += sizeof(int); + ret += sizeof(bool); + ret += sizeof(short); + + if (needReadScriptHash) + ret += Hash.kSize; + + ret += Hash.kSize; + return ret; + } + } + + public struct ObjectInfo + { + public const int kSize = 12; + + public uint dataPos; + public uint size; + public uint typeID; + + public uint realPos; // dataPos + Header.dataOffset; // dont save + + public void LoadFromStream(BinaryReader br) + { + dataPos = br.ReadUInt32(); + size = br.ReadUInt32(); + typeID = br.ReadUInt32(); + } + + public long SaveToStream(BinaryWriter bw) + { + bw.Write(dataPos); + bw.Write(size); + bw.Write(typeID); + return kSize; + } + } + + public struct ScriptType + { + public int localFileIndex; + public long localIdentifierOfBin; + + public void LoadFromStream(BinaryReader br) + { + localFileIndex = br.ReadInt32(); + localIdentifierOfBin = br.AlignedReadInt64(); + } + + public long SaveToStream(BinaryWriter bw) + { + long startPos = bw.BaseStream.Position; + bw.Write(localFileIndex); + bw.AlignedWriteInt64(localIdentifierOfBin); + return bw.BaseStream.Position - startPos; + } + } + + public struct ExternalInfo + { + public string dummy; + public Hash guid; + public int type; + public string name; + + public void LoadFromStream(BinaryReader br) + { + dummy = br.ReadRawString(); + guid.LoadFromStream(br); + type = br.ReadInt32(); + name = br.ReadRawString(); + } + + public long SaveToStream(BinaryWriter bw) + { + long startPos = bw.BaseStream.Position; + bw.WriteRawString(dummy); + guid.SaveToStream(bw); + bw.Write(type); + bw.WriteRawString(name); + return bw.BaseStream.Position - startPos; + } + } + + public struct ScriptsData + { + public ScriptID[] scriptIDs; + public List dllNames; + public List dllTypes; // 16 is user type + + public void LoadFromStream(BinaryReader br) + { + { + int count = br.ReadInt32(); + scriptIDs = new ScriptID[count]; + for(int i = 0; i < count; i++) + scriptIDs[i].LoadFromStream(br); + } + { + int count = br.ReadInt32(); + dllNames = new List(count); + for (var i = 0; i < count; i++) + dllNames.Add(br.ReadSizeString()); + } + { + int count = br.ReadInt32(); + dllTypes = new List(count); + for(var i = 0; i < count; i++) + dllTypes.Add(br.ReadInt32()); + } + } + + public long SaveToStream(BinaryWriter bw) + { + long startPos = bw.BaseStream.Position; + bw.Write(scriptIDs.Length); + for(int i = 0; i < scriptIDs.Length; i++) + scriptIDs[i].SaveToStream(bw); + + bw.Write(dllNames.Count); + for(int i = 0, imax = dllNames.Count; i < imax; i++) + bw.WriteSizeString(dllNames[i]); + + bw.Write(dllTypes.Count); + for(int i = 0, imax = dllTypes.Count; i < imax; i++) + bw.Write(dllTypes[i]); + + return bw.BaseStream.Position - startPos; + } + } + + public struct ScriptID + { + public int fileID; + public long pathID; // localIdentifier + + public void LoadFromStream(BinaryReader br) + { + fileID = br.ReadInt32(); + pathID = br.ReadInt64(); + } + + public long SaveToStream(BinaryWriter bw) + { + bw.Write(fileID); + bw.Write(pathID); + return 4 + 8; + } + } + + public struct Hash + { + public const int kSize = 16; + + public int[] data; + + public void LoadFromStream(BinaryReader br) + { + data = new int[4]; + for(int i = 0; i < data.Length; i++) + { + data[i] = br.ReadInt32(); + } + } + + public long SaveToStream(BinaryWriter bw) + { + for(int i = 0; i < data.Length; i++) + { + bw.Write(data[i]); + } + return kSize; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs.meta new file mode 100644 index 0000000..89a829a --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinFileDefines.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10655ce82e730324db6ae297f77df04b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs new file mode 100644 index 0000000..edeefb3 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs @@ -0,0 +1,78 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using System.Text; + +namespace UnityFS +{ + public static class UnityBinUtils + { + public static void SwapUInt(ref uint val) + { + val = (val >> 24) | ((val >> 8) & 0x0000ff00) | ((val << 8) & 0x00ff0000) | (val << 24); + } + + public static string ReadRawString(this BinaryReader br) + { + long startPos = br.BaseStream.Position; + while (true) + { + byte val = br.ReadByte(); + if(val == 0) + break; + } + int size = (int)(br.BaseStream.Position - startPos); + br.BaseStream.Position = startPos; + + byte[] buffer = br.ReadBytes(size); + string ret = Encoding.UTF8.GetString(buffer, 0, size - 1); + + return ret; + } + + public static void WriteRawString(this BinaryWriter bw, string str) + { + byte[] buffer = Encoding.UTF8.GetBytes(str); + bw.Write(buffer, 0, buffer.Length); + bw.Write((byte)0); + } + + public static string ReadSizeString(this BinaryReader br) + { + int size = br.ReadInt32(); + byte[] buff = br.ReadBytes(size); + br.BaseStream.AlignOffset4(); + + string ret = Encoding.UTF8.GetString(buff); + return ret; + } + + public static void WriteSizeString(this BinaryWriter bw, string str) + { + byte[] buff = Encoding.UTF8.GetBytes(str); + bw.Write(buff.Length); + bw.Write(buff, 0, buff.Length); + bw.BaseStream.AlignOffset4(); + } + + public static void AlignOffset4(this Stream stream) + { + int offset = (((int)stream.Position + 3) >> 2) << 2; + stream.Position = offset; + } + + public static long AlignedReadInt64(this BinaryReader br) + { + br.BaseStream.AlignOffset4(); + return br.ReadInt64(); + } + + public static void AlignedWriteInt64(this BinaryWriter bw, long val) + { + bw.BaseStream.AlignOffset4(); + bw.Write(val); + } + } +} + diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs.meta new file mode 100644 index 0000000..4be54e7 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/3rds/UnityFS/UnityBinUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12a24c30a3914be418be10cfebfa9649 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook.meta index 69ef844..4fab614 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 25b811809f0489143b29977c20dcfe87 +guid: 13fe0cab0b357464d889de45c8d98850 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs index 7acd8c9..07a5e5e 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs @@ -116,8 +116,8 @@ namespace MonoHook static void SetupFlushICacheFunc() { - string processorType = SystemInfo.processorType; - if (processorType.Contains("Intel") || processorType.Contains("AMD")) + string processorType = SystemInfo.processorType.ToLowerInvariant(); + if (processorType.Contains("intel") || processorType.Contains("amd")) return; if (IntPtr.Size == 4) diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs.meta index 5d2086b..8ec4cb3 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9c0482f5e3f6dbf4a82a4c1dc7988d5e +guid: e84139b42a6164e4c93ce4df1be6dcfb MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs index 8e4a126..4efdb0b 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs @@ -16,7 +16,11 @@ namespace MonoHook static HookUtils() { - jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0; + try + { + jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0; + } + catch { } PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize"); if (p_SystemPageSize == null) @@ -35,6 +39,16 @@ namespace MonoHook public static void MemCpy_Jit(void* pDst, byte[] src) { + if (!jit_write_protect_supported) + { + fixed(void * pSrc = &src[0]) + { + MemCpy(pDst, pSrc, src.Length); + } + + return; + } + fixed(void * p = &src[0]) { memcpy_jit(new IntPtr(pDst), new IntPtr(p), src.Length); diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta index 71fe67a..6ecee49 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8ab765aec3653f0449c2ba805a5966a6 +guid: efda6e010e5c6594081c4a62861d469f MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks.meta index 32433e2..8169f8d 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7cf7966d2f4139f42a5504fb12299dc4 +guid: d796fc01daee1964586621890988a5ae folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs index 7e3373d..d494552 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs @@ -12,7 +12,7 @@ using System.IO; namespace HybridCLR.MonoHook { -#if UNITY_2021_1_OR_NEWER +#if UNITY_2021_1_OR_NEWER && !UNITY_2023_1_OR_NEWER [InitializeOnLoad] public class CopyStrippedAOTAssembliesHook { diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta index 67d8c5b..18542c3 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: aeea2b7e7523c9a4aa19be70f832bda2 +guid: cf42c4f20b8a1b94baa04a1a5c6b8beb MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs index c3ce1f5..fbaf8bf 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs @@ -12,7 +12,7 @@ using System.IO; namespace HybridCLR.MonoHook { -#if UNITY_2022 +#if UNITY_2022 || UNITY_2023_1_OR_NEWER [InitializeOnLoad] public class GetIl2CppFolderHook { diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta index ece7485..bcde7d8 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 541e6130979493447825045c244c133c +guid: 96c2bc28db69e1644892219abef3d4b5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs index 169d766..c912756 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs @@ -12,7 +12,7 @@ using System.IO; namespace HybridCLR.MonoHook { -#if UNITY_2021_1_OR_NEWER && UNITY_WEBGL +#if UNITY_2021_1_OR_NEWER && (UNITY_WEBGL || UNITY_WEIXINMINIGAME) [InitializeOnLoad] public class PatchScriptingAssembliesJsonHook { @@ -35,12 +35,29 @@ namespace HybridCLR.MonoHook private static string BuildMainWindowTitle() { - string tempJsonPath = $"{Application.dataPath}/../Library/PlayerDataCache/WebGL/Data/ScriptingAssemblies.json"; - if (File.Exists(tempJsonPath)) + var cacheDir = $"{Application.dataPath}/../Library/PlayerDataCache"; + if (Directory.Exists(cacheDir)) { - var patcher = new PatchScriptingAssemblyList(); - patcher.PathScriptingAssembilesFile(Path.GetDirectoryName(tempJsonPath)); + foreach (var tempJsonPath in Directory.GetDirectories(cacheDir, "*", SearchOption.TopDirectoryOnly)) + { + string dirName = Path.GetFileName(tempJsonPath); + #if UNITY_WEIXINMINIGAME + if (!dirName.Contains("WeixinMiniGame")) + { + continue; + } +#else + if (!dirName.Contains("WebGL")) + { + continue; + } +#endif + + var patcher = new PatchScriptingAssemblyList(); + patcher.PathScriptingAssembilesFile(tempJsonPath); + } } + string newTitle = BuildMainWindowTitleProxy(); return newTitle; } diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta index 09d231a..ccf939f 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ea52aac3bd5754841bff8c177a91a160 +guid: cc89a9041ab48ac41975fbd1e00b9b98 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/LDasm.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/LDasm.cs.meta index 5815a5d..969a5a1 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/LDasm.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/LDasm.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d5a77282b371549439907297e5f967d0 +guid: 3c561c9729c367e4fbef63f4ec56f268 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/MethodHook.cs.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/MethodHook.cs.meta index 9b33582..007e62c 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/MethodHook.cs.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/MethodHook.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1d457aae59bb6a949b97887543318503 +guid: bd0b8071cf434d6498160259e3829980 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins.meta index 7ad2130..1f7f284 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e0c9859301729b84f88491ed39122043 +guid: 16b9dc031f67b4fe5ad79c230f75768c folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta index 9670a65..447c3db 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0b61f42ce4a78754f949acd008581b29 +guid: 56b28b5583a184c669dcb968d175544c PluginImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta index 1bf6000..ed9f26d 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a88be91a9edddd249b1c076491e8cb11 +guid: 69eeb734e262a0a4fbe0887249198f73 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon.meta index 7d2aaee..2e09562 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 76fbfe977abb84741b86eb67907b15e5 +guid: 7adba4475cf0bdc4fa7995c0d748f480 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta index a9e04ae..3045ab9 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cb117b25721641c45bf5ec77a09438f5 +guid: e092a73910a69894daea44290d7292f6 PluginImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64.meta index 7591849..d4267c3 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 25a82d6fb527b6249b44af1fb31d6cdc +guid: 31f6a810e38e66f4c832b135770a04bb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib.meta b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib.meta index 09e7e23..f301feb 100644 --- a/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib.meta +++ b/Assets/01.HybridCLR/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ca79f0e18c71509439472ab7a43208b3 +guid: 4adb23596911347faa69537b900c9f5e PluginImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI.meta b/Assets/01.HybridCLR/Editor/ABI.meta index 156e887..0557322 100644 --- a/Assets/01.HybridCLR/Editor/ABI.meta +++ b/Assets/01.HybridCLR/Editor/ABI.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b04e209fa45773c41999434fdf844d09 +guid: d26c8b77c84f09442a05f2c67e5e09b8 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/ABI/ABIUtil.cs.meta b/Assets/01.HybridCLR/Editor/ABI/ABIUtil.cs.meta index fe823f2..79a2ec0 100644 --- a/Assets/01.HybridCLR/Editor/ABI/ABIUtil.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/ABIUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 22e3eda7240996c48be1b8954d38fe46 +guid: edeb86f4b5b13ca4cb0fe9d87ce509bb MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/MethodDesc.cs.meta b/Assets/01.HybridCLR/Editor/ABI/MethodDesc.cs.meta index fa21d22..0a0a97a 100644 --- a/Assets/01.HybridCLR/Editor/ABI/MethodDesc.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/MethodDesc.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c7b236ad29a3aa045a17c75dd02100a7 +guid: 28e06667d06f37b4990b16f54f903a35 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/ParamInfo.cs.meta b/Assets/01.HybridCLR/Editor/ABI/ParamInfo.cs.meta index 82296df..6b4174e 100644 --- a/Assets/01.HybridCLR/Editor/ABI/ParamInfo.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/ParamInfo.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 44a2793a6b1d2fc4980ba02265d5b9f5 +guid: f2ba16cf4bf82374c814789b6ced3abd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/ParamOrReturnType.cs.meta b/Assets/01.HybridCLR/Editor/ABI/ParamOrReturnType.cs.meta index 6d4872d..12ffd4b 100644 --- a/Assets/01.HybridCLR/Editor/ABI/ParamOrReturnType.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/ParamOrReturnType.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d1bc4457ac8969d4db9028aa8fa262dc +guid: 80682e47c38a2f04f8af94d356688cf0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/PlatformABI.cs.meta b/Assets/01.HybridCLR/Editor/ABI/PlatformABI.cs.meta index d07c1cd..bea367c 100644 --- a/Assets/01.HybridCLR/Editor/ABI/PlatformABI.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/PlatformABI.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e1453681f0ca40843a5f088d96a9afda +guid: b9f06ff0612105b4ea20e0309e759e24 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/TypeCreator.cs.meta b/Assets/01.HybridCLR/Editor/ABI/TypeCreator.cs.meta index 054f1ee..7452840 100644 --- a/Assets/01.HybridCLR/Editor/ABI/TypeCreator.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/TypeCreator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4a6ba1b2aee1b4546a002c82776b97da +guid: 0b1df5760b488fa43a68843c46fda63a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/TypeInfo.cs.meta b/Assets/01.HybridCLR/Editor/ABI/TypeInfo.cs.meta index 61715c1..5df8577 100644 --- a/Assets/01.HybridCLR/Editor/ABI/TypeInfo.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/TypeInfo.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 194f0932bc4996a4fae6fa7d475e8efb +guid: ffafce7f1f0bf614d95b48ca39385377 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta b/Assets/01.HybridCLR/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta index 8909332..4b83d63 100644 --- a/Assets/01.HybridCLR/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta +++ b/Assets/01.HybridCLR/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6d2de90a9f5b6a24ebdf87ac4e3b56c4 +guid: b7af32bdf1cf55c42bfc449820d401cb MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/AOT.meta b/Assets/01.HybridCLR/Editor/AOT.meta index d71f4d6..9b9539f 100644 --- a/Assets/01.HybridCLR/Editor/AOT.meta +++ b/Assets/01.HybridCLR/Editor/AOT.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d498af376cdc9954097685c7c5a98456 +guid: b4071bf66ac9c544487ae88b5ee9b20a folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs b/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs new file mode 100644 index 0000000..37c8952 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs @@ -0,0 +1,56 @@ +using dnlib.DotNet; +using dnlib.DotNet.Writer; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.AOT +{ + public class AOTAssemblyMetadataStripper + { + public static byte[] Strip(byte[] assemblyBytes) + { + var context = ModuleDef.CreateModuleContext(); + var readerOption = new ModuleCreationOptions(context) + { + Runtime = CLRRuntimeReaderKind.Mono + }; + var mod = ModuleDefMD.Load(assemblyBytes, readerOption); + // remove all resources + mod.Resources.Clear(); + foreach (var type in mod.GetTypes()) + { + if (type.HasGenericParameters) + { + continue; + } + foreach (var method in type.Methods) + { + if (!method.HasBody || method.HasGenericParameters) + { + continue; + } + method.Body = null; + } + } + var writer = new System.IO.MemoryStream(); + var options = new ModuleWriterOptions(mod); + options.MetadataOptions.Flags |= MetadataFlags.PreserveRids; + mod.Write(writer, options); + writer.Flush(); + return writer.ToArray(); + } + + public static void Strip(string originalAssemblyPath, string strippedAssemblyPath) + { + byte[] originDllBytes = System.IO.File.ReadAllBytes(originalAssemblyPath); + byte[] strippedDllBytes = Strip(originDllBytes); + UnityEngine.Debug.Log($"aot dll:{originalAssemblyPath}, length: {originDllBytes.Length} -> {strippedDllBytes.Length}, stripping rate:{(originDllBytes.Length - strippedDllBytes.Length)/(double)originDllBytes.Length} "); + Directory.CreateDirectory(System.IO.Path.GetDirectoryName(strippedAssemblyPath)); + System.IO.File.WriteAllBytes(strippedAssemblyPath, strippedDllBytes); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs.meta b/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs.meta new file mode 100644 index 0000000..f7642f9 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/AOT/AOTAssemblyMetadataStripper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e9e6a048682dcb4fab806251411f29f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs b/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs index 5d9c475..dcd2a87 100644 --- a/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs +++ b/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs @@ -17,12 +17,16 @@ namespace HybridCLR.Editor.AOT public AssemblyReferenceDeepCollector Collector { get; set; } public int MaxIterationCount { get; set; } + + public bool ComputeAotAssembly { get; set; } } private readonly int _maxInterationCount; private readonly AssemblyReferenceDeepCollector _assemblyCollector; + private readonly bool _computeAotAssembly; + private readonly HashSet _genericTypes = new HashSet(); private readonly HashSet _genericMethods = new HashSet(); @@ -47,6 +51,7 @@ namespace HybridCLR.Editor.AOT { _assemblyCollector = options.Collector; _maxInterationCount = options.MaxIterationCount; + _computeAotAssembly = options.ComputeAotAssembly; _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod); _hotUpdateAssemblyFiles = new HashSet(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll")); } @@ -71,7 +76,7 @@ namespace HybridCLR.Editor.AOT private bool IsAotType(TypeDef type) { - return !_hotUpdateAssemblyFiles.Contains(type.Module.Name); + return _computeAotAssembly || !_hotUpdateAssemblyFiles.Contains(type.Module.Name); } private bool IsAotGenericMethod(MethodDef method) @@ -191,11 +196,29 @@ namespace HybridCLR.Editor.AOT } } + private bool IsNotShareableAOTGenericType(TypeDef typeDef) + { + if (!IsAotType(typeDef)) + { + return false; + } + return typeDef.GenericParameters.Any(c => !c.HasReferenceTypeConstraint); + } + + private bool IsNotShareableAOTGenericMethod(MethodDef method) + { + if (!IsAotGenericMethod(method)) + { + return false; + } + return method.GenericParameters.Concat(method.DeclaringType.GenericParameters).Any(c => !c.HasReferenceTypeConstraint); + } + private void FilterAOTGenericTypeAndMethods() { ConstraintContext cc = this.ConstraintContext; - AotGenericTypes.AddRange(_genericTypes.Where(type => IsAotType(type.Type)).Select(gc => cc.ApplyConstraints(gc))); - AotGenericMethods.AddRange(_genericMethods.Where(method => IsAotGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm))); + AotGenericTypes.AddRange(_genericTypes.Where(type => IsNotShareableAOTGenericType(type.Type)).Select(gc => cc.ApplyConstraints(gc))); + AotGenericMethods.AddRange(_genericMethods.Where(method => IsNotShareableAOTGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm))); } public void Run() diff --git a/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs.meta b/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs.meta index 01ae980..2e573fc 100644 --- a/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs.meta +++ b/Assets/01.HybridCLR/Editor/AOT/Analyzer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5eb77177ef7793a44af2666b647e9605 +guid: 30bbf4a80a6cf3a43b3f489747d9dd6a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/AOT/ConstraintContext.cs.meta b/Assets/01.HybridCLR/Editor/AOT/ConstraintContext.cs.meta index a4bc887..3e99cab 100644 --- a/Assets/01.HybridCLR/Editor/AOT/ConstraintContext.cs.meta +++ b/Assets/01.HybridCLR/Editor/AOT/ConstraintContext.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b6b6f4ac6086fbc46b43cb1610dba4fb +guid: 812d81a75b690394bbe16ef5f0bcbc46 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs b/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs index 20612c4..1b6021f 100644 --- a/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs +++ b/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs @@ -39,7 +39,7 @@ namespace HybridCLR.Editor.AOT { _typeSimpleNameMapping.Add(e.Key.FullName, e.Value); } - _systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{k}\b"))); + _systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{Regex.Escape(k)}\b"))); } public string PrettifyTypeSig(string typeSig) diff --git a/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs.meta b/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs.meta index 6e37fa3..9fc1497 100644 --- a/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs.meta +++ b/Assets/01.HybridCLR/Editor/AOT/GenericReferenceWriter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: cc730a906269a78429589f950b5a92f3 +guid: d1243cf04685361478972f93b5ca868a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors.meta b/Assets/01.HybridCLR/Editor/BuildProcessors.meta index ffe5b0e..428a0a1 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 573e796f2cada3d44b0500e66b56c257 +guid: f80d2287f01c89642a74b0a60f7a3305 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs new file mode 100644 index 0000000..b879aff --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs @@ -0,0 +1,258 @@ +using System; +using HybridCLR.Editor.Installer; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UnityEditor; +using System.Reflection; +using HybridCLR.Editor.Settings; +#if UNITY_2019 && (UNITY_IOS || UNITY_TVOS) +using UnityEditor.Build; +using UnityEditor.Callbacks; +using UnityEditor.iOS.Xcode; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + public static class AddLil2cppSourceCodeToXcodeproj2019 + { + [PostProcessBuild] + public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) + { + if (!HybridCLRSettings.Instance.enable) + return; + /* + * 1. 生成lump,并且添加到工程 + 3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp + 3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include + 4. 将external目录复制到 Library/external。删除旧目录 + 5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写 + 6. 将 external/zlib下c 文件添加到工程 + 7. 移除libil2cpp.a + 8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include + 9. add external/xxHash + 10. add "#include " to Classes/Prefix.pch + */ + + string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject); + string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; + string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp"; + string lumpDir = $"{pathToBuiltProject}/Libraries/lumps"; + string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external"; + string dstExternalDir = $"{pathToBuiltProject}/Libraries/external"; + //RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir); + CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir); + CopyExternalToXcodeProj(srcExternalDir, dstExternalDir); + var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir); + var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir); + var cflags = new List() + { + "-DIL2CPP_MONO_DEBUGGER_DISABLED", + }; + ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags); + AddSystemHeaderToPrefixPch(pathToBuiltProject); + } + + private static void AddSystemHeaderToPrefixPch(string pathToBuiltProject) + { + // 如果不将 stdio.h 添加到 Prefix.pch, zutil.c会有编译错误 + string prefixPchFile = $"{pathToBuiltProject}/Classes/Prefix.pch"; + string fileContent = File.ReadAllText(prefixPchFile, Encoding.UTF8); + if (!fileContent.Contains("stdio.h")) + { + string newFileContent = fileContent + "\n#include \n"; + File.WriteAllText(prefixPchFile, newFileContent, Encoding.UTF8); + UnityEngine.Debug.Log($"append header to {prefixPchFile}"); + } + } + + private static string GetRelativePathFromProj(string path) + { + return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/'); + } + + private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List lumpFiles, List extraFiles, List cflags) + { + var proj = new PBXProject(); + proj.ReadFromFile(pbxprojFile); + string targetGUID = proj.GetUnityFrameworkTargetGuid(); + // 移除旧的libil2cpp.a + var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a"); + if (!string.IsNullOrEmpty(libil2cppGUID)) + { + proj.RemoveFileFromBuild(targetGUID, libil2cppGUID); + proj.RemoveFile(libil2cppGUID); + File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a")); + } + + //var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group); + + foreach (var lumpFile in lumpFiles) + { + string lumpFileName = Path.GetFileName(lumpFile.lumpFile); + string projPathOfFile = $"Classes/Lumps/{lumpFileName}"; + string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile); + string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile); + if (!string.IsNullOrEmpty(lumpGuid)) + { + proj.RemoveFileFromBuild(targetGUID, lumpGuid); + proj.RemoveFile(lumpGuid); + } + lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source); + proj.AddFileToBuild(targetGUID, lumpGuid); + } + + foreach (var extraFile in extraFiles) + { + string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}"; + string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile); + if (!string.IsNullOrEmpty(extraFileGuid)) + { + proj.RemoveFileFromBuild(targetGUID, extraFileGuid); + proj.RemoveFile(extraFileGuid); + //Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}"); + } + var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source); + proj.AddFileToBuild(targetGUID, lumpGuid); + } + + foreach(var configName in proj.BuildConfigNames()) + { + //Debug.Log($"build config:{bcn}"); + string configGuid = proj.BuildConfigByName(targetGUID, configName); + string headerSearchPaths = "HEADER_SEARCH_PATHS"; + string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths); + //Debug.Log($"config guid:{configGuid} prop:{hspProp}"); + string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp") + .Replace("Libraries/bdwgc", "Libraries/external/bdwgc"); + + //if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include")) + //{ + // newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"; + //} + if (!newPro.Contains("Libraries/external/xxHash")) + { + newPro += " $(SRCROOT)/Libraries/external/xxHash"; + } + newPro += " $(SRCR00T)/Libraries/external/mono"; + //Debug.Log($"config:{bcn} new prop:{newPro}"); + proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro); + + string cflagKey = "OTHER_CFLAGS"; + string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey); + foreach (var flag in cflags) + { + if (!cfProp.Contains(flag)) + { + cfProp += " " + flag; + } + } + if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG=")) + { + cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1"; + } + proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp); + + } + proj.WriteToFile(pbxprojFile); + } + + private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir) + { + BashUtil.RemoveDir(dstLibil2cppDir); + BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true); + } + + + private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir) + { + BashUtil.RemoveDir(dstExternalDir); + BashUtil.CopyDir(srcExternalDir, dstExternalDir, true); + + //string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms"; + //BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS"); + //BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true); + } + + class LumpFile + { + public List cppFiles = new List(); + + public readonly string lumpFile; + + public readonly string il2cppConfigFile; + + public LumpFile(string lumpFile, string il2cppConfigFile) + { + this.lumpFile = lumpFile; + this.il2cppConfigFile = il2cppConfigFile; + this.cppFiles.Add(il2cppConfigFile); + } + + public void SaveFile() + { + var lumpFileContent = new List(); + foreach (var file in cppFiles) + { + lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\""); + } + File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8); + Debug.Log($"create lump file:{lumpFile}"); + } + } + + private static List CreateLumps(string libil2cppDir, string outputDir) + { + BashUtil.RecreateDir(outputDir); + + string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h"; + var lumpFiles = new List(); + int lumpFileIndex = 0; + foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir})) + { + var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile); + foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly)) + { + lumpFile.cppFiles.Add(file); + } + lumpFile.SaveFile(); + lumpFiles.Add(lumpFile); + ++lumpFileIndex; + } + + var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories); + if (mmFiles.Length > 0) + { + var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile); + foreach (var file in mmFiles) + { + lumpFile.cppFiles.Add(file); + } + lumpFile.SaveFile(); + lumpFiles.Add(lumpFile); + } + return lumpFiles; + } + + private static List GetExtraSourceFiles(string externalDir, string libil2cppDir) + { + var files = new List(); + foreach (string extraDir in new string[] + { + $"{externalDir}/zlib", + $"{externalDir}/xxHash", + $"{libil2cppDir}/os/ClassLibraryPAL/brotli", + }) + { + if (!Directory.Exists(extraDir)) + { + continue; + } + files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories)); + } + return files; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs.meta new file mode 100644 index 0000000..64df093 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2019.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2f62ca12f2eb4f2fba8e9cb51279421 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs similarity index 93% rename from Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs rename to Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs index b0788aa..a7ebc3a 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs @@ -7,7 +7,7 @@ using System.Text; using UnityEditor; using System.Reflection; using HybridCLR.Editor.Settings; -#if (UNITY_2020 || UNITY_2021) && UNITY_IOS +#if (UNITY_2020 || UNITY_2021) && (UNITY_IOS || UNITY_TVOS) using UnityEditor.Build; using UnityEditor.Callbacks; using UnityEditor.iOS.Xcode; @@ -15,24 +15,13 @@ using UnityEngine; namespace HybridCLR.Editor.BuildProcessors { - public static class AddLil2cppSourceCodeToXcodeproj2021OrOlder + public static class AddLil2cppSourceCodeToXcodeproj2020Or2021 { - //[MenuItem("Test/GenProj")] - //public static void Modify() - //{ - // OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS"); - //} - - //[MenuItem("Test/CreateLumps")] - //public static void CreateLumpsCmd() - //{ - // CreateLumps($"{SettingsUtil.LocalIl2CppDir}/libil2cpp", $"{SettingsUtil.HybridCLRDataDir}/lumps"); - //} [PostProcessBuild] public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) { - if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable) + if (!HybridCLRSettings.Instance.enable) return; /* * 1. 生成lump,并且添加到工程 @@ -46,7 +35,7 @@ namespace HybridCLR.Editor.BuildProcessors 9. add external/xxHash */ - string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj"; + string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject); string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp"; string lumpDir = $"{pathToBuiltProject}/Libraries/lumps"; @@ -132,6 +121,7 @@ namespace HybridCLR.Editor.BuildProcessors { newPro += " $(SRCROOT)/Libraries/external/xxHash"; } + newPro += " $(SRCR00T)/Libraries/external/mono"; //Debug.Log($"config:{bcn} new prop:{newPro}"); proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro); diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs.meta new file mode 100644 index 0000000..7eba538 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2020Or2021.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61948fcb1bc40ba47b8c10b0ae801ebb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs index e1cdd9e..084e388 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs @@ -2,47 +2,72 @@ using HybridCLR.Editor.Installer; using HybridCLR.Editor.Settings; using System.IO; using System.Text; +using System.Text.RegularExpressions; using UnityEditor; using UnityEditor.Build; using UnityEditor.Callbacks; using UnityEngine; -#if UNITY_2022_2_OR_NEWER && UNITY_IOS +#if UNITY_2022 && (UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS) namespace HybridCLR.Editor.BuildProcessors { public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer { - //[MenuItem("HybridCLR/Modfiyxcode")] - //public static void Modify() - //{ - // OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS"); - //} [PostProcessBuild] public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) { - if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable) + if (!HybridCLRSettings.Instance.enable) return; - - string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj"; + string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject); RemoveExternalLibil2cppOption(pbxprojFile); CopyLibil2cppToXcodeProj(pathToBuiltProject); } + private static string TryRemoveDunplicateShellScriptSegment(string pbxprojFile, string pbxprojContent) + { + // will appear duplicated Shell Script segment when append to existed xcode project. + // This is unity bug. + // we remove duplicated Shell Script to avoid build error. + string copyFileComment = @"/\* CopyFiles \*/,\s+([A-Z0-9]{24}) /\* ShellScript \*/,\s+([A-Z0-9]{24}) /\* ShellScript \*/,"; + var m = Regex.Match(pbxprojContent, copyFileComment, RegexOptions.Multiline); + if (!m.Success) + { + return pbxprojContent; + } + + if (m.Groups[1].Value != m.Groups[2].Value) + { + throw new BuildFailedException($"find invalid /* ShellScript */ segment"); + } + + int startIndexOfDupShellScript = m.Groups[2].Index; + int endIndexOfDupShellScript = pbxprojContent.IndexOf(",", startIndexOfDupShellScript); + + pbxprojContent = pbxprojContent.Remove(startIndexOfDupShellScript, endIndexOfDupShellScript + 1 - startIndexOfDupShellScript); + Debug.LogWarning($"[AddLil2cppSourceCodeToXcodeproj] remove duplicated '/* ShellScript */' from file '{pbxprojFile}'"); + return pbxprojContent; + } + private static void RemoveExternalLibil2cppOption(string pbxprojFile) { string pbxprojContent = File.ReadAllText(pbxprojFile, Encoding.UTF8); string removeBuildOption = @"--external-lib-il2-cpp=\""$PROJECT_DIR/Libraries/libil2cpp.a\"""; - if (!pbxprojContent.Contains(removeBuildOption)) + if (pbxprojContent.Contains(removeBuildOption)) { - //throw new BuildFailedException("modified project.pbxproj fail"); - Debug.LogError("[AddLil2cppSourceCodeToXcodeproj] modified project.pbxproj fail"); - return; + pbxprojContent = pbxprojContent.Replace(removeBuildOption, ""); + Debug.Log($"[AddLil2cppSourceCodeToXcodeproj] remove il2cpp build option '{removeBuildOption}' from file '{pbxprojFile}'"); } - pbxprojContent = pbxprojContent.Replace(removeBuildOption, ""); + else + { + Debug.LogWarning($"[AddLil2cppSourceCodeToXcodeproj] project.pbxproj remove building option:'{removeBuildOption}' fail. This may occur when 'Append' to existing xcode project in building"); + } + + pbxprojContent = TryRemoveDunplicateShellScriptSegment(pbxprojFile, pbxprojContent); + + File.WriteAllText(pbxprojFile, pbxprojContent, Encoding.UTF8); - Debug.Log($"[AddLil2cppSourceCodeToXcodeproj] remove il2cpp build option '{removeBuildOption}' from file '{pbxprojFile}'"); } private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject) diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta index b068634..e71a765 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 564da67930cda6449b2c6d58a756ce91 +guid: a4ce072f7e4a17248a3d9ebfd011356b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs new file mode 100644 index 0000000..a3c880c --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs @@ -0,0 +1,34 @@ +using HybridCLR.Editor.Installer; +using HybridCLR.Editor.Settings; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Callbacks; +using UnityEngine; + +#if UNITY_2023_1_OR_NEWER && (UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS) + +namespace HybridCLR.Editor.BuildProcessors +{ + public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer + { + + [PostProcessBuild] + public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) + { + if (!HybridCLRSettings.Instance.enable) + return; + CopyLibil2cppToXcodeProj(pathToBuiltProject); + } + + private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject) + { + string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; + string destLibil2cppDir = $"{pathToBuiltProject}/Il2CppOutputProject/IL2CPP/libil2cpp"; + BashUtil.RemoveDir(destLibil2cppDir); + BashUtil.CopyDir(srcLibil2cppDir, destLibil2cppDir, true); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs.meta new file mode 100644 index 0000000..af06bb0 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2023OrNewer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2fa46135129b046a28014d58fdfd18ca \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs new file mode 100644 index 0000000..7bb4f77 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; +using UnityEditor.Build; + +namespace HybridCLR.Editor.BuildProcessors +{ + + public static class BuildProcessorUtil + { + + public static string GetXcodeProjectFile(string pathToBuiltProject) + { + foreach (string dir in Directory.GetDirectories(pathToBuiltProject, "*.xcodeproj", SearchOption.TopDirectoryOnly)) + { + string pbxprojFile = $"{dir}/project.pbxproj"; + if (File.Exists(pbxprojFile)) + { + return pbxprojFile; + } + } + throw new BuildFailedException($"can't find xxxx.xcodeproj/project.pbxproj in {pathToBuiltProject}"); + } + } +} + diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs.meta new file mode 100644 index 0000000..6cd79d2 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/BuildProcessorUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c680e56f90f2745298a90803c04f6efc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs index a5840bc..994683b 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs @@ -1,8 +1,10 @@ using HybridCLR.Editor.Settings; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using UnityEditor; using UnityEditor.Build; @@ -16,6 +18,8 @@ namespace HybridCLR.Editor.BuildProcessors { public int callbackOrder => 0; + public static bool DisableMethodBridgeDevelopmentFlagChecking { get; set; } + public void OnPreprocessBuild(BuildReport report) { HybridCLRSettings globalSettings = SettingsUtil.HybridCLRSettings; @@ -67,6 +71,24 @@ namespace HybridCLR.Editor.BuildProcessors Debug.LogWarning("[CheckSettings] No hot update modules configured in HybridCLRSettings"); } + if (!DisableMethodBridgeDevelopmentFlagChecking) + { + string methodBridgeFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; + var match = Regex.Match(File.ReadAllText(methodBridgeFile), @"// DEVELOPMENT=(\d)"); + if (match.Success) + { + int developmentFlagInMethodBridge = int.Parse(match.Groups[1].Value); + int developmentFlagInEditorSettings = EditorUserBuildSettings.development ? 1 : 0; + if (developmentFlagInMethodBridge != developmentFlagInEditorSettings) + { + Debug.LogError($"[CheckSettings] MethodBridge.cpp DEVELOPMENT flag:{developmentFlagInMethodBridge} is inconsistent with EditorUserBuildSettings.development:{developmentFlagInEditorSettings}. Please run 'HybridCLR/Generate/All' before building."); + } + } + else + { + Debug.LogError("[CheckSettings] MethodBridge.cpp DEVELOPMENT flag not found. Please run 'HybridCLR/Generate/All' before building."); + } + } } } } diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs.meta index 7ad0ce7..0cc3643 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/CheckSettings.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0425d3c70acfefd419fce243fb05cdbe +guid: fb4ba063068b17247b2d0233420aa5f0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs index 1d3259e..9630316 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs @@ -8,9 +8,11 @@ using System.Threading.Tasks; using UnityEditor; using UnityEditor.Build; using UnityEditor.Build.Reporting; -using UnityEditor.Il2Cpp; using UnityEditor.UnityLinker; using UnityEngine; +#if !UNITY_2021_1_OR_NEWER +using UnityEditor.Il2Cpp; +#endif namespace HybridCLR.Editor.BuildProcessors { @@ -33,11 +35,28 @@ namespace HybridCLR.Editor.BuildProcessors return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped"; case BuildTarget.StandaloneLinux64: return $"{projectDir}/Library/Bee/artifacts/LinuxPlayerBuildProgram/ManagedStripped"; + case BuildTarget.WSAPlayer: + return $"{projectDir}/Library/Bee/artifacts/UWPPlayerBuildProgram/ManagedStripped"; case BuildTarget.Android: return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped"; +#if TUANJIE_2022_3_OR_NEWER + case BuildTarget.HMIAndroid: + return $"{projectDir}/Library/Bee/artifacts/HMIAndroid/ManagedStripped"; +#endif case BuildTarget.iOS: - return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped"; - case BuildTarget.WebGL: +#if UNITY_TVOS + case BuildTarget.tvOS: +#endif + return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped"; +#if UNITY_VISIONOS + case BuildTarget.VisionOS: +#if UNITY_6000_0_OR_NEWER + return $"{projectDir}/Library/Bee/artifacts/VisionOS/ManagedStripped"; +#else + return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped"; +#endif +#endif + case BuildTarget.WebGL: return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped"; case BuildTarget.StandaloneOSX: return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped"; @@ -45,6 +64,14 @@ namespace HybridCLR.Editor.BuildProcessors return $"{projectDir}/Library/Bee/artifacts/PS4PlayerBuildProgram/ManagedStripped"; case BuildTarget.PS5: return $"{projectDir}/Library/Bee/artifacts/PS5PlayerBuildProgram/ManagedStripped"; +#if UNITY_WEIXINMINIGAME + case BuildTarget.WeixinMiniGame: + return $"{projectDir}/Library/Bee/artifacts/WeixinMiniGame/ManagedStripped"; +#endif +#if UNITY_OPENHARMONY + case BuildTarget.OpenHarmony: + return $"{projectDir}/Library/Bee/artifacts/OpenHarmonyPlayerBuildProgram/ManagedStripped"; +#endif default: return ""; } } @@ -58,9 +85,9 @@ namespace HybridCLR.Editor.BuildProcessors } public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) - { - // 此回调只在 2020中调用 - CopyStripDlls(GetStripAssembliesDir2020(data.target), data.target); + { + BuildTarget target = report.summary.platform; + CopyStripDlls(GetStripAssembliesDir2020(target), target); } #endif @@ -88,7 +115,7 @@ namespace HybridCLR.Editor.BuildProcessors public void OnPostprocessBuild(BuildReport report) { #if UNITY_2021_1_OR_NEWER - BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildTarget target = report.summary.platform; string srcStripDllPath = GetStripAssembliesDir2021(target); if (!string.IsNullOrEmpty(srcStripDllPath) && Directory.Exists(srcStripDllPath)) { @@ -99,7 +126,7 @@ namespace HybridCLR.Editor.BuildProcessors public void OnPreprocessBuild(BuildReport report) { - BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + BuildTarget target = report.summary.platform; var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); BashUtil.RecreateDir(dstPath); } diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta index 9e4b979..3ebc0e1 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7b3e12909c8952c42876eccaa7cf2d08 +guid: f7884710ec2f8e545b3fe9aa05def5a8 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta index cf28fc4..2ab4ba5 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c881272ec3c0f3b49a7a6cafc02303e6 +guid: 9dec2922e3df5464aa047b636eb19e0d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta index 6ce4471..ef28c51 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: de6aa0faf1b682c4580f5122958b35c8 +guid: 8bff6cadf0b8db54b87ba51b24d080f6 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs b/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs index ee21b9b..b376fc5 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs @@ -1,4 +1,5 @@ -using System; +using HybridCLR.Editor.UnityBinFileReader; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -8,15 +9,20 @@ using UnityEditor; using UnityEditor.Android; using UnityEditor.Build; using UnityEditor.Build.Reporting; -using UnityEditor.Il2Cpp; using UnityEditor.UnityLinker; using UnityEngine; +using UnityFS; +#if !UNITY_2023_1_OR_NEWER +using UnityEditor.Il2Cpp; +#endif namespace HybridCLR.Editor.BuildProcessors { public class PatchScriptingAssemblyList : #if UNITY_ANDROID IPostGenerateGradleAndroidProject, +#elif UNITY_OPENHARMONY + UnityEditor.OpenHarmony.IPostGenerateOpenHarmonyProject, #endif IPostprocessBuildWithReport #if !UNITY_2021_1_OR_NEWER && UNITY_WEBGL @@ -45,11 +51,20 @@ namespace HybridCLR.Editor.BuildProcessors } } +#if UNITY_OPENHARMONY + + public void OnPostGenerateOpenHarmonyProject(string path) + { + OnPostGenerateGradleAndroidProject(path); + } + +#endif + public void OnPostprocessBuild(BuildReport report) { // 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过, // 这里不再重复处理 -#if !UNITY_ANDROID && !UNITY_WEBGL +#if !UNITY_ANDROID && !UNITY_WEBGL && !UNITY_OPENHARMONY PathScriptingAssembilesFile(report.summary.outputPath); #endif } @@ -79,7 +94,11 @@ namespace HybridCLR.Editor.BuildProcessors path = Path.GetDirectoryName(path); Debug.Log($"[PatchScriptingAssemblyList] get path parent:{path}"); } +#if UNITY_2020_1_OR_NEWER AddHotFixAssembliesToScriptingAssembliesJson(path); +#else + AddHotFixAssembliesToBinFile(path); +#endif } private void AddHotFixAssembliesToScriptingAssembliesJson(string path) @@ -106,8 +125,61 @@ namespace HybridCLR.Editor.BuildProcessors patcher.Save(file); } } + private void AddHotFixAssembliesToBinFile(string path) + { +#if UNITY_STANDALONE_OSX + path = Path.GetDirectoryName(path); +#endif + if (AddHotFixAssembliesToGlobalgamemanagers(path)) + { + return; + } + if (AddHotFixAssembliesTodataunity3d(path)) + { + return; + } + Debug.LogError($"[PatchScriptingAssemblyList] can not find file '{SettingsUtil.GlobalgamemanagersBinFile}' or '{SettingsUtil.Dataunity3dBinFile}' in '{path}'"); + } -#if UNITY_WEBGL + private bool AddHotFixAssembliesToGlobalgamemanagers(string path) + { + string[] binFiles = Directory.GetFiles(path, SettingsUtil.GlobalgamemanagersBinFile, SearchOption.AllDirectories); + + if (binFiles.Length == 0) + { + return false; + } + + foreach (string binPath in binFiles) + { + var binFile = new UnityBinFile(); + binFile.Load(binPath); + binFile.AddScriptingAssemblies(SettingsUtil.HotUpdateAssemblyFilesIncludePreserved); + binFile.Save(binPath); + Debug.Log($"[PatchScriptingAssemblyList] patch {binPath}"); + } + return true; + } + + private bool AddHotFixAssembliesTodataunity3d(string path) + { + string[] binFiles = Directory.GetFiles(path, SettingsUtil.Dataunity3dBinFile, SearchOption.AllDirectories); + + if (binFiles.Length == 0) + { + return false; + } + + foreach (string binPath in binFiles) + { + var patcher = new Dataunity3dPatcher(); + patcher.ApplyPatch(binPath, SettingsUtil.HotUpdateAssemblyFilesIncludePreserved); + Debug.Log($"[PatchScriptingAssemblyList] patch {binPath}"); + } + return true; + } + +#if UNITY_WEBGL && !UNITY_2022_3_OR_NEWER public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) { PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Temp/StagingArea/Data"); diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta index 62e1fec..0affdc7 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c2478bcce37605a41a5b203b71a35bc7 +guid: 9bb6e2908d8948648979c9ff6bb7937d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta b/Assets/01.HybridCLR/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta index 3eb326d..c4c07e0 100644 --- a/Assets/01.HybridCLR/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta +++ b/Assets/01.HybridCLR/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: aa8f99fec010a2b49a3f487c2f6a5dbc +guid: 4455f7304f8678f408dd6cf21734f55e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands.meta b/Assets/01.HybridCLR/Editor/Commands.meta index b4fabe4..c61c778 100644 --- a/Assets/01.HybridCLR/Editor/Commands.meta +++ b/Assets/01.HybridCLR/Editor/Commands.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 56bc55ec11fc6f84a93f250b698b30f9 +guid: 92f51c069d2607447ae2f61de80540fb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs b/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs index c426f1d..b4dfb41 100644 --- a/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs @@ -2,6 +2,7 @@ using HybridCLR.Editor.Meta; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -22,25 +23,110 @@ namespace HybridCLR.Editor.Commands GenerateAOTGenericReference(target); } + /// + /// 计算热更代码中的泛型引用 + /// + /// public static void GenerateAOTGenericReference(BuildTarget target) { var gs = SettingsUtil.HybridCLRSettings; List hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; - using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames)) + AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames); + var analyzer = new Analyzer(new Analyzer.Options { - var analyzer = new Analyzer(new Analyzer.Options - { - MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), - Collector = collector, - }); + MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), + Collector = collector, + }); - analyzer.Run(); + analyzer.Run(); - var writer = new GenericReferenceWriter(); - writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); - AssetDatabase.Refresh(); + var writer = new GenericReferenceWriter(); + writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); + AssetDatabase.Refresh(); + } + + + + //[MenuItem("HybridCLR/Generate/AOTGenericReference2", priority = 103)] + //public static void GeneratedAOTGenericReferenceExcludeExists() + //{ + // GeneratedAOTGenericReferenceExcludeExists(EditorUserBuildSettings.activeBuildTarget); + //} + + /// + /// 计算热更新代码中的泛型引用,但排除AOT已经存在的泛型引用 + /// + /// + /// + public static void GeneratedAOTGenericReferenceExcludeExistsAOTClassAndMethods(BuildTarget target) + { + + var gs = SettingsUtil.HybridCLRSettings; + List hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + + AssemblyReferenceDeepCollector hotUpdateCollector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames); + var hotUpdateAnalyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(10, gs.maxGenericReferenceIteration), + Collector = hotUpdateCollector, + }); + + hotUpdateAnalyzer.Run(); + + + string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + List aotAssemblyNames = Directory.Exists(aotDllDir) ? + Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList() + : new List(); + if (aotAssemblyNames.Count == 0) + { + throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/AOTGenericReference`"); } + AssemblyReferenceDeepCollector aotCollector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames); + var aotAnalyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(10, gs.maxGenericReferenceIteration), + Collector = aotCollector, + ComputeAotAssembly = true, + }); + + aotAnalyzer.Run(); + + var (resultTypes, resultMethods) = ExcludeExistAOTGenericTypeAndMethodss(hotUpdateAnalyzer.AotGenericTypes.ToList(), hotUpdateAnalyzer.AotGenericMethods.ToList(), aotAnalyzer.AotGenericTypes.ToList(), aotAnalyzer.AotGenericMethods.ToList()); + var writer = new GenericReferenceWriter(); + writer.Write(resultTypes, resultMethods, $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); + AssetDatabase.Refresh(); + } + + + private static (List, List) ExcludeExistAOTGenericTypeAndMethodss(List hotUpdateTypes, List hotUpdateMethods, List aotTypes, List aotMethods) + { + var types = new List(); + + var typeSig2Type = hotUpdateTypes.ToDictionary(t => t.Type.DefinitionAssembly.Name + ":" + t.ToTypeSig(), t => t); + foreach (var t in aotTypes) + { + string key = t.Type.DefinitionAssembly.Name + ":" + t.ToTypeSig(); + if (typeSig2Type.TryGetValue(key, out var removedType)) + { + typeSig2Type.Remove(key); + Debug.Log($"remove AOT type:{removedType.ToTypeSig()} "); + } + } + + var methodSig2Method = hotUpdateMethods.ToDictionary(m => m.Method.DeclaringType.DefinitionAssembly.Name + ":" + m.ToMethodSpec().ToString(), m => m); + foreach (var m in aotMethods) + { + string key = m.Method.DeclaringType.DefinitionAssembly.Name + ":" + m.ToMethodSpec().ToString(); + if (methodSig2Method.TryGetValue(key, out var removedMethod)) + { + methodSig2Method.Remove(key); + Debug.Log($"remove AOT method:{removedMethod.ToMethodSpec()} "); + } + } + + return (typeSig2Type.Values.ToList(), methodSig2Method.Values.ToList()); } } } diff --git a/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta index 05d44bc..39760e8 100644 --- a/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5c551ca444cd0af44bc060b024a9bc35 +guid: 2b464872c07f6ba4f9a4e4a02ca9a28c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs b/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs index a26b97d..583368e 100644 --- a/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs @@ -25,10 +25,15 @@ namespace HybridCLR.Editor.Commands #if UNITY_2022 UnityEditor.EditorUtility.ClearProgressBar(); #endif - Debug.Log("compile finish!!!"); + Debug.Log($"compile finish!!! buildDir:{buildDir} target:{target} development:{developmentBuild}"); } - public static void CompileDll(BuildTarget target, bool developmentBuild = false) + public static void CompileDll(BuildTarget target) + { + CompileDll(target, EditorUserBuildSettings.development); + } + + public static void CompileDll(BuildTarget target, bool developmentBuild) { CompileDll(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), target, developmentBuild); } @@ -36,10 +41,16 @@ namespace HybridCLR.Editor.Commands [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget", priority = 100)] public static void CompileDllActiveBuildTarget() { - CompileDll(EditorUserBuildSettings.activeBuildTarget); + CompileDll(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.development); } - [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Development", priority = 101)] + [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Release", priority = 102)] + public static void CompileDllActiveBuildTargetRelease() + { + CompileDll(EditorUserBuildSettings.activeBuildTarget, false); + } + + [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Development", priority = 104)] public static void CompileDllActiveBuildTargetDevelopment() { CompileDll(EditorUserBuildSettings.activeBuildTarget, true); diff --git a/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs.meta index bad9cec..88b2e30 100644 --- a/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/CompileDllCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 33d7af1ee2e66f645a539ab3f1ffd005 +guid: bf11b6c8bbc5afd4cb4a11921e5bd81e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs b/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs index a56c2b0..44890ee 100644 --- a/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs @@ -1,4 +1,5 @@ using HybridCLR.Editor.Link; +using HybridCLR.Editor.Settings; using System; using System.Collections.Generic; using System.Linq; @@ -19,8 +20,10 @@ namespace HybridCLR.Editor.Commands { UnityVersion = Application.unityVersion, HotUpdateAssemblies = SettingsUtil.HotUpdateAssemblyNamesIncludePreserved, - OutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/UnityVersion.h", - OutputFile2 = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/AssemblyManifest.cpp", + UnityVersionTemplateFile = $"{SettingsUtil.TemplatePathInPackage}/UnityVersion.h.tpl", + UnityVersionOutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/UnityVersion.h", + AssemblyManifestTemplateFile = $"{SettingsUtil.TemplatePathInPackage}/AssemblyManifest.cpp.tpl", + AssemblyManifestOutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/AssemblyManifest.cpp", }; var g = new Il2CppDef.Il2CppDefGenerator(options); diff --git a/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta index f426b8b..21f9427 100644 --- a/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 835086949fb644c42b3bede85daafaf8 +guid: 5165a065d05497c43a2fff885f31ed07 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/LinkGeneratorCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/LinkGeneratorCommand.cs.meta index 6748060..0eeba1f 100644 --- a/Assets/01.HybridCLR/Editor/Commands/LinkGeneratorCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/LinkGeneratorCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3a93a166688011348927f18ea533d9d8 +guid: 4f5b96abdbc4c424eb1bc3bc34b3a1a4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs b/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs index fde1084..0ebdce0 100644 --- a/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs @@ -30,29 +30,31 @@ namespace HybridCLR.Editor.Commands Directory.Delete(il2cppBuildCachePath, true); } - private static void GenerateMethodBridgeCppFile(Analyzer analyzer, string outputFile) + private static void GenerateMethodBridgeCppFile(IReadOnlyCollection genericMethods, List reversePInvokeMethods, IReadOnlyCollection calliMethodSignatures, string tempFile, string outputFile) { - string templateCode = File.ReadAllText(outputFile, Encoding.UTF8); + string templateCode = File.ReadAllText(tempFile, Encoding.UTF8); var g = new Generator(new Generator.Options() { TemplateCode = templateCode, OutputFile = outputFile, - GenericMethods = analyzer.GenericMethods, + GenericMethods = genericMethods, + ReversePInvokeMethods = reversePInvokeMethods, + CalliMethodSignatures = calliMethodSignatures, + Development = EditorUserBuildSettings.development, }); - g.PrepareMethods(); g.Generate(); Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile); } - [MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)] - public static void CompileAndGenerateMethodBridge() + [MenuItem("HybridCLR/Generate/MethodBridgeAndReversePInvokeWrapper", priority = 101)] + public static void GenerateMethodBridgeAndReversePInvokeWrapper() { BuildTarget target = EditorUserBuildSettings.activeBuildTarget; - GenerateMethodBridge(target); + GenerateMethodBridgeAndReversePInvokeWrapper(target); } - public static void GenerateMethodBridge(BuildTarget target) + public static void GenerateMethodBridgeAndReversePInvokeWrapper(BuildTarget target) { string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); List aotAssemblyNames = Directory.Exists(aotDllDir) ? @@ -62,18 +64,33 @@ namespace HybridCLR.Editor.Commands { throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`"); } - using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames)) - { - var analyzer = new Analyzer(new Analyzer.Options - { - MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), - Collector = collector, - }); + AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames); - analyzer.Run(); - string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; - GenerateMethodBridgeCppFile(analyzer, outputFile); - } + var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), + Collector = collector, + }); + + methodBridgeAnalyzer.Run(); + + List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls)); + + var reversePInvokeAnalyzer = new MonoPInvokeCallbackAnalyzer(cache, hotUpdateDlls); + reversePInvokeAnalyzer.Run(); + + var calliAnalyzer = new CalliAnalyzer(cache, hotUpdateDlls); + calliAnalyzer.Run(); + var pinvokeAnalyzer = new PInvokeAnalyzer(cache, hotUpdateDlls); + pinvokeAnalyzer.Run(); + var callPInvokeMethodSignatures = pinvokeAnalyzer.PInvokeMethodSignatures; + + string templateFile = $"{SettingsUtil.TemplatePathInPackage}/MethodBridge.cpp.tpl"; + string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; + + var callNativeMethodSignatures = calliAnalyzer.CalliMethodSignatures.Concat(pinvokeAnalyzer.PInvokeMethodSignatures).ToList(); + GenerateMethodBridgeCppFile(methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, callNativeMethodSignatures, templateFile, outputFile); CleanIl2CppBuildCache(); } diff --git a/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta index 9d2b1fe..9827997 100644 --- a/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d0c8247b111383b44afd088ac0bde458 +guid: 46bc62d5236f5e941850776c435a9560 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs b/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs index 8fe2a46..3278802 100644 --- a/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEditor; +using UnityEditor.Build; namespace HybridCLR.Editor.Commands { @@ -15,8 +16,13 @@ namespace HybridCLR.Editor.Commands [MenuItem("HybridCLR/Generate/All", priority = 200)] public static void GenerateAll() { + var installer = new Installer.InstallerController(); + if (!installer.HasInstalledHybridCLR()) + { + throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'"); + } BuildTarget target = EditorUserBuildSettings.activeBuildTarget; - CompileDllCommand.CompileDll(target); + CompileDllCommand.CompileDll(target, EditorUserBuildSettings.development); Il2CppDefGeneratorCommand.GenerateIl2CppDef(); // 这几个生成依赖HotUpdateDlls @@ -26,8 +32,7 @@ namespace HybridCLR.Editor.Commands StripAOTDllCommand.GenerateStripedAOTDlls(target); // 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll - MethodBridgeGeneratorCommand.GenerateMethodBridge(target); - ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target); + MethodBridgeGeneratorCommand.GenerateMethodBridgeAndReversePInvokeWrapper(target); AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); } } diff --git a/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs.meta index 6747ddf..a27aea2 100644 --- a/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/PrebuildCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f0862bf1b7a39754d8c6c6005d26f4d3 +guid: c20f09bfbe3f32143aae872d3813d9e9 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs b/Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs deleted file mode 100644 index 706e748..0000000 --- a/Assets/01.HybridCLR/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs +++ /dev/null @@ -1,49 +0,0 @@ -using HybridCLR.Editor.ABI; -using HybridCLR.Editor.Link; -using HybridCLR.Editor.Meta; -using HybridCLR.Editor.ReversePInvokeWrap; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using UnityEditor; -using UnityEngine; - -namespace HybridCLR.Editor.Commands -{ - - public static class ReversePInvokeWrapperGeneratorCommand - { - - [MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)] - - public static void CompileAndGenerateReversePInvokeWrapper() - { - BuildTarget target = EditorUserBuildSettings.activeBuildTarget; - CompileDllCommand.CompileDll(target); - GenerateReversePInvokeWrapper(target); - } - - public static void GenerateReversePInvokeWrapper(BuildTarget target) - { - List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; - using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls))) - { - var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); - analyzer.Run(); - - string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp"; - - List methods = analyzer.BuildABIMethods(); - Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}"); - var generator = new Generator(); - generator.Generate(methods, outputFile); - Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile); - } - MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); - } - } -} diff --git a/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs b/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs index f340c1e..8e6560a 100644 --- a/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs +++ b/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs @@ -1,4 +1,5 @@ -using HybridCLR.Editor.Installer; +using HybridCLR.Editor.BuildProcessors; +using HybridCLR.Editor.Installer; using System; using System.Collections.Generic; using System.IO; @@ -56,11 +57,11 @@ namespace HybridCLR.Editor.Commands switch(target) { case BuildTarget.StandaloneWindows: - case BuildTarget.StandaloneWindows64: return $"{buildDir}/{target}"; + case BuildTarget.StandaloneWindows64: return $"{buildDir}/{PlayerSettings.productName}.exe"; case BuildTarget.StandaloneOSX: return buildDir; case BuildTarget.iOS: return buildDir; case BuildTarget.Android: return buildDir; - case BuildTarget.StandaloneLinux64: return buildDir; + case BuildTarget.StandaloneLinux64: return $"{buildDir}/{PlayerSettings.productName}"; default: return buildDir; } } @@ -71,91 +72,124 @@ namespace HybridCLR.Editor.Commands BashUtil.RemoveDir(outputPath); var buildOptions = GetBuildPlayerOptions(target); -#if UNITY_2021_2_OR_NEWER - buildOptions |= BuildOptions.CleanBuildCache; -#endif bool oldExportAndroidProj = EditorUserBuildSettings.exportAsGoogleAndroidProject; #if UNITY_EDITOR_OSX bool oldCreateSolution = UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject; #elif UNITY_EDITOR_WIN bool oldCreateSolution = UnityEditor.WindowsStandalone.UserBuildSettings.createSolution; +#endif +#if TUANJIE_2022_3_OR_NEWER + bool oldOpenHarmonyProj = EditorUserBuildSettings.exportAsOpenHarmonyProject; #endif bool oldBuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly; - EditorUserBuildSettings.buildScriptsOnly = true; - string location = GetLocationPathName(outputPath, target); string oldBuildLocation = EditorUserBuildSettings.GetBuildLocation(target); - EditorUserBuildSettings.SetBuildLocation(target, location); - - switch (target) + try { - case BuildTarget.StandaloneWindows: - case BuildTarget.StandaloneWindows64: + CheckSettings.DisableMethodBridgeDevelopmentFlagChecking = true; + EditorUserBuildSettings.buildScriptsOnly = true; + + string location = GetLocationPathName(outputPath, target); + EditorUserBuildSettings.SetBuildLocation(target, location); + + switch (target) { -#if UNITY_EDITOR_WIN - UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = true; -#endif + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + { + #if UNITY_EDITOR_WIN + UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = true; + #endif + break; + } + case BuildTarget.StandaloneOSX: + { + #if UNITY_EDITOR_OSX + UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = true; + #endif break; + } + #if TUANJIE_2022_3_OR_NEWER + case BuildTarget.HMIAndroid: + #endif + case BuildTarget.Android: + { + EditorUserBuildSettings.exportAsGoogleAndroidProject = true; + break; + } + #if TUANJIE_2022_3_OR_NEWER + case BuildTarget.OpenHarmony: + { + EditorUserBuildSettings.exportAsOpenHarmonyProject = true; + break; + } + #endif } - case BuildTarget.StandaloneOSX: + + Debug.Log($"GenerateStripedAOTDlls build option:{buildOptions}"); + + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions() { -#if UNITY_EDITOR_OSX - UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = true; + scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(), + locationPathName = location, + options = buildOptions, + target = target, + targetGroup = BuildPipeline.GetBuildTargetGroup(target), +#if UNITY_2021_1_OR_NEWER + subtarget = (int)EditorUserBuildSettings.standaloneBuildSubtarget, #endif - break; - } - case BuildTarget.Android: + }; + + var report = BuildPipeline.BuildPlayer(buildPlayerOptions); + + + + if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) { - EditorUserBuildSettings.exportAsGoogleAndroidProject = true; - break; + throw new Exception("GenerateStripedAOTDlls failed"); } } - - Debug.Log($"GenerateStripedAOTDlls build option:{buildOptions}"); - - BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions() + finally { - scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(), - locationPathName = location, - options = buildOptions, - target = target, - targetGroup = BuildPipeline.GetBuildTargetGroup(target), - }; + CheckSettings.DisableMethodBridgeDevelopmentFlagChecking = false; + EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly; + EditorUserBuildSettings.SetBuildLocation(target, oldBuildLocation); - var report = BuildPipeline.BuildPlayer(buildPlayerOptions); - - EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly; - EditorUserBuildSettings.SetBuildLocation(target, oldBuildLocation); - - switch (target) - { - case BuildTarget.StandaloneWindows: - case BuildTarget.StandaloneWindows64: + switch (target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: { #if UNITY_EDITOR_WIN - UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = oldCreateSolution; + UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = oldCreateSolution; #endif break; } - case BuildTarget.StandaloneOSX: + case BuildTarget.StandaloneOSX: { #if UNITY_EDITOR_OSX - UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = oldCreateSolution; + UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = oldCreateSolution; #endif break; } - case BuildTarget.Android: - { - EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj; - break; +#if TUANJIE_2022_3_OR_NEWER + case BuildTarget.HMIAndroid: +#endif + case BuildTarget.Android: + { + EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj; + break; + } +#if TUANJIE_2022_3_OR_NEWER + case BuildTarget.OpenHarmony: + { + EditorUserBuildSettings.exportAsOpenHarmonyProject = oldOpenHarmonyProj; + break; + } +#endif } } - - if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) - { - throw new Exception("GenerateStripedAOTDlls failed"); - } Debug.Log($"GenerateStripedAOTDlls target:{target} path:{outputPath}"); } } diff --git a/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs.meta b/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs.meta index 4108177..3979b80 100644 --- a/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs.meta +++ b/Assets/01.HybridCLR/Editor/Commands/StripAOTDllCommand.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c7d81ec59b79a534783f4186872f6c2e +guid: 21fb0a02f23185141a4a3df67fe61789 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/HashUtil.cs.meta b/Assets/01.HybridCLR/Editor/HashUtil.cs.meta index bf67baf..9cdce22 100644 --- a/Assets/01.HybridCLR/Editor/HashUtil.cs.meta +++ b/Assets/01.HybridCLR/Editor/HashUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b471a7bd21e23c24a805b96e1bda4867 +guid: 5d4ae4a5c0bba49469c525887d812717 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/HotUpdate.meta b/Assets/01.HybridCLR/Editor/HotUpdate.meta new file mode 100644 index 0000000..7b7bf3d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/HotUpdate.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e60a8b17b0e23a94a8ae875716208030 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs b/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs new file mode 100644 index 0000000..2459b48 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs @@ -0,0 +1,109 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.HotUpdate +{ + public class MissingMetadataChecker + { + private readonly HashSet _aotAssNames; + + private readonly HashSet _hotUpdateAssNames; + + private readonly AssemblyCache _assCache; + + public MissingMetadataChecker(string aotDllDir, IEnumerable hotUpdateAssNames) + { + + _hotUpdateAssNames = new HashSet(hotUpdateAssNames ?? new List()); + _aotAssNames = new HashSet(); + foreach (var aotFile in Directory.GetFiles(aotDllDir, "*.dll")) + { + string aotAssName = Path.GetFileNameWithoutExtension(aotFile); + if (_hotUpdateAssNames.Contains(aotAssName)) + { + continue; + } + _aotAssNames.Add(aotAssName); + } + _assCache = new AssemblyCache(new PathAssemblyResolver(aotDllDir)); + } + + public bool Check(string hotUpdateDllPath) + { + bool anyMissing = false; + + ModuleDef mod = ModuleDefMD.Load(File.ReadAllBytes(hotUpdateDllPath), _assCache.ModCtx); + + foreach (var refass in mod.GetAssemblyRefs()) + { + string refAssName = refass.Name; + if (_aotAssNames.Contains(refAssName)) + { + _assCache.LoadModule(refass.Name, true); + } + else if (!_hotUpdateAssNames.Contains(refAssName)) + { + UnityEngine.Debug.LogError($"Missing AOT Assembly: {refAssName}"); + anyMissing = true; + } + } + + + foreach (TypeRef typeRef in mod.GetTypeRefs()) + { + string defAssName = typeRef.DefinitionAssembly.Name; + if (!_aotAssNames.Contains(defAssName)) + { + continue; + } + if (typeRef.ResolveTypeDef() == null) + { + UnityEngine.Debug.LogError($"Missing Type: {typeRef.FullName}"); + anyMissing = true; + } + } + + foreach (IMethodDefOrRef memberRef in mod.GetMemberRefs()) + { + if (memberRef.DeclaringType.DefinitionAssembly == null) + { + continue; + } + string defAssName = memberRef.DeclaringType.DefinitionAssembly.Name; + if (!_aotAssNames.Contains(defAssName)) + { + continue; + } + if (memberRef.IsField) + { + IField field = (IField)memberRef; + if (field.ResolveFieldDef() == null) + { + UnityEngine.Debug.LogError($"Missing Field: {memberRef.FullName}"); + anyMissing = true; + } + } + else if (memberRef.IsMethod) + { + TypeSig declaringTypeSig = memberRef.DeclaringType.ToTypeSig(); + if (memberRef.ResolveMethodDef() == null) + { + if (declaringTypeSig.ElementType == ElementType.Array || declaringTypeSig.ElementType == ElementType.SZArray) + { + continue; + } + UnityEngine.Debug.LogError($"Missing Method: {memberRef.FullName}"); + anyMissing = true; + } + } + } + return !anyMissing; + } + } +} diff --git a/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs.meta b/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs.meta new file mode 100644 index 0000000..bc58ca1 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/HotUpdate/MissingMetadataChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bdd260aca2a6deb44b20210f01faa86b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/Il2CppDef.meta b/Assets/01.HybridCLR/Editor/Il2CppDef.meta index 0ce8f8f..dc951ca 100644 --- a/Assets/01.HybridCLR/Editor/Il2CppDef.meta +++ b/Assets/01.HybridCLR/Editor/Il2CppDef.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f9cb756a0fa6d8f4496cff87e042c98e +guid: da46bc9f1a4dece41a5c193166be9a30 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs b/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs index 8728c65..0632750 100644 --- a/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs +++ b/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs @@ -17,9 +17,13 @@ namespace HybridCLR.Editor.Il2CppDef { public List HotUpdateAssemblies { get; set; } - public string OutputFile { get; set; } + public string UnityVersionTemplateFile { get; set; } - public string OutputFile2 { get; set; } + public string UnityVersionOutputFile { get; set; } + + public string AssemblyManifestTemplateFile { get; set; } + + public string AssemblyManifestOutputFile { get; set; } public string UnityVersion { get; set; } } @@ -41,7 +45,7 @@ namespace HybridCLR.Editor.Il2CppDef private void GenerateIl2CppConfig() { - var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile)); + var frr = new FileRegionReplace(File.ReadAllText(_options.UnityVersionTemplateFile)); List lines = new List(); @@ -52,7 +56,14 @@ namespace HybridCLR.Editor.Il2CppDef lines.Add($"#define HYBRIDCLR_UNITY_VERSION {majorVer}{minorVer1.ToString("D2")}{minorVer2.ToString("D2")}"); lines.Add($"#define HYBRIDCLR_UNITY_{majorVer} 1"); - for (int ver = 2019; ver <= 2024; ver++) + for (int ver = 2019; ver <= 2023; ver++) + { + if (majorVer >= ver) + { + lines.Add($"#define HYBRIDCLR_UNITY_{ver}_OR_NEW 1"); + } + } + for (int ver = 6000; ver <= 6100; ver++) { if (majorVer >= ver) { @@ -60,15 +71,25 @@ namespace HybridCLR.Editor.Il2CppDef } } +#if TUANJIE_1_1_OR_NEWER + var tuanjieMatch = Regex.Matches(Application.tuanjieVersion, @"(\d+)\.(\d+)\.(\d+)"); + int tuanjieMajorVer = int.Parse(tuanjieMatch[0].Groups[1].Value); + int tuanjieMinorVer1 = int.Parse(tuanjieMatch[0].Groups[2].Value); + int tuanjieMinorVer2 = int.Parse(tuanjieMatch[0].Groups[3].Value); + lines.Add($"#define HYBRIDCLR_TUANJIE_VERSION {tuanjieMajorVer}{tuanjieMinorVer1.ToString("D2")}{tuanjieMinorVer2.ToString("D2")}"); +#elif TUANJIE_2022_3_OR_NEWER + lines.Add($"#define HYBRIDCLR_TUANJIE_VERSION 10000"); +#endif + frr.Replace("UNITY_VERSION", string.Join("\n", lines)); - frr.Commit(_options.OutputFile); - Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile}"); + frr.Commit(_options.UnityVersionOutputFile); + Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.UnityVersionOutputFile}"); } private void GeneratePlaceHolderAssemblies() { - var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile2)); + var frr = new FileRegionReplace(File.ReadAllText(_options.AssemblyManifestTemplateFile)); List lines = new List(); @@ -79,8 +100,8 @@ namespace HybridCLR.Editor.Il2CppDef frr.Replace("PLACE_HOLDER", string.Join("\n", lines)); - frr.Commit(_options.OutputFile2); - Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile2}"); + frr.Commit(_options.AssemblyManifestOutputFile); + Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.AssemblyManifestOutputFile}"); } } } diff --git a/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta b/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta index d579df3..b7fe9d7 100644 --- a/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta +++ b/Assets/01.HybridCLR/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1fc9bd5aef7ca17418299b743ca6ccc0 +guid: 590419ee7e82ac24cbac9b8a48891fe0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Installer.meta b/Assets/01.HybridCLR/Editor/Installer.meta index 8f70d1c..b27774d 100644 --- a/Assets/01.HybridCLR/Editor/Installer.meta +++ b/Assets/01.HybridCLR/Editor/Installer.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1361cfbdb13f79245891b5e54cf3ccca +guid: a2c8f84b297371d4cbcd5ca655bf360d folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs b/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs index 555f3ca..90e4259 100644 --- a/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs +++ b/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs @@ -83,7 +83,7 @@ namespace HybridCLR.Editor.Installer { RemoveDir(subDir); } - Directory.Delete(dir); + Directory.Delete(dir, true); break; } catch (Exception e) @@ -111,12 +111,12 @@ namespace HybridCLR.Editor.Installer #endif if (srcFile.Length > maxPathLength) { - UnityEngine.Debug.LogError($"srcFile:{srcFile} path is too long. copy ignore!"); + UnityEngine.Debug.LogError($"srcFile:{srcFile} path is too long. skip copy!"); return; } if (dstFile.Length > maxPathLength) { - UnityEngine.Debug.LogError($"dstFile:{dstFile} path is too long. copy ignore!"); + UnityEngine.Debug.LogError($"dstFile:{dstFile} path is too long. skip copy!"); return; } File.Copy(srcFile, dstFile); diff --git a/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs.meta b/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs.meta index 09010ac..ef7e11d 100644 --- a/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs.meta +++ b/Assets/01.HybridCLR/Editor/Installer/BashUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9791af60640dab34a94dcd2636015e7a +guid: 960a0257c3a17f64b810193308ce1558 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs b/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs index 1118994..fd40dbd 100644 --- a/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs +++ b/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs @@ -33,7 +33,7 @@ namespace HybridCLR.Editor.Installer { _curVersion = ParseUnityVersion(Application.unityVersion); _versionManifest = GetHybridCLRVersionManifest(); - _curDefaultVersion = _versionManifest.versions.FirstOrDefault(v => v.unity_version == _curVersion.major.ToString()); + _curDefaultVersion = _versionManifest.versions.FirstOrDefault(v => _curVersion.isTuanjieEngine ? v.unity_version == $"{_curVersion.major}-tuanjie" : v.unity_version == _curVersion.major.ToString()); PackageVersion = LoadPackageInfo().version; InstalledLibil2cppVersion = ReadLocalVersion(); } @@ -88,6 +88,7 @@ namespace HybridCLR.Editor.Installer public int major; public int minor1; public int minor2; + public bool isTuanjieEngine; public override string ToString() { @@ -108,7 +109,8 @@ namespace HybridCLR.Editor.Installer int major = int.Parse(match.Groups[1].Value); int minor1 = int.Parse(match.Groups[2].Value); int minor2 = int.Parse(match.Groups[3].Value); - return new UnityVersion { major = major, minor1 = minor1, minor2 = minor2 }; + bool isTuanjieEngine = versionStr.Contains("t"); + return new UnityVersion { major = major, minor1 = minor1, minor2 = minor2, isTuanjieEngine = isTuanjieEngine }; } public string GetCurrentUnityVersionMinCompatibleVersionStr() @@ -120,9 +122,12 @@ namespace HybridCLR.Editor.Installer { switch(majorVersion) { - case 2020: return $"2020.3.0"; - case 2021: return $"2021.3.0"; - case 2022: return $"2022.3.0"; + case 2019: return "2019.4.0"; + case 2020: return "2020.3.0"; + case 2021: return "2021.3.0"; + case 2022: return "2022.3.0"; + case 2023: return "2023.2.0"; + case 6000: return "6000.0.0"; default: return $"2020.3.0"; } } @@ -141,7 +146,8 @@ namespace HybridCLR.Editor.Installer { return CompatibleType.Incompatible; } - if (version.minor1 != 3) + if ((version.major == 2019 && version.minor1 < 4) + || (version.major >= 2020 && version.major <= 2022 && version.minor1 < 3)) { return CompatibleType.MaybeIncompatible; } @@ -188,6 +194,24 @@ namespace HybridCLR.Editor.Installer return Directory.Exists($"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr"); } + private string GetUnityIl2CppDllInstallLocation() + { +#if UNITY_EDITOR_WIN + return $"{SettingsUtil.LocalIl2CppDir}/build/deploy/net471/Unity.IL2CPP.dll"; +#else + return $"{SettingsUtil.LocalIl2CppDir}/build/deploy/il2cppcore/Unity.IL2CPP.dll"; +#endif + } + + private string GetUnityIl2CppDllModifiedPath(string curVersionStr) + { +#if UNITY_EDITOR_WIN + return $"{SettingsUtil.ProjectDir}/{SettingsUtil.HybridCLRDataPathInPackage}/ModifiedUnityAssemblies/{curVersionStr}/Unity.IL2CPP-Win.dll"; +#else + return $"{SettingsUtil.ProjectDir}/{SettingsUtil.HybridCLRDataPathInPackage}/ModifiedUnityAssemblies/{curVersionStr}/Unity.IL2CPP-Mac.dll"; +#endif + } + void CloneBranch(string workDir, string repoUrl, string branch, string repoDir) { BashUtil.RemoveDir(repoDir); @@ -255,7 +279,21 @@ namespace HybridCLR.Editor.Installer // clean Il2cppBuildCache BashUtil.RemoveDir($"{SettingsUtil.ProjectDir}/Library/Il2cppBuildCache", true); - + if (version.major == 2019) + { + string curVersionStr = version.ToString(); + string srcIl2CppDll = GetUnityIl2CppDllModifiedPath(curVersionStr); + if (File.Exists(srcIl2CppDll)) + { + string dstIl2CppDll = GetUnityIl2CppDllInstallLocation(); + File.Copy(srcIl2CppDll, dstIl2CppDll, true); + Debug.Log($"copy {srcIl2CppDll} => {dstIl2CppDll}"); + } + else + { + throw new Exception($"the modified Unity.IL2CPP.dll of {curVersionStr} isn't found. please install hybridclr in 2019.4.40 first, then switch to your unity version"); + } + } if (HasInstalledHybridCLR()) { WriteLocalVersion(); diff --git a/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs.meta b/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs.meta index ecf330b..6b30944 100644 --- a/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs.meta +++ b/Assets/01.HybridCLR/Editor/Installer/InstallerController.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fbdbfffcea3ea9f4aa76780e64300eb2 +guid: 44c8627d126b30d4e9560b1f738264ca MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs b/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs index 676fe6e..1869f89 100644 --- a/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs +++ b/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs @@ -44,9 +44,9 @@ namespace HybridCLR.Editor.Installer EditorGUILayout.LabelField($"Installed: {hasInstall}", EditorStyles.boldLabel); GUILayout.Space(10f); - EditorGUILayout.LabelField($"Package Version: v{_controller.PackageVersion}"); + EditorGUILayout.LabelField($"Package Version: v{_controller.PackageVersion}"); GUILayout.Space(5f); - EditorGUILayout.LabelField($"Installed Version: {_controller.InstalledLibil2cppVersion ?? "Unknown"}"); + EditorGUILayout.LabelField($"Installed Version: v{_controller.InstalledLibil2cppVersion ?? " Unknown"}"); GUILayout.Space(5f); GUILayout.Space(10f); diff --git a/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs.meta b/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs.meta index 5436abb..f404c28 100644 --- a/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs.meta +++ b/Assets/01.HybridCLR/Editor/Installer/InstallerWindow.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 42de960287182a74685ad9217f4a757c +guid: 959fbf0bb06629542969354505189240 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Link.meta b/Assets/01.HybridCLR/Editor/Link.meta index ca5db58..1cad1b3 100644 --- a/Assets/01.HybridCLR/Editor/Link.meta +++ b/Assets/01.HybridCLR/Editor/Link.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ab7196c397e1e9b4e8209684ecc7a46b +guid: 5186a137e0258034cb3832bdf6b16a70 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Link/Analyzer.cs b/Assets/01.HybridCLR/Editor/Link/Analyzer.cs index b54d5f3..ffbb93d 100644 --- a/Assets/01.HybridCLR/Editor/Link/Analyzer.cs +++ b/Assets/01.HybridCLR/Editor/Link/Analyzer.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using dnlib.DotNet; using HybridCLR.Editor.Meta; using UnityEditor; +using UnityEngine; using IAssemblyResolver = HybridCLR.Editor.Meta.IAssemblyResolver; namespace HybridCLR.Editor.Link @@ -22,26 +23,27 @@ namespace HybridCLR.Editor.Link public HashSet CollectRefs(List rootAssemblies) { - using (var assCollector = new AssemblyCache(_resolver)) - { - var rootAssemblyNames = new HashSet(rootAssemblies); + var assCollector = new AssemblyCache(_resolver); + var rootAssemblyNames = new HashSet(rootAssemblies); - var typeRefs = new HashSet(TypeEqualityComparer.Instance); - foreach (var rootAss in rootAssemblies) + var typeRefs = new HashSet(TypeEqualityComparer.Instance); + foreach (var rootAss in rootAssemblies) + { + var dnAss = assCollector.LoadModule(rootAss, false); + foreach (var type in dnAss.GetTypeRefs()) { - var dnAss = assCollector.LoadModule(rootAss, false); - foreach (var type in dnAss.GetTypeRefs()) + if (type.DefinitionAssembly == null) { - if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString())) - { - typeRefs.Add(type); - } + Debug.LogWarning($"assembly:{dnAss.Name} TypeRef {type.FullName} has no DefinitionAssembly"); + continue; + } + if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString())) + { + typeRefs.Add(type); } } - - assCollector.Dispose(); - return typeRefs; } + return typeRefs; } } } diff --git a/Assets/01.HybridCLR/Editor/Link/Analyzer.cs.meta b/Assets/01.HybridCLR/Editor/Link/Analyzer.cs.meta index 03211dc..0c6fa90 100644 --- a/Assets/01.HybridCLR/Editor/Link/Analyzer.cs.meta +++ b/Assets/01.HybridCLR/Editor/Link/Analyzer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 966868d081b9f044380d7ce9308231d8 +guid: fd3dd4871efd10e46947cb61c13797fd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs b/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs index 0ede314..d72d0f7 100644 --- a/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs +++ b/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace HybridCLR.Editor.Link { - internal class LinkXmlWriter + public class LinkXmlWriter { public void Write(string outputLinkXmlFile, HashSet refTypes) { @@ -32,6 +32,12 @@ namespace HybridCLR.Editor.Link assTypeNames.Sort(string.CompareOrdinal); foreach(var typeName in assTypeNames) { +#if UNITY_2023_1_OR_NEWER + if (typeName == "UnityEngine.Debug") + { + continue; + } +#endif writer.WriteStartElement("type"); writer.WriteAttributeString("fullname", typeName); writer.WriteAttributeString("preserve", "all"); diff --git a/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs.meta b/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs.meta index 1b2b4b9..4c6c61c 100644 --- a/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs.meta +++ b/Assets/01.HybridCLR/Editor/Link/LinkXmlWriter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 06c46ecd48495b146b7863a70fd99208 +guid: d5cc4ae4adc319b4bb1e115567d7613e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta.meta b/Assets/01.HybridCLR/Editor/Meta.meta index 09a79be..3291c30 100644 --- a/Assets/01.HybridCLR/Editor/Meta.meta +++ b/Assets/01.HybridCLR/Editor/Meta.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 313b4ddcb98889246a35217543c6a324 +guid: 3787c7d8b775c754aa4ae06bf78e96ea folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblyCache.cs.meta b/Assets/01.HybridCLR/Editor/Meta/AssemblyCache.cs.meta index 4bd225b..a99c3b2 100644 --- a/Assets/01.HybridCLR/Editor/Meta/AssemblyCache.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblyCache.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c9916e9cd98115a4e813f9d227f4d524 +guid: fa4650e79a52228488aa85e0690ca52c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs b/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs index 82fb007..04f2d15 100644 --- a/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs @@ -1,20 +1,23 @@ using dnlib.DotNet; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HybridCLR.Editor.Meta { - public abstract class AssemblyCacheBase : IDisposable + public abstract class AssemblyCacheBase { private readonly IAssemblyResolver _assemblyPathResolver; private readonly ModuleContext _modCtx; private readonly AssemblyResolver _asmResolver; - private bool disposedValue; private bool _loadedNetstandard; + + public ModuleContext ModCtx => _modCtx; + public Dictionary LoadedModules { get; } = new Dictionary(); private readonly List _loadedModulesIncludeNetstandard = new List(); @@ -28,6 +31,17 @@ namespace HybridCLR.Editor.Meta _asmResolver.UseGAC = false; } + + public ModuleDefMD TryLoadModule(string moduleName, bool loadReferenceAssemblies = true) + { + string dllPath = _assemblyPathResolver.ResolveAssembly(moduleName, false); + if (string.IsNullOrEmpty(dllPath)) + { + return null; + } + return LoadModule(moduleName, loadReferenceAssemblies); + } + public ModuleDefMD LoadModule(string moduleName, bool loadReferenceAssemblies = true) { // Debug.Log($"load module:{moduleName}"); @@ -75,33 +89,11 @@ namespace HybridCLR.Editor.Meta private ModuleDefMD DoLoadModule(string dllPath) { //Debug.Log($"do load module:{dllPath}"); - ModuleDefMD mod = ModuleDefMD.Load(dllPath, _modCtx); + ModuleDefMD mod = ModuleDefMD.Load(File.ReadAllBytes(dllPath), _modCtx); + mod.EnableTypeDefFindCache = true; _asmResolver.AddToCache(mod); _loadedModulesIncludeNetstandard.Add(mod); return mod; } - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - foreach (var mod in _loadedModulesIncludeNetstandard) - { - mod.Dispose(); - } - _loadedModulesIncludeNetstandard.Clear(); - LoadedModules.Clear(); - } - disposedValue = true; - } - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } } } diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs.meta b/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs.meta index 9c28795..5c02171 100644 --- a/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblyCacheBase.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e640f5657ae667947b7330b660191943 +guid: 3b01fa99119e72141bfee5628c0ffce1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta b/Assets/01.HybridCLR/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta index b77117b..e93354f 100644 --- a/Assets/01.HybridCLR/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8242ecc75b20deb489e7d9cadbb4d478 +guid: 0342c7d8575fdea49896260c77285286 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblyResolverBase.cs.meta b/Assets/01.HybridCLR/Editor/Meta/AssemblyResolverBase.cs.meta index d3198f5..e153d4e 100644 --- a/Assets/01.HybridCLR/Editor/Meta/AssemblyResolverBase.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblyResolverBase.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bd22e83fb27da4d49a6a22b4e724b789 +guid: 5f8d48774b790364cbd36f1f68fd6614 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs b/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs new file mode 100644 index 0000000..3784b37 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + + public class AssemblySorter + { + class Node + { + public string Name; + public List Dependencies = new List(); + + public Node(string name) + { + Name = name; + } + } + + class TopologicalSorter + { + + public static List Sort(List nodes) + { + List sorted = new List(); + HashSet visited = new HashSet(); + HashSet tempMarks = new HashSet(); + + foreach (var node in nodes) + { + if (!visited.Contains(node)) + { + Visit(node, visited, tempMarks, sorted); + } + } + return sorted; + } + + private static void Visit(Node node, HashSet visited, HashSet tempMarks, List sorted) + { + if (tempMarks.Contains(node)) + { + throw new Exception("Detected cyclic dependency!"); + } + + if (!visited.Contains(node)) + { + tempMarks.Add(node); + foreach (var dependency in node.Dependencies) + { + Visit(dependency, visited, tempMarks, sorted); + } + tempMarks.Remove(node); + visited.Add(node); + sorted.Add(node); + } + } + } + + private static List SortAssemblyByReferenceOrder(IEnumerable assemblies, Dictionary> refs) + { + var nodes = new List(); + var nodeMap = new Dictionary(); + foreach (var assembly in assemblies) + { + var node = new Node(assembly); + nodes.Add(node); + nodeMap.Add(assembly, node); + } + foreach (var assembly in assemblies) + { + var node = nodeMap[assembly]; + foreach (var refAssembly in refs[assembly]) + { + node.Dependencies.Add(nodeMap[refAssembly]); + } + } + var sortedNodes = TopologicalSorter.Sort(nodes); + return sortedNodes.Select(node => node.Name).ToList(); + } + + public static List SortAssemblyByReferenceOrder(IEnumerable assemblies, IAssemblyResolver assemblyResolver) + { + var assCache = new AssemblyCache(assemblyResolver); + var assRefAssemblies = new Dictionary>(); + foreach (var assName in assemblies) + { + var refAssemblies = new HashSet(); + var mod = assCache.LoadModule(assName, false); + foreach (var refAss in mod.GetAssemblyRefs()) + { + if (assemblies.Contains(refAss.Name.ToString())) + { + refAssemblies.Add(refAss.Name.ToString()); + } + } + assRefAssemblies.Add(assName, refAssemblies); + } + return SortAssemblyByReferenceOrder(assemblies, assRefAssemblies); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs.meta b/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs.meta new file mode 100644 index 0000000..6fce7f9 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9b8eb45398fa344daa8c6e9b9fbf291 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/Meta/CombinedAssemblyResolver.cs.meta b/Assets/01.HybridCLR/Editor/Meta/CombinedAssemblyResolver.cs.meta index af5c367..81b443c 100644 --- a/Assets/01.HybridCLR/Editor/Meta/CombinedAssemblyResolver.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/CombinedAssemblyResolver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e5b98951f11c35e44884fea72fb99e56 +guid: 89b83906438c52d4b9af4aaef055f177 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs b/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs index 5bee4e4..8206553 100644 --- a/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs +++ b/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs @@ -29,6 +29,12 @@ namespace HybridCLR.Editor.Meta Debug.Log($"[FixedSetAssemblyResolver] resolve:{assemblyName} path:{assemblyPath}"); return true; } + assemblyPath = $"{_rootDir}/{assemblyName}.dll.bytes"; + if (File.Exists(assemblyPath)) + { + Debug.Log($"[FixedSetAssemblyResolver] resolve:{assemblyName} path:{assemblyPath}"); + return true; + } } assemblyPath = null; return false; diff --git a/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs.meta b/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs.meta index 114a9d6..cc4fb61 100644 --- a/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/FixedSetAssemblyResolver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5b53789283b21a240a8fa65b68900dfe +guid: f135accd10f42c64b9735c3aa8cb1e77 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs b/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs index 47883f5..d200399 100644 --- a/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs +++ b/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs @@ -7,13 +7,11 @@ using System.Threading.Tasks; namespace HybridCLR.Editor.Meta { - /// - /// Replaces generic type/method var with its generic argument - /// - public sealed class GenericArgumentContext + + public class GenericArgumentContext { - List typeArgsStack = new List(); - List methodArgsStack = new List(); + private readonly List typeArgsStack; + private readonly List methodArgsStack; public GenericArgumentContext(List typeArgsStack, List methodArgsStack) { @@ -21,16 +19,6 @@ namespace HybridCLR.Editor.Meta this.methodArgsStack = methodArgsStack; } - - - /// - /// Replaces a generic type/method var with its generic argument (if any). If - /// isn't a generic type/method var or if it can't - /// be resolved, it itself is returned. Else the resolved type is returned. - /// - /// Type signature - /// New which is never null unless - /// is null public TypeSig Resolve(TypeSig typeSig) { if (!typeSig.ContainsGenericParameter) @@ -41,9 +29,9 @@ namespace HybridCLR.Editor.Meta switch (typeSig.ElementType) { case ElementType.Ptr: return new PtrSig(Resolve(typeSig.Next)); - case ElementType.ByRef: return new PtrSig(Resolve(typeSig.Next)); + case ElementType.ByRef: return new ByRefSig(Resolve(typeSig.Next)); - case ElementType.SZArray: return new PtrSig(Resolve(typeSig.Next)); + case ElementType.SZArray: return new SZArraySig(Resolve(typeSig.Next)); case ElementType.Array: { var ara = (ArraySig)typeSig; @@ -53,7 +41,7 @@ namespace HybridCLR.Editor.Meta case ElementType.Var: { GenericVar genericVar = (GenericVar)typeSig; - var newSig = Resolve(typeArgsStack, genericVar.Number, true); + var newSig = Resolve(typeArgsStack, genericVar.Number); if (newSig == null) { throw new Exception(); @@ -64,7 +52,7 @@ namespace HybridCLR.Editor.Meta case ElementType.MVar: { GenericMVar genericVar = (GenericMVar)typeSig; - var newSig = Resolve(methodArgsStack, genericVar.Number, true); + var newSig = Resolve(methodArgsStack, genericVar.Number); if (newSig == null) { throw new Exception(); @@ -79,7 +67,29 @@ namespace HybridCLR.Editor.Meta case ElementType.FnPtr: { - throw new NotSupportedException(typeSig.ToString()); + var fptr = (FnPtrSig)typeSig; + var cs = fptr.Signature; + CallingConventionSig ccs; + switch (cs) + { + case MethodSig ms: + { + ccs = new MethodSig(ms.GetCallingConvention(), ms.GenParamCount, Resolve(ms.RetType), ms.Params.Select(p => Resolve(p)).ToList()); + break; + } + case PropertySig ps: + { + ccs = new PropertySig(ps.HasThis, Resolve(ps.RetType)); + break; + } + case GenericInstMethodSig gims: + { + ccs = new GenericInstMethodSig(gims.GenericArguments.Select(ga => Resolve(ga)).ToArray()); + break; + } + default: throw new NotSupportedException(cs.ToString()); + } + return new FnPtrSig(ccs); } case ElementType.ValueArray: @@ -91,13 +101,9 @@ namespace HybridCLR.Editor.Meta } } - private TypeSig Resolve(List args, uint number, bool isTypeVar) + private TypeSig Resolve(List args, uint number) { - var typeSig = args[(int)number]; - var gvar = typeSig as GenericSig; - if (gvar is null || gvar.IsTypeVar != isTypeVar) - return typeSig; - return gvar; + return args[(int)number]; } } diff --git a/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs.meta b/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs.meta index d2a5030..acb9355 100644 --- a/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/GenericArgumentContext.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8fb1ac43c73a55e4d98e853efca62e46 +guid: 07595a9b5b2f54c44a67022ae3e077d4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/GenericClass.cs.meta b/Assets/01.HybridCLR/Editor/Meta/GenericClass.cs.meta index 1a1c2f3..438a1a3 100644 --- a/Assets/01.HybridCLR/Editor/Meta/GenericClass.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/GenericClass.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 72167574ca223e34cb0b704882225877 +guid: c95ff173013909548bd9e2008812f9ff MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs b/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs index 96252fc..243aecb 100644 --- a/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs +++ b/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs @@ -94,7 +94,7 @@ namespace HybridCLR.Editor.Meta methodDef = method.ResolveMethodDef(); if (methodDef == null) { - Debug.LogWarning($"method:{method} ResolveMethodDef() == null"); + //Debug.LogWarning($"method:{method} ResolveMethodDef() == null"); return null; } if (method is MethodSpec methodSpec) diff --git a/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs.meta b/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs.meta index 5c0f520..ef15a5c 100644 --- a/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/GenericMethod.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5110d4398a0b6504c94ed3c37b0da2e9 +guid: 88ecf3d52ec393b4cac142518944e487 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/IAssemblyResolver.cs.meta b/Assets/01.HybridCLR/Editor/Meta/IAssemblyResolver.cs.meta index c7513b4..d56059d 100644 --- a/Assets/01.HybridCLR/Editor/Meta/IAssemblyResolver.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/IAssemblyResolver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7cbf06fa49b97cf48a56cb6aeefc7563 +guid: f962a018018dbb945a19f82d2e098686 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs b/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs index eb95a7a..2302540 100644 --- a/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs +++ b/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs @@ -122,7 +122,7 @@ namespace HybridCLR.Editor.Meta } return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => ToShareTypeSig(corTypes, ga)).ToList()); } - case ElementType.FnPtr: return corTypes.IntPtr; + case ElementType.FnPtr: return corTypes.UIntPtr; case ElementType.ValueArray: return typeSig; case ElementType.Module: return typeSig; default: @@ -189,5 +189,29 @@ namespace HybridCLR.Editor.Meta } return methodGenericParams; } + + public static bool IsSupportedPInvokeTypeSig(TypeSig typeSig) + { + typeSig = typeSig.RemovePinnedAndModifiers(); + if (typeSig.IsByRef) + { + return true; + } + switch (typeSig.ElementType) + { + case ElementType.SZArray: + case ElementType.Array: + //case ElementType.Class: + case ElementType.String: + //case ElementType.Object: + return false; + default: return true; + } + } + + public static bool IsSupportedPInvokeMethodSignature(MethodSig methodSig) + { + return IsSupportedPInvokeTypeSig(methodSig.RetType) && methodSig.Params.All(p => IsSupportedPInvokeTypeSig(p)); + } } } diff --git a/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs.meta b/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs.meta index cf5e4bb..d9342a4 100644 --- a/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/MetaUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a2e0aa5795138414ea5139e7691e0185 +guid: f3dbfe2e8b6a92742b18e287c5d281dd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/MethodReferenceAnalyzer.cs.meta b/Assets/01.HybridCLR/Editor/Meta/MethodReferenceAnalyzer.cs.meta index 7398f6b..7554a58 100644 --- a/Assets/01.HybridCLR/Editor/Meta/MethodReferenceAnalyzer.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/MethodReferenceAnalyzer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1c41435d2422e114eac193c405264d1d +guid: 1c644b0c018fb87498d69c3202439d21 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs b/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs index a356117..1cfc376 100644 --- a/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs +++ b/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs @@ -20,11 +20,16 @@ namespace HybridCLR.Editor.Meta { foreach(var path in _searchPaths) { - string assPath = Path.Combine(path, assemblyName + ".dll"); - if (File.Exists(assPath)) + assemblyPath = Path.Combine(path, $"{assemblyName}.dll"); + if (File.Exists(assemblyPath)) { - Debug.Log($"resolve {assemblyName} at {assPath}"); - assemblyPath = assPath; + Debug.Log($"resolve {assemblyName} at {assemblyPath}"); + return true; + } + assemblyPath = Path.Combine(path, $"{assemblyName}.dll.bytes"); + if (File.Exists(assemblyPath)) + { + Debug.Log($"resolve {assemblyName} at {assemblyPath}"); return true; } } diff --git a/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs.meta b/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs.meta index 85109ca..af02cb8 100644 --- a/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs.meta +++ b/Assets/01.HybridCLR/Editor/Meta/PathAssemblyResolver.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 94848f63e75d660448de23b230886219 +guid: 121d574bf01969444aa6619a8f6dbb4c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/MethodBridge.meta b/Assets/01.HybridCLR/Editor/MethodBridge.meta index d35fd3e..5ff8e80 100644 --- a/Assets/01.HybridCLR/Editor/MethodBridge.meta +++ b/Assets/01.HybridCLR/Editor/MethodBridge.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4ff9fc5d1bc64004c86d5828b8a8e07a +guid: 0c2444f09010bce41a52d951b7100c49 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs b/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs index 59e2dd7..dd0fd66 100644 --- a/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs +++ b/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs @@ -1,4 +1,5 @@ using dnlib.DotNet; +using HybridCLR.Editor.ABI; using HybridCLR.Editor.Meta; using System; using System.Collections.Generic; diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs.meta index 6b58be9..4fd796f 100644 --- a/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs.meta +++ b/Assets/01.HybridCLR/Editor/MethodBridge/Analyzer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5a1027c0dd7b35b4fbd5eacd6933f83f +guid: ee1ec106190e514489c7ba32bc7bc2e7 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs b/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs new file mode 100644 index 0000000..3459e15 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs @@ -0,0 +1,9 @@ +using dnlib.DotNet; + +namespace HybridCLR.Editor.MethodBridge +{ + public class CallNativeMethodSignatureInfo + { + public MethodSig MethodSig { get; set; } + } +} diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs.meta new file mode 100644 index 0000000..026237d --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/CallNativeMethodSignatureInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2e4ca0a49975a84a8a72dbc70ec7795 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs b/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs new file mode 100644 index 0000000..14611ac --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs @@ -0,0 +1,65 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.MethodBridge +{ + + public class CalliAnalyzer + { + private readonly List _rootModules = new List(); + + private readonly List _calliMethodSignatures = new List(); + + public List CalliMethodSignatures => _calliMethodSignatures; + + public CalliAnalyzer(AssemblyCache cache, List assemblyNames) + { + foreach (var assemblyName in assemblyNames) + { + _rootModules.Add(cache.LoadModule(assemblyName)); + } + } + + private void CollectCalli() + { + foreach (var mod in _rootModules) + { + Debug.Log($"ass:{mod.FullName} methodcount:{mod.Metadata.TablesStream.MethodTable.Rows}"); + for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++) + { + var method = mod.ResolveMethod(rid); + //Debug.Log($"method:{method}"); + if (!method.HasBody) + { + continue; + } + + foreach (var il in method.Body.Instructions) + { + if (il.OpCode.Code == dnlib.DotNet.Emit.Code.Calli) + { + MethodSig methodSig = (MethodSig)il.Operand; + + _calliMethodSignatures.Add(new CallNativeMethodSignatureInfo() + { + MethodSig = methodSig, + }); + Debug.Log($"method:{method} calli method signature:{methodSig}"); + } + } + } + } + } + + public void Run() + { + CollectCalli(); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs.meta new file mode 100644 index 0000000..620c7c7 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/CalliAnalyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ce33c8e48da5a649b261ba3a60fd3b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs b/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs index bb9f56e..185f05e 100644 --- a/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs +++ b/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs @@ -13,6 +13,9 @@ using System.Threading.Tasks; using UnityEditor; using UnityEngine; using TypeInfo = HybridCLR.Editor.ABI.TypeInfo; +using CallingConvention = System.Runtime.InteropServices.CallingConvention; +using TypeAttributes = dnlib.DotNet.TypeAttributes; +using System.Runtime.InteropServices; namespace HybridCLR.Editor.MethodBridge { @@ -25,14 +28,46 @@ namespace HybridCLR.Editor.MethodBridge public string OutputFile { get; set; } public IReadOnlyCollection GenericMethods { get; set; } + + public List ReversePInvokeMethods { get; set; } + + public IReadOnlyCollection CalliMethodSignatures { get; set; } + + public bool Development { get; set; } + } + + private class ABIReversePInvokeMethodInfo + { + public MethodDesc Method { get; set; } + + public CallingConvention Callvention { get; set; } + + public int Count { get; set; } + + public string Signature { get; set; } + } + + private class CalliMethodInfo + { + public MethodDesc Method { get; set; } + + public CallingConvention Callvention { get; set; } + + public string Signature { get; set; } } private readonly List _genericMethods; + private readonly List _originalReversePInvokeMethods; + + private readonly List _originalCalliMethodSignatures; + private readonly string _templateCode; private readonly string _outputFile; + private readonly bool _development; + private readonly TypeCreator _typeCreator; private readonly HashSet _managed2nativeMethodSet = new HashSet(); @@ -41,15 +76,22 @@ namespace HybridCLR.Editor.MethodBridge private readonly HashSet _adjustThunkMethodSet = new HashSet(); + private List _reversePInvokeMethods; + + private List _callidMethods; + public Generator(Options options) { List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList(); genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2)); _genericMethods = genericMethodInfo.Select(m => m.Item1).ToList(); - + _originalReversePInvokeMethods = options.ReversePInvokeMethods; + _originalCalliMethodSignatures = options.CalliMethodSignatures.ToList(); + _templateCode = options.TemplateCode; _outputFile = options.OutputFile; _typeCreator = new TypeCreator(); + _development = options.Development; } private readonly Dictionary _sig2Types = new Dictionary(); @@ -98,6 +140,30 @@ namespace HybridCLR.Editor.MethodBridge return mbs; } + private MethodDesc CreateMethodDesc(TypeSig returnType, List parameters) + { + var paramInfos = new List(); + if (returnType.ContainsGenericParameter) + { + throw new Exception($"[PreservedMethod] method has generic parameters"); + } + foreach (var paramInfo in parameters) + { + if (paramInfo.ContainsGenericParameter) + { + throw new Exception($"[PreservedMethod] method has generic parameters"); + } + paramInfos.Add(new ParamInfo() { Type = GetSharedTypeInfo(paramInfo) }); + } + var mbs = new MethodDesc() + { + MethodDef = null, + ReturnInfo = new ReturnInfo() { Type = returnType != null ? GetSharedTypeInfo(returnType) : TypeInfo.s_void }, + ParamInfos = paramInfos, + }; + return mbs; + } + private void AddManaged2NativeMethod(MethodDesc method) { method.Init(); @@ -167,12 +233,23 @@ namespace HybridCLR.Editor.MethodBridge } } - public void PrepareMethods() + private void PrepareMethodBridges() { - foreach(var method in _genericMethods) + foreach (var method in _genericMethods) { ProcessMethod(method.Method, method.KlassInst, method.MethodInst); } + foreach (var reversePInvokeMethod in _originalReversePInvokeMethods) + { + MethodDef method = reversePInvokeMethod.Method; + ICorLibTypes corLibTypes = method.Module.CorLibTypes; + + var returnType = MetaUtil.ToShareTypeSig(corLibTypes, method.ReturnType); + var parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, p.Type)).ToList(); + var sharedMethod = CreateMethodDesc(method, true, returnType, parameters); + sharedMethod.Init(); + AddNative2ManagedMethod(sharedMethod); + } } static void CheckUnique(IEnumerable names) @@ -220,39 +297,114 @@ namespace HybridCLR.Editor.MethodBridge _managed2NativeMethodList0.Count, _native2ManagedMethodList0.Count, _adjustThunkMethodList0.Count, _structTypes0.Count); } + private class AnalyzeFieldInfo + { + public FieldDef field; + + public TypeInfo type; + } + private class AnalyzeTypeInfo { - public TypeInfo toSharedType; - public List fields; + public TypeInfo isoType; + public List fields; public string signature; + public uint originalPackingSize; + public uint packingSize; + public uint classSize; + public LayoutKind layout; + public bool blittable; } private readonly Dictionary _analyzeTypeInfos = new Dictionary(); private readonly Dictionary _signature2Type = new Dictionary(); + + + private bool IsBlittable(TypeSig typeSig) + { + typeSig = typeSig.RemovePinnedAndModifiers(); + if (typeSig.IsByRef) + { + return true; + } + switch (typeSig.ElementType) + { + case ElementType.Void: return false; + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.Char: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + case ElementType.I8: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + case ElementType.I: + case ElementType.U: + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.FnPtr: + case ElementType.TypedByRef: return true; + case ElementType.String: + case ElementType.Class: + case ElementType.Array: + case ElementType.SZArray: + case ElementType.Object: + case ElementType.Module: + case ElementType.Var: + case ElementType.MVar: return false; + case ElementType.ValueType: + { + TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{typeSig} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function"); + } + if (typeDef.IsEnum) + { + return true; + } + return CalculateAnalyzeTypeInfoBasic(GetSharedTypeInfo(typeSig)).blittable; + } + case ElementType.GenericInst: + { + GenericInstSig gis = (GenericInstSig)typeSig; + if (!gis.GenericType.IsValueType) + { + return false; + } + TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef.IsEnum) + { + return true; + } + return CalculateAnalyzeTypeInfoBasic(GetSharedTypeInfo(typeSig)).blittable; + } + default: throw new NotSupportedException($"{typeSig.ElementType}"); + } + } + private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic(TypeInfo typeInfo) { + Debug.Assert(typeInfo.IsStruct); + if (_analyzeTypeInfos.TryGetValue(typeInfo, out var ati)) + { + return ati; + } TypeSig type = typeInfo.Klass; TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; - ClassLayout sa = typeDef.ClassLayout; - var analyzeTypeInfo = new AnalyzeTypeInfo(); - - // don't share type with explicit layout - if (sa != null) - { - analyzeTypeInfo.toSharedType = typeInfo; - analyzeTypeInfo.signature = typeInfo.CreateSigName(); - _signature2Type.Add(analyzeTypeInfo.signature, typeInfo); - return analyzeTypeInfo; - } - - var fields = analyzeTypeInfo.fields = new List(); + var fields = new List(); + bool blittable = true; foreach (FieldDef field in typeDef.Fields) { if (field.IsStatic) @@ -260,8 +412,39 @@ namespace HybridCLR.Editor.MethodBridge continue; } TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; - fields.Add(GetSharedTypeInfo(fieldType)); + blittable &= IsBlittable(fieldType); + TypeInfo sharedFieldTypeInfo = GetSharedTypeInfo(fieldType); + TypeInfo isoType = ToIsomorphicType(sharedFieldTypeInfo); + fields.Add(new AnalyzeFieldInfo { field = field, type = isoType }); } + //analyzeTypeInfo.blittable = blittable; + //analyzeTypeInfo.packingSize = blittable ? analyzeTypeInfo.originalPackingSize : 0; + + ClassLayout sa = typeDef.ClassLayout; + uint originalPackingSize = sa?.PackingSize ?? 0; + var analyzeTypeInfo = new AnalyzeTypeInfo() + { + originalPackingSize = originalPackingSize, + packingSize = blittable && !typeDef.IsAutoLayout ? originalPackingSize : 0, + classSize = sa?.ClassSize ?? 0, + layout = typeDef.IsAutoLayout ? LayoutKind.Auto : (typeDef.IsExplicitLayout ? LayoutKind.Explicit : LayoutKind.Sequential), + fields = fields, + blittable = blittable, + }; + _analyzeTypeInfos.Add(typeInfo, analyzeTypeInfo); + analyzeTypeInfo.signature = GetOrCalculateTypeInfoSignature(typeInfo); + + if (_signature2Type.TryGetValue(analyzeTypeInfo.signature, out var sharedType)) + { + // Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} "); + analyzeTypeInfo.isoType = sharedType; + } + else + { + analyzeTypeInfo.isoType = typeInfo; + _signature2Type.Add(analyzeTypeInfo.signature, typeInfo); + } + return analyzeTypeInfo; } @@ -284,11 +467,16 @@ namespace HybridCLR.Editor.MethodBridge { return ati.signature; } - + var sigBuf = new StringBuilder(); + if (ati.packingSize != 0 || ati.classSize != 0 || ati.layout != LayoutKind.Sequential || !ati.blittable) + { + sigBuf.Append($"[{ati.classSize}|{ati.packingSize}|{ati.layout}|{(ati.blittable ? 0 : 1)}]"); + } foreach (var field in ati.fields) { - sigBuf.Append(GetOrCalculateTypeInfoSignature(ToIsomorphicType(field))); + string fieldOffset = field.field.FieldOffset != null ? field.field.FieldOffset.ToString() + "|" : ""; + sigBuf.Append("{" + fieldOffset + GetOrCalculateTypeInfoSignature(ToIsomorphicType(field.type)) + "}"); } return ati.signature = sigBuf.ToString(); } @@ -299,27 +487,7 @@ namespace HybridCLR.Editor.MethodBridge { return type; } - if (!_analyzeTypeInfos.TryGetValue(type, out var ati)) - { - ati = CalculateAnalyzeTypeInfoBasic(type); - _analyzeTypeInfos.Add(type, ati); - } - if (ati.toSharedType == null) - { - string signature = GetOrCalculateTypeInfoSignature(type); - Debug.Assert(signature == ati.signature); - if (_signature2Type.TryGetValue(signature, out var sharedType)) - { - // Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} "); - ati.toSharedType = sharedType; - } - else - { - ati.toSharedType = type; - _signature2Type.Add(signature, type); - } - } - return ati.toSharedType; + return CalculateAnalyzeTypeInfoBasic(type).isoType; } private MethodDesc ToIsomorphicMethod(MethodDesc method) @@ -370,11 +538,131 @@ namespace HybridCLR.Editor.MethodBridge return methodMap.Values.ToList(); } + + + private static string MakeReversePInvokeSignature(MethodDesc desc, CallingConvention CallingConventionention) + { + string convStr = ((char)('A' + (int)CallingConventionention - 1)).ToString(); + return $"{convStr}{desc.Sig}"; + } + private static string MakeCalliSignature(MethodDesc desc, CallingConvention CallingConventionention) + { + string convStr = ((char)('A' + Math.Max((int)CallingConventionention - 1, 0))).ToString(); + return $"{convStr}{desc.Sig}"; + } + + private static CallingConvention GetCallingConvention(MethodDef method) + { + var monoPInvokeCallbackAttr = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); + if (monoPInvokeCallbackAttr == null) + { + return CallingConvention.Winapi; + } + object delegateTypeSig = monoPInvokeCallbackAttr.ConstructorArguments[0].Value; + + TypeDef delegateTypeDef; + if (delegateTypeSig is ClassSig classSig) + { + delegateTypeDef = classSig.TypeDefOrRef.ResolveTypeDefThrow(); + } + else if (delegateTypeSig is GenericInstSig genericInstSig) + { + delegateTypeDef = genericInstSig.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); + } + else + { + delegateTypeDef = null; + } + + if (delegateTypeDef == null) + { + throw new NotSupportedException($"Unsupported delegate type: {delegateTypeSig}"); + } + var attr = delegateTypeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"); + if (attr == null) + { + return CallingConvention.Winapi; + } + var conv = attr.ConstructorArguments[0].Value; + return (CallingConvention)conv; + } + + private List BuildABIMethods(List rawMethods) + { + var methodsBySig = new Dictionary(); + foreach (var method in rawMethods) + { + var sharedMethod = new MethodDesc + { + MethodDef = method.Method, + ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo(method.Method.ReturnType) }, + ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = GetSharedTypeInfo(p.Type) }).ToList(), + }; + sharedMethod.Init(); + sharedMethod = ToIsomorphicMethod(sharedMethod); + + CallingConvention callingConv = GetCallingConvention(method.Method); + string signature = MakeReversePInvokeSignature(sharedMethod, callingConv); + + if (!methodsBySig.TryGetValue(signature, out var arm)) + { + arm = new ABIReversePInvokeMethodInfo() + { + Method = sharedMethod, + Signature = signature, + Count = 0, + Callvention = callingConv, + }; + methodsBySig.Add(signature, arm); + } + int preserveCount = method.GenerationAttribute != null ? (int)method.GenerationAttribute.ConstructorArguments[0].Value : 1; + arm.Count += preserveCount; + } + var newMethods = methodsBySig.Values.ToList(); + newMethods.Sort((a, b) => string.CompareOrdinal(a.Signature, b.Signature)); + return newMethods; + } + + private List BuildCalliMethods(List rawMethods) + { + var methodsBySig = new Dictionary(); + foreach (var method in rawMethods) + { + var sharedMethod = new MethodDesc + { + MethodDef = null, + ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo(method.MethodSig.RetType) }, + ParamInfos = method.MethodSig.Params.Select(p => new ParamInfo { Type = GetSharedTypeInfo(p) }).ToList(), + }; + sharedMethod.Init(); + sharedMethod = ToIsomorphicMethod(sharedMethod); + + CallingConvention callingConv = (CallingConvention)((int)(method.MethodSig.CallingConvention & dnlib.DotNet.CallingConvention.Mask) + 1); + string signature = MakeCalliSignature(sharedMethod, callingConv); + + if (!methodsBySig.TryGetValue(signature, out var arm)) + { + arm = new CalliMethodInfo() + { + Method = sharedMethod, + Signature = signature, + Callvention = callingConv, + }; + methodsBySig.Add(signature, arm); + } + } + var newMethods = methodsBySig.Values.ToList(); + newMethods.Sort((a, b) => string.CompareOrdinal(a.Signature, b.Signature)); + return newMethods; + } + private void BuildOptimizedMethods() { _managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0); _native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0); _adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0); + _reversePInvokeMethods = BuildABIMethods(_originalReversePInvokeMethods); + _callidMethods = BuildCalliMethods(_originalCalliMethodSignatures); } private void OptimizationTypesAndMethods() @@ -389,10 +677,15 @@ namespace HybridCLR.Editor.MethodBridge { var frr = new FileRegionReplace(_templateCode); - List lines = new List(20_0000); + List lines = new List(20_0000) + { + "\n", + $"// DEVELOPMENT={(_development ? 1 : 0)}", + "\n" + }; var classInfos = new List(); - var classTypeSet = new HashSet(); + var classTypeSet = new Dictionary(); foreach (var type in structTypes) { GenerateClassInfo(type, classTypeSet, classInfos); @@ -424,6 +717,15 @@ namespace HybridCLR.Editor.MethodBridge GenerateAdjustThunkStub(_adjustThunkMethodList, lines); + GenerateReversePInvokeWrappers(_reversePInvokeMethods, lines); + + foreach (var method in _callidMethods) + { + GenerateManaged2NativeFunctionPointerMethod(method, lines); + } + GenerateManaged2NativeFunctionPointerMethodStub(_callidMethods, lines); + + frr.Replace("CODE", string.Join("\n", lines)); Directory.CreateDirectory(Path.GetDirectoryName(_outputFile)); @@ -431,8 +733,69 @@ namespace HybridCLR.Editor.MethodBridge frr.Commit(_outputFile); } + private static string GetIl2cppCallConventionName(CallingConvention conv) + { + switch (conv) + { + case 0: + case CallingConvention.Winapi: + return "DEFAULT_CALL"; + case CallingConvention.Cdecl: + return "CDECL"; + case CallingConvention.StdCall: + return "STDCALL"; + case CallingConvention.ThisCall: + return "THISCALL"; + case CallingConvention.FastCall: + return "FASTCALL"; + default: + throw new NotSupportedException($"Unsupported CallingConvention {conv}"); + } + } + + private void GenerateReversePInvokeWrappers(List methods, List lines) + { + int methodIndex = 0; + var stubCodes = new List(); + foreach (var methodInfo in methods) + { + MethodDesc method = methodInfo.Method; + string il2cppCallConventionName = GetIl2cppCallConventionName(methodInfo.Callvention); + string paramDeclaringListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); + string paramNameListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"__arg{p.Index}").Concat(new string[] { "method" })); + string paramTypeListWithMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); + string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})"; + for (int i = 0; i < methodInfo.Count; i++, methodIndex++) + { + lines.Add($@" +{method.ReturnInfo.Type.GetTypeName()} {il2cppCallConventionName} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr}) +{{ + il2cpp::vm::ScopedThreadAttacher _vmThreadHelper; + const MethodInfo* method = InterpreterModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex}); + {methodTypeDef}; + {(method.ReturnInfo.IsVoid ? "" : "return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr}); +}} + "); + stubCodes.Add($"\t{{\"{methodInfo.Signature}\", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}},"); + } + Debug.Log($"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}"); + } + + lines.Add(@" +const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStub[] +{ +"); + lines.AddRange(stubCodes); + + lines.Add(@" + {nullptr, nullptr}, +}; +"); + } + public void Generate() { + PrepareMethodBridges(); CollectTypesAndMethods(); OptimizationTypesAndMethods(); GenerateCode(); @@ -475,47 +838,68 @@ namespace HybridCLR.Editor.MethodBridge class ClassInfo { public TypeInfo type; - - public TypeDef typeDef; - - public List fields = new List(); - - public ClassLayout layout; + public List fields; + public uint packingSize; + public uint classSize; + public LayoutKind layout; + public bool blittable; } - private void GenerateClassInfo(TypeInfo type, HashSet typeSet, List classInfos) + private void GenerateClassInfo(TypeInfo type, Dictionary typeSet, List classInfos) { - if (!typeSet.Add(type)) + if (typeSet.ContainsKey(type)) { return; } - TypeSig typeSig = type.Klass; - var fields = new List(); - TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); + AnalyzeTypeInfo ati = CalculateAnalyzeTypeInfoBasic(type); + //TypeSig typeSig = type.Klass; + //var fields = new List(); - List klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList(); - GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + //TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); - ClassLayout sa = typeDef.ClassLayout; - - ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes; - foreach (FieldDef field in typeDef.Fields) + //List klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList(); + //GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + //ClassLayout sa = typeDef.ClassLayout; + + //ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes; + //bool blittable = true; + //foreach (FieldDef field in typeDef.Fields) + //{ + // if (field.IsStatic) + // { + // continue; + // } + // TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + // fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType); + // var fieldTypeInfo = ToIsomorphicType(GetSharedTypeInfo(fieldType)); + // if (fieldTypeInfo.IsStruct) + // { + // GenerateClassInfo(fieldTypeInfo, typeSet, classInfos); + // } + // blittable &= IsBlittable(fieldType, fieldTypeInfo, typeSet); + // fields.Add(new FieldInfo { field = field, type = fieldTypeInfo }); + //} + + foreach (var field in ati.fields) { - if (field.IsStatic) + if (field.type.IsStruct) { - continue; + GenerateClassInfo(field.type, typeSet, classInfos); } - TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; - fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType); - var fieldTypeInfo = ToIsomorphicType(_typeCreator.CreateTypeInfo(fieldType)); - if (fieldTypeInfo.IsStruct) - { - GenerateClassInfo(fieldTypeInfo, typeSet, classInfos); - } - fields.Add(new FieldInfo { field = field, type = fieldTypeInfo }); } - classInfos.Add(new ClassInfo() { type = type, typeDef = typeDef, fields = fields, layout = sa }); + var classInfo = new ClassInfo() + { + type = type, + fields = ati.fields, + packingSize = ati.packingSize, + classSize = ati.classSize, + layout = ati.layout, + blittable = ati.blittable, + }; + typeSet.Add(type, classInfo); + classInfos.Add(classInfo); } private void GenerateStructDefines(List classInfos, List lines) @@ -523,16 +907,13 @@ namespace HybridCLR.Editor.MethodBridge foreach (var ci in classInfos) { lines.Add($"// {ci.type.Klass}"); - uint packingSize = ci.layout?.PackingSize ?? 0; - if (packingSize != 0) - { - lines.Add($"#pragma pack(push, {packingSize})"); - } - uint classSize = ci.layout?.ClassSize ?? 0; + uint packingSize = ci.packingSize; + uint classSize = ci.classSize; - if (ci.typeDef.IsExplicitLayout) + if (ci.layout == LayoutKind.Explicit) { - lines.Add($"union {ci.type.GetTypeName()} {{"); + lines.Add($"struct {ci.type.GetTypeName()} {{"); + lines.Add("\tunion {"); if (classSize > 0) { lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};"); @@ -544,14 +925,28 @@ namespace HybridCLR.Editor.MethodBridge string fieldName = $"__{index}"; string commentFieldName = $"{field.field.Name}"; lines.Add("\t#pragma pack(push, 1)"); - lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}];" : "")} {field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}"); + lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}]; " : "")}{field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}"); lines.Add($"\t#pragma pack(pop)"); - lines.Add($"\tstruct {{ {field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}"); + if (packingSize > 0) + { + lines.Add($"\t#pragma pack(push, {packingSize})"); + } + lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding_forAlignmentOnly[{offset}]; " : "")}{field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}"); + if (packingSize > 0) + { + lines.Add($"\t#pragma pack(pop)"); + } ++index; } + lines.Add("\t};"); + lines.Add("};"); } else { + if (packingSize != 0) + { + lines.Add($"#pragma pack(push, {packingSize})"); + } lines.Add($"{(classSize > 0 ? "union" : "struct")} {ci.type.GetTypeName()} {{"); if (classSize > 0) { @@ -570,18 +965,18 @@ namespace HybridCLR.Editor.MethodBridge { lines.Add("\t};"); } - } - lines.Add("};"); - if (packingSize != 0) - { - lines.Add($"#pragma pack(pop)"); + lines.Add("};"); + if (packingSize != 0) + { + lines.Add($"#pragma pack(pop)"); + } } } } - public const string SigOfObj = "u"; + private const string SigOfObj = "u"; - public static string ToFullName(TypeSig type) + private static string ToFullName(TypeSig type) { type = type.RemovePinnedAndModifiers(); switch (type.ElementType) @@ -676,9 +1071,9 @@ namespace HybridCLR.Editor.MethodBridge return $"{Path.GetFileNameWithoutExtension(typeDef.Module.Name)}:{typeDef.FullName}"; } - public void GenerateStructureSignatureStub(List types, List lines) + private void GenerateStructureSignatureStub(List types, List lines) { - lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); + lines.Add("const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); foreach (var type in types) { TypeInfo isoType = ToIsomorphicType(type); @@ -688,10 +1083,10 @@ namespace HybridCLR.Editor.MethodBridge lines.Add("};"); } - public void GenerateManaged2NativeStub(List methods, List lines) + private void GenerateManaged2NativeStub(List methods, List lines) { lines.Add($@" -Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = +const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = {{ "); @@ -704,10 +1099,10 @@ Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = lines.Add("};"); } - public void GenerateNative2ManagedStub(List methods, List lines) + private void GenerateNative2ManagedStub(List methods, List lines) { lines.Add($@" -Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = +const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = {{ "); @@ -720,10 +1115,10 @@ Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = lines.Add("};"); } - public void GenerateAdjustThunkStub(List methods, List lines) + private void GenerateAdjustThunkStub(List methods, List lines) { lines.Add($@" -NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = +const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = {{ "); @@ -746,7 +1141,7 @@ NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = return type.NeedExpandValue() ? $"(uint64_t)({varName})" : $"N2MAsUint64ValueOrAddress<{type.GetTypeName()}>({varName})"; } - public void GenerateManaged2NativeMethod(MethodDesc method, List lines) + private void GenerateManaged2NativeMethod(MethodDesc method, List lines) { string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]")).Concat(new string[] { "method" })); @@ -760,7 +1155,7 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_ "); } - public string GenerateArgumentSizeAndOffset(List paramInfos) + private string GenerateArgumentSizeAndOffset(List paramInfos) { StringBuilder s = new StringBuilder(); int index = 0; @@ -774,7 +1169,7 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_ return s.ToString(); } - public string GenerateCopyArgumentToInterpreterStack(List paramInfos) + private string GenerateCopyArgumentToInterpreterStack(List paramInfos) { StringBuilder s = new StringBuilder(); int index = 0; @@ -815,14 +1210,46 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{(adjustorThunk ? "AdjustorT "); } - public void GenerateNative2ManagedMethod(MethodDesc method, List lines) + private void GenerateNative2ManagedMethod(MethodDesc method, List lines) { GenerateNative2ManagedMethod0(method, false, lines); } - public void GenerateAdjustThunkMethod(MethodDesc method, List lines) + private void GenerateAdjustThunkMethod(MethodDesc method, List lines) { GenerateNative2ManagedMethod0(method, true, lines); } + + private void GenerateManaged2NativeFunctionPointerMethod(CalliMethodInfo methodInfo, List lines) + { + MethodDesc method = methodInfo.Method; + string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); + string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]"))); + string il2cppCallConventionName = GetIl2cppCallConventionName(methodInfo.Callvention); + lines.Add($@" +static void __M2NF_{methodInfo.Signature}(Il2CppMethodPointer methodPointer, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret) +{{ + typedef {method.ReturnInfo.Type.GetTypeName()} ({il2cppCallConventionName} *NativeMethod)({paramListStr}); + {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(methodPointer))({paramNameListStr}); +}} +"); + } + + private void GenerateManaged2NativeFunctionPointerMethodStub(List calliMethodSignatures, List lines) + { + lines.Add(@" +const Managed2NativeFunctionPointerCallData hybridclr::interpreter::g_managed2NativeFunctionPointerCallStub[] +{ +"); + foreach (var method in calliMethodSignatures) + { + lines.Add($"\t{{\"{method.Signature}\", __M2NF_{method.Signature}}},"); + } + + lines.Add(@" + {nullptr, nullptr}, +}; +"); + } } } diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs.meta index 2e72b2c..914508e 100644 --- a/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs.meta +++ b/Assets/01.HybridCLR/Editor/MethodBridge/Generator.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d550ac0e8f92e464c824432e14d33824 +guid: e42a0f3bcbc5ddf438a85ae16c1b3116 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs b/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs new file mode 100644 index 0000000..917c2a1 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs @@ -0,0 +1,78 @@ +using dnlib.DotNet; +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using CallingConvention = System.Runtime.InteropServices.CallingConvention; +using UnityEngine; + +namespace HybridCLR.Editor.MethodBridge +{ + public class RawMonoPInvokeCallbackMethodInfo + { + public MethodDef Method { get; set; } + + public CustomAttribute GenerationAttribute { get; set; } + } + + public class MonoPInvokeCallbackAnalyzer + { + + private readonly List _rootModules = new List(); + + private readonly List _reversePInvokeMethods = new List(); + + public List ReversePInvokeMethods => _reversePInvokeMethods; + + public MonoPInvokeCallbackAnalyzer(AssemblyCache cache, List assemblyNames) + { + foreach (var assemblyName in assemblyNames) + { + _rootModules.Add(cache.LoadModule(assemblyName)); + } + } + + private void CollectReversePInvokeMethods() + { + foreach (var mod in _rootModules) + { + Debug.Log($"ass:{mod.FullName} method count:{mod.Metadata.TablesStream.MethodTable.Rows}"); + for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++) + { + var method = mod.ResolveMethod(rid); + //Debug.Log($"method:{method}"); + if (!method.IsStatic || !method.HasCustomAttributes) + { + continue; + } + CustomAttribute wa = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); + if (wa == null) + { + continue; + } + if (!MetaUtil.IsSupportedPInvokeMethodSignature(method.MethodSig)) + { + Debug.LogError($"MonoPInvokeCallback method {method.FullName} has unsupported parameter or return type. Please check the method signature."); + } + //foreach (var ca in method.CustomAttributes) + //{ + // Debug.Log($"{ca.AttributeType.FullName} {ca.TypeFullName}"); + //} + _reversePInvokeMethods.Add(new RawMonoPInvokeCallbackMethodInfo() + { + Method = method, + GenerationAttribute = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "HybridCLR.ReversePInvokeWrapperGenerationAttribute"), + }); + } + } + } + + public void Run() + { + CollectReversePInvokeMethods(); + } + } +} diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs.meta new file mode 100644 index 0000000..792b5b5 --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/MonoPInvokeCallbackAnalyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c172068b408c0e349b2ceee4c4635085 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs b/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs new file mode 100644 index 0000000..1ddbd3e --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs @@ -0,0 +1,50 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.MethodBridge +{ + + public class PInvokeAnalyzer + { + private readonly List _rootModules = new List(); + + private readonly List _pinvokeMethodSignatures = new List(); + + public List PInvokeMethodSignatures => _pinvokeMethodSignatures; + + public PInvokeAnalyzer(AssemblyCache cache, List assemblyNames) + { + foreach (var assemblyName in assemblyNames) + { + _rootModules.Add(cache.LoadModule(assemblyName)); + } + } + + public void Run() + { + foreach (var mod in _rootModules) + { + foreach (TypeDef type in mod.GetTypes()) + { + foreach (MethodDef method in type.Methods) + { + if (method.IsPinvokeImpl) + { + if (!MetaUtil.IsSupportedPInvokeMethodSignature(method.MethodSig)) + { + Debug.LogError($"PInvoke method {method.FullName} has unsupported parameter or return type. Please check the method signature."); + } + _pinvokeMethodSignatures.Add(new CallNativeMethodSignatureInfo { MethodSig = method.MethodSig }); + } + } + } + } + } + } +} diff --git a/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs.meta b/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs.meta new file mode 100644 index 0000000..3d2ae8a --- /dev/null +++ b/Assets/01.HybridCLR/Editor/MethodBridge/PInvokeAnalyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9923175c961b78849aeaf99708e294ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap.meta b/Assets/01.HybridCLR/Editor/ReversePInvokeWrap.meta index 868a00c..234a1bc 100644 --- a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap.meta +++ b/Assets/01.HybridCLR/Editor/ReversePInvokeWrap.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b3d9c35876903a2468ee96919bc64296 +guid: 259c1cb7fe681f74eb435ab8f268890d folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs b/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs deleted file mode 100644 index e089c5b..0000000 --- a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Analyzer.cs +++ /dev/null @@ -1,108 +0,0 @@ -using dnlib.DotNet; -using HybridCLR.Editor.ABI; -using HybridCLR.Editor.Meta; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; - -namespace HybridCLR.Editor.ReversePInvokeWrap -{ - public class RawReversePInvokeMethodInfo - { - public MethodDef Method { get; set; } - - public CustomAttribute GenerationAttribute { get; set; } - } - - public class ABIReversePInvokeMethodInfo - { - public MethodDesc Method { get; set; } - - public int Count { get; set; } - } - - public class Analyzer - { - - private readonly List _rootModules = new List(); - - private readonly List _reversePInvokeMethods = new List(); - - public Analyzer(AssemblyCache cache, List assemblyNames) - { - foreach (var assemblyName in assemblyNames) - { - _rootModules.Add(cache.LoadModule(assemblyName)); - } - } - - private void CollectReversePInvokeMethods() - { - foreach (var mod in _rootModules) - { - Debug.Log($"ass:{mod.FullName} methodcount:{mod.Metadata.TablesStream.MethodTable.Rows}"); - for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++) - { - var method = mod.ResolveMethod(rid); - //Debug.Log($"method:{method}"); - if (!method.IsStatic || !method.HasCustomAttributes) - { - continue; - } - CustomAttribute wa = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); - if (wa == null) - { - continue; - } - //foreach (var ca in method.CustomAttributes) - //{ - // Debug.Log($"{ca.AttributeType.FullName} {ca.TypeFullName}"); - //} - _reversePInvokeMethods.Add(new RawReversePInvokeMethodInfo() - { - Method = method, - GenerationAttribute = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "HybridCLR.ReversePInvokeWrapperGenerationAttribute"), - }); - } - } - } - - public List BuildABIMethods() - { - var methodsBySig = new Dictionary(); - var typeCreator = new TypeCreator(); - foreach(var method in _reversePInvokeMethods) - { - MethodDesc desc = new MethodDesc - { - MethodDef = method.Method, - ReturnInfo = new ReturnInfo { Type = typeCreator.CreateTypeInfo(method.Method.ReturnType)}, - ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = typeCreator.CreateTypeInfo(p.Type)}).ToList(), - }; - desc.Init(); - if (!methodsBySig.TryGetValue(desc.Sig, out var arm)) - { - arm = new ABIReversePInvokeMethodInfo() - { - Method = desc, - Count = 0, - }; - methodsBySig.Add(desc.Sig, arm); - } - int preserveCount = method.GenerationAttribute != null ? (int)method.GenerationAttribute.ConstructorArguments[0].Value : 1; - arm.Count += preserveCount; - } - var methods = methodsBySig.Values.ToList(); - methods.Sort((a, b) => String.CompareOrdinal(a.Method.Sig, b.Method.Sig)); - return methods; - } - - public void Run() - { - CollectReversePInvokeMethods(); - } - } -} diff --git a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs b/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs deleted file mode 100644 index fdf6df5..0000000 --- a/Assets/01.HybridCLR/Editor/ReversePInvokeWrap/Generator.cs +++ /dev/null @@ -1,59 +0,0 @@ -using HybridCLR.Editor.ABI; -using HybridCLR.Editor.Template; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using UnityEngine; - -namespace HybridCLR.Editor.ReversePInvokeWrap -{ - public class Generator - { - public void Generate(List methods, string outputFile) - { - string template = File.ReadAllText(outputFile, Encoding.UTF8); - var frr = new FileRegionReplace(template); - var codes = new List(); - - int methodIndex = 0; - var stubCodes = new List(); - foreach(var methodInfo in methods) - { - MethodDesc method = methodInfo.Method; - string paramDeclaringListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); - string paramNameListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"__arg{p.Index}").Concat(new string[] { "method" })); - string paramTypeListWithMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); - string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})"; - for (int i = 0; i < methodInfo.Count; i++, methodIndex++) - { - codes.Add($@" - {method.ReturnInfo.Type.GetTypeName()} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr}) - {{ - const MethodInfo* method = MetadataModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex}); - {methodTypeDef}; - {(method.ReturnInfo.IsVoid ? "" : "return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr}); - }} -"); - stubCodes.Add($"\t\t{{\"{method.Sig}\", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}},\n"); - } - Debug.Log($"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}"); - } - - codes.Add(@" - ReversePInvokeMethodData g_reversePInvokeMethodStub[] - { -"); - codes.AddRange(stubCodes); - - codes.Add(@" - {nullptr, nullptr}, - }; -"); - - frr.Replace("CODE", string.Join("", codes)); - frr.Commit(outputFile); - } - } -} diff --git a/Assets/01.HybridCLR/Editor/Settings.meta b/Assets/01.HybridCLR/Editor/Settings.meta index 69f49b5..f73ef75 100644 --- a/Assets/01.HybridCLR/Editor/Settings.meta +++ b/Assets/01.HybridCLR/Editor/Settings.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 27ca22b3a15cc24439084d058d543a40 +guid: 3708ee1d4035cb14abaa4d64a8ec8148 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs b/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs deleted file mode 100644 index 0c3865e..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs +++ /dev/null @@ -1,32 +0,0 @@ -using HybridCLR.Editor; -using System; -using UnityEditor; -using UnityEditorInternal; - -namespace HybridCLR.Editor.Settings -{ - - /// - /// 监听编辑器状态,当编辑器重新 focus 时,重新加载实例,避免某些情景下 svn 、git 等外部修改了数据却无法同步的异常。 - /// - [InitializeOnLoad] - public static class EditorStatusWatcher - { - public static Action OnEditorFocused; - static bool isFocused; - static EditorStatusWatcher() => EditorApplication.update += Update; - static void Update() - { - if (isFocused != InternalEditorUtility.isApplicationActive) - { - isFocused = InternalEditorUtility.isApplicationActive; - if (isFocused) - { - HybridCLRSettings.LoadOrCreate(); - OnEditorFocused?.Invoke(); - } - } - } - } - -} \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs.meta b/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs.meta deleted file mode 100644 index e0306eb..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/EditorStatusWatcher.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 69cc82d0341662846987a1fb1df4b8a5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs index 5ada220..51ecb3b 100644 --- a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs +++ b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs @@ -18,20 +18,21 @@ namespace HybridCLR.Editor.Settings private SerializedProperty _hotUpdateAssemblies; private SerializedProperty _preserveHotUpdateAssemblies; private SerializedProperty _hotUpdateDllCompileOutputRootDir; - private SerializedProperty _externalHotUpdateAssembliyDirs; + private SerializedProperty _externalHotUpdateAssemblyDirs; private SerializedProperty _strippedAOTDllOutputRootDir; private SerializedProperty _patchAOTAssemblies; private SerializedProperty _outputLinkFile; private SerializedProperty _outputAOTGenericReferenceFile; private SerializedProperty _maxGenericReferenceIteration; private SerializedProperty _maxMethodBridgeGenericIteration; - private GUIStyle buttonStyle; + public HybridCLRSettingsProvider() : base("Project/HybridCLR Settings", SettingsScope.Project) { } + public override void OnActivate(string searchContext, VisualElement rootElement) { - EditorStatusWatcher.OnEditorFocused += OnEditorFocused; InitGUI(); } + private void InitGUI() { var setting = HybridCLRSettings.LoadOrCreate(); @@ -45,7 +46,7 @@ namespace HybridCLR.Editor.Settings _hotUpdateAssemblies = _serializedObject.FindProperty("hotUpdateAssemblies"); _preserveHotUpdateAssemblies = _serializedObject.FindProperty("preserveHotUpdateAssemblies"); _hotUpdateDllCompileOutputRootDir = _serializedObject.FindProperty("hotUpdateDllCompileOutputRootDir"); - _externalHotUpdateAssembliyDirs = _serializedObject.FindProperty("externalHotUpdateAssembliyDirs"); + _externalHotUpdateAssemblyDirs = _serializedObject.FindProperty("externalHotUpdateAssembliyDirs"); _strippedAOTDllOutputRootDir = _serializedObject.FindProperty("strippedAOTDllOutputRootDir"); _patchAOTAssemblies = _serializedObject.FindProperty("patchAOTAssemblies"); _outputLinkFile = _serializedObject.FindProperty("outputLinkFile"); @@ -53,126 +54,53 @@ namespace HybridCLR.Editor.Settings _maxGenericReferenceIteration = _serializedObject.FindProperty("maxGenericReferenceIteration"); _maxMethodBridgeGenericIteration = _serializedObject.FindProperty("maxMethodBridgeGenericIteration"); } - private void OnEditorFocused() - { - InitGUI(); - Repaint(); - } - public override void OnTitleBarGUI() - { - base.OnTitleBarGUI(); - var rect = GUILayoutUtility.GetLastRect(); - buttonStyle = buttonStyle ?? GUI.skin.GetStyle("IconButton"); - #region 绘制官方网站跳转按钮 - var w = rect.x + rect.width; - rect.x = w - 57; - rect.y += 6; - rect.width = rect.height = 18; - var content = EditorGUIUtility.IconContent("_Help"); - content.tooltip = "点击访问 HybridCLR 官方文档"; - if (GUI.Button(rect, content, buttonStyle)) - { - Application.OpenURL("https://focus-creative-games.github.io/hybridclr/"); - } - #endregion - #region 绘制 Preset - rect.x += 19; - content = EditorGUIUtility.IconContent("Preset.Context"); - content.tooltip = "点击存储或加载 Preset ."; - if (GUI.Button(rect, content, buttonStyle)) - { - var target = HybridCLRSettings.Instance; - var receiver = ScriptableObject.CreateInstance(); - receiver.Init(target, this); - PresetSelector.ShowSelector(target, null, true, receiver); - } - #endregion - #region 绘制 Reset - rect.x += 19; - content = EditorGUIUtility.IconContent( -#if UNITY_2021_3_OR_NEWER - "pane options" -#else - "_Popup" -#endif - ); - content.tooltip = "Reset"; - if (GUI.Button(rect, content, buttonStyle)) - { - GenericMenu menu = new GenericMenu(); - menu.AddItem(new GUIContent("Reset"), false, () => - { - Undo.RecordObject(HybridCLRSettings.Instance, "Capture Value for Reset"); - var dv = ScriptableObject.CreateInstance(); - var json = EditorJsonUtility.ToJson(dv); - UnityEngine.Object.DestroyImmediate(dv); - EditorJsonUtility.FromJsonOverwrite(json, HybridCLRSettings.Instance); - HybridCLRSettings.Save(); - }); - menu.ShowAsContext(); - } - #endregion - } public override void OnGUI(string searchContext) { - using (CreateSettingsWindowGUIScope()) + if (_serializedObject == null || !_serializedObject.targetObject) { - //解决编辑器打包时出现的 _serializedObject.targetObject 意外销毁的情况 - if (_serializedObject == null||!_serializedObject.targetObject) - { - InitGUI(); - } - _serializedObject.Update(); - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(_enable); - EditorGUILayout.PropertyField(_hybridclrRepoURL); - EditorGUILayout.PropertyField(_il2cppPlusRepoURL); - EditorGUILayout.PropertyField(_useGlobalIl2cpp); - EditorGUILayout.PropertyField(_hotUpdateAssemblyDefinitions); - EditorGUILayout.PropertyField(_hotUpdateAssemblies); - EditorGUILayout.PropertyField(_preserveHotUpdateAssemblies); - EditorGUILayout.PropertyField(_hotUpdateDllCompileOutputRootDir); - EditorGUILayout.PropertyField(_externalHotUpdateAssembliyDirs); - EditorGUILayout.PropertyField(_strippedAOTDllOutputRootDir); - EditorGUILayout.PropertyField(_patchAOTAssemblies); - EditorGUILayout.PropertyField(_outputLinkFile); - EditorGUILayout.PropertyField(_outputAOTGenericReferenceFile); - EditorGUILayout.PropertyField(_maxGenericReferenceIteration); - EditorGUILayout.PropertyField(_maxMethodBridgeGenericIteration); - if (EditorGUI.EndChangeCheck()) - { - _serializedObject.ApplyModifiedProperties(); - HybridCLRSettings.Save(); - } + InitGUI(); + } + _serializedObject.Update(); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(_enable); + EditorGUILayout.PropertyField(_hybridclrRepoURL); + EditorGUILayout.PropertyField(_il2cppPlusRepoURL); + EditorGUILayout.PropertyField(_useGlobalIl2cpp); + EditorGUILayout.PropertyField(_hotUpdateAssemblyDefinitions); + EditorGUILayout.PropertyField(_hotUpdateAssemblies); + EditorGUILayout.PropertyField(_preserveHotUpdateAssemblies); + EditorGUILayout.PropertyField(_hotUpdateDllCompileOutputRootDir); + EditorGUILayout.PropertyField(_externalHotUpdateAssemblyDirs); + EditorGUILayout.PropertyField(_strippedAOTDllOutputRootDir); + EditorGUILayout.PropertyField(_patchAOTAssemblies); + EditorGUILayout.PropertyField(_outputLinkFile); + EditorGUILayout.PropertyField(_outputAOTGenericReferenceFile); + EditorGUILayout.PropertyField(_maxGenericReferenceIteration); + EditorGUILayout.PropertyField(_maxMethodBridgeGenericIteration); + if (EditorGUI.EndChangeCheck()) + { + _serializedObject.ApplyModifiedProperties(); + HybridCLRSettings.Save(); } } - private IDisposable CreateSettingsWindowGUIScope() - { - var unityEditorAssembly = Assembly.GetAssembly(typeof(EditorWindow)); - var type = unityEditorAssembly.GetType("UnityEditor.SettingsWindow+GUIScope"); - return Activator.CreateInstance(type) as IDisposable; - } + public override void OnDeactivate() { base.OnDeactivate(); - EditorStatusWatcher.OnEditorFocused -= OnEditorFocused; HybridCLRSettings.Save(); } - static HybridCLRSettingsProvider provider; + static HybridCLRSettingsProvider s_provider; + [SettingsProvider] public static SettingsProvider CreateMyCustomSettingsProvider() { - if (HybridCLRSettings.Instance && provider == null) + if (s_provider == null) { - provider = new HybridCLRSettingsProvider(); - using (var so = new SerializedObject(HybridCLRSettings.Instance)) - { - provider.keywords = GetSearchKeywordsFromSerializedObject(so); - } + s_provider = new HybridCLRSettingsProvider(); } - return provider; + return s_provider; } } } \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs.meta b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs.meta index 77fe900..0a21f37 100644 --- a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs.meta +++ b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettingProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fad9b3139b5943b44acf2305d739db81 +guid: d2bd1694fedc8b54c88bb9f6c67907d3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs index 92247bf..f577a95 100644 --- a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs +++ b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs @@ -1,54 +1,98 @@ +using System.IO; using UnityEditorInternal; using UnityEngine; namespace HybridCLR.Editor.Settings { - [FilePath("ProjectSettings/HybridCLRSettings.asset")] - public class HybridCLRSettings : ScriptableSingleton + + public class HybridCLRSettings : ScriptableObject { - [Header("开启HybridCLR插件")] + [Tooltip("enable HybridCLR")] public bool enable = true; - [Header("使用全局安装的il2cpp")] + [Tooltip("use il2cpp in unity editor installation location")] public bool useGlobalIl2cpp; - [Header("hybridclr 仓库 URL")] + [Tooltip("hybridclr repo URL")] public string hybridclrRepoURL = "https://gitee.com/focus-creative-games/hybridclr"; - [Header("il2cpp_plus 仓库 URL")] + [Tooltip("il2cpp_plus repo URL")] public string il2cppPlusRepoURL = "https://gitee.com/focus-creative-games/il2cpp_plus"; - [Header("热更新Assembly Definitions")] + [Tooltip("hot update assembly definitions(asd)")] public AssemblyDefinitionAsset[] hotUpdateAssemblyDefinitions; - [Header("热更新dlls")] + [Tooltip("hot update assembly names(without .dll suffix)")] public string[] hotUpdateAssemblies; - [Header("预留的热更新dlls")] + [Tooltip("preserved hot update assembly names(without .dll suffix)")] public string[] preserveHotUpdateAssemblies; - [Header("热更新dll编译输出根目录")] + [Tooltip("output directory of compiling hot update assemblies")] public string hotUpdateDllCompileOutputRootDir = "HybridCLRData/HotUpdateDlls"; - [Header("外部热更新dll搜索路径")] + [Tooltip("searching paths of external hot update assemblies")] public string[] externalHotUpdateAssembliyDirs; - [Header("裁减后AOT dll输出根目录")] + [Tooltip("output directory of stripped AOT assemblies")] public string strippedAOTDllOutputRootDir = "HybridCLRData/AssembliesPostIl2CppStrip"; - [Header("补充元数据AOT dlls")] + [Tooltip("supplementary metadata assembly names(without .dll suffix)")] public string[] patchAOTAssemblies; - [Header("生成的link.xml路径")] + [Tooltip("output file of automatic generated link.xml by scanning hot update assemblies")] public string outputLinkFile = "HybridCLRGenerate/link.xml"; - [Header("自动扫描生成的AOTGenericReferences.cs路径")] + [Tooltip("output file of automatic generated AOTGenericReferences.cs")] public string outputAOTGenericReferenceFile = "HybridCLRGenerate/AOTGenericReferences.cs"; - [Header("AOT泛型实例化搜索迭代次数")] + [Tooltip("max iteration count of searching generic methods in hot update assemblies")] public int maxGenericReferenceIteration = 10; - [Header("MethodBridge泛型搜索迭代次数")] + [Tooltip("max iteration count of searching method bridge generic methods in AOT assemblies")] public int maxMethodBridgeGenericIteration = 10; + + + + private static HybridCLRSettings s_Instance; + + public static HybridCLRSettings Instance + { + get + { + if (!s_Instance) + { + LoadOrCreate(); + } + return s_Instance; + } + } + + private static string GetFilePath() + { + return "ProjectSettings/HybridCLRSettings.asset"; + } + + public static HybridCLRSettings LoadOrCreate() + { + string filePath = GetFilePath(); + Object[] objs = InternalEditorUtility.LoadSerializedFileAndForget(filePath); + s_Instance = objs.Length > 0 ? (HybridCLRSettings)objs[0] : (s_Instance ?? CreateInstance()); + return s_Instance; + } + + public static void Save() + { + if (!s_Instance) + { + return; + } + + string filePath = GetFilePath(); + string directoryName = Path.GetDirectoryName(filePath); + Directory.CreateDirectory(directoryName); + var obj = new Object[1] { s_Instance }; + InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, true); + } } } diff --git a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs.meta b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs.meta index e16d72c..570bc8f 100644 --- a/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs.meta +++ b/Assets/01.HybridCLR/Editor/Settings/HybridCLRSettings.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9b81f022f5b244f4cb93a2f7956e0b1f +guid: e189374413a3f00468e49d51d8b27a09 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Settings/MenuProvider.cs.meta b/Assets/01.HybridCLR/Editor/Settings/MenuProvider.cs.meta index 2e11828..a4474b2 100644 --- a/Assets/01.HybridCLR/Editor/Settings/MenuProvider.cs.meta +++ b/Assets/01.HybridCLR/Editor/Settings/MenuProvider.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 90e2038b306a79e4c99d7fc2dce9531e +guid: a475a5f281298b84da32373694704c68 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs b/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs deleted file mode 100644 index 903f802..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditorInternal; -using UnityEngine; - -namespace HybridCLR.Editor.Settings -{ - public class ScriptableSingleton : ScriptableObject where T : ScriptableObject - { - private static T s_Instance; - public static T Instance - { - get - { - if (!s_Instance) - { - LoadOrCreate(); - } - return s_Instance; - } - } - public static T LoadOrCreate() - { - string filePath = GetFilePath(); - if (!string.IsNullOrEmpty(filePath)) - { - var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath); - s_Instance = arr.Length > 0 ? arr[0] as T : s_Instance??CreateInstance(); - } - else - { - Debug.LogError($"save location of {nameof(ScriptableSingleton)} is invalid"); - } - return s_Instance; - } - - public static void Save(bool saveAsText = true) - { - if (!s_Instance) - { - Debug.LogError("Cannot save ScriptableSingleton: no instance!"); - return; - } - - string filePath = GetFilePath(); - if (!string.IsNullOrEmpty(filePath)) - { - string directoryName = Path.GetDirectoryName(filePath); - if (!Directory.Exists(directoryName)) - { - Directory.CreateDirectory(directoryName); - } - UnityEngine.Object[] obj = new T[1] { s_Instance }; - InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, saveAsText); - } - } - protected static string GetFilePath() - { - return typeof(T).GetCustomAttributes(inherit: true) - .Where(v => v is FilePathAttribute) - .Cast() - .FirstOrDefault() - ?.filepath; - } - } - [AttributeUsage(AttributeTargets.Class)] - public class FilePathAttribute : Attribute - { - internal string filepath; - /// - /// 单例存放路径 - /// - /// 相对 Project 路径 - public FilePathAttribute(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentException("Invalid relative path (it is empty)"); - } - if (path[0] == '/') - { - path = path.Substring(1); - } - filepath = path; - } - } -} \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs.meta b/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs.meta deleted file mode 100644 index b3063aa..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/ScriptableSignleton.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c1ae1000efb4b504db3abc582c03a830 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs b/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs deleted file mode 100644 index e60f3aa..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs +++ /dev/null @@ -1,39 +0,0 @@ -using UnityEditor; -using UnityEditor.Presets; -using UnityEngine; - -namespace HybridCLR.Editor.Settings -{ - public class SettingsPresetReceiver : PresetSelectorReceiver - { - private Object m_Target; - private Preset m_InitialValue; - private SettingsProvider m_Provider; - - internal void Init(Object target, SettingsProvider provider) - { - m_Target = target; - m_InitialValue = new Preset(target); - m_Provider = provider; - } - public override void OnSelectionChanged(Preset selection) - { - if (selection != null) - { - Undo.RecordObject(m_Target, "Apply Preset " + selection.name); - selection.ApplyTo(m_Target); - } - else - { - Undo.RecordObject(m_Target, "Cancel Preset"); - m_InitialValue.ApplyTo(m_Target); - } - m_Provider.Repaint(); - } - public override void OnSelectionClosed(Preset selection) - { - OnSelectionChanged(selection); - Object.DestroyImmediate(this); - } - } -} \ No newline at end of file diff --git a/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs.meta b/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs.meta deleted file mode 100644 index 9fc4aa8..0000000 --- a/Assets/01.HybridCLR/Editor/Settings/SettingsPresetReceiver.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 05cacd9b2248a85449b4c6b4646ed74c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/01.HybridCLR/Editor/SettingsUtil.cs b/Assets/01.HybridCLR/Editor/SettingsUtil.cs index 9a074ea..0aaa269 100644 --- a/Assets/01.HybridCLR/Editor/SettingsUtil.cs +++ b/Assets/01.HybridCLR/Editor/SettingsUtil.cs @@ -46,6 +46,10 @@ namespace HybridCLR.Editor public static string Il2CppBuildCacheDir { get; } = $"{ProjectDir}/Library/Il2cppBuildCache"; + public static string GlobalgamemanagersBinFile { get; } = "globalgamemanagers"; + + public static string Dataunity3dBinFile { get; } = "data.unity3d"; + public static string GetHotUpdateDllsOutputDirByTarget(BuildTarget target) { return $"{HotUpdateDllsRootOutputDir}/{target}"; @@ -61,9 +65,6 @@ namespace HybridCLR.Editor public string name; } - /// - /// 热更新dll列表。不包含 preserveHotUpdateAssemblies。 - /// public static List HotUpdateAssemblyNamesExcludePreserved { get diff --git a/Assets/01.HybridCLR/Editor/SettingsUtil.cs.meta b/Assets/01.HybridCLR/Editor/SettingsUtil.cs.meta index 5e8c5de..323dcf6 100644 --- a/Assets/01.HybridCLR/Editor/SettingsUtil.cs.meta +++ b/Assets/01.HybridCLR/Editor/SettingsUtil.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: aa5d56e6d033fa141bdbee0bed804a93 +guid: 381c08faeafbc004f97504eeba87380d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Editor/Template.meta b/Assets/01.HybridCLR/Editor/Template.meta index a41ed1f..f2430d5 100644 --- a/Assets/01.HybridCLR/Editor/Template.meta +++ b/Assets/01.HybridCLR/Editor/Template.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7e689495c0da98241979cf355e3400c9 +guid: 9af6345cc5ab1ae4a81262ab4b537911 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Editor/Template/FileRegionReplace.cs.meta b/Assets/01.HybridCLR/Editor/Template/FileRegionReplace.cs.meta index c9564c6..14a642a 100644 --- a/Assets/01.HybridCLR/Editor/Template/FileRegionReplace.cs.meta +++ b/Assets/01.HybridCLR/Editor/Template/FileRegionReplace.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 659b26a59d97aa34081e889e6bf0d77d +guid: 15d4563ad83546c42bc65c99be9bd54a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/LICENSE b/Assets/01.HybridCLR/LICENSE index dcad5cf..6c62df1 100644 --- a/Assets/01.HybridCLR/LICENSE +++ b/Assets/01.HybridCLR/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Code Philosophy Technology Ltd. +Copyright (c) 2025 Code Philosophy Technology Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Assets/01.HybridCLR/LICENSE.meta b/Assets/01.HybridCLR/LICENSE.meta index a251831..d5478d5 100644 --- a/Assets/01.HybridCLR/LICENSE.meta +++ b/Assets/01.HybridCLR/LICENSE.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 644ca814682c7b94ba2300aba259e792 +guid: f09e582706a5776448316f6c584e63a6 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/01.HybridCLR/Plugins.meta b/Assets/01.HybridCLR/Plugins.meta index 1101a24..ccdd127 100644 --- a/Assets/01.HybridCLR/Plugins.meta +++ b/Assets/01.HybridCLR/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6d84666bc594c8449a18fa2a0d2de46f +guid: a26873724919287449e2c9eec68ef1da folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Plugins/LZ4.dll b/Assets/01.HybridCLR/Plugins/LZ4.dll new file mode 100644 index 0000000..f1aeba3 Binary files /dev/null and b/Assets/01.HybridCLR/Plugins/LZ4.dll differ diff --git a/Assets/01.HybridCLR/Plugins/LZ4.dll.meta b/Assets/01.HybridCLR/Plugins/LZ4.dll.meta new file mode 100644 index 0000000..527366c --- /dev/null +++ b/Assets/01.HybridCLR/Plugins/LZ4.dll.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: ca69cf4ffd628394a9dd1ef1c56f7f20 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/01.HybridCLR/Plugins/dnlib.dll b/Assets/01.HybridCLR/Plugins/dnlib.dll index 170ffde..ba1f36d 100644 Binary files a/Assets/01.HybridCLR/Plugins/dnlib.dll and b/Assets/01.HybridCLR/Plugins/dnlib.dll differ diff --git a/Assets/01.HybridCLR/Plugins/dnlib.dll.meta b/Assets/01.HybridCLR/Plugins/dnlib.dll.meta index e1dc916..bdb7a88 100644 --- a/Assets/01.HybridCLR/Plugins/dnlib.dll.meta +++ b/Assets/01.HybridCLR/Plugins/dnlib.dll.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e53d58bb133a8194f88bf786587ebd46 +guid: b93c6604eb031674b80de14cd4458dc0 PluginImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/README.md b/Assets/01.HybridCLR/README.md index 9b30ebb..32a5306 100644 --- a/Assets/01.HybridCLR/README.md +++ b/Assets/01.HybridCLR/README.md @@ -1,7 +1,3 @@ - -- [README 中文](./README_zh.md) -- [README English](./README.md) - # HybridCLR [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) @@ -11,81 +7,84 @@

-HybridCLR is a **almost perfect** full-platform native c# hot update solution for Unity with complete features, zero cost, high performance, and low memory**. +[README 中文](./README.md) | [README English](./README_EN.md) -HybridCLR expands the ability of il2cpp, making it change from pure [AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime to 'AOT+Interpreter' hybrid runtime, and then natively supports dynamic loading of assembly , so that the games packaged based on il2cpp backend can be executed not only on the Android platform, but also on IOS, Consoles and other platforms that limit JIT efficiently in **AOT+interpreter** hybrid mode, completely supporting hot updates from the bottom layer. +[Github](https://github.com/focus-creative-games/hybridclr) | [Gitee](https://gitee.com/focus-creative-games/hybridclr) -HybridCLR not only supports the traditional fully interpreted execution mode, but also pioneered [Differential Hybrid Execution](https://hybridclr.doc.code-philosophy.com/en/docs/business/differentialhybridexecution) technique. That is, you can add, delete, or modify the AOT dll at will, and intelligently make the changed or newly added classes and functions run in interpreter mode, but the unchanged classes and functions run in AOT mode, so that the running performance of the hot-updated game logic basically reaches the original AOT level. +HybridCLR是一个**特性完整、零成本、高性能、低内存**的**近乎完美**的Unity全平台原生c#热更新解决方案。 -Welcome to embrace modern native C# hot update technology! ! ! +HybridCLR扩充了il2cpp运行时代码,使它由纯[AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,从底层彻底支持了热更新。使用HybridCLR技术的游戏不仅能在Android平台,也能在IOS、Consoles、WebGL等所有il2cpp支持的平台上高效运行。 -## Documentation +由于HybridCLR对ECMA-335规范 的良好支持以及对Unity开发工作流的高度兼容,Unity项目在接入HybridCLR后,可以几乎无缝地获得C#代码热更新的能力,开发者不需要改变日常开发习惯和要求。HybridCLR首次实现了将Unity平台的全平台代码热更新方案的工程难度降到几乎为零的水平。 -- [Official Documentation](https://hybridclr.doc.code-philosophy.com/en/docs/intro) -- [Quickstart](https://hybridclr.doc.code-philosophy.com/en/docs/beginner/quickstart) -- [Release Log](./RELEASELOG.md) +欢迎拥抱现代原生C#热更新技术 !!! -## Features +## 文档 -- Features complete. A nearly complete implementation of the [ECMA-335 specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), with only a very small number of [unsupported features](https://hybridclr.doc.code-philosophy.com/en/docs/basic/notsupportedfeatures). -- Zero learning and use costs. HybridCLR enhances the pure AOT runtime into a complete runtime, making hot update code work seamlessly with AOT code. The script class and the AOT class are in the same runtime, and you can freely write codes such as inheritance, reflection, and multi-threading (volatile, ThreadStatic, Task, async). No need to write any special code, no code generation, almost unlimited. -- Efficient execution. Implemented an extremely efficient register interpreter, all indicators are significantly better than other hot update schemes. [Performance Test Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/performance) -- Memory efficient. The classes defined in the hot update script occupy the same memory space as ordinary c# classes, which is far superior to other hot update solutions. [Memory and GC](https://hybridclr.doc.code-philosophy.com/en/docs/basic/memory) -- Due to the perfect support for generics, libraries that are not compatible with il2cpp due to AOT generics issues can now run perfectly under il2cpp -- Support some features not supported by il2cpp, such as __makeref, __reftype, __refvalue directives -- [Differential Hybrid Execution](https://hybridclr.doc.code-philosophy.com/en/docs/business/differentialhybridexecution) +- [官方文档](https://hybridclr.doc.code-philosophy.com/docs/intro) +- [快速上手](https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart) +- [商业项目案例](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase) -## Working Principle +## 特性 -HybridCLR is inspired by mono's [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) technology, and provides additional AOT runtimes such as unity's il2cpp The interpreter module is provided to transform them from pure AOT runtime to "AOT + Interpreter" hybrid operation mode. +- 近乎完整实现了[ECMA-335规范](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/),只有极少量的[不支持的特性](https://hybridclr.doc.code-philosophy.com/docs/basic/notsupportedfeatures)。 +- 零学习和使用成本。对绝大多数开发者来说写代码近乎没有限制。 热更新代码与AOT代码无缝工作,可以随意写继承、**泛型**、**反射**之类的代码。不需要额外写任何特殊代码、没有代码生成 +- 完全支持多线程,包含但不限于 volatile、ThreadStatic、async Task等相关功能和特性。这是其他所有热更新方案都不支持的 +- 几乎完全兼容Unity的工作流。包括且不限于支持热更新**MonoBehaviour**、ScriptableObject、**DOTS**技术,资源上挂载的热更新脚本可以正确实例化,这是其他所有热更新方案都不支持的 +- 执行高效。实现了一个极其高效的寄存器解释器,所有指标都大幅优于其他热更新方案。[性能测试报告](https://hybridclr.doc.code-philosophy.com/docs/basic/performance) +- 内存高效。 热更新脚本中定义的类跟普通c#类占用一样的内存空间,远优于其他热更新方案。[内存占用报告](https://hybridclr.doc.code-philosophy.com/docs/basic/memory) +- 支持MonoPInvokeCallback,可以与native代码或者其他语言如lua、javascript、python良好交互 +- 支持PInvoke +- 支持一些il2cpp不支持的特性,如\_\_makeref、 \_\_reftype、\_\_refvalue指令 +- 支持独创的 **Differential Hybrid Execution(DHE)** 差分混合执行技术,即可以对AOT dll任意增删改,会智能地让未改动的函数以AOT方式运行,变化或者新增的函数以interpreter模式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平 +- 支持**热重载**技术,可以100%卸载程序集 +- 支持动态**Hotfix**技术,可以运行过程中无感修复代码bug +- 支持现代的dll加密技术,有效保障代码安全 + +## 支持的版本与平台 + +- 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x、2023.2.x、6000.x.y 所有LTS版本 +- 支持所有il2cpp支持的平台 +- 支持团结引擎和鸿蒙平台 + +## 工作原理 + +HybridCLR从mono的 [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) 技术中得到启发,为unity的il2cpp之类的AOT runtime额外提供了interpreter模块,将它们由纯AOT运行时改造为"AOT + Interpreter"混合运行方式。 ![icon](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/architecture.png) -More specifically, HybridCLR does the following: +更具体地说,HybridCLR做了以下几点工作: -- Implemented an efficient metadata (dll) parsing library -- Modified the metadata management module to realize the dynamic registration of metadata -- Implemented a compiler from IL instruction set to custom register instruction set -- Implemented an efficient register interpreter -- Provide a large number of instinct functions to improve the performance of the interpreter +- 实现了一个高效的元数据(dll)解析库 +- 改造了元数据管理模块,实现了元数据的动态注册 +- 实现了一个IL指令集到自定义的寄存器指令集的compiler +- 实现了一个高效的寄存器解释器 +- 额外提供大量的instinct函数,提升解释器性能 -## The Difference From Other C# Hot-Update Solution +## 稳定性状况 -HybridCLR is a native c# hot update solution. In layman's terms, il2cpp is equivalent to the aot module of mono, and HybridCLR is equivalent to the interpreter module of mono, and the combination of the two becomes a complete mono. HybridCLR makes il2cpp a full-featured runtime, natively (that is, through System.Reflection.Assembly.Load) supports dynamic loading of dlls, thereby supporting hot updates of the ios platform. +HybridCLR已经被广泛验证是非常高效、稳定的Unity热更新解决方案,良好满足大中型商业项目的稳定和性能要求。 -Just because HybridCLR is implemented at the native runtime level, the types of the hot update part and the AOT part of the main project are completely equivalent and seamlessly unified. You can call, inherit, reflect, and multi-thread at will, without generating code or writing adapters. +目前已经有数千个商业游戏项目接入了HybridCLR,其中有超过千个已经在App Store和Google Player上线,仅仅iOS免费榜前500名中就有近百款使用了HybridCLR。上线的项目中包括MMORPG、重度卡牌、重度塔防之类的游戏。国内绝大多数**Top游戏公司**都已经在使用HybridCLR。 -Other hot update solutions are independent vm, and the relationship with il2cpp is essentially equivalent to the relationship of embedding lua in mono. Therefore, the type system is not uniform. In order to allow the hot update type to inherit some AOT types, an adapter needs to be written, and the type in the interpreter cannot be recognized by the type system of the main project. Incomplete features, troublesome development, and low operating efficiency. +可查看我们已知的头部公司中使用HybridCLR并且已经上线的[项目列表](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase)。 -## Supported Versions And Platforms +## 支持与联系 -- Support 2019.4.x, 2020.3.x, 2021.3.x, 2022.3.x full series of LTS versions. The `2023.2.0ax` version is also supported, but not released to the public. -- Supports all il2cpp supported platforms +- 官方1群(3000人):651188171(满) +- 新手1群(3000人):428404198(满) +- 新手2群(2000人):680274677(满) +- 新手3群(2000人):**920714552(推荐)** +- discord频道 `https://discord.gg/BATfNfJnm2` +- 商业合作邮箱: business#code-philosophy.com +- [商业化支持](https://hybridclr.doc.code-philosophy.com/docs/business/intro) -## Stability Status +## 关于作者 -HybridCLR has been widely verified as a very efficient and stable solution for hot update of Unity. +**walon** :**Code Philosophy(代码哲学)** 创始人 -The official versions of **extremely stable** 1.x, 2.x, and 3.x are currently released, which are sufficient to meet the stability requirements of large and medium-sized commercial projects. -At present, at least thousands of commercial game projects have been integrated, and hundreds of them have been launched on both ends. The online projects include MMORPG, heavy card, heavy tower defense and other games. **Most top game companies** (such as Tencent and NetEase) are already using HybridCLR. +毕业于清华大学物理系,2006年CMO金牌,奥数国家集训队成员,保送清华基科班。专注于游戏技术,擅长开发架构和基础技术设施。 -You can read the [game projects in top game companies](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase) those are using HybridCLR and has been launched. - -## Support And Contact - -- Official 1 group: 651188171 (full) -- Novice QQ group 1: 428404198 (full) -- Novice QQ group 2: **680274677 (recommended)** -- discord channel [https://discord.gg/BATfNfJnm2](https://discord.gg/BATfNfJnm2) -- Business cooperation email: business#code-philosophy.com -- [Commercial Support](https://hybridclr.doc.code-philosophy.com/en/docs/business/intro) - -## About The Author - -**walon** : Founder of **Code Philosophy (code philosophy)** - -Graduated from the Department of Physics of Tsinghua University, won the CMO gold medal in 2006, a member of the National Mathematical Olympiad Training Team, and was recommended to Tsinghua University for basic courses. Focus on game technology, good at developing architecture and basic technical facilities. - -## License +## license HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license diff --git a/Assets/01.HybridCLR/README.md.meta b/Assets/01.HybridCLR/README.md.meta index 839f681..b674416 100644 --- a/Assets/01.HybridCLR/README.md.meta +++ b/Assets/01.HybridCLR/README.md.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 7439608fe5069984f96ee7a6460465b4 +guid: b4b6051e2483d664facc72a5102dcffc TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/01.HybridCLR/README_EN.md b/Assets/01.HybridCLR/README_EN.md new file mode 100644 index 0000000..b57bd00 --- /dev/null +++ b/Assets/01.HybridCLR/README_EN.md @@ -0,0 +1,88 @@ + +- [README Chinese](./README.md) +- [README English](./README_EN.md) + +# HybridCLR + +[![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) + +![logo](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/logo.jpg) + +
+
+ +HybridCLR is a **feature-complete, zero-cost, high-performance, low-memory** **near-perfect** Unity cross-platform native C# hot update solution. + +HybridCLR extends the il2cpp runtime code, transforming it from a pure [AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime to an AOT+Interpreter hybrid runtime, thereby natively supporting the dynamic loading of assemblies and fundamentally supporting hot updates from the bottom layer. Games using HybridCLR technology can not only run efficiently on the Android platform but also on all platforms supported by il2cpp, including iOS, Consoles, WebGL, etc. + +Thanks to HybridCLR's good support for the ECMA-335 specification and its high compatibility with the Unity development workflow, Unity projects can almost seamlessly gain the ability to hot update C# code after integrating HybridCLR. Developers do not need to change their daily development habits and requirements. HybridCLR is the first to achieve the engineering difficulty of a full-platform code hot update solution for the Unity platform to almost zero. + +Welcome to embrace modern native C# hot update technology! + +## Documentation + +- [Official Documentation](https://hybridclr.doc.code-philosophy.com/en/docs/intro) +- [Quick Start](https://hybridclr.doc.code-philosophy.com/en/docs/beginner/quickstart) +- [Business Project Cases](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase) + +## Features + +- Nearly complete implementation of the [ECMA-335 specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), with only a very small number of [unsupported features](https://hybridclr.doc.code-philosophy.com/en/docs/basic/notsupportedfeatures). +- Zero learning and usage costs. For most developers, writing code is almost unrestricted. Hot update code works seamlessly with AOT code, allowing for inheritance, **generics**, **reflection**, and other code without additional special code or code generation. +- Full support for multithreading, including but not limited to volatile, ThreadStatic, async Task, and related features and characteristics. This is not supported by any other hot update solution. +- Almost complete compatibility with Unity's workflow. This includes support for hot updating **MonoBehaviour**, ScriptableObject, **DOTS** technology, and correctly instantiating hot update scripts mounted on resources, which is not supported by any other hot update solution. +- Efficient execution. A highly efficient register interpreter has been implemented, with all indicators significantly better than other hot update solutions. [Performance Test Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/performance) +- Efficient memory usage. Classes defined in hot update scripts occupy the same memory space as ordinary C# classes, far superior to other hot update solutions. [Memory Usage Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/memory) +- Supports MonoPInvokeCallback, enabling good interaction with native code or other languages such as Lua, JavaScript, Python. +- Supports some features not supported by il2cpp, such as __makeref, __reftype, __refvalue instructions. +- Supports the unique **Differential Hybrid Execution (DHE)** technology, which allows for arbitrary additions, deletions, and modifications to AOT DLLs. It intelligently runs unchanged functions in AOT mode and changed or newly added functions in interpreter mode, bringing the performance of hot-updated game logic close to that of native AOT. +- Supports **hot reload** technology, allowing 100% unloading of assemblies. +- Supports modern DLL encryption technology to effectively protect code security. + +## Supported Versions and Platforms + +- Supports all LTS versions including 2019.4.x, 2020.3.x, 2021.3.x, 2022.3.x, 2023.2.x, 6000.x.y. +- Supports all platforms supported by il2cpp. +- Supports Tuanjie(China) Engine and HarmonyOS platform. + +## Working Principle + +HybridCLR draws inspiration from Mono's [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) technology, providing an interpreter module for AOT runtimes like Unity's il2cpp, transforming them from pure AOT runtimes to "AOT + Interpreter" hybrid operation modes. + +![icon](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/architecture.png) + +More specifically, HybridCLR has done the following: + +- Implemented an efficient metadata (dll) parsing library. +- Modified the metadata management module to achieve dynamic registration of metadata. +- Implemented a compiler that converts IL instructions to a custom register instruction set. +- Implemented an efficient register interpreter. +- Provided a large number of instinct functions to enhance interpreter performance. + +## Stability Status + +HybridCLR has been widely verified as an efficient and stable Unity hot update solution, meeting the stability and performance requirements of medium and large commercial projects. + +Currently, thousands of commercial game projects have integrated HybridCLR, with over a thousand already launched on the App Store and Google Play. Nearly a hundred of the top 500 free iOS games use HybridCLR, including MMORPGs, heavy card games, and heavy tower defense games. Most of the **Top Game Companies** in China are already using HybridCLR. + +You can view the [list of known top companies using HybridCLR and their launched projects](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase). + +## Support and Contact + +- Official Group 1: 651188171 (Full) +- Beginner Group 1: 428404198 (Full) +- Beginner Group 2: 680274677 (Full) +- Beginner Group 3: **920714552 (Recommended)** +- Discord channel https://discord.gg/BATfNfJnm2 +- Business cooperation email: business#code-philosophy.com +- [Commercial Support](https://hybridclr.doc.code-philosophy.com/en/docs/business/intro) + +## About the Author + +**walon**: Founder of **Code Philosophy (代码哲学)** + +Graduated from the Department of Physics at Tsinghua University, gold medalist of the 2006 CMO, member of the National Mathematical Olympiad Training Team, and sent to the Basic Science Class of Tsinghua. Focused on game technology, proficient in development architecture and basic technical infrastructure. + +## License + +HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license. diff --git a/Assets/01.HybridCLR/README_zh.md.meta b/Assets/01.HybridCLR/README_EN.md.meta similarity index 75% rename from Assets/01.HybridCLR/README_zh.md.meta rename to Assets/01.HybridCLR/README_EN.md.meta index b2dba1f..2da64ec 100644 --- a/Assets/01.HybridCLR/README_zh.md.meta +++ b/Assets/01.HybridCLR/README_EN.md.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 71ea18ddaf41e6f4d82f7f70d47a2e72 +guid: c9e34f237251ef44193538977db6b15f TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/01.HybridCLR/README_zh.md b/Assets/01.HybridCLR/README_zh.md deleted file mode 100644 index d5bb6b7..0000000 --- a/Assets/01.HybridCLR/README_zh.md +++ /dev/null @@ -1,91 +0,0 @@ -- [README 中文](./README_zh.md) -- [README English](./README.md) - -# HybridCLR - -[![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) - -![logo](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/logo.jpg) - -
-
- -HybridCLR是一个**特性完整、零成本、高性能、低内存**的**近乎完美**的Unity全平台原生c#热更方案。 - -HybridCLR扩充了il2cpp的代码,使它由纯[AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime变成‘AOT+Interpreter’ 混合runtime,进而原生支持动态加载assembly,使得基于il2cpp backend打包的游戏不仅能在Android平台,也能在IOS、Consoles等限制了JIT的平台上高效地以**AOT+interpreter**混合模式执行,从底层彻底支持了热更新。 - -HybridCLR不仅支持传统的全解释执行模式,还开创性地实现了 [Differential Hybrid Execution(差分混合执行技术)](https://hybridclr.doc.code-philosophy.com/docs/business/differentialhybridexecution) 差分混合执行技术。即可以对AOT dll任意增删改,会智能地让变化或者新增的类和函数以interpreter模式运行,但未改动的类和函数以AOT方式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平。 - -欢迎拥抱现代原生C#热更新技术 !!! - -## 文档 - -- [官方文档](https://hybridclr.doc.code-philosophy.com/docs/intro) -- [快速上手](https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart) -- [发布日志](./RELEASELOG.md) - -## 特性 - -- 特性完整。 近乎完整实现了[ECMA-335规范](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/),只有极少量的[不支持的特性](https://hybridclr.doc.code-philosophy.com/docs/basic/notsupportedfeatures)。 -- 零学习和使用成本。 HybridCLR将纯AOT runtime增强为完整的runtime,使得热更新代码与AOT代码无缝工作。脚本类与AOT类在同一个运行时内,可以随意写继承、反射、多线程(volatile、ThreadStatic、Task、async)之类的代码。不需要额外写任何特殊代码、没有代码生成,几乎没有限制。 -- 执行高效。实现了一个极其高效的寄存器解释器,所有指标都大幅优于其他热更新方案。[性能测试报告](https://hybridclr.doc.code-philosophy.com/docs/basic/performance) -- 内存高效。 热更新脚本中定义的类跟普通c#类占用一样的内存空间,远优于其他热更新方案。[内存与GC](https://hybridclr.doc.code-philosophy.com/docs/basic/memory) -- 由于对泛型的完美支持,使得因为AOT泛型问题跟il2cpp不兼容的库现在能够完美地在il2cpp下运行 -- 支持一些il2cpp不支持的特性,如__makeref、 __reftype、__refvalue指令 -- [Differential Hybrid Execution(差分混合执行技术)](https://hybridclr.doc.code-philosophy.com/docs/business/differentialhybridexecution) - -## 工作原理 - -HybridCLR从mono的 [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) 技术中得到启发,为unity的il2cpp之类的AOT runtime额外提供了interpreter模块,将它们由纯AOT运行时改造为"AOT + Interpreter"混合运行方式。 - -![icon](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/architecture.png) - -更具体地说,HybridCLR做了以下几点工作: - -- 实现了一个高效的元数据(dll)解析库 -- 改造了元数据管理模块,实现了元数据的动态注册 -- 实现了一个IL指令集到自定义的寄存器指令集的compiler -- 实现了一个高效的寄存器解释器 -- 额外提供大量的instinct函数,提升解释器性能 - -## 与其他流行的c#热更新方案的区别 - -HybridCLR是原生的c#热更新方案。通俗地说,il2cpp相当于mono的aot模块,HybridCLR相当于mono的interpreter模块,两者合一成为完整mono。HybridCLR使得il2cpp变成一个全功能的runtime,原生(即通过System.Reflection.Assembly.Load)支持动态加载dll,从而支持ios平台的热更新。 - -正因为HybridCLR是原生runtime级别实现,热更新部分的类型与主工程AOT部分类型是完全等价并且无缝统一的。可以随意调用、继承、反射、多线程,不需要生成代码或者写适配器。 - -其他热更新方案则是独立vm,与il2cpp的关系本质上相当于mono中嵌入lua的关系。因此类型系统不统一,为了让热更新类型能够继承AOT部分类型,需要写适配器,并且解释器中的类型不能为主工程的类型系统所识别。特性不完整、开发麻烦、运行效率低下。 - -## 支持的版本与平台 - -- 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x全系列LTS版本。`2023.2.0ax`版本也已支持,但未对外发布。 -- 支持所有il2cpp支持的平台 - -## 稳定性状况 - -HybridCLR已经被广泛验证是非常高效、稳定的Unity热更新解决方案。 - -当前发布了**极其稳定**的1.x、2.x、3.x正式版本,足以满足大中型商业项目的稳定性要求。 -目前至少有上千个商业游戏项目完成接入,其中有几百款已经双端上线,上线的项目中包括MMORPG、重度卡牌、重度塔防之类的游戏。**绝大多数头部游戏公司**(如腾讯、网易)都已经在使用HybridCLR。 - -可查看我们已知的头部公司中使用HybridCLR并且已经上线的[项目列表](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase)。 - - -## 支持与联系 - -- 官方1群:651188171(满) -- 新手1群:428404198(满) -- 新手2群:**680274677(推荐)** -- discord频道 https://discord.gg/BATfNfJnm2 -- 商业合作邮箱: business#code-philosophy.com -- [商业化支持](https://hybridclr.doc.code-philosophy.com/docs/business/intro) - -## 关于作者 - -**walon** :**Code Philosophy(代码哲学)** 创始人 - -毕业于清华大学物理系,2006年CMO金牌,奥数国家集训队成员,保送清华基科班。专注于游戏技术,擅长开发架构和基础技术设施。 - -## license - -HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license diff --git a/Assets/01.HybridCLR/RELEASELOG.md b/Assets/01.HybridCLR/RELEASELOG.md index 61ffc5e..3d75207 100644 --- a/Assets/01.HybridCLR/RELEASELOG.md +++ b/Assets/01.HybridCLR/RELEASELOG.md @@ -1,402 +1,927 @@ -# 发布日志 +# ReleaseLog + +## 8.2.0 + +Release Date: 2025-06-12. + +### Runtime + +- [fix] fix line number mistake in stacktrace +- [fix] Fixed bug that PDBImage::SetupStackFrameInfo didn't set ilOffset and sourceCodeLineNumber of stackFrame when SequencePoint not found +- [merge] merge il2cpp changes from 2022.3.54-2022.3.63 + +### Editor + +- [change] changed from throw exception to logError when not supported pinvoke or reverse pinvoke method parameter type was found + +## 8.1.0 + +Release Date: 2025-05-29. + +### Runtime + +- [opt] **important**! use std::unordered_set for s_GenericInst to reduce the time cost of Assembly.Load to 33% of the original. + +### Editor + +- [fix] fix bug of GenericArgumentContext that inflate ByRef and SZArray to Ptr. + +## 8.0.0 + +Release Date: 2025-05-02. + +### Runtime + +- [new] support define PInvoke method in interpreter assembly +- [new] InterpreterImage initialize ImplMap for PInvoke methods. +- [new] RawImageBase support ModuleRef and ImplMap table. +- [fix] fixed a compilation error on PS4 platform for the code `TokenGenericContextType key = { token, genericContext };` — the C++ compiler version on PS4 is too old to support this initialization syntax for std::tuple. + +### Editor + +- [fix] fix error of computing CallingConvention in MethodBridge/Generator::BuildCalliMethods +- [new] generate Managed2NativeFunction for PInvoke method +- [change] AssemblyResolver also resolves `*.dll.bytes` files besides `*.dll`. +- [change] change type of the first argument `methodPointer` of Managed2NativeFunctionPointer from `const void*` to `Il2CppMethodPointer` +- [change] the shared type of ElementType.FnPtr is changed from IntPtr to UIntPtr +- [change] validate unsupported parameter type(.e.g string) in MonoPInvokeCallback signature when generate MethodBridge file +- [opt] optimization unnecessary initialization of typeArgsStack and methodArgsStack of GenericArgumentContext +- [refactor] refactor code of settings. +- [refactor] move ReversePInvokeWrap/Analyzer.cs to MethodBridge/MonoPInvokeCallbackAnalyzer.cs + +## 7.10.0 + +Release Date: 2025-04-22. + +### Runtime + +- [fix] fix the bug that doesn't lock g_MetadataLock in PDBImage::SetupStackFrameInfo. +- [change] remove Il2CppTypeHash and Il2CppTypeEqualTo, replace with il2cpp::metadata::Il2CppTypeHash and il2cpp::metadata::Il2CppTypeEqualityComparer. +- [merge] merge il2cpp changes from tuanjie 1.3.4 to 1.5.0, base unity from 2022.3.48 to 2022.3.55 . + +### Editor + +- [fix] fix bug of `CompileDll(BuildTarget target)` that use EditorUserBuildSettings.activeBuildTarget instead of target to call CompileDll. +- [opt] AOTAssemblyMetadataStripper strips AOT assembly resources. (#54) + +## 7.9.0 + +Release Date: 2025-03-31. + +### Runtime + +- [merge] merge il2cpp changes from 6000.0.30f1 to 6000.0.44f1 + +## 7.8.1 + +Release Date: 2025-03-24. + +### Runtime + +- [fix] fix bug of CreateInitLocals when size <= 16 +- [change] remove unnecessary `frame->ip = (byte*)ip;` assignment in LOAD_PREV_FRAME() + +## 7.8.0 + +Release Date: 2025-03-24. + +### Runtime + +- [opt] fixed a **critical** bug where taking the address of the ip variable severely impacted compiler optimizations, leading to significant performance degradation. +- [opt] add HiOpCodeEnum::None case to interpreter loop. avoid decrement *ip when compute jump table, boosts about 5% performance. +- [opt] opt InitLocals and InitInlineLocals in small size cases +- [opt] reorder MethodInfo fields to reduce memory size + +### Editor + +- [fix] fixed the bug where BashUtil.RemoveDir failed to run under certain circumstances on macOS systems. + +## 7.7.0 + +Release Date: 2025-03-12. + +### Runtime + +- [change] fixed the issue that HYBRIDCLR_ENABLE_PROFILER was disabled in release build +- [fix] fix a crash in PDBImage::SetMethodDebugInfo when GetMethodDataFromCache returns nullptr +- [fix] fix assert bug of InterpreterDelegateInvoke when method->parameters_count - curMethod->parameters_count == 1 +- [fix] fix compiler error of initialize constructor code `{a, b}` for `std::tuple` in PS5 +- [opt] removed unnecessary pdb lock in PDBImage +- [change] fix some compiler warnings +- [change] HYBRIDCLR_ENABLE_STRACKTRACE was enabled in both DEBUG and RELEASE build without considering HYBRIDCLR_ENABLE_STRACE_TRACE_IN_WEBGL_RELEASE_BUILD flag. + +### Editor + +- [fix] fixed hook failed in version below MacOS 11 +- [change] CompileDllActiveBuildTarget and GenerateAll use EditorUserBuildSettings.development to compile hot update dll. +- [remove] remove option HybridCLRSettings.enableProfilerInReleaseBuild +- [remove] remove option HybridCLRSettings.enableStraceTraceInWebGLReleaseBuild + +## 7.6.0 + +Release Date: 2025-03-01. + +### Runtime + +- [fix] fixed the bug in ClassFieldLayoutCalculator where it incorrectly handles [StructLayout] and blittable attribute when calculating the layout for structs. +- [fix] fix bug of computing explicit struct layout caused by commit "199b1b1a789d760828bd33e7e1438261cd1f8d15" +- [fix] fix the code `TokenGenericContextType key = { token, genericContext }` has compiler error in PS5 +- [merge] merge il2cpp changes from 2021.3.44f1 to 2021.3.49f1 + +### Editor + +- [fix] fixed the bug in the MethodBridge generator where it incorrectly handles [StructLayout] and blittable attribute when generating code for struct classes. +- [new] add AssemblySorter to sort assemblies by reference order + +## 7.5.0 + +Release Date: 2025-02-05. + +### Editor + +- [revert] Revert 'support preserve UnityEngine core types when GenerateLinkXml'. + +## 7.4.1 + +Release Date: 2025-01-19. + +### Editor + +[fix] fixe the bug that preserving UnityEngine.PerformanceReportingModule when generating link.xml would cause the Android app built with Unity 2019 to crash on startup. + +## 7.4.0 + +Release Date: 2025-01-17. + +### Runtime + +- [new] calli supports call both native function pointer and managed method + +### Editor + +- [new] add Managed2NativeFunctionPointer MethodBridge functions +- [new] support preserve UnityEngine core types when GenerateLinkXml +- [fix] fixed the bug in AOTAssemblyMetadataStripper::Strip where ModuleWriterOptions MetadataFlags.PreserveRids was not used. +- [fix] fixed the bug where StripAOTDllCommand did not set BuildPlayerOptions.subtarget in Unity 2021+ versions, causing failure when publishing dedicated buildTarget. +- [change] add UnityVersion.h.tpl and AssemblyManifest.cpp.tpl, Il2CppDefGenerator doesn't generates and override code file from same one +- [change] add MethodBridge.cpp.tpl. MethodBridgeGeneratorCommand doesn't generate and override from same file + +## 7.3.0 + +Release Date: 2024-12-31. + +### Runtime + +- [fix] fix bug that Image::ReadRuntimeHandleFromMemberRef didn't inflate parent type when read field of GenericType +- [fix] fix an issue occurred in InterpreterImage::GenerateCustomAttributesCacheInternal where HYBRIDCLR_METADATA_MALLOC was incorrectly used to allocate the cache. When occasional contention occurs, releasing memory using HYBRIDCLR_FREE causes a crash. +- [fix] fixed a potential deadlock issue in Unity 2019 and 2020 versions within InterpreterImage::GenerateCustomAttributesCacheInternal, where il2cpp::vm::g_MetadataLock was held before running ConstructCustomAttribute. +- [fix] fixed a bug in Unity 2019 and 2020 within InterpreterImage::GenerateCustomAttributesCacheInternal, where cache memory leaks occurred under multithreading contention. +- [fix] fix the bug that InterpreterImage::ConstructCustomAttribute doesn't set write barrier for field +- [fix] fix the bug that `InterpreterImage::InitTypeDefs_2` runs after `InitClassLayouts`, causing the `packingSize` field to be incorrectly initialized. +- [fix] fix the bug in ClassFieldLayoutCalculator::LayoutFields where the alignment calculation incorrectly considers naturalAlignment, resulting in field offsets that are inconsistent with the actual field offsets in AOT. This bug originates from IL2CPP itself and only occurs in Unity 2021 and earlier versions. + +### Editor + +- [fix] fix the issue in Unity 6000 where the modification of the trimmed AOT DLL output directory for the visionOS build target caused CopyStrippedAOTAssemblies::GetStripAssembliesDir2021 to fail in copying AOT DLLs. +- [fix] fix the bug where MissingMetadataChecker can't detect references to newly added AOT assemblies. + +## 7.2.0 + +Release Date: 2024-12-9. + +### Runtime + +- [fix] fix a critical bug in Image::ReadArrayType, where it incorrectly uses alloca to allocate Il2CppArray's sizes and lobounds data. +- [merge] merge il2cpp changes from 2022.3.51f1 to 2022.3.54f1 +- [merge] merge il2cpp changes from 6000.0.21 to 6000.0.30 + +## 7.1.0 + +Release Date: 2024-12-4. + +### Runtime + +- [new] support prejit interpreter class and method +- [new] add RuntimeOptionId::MaxInlineableMethodBodySize +- [merge] merge il2cpp changes from tuanjie v1.3.1 to v1.3.4 +- [fix] fix memory leak of TransformContext::irbbs and ir2offsetMap +- [opt] does not insert CheckThrowIfNull check when inlining constructors +- [opt] remove unnecessary typeSize calculation from the NewValueTypeInterpVar instruction. +- [change] change default maxInlineableMethodBodySize from 16 to 32 +- [change] remove the unnecessary Inflate operation on arg.type when initializing ArgVarInfo in TransformContext::TransformBodyImpl. +- [change] remove unnecessary fields genericContext, klassContainer, methodContainer from the TransformContext + +### Editor + +- [new] support prejit interpreter class and method +- [new] add RuntimeOptionId::MaxInlineableMethodBodySize +- [fix] fix the bug that CopyStrippedAOTAssemblies didn't work on UWP platform of 6000.0.x +- [fix] fix the issue that CopyStrippedAOTAssemblies didn't support HMIAndroid in tuanjie engine +- [change] change the attributes on fields of HybridCLRSettings from `[Header]` to `[ToolTip]` +- [refactor] refactor code comments and translate them to English + +## 7.0.0 + +Release Date: 2024-11-15. + +### Runtime + +- [new] support method inlining +- [refactor] refactor Transform codes + +### Editor + +- [new] add option RuntimeOptionId::MaxMethodBodyCacheSize and RuntimeOptionId::MaxMethodInlineDepth +- [fix] fix the bug in GenericReferenceWriter where _systemTypePattern did not properly escape the '.' in type names. This caused issues when compiler-generated anonymous types and functions contained string sequences like 'System-Int', incorrectly matching them to 'System.Int', resulting in runtime exceptions. +- [fix] fix the bug in `MissingMetadataChecker` where it did not check for missing fields. + +## 6.11.0 + +Release Date: 2024-10-31. + +### Runtime + +- [merge] Merges changes from Tuanjie versions 1.3.0 to 1.3.1 +- [merge] Merges il2cpp code changes from version 2022.3.48f1 to 2022.3.51f1 + +## 6.10.1 + +Release Date: 2024-10-24. + +### Editor + +- [fix] Fixs HookUtils compile errors in Unity 2019 and 2020 +- [change] remove README_zh.md.meta, add README_EN.md.meta + +## 6.10.0 + +Release Date: 2024-10-23. + +### Runtime + +- [new] Officially supports 6000.0.23f LTS version +- [merge] Merges changes from Tuanjie versions 1.2.6 to 1.3.0 +- [fix] Fixed an issue in MonoHook where processorType was not handled correctly on some CPUs when the processorType was returned in all uppercase (e.g., some machines return 'INTEL' instead of 'Intel'). + +## 6.9.0 + +Release Date: 2024-9-30. + +### Runtime + +- [fix] Fixes the bug where thrown exceptions did not call `il2cpp::vm::Exception::PrepareExceptionForThrow`, resulting in an empty stack trace. +- [merge] Merges changes from versions 2021.3.42f1 to 2021.3.44f1, fixing compilation errors introduced by il2cpp changes in version 2021.3.44. +- [merge] Merges changes from versions 2022.3.41f1 to 2022.3.48f1, fixing compilation errors introduced by il2cpp changes in version 2022.3.48. +- [merge] Merges code from 6000.0.19f1 to 6000.0.21f1, fixing compilation errors introduced by il2cpp changes in version 6000.0.20. +- [merge] Merges changes from Tuanjie versions 1.1.0 to 1.2.6 + +## 6.8.0 + +Release Date: 2024-9-14. + +### Runtime + +- [fix] Fixes the bug where exception stacks did not include line numbers. +- [fix] Fixes the bug where `Il2CppGenericContextCompare` simply compared class_inst and method_inst pointers for equality, which is not the case for all GenericInst (e.g., `s_Il2CppMetadataRegistration->genericInsts`) that do not come from GenericInstPool, hence identical GenericInst are not pointer equal. +- [merge] Merges il2cpp code changes from version 6000.0.10 to 6000.0.19 + +## 6.7.1 + +Release Date: 2024-8-26. + +### Runtime + +- [fix] Fixes the bug where there were compilation errors when publishing to the iOS platform with Unity 2019. + +## 6.7.0 + +Release Date: 2024-8-26. + +### Runtime + +- [opt] No longer enables PROFILER in Release compilation mode, this optimization reduces the overhead of function calls by 10-15%, and overall performance is improved by approximately 2-4%. +- [opt] When publishing for WebGL targets, StackTrace is no longer maintained in Release compilation mode, which improves performance by about 1-2%. +- [fix] Fixes the bug where `Transform Enum::GetHashCode` did not change the variable type from `uintptr_t` to `int32_t` on the stack, leading to incorrect calculations when participating in subsequent numerical computations due to the parameter type being extended to 64 bits. +- [fix] Fixes the bug where a stack overflow was triggered by calling delegates extensively within interpreter functions. + +### Editor + +- [new] HybridCLRSettings adds two new options: `enableProfilerInReleaseBuild` and `enableStackTraceInWebGLReleaseBuild`. +- [change] Fixes the issue where an assertion failure occurred when switching from the WebGL platform to other platforms (no substantial impact). + +## 6.6.0 + +Release Date: 2024-8-12. + +### Runtime + +- [fix] Fixes the bug where `CustomAttribute` construction or namedArg includes a `typeof(T[])` parameter, causing a crash. +- [fix] Fixes the bug where `T[index].CallMethod()` throws an `ArrayTypeMismatchException` when `CallMethod` is an interface function of generic type T, and the array element is a subclass of T. +- [fix] Fixes the bug where `MethodBase.GetCurrentMethod` does not return the correct result. A new instinct instruction `MethodBaseGetCurrentMethod` is added. +- [fix] Fixes the bug where loading pdb on platforms like WebGL still does not display stack code line numbers. +- [fix] Fixes the bug where, after calling a sub-interpreter function and returning, logging prints the code line number of the called function due to `frame->ip` not being reset to `&ip`. +- [fix] Fixes the bug where calling a sub-interpreter function displays the line number of the next statement in the parent function's code line number due to `frame->ip` pointing to the next instruction. +- [merge] Merges il2cpp code from 2021.3.42f1 and 2022.3.41f1, fixing compilation errors caused by the new `il2cpp_codegen_memcpy_with_write_barrier` function in versions 2021.3.42f1 and 2022.3.40f1. + +## 6.5.0 + +Release Date: 2024-8-5. + +### Runtime + +- [new] Hot update function stacks for versions 2019-2020 can now correctly display code files and line numbers. +- [merge] Merges il2cpp changes from Unity versions 6000.0.1 to 6000.0.10 + +## 6.4.0 + +Release Date: 2024-7-25. + +### Runtime + +- [new] Supports loading dll and pdb symbol files with `Assembly.Load(byte[] assData, byte[] pdbData)`, displaying the correct code files and line numbers in function stacks when printing on versions 2021+. +- [fix] Fixes the bug where `InterpreterImage::GetEventInfo` and `GetPropertyInfo` might not initialize `method`, resulting in empty getter functions. +- [opt] Optimizes the order of function stacks printed by `StackTrace` and `UnityEngine.Debug`, displaying interpreter functions at the correct stack positions in most cases. +- [opt] Optimizes metadata memory. + +### Editor + +- [fix] Fixes the bug where `GenerateMethodBridge` did not consider `ClassLayout`, `Layout`, and `FieldOffset` factors when calculating equivalent classes. +- [fix] Fixes the bug where `PatchScriptingAssembliesJsonHook` throws an异常 when the `Library/PlayerDataCache` directory does not exist. + +## 6.3.0 + +Release Date: 2024-7-15. + +### Runtime + +- [opt] Significantly optimizes metadata memory, reducing memory usage by 15-40% compared to version 6.2.0. +- [fix] Fixes the bug where memory was not released for `insts` in `IRBasicBlock` during transformation, causing a memory leak approximately 0.7-1.6 times the size of the dll. +- [fix] Fixes the bug where `ClassFieldLayoutCalculator` caused a memory leak. +- [fix] Fixes the bug where `MetadataAllocT` incorrectly used `HYBRIDCLR_MALLOC` instead of `HYBRIDCLR_METADATA_MALLOC`. +- [opt] Optimizes the native stack size occupied by `Interpreter::Execute` to avoid stack overflow errors when nesting is too deep. + +### Editor + +- [fix] Fixes the bug where exporting an xcode project for Unity 2022 includes multiple ShellScript fragments, incorrectly deleting non-repeated fragments. +- [fix] Fixes the bug where the temporary directory name is `WinxinMiniGame{xxx}` when `TextureCompression` is not the default value on the WeChat Mini Games platform, causing the `scriptingassemblies.json` file to not be successfully modified. +- [fix] Fixes the bug where the WeChat Mini Games platform on the Unity Engine, due to the definition of both `UNITY_WEIXINMINIGAME` and `UNITY_WEBGL` macros, fails to find the `scriptingassemblies.json` file from the wrong path, resulting in a script missing bug at runtime. + +## 6.2.0 + +Release Date: 2024-7-1. + +### Runtime + +- [merge] Merges changes from versions 2021.3.27f1 to 2021.3.40f1. +- [opt] Optimizes metadata memory, reducing memory usage by 20-25%. +- [opt] Optimizes the implementation of `GetHashCode` for enum types, no longer generating GC. + +## 6.1.0 + +Release Date: 2024-6-17. + +### Runtime + +- [merge] Merges changes from versions 2022.3.23f1 to 2022.3.33f1, fixing incompatibility issues with version 2022.3.33. +- [new] Supports the new function return value Attribute added in version 2022.3.33. +- [fix] Fixes the bug where `FieldInfo` calling `GetFieldMarshaledSizeForField` crashes. + +### Editor + +- [fix] Upgrades the dnlib version, fixing the serious bug where `ModuleMD` saves dlls without setting the assembly-qualified `mscorlib` assembly types to the current assembly. +- [fix] Fixes the issue where `Generate/LinkXml` generates a `link.xml` that preserves all `UnityEngine.Debug`, causing compilation errors on iOS and visionOS platforms with Unity 2023 and higher versions. This bug is caused by Unity, and we temporarily solve this problem by ignoring the `UnityEngine.Debug` class when generating `link.xml`. + +## 6.0.0 + +Release Date: 2024-6-11. + +### Runtime + +- [new] Supports Unity 6000.x.y and Unity 2023.2.x versions. +- [refactor] Merges `ReversePInvokeMethodStub` into `MethodBridge`, and moves ReversePInvoke-related code from `MetadataModule` to `InterpreterModule`. +- [new] Supports MonoPInvokeCallback functions with parameters or return types as struct types. + +### Editor + +- [new] Supports Unity 6000.x.y and Unity 2023.2.x versions. +- [new] Supports MonoPInvokeCallback functions with parameters or return types as struct types. +- [new] Adds `GeneratedAOTGenericReferenceExcludeExistsAOTClassAndMethods`, which calculates hot update references to AOT generic types and functions, excluding those already existing in AOT, ultimately generating a more accurate list of supplementary metadata assembly programs. +- [fix] Fixes the bug where `CopyStrippedAOTAssemblies` class has compilation errors on some Unity versions that do not support visionOS. +- [fix] Fixes the bug where calculating the `CallingConvention` of `MonoPInvokeCallback` is incorrectly treated as Winapi if the delegate is defined in another assembly, resulting in an incorrect wrapper signature calculation. +- [fix] PatchScriptingAssemblyList.cs has compilation errors on Unity 2023+ WebGL platforms. +- [fix] Fixes the bug where calculating Native2Manager bridge functions does not consider MonoPInvokeCallback functions, leading to `UnsupportedNative2ManagedMethod` when calling C# hot update functions from Lua or other languages. +- [refactor] Merges `ReversePInvokeMethodStub` into `MethodBridge`, and moves ReversePInvoke-related code from `MetadataModule` to `InterpreterModule`. +- [opt] Checks if the development option during packaging is consistent with the current development option. Switching the development option after `Generate/All` and then packaging will cause serious crashes. +- [opt] `Generate/All` checks if HybridCLR is installed before generating. + +## 5.4.1 + +Release Date: 2024-5-30. + +### Editor + +- [new] Supports the visionOS platform. +- [fix]**[Serious]** Fixes the bug where calculating `MonoPInvokeCallback`'s `CallingConvention` incorrectly treats it as Winapi if the delegate is defined in another assembly, resulting in an incorrect wrapper signature calculation. +- [fix] Fixes the bug where the wrong Unity-iPhone.xcodeproj path is used on tvOS platforms, causing the project.pbxproj to not be found. + +## 5.4.0 + +Release Date: 2024-5-20. + +### Runtime + +- [new] ReversePInvoke supports CallingConvention. +- [fix] Fixes the bug where `calli`'s `argBasePtr=argIdx[0]` when the number of arguments is 0, due to `argIdxs` not being assigned, causing the function stack frame to point to the wrong location. +- [fix] Fixes the bug where `MetadataModule::GetReversePInvokeWrappe`'s `ComputeSignature` might deadlock. +- [fix] Fixes the bug where AOT base class virtual functions implementing hot update interface functions use `CallInterpVirtual`, causing runtime exceptions. +- [fix] Fixes the issue where some sub-instructions of the `PREFIX1` prefix instruction are missing and not sorted by instruction number in the Transform. +- [fix] Fixes the bug where the `no.{x}` prefix instruction is 3 bytes long but incorrectly treated as 2 bytes in the Transform. +- [fix] Fixes the bug where the `unaligned.{x}` prefix instruction is 3 bytes long but incorrectly treated as 2 bytes in the Transform. +- [opt] Removes unnecessary `INIT_CLASS` operations in `Interpreter_Execute`, as `PREPARE_NEW_FRAME_FROM_NATIVE` will always check. +- [opt] No longer caches MethodBody of non-generic functions, optimizing memory. +- [opt] **Optimizes supplementary metadata memory**, saving approximately 2.8 times the size of metadata dll memory. +- [refactor] Changes the type of the `_rawImage` field in `Image` from `RawImage` to `RawImage*`. + +### Editor + +- [new] ReversePInvoke supports CallingConvention. +- [fix] Fixes the bug where calculating the equivalence of structs by flattening and expanding them does not apply on some platforms. For example, struct A { uint8_t x; A2 y; } struct A2 { uint8_t x; int32_t y;}; and struct B { uint8_t x; uint8_t y; int32_t z; } are not equivalent under the x86_64 ABI. +- [fix] Fixes the bug where appending to an existing xcode project causes the 'Run Script' command to be duplicated the first time and subsequently fails to find --external-lib-il2-cpp, printing an error log. + +## 5.3.0 + +Release Date: 2024-4-22. + +### Runtime + +- [fix] Fixes the bug where MachineState::CollectFramesWithoutDuplicates incorrectly uses `hybridclr::metadata::IsInterpreterMethod` to remove hot update functions, leading to an increasingly long StackFrames list and an infinite loop when printing the stack. The implementation is adjusted to uniformly use `il2cpp::vm::StackTrace::PushFrame` and `PopFrame` for perfect interpreter stack printing. The downside is the increased overhead of maintaining the stack when calling interpreter functions. +- [fix] Fixes the serious bug where `StringUtils::Utf16ToUtf8` does not correctly handle `maxinumSize==0`, causing a significant overflow when converting strings of length 0 in `InterpreterImage::ConvertConstValue`. +- [fix] Fixes the bug where `_ReversePInvokeMethod_XXX` functions do not set `Il2CppThreadContext`, causing a crash when obtaining thread variables from native threads. +- [merge] Merges il2cpp changes from versions 2021.3.34 to 2021.3.37f1. +- [merge] Merges il2cpp changes from versions 2022.3.19 to 2022.3.23f1. + +### Editor + +- [fix] Fixes the bug where exporting a tvOS project does not modify xcode project settings, causing packaging to fail. +- [fix] Fixes the bug where building for tvOS targets does not copy the pruned AOT dll, causing bridge function generation to fail. +- [fix] Solves the issue where the locationPathName generated by `StripAOTDllCommand` is not standardized, causing incompatibility with some plugins like the Embedded Browser. +- [fix] Fixes the bug where deleting the `TUANJIE_2022` macro in Unity Engine 1.1.0 does not copy the pruned AOT assembly. +- [fix] Fixes the bug where `_ReversePInvokeMethod_XXX` functions do not set `Il2CppThreadContext`, causing a crash when obtaining thread variables from native threads. +- [fix] Fixes the bug where iOS platform mono-related header files are not found when the development build option is enabled. + +## 5.2.1 + +Release Date: 2024-4-7. + +### Runtime + +- [fix] Fixes the bug where stack logs are not printed on the WebGL platform. +- [fix] Fixes the bug where `RuntimeConfig::GetRuntimeOption` incorrectly returns `s_threadFrameStackSize` for `InterpreterThreadExceptionFlowSize`. + +### Editor + +- [opt] Sets `mod.EnableTypeDefFindCache = true` in `LoadModule`, reducing the time to calculate bridge functions to one-third of the original. +- [fix] Fixes the bug where renaming the xcode project file to `Tuanjie-iPhone.xcodeproj` when exporting for the Unity Engine platform causes xcode project construction to fail. + +## 5.2.0 + +Release Date: 2024-3-25. + +### Runtime + +- [new] Supports the Unity Engine. +- [new] Supports function pointers, supporting IL2CPP_TYPE_FNPTR type. +- [fix] Fixes the bug where the `SetMdArrElementVarVar_ref` instruction does not SetWriteBarrier. +- [fix] Fixes the bug where `InvokeSingleDelegate` crashes when calling a generic function without supplementary metadata. +- [fix] Fixes the bug where `InterpreterDelegateInvoke` crashes when calling a delegate pointing to a generic function without supplementary metadata. +- [fix] Fixes the bug where `RawImage::GetBlobFromRawIndex` fails when the BlobStream is empty. +- [change] Refactorizes the metadata index design, allowing up to 3 64M dlls, 16 16M dlls, 64 4M dlls, and 255 1M dlls to be allocated. + +### Editor + +- [new] Supports the Unity Engine. +- [fix] Fixes the bug where `GenericArgumentContext` does not support `ElementType.FnPtr`. +- [change] Adds the `[Preserve]` attribute to RuntimeApi to prevent it from being pruned. + +## 5.1.0 + +Release Date: 2024-2-26. + +### Runtime + +- [fix] Fixes the runtime error caused by not implementing `System.ByReference`1's .ctor and get_Value functions in 2021, where il2cpp runs normally through special instinct functions. +- [opt] Optimizes metadata loading by delaying the loading of some metadata, reducing the execution time of `Assembly::Load` by approximately 30%. +- [change] Changes `tempRet` from a local variable in `Interpreter::Execute` to a local variable in `CallDelegateInvoke_xxx`, reducing the possibility of stack overflow when nesting is too deep. + +## 5.0.0 + +Release Date: 2024-1-26. + +### Runtime + +- [new] Restores support for 2019. +- [fix] Fixes the bug where dlls are not loaded in dependency order, and since the assembly list at the time of image creation is cached, if dependent assemblies are loaded after this assembly, delayed access may result in `TypeLoadedException` due to not being in the cached assembly list. + +### Editor + +- [new] Restores support for 2019. +- [new] Supports building 2019 on the iOS platform in source form. +- [new] Adds AOTAssemblyMetadataStripper to remove non-generic function metadata from AOT dlls. +- [new] Adds MissingMetadataChecker to check for missing types or function metadata. +- [opt] Optimizes AOTReference calculations; if all generic parameters of a generic are class-constrained, they are not added to the set of metadata that needs to be supplemented. +- [change] Makes some adjustments to support the Unity Engine (note that the il2cpp_plus branch supporting the Unity Engine has not been made public). ## 4.0.15 -发布日期 2024年1月2日. +Release Date: 2024-1-2. ### Runtime -- [fix] 修复计算未完全实例化的泛型类时将VAR和MVAR类型参数大小计算成sizeof(void*),导致计算出无效且过大的instance,在执行LayoutFieldsLocked过程中调用UpdateInstanceSizeForGenericClass错误地使用泛型基类instance覆盖设置了实例类型的instance值的严重bug -- [change] 支持打印热更新栈,虽然顺序不太正确 -- [change] 使用HYBRIDCLR_MALLOC之类分配函数替换IL2CPP_MALLOC -- [refactor] 重构Config接口,统一通过GetRuntimeOption和SetRuntimeOption获取和设置选项 -- [opt] 删除NewValueTypeVar和NewValueTypeInterpVar指令不必要的对结构memset操作 +- [fix] Fixes the serious bug where the size of the instance of a not fully instantiated generic class is calculated as `sizeof(void*)`, resulting in an invalid and excessively large instance. This causes an error when using the generic base class instance to overwrite the instance type value set during `LayoutFieldsLocked` in `UpdateInstanceSizeForGenericClass`. +- [change] Supports printing hot update stacks, although the order is not quite correct. +- [change] Replaces IL2CPP_MALLOC with HYBRIDCLR_MALLOC and similar allocation functions. +- [refactor] Refactorizes the Config interface to统一ly retrieve and set options through `GetRuntimeOption` and `SetRuntimeOption`. +- [opt] Removes unnecessary memset operations on structures for `NewValueTypeVar` and `NewValueTypeInterpVar` instructions. ### Editor -- [fix] 修复Additional Compiler Arguments中输入 -nullable:enable 之后,Editor抛出InvalidCastException的bug。来自报告 https://github.com/focus-creative-games/hybridclr/issues/116 -- [fix] 修复某些情况下报错:BuildFailedException: Build path contains a project previously built without the "Create Visual Studio Solution" -- [opt] 优化桥接函数生成,将同构的struct映射到同一个结构,减少了30-35%的桥接函数数量 -- [change] StripAOTDllCommand导出时不再设置BuildScriptsOnly选项 -- [change] 调整Installer窗口的显示内容 -- [refactor] RuntimeApi中设置hybridclr参数的功能统一通过GetRuntimeOption和SetRuntimeOption函数 +- [fix] Fixes the bug where entering `-nullable:enable` in Additional Compiler Arguments throws an `InvalidCastException` in the Editor. Reported at https://github.com/focus-creative-games/hybridclr/issues/116 +- [fix] Fixes the error: `BuildFailedException: Build path contains a project previously built without the "Create Visual Studio Solution"` +- [opt] Optimizes bridge function generation by mapping isomorphic structs to the same structure, reducing the number of bridge functions by 30-35%. +- [change] `StripAOTDllCommand` no longer sets the `BuildScriptsOnly` option when exporting. +- [change] Adjusts the display content of the Installer window. +- [refactor] Centralizes the functionality of setting hybridclr parameters in RuntimeApi through `GetRuntimeOption` and `SetRuntimeOption` functions. ## 4.0.14 -发布日期 2023.12.11. +Release Date: 2023-12-11. ### Runtime -- [fix] 修复优化 box; brtrue|brfalse序列时,当类型为class或nullable类型时,无条件转换为无条件branch语句的bug -- [fix] 修复 ClassFieldLayoutCalculator未释放 _classMap的每个key-value对中value对象,造成内存泄露的bug -- [fix] 修复计算 ExplicitLayout的struct的native_size的bug -- [fix] 修复当出现签名完全相同的虚函数与虚泛型函数时,计算override未考虑泛型签名,错误地返回了不匹配的函数,导致虚表错误的bug -- [fix][2021] 修复开启faster(smaller) build选项后某些情况下完全泛型共享AOT函数未使用补充元数据来设置函数指针,导致调用时出错的bug +- [fix] Fixes the bug where optimizing the `box; brtrue|brfalse` sequence unconditionally converts to an unconditional branch statement when the type is a class or nullable type. +- [fix] Fixes the bug where `ClassFieldLayoutCalculator` does not release value objects in each key-value pair of `_classMap`, causing a memory leak. +- [fix] Fixes the bug where calculating the native_size of a struct with `ExplicitLayout` is incorrect. +- [fix] Fixes the bug where when there are virtual functions with identical signatures and virtual generic functions, the override calculation does not consider the generic signature, incorrectly returning a non-matching function, resulting in an incorrect vtable. +- [fix][2021] Fixes the bug where when the faster (smaller) build option is enabled, some fully generic shared AOT functions do not use supplementary metadata to set function pointers, causing errors when called. ## 4.0.13 -发布日期 2023.11.27. +Release Date: 2023-11-27. ### Runtime -- [fix] 修复ConvertInvokeArgs有可能传递了非对齐args,导致CopyStackObject在armv7这种要求内存对齐的平台发生崩溃的bug -- [fix] 修复通过StructLayout指定size时,计算ClassFieldLayout的严重bug -- [fix] 修复bgt之类指令未取双重取反进行判断,导致当浮点数与Nan比较时由于不满足对称性执行了错误的分支的bug -- [fix] 修复Class::FromGenericParameter错误地设置了thread_static_fields_size=-1,导致为其分配ThreadStatic内存的严重bug -- [opt] Il2CppGenericInst分配统一使用MetadataCache::GetGenericInst分配唯一池对象,优化内存分配 -- [opt] 由于Interpreter部分Il2CppGenericInst统一使用MetadataCache::GetGenericInst,比较 Il2CppGenericContext时直接比较 class_inst和method_inst指针 +- [fix] Fixes the bug where `ConvertInvokeArgs` might pass non-aligned args, causing `CopyStackObject` to crash on platforms like armv7 that require memory alignment. +- [fix] Fixes the serious bug where calculating `ClassFieldLayout` when the size is specified by `StructLayout`. +- [fix] Fixes the bug where instructions like `bgt` do not double-negate the judgment, causing incorrect branch execution when comparing floating-point numbers with NaN due to不对称性. +- [fix] Fixes the serious bug where `Class::FromGenericParameter` incorrectly sets `thread_static_fields_size=-1`, causing ThreadStatic memory allocation for it. +- [opt] Allocates `Il2CppGenericInst`统一ly using `MetadataCache::GetGenericInst` to allocate unique pool objects, optimizing memory allocation. +- [opt] Since some Il2CppGenericInst in the Interpreter uses `MetadataCache::GetGenericInst` uniformly, compare `Il2CppGenericContext` by directly comparing class_inst and method_inst pointers. ### Editor -- [fix] 修复裁剪aot dll中出现netstandard时,生成桥接函数异常的bug -- [fix] 修复当出现非常规字段名时生成的桥接函数代码文件有编译错误的bug -- [change] 删除不必要的Datas~/Templates目录,直接以原始文件为模板 -- [refactor] 重构 AssemblyCache和 AssemblyReferenceDeepCollector,消除冗余代码 +- [fix] Fixes the bug where pruning aot dll results in an exception when generating bridge functions if netstandard is referenced. +- [fix] Fixes the bug where unusual field names result in compilation errors in the generated bridge function code files. +- [change] Removes the unnecessaryDatas~/Templates directory, using the original files as templates directly. +- [refactor] Refactorizes `AssemblyCache` and `AssemblyReferenceDeepCollector` to eliminate redundant code. ## 4.0.12 -发布日期 2023.11.02. +Release Date: 2023-11-02. ### Editor -- [fix] 修复BashUtil.RemoveDir的bug导致Installer安装失败的bug +- [fix] Fixes the bug in `BashUtil.RemoveDir` causing Installer installation to fail. ## 4.0.11 -发布日期 2023.11.02. +Release Date: 2023-11-02. ### Runtime -- [fix] 修复开启完全泛型共享后, 对于某些MethodInfo,由于methodPointer与virtualMethodPointer使用补充元数据后的解释器函数,而invoker_method仍然为支持完全泛型共享的调用形式,导致invoker_method与methodPointer及virtualMethodPointer不匹配的bug -- [fix] 修复Il2CppGenericContextCompare比较时仅仅对比inst指针的bug,造成热更新模块大量泛型函数重复 -- [fix] 修复完全泛型共享时未正确设置MethodInfo的bug +- [fix] Fixes the bug where when full generic sharing is enabled, for some `MethodInfo`, since `methodPointer` and `virtualMethodPointer` use the interpreter function with supplementary metadata, while `invoker_method` remains in the call form supporting full generic sharing, causing `invoker_method` to mismatch with `methodPointer` and `virtualMethodPointer`. +- [fix] Fixes the bug where `Il2CppGenericContextCompare` only compares inst pointers, causing a large number of duplicate generic functions in the hot update module. +- [fix] Fixes the bug where `MethodInfo` is not correctly set when full generic sharing is enabled. ### Editor -- [new] 检查当前安装的libil2cpp版本是否与package版本匹配,避免升级package后未重新install的问题 -- [new] Generate支持 netstandard -- [fix] 修复 ReversePInvokeWrap生成不必要地解析referenced dll,导致如果有aot dll引用了netstandard会出现解析错误的bug -- [fix] 修复BashUtil.RemoveDir在偶然情况下出现删除目录失败的问题。新增多次重试 -- [fix] 修复桥接函数计算时未归结函数参数类型,导致出现多个同名签名的bug - +- [new] Checks if the currently installed libil2cpp version matches the package version to avoid issues when upgrading the package without reinstalling. +- [new] `Generate` supports netstandard. +- [fix] Fixes the bug where `ReversePInvokeWrap` generates unnecessarily, parsing referenced dlls, causing parsing errors if aot dll references netstandard. +- [fix] Fixes the bug where `BashUtil.RemoveDir` occasionally fails to delete directories. Adds multiple retries. +- [fix] Fixes the bug where bridge function calculation does not reduce function parameter types, resulting in multiple functions with the same signature. ## 4.0.10 -发布日期 2023.10.12. +Release Date: 2023-10-12. ### Runtime -- [merge][il2cpp] 合并2022.3.10-2022.3.11f1的il2cpp改动,修复2022.3.11版本不兼容的问题 +- [merge][il2cpp] Merges il2cpp changes from versions 2022.3.10 to 2022.3.11f1, fixing incompatibility issues with version 2022.3.11. ## 4.0.9 -发布日期 2023.10.11. +Release Date: 2023-10-11. ### Runtime -- [merge][il2cpp][fix] 合并2021.3.29-2021.3.31f1的il2cpp改动,修复在2021.3.31版本的不兼容问题 -- [merge][il2cpp] 合并2022.3.7-2022.3.10f1的il2cpp改动 +- [merge][il2cpp][fix] Merges il2cpp changes from versions 2021.3.29 to 2021.3.31f1, fixing incompatibility issues with version 2021.3.31. +- [merge][il2cpp] Merges il2cpp changes from versions 2022.3.7 to 2022.3.10f1. ### Editor -- [fix] 修复2022版本iOS平台AddLil2cppSourceCodeToXcodeproj2022OrNewer的编译错误 +- [fix] Fixes the compilation error with `AddLil2cppSourceCodeToXcodeproj2022OrNewer` on the iOS platform for Unity 2022 versions. ## 4.0.8 -发布日期 2023.10.10. +Release Date: 2023-10-10. ### Runtime -- [fix] 修复计算值类型泛型桥接函数签名时,错误地将值类型泛型参数类型也换成签名,导致与Editor计算的签名不一致的bug -- [fix][refactor] RuntimeApi相关函数由PInvoke改为InternalCall,解决Android平台调用RuntimeApi时触发重新加载libil2cpp.a的问题 +- [fix] Fixes the bug where calculating the bridge function signature for value type generic bridge functions incorrectly replaces the value type generic parameter type with the signature, resulting in an inconsistent signature with the Editor calculation. +- [fix][refactor] Changes RuntimeApi related functions from PInvoke to InternalCall, solving the issue of reloading libil2cpp.a when calling RuntimeApi on Android platforms. ### Editor -- [refactor] RuntimeApi相关函数由PInvoke改为InternalCall -- [refactor] 调整HybridCLR.Editor模块一些不规范的命名空间 +- [refactor] Changes RuntimeApi related functions from PInvoke to InternalCall . +- [refactor] Adjusts some non-standard namespace names in the HybridCLR.Editor module. ## 4.0.7 -发布日期 2023.10.09. +Release Date: 2023-10-09. ### Runtime -- [fix] 修复initobj调用了CopyN,但CopyN未考虑对象的内存对齐的情况,在32位这种的平台可能发生未对齐访问异常的bug -- [fix] 修复计算未完全实例化的泛型函数的桥接函数签名时崩溃的bug -- [fix] 修复Il2cpp代码生成选项为faster(smaller)时,2021和2022版本GenericMethod::CreateMethodLocked的bug -- [remove] 移除所有array相关指令中index为int64_t的指令,简化代码 -- [remove] 移除ldfld_xxx_ref系列指令 +- [fix] Fixes the bug where `initobj` calls `CopyN`, but `CopyN` does not consider object memory alignment, which may cause unaligned access exceptions on platforms like 32-bit. +- [fix] Fixes the bug where calculating the bridge function signature for not fully instantiated generic functions crashes. +- [fix] Fixes the bug where `GenericMethod::CreateMethodLocked` has issues when the Il2cpp code generation option is faster (smaller) for versions 2021 and 2022. +- [remove] Removes all array-related instructions with int64_t indices to simplify the code. +- [remove] Removes the `ldfld_xxx_ref` series of instructions. ### Editor -- [fix] 修复生成桥接函数时,如果热更新程序集未包含任何代码直接引用了某个aot程序集,则没有为该aot程序集生成桥接函数,导致出现NotSupportNative2Managed异常的bug -- [fix] 修复mac下面路径过长导致拷贝文件失败的bug -- [fix] 修复发布PS5目标时未处理ScriptingAssemblies.json的bug -- [change] 打包时清空裁减aot dll目录 +- [fix] Fixes the bug where generating bridge functions does not generate bridge functions for an aot assembly if the hot update assembly does not directly reference any code, resulting in a `NotSupportNative2Managed` exception. +- [fix] Fixes the bug where copying files fails on Mac due to excessively long paths. +- [fix] Fixes the bug where publishing for PS5 targets does not process `ScriptingAssemblies.json`. +- [change] Clears the pruned aot dll directory when packaging. ## 4.0.6 -发布日期 2023.09.26. +Release Date: 2023-09-26. ### Runtime -- [fix] 修复2021和2022版本开启完全泛型共享后的bug -- [fix] 修复加载PlaceHolder Assembly后未增加assemblyVersion导致Assembly::GetAssemblies()错误地获得了旧程序集列表的bug +- [fix] Fixes the bug with versions 2021 and 2022 when full generic sharing is enabled. +- [fix] Fixes the bug where loading a PlaceHolder Assembly does not increase `assemblyVersion`, causing `Assembly::GetAssemblies()` to incorrectly obtain an old assembly list. ## 4.0.5 -发布日期 2023.09.25. +Release Date: 2023-09-25. ### Runtime -- [fix] 修复Transform中未析构pendingFlows造成内存泄露的bug -- [fix] 修复多维数组SetMdArrElement未区分带ref与不带ref结构的bug -- [fix] 修复CpobjVarVAr_WriteBarrier_n_4未设置size的bug -- [fix] 修复计算interface成员函数slot时未考虑到static之类函数的bug -- [fix] 修复2022版本ExplicitLayout未设置layout.alignment,导致计算出size==0的bug -- [fix] 修复InterpreterInvoke在完全泛型共享时,class类型的methodPointer与virtualMethodPointer有可能不一致,导致失误对this指针+1的bug -- [fix] ldobj当T为byte之类size<4的类型时,未将数据展开为int的bug -- [fix] 修复CopySize未考虑到内存对齐的问题 -- [opt] 优化stelem当元素为size较大的struct时统一当作含ref结构的问题 -- [opt] TemporaryMemoryArena默认内存块大小由1M调整8K -- [opt] 将Image::Image中Assembly::GetAllAssemblies()换成Assembly::GetAllAssemblies(AssemblyVector&),避免创建assembly快照而造成不必要的内存泄露 +- [fix] Fixes the bug where `Transform` does not destruct `pendingFlows`, causing a memory leak. +- [fix] Fixes the bug where `SetMdArrElement` does not distinguish between structures with and without ref. +- [fix] Fixes the bug where `CpobjVarVAr_WriteBarrier_n_4` does not set the size. +- [fix] Fixes the bug where calculating interface member function slots does not consider static and similar functions. +- [fix] Fixes the bug where `ExplicitLayout` is not set for layout.alignment in version 2022, resulting in a size of 0. +- [fix] Fixes the bug where `InterpreterInvoke` in full generic sharing may have inconsistent `methodPointer` and `virtualMethodPointer` for class types, causing an error in incrementing the this pointer by 1. +- [fix] Fixes the bug where `ldobj` does not expand data into an int when T is a type like byte with a size less than 4. +- [fix] Fixes the bug where `CopySize` does not consider memory alignment issues. +- [opt] Optimizes `stelem` when the element is a larger struct, unifying it as a structure containing ref. +- [opt] Adjusts the default memory block size of `TemporaryMemoryArena` from 1M to 8K. +- [opt] Changes `Assembly::GetAllAssemblies()` in `Image::Image` to `Assembly::GetAllAssemblies(AssemblyVector&)`, avoiding the creation of an assembly snapshot and preventing unnecessary memory leaks. ### Editor -- [fix] 修复StandaloneLinux平台DllImport的dllName和裁剪dll路径的错误 -- [change] 对于小版本不兼容的Unity版本,不再禁止安装,而是提示警告 -- [fix] 修复桥接函数计算中MetaUtil.ToShareTypeSig将Ptr和ByRef计算成IntPtr的bug,正确应该是UIntPtr +- [fix] Fixes the bug where `DllImport` for the StandaloneLinux platform has incorrect dllName and pruned dll path errors. +- [change] For Unity versions with minor incompatibility, installation is no longer prohibited, but a warning is displayed instead. +- [fix] Fixes the bug where `MetaUtil.ToShareTypeSig` calculates `Ptr` and `ByRef` as `IntPtr` in bridge function calculations, which should correctly be `UIntPtr`. ## 4.0.4 -发布日期 2023.09.11。 +Release Date: 2023-09-11. ### Runtime -- [new][platform] 彻底支持所有平台,包括UWP和PS5 -- [fix][严重] 修复计算interpreter部分enum类型的桥接函数签名的bug -- [fix] 修复在某些平台下有编译错误的问题 -- [fix] 修复转换STOBJ指令未正确处理增量式GC的bug -- [fix] [fix] 修复 StindVarVar_ref指令未正确设置WriteBarrier的bug -- [fix] 修复2020 GenericMethod::CreateMethodLocked调用vm::MetadataAllocGenericMethod()未持有s_GenericMethodMutex锁的线程安全问题 +- [new][platform] Fully supports all platforms, including UWP and PS5. +- [fix][serious] Fixes the bug where calculating the bridge function signature for interpreter parts of enum types is incorrect. +- [fix] Fixes compilation errors on some platforms. +- [fix] Fixes the bug where converting STOBJ instructions does not correctly handle incremental GC. +- [fix] Fixes the bug where the `StindVarVar_ref` instruction does not correctly set WriteBarrier. +- [fix] Fixes the thread safety issue where `GenericMethod::CreateMethodLocked` calls `vm::MetadataAllocGenericMethod()` without holding the `s_GenericMethodMutex` lock in version 2020. ### Editor -- [fix] 修复AddLil2cppSourceCodeToXcodeproj2021OrOlder在Unity 2020下偶然同时包含了不同目录的两个ThreadPool.cpp文件导致出现编译错误的问题 -- [fix] 修复不正确地从EditorUserBuildSettings.selectedBuildTargetGroup获得BuildGroupTarget的bug -- [fix] StripAOTDllCommand生成AOT dll时的BuildOption采用当前Player的设置,避免当打包开启development时,StripAOTDllCommand生成Release aot dll,而打包生成debug aot dll,产生补充元数据及桥接函数生成不匹配的严重错误 -- [change] 为了更好地支持全平台,调整了RuntimeApi.cs中dllName的实现,默认取 __Internal -- [change] 为了更好地支持全平台,自2021起裁剪AOT dll全都通过MonoHook复制 +- [fix] Fixes the bug where `AddLil2cppSourceCodeToXcodeproj2021OrOlder` includes two ThreadPool.cpp files in different directories, causing compilation errors in Unity 2020. +- [fix] Fixes the bug where obtaining `BuildGroupTarget` from `EditorUserBuildSettings.selectedBuildTargetGroup` is incorrect. +- [fix] `StripAOTDllCommand` generates AOT dlls with the current Player settings to avoid serious mismatches between supplementary metadata and bridge function generation when packaging with development enabled. +- [change] To better support all platforms, adjusts the implementation of dllName in RuntimeApi.cs to default to `__Internal`. +- [change] To better support all platforms, all AOT dll pruning since 2021 is done through MonoHook copying. ## 4.0.3 -发布日期 2023.08.31。 +Release Date: 2023-08-31. ### Editor -- [fix] 修复桥接函数计算的bug +- [fix] Fixes the bug in bridge function calculation. ## 4.0.2 -发布日期 2023.08.29。 +Release Date: 2023-08-29. ### Runtime -- [fix][严重] 修复LdobjVarVar_ref指令的bug。此bug由增量式GC代码引入 -- [fix] 修复未处理ResolveField获得的Field为nullptr时情形导致崩溃的bug -- [fix] 修复未正确处理AOT及interpreter interface中显式实现父接口函数的bug +- [fix][serious] Fixes the bug in `LdobjVarVar_ref` instruction. This bug was introduced by incremental GC code. +- [fix] Fixes the bug where `ResolveField` obtaining a Field as nullptr is not handled, causing a crash. +- [fix] Fixes the bug where AOT and interpreter interface explicitly implement parent interface functions are not correctly handled. ## 4.0.1 -发布日期 2023.08.28。 +Release Date: 2023-08-28. ### Runtime -- [fix] 修复2020版本开启增量式GC后出现编译错误的问题 +- [fix] Fixes the compilation error when incremental GC is enabled in version 2020. ## 4.0.0 -发布日期 2023.08.28。 +Release Date: 2023-08-28. ### Runtime -- [new] 支持增量式GC -- [refactor] 重构桥接函数,彻底支持所有il2cpp支持的平台 -- [opt] 大幅优化Native2Managed方向的传参 +- [new] Supports incremental GC. +- [refactor] Refactorizes bridge functions to fully support all platforms supported by il2cpp. +- [opt] Significantly optimizes Native2Managed direction parameter passing. ### Editor -- [change] 删除增量式GC选项检查 -- [refactor] 重构桥接函数生成 +- [change] Removes incremental GC option checks. +- [refactor] Refactorizes bridge function generation. ## 3.4.2 -发布日期 2023.08.14。 +Release Date: 2023-08-14. ### Runtime -- [fix] 修复RawImage::LoadTables读取_4byteGUIDIndex的bug -- [version] 支持2022.3.7版本 -- [version] 支持2021.3.29版本 +- [fix] Fixes the bug in `RawImage::LoadTables` reading `_4byteGUIDIndex`. +- [version] Supports version 2022.3.7. +- [version] Supports version 2021.3.29. ### Editor -- [fix] 修复计算AOTGenericReference未考虑到泛型调用泛型的情况,导致少计算了泛型及补充元数据 +- [fix] Fixes the bug where calculating AOTGenericReference does not consider generic calls on generics, resulting in fewer calculated generics and supplementary metadata. ## 3.4.1 -发布日期 2023.07.31。 +Release Date: 2023-07-31. ### Runtime -- [fix] 修复 InitializeRuntimeMetadata的内存可见性问题 -- [fix] 修复CustomAttribute未正确处理父类NamedArg导致崩溃的bug -- [opt] 优化Transfrom Instinct指令的代码,从HashMap中快速查找而不是挨个匹配 +- [fix] Fixes the memory visibility issue in `InitializeRuntimeMetadata`. +- [fix] Fixes the bug where `CustomAttribute` does not correctly handle parent NamedArg, causing a crash. +- [opt] Optimizes the code for Transform Instinct instructions, quickly looking up in the HashMap instead of matching one by one. ### Editor -- [fix] 修复FilterHotFixAssemblies只对比程序集名尾部,导致有AOT的尾部与某个热更新程序集匹配时意外被过滤的bug -- [change] 检查Settings中热更新程序集列表配置中程序集名不能为空 +- [fix] Fixes the bug where `FilterHotFixAssemblies` only compares the tail of the assembly name, causing an assembly to be unexpectedly filtered if it matches the tail of an AOT assembly. +- [change] Checks that the assembly name in the hot update assembly list configuration in Settings is not empty. ## 3.4.0 -发布日期 2023.07.17。 +Release Date: 2023-07-17. ### Runtime -- [version] 支持2021.3.28和2022.3.4版本 -- [opt] 删除MachineState::InitEvalStack分配_StackBase后不必要的memset -- [fix] 修复Exception机制的bug -- [fix] 修复CustomAttribute不支持Type[]类型参数的bug -- [fix] 修复不支持new string(xxx)用法的问题 -- [refactor] 重构VTableSetup实现 -- [fix] 修复未计算子interface中显式实现父interface的函数的bug -- [opt] Lazy初始化CustomAttributeData,而不是加载时全部初始化,明显减少Assembly.Load时间 -- [fix] 修复2022 当new byte\[]{a,b,c...}方式初始化较长的byte[]数据时,返回错误数据的bug +- [version] Supports versions 2021.3.28 and 2022.3.4. +- [opt] Removes unnecessary memset after allocating `_StackBase` in `MachineState::InitEvalStack`. +- [fix] Fixes the exception mechanism bug. +- [fix] Fixes the bug where `CustomAttribute` does not support Type[] type parameters. +- [fix] Fixes the issue where the new string(xxx) syntax is not supported. +- [refactor] Refactorizes VTableSetup implementation. +- [fix] Fixes the bug where functions explicitly implementing parent interfaces in subinterfaces are not calculated. +- [opt] Lazily initializes `CustomAttributeData` instead of initializing all at load time, significantly reducing `Assembly.Load` time. +- [fix] Fixes the bug where new byte[]{a,b,c...} initialization of longer byte[] data returns incorrect data in version 2022. ### Editor -- [fix] 修复计算桥接函数未考虑到泛型类的成员函数中可能包含的Native2Managed调用 -- [change] link.xml及AOTGenericReferences.cs默认输出路径改为HybridCLRGenerate,避免与顶层HybridCLRData混淆 -- [fix] 修复Win下生成的Lump文件中include路径以\为目录分隔符导致同步到Mac后找不到路径的bug -- [refactor] 重构Installer - +- [fix] Fixes the bug where calculating bridge functions does not consider Native2Managed calls that may be included in generic class member functions. +- [change] The default output paths for link.xml and AOTGenericReferences.cs are changed to HybridCLRGenerate to avoid confusion with the top-level HybridCLRData. +- [fix] Fixes the bug where the include path in the lump file generated on Windows uses \ as the directory separator, causing path not found errors when synchronized to Mac. +- [refactor] Refactorizes the Installer. ## 3.3.0 -发布日期 2023.07.03。 +Release Date: 2023-07-03. ### Runtime -- [fix] 修复localloc分配的内存未释放的bug -- [change] MachineState改用RegisterRoot的方式注册执行栈,避免GC时扫描整个堆栈 -- [opt] 优化Managed2NativeCallByReflectionInvoke性能,提前计算好传参方式 -- [refactor] 重构ConvertInvokeArgs +- [fix] Fixes the bug where memory allocated by localloc is not released. +- [change] `MachineState` uses RegisterRoot to register the execution stack, avoiding GC scanning of the entire stack. +- [opt] Optimizes the performance of Managed2NativeCallByReflectionInvoke by calculating the parameter passing method in advance. +- [refactor] Refactorizes ConvertInvokeArgs. ### Editor -- [fix] 修复2020-2021编译libil2cpp.a未包含brotli相关代码文件导致出现编译错误的bug -- [fix] 修复从导出xcode项目包含绝对路径导致传送到其他机器上编译时找不到路径的bug -- [fix] 解决Generate LinkXml、 MethodBridge、AOTGenericReference、ReversePInvokeWrap 生成不稳定的问题 -- [fix] 修复使用不兼容版本打开Installer时出现异常的bug -- [change] 禁用hybridclr后打包ios时不再修改导出的xcode工程 +- [fix] Fixes the bug where compiling libil2cpp.a for 2020-2021 does not include brotli-related code files, resulting in compilation errors. +- [fix] Fixes the bug where exporting an xcode project includes absolute paths, causing path not found errors when compiled on other machines. +- [fix] Solves the instability issues in generating LinkXml, MethodBridge, AOTGenericReference, and ReversePInvokeWrap. +- [fix] Fixes the exception when opening the Installer with an incompatible version. +- [change] When hybridclr is disabled, packaging iOS no longer modifies the exported xcode project. ## 3.2.1 ### Runtime -- [fix] 修复il2cpp TypeNameParser未将类型名中转义字符'\'去掉,导致找不到嵌套子类型的bug +- [fix] Fixes the bug where il2cpp TypeNameParser does not remove escape characters '\' from type names, causing nested child types to not be found. ### Editor -- [new] Installer界面新增显示package版本 -- [new] CompileDll新增MacOS、Linux、WebGL目标 -- [fix] 修复重构文档站后的帮助文档的链接错误 -- [change] 为Anaylizer加上using 限定,解决某些情况下与项目的类型同名而产生编译冲突的问题 +- [new] The Installer interface adds display of package version. +- [new] CompileDll adds MacOS, Linux, and WebGL targets. +- [fix] Fixes the help documentation link errors after refactoring the documentation site. +- [change] Adds using qualifiers to Analyzer to resolve compilation conflicts with project types that have the same name. ## 3.2.0 ### Runtime -- [fix] 修复未在PlaceHolder中的Assembly加载时,如果由于不在Assembly列表,也没有任何解释器栈,导致Class::resolve_parse_info_internal查找不到类型的bug -- [fix] 修复读取CustomAttribute System.Type类型数据崩溃的bug +- [fix] Fixes the bug where if an Assembly is not in the PlaceHolder, and there is no interpreter stack, `Class::resolve_parse_info_internal` cannot find the type due to not being in the Assembly list. ### Editor -- [new] 支持直接从源码打包iOS,不再需要单独编译libil2cpp.a -- [opt] 优化版本不兼容时错误提示,不再抛出异常,而是显示"与当前版本不兼容" - +- [new] Supports packaging iOS directly from source code, no longer needing to compile libil2cpp.a separately. +- [opt] Optimizes error prompts for incompatible versions, no longer throwing exceptions, but displaying "incompatible with the current version". ## 3.1.1 ### Runtime -- [fix] 修复2021及更高版本,InterpreterModule::Managed2NativeCallByReflectionInvoke调用值类型成员函数时,对this指针多余this=this-1操作。 -- [fix] 修复解析CustomAttribute中Enum[]类型字段的bug -- [fix] 修复2021及更高版本反射调用值类型 close Delegate的Invoke函数时未修复target指针的bug -- [new] 新增对增量式GC宏的检查,避免build.gradle中意外开启增量式GC引发的极其隐蔽的问题 +- [fix] Fixes the bug where InterpreterModule::Managed2NativeCallByReflectionInvoke calls value type member functions in 2021 and higher versions, with an extra this=this-1 operation. +- [fix] Fixes the bug where parsing CustomAttribute Enum[] type fields. +- [fix] Fixes the bug where invoking the Invoke function of a closed Delegate via reflection in 2021 and higher versions does not repair the target pointer. ### Editor -- [fix] 修复 Win32、Android32、WebGL平台的编译错误 -- [fix] 修复计算桥接函数时未考虑到补充元数据泛型实例化会导致访问到一些非公开的函数的情况,导致少生成一些必要的桥接函数 -- [opt] 生成AOTGenericReferences时,补充元数据assembly列表由注释改成List列表,方便在代码中直接使用。 -- [change] CheckSettings中不再自动设置Api Compatible Level +- [fix] Fixes compilation errors for Win32, Android32, and WebGL platforms. +- [fix] Fixes the bug where calculating bridge functions does not consider supplementary metadata generic instantiation, which may access some non-public functions, resulting in fewer necessary bridge functions being generated. +- [opt] When generating AOTGenericReferences, the supplementary metadata assembly list is changed from comments to List lists for easy direct use in code. +- [change] CheckSettings no longer automatically sets Api Compatible Level. ## 3.1.0 ### Runtime -- [rollback] 还原对Unity 2020.3.x支持 -- [fix] 修复 WebGL平台ABI的bug +- [rollback] Reverts support for Unity 2020.3.x. +- [fix] Fixes the WebGL platform ABI bug. ### Editor -- [rollback] 还原对Unity 2020.3.x支持 +- [rollback] Reverts support for Unity 2020.3.x. ## 3.0.3 ### Runtime -- [fix] 修复Enum::GetValues返回值不正确的bug +- [fix] Fixes the bug where Enum::GetValues returns incorrect values. ## 3.0.2 ### Runtime -- [fix] 修复Memory Profiler中创建内存快照时崩溃的bug +- [fix] Fixes the bug where creating a memory snapshot in Memory Profiler crashes. ### Editor -- [remove] 移除 `HybridCLR/CreateAOTDllSnapshot`菜单 - +- [remove] Removes the `HybridCLR/CreateAOTDllSnapshot` menu. ## 3.0.1 ### Runtime -- [new] 支持2022.3.0 +- [new] Supports version 2022.3.0. ## 3.0.0 ### Runtime -- [fix] 修复不支持访问CustomData字段及值的bug -- [remove] 移除对2019及2020版本支持 +- [fix] Fixes the bug where accessing CustomData fields and values is not supported. +- [remove] Removes support for 2019 and 2020 versions. ### Editor -- 包名更改为com.code-philosophy.hybridclr -- 移除UnityFS插件 -- 移除Zip插件 -- HybridCLR菜单位置调整 +- Changes the package name to com.code-philosophy.hybridclr. +- Removes the UnityFS plugin. +- Removes the Zip plugin. +- Adjusts the HybridCLR menu location. ## 2.4.2 ### Runtime -- [version] 支持 2020.3.48,最后一个2020LTS版本 -- [version] 支持 2021.3.25 +- [version] Supports 2020.3.48, the last 2020 LTS version. +- [version] Supports 2021.3.25. ## 2.4.1 @@ -404,7 +929,7 @@ ### Editor -- [fix] 修复遗漏 RELEASELOG.md.meta 文件的问题 +- [fix] Fixes the遗漏 RELEASELOG.md.meta file issue. ## 2.4.0 @@ -412,9 +937,9 @@ ### Editor -- [new] CheckSettings中检查ScriptingBackend及ApiCompatibleLevel,切换为正确的值 -- [new] 新增 MsvcStdextWorkaround.cs 解决2020 vs下stdext编译错误的问题 -- [fix] 修复当struct只包含一个float或double字段时,在arm64上计算桥接函数签名错误的bug +- [new] CheckSettings checks ScriptingBackend and ApiCompatibleLevel, switching to the correct values. +- [new] Adds MsvcStdextWorkaround.cs to solve stdext compilation errors in 2020 vs. +- [fix] Fixes the bug where calculating bridge function signatures for structs containing only one float or double field is incorrect on arm64. ## 2.3.1 @@ -422,7 +947,7 @@ ### Editor -- [fix] 修复本地复制libil2cpp却仍然从仓库下载安装的bug +- [fix] Fixes the bug where copying libil2cpp locally still downloads and installs from the repository. ## 2.3.0 @@ -430,7 +955,9 @@ ### Editor -- [new] Installer支持从本地目录复制改造后的libil2cpp -- [fix] 修复2019版本MonoBleedingEdge的子目录中包含了过长路径的文件导致Installer复制文件出错的问题 +- [new] The Installer supports copying modified libil2cpp from a local directory. +- [fix] Fixes the bug where the MonoBleedingEdge subdirectory in version 2019 includes files with excessively long paths, causing the Installer to fail when copying files. + + diff --git a/Assets/01.HybridCLR/RELEASELOG.md.meta b/Assets/01.HybridCLR/RELEASELOG.md.meta index b9f4089..47abd21 100644 --- a/Assets/01.HybridCLR/RELEASELOG.md.meta +++ b/Assets/01.HybridCLR/RELEASELOG.md.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4afa874744008ef40b7a410066ae71de +guid: 8e53ce54bd8e88c4785c625555308dba TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/01.HybridCLR/Runtime.meta b/Assets/01.HybridCLR/Runtime.meta index 7e42c24..d5e99d3 100644 --- a/Assets/01.HybridCLR/Runtime.meta +++ b/Assets/01.HybridCLR/Runtime.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e95340bb3cc05874ea371b716fec1f4d +guid: a6d5e365e1b7d9742bee023ea54b31f2 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs b/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs index dd839ca..f244856 100644 --- a/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs +++ b/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs @@ -3,8 +3,8 @@ namespace HybridCLR { public enum HomologousImageMode { - Consistent, // AOT dll需要跟主工程精确一致,即为裁剪后的AO dll - SuperSet, // AOT dll不需要跟主工程精确一致,但必须包含裁剪后的AOT dll的所有元数据,即为裁剪后dll的超集。推荐使用原始aot dll + Consistent, + SuperSet, } } diff --git a/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs.meta b/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs.meta index 4a23099..dde78bf 100644 --- a/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs.meta +++ b/Assets/01.HybridCLR/Runtime/HomologousImageMode.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: bfb72a4a8e158ab4f9dd2552f7d662a1 +guid: 0f0351553ad90e74aa586746b5965ded MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs b/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs index 195122a..93d4b38 100644 --- a/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs +++ b/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs @@ -4,12 +4,13 @@ namespace HybridCLR public enum LoadImageErrorCode { OK = 0, - BAD_IMAGE, // dll 不合法 - NOT_IMPLEMENT, // 不支持的元数据特性 - AOT_ASSEMBLY_NOT_FIND, // 对应的AOT assembly未找到 - HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY, // 不能给解释器assembly补充元数据 - HOMOLOGOUS_ASSEMBLY_HAS_LOADED, // 已经补充过了,不能再次补充 - INVALID_HOMOLOGOUS_MODE, // 非法HomologousImageMode - }; + BAD_IMAGE, // invalid dll file + NOT_IMPLEMENT, // not implement feature + AOT_ASSEMBLY_NOT_FIND, // AOT assembly not found + HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY, // can not load supplementary metadata assembly for non-AOT assembly + HOMOLOGOUS_ASSEMBLY_HAS_LOADED, // can not load supplementary metadata assembly for the same assembly + INVALID_HOMOLOGOUS_MODE, // invalid homologous image mode + PDB_BAD_FILE, // invalid pdb file + }; } diff --git a/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs.meta b/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs.meta index 13db8f4..4f77029 100644 --- a/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs.meta +++ b/Assets/01.HybridCLR/Runtime/LoadImageErrorCode.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6982c52ba05eada40bd1f38a1b719daa +guid: 2c7d5b71981fba643b4c21ed01bcb675 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta b/Assets/01.HybridCLR/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta index e1d8b72..a46bd5a 100644 --- a/Assets/01.HybridCLR/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta +++ b/Assets/01.HybridCLR/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a9ad08231091388419452f4b3318e4f3 +guid: f99dd22d9d81b2540b4663b3bcdf0a79 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Runtime/RuntimeApi.cs b/Assets/01.HybridCLR/Runtime/RuntimeApi.cs index 8169063..1ee67bb 100644 --- a/Assets/01.HybridCLR/Runtime/RuntimeApi.cs +++ b/Assets/01.HybridCLR/Runtime/RuntimeApi.cs @@ -6,13 +6,16 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using UnityEditor; +using UnityEngine.Scripting; namespace HybridCLR { + [Preserve] public static class RuntimeApi { /// - /// 加载补充元数据assembly + /// load supplementary metadata assembly /// /// /// @@ -28,7 +31,38 @@ namespace HybridCLR #endif /// - /// 获取解释器线程栈的最大StackObject个数(size*8 为最终占用的内存大小) + /// prejit method to avoid the jit cost of first time running + /// + /// + /// return true if method is jited, return false if method can't be jited + /// +#if UNITY_EDITOR + public static bool PreJitMethod(MethodInfo method) + { + return false; + } +#else + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool PreJitMethod(MethodInfo method); +#endif + + /// + /// prejit all methods of class to avoid the jit cost of first time running + /// + /// + /// return true if class is jited, return false if class can't be jited +#if UNITY_EDITOR + public static bool PreJitClass(Type type) + { + return false; + } +#else + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern bool PreJitClass(Type type); +#endif + + /// + /// get the maximum number of StackObjects in the interpreter thread stack (size*8 represents the final memory size occupied /// /// public static int GetInterpreterThreadObjectStackSize() @@ -37,17 +71,17 @@ namespace HybridCLR } /// - /// 设置解释器线程栈的最大StackObject个数(size*8 为最终占用的内存大小) + /// set the maximum number of StackObjects for the interpreter thread stack (size*8 represents the final memory size occupied) /// /// public static void SetInterpreterThreadObjectStackSize(int size) { SetRuntimeOption(RuntimeOptionId.InterpreterThreadObjectStackSize, size); } - + /// - /// 获取解释器线程函数帧数量(sizeof(InterpreterFrame)*size 为最终占用的内存大小) + /// get the number of interpreter thread function frames (sizeof(InterpreterFrame)*size represents the final memory size occupied) /// /// public static int GetInterpreterThreadFrameStackSize() @@ -56,7 +90,7 @@ namespace HybridCLR } /// - /// 设置解释器线程函数帧数量(sizeof(InterpreterFrame)*size 为最终占用的内存大小) + /// set the number of interpreter thread function frames (sizeof(InterpreterFrame)*size represents the final memory size occupied) /// /// public static void SetInterpreterThreadFrameStackSize(int size) @@ -69,6 +103,11 @@ namespace HybridCLR private static readonly Dictionary s_runtimeOptions = new Dictionary(); + /// + /// set runtime option value + /// + /// + /// public static void SetRuntimeOption(RuntimeOptionId optionId, int value) { s_runtimeOptions[optionId] = value; @@ -78,6 +117,11 @@ namespace HybridCLR public static extern void SetRuntimeOption(RuntimeOptionId optionId, int value); #endif + /// + /// get runtime option value + /// + /// + /// #if UNITY_EDITOR public static int GetRuntimeOption(RuntimeOptionId optionId) { diff --git a/Assets/01.HybridCLR/Runtime/RuntimeApi.cs.meta b/Assets/01.HybridCLR/Runtime/RuntimeApi.cs.meta index 71029af..6ed5cdc 100644 --- a/Assets/01.HybridCLR/Runtime/RuntimeApi.cs.meta +++ b/Assets/01.HybridCLR/Runtime/RuntimeApi.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a6b8a4a760dd0a14e92007d5e5aab70a +guid: 0d58bdc22b6d6b54ab6791baf16a0a3d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs b/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs index 3dc24dc..25c3417 100644 --- a/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs +++ b/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs @@ -5,5 +5,8 @@ InterpreterThreadObjectStackSize = 1, InterpreterThreadFrameStackSize = 2, ThreadExceptionFlowSize = 3, + MaxMethodBodyCacheSize = 4, + MaxMethodInlineDepth = 5, + MaxInlineableMethodBodySize = 6, } } diff --git a/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs.meta b/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs.meta index 48cf9a1..9c7181e 100644 --- a/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs.meta +++ b/Assets/01.HybridCLR/Runtime/RuntimeOptionId.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 926f1f78d8ea7d24c91951ad5bbf0208 +guid: 64be598b47302644a96013c74d945653 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/01.HybridCLR/package.json b/Assets/01.HybridCLR/package.json index c484abc..f4b14d8 100644 --- a/Assets/01.HybridCLR/package.json +++ b/Assets/01.HybridCLR/package.json @@ -1,9 +1,9 @@ { "name": "com.code-philosophy.hybridclr", - "version": "4.0.15", + "version": "8.2.0", "displayName": "HybridCLR", "description": "HybridCLR is a fully featured, zero-cost, high-performance, low-memory solution for Unity's all-platform native c# hotupdate.", - "category": "Runtime", + "category": "Scripting", "documentationUrl": "https://hybridclr.doc.code-philosophy.com/#/", "changelogUrl": "https://hybridclr.doc.code-philosophy.com/#/other/changelog", "licensesUrl": "https://github.com/focus-creative-games/hybridclr_unity/blob/main/LICENSE", diff --git a/Assets/01.HybridCLR/package.json.meta b/Assets/01.HybridCLR/package.json.meta index c28fa30..65ee986 100644 --- a/Assets/01.HybridCLR/package.json.meta +++ b/Assets/01.HybridCLR/package.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9fb97777444e1d24b84e4fd9cae37eb3 +guid: 8ea8eca3a387d9d4988a2fca1036f2e7 PackageManifestImporter: externalObjects: {} userData: