Files
test/Assets/Scripts/CECHostPlayer.ConfigData.cs
T

549 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
// C++: Host config constants (version, shortcut set counts/sizes)
public 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;
}
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;
// 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<uint>(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<int>(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;ksc<pSCS->GetShortcutNum();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;i<c;i++) pSCS->CreateSystemModuleShortcut(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<uint>(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<BoothItem>() > dataBuf.Length)
return false;
temp = GPDataTypeHelper.FromBytes<BoothItem>(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<BoothItem>();
}
}
}
// 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;
}
/// <summary>
/// Save host config (shortcut sets, etc.) to buffer. When pData is null, only outputs size in iHostSize.
/// 保存主机配置(快捷键组等)到缓冲区。pData 为 null 时仅输出 iHostSize。
/// </summary>
/// <param name="writeOffset">When pData is not null, write at this index. 写入时的起始下标。</param>
public bool SaveConfigData(byte[] pData, ref int iHostSize, int writeOffset = 0)
{
var list = new List<byte>();
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<EC_IvtrItem> m_aItems = new List<EC_IvtrItem>();
private readonly List<CECDealInventory_ITEMINFO> m_aItemInfo = new List<CECDealInventory_ITEMINFO>();
// 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<iOldSize;i++) { if (m_aItems[i] && m_aItemInfo[i].bDelete) delete m_aItems[i]; } }
if (iNewSize < iOldSize)
{
for (int i = iNewSize; i < iOldSize; i++)
{
if (GetItem(i) != null && m_aItemInfo[i].bDelete)
SetItem(i, null); // C#: release reference instead of delete
}
}
// CECInventory::Resize(iNewSize);
base.Resize(iNewSize);
// m_aItemInfo.SetSize(iNewSize, 10);
if (m_aItemInfo.Count > 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
};
}
}
}
/// <summary>C++ CECDealInventory::GetItemIndexByFlag</summary>
public int GetItemIndexByFlag(int iFlag)
{
int n = GetSize();
for (int i = 0; i < n; i++)
{
if (GetItem(i, false) != null && m_aItemInfo[i].iFlag == iFlag)
return i;
}
return -1;
}
/// <summary>C++ CECDealInventory::RemoveItemByFlag</summary>
public void RemoveItemByFlag(int iFlag, int iAmount)
{
int n = GetSize();
for (int i = 0; i < n; i++)
{
var slotItem = GetItem(i, false);
if (slotItem == null)
continue;
var info = m_aItemInfo[i];
if (info.iFlag != iFlag)
continue;
if (iAmount < 0 || iAmount >= info.iAmount)
{
SetItem(i, null);
}
else
{
info.iAmount -= iAmount;
m_aItemInfo[i] = info;
if (info.bDelete)
slotItem.AddAmount(-iAmount);
}
return;
}
}
}
// ̯ƱԶת
[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);
}
}
}