Update EC_Invtr
This commit is contained in:
@@ -61,5 +61,10 @@ namespace BrewMonster.Scripts
|
||||
public const int IVTRSIZE_CLIENTCARDPACK = 32; // Client pack for general card collection
|
||||
|
||||
public const int NUM_NPCIVTR = 8; // NPC inventory number
|
||||
|
||||
// Inventory package types (match legacy C++ IVTRTYPE_*)
|
||||
public const byte IVTRTYPE_PACK = 0;
|
||||
public const byte IVTRTYPE_EQUIPPACK = 1;
|
||||
public const byte IVTRTYPE_TASKPACK = 2;
|
||||
}
|
||||
}
|
||||
@@ -1,798 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts.Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// C# mirror of C++ CECInventory (EC_Inventory.h / EC_Inventory.cpp).
|
||||
/// This is an instance-based inventory using a fixed-size item array.
|
||||
/// </summary>
|
||||
public class CECInventory
|
||||
{
|
||||
// Item array: index is slot, null means empty.
|
||||
private EC_IvtrItem[] m_aItems = Array.Empty<EC_IvtrItem>();
|
||||
|
||||
public CECInventory()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Init(int iSize)
|
||||
{
|
||||
Resize(iSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
// In C++ this deletes all heap-allocated items.
|
||||
// Here we simply clear references so GC can collect them.
|
||||
RemoveAllItems();
|
||||
m_aItems = Array.Empty<EC_IvtrItem>();
|
||||
}
|
||||
|
||||
public void RemoveAllItems()
|
||||
{
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
m_aItems[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(int iNewSize)
|
||||
{
|
||||
int oldSize = m_aItems.Length;
|
||||
if (iNewSize < 0) iNewSize = 0;
|
||||
|
||||
if (iNewSize == oldSize)
|
||||
return;
|
||||
|
||||
var newArray = iNewSize > 0 ? new EC_IvtrItem[iNewSize] : Array.Empty<EC_IvtrItem>();
|
||||
|
||||
if (oldSize > 0 && iNewSize > 0)
|
||||
{
|
||||
Array.Copy(m_aItems, newArray, Math.Min(oldSize, iNewSize));
|
||||
}
|
||||
|
||||
m_aItems = newArray;
|
||||
}
|
||||
|
||||
public EC_IvtrItem PutItem(int iSlot, EC_IvtrItem pItem)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var old = m_aItems[iSlot];
|
||||
m_aItems[iSlot] = pItem;
|
||||
return old;
|
||||
}
|
||||
|
||||
public void SetItem(int iSlot, EC_IvtrItem pItem)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_aItems[iSlot] = pItem;
|
||||
}
|
||||
|
||||
public EC_IvtrItem GetItem(int iSlot, bool bRemove = false)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pItem = m_aItems[iSlot];
|
||||
if (bRemove)
|
||||
m_aItems[iSlot] = null;
|
||||
return pItem;
|
||||
}
|
||||
|
||||
public void ExchangeItem(int iSlot1, int iSlot2)
|
||||
{
|
||||
if (iSlot1 < 0 || iSlot1 >= m_aItems.Length ||
|
||||
iSlot2 < 0 || iSlot2 >= m_aItems.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (iSlot1 == iSlot2)
|
||||
return;
|
||||
|
||||
var tmp = m_aItems[iSlot1];
|
||||
m_aItems[iSlot1] = m_aItems[iSlot2];
|
||||
m_aItems[iSlot2] = tmp;
|
||||
}
|
||||
|
||||
public bool MergeItem(int tid, int iExpireDate, int iAmount, out int piLastSlot, out int piLastAmount)
|
||||
{
|
||||
piLastSlot = -1;
|
||||
piLastAmount = 0;
|
||||
|
||||
int firstEmpty = -1;
|
||||
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var slotItem = m_aItems[i];
|
||||
if (slotItem != null)
|
||||
{
|
||||
if (slotItem.GetTemplateID() != tid)
|
||||
continue;
|
||||
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(tid));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, slotItem.GetCount()));
|
||||
if (canAdd <= 0) continue;
|
||||
|
||||
int add = Math.Min(canAdd, iAmount);
|
||||
slotItem.AddAmount(add);
|
||||
iAmount -= add;
|
||||
|
||||
if (iAmount == 0)
|
||||
{
|
||||
piLastSlot = i;
|
||||
piLastAmount = slotItem.GetCount();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (firstEmpty < 0)
|
||||
{
|
||||
firstEmpty = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstEmpty < 0 || iAmount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var newItem = new EC_IvtrItem(tid, iExpireDate)
|
||||
{
|
||||
Slot = firstEmpty,
|
||||
State = 0,
|
||||
Crc = 0,
|
||||
Content = null
|
||||
};
|
||||
newItem.SetCount(iAmount);
|
||||
|
||||
m_aItems[firstEmpty] = newItem;
|
||||
piLastSlot = firstEmpty;
|
||||
piLastAmount = iAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool MoveItem(int iSrc, int iDest, int iAmount)
|
||||
{
|
||||
if (iSrc < 0 || iSrc >= m_aItems.Length ||
|
||||
iDest < 0 || iDest >= m_aItems.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pSrc = m_aItems[iSrc];
|
||||
var pDst = m_aItems[iDest];
|
||||
|
||||
if (pSrc == null)
|
||||
return false;
|
||||
|
||||
if (iAmount == 0)
|
||||
return false;
|
||||
|
||||
if (pDst == null)
|
||||
{
|
||||
var clone = new EC_IvtrItem(pSrc.GetTemplateID(), pSrc.GetExpireDate())
|
||||
{
|
||||
Slot = iDest,
|
||||
Package = pSrc.Package,
|
||||
State = pSrc.State,
|
||||
Crc = pSrc.Crc,
|
||||
Content = pSrc.Content != null ? (byte[])pSrc.Content.Clone() : null
|
||||
};
|
||||
clone.SetCount(iAmount);
|
||||
m_aItems[iDest] = clone;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSrc.GetTemplateID() != pDst.GetTemplateID())
|
||||
return false;
|
||||
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(pDst.GetTemplateID()));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, pDst.GetCount()));
|
||||
int add = Math.Min(canAdd, iAmount);
|
||||
if (add <= 0) return false;
|
||||
pDst.AddAmount(add);
|
||||
iAmount = add;
|
||||
}
|
||||
|
||||
RemoveItem(iSrc, iAmount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveItem(int iSlot, int iAmount)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pItem = m_aItems[iSlot];
|
||||
if (pItem == null)
|
||||
return true;
|
||||
|
||||
int newCount = pItem.AddAmount(-Math.Max(0, iAmount));
|
||||
if (newCount <= 0)
|
||||
m_aItems[iSlot] = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int FindItem(int idItem, int baseIdx = 0)
|
||||
{
|
||||
if (baseIdx < 0) baseIdx = 0;
|
||||
for (int i = baseIdx; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem != null && pItem.GetTemplateID() == idItem)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int GetItemTotalNum(int idItem)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem != null && pItem.GetTemplateID() == idItem)
|
||||
count += Math.Max(0, pItem.GetCount());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int SearchEmpty()
|
||||
{
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
if (m_aItems[i] == null)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int GetEmptySlotNum()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
if (m_aItems[i] == null)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int CanAddItem(int idItem, int iAmount, bool tryPile)
|
||||
{
|
||||
int foundEmpty = -1;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem == null)
|
||||
{
|
||||
if (!tryPile) return i;
|
||||
if (foundEmpty < 0) foundEmpty = i;
|
||||
}
|
||||
else if (pItem.GetTemplateID() == idItem)
|
||||
{
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(idItem));
|
||||
if (pItem.GetCount() + iAmount <= pileLimit)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return foundEmpty;
|
||||
}
|
||||
|
||||
public int GetSize()
|
||||
{
|
||||
return m_aItems.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static inventory facade used by the current client code.
|
||||
/// This implementation was originally in EC_Inventory.cs and is now colocated
|
||||
/// with CECInventory so both static-style and instance-style code continue to work.
|
||||
/// </summary>
|
||||
public static class EC_Inventory
|
||||
{
|
||||
// We currently support exactly three inventory packs, matching legacy C++ semantics:
|
||||
// 0 = normal pack, 1 = equip pack, 2 = task pack.
|
||||
private const int PackageCount = 3;
|
||||
|
||||
// Fixed-size arrays per package, mimicking C++ CECInventory::m_aItems (APtrArray<CECIvtrItem*>).
|
||||
// Index is the slot index; a null entry means the slot is empty.
|
||||
private static readonly int[] _packSizeByPackage = new int[PackageCount];
|
||||
private static readonly EC_IvtrItem[][] _itemsByPackage = new EC_IvtrItem[PackageCount][];
|
||||
private const int MaxContentHexToLog = 64;
|
||||
|
||||
// Package constants to mirror legacy C++ names
|
||||
public const byte IVTRTYPE_PACK = 0;
|
||||
public const byte IVTRTYPE_EQUIPPACK = 1;
|
||||
public const byte IVTRTYPE_TASKPACK = 2;
|
||||
|
||||
private static int GetPackageIndex(byte pkg)
|
||||
{
|
||||
switch (pkg)
|
||||
{
|
||||
case IVTRTYPE_PACK:
|
||||
case IVTRTYPE_EQUIPPACK:
|
||||
case IVTRTYPE_TASKPACK:
|
||||
return pkg;
|
||||
default:
|
||||
// Only three legacy packages are currently supported; ignore others safely.
|
||||
Debug.LogWarning($"[Inventory] Unsupported package id={pkg}, expected 0..2.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetPackSize(byte byPackage)
|
||||
{
|
||||
int idx = GetPackageIndex(byPackage);
|
||||
if (idx < 0) return 0;
|
||||
return _packSizeByPackage[idx];
|
||||
}
|
||||
|
||||
private static EC_IvtrItem[] EnsureSlots(byte byPackage)
|
||||
{
|
||||
int idx = GetPackageIndex(byPackage);
|
||||
if (idx < 0)
|
||||
return Array.Empty<EC_IvtrItem>();
|
||||
|
||||
int size = Math.Max(0, _packSizeByPackage[idx]);
|
||||
var slots = _itemsByPackage[idx];
|
||||
|
||||
if (slots == null || slots.Length != size)
|
||||
{
|
||||
var newSlots = size > 0 ? new EC_IvtrItem[size] : Array.Empty<EC_IvtrItem>();
|
||||
|
||||
// Preserve items that still fit into the resized pack, similar to C++ Resize.
|
||||
if (slots != null && slots.Length > 0 && newSlots.Length > 0)
|
||||
{
|
||||
Array.Copy(slots, newSlots, Math.Min(slots.Length, newSlots.Length));
|
||||
}
|
||||
|
||||
_itemsByPackage[idx] = newSlots;
|
||||
slots = newSlots;
|
||||
}
|
||||
|
||||
return slots;
|
||||
}
|
||||
|
||||
private static string GetPackageName(byte pkg)
|
||||
{
|
||||
switch (pkg)
|
||||
{
|
||||
case 0: return "IVTRTYPE_PACK";
|
||||
case 1: return "IVTRTYPE_EQUIPPACK";
|
||||
case 2: return "IVTRTYPE_TASKPACK";
|
||||
default: return "PACK_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
private static string BytesToHex(byte[] bytes, int max)
|
||||
{
|
||||
if (bytes == null || bytes.Length == 0) return "";
|
||||
int len = Math.Min(bytes.Length, max);
|
||||
string hex = BitConverter.ToString(bytes, 0, len);
|
||||
if (bytes.Length > len) hex += "-...";
|
||||
return hex;
|
||||
}
|
||||
|
||||
// C++ has CECInventory per pack; this helper returns a snapshot Dictionary view
|
||||
// of the current slots for convenience where a map-like API is easier to use.
|
||||
public static Dictionary<int, EC_IvtrItem> GetPack(byte byPackage)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
var result = new Dictionary<int, EC_IvtrItem>(slots.Length);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it != null)
|
||||
result[i] = it;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static EC_IvtrItem GetItem(int iSlot, bool bRemove)
|
||||
{
|
||||
// Backward-compatible overload defaulting to inventory package
|
||||
return GetItem(IVTRTYPE_PACK, iSlot, bRemove);
|
||||
}
|
||||
|
||||
public static EC_IvtrItem GetItem(byte byPackage, int slot, bool remove)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (slot < 0 || slot >= slots.Length)
|
||||
return null;
|
||||
|
||||
var item = slots[slot];
|
||||
if (remove && slot >= 0 && slot < slots.Length)
|
||||
slots[slot] = null;
|
||||
return item;
|
||||
}
|
||||
|
||||
public static void Resize(byte byPackage, int newSize)
|
||||
{
|
||||
int idx = GetPackageIndex(byPackage);
|
||||
if (idx < 0)
|
||||
return;
|
||||
|
||||
newSize = Math.Max(0, newSize);
|
||||
int oldSize = _packSizeByPackage[idx];
|
||||
_packSizeByPackage[idx] = newSize;
|
||||
|
||||
var oldSlots = _itemsByPackage[idx];
|
||||
|
||||
if (oldSlots == null)
|
||||
{
|
||||
_itemsByPackage[idx] = newSize > 0 ? new EC_IvtrItem[newSize] : Array.Empty<EC_IvtrItem>();
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldSize == newSize && oldSlots.Length == newSize)
|
||||
return;
|
||||
|
||||
var newSlots = newSize > 0 ? new EC_IvtrItem[newSize] : Array.Empty<EC_IvtrItem>();
|
||||
if (oldSlots.Length > 0 && newSlots.Length > 0)
|
||||
{
|
||||
Array.Copy(oldSlots, newSlots, Math.Min(oldSlots.Length, newSlots.Length));
|
||||
}
|
||||
_itemsByPackage[idx] = newSlots;
|
||||
}
|
||||
|
||||
public static EC_IvtrItem PutItem(byte byPackage, int slot, EC_IvtrItem item)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (slot < 0 || slot >= slots.Length)
|
||||
return null;
|
||||
|
||||
var oldItem = slots[slot];
|
||||
slots[slot] = item;
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
public static void SetItem(byte byPackage, int slot, EC_IvtrItem item)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (slot < 0 || slot >= slots.Length)
|
||||
return;
|
||||
slots[slot] = item;
|
||||
}
|
||||
|
||||
public static void ExchangeItem(byte byPackage, int slot1, int slot2)
|
||||
{
|
||||
if (slot1 == slot2) return;
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (slot1 < 0 || slot1 >= slots.Length || slot2 < 0 || slot2 >= slots.Length)
|
||||
return;
|
||||
|
||||
var i1 = slots[slot1];
|
||||
var i2 = slots[slot2];
|
||||
slots[slot1] = i2;
|
||||
slots[slot2] = i1;
|
||||
}
|
||||
|
||||
public static bool RemoveItem(byte byPackage, int slot, int amount)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (slot < 0 || slot >= slots.Length)
|
||||
return false;
|
||||
|
||||
var item = slots[slot];
|
||||
if (item == null)
|
||||
return true;
|
||||
|
||||
int newCount = Math.Max(0, item.m_iCount - Math.Max(0, amount));
|
||||
item.m_iCount = newCount;
|
||||
if (newCount <= 0)
|
||||
slots[slot] = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void RemoveAllItems(byte byPackage)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
slots[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int SearchEmpty(byte byPackage)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (slots[i] == null)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int GetEmptySlotNum(byte byPackage)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
int empty = 0;
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
if (slots[i] == null)
|
||||
empty++;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
public static int FindItem(byte byPackage, int templateId, int baseIdx = 0)
|
||||
{
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (baseIdx < 0) baseIdx = 0;
|
||||
for (int i = baseIdx; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it != null && it.m_tid == templateId)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int GetItemTotalNum(byte byPackage, int templateId)
|
||||
{
|
||||
int total = 0;
|
||||
var slots = EnsureSlots(byPackage);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it != null && it.m_tid == templateId)
|
||||
total += Math.Max(0, it.m_iCount);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public static int GetItemCanPileCount(byte byPackage, int templateId)
|
||||
{
|
||||
int ret = 0;
|
||||
var slots = EnsureSlots(byPackage);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it != null && it.m_tid == templateId)
|
||||
{
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(templateId));
|
||||
ret += Math.Max(0, pileLimit - Math.Max(0, it.m_iCount));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int CanAddItem(byte byPackage, int templateId, int amount, bool tryPile)
|
||||
{
|
||||
int firstEmpty = -1;
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(templateId));
|
||||
var slots = EnsureSlots(byPackage);
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it == null)
|
||||
{
|
||||
// return first empty slot if not trying to pile item
|
||||
if (!tryPile) return i;
|
||||
if (firstEmpty < 0) firstEmpty = i;
|
||||
}
|
||||
else if (it.m_tid == templateId && it.m_iCount + amount <= pileLimit)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return firstEmpty;
|
||||
}
|
||||
|
||||
public static bool MergeItem(byte byPackage, int templateId, int expireDate, int amount, out int lastSlot, out int slotAmount)
|
||||
{
|
||||
lastSlot = -1;
|
||||
slotAmount = 0;
|
||||
var slots = EnsureSlots(byPackage);
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(templateId));
|
||||
int firstEmpty = -1;
|
||||
|
||||
for (int i = 0; i < slots.Length && amount > 0; i++)
|
||||
{
|
||||
var slotItem = slots[i];
|
||||
if (slotItem == null)
|
||||
{
|
||||
if (firstEmpty < 0) firstEmpty = i;
|
||||
continue;
|
||||
}
|
||||
if (slotItem.m_tid != templateId) continue;
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, slotItem.m_iCount));
|
||||
if (canAdd <= 0) continue;
|
||||
int add = Math.Min(canAdd, amount);
|
||||
slotItem.m_iCount += add;
|
||||
amount -= add;
|
||||
lastSlot = i;
|
||||
slotAmount = slotItem.m_iCount;
|
||||
}
|
||||
if (amount <= 0) return true;
|
||||
if (firstEmpty < 0) return false;
|
||||
|
||||
var newItem = new EC_IvtrItem
|
||||
{
|
||||
Package = byPackage,
|
||||
Slot = firstEmpty,
|
||||
m_tid = templateId,
|
||||
m_expire_date = expireDate,
|
||||
State = 0,
|
||||
m_iCount = amount,
|
||||
Crc = 0,
|
||||
Content = null
|
||||
};
|
||||
slots[firstEmpty] = newItem;
|
||||
lastSlot = firstEmpty;
|
||||
slotAmount = amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool MoveItem(byte byPackage, int src, int dest, int amount)
|
||||
{
|
||||
if (src == dest) return false;
|
||||
if (amount <= 0) return false;
|
||||
|
||||
var slots = EnsureSlots(byPackage);
|
||||
if (src < 0 || src >= slots.Length || dest < 0 || dest >= slots.Length) return false;
|
||||
|
||||
var srcItem = slots[src];
|
||||
var dstItem = slots[dest];
|
||||
if (srcItem == null) return false;
|
||||
|
||||
if (dstItem == null)
|
||||
{
|
||||
var clone = new EC_IvtrItem
|
||||
{
|
||||
Package = byPackage,
|
||||
Slot = dest,
|
||||
m_tid = srcItem.m_tid,
|
||||
m_expire_date = srcItem.m_expire_date,
|
||||
State = srcItem.State,
|
||||
m_iCount = amount,
|
||||
Crc = srcItem.Crc,
|
||||
Content = srcItem.Content != null ? (byte[])srcItem.Content.Clone() : null
|
||||
};
|
||||
slots[dest] = clone;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dstItem.m_tid != srcItem.m_tid) return false;
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(dstItem.m_tid));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, dstItem.m_iCount));
|
||||
int add = Math.Min(canAdd, amount);
|
||||
if (add <= 0) return false;
|
||||
dstItem.m_iCount += add;
|
||||
amount = add;
|
||||
}
|
||||
RemoveItem(byPackage, src, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void UpdatePack(byte byPackage, int ivtrSize, IEnumerable<EC_IvtrItem> items)
|
||||
{
|
||||
Resize(byPackage, ivtrSize);
|
||||
var slots = EnsureSlots(byPackage);
|
||||
|
||||
// Clear existing entries; keep size.
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
slots[i] = null;
|
||||
|
||||
if (items != null)
|
||||
{
|
||||
foreach (var it in items)
|
||||
{
|
||||
if (it != null && it.Slot >= 0 && it.Slot < slots.Length)
|
||||
{
|
||||
slots[it.Slot] = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Log this pack's items
|
||||
LogPackInternal(byPackage, ivtrSize, slots);
|
||||
}
|
||||
|
||||
public static bool ResetWithDetailData(byte byPackage, int ivtrSize, byte[] data)
|
||||
{
|
||||
// Uses EC_IvtrItem.TryParseInventoryDetail format
|
||||
if (data == null)
|
||||
{
|
||||
Resize(byPackage, ivtrSize);
|
||||
RemoveAllItems(byPackage);
|
||||
return true;
|
||||
}
|
||||
if (!EC_IvtrItemUtils.Instance.TryParseInventoryDetail(data, out var pkg, out var size, out var items))
|
||||
return false;
|
||||
// Prefer header values when valid
|
||||
byte finalPkg = byPackage;
|
||||
if (pkg == byPackage) finalPkg = pkg;
|
||||
int finalSize = ivtrSize > 0 ? ivtrSize : size;
|
||||
UpdatePack(finalPkg, finalSize, items);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void LogPackInternal(byte byPackage, int ivtrSize, EC_IvtrItem[] slots)
|
||||
{
|
||||
//Debug.Log($"[Inventory] === Pack {GetPackageName(byPackage)}({byPackage}) size={ivtrSize}, items={slots?.Length ?? 0} ===");
|
||||
if (slots == null || slots.Length == 0)
|
||||
{
|
||||
//Debug.Log("[Inventory] (empty)");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var it = slots[i];
|
||||
if (it == null)
|
||||
continue;
|
||||
|
||||
string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(it.m_tid);
|
||||
string extraHex = it.Content != null && it.Content.Length > 0 ? EC_IvtrItemUtils.Instance.BytesToHex(it.Content, MaxContentHexToLog) : "";
|
||||
//int extraLen = it.Content?.Length ?? 0;
|
||||
//Debug.Log(
|
||||
// $"[Inventory] pkg={GetPackageName(it.Package)}({it.Package}) slot={it.Slot} tid={it.TemplateId}{(string.IsNullOrEmpty(itemName) ? "" : " \"" + itemName + "\"")} count={it.Count} state={it.State} expire={it.ExpireDate} crc={it.Crc} content_len={extraLen}{(extraLen > 0 ? ", content_hex=" + extraHex : "")}"
|
||||
//);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogInventoryPacket(string tag, byte[] buffer, int hostId)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
if (buffer.Length < 6)
|
||||
{
|
||||
//LogInventoryRaw(tag, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
byte byPackage = buffer[index++];
|
||||
byte ivtrSize = buffer[index++];
|
||||
uint contentLength = BitConverter.ToUInt32(buffer, index); index += 4;
|
||||
|
||||
int remaining = buffer.Length - index;
|
||||
int contentBytes = remaining;
|
||||
if (contentLength < (uint)remaining)
|
||||
{
|
||||
contentBytes = (int)contentLength;
|
||||
}
|
||||
|
||||
if (contentBytes > 0)
|
||||
{
|
||||
byte[] content = new byte[contentBytes];
|
||||
Buffer.BlockCopy(buffer, index, content, 0, contentBytes);
|
||||
}
|
||||
|
||||
int trailing = buffer.Length - (index + contentBytes);
|
||||
if (trailing > 0)
|
||||
{
|
||||
byte[] tail = new byte[trailing];
|
||||
Buffer.BlockCopy(buffer, index + contentBytes, tail, 0, trailing);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogInventoryRaw(string tag, byte[] buffer)
|
||||
{
|
||||
Debug.Log($"[Inventory] {tag}: RAW HEX (len={buffer?.Length ?? 0})=\n{(buffer == null ? "<null>" : BitConverter.ToString(buffer))}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts.Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// C# mirror of C++ CECInventory (EC_Inventory.h / EC_Inventory.cpp).
|
||||
/// Instance-based inventory core plus static helpers used by existing client code.
|
||||
/// </summary>
|
||||
public class EC_Inventory
|
||||
{
|
||||
// ===== Instance-based inventory (per-pack) =====
|
||||
|
||||
// Item array: index is slot, null means empty.
|
||||
private EC_IvtrItem[] m_aItems = Array.Empty<EC_IvtrItem>();
|
||||
|
||||
public EC_Inventory()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Init(int iSize)
|
||||
{
|
||||
Resize(iSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
// In C++ this deletes all heap-allocated items.
|
||||
// Here we simply clear references so GC can collect them.
|
||||
RemoveAllItems();
|
||||
m_aItems = Array.Empty<EC_IvtrItem>();
|
||||
}
|
||||
|
||||
public void RemoveAllItems()
|
||||
{
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
m_aItems[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(int iNewSize)
|
||||
{
|
||||
int oldSize = m_aItems.Length;
|
||||
if (iNewSize < 0) iNewSize = 0;
|
||||
|
||||
if (iNewSize == oldSize)
|
||||
return;
|
||||
|
||||
var newArray = iNewSize > 0 ? new EC_IvtrItem[iNewSize] : Array.Empty<EC_IvtrItem>();
|
||||
|
||||
if (oldSize > 0 && iNewSize > 0)
|
||||
{
|
||||
Array.Copy(m_aItems, newArray, Math.Min(oldSize, iNewSize));
|
||||
}
|
||||
|
||||
m_aItems = newArray;
|
||||
}
|
||||
|
||||
public EC_IvtrItem PutItem(int iSlot, EC_IvtrItem pItem)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var old = m_aItems[iSlot];
|
||||
m_aItems[iSlot] = pItem;
|
||||
return old;
|
||||
}
|
||||
|
||||
public void SetItem(int iSlot, EC_IvtrItem pItem)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_aItems[iSlot] = pItem;
|
||||
}
|
||||
|
||||
public EC_IvtrItem GetItem(int iSlot, bool bRemove = false)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pItem = m_aItems[iSlot];
|
||||
if (bRemove)
|
||||
m_aItems[iSlot] = null;
|
||||
return pItem;
|
||||
}
|
||||
|
||||
public void ExchangeItem(int iSlot1, int iSlot2)
|
||||
{
|
||||
if (iSlot1 < 0 || iSlot1 >= m_aItems.Length ||
|
||||
iSlot2 < 0 || iSlot2 >= m_aItems.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (iSlot1 == iSlot2)
|
||||
return;
|
||||
|
||||
var tmp = m_aItems[iSlot1];
|
||||
m_aItems[iSlot1] = m_aItems[iSlot2];
|
||||
m_aItems[iSlot2] = tmp;
|
||||
}
|
||||
|
||||
public bool MergeItem(int tid, int iExpireDate, int iAmount, out int piLastSlot, out int piLastAmount)
|
||||
{
|
||||
piLastSlot = -1;
|
||||
piLastAmount = 0;
|
||||
|
||||
int firstEmpty = -1;
|
||||
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var slotItem = m_aItems[i];
|
||||
if (slotItem != null)
|
||||
{
|
||||
if (slotItem.GetTemplateID() != tid)
|
||||
continue;
|
||||
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(tid));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, slotItem.GetCount()));
|
||||
if (canAdd <= 0) continue;
|
||||
|
||||
int add = Math.Min(canAdd, iAmount);
|
||||
slotItem.AddAmount(add);
|
||||
iAmount -= add;
|
||||
|
||||
if (iAmount == 0)
|
||||
{
|
||||
piLastSlot = i;
|
||||
piLastAmount = slotItem.GetCount();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (firstEmpty < 0)
|
||||
{
|
||||
firstEmpty = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstEmpty < 0 || iAmount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var newItem = new EC_IvtrItem(tid, iExpireDate)
|
||||
{
|
||||
Slot = firstEmpty,
|
||||
State = 0,
|
||||
Crc = 0,
|
||||
Content = null
|
||||
};
|
||||
newItem.SetCount(iAmount);
|
||||
|
||||
m_aItems[firstEmpty] = newItem;
|
||||
piLastSlot = firstEmpty;
|
||||
piLastAmount = iAmount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool MoveItem(int iSrc, int iDest, int iAmount)
|
||||
{
|
||||
if (iSrc < 0 || iSrc >= m_aItems.Length ||
|
||||
iDest < 0 || iDest >= m_aItems.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pSrc = m_aItems[iSrc];
|
||||
var pDst = m_aItems[iDest];
|
||||
|
||||
if (pSrc == null)
|
||||
return false;
|
||||
|
||||
if (iAmount == 0)
|
||||
return false;
|
||||
|
||||
if (pDst == null)
|
||||
{
|
||||
var clone = new EC_IvtrItem(pSrc.GetTemplateID(), pSrc.GetExpireDate())
|
||||
{
|
||||
Slot = iDest,
|
||||
Package = pSrc.Package,
|
||||
State = pSrc.State,
|
||||
Crc = pSrc.Crc,
|
||||
Content = pSrc.Content != null ? (byte[])pSrc.Content.Clone() : null
|
||||
};
|
||||
clone.SetCount(iAmount);
|
||||
m_aItems[iDest] = clone;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSrc.GetTemplateID() != pDst.GetTemplateID())
|
||||
return false;
|
||||
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(pDst.GetTemplateID()));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, pDst.GetCount()));
|
||||
int add = Math.Min(canAdd, iAmount);
|
||||
if (add <= 0) return false;
|
||||
pDst.AddAmount(add);
|
||||
iAmount = add;
|
||||
}
|
||||
|
||||
RemoveItem(iSrc, iAmount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveItem(int iSlot, int iAmount)
|
||||
{
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pItem = m_aItems[iSlot];
|
||||
if (pItem == null)
|
||||
return true;
|
||||
|
||||
int newCount = pItem.AddAmount(-Math.Max(0, iAmount));
|
||||
if (newCount <= 0)
|
||||
m_aItems[iSlot] = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int FindItem(int idItem, int baseIdx = 0)
|
||||
{
|
||||
if (baseIdx < 0) baseIdx = 0;
|
||||
for (int i = baseIdx; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem != null && pItem.GetTemplateID() == idItem)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int GetItemTotalNum(int idItem)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem != null && pItem.GetTemplateID() == idItem)
|
||||
count += Math.Max(0, pItem.GetCount());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int SearchEmpty()
|
||||
{
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
if (m_aItems[i] == null)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int GetEmptySlotNum()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
if (m_aItems[i] == null)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int CanAddItem(int idItem, int iAmount, bool tryPile)
|
||||
{
|
||||
int foundEmpty = -1;
|
||||
for (int i = 0; i < m_aItems.Length; i++)
|
||||
{
|
||||
var pItem = m_aItems[i];
|
||||
if (pItem == null)
|
||||
{
|
||||
if (!tryPile) return i;
|
||||
if (foundEmpty < 0) foundEmpty = i;
|
||||
}
|
||||
else if (pItem.GetTemplateID() == idItem)
|
||||
{
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(idItem));
|
||||
if (pItem.GetCount() + iAmount <= pileLimit)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return foundEmpty;
|
||||
}
|
||||
|
||||
public int GetSize()
|
||||
{
|
||||
return m_aItems.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using BrewMonster;
|
||||
using BrewMonster.Common;
|
||||
using ModelRenderer.Scripts.GameData;
|
||||
using PerfectWorld.Scripts.Managers;
|
||||
using BrewMonster.Scripts;
|
||||
|
||||
namespace BrewMonster.Scripts.Managers
|
||||
{
|
||||
@@ -654,34 +655,23 @@ namespace BrewMonster.Scripts.Managers
|
||||
// === MVC: Model ===
|
||||
private class InventoryModel
|
||||
{
|
||||
private readonly FieldInfo itemsByPackageField;
|
||||
|
||||
public InventoryModel()
|
||||
{
|
||||
var inventoryType = typeof(EC_Inventory);
|
||||
itemsByPackageField = inventoryType.GetField("_itemsByPackage", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (itemsByPackageField == null)
|
||||
{
|
||||
Debug.LogError("[InventoryUI] Could not access _itemsByPackage field from EC_Inventory");
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<int, EC_IvtrItem> GetInventoryData(byte package)
|
||||
{
|
||||
if (itemsByPackageField == null)
|
||||
// Read from host player's per-package CECInventory instance
|
||||
var host = CECGameRun.Instance?.GetHostPlayer();
|
||||
var inv = host?.GetInventory(package);
|
||||
var result = new Dictionary<int, EC_IvtrItem>();
|
||||
if (inv == null)
|
||||
return result;
|
||||
|
||||
int size = inv.GetSize();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
return new Dictionary<int, EC_IvtrItem>();
|
||||
var item = inv.GetItem(i, false);
|
||||
if (item != null)
|
||||
result[i] = item;
|
||||
}
|
||||
var itemsByPackage = itemsByPackageField.GetValue(null) as Dictionary<byte, Dictionary<int, EC_IvtrItem>>;
|
||||
if (itemsByPackage == null)
|
||||
{
|
||||
return new Dictionary<int, EC_IvtrItem>();
|
||||
}
|
||||
if (itemsByPackage.TryGetValue(package, out var packageItems))
|
||||
{
|
||||
return packageItems;
|
||||
}
|
||||
return new Dictionary<int, EC_IvtrItem>();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
public bool m_bIsInNPCPack; // true, this item is in NPC package
|
||||
public bool m_bLocalDetailData; // true, data from GetDetailDataFromLocal
|
||||
|
||||
public CECInventory m_pDescIvtr; // Inventory only used to get item description
|
||||
public EC_Inventory m_pDescIvtr; // Inventory only used to get item description
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -979,7 +979,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
/// Get item description text (normal / booth-buy / reward / repair).
|
||||
/// Mirrors the inline C++ <c>GetDesc</c>.
|
||||
/// </summary>
|
||||
public string GetDesc(DescType iDescType = DescType.DESC_NORMAL, CECInventory pInventory = null)
|
||||
public string GetDesc(DescType iDescType = DescType.DESC_NORMAL, EC_Inventory pInventory = null)
|
||||
{
|
||||
m_pDescIvtr = pInventory;
|
||||
|
||||
|
||||
@@ -442,15 +442,18 @@ namespace BrewMonster.Scripts.Managers
|
||||
/// </summary>
|
||||
private static IndexOfIteminEquipmentInventory GetAvailableFingerSlot()
|
||||
{
|
||||
var host = CECGameRun.Instance?.GetHostPlayer();
|
||||
var equipInv = host?.GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK);
|
||||
|
||||
// Check if FINGER1 slot is empty
|
||||
var finger1Item = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1, false);
|
||||
var finger1Item = equipInv?.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1, false);
|
||||
if (finger1Item == null)
|
||||
{
|
||||
return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER1;
|
||||
}
|
||||
|
||||
// Check if FINGER2 slot is empty
|
||||
var finger2Item = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2, false);
|
||||
var finger2Item = equipInv?.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2, false);
|
||||
if (finger2Item == null)
|
||||
{
|
||||
return IndexOfIteminEquipmentInventory.EQUIPIVTR_FINGER2;
|
||||
|
||||
@@ -454,12 +454,10 @@ namespace BrewMonster.Scripts.Task
|
||||
public int GetCommonItemCount(uint ulCommonItem)
|
||||
{
|
||||
// CECInventory pPack = m_pHost.GetPack();
|
||||
//EC_Inventory pPack = m_pHost.GetPack();
|
||||
|
||||
// return pPack != null ? EC_Inventory.GetItemTotalNum( 0, (int)ulCommonItem) : 0;
|
||||
// return pPack != null ? pPack.GetItemTotalNum((int)ulCommonItem) : 0;
|
||||
|
||||
// paramater 1 to get type inventory (0:inventoty, 1:equip,...)
|
||||
return EC_Inventory.GetItemTotalNum(EC_Inventory.IVTRTYPE_PACK, (int)ulCommonItem);
|
||||
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_PACK);
|
||||
return inv != null ? inv.GetItemTotalNum((int)ulCommonItem) : 0;
|
||||
}
|
||||
|
||||
public int GetTaskItemCount(uint ulTaskItem)
|
||||
@@ -467,7 +465,8 @@ namespace BrewMonster.Scripts.Task
|
||||
// CECInventory* pPack = m_pHost->GetTaskPack();
|
||||
// return pPack ? pPack->GetItemTotalNum((int)ulTaskItem) : 0;
|
||||
|
||||
return EC_Inventory.GetItemTotalNum(EC_Inventory.IVTRTYPE_TASKPACK, (int)ulTaskItem);
|
||||
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_TASKPACK);
|
||||
return inv != null ? inv.GetItemTotalNum((int)ulTaskItem) : 0;
|
||||
}
|
||||
|
||||
private ATaskTemplMan GetTaskTemplMan()
|
||||
@@ -725,7 +724,8 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
public uint GetInvEmptySlot()
|
||||
{
|
||||
return (uint)EC_Inventory.GetEmptySlotNum(EC_Inventory.IVTRTYPE_PACK);
|
||||
var inv = m_pHost?.GetInventory(InventoryConst.IVTRTYPE_PACK);
|
||||
return inv != null ? (uint)inv.GetEmptySlotNum() : 0u;
|
||||
}
|
||||
|
||||
public int GetFactionContrib()
|
||||
|
||||
@@ -718,7 +718,6 @@ GameObject:
|
||||
m_Component:
|
||||
- component: {fileID: 5275130098495308601}
|
||||
- component: {fileID: 7874153745862569389}
|
||||
- component: {fileID: 112648634020396885}
|
||||
- component: {fileID: 3332719603249310962}
|
||||
m_Layer: 5
|
||||
m_Name: PreviewCamera
|
||||
@@ -797,14 +796,6 @@ Camera:
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!81 &112648634020396885
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 633515748786992396}
|
||||
m_Enabled: 1
|
||||
--- !u!114 &3332719603249310962
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
+102
-15
@@ -116,6 +116,31 @@ public partial class CECHostPlayer : CECPlayer
|
||||
|
||||
public bool IsChangingFace() { return m_bChangingFace; }
|
||||
|
||||
// ===== Inventory packs (instance-based) =====
|
||||
// 0 = normal pack, 1 = equip pack, 2 = task pack (see InventoryConst.IVTRTYPE_*)
|
||||
private readonly EC_Inventory m_packInventory = new EC_Inventory();
|
||||
private readonly EC_Inventory m_equipInventory = new EC_Inventory();
|
||||
private readonly EC_Inventory m_taskInventory = new EC_Inventory();
|
||||
|
||||
public EC_Inventory PackInventory => m_packInventory;
|
||||
public EC_Inventory EquipInventory => m_equipInventory;
|
||||
public EC_Inventory TaskInventory => m_taskInventory;
|
||||
|
||||
public EC_Inventory GetInventory(byte byPackage)
|
||||
{
|
||||
switch (byPackage)
|
||||
{
|
||||
case InventoryConst.IVTRTYPE_PACK:
|
||||
return m_packInventory;
|
||||
case InventoryConst.IVTRTYPE_EQUIPPACK:
|
||||
return m_equipInventory;
|
||||
case InventoryConst.IVTRTYPE_TASKPACK:
|
||||
return m_taskInventory;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
@@ -773,8 +798,9 @@ public partial class CECHostPlayer : CECPlayer
|
||||
Content = null
|
||||
};
|
||||
|
||||
// Add item to inventory
|
||||
EC_Inventory.SetItem(where, index, newItem);
|
||||
// Add item to inventory (instance-based)
|
||||
var inv = GetInventory(where);
|
||||
inv?.SetItem(index, newItem);
|
||||
|
||||
Debug.Log(
|
||||
$"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}");
|
||||
@@ -824,8 +850,9 @@ public partial class CECHostPlayer : CECPlayer
|
||||
Content = null
|
||||
};
|
||||
|
||||
// Add item to inventory
|
||||
EC_Inventory.SetItem(byPackage, bySlot, newItem);
|
||||
// Add item to inventory (instance-based)
|
||||
var inv = GetInventory(byPackage);
|
||||
inv?.SetItem(bySlot, newItem);
|
||||
|
||||
//Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}");
|
||||
|
||||
@@ -865,7 +892,8 @@ public partial class CECHostPlayer : CECPlayer
|
||||
$"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}");
|
||||
|
||||
// Update the inventory by removing the item
|
||||
bool success = EC_Inventory.RemoveItem(byPackage, bySlot, count);
|
||||
var inv = GetInventory(byPackage);
|
||||
bool success = inv != null && inv.RemoveItem(bySlot, count);
|
||||
|
||||
if (success)
|
||||
{
|
||||
@@ -896,20 +924,22 @@ public partial class CECHostPlayer : CECPlayer
|
||||
byte index_inv = data[0];
|
||||
byte index_equip = data[1];
|
||||
// Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT
|
||||
var invItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, true);
|
||||
var equipItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, true);
|
||||
var packInv = GetInventory(InventoryConst.IVTRTYPE_PACK);
|
||||
var equipInv = GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK);
|
||||
var invItem = packInv?.GetItem(index_inv, true);
|
||||
var equipItem = equipInv?.GetItem(index_equip, true);
|
||||
if (invItem != null)
|
||||
{
|
||||
invItem.Package = EC_Inventory.IVTRTYPE_EQUIPPACK;
|
||||
invItem.Package = InventoryConst.IVTRTYPE_EQUIPPACK;
|
||||
invItem.Slot = index_equip;
|
||||
EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, invItem);
|
||||
equipInv?.SetItem(index_equip, invItem);
|
||||
}
|
||||
|
||||
if (equipItem != null)
|
||||
{
|
||||
equipItem.Package = EC_Inventory.IVTRTYPE_PACK;
|
||||
equipItem.Package = InventoryConst.IVTRTYPE_PACK;
|
||||
equipItem.Slot = index_inv;
|
||||
EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, equipItem);
|
||||
packInv?.SetItem(index_inv, equipItem);
|
||||
}
|
||||
|
||||
// Trigger UI refresh if an EC_InventoryUI is present in scene
|
||||
@@ -934,7 +964,7 @@ public partial class CECHostPlayer : CECPlayer
|
||||
Debug.Log("[Inventory] OWN_ITEM_INFO received");
|
||||
var data = Msg.dwParam1 as byte[];
|
||||
int hostId = Convert.ToInt32(Msg.dwParam3);
|
||||
EC_Inventory.LogInventoryPacket("OWN_ITEM_INFO", data, hostId);
|
||||
LogInventoryPacket("OWN_ITEM_INFO", data, hostId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -950,7 +980,7 @@ public partial class CECHostPlayer : CECPlayer
|
||||
{
|
||||
case CommandID.OWN_IVTR_DATA:
|
||||
{
|
||||
EC_Inventory.LogInventoryPacket("OWN_IVTR_DATA", data, hostId);
|
||||
LogInventoryPacket("OWN_IVTR_DATA", data, hostId);
|
||||
break;
|
||||
}
|
||||
case CommandID.OWN_IVTR_DETAIL_DATA:
|
||||
@@ -964,11 +994,25 @@ public partial class CECHostPlayer : CECPlayer
|
||||
if (EC_IvtrItemUtils.Instance.TryParseInventoryDetail(data, out var pkg,
|
||||
out var size, out var items))
|
||||
{
|
||||
EC_Inventory.UpdatePack(pkg, size, items);
|
||||
var inv = GetInventory(pkg);
|
||||
if (inv != null)
|
||||
{
|
||||
inv.Resize(size);
|
||||
inv.RemoveAllItems();
|
||||
|
||||
if (items != null)
|
||||
{
|
||||
foreach (var it in items)
|
||||
{
|
||||
if (it != null && it.Slot >= 0 && it.Slot < size)
|
||||
inv.SetItem(it.Slot, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we got the item from the Equipment Pack. If so, we have to load the equipment items
|
||||
if (byPackage == EC_Inventory.IVTRTYPE_EQUIPPACK)
|
||||
if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK)
|
||||
{
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
@@ -1063,6 +1107,49 @@ public partial class CECHostPlayer : CECPlayer
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Inventory packet logging helpers (was static on EC_Inventory/CECInventory) =====
|
||||
private void LogInventoryPacket(string tag, byte[] buffer, int hostId)
|
||||
{
|
||||
if (buffer == null)
|
||||
return;
|
||||
|
||||
int index = 0;
|
||||
if (buffer.Length < 6)
|
||||
{
|
||||
//LogInventoryRaw(tag, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
byte byPackage = buffer[index++];
|
||||
byte ivtrSize = buffer[index++];
|
||||
uint contentLength = BitConverter.ToUInt32(buffer, index); index += 4;
|
||||
|
||||
int remaining = buffer.Length - index;
|
||||
int contentBytes = remaining;
|
||||
if (contentLength < (uint)remaining)
|
||||
{
|
||||
contentBytes = (int)contentLength;
|
||||
}
|
||||
|
||||
if (contentBytes > 0)
|
||||
{
|
||||
byte[] content = new byte[contentBytes];
|
||||
Buffer.BlockCopy(buffer, index, content, 0, contentBytes);
|
||||
}
|
||||
|
||||
int trailing = buffer.Length - (index + contentBytes);
|
||||
if (trailing > 0)
|
||||
{
|
||||
byte[] tail = new byte[trailing];
|
||||
Buffer.BlockCopy(buffer, index + contentBytes, tail, 0, trailing);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogInventoryRaw(string tag, byte[] buffer)
|
||||
{
|
||||
Debug.Log($"[Inventory] {tag}: RAW HEX (len={buffer?.Length ?? 0})=\n{(buffer == null ? "<null>" : BitConverter.ToString(buffer))}");
|
||||
}
|
||||
|
||||
public void OnMsgHstCorrectPos(in ECMSG Msg)
|
||||
{
|
||||
Debug.LogWarning("HoangDev : OnMsgHstCorrectPos");
|
||||
|
||||
@@ -129,17 +129,16 @@ public partial class CECPlayer
|
||||
|
||||
public bool UpdateEquipSkins()
|
||||
{
|
||||
var equipPack = EC_Inventory.GetPack(EC_Inventory.IVTRTYPE_EQUIPPACK);
|
||||
|
||||
int[] aNewEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK];
|
||||
EC_IvtrItem pItem = null;
|
||||
for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++)
|
||||
{
|
||||
|
||||
if (equipPack.TryGetValue(i, out pItem))
|
||||
{
|
||||
// Use host player's equipment inventory (per-instance CECInventory)
|
||||
var host = CECGameRun.Instance?.GetHostPlayer();
|
||||
var equipInv = host?.EquipInventory;
|
||||
pItem = equipInv?.GetItem(i, false);
|
||||
if (pItem != null)
|
||||
aNewEquips[i] = pItem.m_tid;
|
||||
}
|
||||
}
|
||||
|
||||
ShowEquipments(aNewEquips, true, true);
|
||||
|
||||
Reference in New Issue
Block a user