From 4df362fd16e908da41cd1da83faf71c85e5efaab Mon Sep 17 00:00:00 2001 From: MinhHai Date: Wed, 11 Feb 2026 14:54:51 +0700 Subject: [PATCH] add logic for SaveConfig, avoid Send to Server --- .../UI/DialogScriptTableObject.asset | 4 + .../Scripts/Network/CSNetwork/GameSession.cs | 7 +- .../Scripts/Objet/Shortcut/CECShortcutSet.cs | 266 ++++++++----- .../Scripts/UI/Dialogs/CDlgDragDrop.cs | 2 +- .../Scripts/UI/HUDMainGamePlay.cs | 3 +- .../Scripts/UI/Login/BtnBackToSelectRole.cs | 3 + Assets/Scripts/CECHostPlayer.ConfigData.cs | 351 +++++++++++++++++- Assets/Scripts/CECHostPlayer.cs | 103 +---- 8 files changed, 549 insertions(+), 190 deletions(-) diff --git a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset index 12feb845bb..718bcfc128 100644 --- a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset +++ b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset @@ -47,3 +47,7 @@ MonoBehaviour: prefab: {fileID: 6830833846243993097, guid: 97dd1de3aba08a04980849e40d5c1ea4, type: 3} - id: MagicProgress1 prefab: {fileID: 1126053271199039253, guid: 526d462bd8c87b74c9e461e80d028cb2, type: 3} + - id: MagicProgress1 + prefab: {fileID: 1126053271199039253, guid: 526d462bd8c87b74c9e461e80d028cb2, type: 3} + - id: Win_Message2 + prefab: {fileID: 1590197940424963217, guid: 0c248d0510a114829b58d62d2ecc3b5e, type: 3} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index e68bd4dd7a..925460e9a3 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -1501,6 +1501,8 @@ namespace CSNetwork /// public void SaveConfigData(byte[] pBuf, int len) { + BMLogger.Log($"[MH] Session SaveConfigData len={len}"); + if (pBuf == null || len <= 0) return; var p = new setuiconfig(); p.Roleid = m_iCharID; @@ -1508,6 +1510,9 @@ namespace CSNetwork byte[] slice = new byte[len]; Buffer.BlockCopy(pBuf, 0, slice, 0, len); p.Ui_config = new Octets(slice); + + // TODO: open later + return; SendProtocol(p); } @@ -1786,7 +1791,7 @@ namespace CSNetwork { gamedatasend gamedatasend = new gamedatasend(); gamedatasend.Data = C2SCommandFactory.CreateTaskNotifyCmd( pData, dwDataSize); - BMLogger.Log($"[MH Task] c2s_SendCmdTaskNotify Command ID : {pData[0]} Size: {dwDataSize}"); + //BMLogger.Log($"[MH Task] c2s_SendCmdTaskNotify Command ID : {pData[0]} Size: {dwDataSize}"); SendProtocol(gamedatasend); } diff --git a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs index b6cb6d8476..7dc6334168 100644 --- a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs +++ b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs @@ -168,21 +168,21 @@ namespace BrewMonster /// /// Create an auto fashion shortcut at specified position /// - /* public bool CreateAutoFashionShortcut(int iSlot, int iFashionIdx) - { - CECSCAutoFashion pAutoFashionSC = new CECSCAutoFashion(); - if (pAutoFashionSC == null) - return false; - - if (!pAutoFashionSC.Init(iFashionIdx)) - { - Debug.LogError("CECShortcutSet::CreateAutoFashionShortcut, Failed to initialize auto fashion shortcut"); - return false; - } - - SetShortcut(iSlot, pAutoFashionSC); - return true; - } + // public bool CreateAutoFashionShortcut(int iSlot, int iFashionIdx) + // { + // CECSCAutoFashion pAutoFashionSC = new CECSCAutoFashion(); + // if (pAutoFashionSC == null) + // return false; + // + // if (!pAutoFashionSC.Init(iFashionIdx)) + // { + // Debug.LogError("CECShortcutSet::CreateAutoFashionShortcut, Failed to initialize auto fashion shortcut"); + // return false; + // } + // + // SetShortcut(iSlot, pAutoFashionSC); + // return true; + // } /// /// Create a system module shortcut at specified position @@ -201,7 +201,7 @@ namespace BrewMonster SetShortcut(iSlot, pSysModule); return true; - }*/ + } /// /// Duplicate a shortcut to specified position @@ -495,6 +495,8 @@ namespace BrewMonster // Record shortcut's position and type data.AddRange(BitConverter.GetBytes(i)); data.AddRange(BitConverter.GetBytes((int)pSC.GetType())); + + BMLogger.Log($"[MH] Saving shortcut slot: {i} Type: {pSC.GetType()}"); // TODO: implement other shortcut types switch ((CECShortcut.ShortcutType)pSC.GetType()) @@ -514,42 +516,42 @@ namespace BrewMonster break; } - /* case CECShortcut.ShortcutType.SCT_ITEM: - { - CECSCItem itemSC = (CECSCItem)pSC; - data.AddRange(BitConverter.GetBytes(itemSC.GetInventory())); - data.AddRange(BitConverter.GetBytes(itemSC.GetIvtrSlot())); - data.AddRange(BitConverter.GetBytes(itemSC.GetItemTID())); - break; - } + // case CECShortcut.ShortcutType.SCT_ITEM: + // { + // CECSCItem itemSC = (CECSCItem)pSC; + // data.AddRange(BitConverter.GetBytes(itemSC.GetInventory())); + // data.AddRange(BitConverter.GetBytes(itemSC.GetIvtrSlot())); + // data.AddRange(BitConverter.GetBytes(itemSC.GetItemTID())); + // break; + // } - case CECShortcut.ShortcutType.SCT_SKILLGRP: - { - CECSCSkillGrp skillGrpSC = (CECSCSkillGrp)pSC; - data.AddRange(BitConverter.GetBytes(skillGrpSC.GetGroupIndex())); - break; - } + case CECShortcut.ShortcutType.SCT_SKILLGRP: + { + CECSCSkillGrp skillGrpSC = (CECSCSkillGrp)pSC; + data.AddRange(BitConverter.GetBytes(skillGrpSC.GetGroupIndex())); + break; + } - case CECShortcut.ShortcutType.SCT_PET: - { - CECSCPet petSC = (CECSCPet)pSC; - data.AddRange(BitConverter.GetBytes(petSC.GetPetIndex())); - break; - } + // case CECShortcut.ShortcutType.SCT_PET: + // { + // CECSCPet petSC = (CECSCPet)pSC; + // data.AddRange(BitConverter.GetBytes(petSC.GetPetIndex())); + // break; + // } + // + // case CECShortcut.ShortcutType.SCT_AUTOFASHION: + // { + // CECSCAutoFashion fashionSC = (CECSCAutoFashion)pSC; + // data.AddRange(BitConverter.GetBytes(fashionSC.GetAutoFashionIndex())); + // break; + // } - case CECShortcut.ShortcutType.SCT_AUTOFASHION: - { - CECSCAutoFashion fashionSC = (CECSCAutoFashion)pSC; - data.AddRange(BitConverter.GetBytes(fashionSC.GetAutoFashionIndex())); - break; - } - - case CECShortcut.ShortcutType.SCT_SYSMODULE: - { - CECSCSysModule sysSC = (CECSCSysModule)pSC; - data.AddRange(BitConverter.GetBytes(sysSC.GetSysModID())); - break; - }*/ + case CECShortcut.ShortcutType.SCT_SYSMODULE: + { + CECSCSysModule sysSC = (CECSCSysModule)pSC; + data.AddRange(BitConverter.GetBytes(sysSC.GetSysModID())); + break; + } default: Debug.LogError($"CECShortcutSet::SaveConfigData - Unknown shortcut type = { pSC.GetType()}"); @@ -588,6 +590,8 @@ namespace BrewMonster int iSCType = GPDataTypeHelper.FromBytes(pDataBuf, offset); offset += sizeof(int); + + BMLogger.Log("[MH] Loading shortcut slot: " + iSlot + " Type: " + iSCType); switch ((CECShortcut.ShortcutType)iSCType) { @@ -680,41 +684,41 @@ namespace BrewMonster break; } - /*case CECShortcut.ShortcutType.SCT_PET: - { - if (dwVer >= 4) - { - int iPetIndex = BitConverter.ToInt32(pDataBuf, offset); - offset += sizeof(int); - - if (iPetIndex >= 0) - CreatePetShortcut(iSlot, iPetIndex); - } - else - { - Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet"); - return false; - } - break; - } - - case CECShortcut.ShortcutType.SCT_AUTOFASHION: - { - if (dwVer >= 5) - { - int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset); - offset += sizeof(int); - - if (iAutoFashionIndex >= 0) - CreateAutoFashionShortcut(iSlot, iAutoFashionIndex); - } - else - { - Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion"); - return false; - } - break; - } + // case CECShortcut.ShortcutType.SCT_PET: + // { + // if (dwVer >= 4) + // { + // int iPetIndex = BitConverter.ToInt32(pDataBuf, offset); + // offset += sizeof(int); + // + // if (iPetIndex >= 0) + // CreatePetShortcut(iSlot, iPetIndex); + // } + // else + // { + // Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet"); + // return false; + // } + // break; + // } + // + // case CECShortcut.ShortcutType.SCT_AUTOFASHION: + // { + // if (dwVer >= 5) + // { + // int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset); + // offset += sizeof(int); + // + // if (iAutoFashionIndex >= 0) + // CreateAutoFashionShortcut(iSlot, iAutoFashionIndex); + // } + // else + // { + // Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion"); + // return false; + // } + // break; + // } case CECShortcut.ShortcutType.SCT_SYSMODULE: { @@ -732,7 +736,7 @@ namespace BrewMonster return false; } break; - }*/ + } /* default: //TODO: uncomment @@ -1168,6 +1172,98 @@ namespace BrewMonster { public CECSkill GetSkillByID(int id) => null; }*/ + + // class CECSCSysModule : public CECShortcut + public class CECSCSysModule : CECShortcut + { + // public: // Types + // enum { FM_NONE = -1, FM_GT, FM_TOUCH, ... FM_NUM, }; + public enum SysModuleType + { + FM_NONE = -1, + FM_GT, + FM_TOUCH, + FM_ROBOT, // 帮派系统 (Faction / Guild system) + FM_WIKI, + FM_OFFLINESHOP, // 摆摊 (Offline shop / Stall) + FM_BORADCAST, // 广播系统 (Broadcast system) + FM_MATCH, // 边缘系统 (Match system) + FM_ADDEXP, // 帮会系统 (Guild / Add exp system) + FM_AUTOHPMP, // 辅助功能,自动加药 (Auxiliary function, auto potion) + + FM_NUM, + } + + // public: // Attributes + // static const int g_SysIndexMap[FM_NUM]; + public static readonly int[] g_SysIndexMap = new int[(int)SysModuleType.FM_NUM]; + + // protected: // Attributes + // ACString m_strDesc; + protected string m_strDesc; + // char m_IconFile[256]; + protected string m_IconFile; + // int m_iSystem; // system ID + protected int m_iSystem; + + // public: // Constructor and Destructor + // CECSCSysModule(); + public CECSCSysModule() + { + m_iSCType = (int)ShortcutType.SCT_SYSMODULE; + m_strDesc = string.Empty; + m_IconFile = string.Empty; + m_iSystem = (int)SysModuleType.FM_NONE; + } + + // CECSCSysModule(const CECSCSysModule& src); + public CECSCSysModule(CECSCSysModule src) + { + m_iSCType = src.m_iSCType; + m_strDesc = src.m_strDesc; + m_IconFile = src.m_IconFile; + m_iSystem = src.m_iSystem; + } + + // virtual ~CECSCSysModule() {} + // (no destructor in C#) + + // bool Init(int iSys); + public bool Init(int iSys) + { + m_iSystem = iSys; + // TODO: load m_strDesc and m_IconFile from config/table by iSys if needed + return true; + } + + // virtual CECShortcut* Clone(); + public override CECShortcut Clone() + { + return new CECSCSysModule(this); + } + + // virtual bool Execute(); + public override bool Execute() + { + // TODO: open corresponding system UI by m_iSystem (e.g. GT, Touch, Robot, Wiki, OfflineShop, Broadcast, Match, AddExp, AutoHpMp) + return true; + } + + // int GetSysModID() const { return m_iSystem; } + public int GetSysModID() { return m_iSystem; } + + // virtual const wchar_t* GetDesc(); + public override string GetDesc() + { + return m_strDesc ?? string.Empty; + } + + public override string GetIconFile() + { + return string.IsNullOrEmpty(m_IconFile) ? "unknown" : m_IconFile; + } + } + #endregion } diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs index 53dec1542c..358cd7d447 100644 --- a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs @@ -15,7 +15,7 @@ namespace BrewMonster #endif public void OnSkillDragDrop() { - var iSlot = 2; + var iSlot = 1; var nCombo = 2; CECShortcutSet pSCS = CECUIManager.Instance.GetInGameUIMan().GetSCSByDlg(1); if (pSCS.GetShortcut(iSlot - 1) == null || !EC_Game.GetConfigs().GetGameSettings().bLockQuickBar) diff --git a/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs b/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs index 0fa39db4d8..f3e481228d 100644 --- a/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs +++ b/Assets/PerfectWorld/Scripts/UI/HUDMainGamePlay.cs @@ -26,7 +26,8 @@ namespace BrewMonster private void OnEscapeClicked() { // Open the exit dialog , not directly exit the game - return; + + // return; if(EC_Game.GetGameRun()?.GetHostPlayer() != null) { EC_Game.GetGameRun()?.GetHostPlayer().OnClickBtnEscape(); diff --git a/Assets/PerfectWorld/Scripts/UI/Login/BtnBackToSelectRole.cs b/Assets/PerfectWorld/Scripts/UI/Login/BtnBackToSelectRole.cs index 59d081a721..8468a0a5e7 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/BtnBackToSelectRole.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/BtnBackToSelectRole.cs @@ -10,6 +10,9 @@ namespace BrewMonster.UI { public void OnClick() { + CECUIManager.Instance.ShowUI( "Win_Message2" ); + + return; UnityGameSession.ReturnToSelectRole(); } } diff --git a/Assets/Scripts/CECHostPlayer.ConfigData.cs b/Assets/Scripts/CECHostPlayer.ConfigData.cs index 3b4e7113dc..5a2566acf1 100644 --- a/Assets/Scripts/CECHostPlayer.ConfigData.cs +++ b/Assets/Scripts/CECHostPlayer.ConfigData.cs @@ -1,7 +1,352 @@ +using BrewMonster.Assets.PerfectWorld.Scripts.UI; +using BrewMonster.Scripts.Managers; +using CSNetwork.GPDataType; +using PerfectWorld.Scripts; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using BrewMonster.Scripts; + namespace BrewMonster { - public class CECHostPlayer_ConfigData + public partial class CECHostPlayer { - + // Shortcut sets (converted from C++: m_aSCSets1[NUM_HOSTSCSETS1], m_aSCSets2[NUM_HOSTSCSETS2], m_aSCSetSysMod[NUM_SYSMODSETS]) + public CECShortcutSet[] m_aSCSets1 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS1]; // SC set 1 + public CECShortcutSet[] m_aSCSets2 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS2]; // SC set 2 + + public CECShortcutSet[] + m_aSCSetSysMod = new CECShortcutSet[HostCfgConstants.NUM_SYSMODSETS]; // System module shortcut sets + + public int[] + m_aFashionSCSets = new int[HostCfgConstants.SIZE_FASHIONSCSET]; // Auto fashion shortcut sets (indices) + + // C++: CECDealInventory* m_pBoothBPack / m_pBoothSPack – booth buy pack and sell pack + private CECDealInventory m_pBoothBPack = null; // 摆摊收购包 Booth buy pack + private CECDealInventory m_pBoothSPack = null; // 摆摊出售包 Booth sell pack + + // C++: Host config constants (version, shortcut set counts/sizes) + private static class HostCfgConstants + { + public const int HOSTCFG_VERSION = 11; + public const int NUM_HOSTSCSETS1 = 5; // expanded from 3 to 5 (2009.05.27) + public const int NUM_HOSTSCSETS2 = 3; + public const int SIZE_HOSTSCSET1 = 9; // expanded from 6 to 9 (2009.05.27) + public const int SIZE_HOSTSCSET2 = 8; + public const int NUM_SYSMODSETS = 4; // System module shortcut sets count + public const int SIZE_SYSMODSCSET = 4; // System module shortcut set size (first 4 slots) + public const int SIZE_FASHIONSCSET = 240; + } + + // Load configs data (shortcut, etc.) from specified buffer + // Converted from: bool CECHostPlayer::LoadConfigData(const void* pDataBuf) + public bool LoadConfigData(byte[] dataBuf) + { + if (dataBuf == null || dataBuf.Length < sizeof(uint)) + return false; + + int offset = 0; + + // Version number + uint dwVer = GPDataTypeHelper.FromBytes(dataBuf, offset); + offset += sizeof(uint); + if (dwVer > HostCfgConstants.HOSTCFG_VERSION) + { + return false; + } + + // Load shortcut configs... + int iHostSCSets1 = (dwVer <= 4) ? 3 : HostCfgConstants.NUM_HOSTSCSETS1; + + for (int i = 0; i < iHostSCSets1; i++) + { + if (offset >= dataBuf.Length) + return false; + + if (m_aSCSets1[i] == null) + { + m_aSCSets1[i] = new CECShortcutSet(); + m_aSCSets1[i].Init(HostCfgConstants.SIZE_HOSTSCSET1); + } + + if (!m_aSCSets1[i].LoadConfigData(dataBuf, dwVer, ref offset)) + return false; + } + + for (int i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) + { + if (offset >= dataBuf.Length) + break; // No more data; tolerate truncated optional parts + + if (m_aSCSets2[i] == null) + { + m_aSCSets2[i] = new CECShortcutSet(); + m_aSCSets2[i].Init(HostCfgConstants.SIZE_HOSTSCSET2); + } + + if (!m_aSCSets2[i].LoadConfigData(dataBuf, dwVer, ref offset)) + return false; + } + + // Load auto fashion shortcut sets + // Load auto fashion shortcut sets + // if(dwVer > 5) + if (dwVer > 5) + { + // int size = 0; + // if (dwVer == 6) size = 120; else size = HostCfgConstants.SIZE_FASHIONSCSET; + int size = (dwVer == 6) ? 120 : HostCfgConstants.SIZE_FASHIONSCSET; + // for (i=0; i < size; i++) + for (int i = 0; i < size; i++) + { + // if (dwVer <= 8 && (i % 6 == 5)) continue; + if (dwVer <= 8 && (i % 6 == 5)) continue; + // m_aFashionSCSets[i] = *((int*)pData); pData += sizeof(int); + if (offset + sizeof(int) > dataBuf.Length) return false; + m_aFashionSCSets[i] = GPDataTypeHelper.FromBytes(dataBuf, offset); + offset += sizeof(int); + } + } + + // Load system module shortcut sets + // Load system module shortcut sets + // if(dwVer > 10) + if (dwVer > 10) + { + // for (i=0; i < NUM_SYSMODSETS; i++) + for (int iSysMod = 0; iSysMod < HostCfgConstants.NUM_SYSMODSETS; iSysMod++) + { + // (C#: bounds check; C++ advances pData so no separate check) + if (offset >= dataBuf.Length) + return false; + + // (C#: lazy init; C++ assumes array already allocated) + if (m_aSCSetSysMod[iSysMod] == null) + { + m_aSCSetSysMod[iSysMod] = new CECShortcutSet(); + m_aSCSetSysMod[iSysMod].Init(HostCfgConstants.SIZE_SYSMODSCSET); + } + + // int iSize; + // if (!m_aSCSetSysMod[i]->LoadConfigData(pData, &iSize, dwVer)) return false; + if (!m_aSCSetSysMod[iSysMod].LoadConfigData(dataBuf, dwVer, ref offset)) + return false; + + // if (i==0) // 如果第一个4个位置均为空,则初始化默认快捷键 | If the first 4 slots are all empty, init default shortcuts + if (iSysMod == 0) + { + // CECShortcutSet *pSCS = m_aSCSetSysMod[0]; + CECShortcutSet pSCS = m_aSCSetSysMod[0]; + // int ksc = 0; + // for (ksc = 0;kscGetShortcutNum();ksc++) { if (pSCS->GetShortcut(ksc)) break; } + int ksc; + for (ksc = 0; ksc < pSCS.GetShortcutNum(); ksc++) + { + if (pSCS.GetShortcut(ksc) != null) + break; + } + + // if (ksc == pSCS->GetShortcutNum()) + if (ksc == pSCS.GetShortcutNum()) + { + // int c = CECUIConfig::Instance().GetGameUI().nDefaultSystemModuleIndex.size(); + // c = min(c,4); + var defaultList = CECUIConfig.Instance.GetGameUI().nDefaultSystemModuleIndex; + int c = (defaultList != null) ? defaultList.Count : 0; + c = Math.Min(c, 4); + // for (int i=0;iCreateSystemModuleShortcut(i, CECUIConfig::Instance().GetGameUI().nDefaultSystemModuleIndex[i]); + for (int j = 0; j < c; j++) + pSCS.CreateSystemModuleShortcut(j, defaultList[j]); + } + } + // pData += iSize; (C#: offset updated by LoadConfigData ref) + } + } + + // Notes: + // - Auto fashion sets, system module shortcut sets, booth packs, and AutoYinpiao + // sections from native are not loaded here in this Unity port yet. + // The native format appends these after the two shortcut-set groups. + // We intentionally ignore them safely for now. + + return true; + } + + /// + /// Save host config (shortcut sets, etc.) to buffer. When pData is null, only outputs size in iHostSize. + /// 保存主机配置(快捷键组等)到缓冲区。pData 为 null 时仅输出 iHostSize。 + /// + /// When pData is not null, write at this index. 写入时的起始下标。 + public bool SaveConfigData(byte[] pData, ref int iHostSize, int writeOffset = 0) + { + var list = new List(); + list.AddRange(BitConverter.GetBytes(HostCfgConstants.HOSTCFG_VERSION)); + for (int i = 0; i < m_aSCSets1.Length; i++) + { + if (m_aSCSets1[i] == null || !m_aSCSets1[i].SaveConfigData(out byte[] buf)) + continue; + list.AddRange(buf); + } + + for (int i = 0; i < m_aSCSets2.Length; i++) + { + if (m_aSCSets2[i] == null || !m_aSCSets2[i].SaveConfigData(out byte[] buf)) + continue; + list.AddRange(buf); + } + + // Save auto fashion shortcut sets | 保存自动时装快捷键组 + // if(pDataBuf) + // { + // for (i=0; i < SIZE_FASHIONSCSET; i++) + // { + // *((int*)pData) = m_aFashionSCSets[i]; + // if(pData) + // pData += sizeof (int); + // } + // } + // iTotalSize += sizeof(int) * SIZE_FASHIONSCSET; + for (int i = 0; i < HostCfgConstants.SIZE_FASHIONSCSET; i++) + { + list.AddRange(BitConverter.GetBytes(m_aFashionSCSets[i])); + } + + // Save system module shortcut sets | 保存系统模块快捷键组 + // for (i=0; i < NUM_SYSMODSETS; i++) + // { + // m_aSCSetSysMod[i]->SaveConfigData(pData, &iSize); + // iTotalSize += iSize; + // if (pData) + // pData += iSize; + // } + for (int i = 0; i < HostCfgConstants.NUM_SYSMODSETS; i++) + { + if (m_aSCSetSysMod[i] == null || !m_aSCSetSysMod[i].SaveConfigData(out byte[] buf)) + continue; + list.AddRange(buf); + } + + // Save Booth Buy and Sell Pack + // 保存摆摊收购包与出售包 + // CECDealInventory *pBoothPacks[2] = {GetBoothBuyPack(), GetBoothSellPack()}; + CECDealInventory[] pBoothPacks = new CECDealInventory[] { GetBoothBuyPack(), GetBoothSellPack() }; + // for (int k=0 ; k < sizeof(pBoothPacks)/sizeof(pBoothPacks[0]); ++k) + for (int k = 0; k < pBoothPacks.Length; ++k) + { + // CECDealInventory *pBoothPack = pBoothPacks[k]; + CECDealInventory pBoothPack = pBoothPacks[k]; + // bool isBuyPack = (pBoothPack == GetBoothBuyPack()); + bool isBuyPack = (pBoothPack == GetBoothBuyPack()); + // DWORD dwSize = pBoothPack->GetSize(); + uint dwSize = (uint)(pBoothPack != null ? pBoothPack.GetSize() : 0); + // if (pData) { *((DWORD *)pData) = dwSize; pData += sizeof(DWORD); + list.AddRange(BitConverter.GetBytes(dwSize)); + // + // BoothItem temp; for (DWORD i = 0; i < dwSize; ++ i) + if (pBoothPack != null) + { + for (uint i = 0; i < dwSize; ++i) + { + // ::ZeroMemory(&temp, sizeof(temp)); + BoothItem temp = default; + // const CECDealInventory::ITEMINFO &ii = pBoothPack->GetItemInfo(i); + CECDealInventory_ITEMINFO ii = pBoothPack.GetItemInfo((int)i); + // CECIvtrItem* pItem1 = pBoothPack->GetItem(i); + EC_IvtrItem pItem1 = pBoothPack.GetItem((int)i); + // if (pItem1) { CECIvtrItem* pItem2 = m_pPack->GetItem(ii.iOrigin); + if (pItem1 != null) + { + // CECIvtrItem* pItem2 = m_pPack->GetItem(ii.iOrigin); + EC_IvtrItem pItem2 = m_pPack.GetItem(ii.iOrigin, false); + // if (pItem2 && pItem2->GetTemplateID() == pItem1->GetTemplateID()) + if (pItem2 != null && pItem2.GetTemplateID() == pItem1.GetTemplateID()) + { + // temp.idItem = pItem1->GetTemplateID(); temp.iOrigin = ii.iOrigin; + temp.idItem = (uint)pItem1.GetTemplateID(); + temp.iOrigin = (uint)ii.iOrigin; + // temp.iUnitPrice = pItem1->GetUnitPrice(); + temp.iUnitPrice = (uint)pItem1.GetUnitPrice(); + // temp.iAmount = isBuyPack ? ii.iAmount : a_Min(ii.iAmount, pItem2->GetCount()); + temp.iAmount = isBuyPack + ? (uint)ii.iAmount + : (uint)Math.Min(ii.iAmount, pItem2.GetCount()); + } + } + + // + // *((BoothItem *)pData) = temp; pData += sizeof(temp); + list.AddRange(BitConverter.GetBytes(temp.idItem)); + list.AddRange(BitConverter.GetBytes(temp.iOrigin)); + list.AddRange(BitConverter.GetBytes(temp.iAmount)); + list.AddRange(BitConverter.GetBytes(temp.iUnitPrice)); + } + } + // } iTotalSize += sizeof(DWORD) + dwSize * sizeof(BoothItem); + } + + iHostSize = list.Count; + if (pData != null && writeOffset >= 0 && writeOffset + iHostSize <= pData.Length) + Buffer.BlockCopy(list.ToArray(), 0, pData, writeOffset, iHostSize); + return true; + } + + // C++: GetBoothBuyPack() / GetBoothSellPack() + // 获取摆摊收购包 / 摆摊出售包 + public CECDealInventory GetBoothBuyPack() => m_pBoothBPack; + public CECDealInventory GetBoothSellPack() => m_pBoothSPack; + + bool CreateInventories() + { + + // only use to init the booth inventories + if (m_pBoothBPack == null) + { + m_pBoothBPack = new CECDealInventory(); + m_pBoothBPack.Init(InventoryConst.IVTRSIZE_BOOTHBPACK); + } + + if (m_pBoothSPack == null) + { + m_pBoothSPack = new CECDealInventory(); + m_pBoothSPack.Init(InventoryConst.IVTRSIZE_BOOTHSPACK); + } + + return true; + } } -} \ No newline at end of file + + // C++: struct BoothItem (save format for booth buy/sell pack item) + // 摆摊买卖包单项保存结构 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BoothItem + { + public uint idItem; + public uint iOrigin; + public uint iAmount; + public uint iUnitPrice; + } + + // C++: CECDealInventory::ITEMINFO (EC_DealInventory.h) + // 物品附加信息 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct CECDealInventory_ITEMINFO + { + public int iOrigin; // 原始位置 Original position in player's normal pack + public int iAmount; // 数量 Amount + [MarshalAs(UnmanagedType.Bool)] + public bool bDelete; // true 时物品对象可释放 true, item object can be released + public int iFlag; // 物品标志 Item flag + } + + // C++: CECDealInventory (EC_DealInventory.h / EC_DealInventory.cpp) – minimal view for SaveConfigData + // 交易/摆摊背包,仅提供保存配置所需的接口 + public class CECDealInventory : EC_Inventory + { + private readonly List m_aItems = new List(); + private readonly List m_aItemInfo = new List(); + + public int GetSize() => m_aItems.Count; + public CECDealInventory_ITEMINFO GetItemInfo(int n) => m_aItemInfo[n]; + public EC_IvtrItem GetItem(int i) => (i >= 0 && i < m_aItems.Count) ? m_aItems[i] : null; + } +} diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 1380515bb1..7118172ef7 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -55,10 +55,8 @@ namespace BrewMonster private int m_iMoveEnv; public A3DVECTOR3 m_vVelocity; // Velocity - - // Shortcut sets (converted from C++: m_aSCSets1[NUM_HOSTSCSETS1], m_aSCSets2[NUM_HOSTSCSETS2]) - public CECShortcutSet[] m_aSCSets1 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS1]; // SC set 1 - public CECShortcutSet[] m_aSCSets2 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS2]; // SC set 2 + + bool m_bChangingFace; // true, host is changing face private int m_iRoleCreateTime; private int m_iRoleLastLoginTime; // Role last login time @@ -297,15 +295,6 @@ namespace BrewMonster } } - private static class HostCfgConstants - { - public const int HOSTCFG_VERSION = 11; - public const int NUM_HOSTSCSETS1 = 5; // expanded from 3 to 5 (2009.05.27) - public const int NUM_HOSTSCSETS2 = 3; - public const int SIZE_HOSTSCSET1 = 9; // expanded from 6 to 9 (2009.05.27) - public const int SIZE_HOSTSCSET2 = 8; - } - private void Awake() { base.Awake(); @@ -330,6 +319,8 @@ namespace BrewMonster m_GatherCnt.Reset(true); m_PetOptCnt.SetPeriod(1000); m_PetOptCnt.Reset(true); + + CreateInventories(); } public bool LoadResources() @@ -3460,92 +3451,6 @@ namespace BrewMonster return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } - // Load configs data (shortcut, etc.) from specified buffer - // Converted from: bool CECHostPlayer::LoadConfigData(const void* pDataBuf) - public bool LoadConfigData(byte[] dataBuf) - { - if (dataBuf == null || dataBuf.Length < sizeof(uint)) - return false; - - int offset = 0; - - // Version number - uint dwVer = GPDataTypeHelper.FromBytes(dataBuf, offset); - offset += sizeof(uint); - if (dwVer > HostCfgConstants.HOSTCFG_VERSION) - { - return false; - } - - // Load shortcut configs... - int iHostSCSets1 = (dwVer <= 4) ? 3 : HostCfgConstants.NUM_HOSTSCSETS1; - - for (int i = 0; i < iHostSCSets1; i++) - { - if (offset >= dataBuf.Length) - return false; - - if (m_aSCSets1[i] == null) - { - m_aSCSets1[i] = new CECShortcutSet(); - m_aSCSets1[i].Init(HostCfgConstants.SIZE_HOSTSCSET1); - } - - if (!m_aSCSets1[i].LoadConfigData(dataBuf, dwVer, ref offset)) - return false; - } - - for (int i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) - { - if (offset >= dataBuf.Length) - break; // No more data; tolerate truncated optional parts - - if (m_aSCSets2[i] == null) - { - m_aSCSets2[i] = new CECShortcutSet(); - m_aSCSets2[i].Init(HostCfgConstants.SIZE_HOSTSCSET2); - } - - if (!m_aSCSets2[i].LoadConfigData(dataBuf, dwVer, ref offset)) - return false; - } - - // Notes: - // - Auto fashion sets, system module shortcut sets, booth packs, and AutoYinpiao - // sections from native are not loaded here in this Unity port yet. - // The native format appends these after the two shortcut-set groups. - // We intentionally ignore them safely for now. - - return true; - } - - /// - /// Save host config (shortcut sets, etc.) to buffer. When pData is null, only outputs size in iHostSize. - /// 保存主机配置(快捷键组等)到缓冲区。pData 为 null 时仅输出 iHostSize。 - /// - /// When pData is not null, write at this index. 写入时的起始下标。 - public bool SaveConfigData(byte[] pData, ref int iHostSize, int writeOffset = 0) - { - var list = new List(); - list.AddRange(BitConverter.GetBytes(HostCfgConstants.HOSTCFG_VERSION)); - for (int i = 0; i < m_aSCSets1.Length; i++) - { - if (m_aSCSets1[i] == null || !m_aSCSets1[i].SaveConfigData(out byte[] buf)) - continue; - list.AddRange(buf); - } - for (int i = 0; i < m_aSCSets2.Length; i++) - { - if (m_aSCSets2[i] == null || !m_aSCSets2[i].SaveConfigData(out byte[] buf)) - continue; - list.AddRange(buf); - } - iHostSize = list.Count; - if (pData != null && writeOffset >= 0 && writeOffset + iHostSize <= pData.Length) - Buffer.BlockCopy(list.ToArray(), 0, pData, writeOffset, iHostSize); - return true; - } - public int GetCharacterID() { return m_PlayerInfo.cid;