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 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 BOOTH_AUTO_YINPIAO m_AutoYinpiao; // 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) } } // Load Saved Booth Buy and Sell Pack // 加载保存的摆摊收购包与出售包 // if (dwVer > 7) { struct BoothItem { ... }; BoothItem temp; const int nPacks = 2; ... if (dwVer > 7) { // BoothItem temp; BoothItem temp; // const int nPacks = 2; const int nPacks = 2; // CECDealInventory *pBoothPacks[nPacks] = {GetBoothBuyPack(), GetBoothSellPack()}; CECDealInventory[] pBoothPacks = new CECDealInventory[] { GetBoothBuyPack(), GetBoothSellPack() }; // DWORD nMaxBoothPacks[nPacks] = {IVTRSIZE_BOOTHBPACK_MAX, IVTRSIZE_BOOTHSPACK_MAX}; uint[] nMaxBoothPacks = new uint[] { InventoryConst.IVTRSIZE_BOOTHBPACK_MAX, InventoryConst.IVTRSIZE_BOOTHSPACK_MAX }; // for (int k=0 ; k < nPacks; ++k) for (int k = 0; k < nPacks; ++k) { // CECDealInventory *pBoothPack = pBoothPacks[k]; CECDealInventory pBoothPack = pBoothPacks[k]; // bool isBuyPack = (pBoothPack == GetBoothBuyPack()); bool isBuyPack = (pBoothPack == GetBoothBuyPack()); // DWORD dwCurSize = pBoothPack->GetSize(); int dwCurSize = (pBoothPack != null) ? pBoothPack.GetSize() : 0; // DWORD dwSize = *((DWORD *)pData); pData += sizeof(dwSize); if (offset + sizeof(uint) > dataBuf.Length) return false; uint dwSize = GPDataTypeHelper.FromBytes(dataBuf, offset); offset += sizeof(uint); // ��֤���ݣ��г��������� // 验证数据,防止越界读取 | Verify data, prevent out-of-bounds read if (dwSize > nMaxBoothPacks[k]) { UnityEngine.Debug.LogWarningFormat("CECHostPlayer::LoadConfigData, Failed because pack {0} size invalid ({1}:{2}).", k, dwSize, nMaxBoothPacks[k]); return false; } for (uint i = 0; i < dwSize; ++i) { // ����İ�����С�ܿ����뵱ǰ������С��ͬ���Ե�ǰ������СΪ׼ // 保存的包大小可能和当前背包大小不同,以当前背包大小为准 | Saved pack size may differ from current; use current as reference if (i < (uint)dwCurSize) { if (offset + Marshal.SizeOf() > dataBuf.Length) return false; temp = GPDataTypeHelper.FromBytes(dataBuf, offset); // ��֤��ȡ���ݵĺϷ��� if (temp.idItem > 0 && temp.iAmount > 0 && temp.iUnitPrice >= 0 && temp.iOrigin >= 0) { EC_IvtrItem pItem2 = m_pPack.GetItem((int)temp.iOrigin, false); if (pItem2 != null && pItem2.GetTemplateID() == (int)temp.idItem) { // ��Ʒ�ڵ�ǰ�����鵽������ȷ����ԭ��Ʒͬ����Ʒ int iAmount = isBuyPack ? (int)temp.iAmount : EC_Utility.a_Min((int)temp.iAmount, pItem2.GetCount()); if (pBoothPack != null) pBoothPack.AddBoothItem(pItem2, (int)temp.iOrigin, iAmount, (int)temp.iUnitPrice); } } } offset += Marshal.SizeOf(); } } } // 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); } // ��Ʊ�Զ�ת�� list.AddRange( BitConverter.GetBytes(m_AutoYinpiao.low_money) ); list.AddRange( BitConverter.GetBytes(m_AutoYinpiao.high_money) ); 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; } } // 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; // C++: AddBoothItem(pItem, iOrigin, iAmount, iUnitPrice) – add item to booth pack with origin/amount/price public void AddBoothItem(EC_IvtrItem pItem, int iOrigin, int iAmount, int iUnitPrice) { int slot = SearchEmpty(); if (slot < 0) return; while (m_aItemInfo.Count <= slot) m_aItemInfo.Add(default); m_aItemInfo[slot] = new CECDealInventory_ITEMINFO { iOrigin = iOrigin, iAmount = iAmount, bDelete = false, iFlag = 0 }; SetItem(slot, pItem); if (pItem != null) pItem.SetUnitPrice(iUnitPrice); } // Resize inventory // C++: void CECDealInventory::Resize(int iNewSize) public override void Resize(int iNewSize) { // int iOldSize = m_aItemInfo.GetSize(); int iOldSize = m_aItemInfo.Count; // if(iNewSize < iOldSize) { for(int i=iNewSize;i iNewSize) m_aItemInfo.RemoveRange(iNewSize, m_aItemInfo.Count - iNewSize); while (m_aItemInfo.Count < iNewSize) m_aItemInfo.Add(default); // if(iOldSize < iNewSize) { /* Clear new slots */ for (int i=iOldSize; i < iNewSize; i++) { m_aItemInfo[i].iOrigin = 0; ... } } if (iOldSize < iNewSize) { // Clear new slots for (int i = iOldSize; i < iNewSize; i++) { m_aItemInfo[i] = new CECDealInventory_ITEMINFO { iOrigin = 0, iAmount = 0, bDelete = false, iFlag = 0 }; } } } } // ��̯��Ʊ�Զ�ת�� [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BOOTH_AUTO_YINPIAO { public bool open; public CECCounter cnt; public int low_money; public int high_money; // C++: BOOTH_AUTO_YINPIAO() : open(false), low_money(50000000), high_money(100000000) { cnt.SetPeriod(60000); cnt.Reset(true); } public BOOTH_AUTO_YINPIAO(int i=0) { open = false; low_money = 50000000; high_money = 100000000; cnt = new CECCounter(); cnt.SetPeriod(60000); cnt.Reset(true); } } }