diff --git a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset index f7630fe9b9..1fbb8a23ba 100644 --- a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset +++ b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset @@ -49,3 +49,5 @@ MonoBehaviour: prefab: {fileID: 1126053271199039253, guid: 526d462bd8c87b74c9e461e80d028cb2, type: 3} - id: DlgPlayerOptions prefab: {fileID: 1813565726936289741, guid: a0e02be030755ab4a917523764fe4eef, type: 3} + - id: Win_Message2 + prefab: {fileID: 1590197940424963217, guid: 0c248d0510a114829b58d62d2ecc3b5e, type: 3} diff --git a/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs new file mode 100644 index 0000000000..10414ecd66 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs @@ -0,0 +1,84 @@ +using System; +using System.Runtime.InteropServices; +using EditorAttributes; +// using NaughtyAttributes; +using UnityEngine; + +namespace BrewMonster +{ + public class TestByteNumber : MonoBehaviour + { + + // Start is called once before the first execution of Update after the MonoBehaviour is created + void Start() + { + + } + + [ContextMenu("Test")] + public void Test() + { + var origin = Marshal.SizeOf(); + var diff = Marshal.SizeOf() - Marshal.SizeOf(); + BMLogger.Log($" Origin : {origin } - diff = {diff}"); // 255 + } + + [ContextMenu(" TestCompress")] + public void TestCompress() + { + int value = 123456; + byte[] src = BitConverter.GetBytes(value); + + int dstLen = 10000; + byte[] dst = new byte[dstLen]; + + int res = AFilePackage.Compress( src, 0, src.Length, dst, 0, ref dstLen); + + BMLogger.Log($" Res : {res} - srcLen = {src.Length} - dstLen = {dstLen} - compressed data: {BitConverter.ToString(dst, 0, dstLen)}"); + } + + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct EC_GAME_SETTING_TEST + { + [MarshalAs(UnmanagedType.U1)] public bool bNoTeamRequest; + [MarshalAs(UnmanagedType.U1)] public bool bNoTradeRequest; + [MarshalAs(UnmanagedType.U1)] public bool bTurnaround; + [MarshalAs(UnmanagedType.U1)] public bool bReverseWheel; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_USERCHANNEL_NUM * 15, + ArraySubType = UnmanagedType.I1)] // GP_CHAT_MAX = 15; I1 = 1 byte per bool to match C++ bool[6][15] + public byte[] bChannel; + [MarshalAs(UnmanagedType.U1)] + public bool bAutoReply; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)] + public string szAutoReply; + + [MarshalAs(UnmanagedType.U1)] public float fCamTurnSpeed; + public float fCamZoomSpeed; + public byte nFontSize; + [MarshalAs(UnmanagedType.U1)] public bool bAtk_Player; + [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoMafia; + [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoWhite; + [MarshalAs(UnmanagedType.U1)] public bool bFontBold; + [MarshalAs(UnmanagedType.U1)] public bool bBls_NoRed; + [MarshalAs(UnmanagedType.U1)] public bool bBls_NoMafia; + [MarshalAs(UnmanagedType.U1)] public bool bBls_Self; + [MarshalAs(UnmanagedType.U1)] public bool bBlsRefuse_Neutral; + [MarshalAs(UnmanagedType.U1)] public bool bHideAutoGuide; + [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoAlliance; + [MarshalAs(UnmanagedType.U1)] public bool bBls_NoAlliance; + [MarshalAs(UnmanagedType.U1)] public bool bBlsRefuse_NonTeammate; + [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoForce; + [MarshalAs(UnmanagedType.U1)] public bool bBls_NoForce; + [MarshalAs(UnmanagedType.U1)] public bool bLockQuickBar; + [MarshalAs(UnmanagedType.U1)] public bool bPetAutoSkill; + [MarshalAs(UnmanagedType.U1)] public bool bAutoTeamForTask; + [MarshalAs(UnmanagedType.U1)] public bool bDisableAutoWikiHelp; + [MarshalAs(UnmanagedType.U1)] public bool bExclusiveAwardMode; + [MarshalAs(UnmanagedType.U1)] public bool bHideIceThunderBall; + + } +} diff --git a/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta new file mode 100644 index 0000000000..dafe0fb5d3 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 67551ceb317224e67b8140cbe7175c44 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index 514e613db4..52fb7ce95e 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -1515,7 +1515,7 @@ namespace CSNetwork /// public void SaveConfigData(byte[] pBuf, int len) { - BMLogger.Log($"[MH] Session SaveConfigData len={len}"); + BMLogger.Log($"[MH] Session.SaveConfigData | len={len}"); if (pBuf == null || len <= 0) return; var p = new setuiconfig(); @@ -1526,7 +1526,7 @@ namespace CSNetwork p.Ui_config = new Octets(slice); // TODO: open later - return; + // return; SendProtocol(p); } @@ -2000,5 +2000,17 @@ namespace CSNetwork gamedatasend.Data = C2SCommandFactory.CreateDebugCmd(icmd, param1); SendProtocol(gamedatasend); } + + // Cross-server get in (C++: c2s_CmdNPCSevCrossServerGetIn) — TODO: implement C2S packet when needed + public void c2s_CmdNPCSevCrossServerGetIn() + { + // TODO: C2SCommandFactory.CreateNPCSevCrossServerGetInCmd() and SendProtocol + } + + // Cross-server get out (C++: c2s_CmdNPCSevCrossServerGetOut) — TODO: implement C2S packet when needed + public void c2s_CmdNPCSevCrossServerGetOut() + { + // TODO: C2SCommandFactory.CreateNPCSevCrossServerGetOutCmd() and SendProtocol + } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs index 74fff564e7..26500fc7f6 100644 --- a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs @@ -9,8 +9,8 @@ namespace BrewMonster #if UNITY_EDITOR private void Update() { - // if (Input.GetKeyDown(KeyCode.S) ) - // OnSkillDragDrop(); + if (Input.GetKeyDown(KeyCode.S) ) + OnSkillDragDrop(); } #endif public void OnSkillDragDrop() diff --git a/Assets/PerfectWorld/Scripts/Utils/AFilePackage.cs b/Assets/PerfectWorld/Scripts/Utils/AFilePackage.cs index 565b9d4db1..2c4dba7a7b 100644 --- a/Assets/PerfectWorld/Scripts/Utils/AFilePackage.cs +++ b/Assets/PerfectWorld/Scripts/Utils/AFilePackage.cs @@ -35,29 +35,53 @@ namespace BrewMonster } /// - /// Compress data (raw deflate). Caller should allocate dst with size >= dstOffset + srcLen * 2 for safety. - /// 压缩数据(原始 deflate)。调用方应分配 dst 大小 >= dstOffset + srcLen * 2。 + /// Compress data in zlib format (2-byte header + deflate + 4-byte Adler-32), matching what UnCompress expects. + /// 压缩为 zlib 格式(2 字节头 + deflate + 4 字节 Adler-32),与 UnCompress 一致。 /// /// Start index in dst where compressed bytes are written. 压缩数据写入 dst 的起始下标。 /// On input max length; on output actual compressed length. 输入为最大长度,输出为实际压缩长度。 /// 0 ok, non-zero error - public static int Compress(byte[] src, int srcLen, byte[] dst, int dstOffset, ref int dstLen) + public static int Compress(byte[] src, int srcOffset, int srcLen, byte[] dst, int dstOffset, ref int dstLen) { try { - using (var output = new MemoryStream()) + // Raw deflate into temporary buffer (same as decompression uses DeflateStream) + byte[] deflateBytes; + using (var deflateOutput = new MemoryStream()) { - using (var deflate = new DeflateStream(output, CompressionLevel.Fastest)) + using (var deflate = new DeflateStream(deflateOutput, CompressionLevel.Optimal)) { - deflate.Write(src, 0, srcLen); + deflate.Write(src, srcOffset, srcLen); } - byte[] compressed = output.ToArray(); - if (dstOffset + compressed.Length > dst.Length) - return Z_BUF_ERROR; - Buffer.BlockCopy(compressed, 0, dst, dstOffset, compressed.Length); - dstLen = compressed.Length; - return Z_OK; + deflateBytes = deflateOutput.ToArray(); } + + // Zlib format: 2-byte header + deflate + 4-byte Adler-32 (matches ZlibUnCompressDeflate which skips 2, length-6) + const int zlibHeaderLen = 2; + const int zlibFooterLen = 4; + int totalLen = zlibHeaderLen + deflateBytes.Length + zlibFooterLen; + + if (dstOffset + totalLen > dst.Length) + return Z_BUF_ERROR; + + int writeAt = dstOffset; + + // 2-byte zlib header (deflate, 32K window, default compression) + dst[writeAt++] = 0x78; + dst[writeAt++] = 0x9C; + + Buffer.BlockCopy(deflateBytes, 0, dst, writeAt, deflateBytes.Length); + writeAt += deflateBytes.Length; + + // 4-byte Adler-32 of uncompressed data (big-endian) + uint adler = Adler32(src, srcOffset, srcLen); + dst[writeAt++] = (byte)(adler >> 24); + dst[writeAt++] = (byte)(adler >> 16); + dst[writeAt++] = (byte)(adler >> 8); + dst[writeAt++] = (byte)(adler); + + dstLen = totalLen; + return Z_OK; } catch (Exception e) { @@ -66,6 +90,19 @@ namespace BrewMonster } } + private static uint Adler32(byte[] data, int offset, int length) + { + const uint Mod = 65521u; + uint a = 1u, b = 0u; + for (int i = 0; i < length; i++) + { + byte c = data[offset + i]; + a = (a + c) % Mod; + b = (b + a) % Mod; + } + return (b << 16) | a; + } + private static int ZlibUnCompress(byte[] dest, ref int destLen, byte[] source, int sourceLen) { try diff --git a/Assets/Scripts/CECGameRun.cs b/Assets/Scripts/CECGameRun.cs index a954064e22..eee03286b8 100644 --- a/Assets/Scripts/CECGameRun.cs +++ b/Assets/Scripts/CECGameRun.cs @@ -329,6 +329,8 @@ public partial class CECGameRun /// True if loaded successfully / 加载成功返回true public bool LoadConfigsFromServer(byte[] pDataBuf, int iDataSize) { + BMLogger.Log($"MH CECGameRun.LoadConfigsFromServer, iDataSize = {iDataSize}"); + if (pDataBuf == null || iDataSize == 0) { BMLogger.LogError("CECGameRun::LoadConfigsFromServer, configs data is empty"); @@ -829,6 +831,7 @@ public partial class CECGameRun // pData += sizeof (DWORD); Buffer.BlockCopy(BitConverter.GetBytes(USERCFG_VERSION), 0, pDataBuf, offset, sizeof(uint)); offset += sizeof(uint); + BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after version)"); // *((int*)pData) = iHostSize; // pData += sizeof (int); @@ -836,8 +839,9 @@ public partial class CECGameRun // pData += iHostSize; Buffer.BlockCopy(BitConverter.GetBytes(iHostSize), 0, pDataBuf, offset, sizeof(int)); offset += sizeof(int); - pHost.SaveConfigData(pDataBuf, ref iHostSize, offset); + pHost.SaveConfigData(pDataBuf, ref iHostSize, offset); // TODO: converted but need to check offset += iHostSize; + BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after host config, iHostSize={iHostSize})"); // *((int*)pData) = (int)dwUISize; // pData += sizeof (int); @@ -847,6 +851,7 @@ public partial class CECGameRun offset += sizeof(int); pGameUI.GetUserLayout(pDataBuf, ref dwUISize); // TODO: Check if this is needed here offset += (int)dwUISize; + BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after UI layout, dwUISize={dwUISize})"); // *((int*)pData) = iSettingSize; // pData += sizeof (int); @@ -856,6 +861,7 @@ public partial class CECGameRun offset += sizeof(int); EC_Game.GetConfigs().SaveUserConfigData(pDataBuf, offset, out iSettingSize); offset += iSettingSize; + BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after user config, iSettingSize={iSettingSize}), iTotalSize={iTotalSize}"); // if (m_pCfgDataBuf) { // if (m_iCfgDataSize == iTotalSize && !memcmp(m_pCfgDataBuf, pDataBuf, iTotalSize)) { a_freetemp(pDataBuf); return 1; } @@ -887,10 +893,12 @@ public partial class CECGameRun // dwCompLen -= iVerLen; // int iRes = AFilePackage::Compress(pSrc, iTotalSize - iVerLen, pDst, &dwCompLen); int iVerLen = sizeof(uint); - int compLen = (iTotalSize - iVerLen) * 2; + // int compLen = (iTotalSize - iVerLen) * 2; + int compLen = iTotalSize * 2; byte[] pCompBuf = new byte[iVerLen + compLen]; + compLen -= iVerLen; Buffer.BlockCopy(pDataBuf, 0, pCompBuf, 0, iVerLen); - int iRes = AFilePackage.Compress(pDataBuf, iTotalSize - iVerLen, pCompBuf, iVerLen, ref compLen); + int iRes = AFilePackage.Compress(pDataBuf, iVerLen,iTotalSize - iVerLen, pCompBuf, iVerLen, ref compLen); // if (0 == iRes) { g_pGame->GetGameSession()->SaveConfigData(pCompBuf, dwCompLen+iVerLen); iRes = 2; } // else { a_LogOutput(1, "CECGameRun::SaveConfigsToServer, Failed to compress config data (%d:%d)", iRes, iTotalSize); iRes = 0; }