Merge pull request 'Update dlg pet rec and fix bug restore egg from NPC.' (#182) from feature/hp_pet into develop
Reviewed-on: https://git.pthub.vn/Unity/perfect-world-unity/pulls/182
This commit is contained in:
@@ -9,7 +9,6 @@ using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using BrewMonster.Network;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
public class CECNPCMan : IMsgHandler
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using CSNetwork.GPDataType;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using static BrewMonster.Scripts.CECHPWorkSpell.Spell_magic_state;
|
||||
namespace BrewMonster.Scripts
|
||||
|
||||
@@ -6,7 +6,6 @@ using CSNetwork.GPDataType;
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using PerfectWorld.Scripts;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts.Managers
|
||||
@@ -129,6 +128,42 @@ namespace BrewMonster.Scripts.Managers
|
||||
m_aItems[iSlot2] = tmp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Place or stack item in a specific slot (server-specified slot). Matches C++ expectation that client uses same slot as server.
|
||||
/// </summary>
|
||||
public bool PutItemInSlot(int iSlot, int tid, int iExpireDate, int iAmount, out int piLastSlot, out int piLastAmount)
|
||||
{
|
||||
piLastSlot = -1;
|
||||
piLastAmount = 0;
|
||||
if (iSlot < 0 || iSlot >= m_aItems.Length || iAmount <= 0)
|
||||
return false;
|
||||
|
||||
var slotItem = m_aItems[iSlot];
|
||||
if (slotItem == null)
|
||||
{
|
||||
var newItem = EC_IvtrItem.CreateItem(tid, iExpireDate, iAmount);
|
||||
if (newItem == null)
|
||||
return false;
|
||||
newItem.Slot = iSlot;
|
||||
newItem.SetCount(iAmount);
|
||||
m_aItems[iSlot] = newItem;
|
||||
piLastSlot = iSlot;
|
||||
piLastAmount = iAmount;
|
||||
return true;
|
||||
}
|
||||
if (slotItem.GetTemplateID() != tid)
|
||||
return false;
|
||||
int pileLimit = Math.Max(1, EC_IvtrItem.GetPileLimit(tid));
|
||||
int canAdd = Math.Max(0, pileLimit - Math.Max(0, slotItem.GetCount()));
|
||||
if (canAdd <= 0)
|
||||
return false;
|
||||
int add = Math.Min(canAdd, iAmount);
|
||||
slotItem.AddAmount(add);
|
||||
piLastSlot = iSlot;
|
||||
piLastAmount = slotItem.GetCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool MergeItem(int tid, int iExpireDate, int iAmount, out int piLastSlot, out int piLastAmount)
|
||||
{
|
||||
piLastSlot = -1;
|
||||
@@ -170,6 +205,9 @@ namespace BrewMonster.Scripts.Managers
|
||||
return false;
|
||||
}
|
||||
var newItem = EC_IvtrItem.CreateItem(tid, iExpireDate, iAmount);
|
||||
if (newItem == null)
|
||||
return false;
|
||||
newItem.Slot = firstEmpty;
|
||||
newItem.SetCount(iAmount);
|
||||
|
||||
m_aItems[firstEmpty] = newItem;
|
||||
|
||||
@@ -14,9 +14,6 @@ using System.Text.RegularExpressions;
|
||||
using System.Reflection;
|
||||
using BrewMonster.Scripts.Managers;
|
||||
using BrewMonster.Scripts;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using CSNetwork.Protocols;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
namespace PerfectWorld.Scripts.Managers
|
||||
{
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
using Animancer;
|
||||
using BrewMonster;
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.PerfectWorld.Scripts.Vfx;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.Managers;
|
||||
using BrewMonster.Scripts.Skills;
|
||||
using CSNetwork.GPDataType;
|
||||
using ModelRenderer.Scripts.GameData;
|
||||
using PerfectWorld.Scripts.Managers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UIElements;
|
||||
using static BrewMonster.CECPlayer;
|
||||
using BrewMonster.Network;
|
||||
using System.Runtime.InteropServices;
|
||||
using PerfectWorld.Scripts.Managers.BrewMonster.Managers;
|
||||
using CSNetwork;
|
||||
|
||||
@@ -4,9 +4,6 @@ using ModelRenderer.Scripts.GameData;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using static CECNPC;
|
||||
|
||||
public class CECMonster : CECNPC
|
||||
{
|
||||
|
||||
@@ -1315,6 +1315,26 @@ namespace CSNetwork.GPDataType
|
||||
public byte bySlot;
|
||||
}
|
||||
|
||||
/// <summary>One item in cmd_purchase_item (buy from NPC/booth). Wire: item_id, expire_date, count, inv_index, booth_slot = 15 bytes.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_purchase_item_ITEM
|
||||
{
|
||||
public int item_id;
|
||||
public int expire_date;
|
||||
public uint count;
|
||||
public ushort inv_index;
|
||||
public byte booth_slot;
|
||||
}
|
||||
|
||||
/// <summary>Fixed header of cmd_purchase_item. Rest of packet is item_count x cmd_purchase_item_ITEM.</summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_purchase_item_header
|
||||
{
|
||||
public uint cost;
|
||||
public uint yinpiao;
|
||||
public byte flag;
|
||||
public ushort item_count;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct cmd_get_own_money
|
||||
@@ -1394,7 +1414,7 @@ namespace CSNetwork.GPDataType
|
||||
public byte index;
|
||||
};
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct cmd_pickup_item
|
||||
public struct cmd_pickup_item
|
||||
{
|
||||
public int tid;
|
||||
public int expire_date;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,6 @@ using CSNetwork.GPDataType;
|
||||
using CSNetwork.S2CCommand;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using static BrewMonster.EC_Resource;
|
||||
using static BrewMonster.IconResourceType;
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using static BrewMonster.SkillArrayWrapper;
|
||||
|
||||
namespace BrewMonster
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
namespace BrewMonster.Scripts.Skills
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
namespace BrewMonster.Scripts.Task.UI
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using static UnityEngine.Rendering.DebugUI;
|
||||
|
||||
namespace BrewMonster.UI
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
|
||||
private GShopItem currentItem;
|
||||
private NPCShopUIManager shopManager;
|
||||
private int shopItemIndex;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -39,10 +40,11 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
buyButton.onClick.AddListener(OnBuyButtonClicked);
|
||||
}
|
||||
|
||||
public void SetupDetailPanel(GShopItem item, NPCShopUIManager manager)
|
||||
public void SetupDetailPanel(GShopItem item, NPCShopUIManager manager, int index)
|
||||
{
|
||||
currentItem = item;
|
||||
shopManager = manager;
|
||||
shopItemIndex = index;
|
||||
|
||||
UpdateDisplay();
|
||||
}
|
||||
@@ -189,17 +191,19 @@ public class NPCShopDetailPanel : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// Create npc_trade_item array for buying from NPC
|
||||
// The tid is the item template ID, index is shop item index (0 for now), count is quantity to buy
|
||||
// Server requires SEVNPC_HELLO with NPC id before buy, and the correct shop slot index
|
||||
if (shopManager != null && shopManager.CurrentNPCID != 0)
|
||||
UnityGameSession.c2s_CmdNPCSevHello((int)shopManager.CurrentNPCID);
|
||||
|
||||
// Create npc_trade_item: tid = template ID, index = shop slot (server validates this), count = quantity
|
||||
npc_trade_item[] items = new npc_trade_item[1];
|
||||
items[0] = new npc_trade_item
|
||||
{
|
||||
tid = (int)currentItem.id,
|
||||
index = 0, // Shop item index - may need to be determined from shop item position
|
||||
count = 1 // Quantity to buy
|
||||
index = (uint)shopItemIndex,
|
||||
count = 1
|
||||
};
|
||||
|
||||
// Send the buy command
|
||||
UnityGameSession.c2s_CmdNPCSevBuy(1, items);
|
||||
|
||||
Debug.Log($"[NPCShopDetailPanel] Sent buy command for item {currentItem.id}, price {price}");
|
||||
|
||||
@@ -19,6 +19,7 @@ public class NPCShopItemPanel : MonoBehaviour
|
||||
private GShopItem itemData;
|
||||
private Coroutine iconLoadCoroutine;
|
||||
private NPCShopUIManager shopManager;
|
||||
private int shopItemIndex;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -54,10 +55,11 @@ public class NPCShopItemPanel : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupItem(GShopItem item, NPCShopUIManager manager)
|
||||
public void SetupItem(GShopItem item, NPCShopUIManager manager, int index)
|
||||
{
|
||||
itemData = item;
|
||||
shopManager = manager;
|
||||
shopItemIndex = index;
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
@@ -65,7 +67,7 @@ public class NPCShopItemPanel : MonoBehaviour
|
||||
{
|
||||
if (shopManager != null && itemData.id != 0)
|
||||
{
|
||||
shopManager.ShowItemDetail(itemData);
|
||||
shopManager.ShowItemDetail(itemData, shopItemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
private int currentTabIndex = 0;
|
||||
private uint currentNPCID = 0;
|
||||
private NPC_SELL_SERVICE? cachedSellService = null;
|
||||
|
||||
/// <summary>Current NPC id for this shop session. Send SEVNPC_HELLO with this before buy.</summary>
|
||||
public uint CurrentNPCID => currentNPCID;
|
||||
private NPCShopDetailPanel detailPanelScript;
|
||||
|
||||
void Start()
|
||||
@@ -278,8 +281,9 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
if (elementDataMan == null)
|
||||
return;
|
||||
|
||||
foreach (var good in page.goods)
|
||||
for (int i = 0; i < page.goods.Length; i++)
|
||||
{
|
||||
var good = page.goods[i];
|
||||
if (good.id == 0)
|
||||
continue;
|
||||
|
||||
@@ -293,8 +297,8 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
// Create GShopItem
|
||||
GShopItem shopItem = CreateShopItemFromGood(good, itemData, itemDataType);
|
||||
|
||||
// Create panel
|
||||
CreateItemPanel(shopItem);
|
||||
// Create panel with shop slot index (server expects this in npc_trade_item.index)
|
||||
CreateItemPanel(shopItem, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -372,7 +376,7 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
return shopItem;
|
||||
}
|
||||
|
||||
void CreateItemPanel(GShopItem item)
|
||||
void CreateItemPanel(GShopItem item, int shopItemIndex)
|
||||
{
|
||||
if (itemPanelPrefab == null || itemContainer == null)
|
||||
return;
|
||||
@@ -386,7 +390,7 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
|
||||
if (itemPanelScript != null)
|
||||
{
|
||||
itemPanelScript.SetupItem(item, this);
|
||||
itemPanelScript.SetupItem(item, this, shopItemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -406,7 +410,7 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
currentItemPanels.Clear();
|
||||
}
|
||||
|
||||
public void ShowItemDetail(GShopItem item)
|
||||
public void ShowItemDetail(GShopItem item, int shopItemIndex)
|
||||
{
|
||||
if (item.id == 0)
|
||||
return;
|
||||
@@ -428,7 +432,7 @@ public class NPCShopUIManager : MonoBehaviour
|
||||
if (detailPanelScript != null)
|
||||
{
|
||||
npcShopDetailPanel.SetActive(true);
|
||||
detailPanelScript.SetupDetailPanel(item, this);
|
||||
detailPanelScript.SetupDetailPanel(item, this, shopItemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.Managers;
|
||||
@@ -22,12 +22,76 @@ namespace BrewMonster
|
||||
var data = Msg.dwParam1 as byte[];
|
||||
int cmd = Convert.ToInt32(Msg.dwParam2);
|
||||
int hostId = Convert.ToInt32(Msg.dwParam3);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CommandID.OWN_IVTR_DATA:
|
||||
{
|
||||
LogInventoryPacket("OWN_IVTR_DATA", data, hostId);
|
||||
|
||||
// C++: pPack->ResetItems(*pCmd) where cmd_own_ivtr_info.content is a compact stream:
|
||||
// for each slot [0..ivtr_size): tid (int); if tid>=0 then expire_date (int) and amount (int).
|
||||
if (data != null && data.Length >= 6)
|
||||
{
|
||||
byte byPackage = data[0];
|
||||
byte ivtrSize = data[1];
|
||||
uint contentLength = BitConverter.ToUInt32(data, 2);
|
||||
int index = 6;
|
||||
int remaining = data.Length - index;
|
||||
int contentBytes = remaining;
|
||||
if (contentLength < (uint)remaining)
|
||||
contentBytes = (int)contentLength;
|
||||
|
||||
var inv = GetInventory(byPackage);
|
||||
if (inv != null)
|
||||
{
|
||||
inv.Resize(ivtrSize);
|
||||
inv.RemoveAllItems();
|
||||
|
||||
int end = index + Math.Max(0, contentBytes);
|
||||
for (int slot = 0; slot < ivtrSize; slot++)
|
||||
{
|
||||
if (index + 4 > end)
|
||||
break;
|
||||
int tid = BitConverter.ToInt32(data, index);
|
||||
index += 4;
|
||||
if (tid < 0)
|
||||
{
|
||||
inv.SetItem(slot, null);
|
||||
continue;
|
||||
}
|
||||
if (index + 8 > end)
|
||||
break;
|
||||
int expireDate = BitConverter.ToInt32(data, index);
|
||||
index += 4;
|
||||
int amount = BitConverter.ToInt32(data, index);
|
||||
index += 4;
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
var item = EC_IvtrItem.CreateItem(tid, expireDate, amount);
|
||||
if (item != null)
|
||||
{
|
||||
item.Package = byPackage;
|
||||
item.Slot = slot;
|
||||
item.SetCount(amount);
|
||||
inv.SetItem(slot, item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inv.SetItem(slot, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK)
|
||||
{
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
ui?.RefreshAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CommandID.OWN_IVTR_DETAIL_DATA:
|
||||
@@ -71,6 +135,19 @@ namespace BrewMonster
|
||||
|
||||
break;
|
||||
}
|
||||
case CommandID.CHANGE_IVTR_SIZE:
|
||||
{
|
||||
// C++: resize pack (normal inventory)
|
||||
if (data != null && data.Length >= 4)
|
||||
{
|
||||
int newSize = BitConverter.ToInt32(data, 0);
|
||||
if (m_pPack != null)
|
||||
m_pPack.Resize(newSize);
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
ui?.RefreshAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CommandID.GET_OWN_MONEY:
|
||||
{
|
||||
if (data != null)
|
||||
@@ -168,14 +245,13 @@ namespace BrewMonster
|
||||
{
|
||||
case CommandID.OWN_ITEM_INFO:
|
||||
{
|
||||
//Debug.Log("[Inventory] OWN_ITEM_INFO received");
|
||||
//var data = Msg.dwParam1 as byte[];
|
||||
//int hostId = Convert.ToInt32(Msg.dwParam3);
|
||||
//LogInventoryPacket("OWN_ITEM_INFO", data, hostId);
|
||||
if (Application.isEditor || Debug.isDebugBuild)
|
||||
Debug.Log($"[INVNET] HST_OWNITEMINFO cmd=OWN_ITEM_INFO bytes={(Msg.dwParam1 as byte[])?.Length ?? 0}");
|
||||
|
||||
//Handmade
|
||||
// Match C++ cmd_own_item_info layout and behavior: update an existing item in place.
|
||||
// If the slot is missing (can happen if client missed OWN_IVTR_DATA), create it to match server state.
|
||||
var data = Msg.dwParam1 as byte[];
|
||||
if (data == null || data.Length == 0)
|
||||
if (data == null || data.Length < 22)
|
||||
return;
|
||||
|
||||
byte byPackage = data[0];
|
||||
@@ -184,7 +260,6 @@ namespace BrewMonster
|
||||
int expire_date = BitConverter.ToInt32(data, 6);
|
||||
int state = BitConverter.ToInt32(data, 10);
|
||||
uint count = BitConverter.ToUInt32(data, 14);
|
||||
ushort crc = BitConverter.ToUInt16(data, 18);
|
||||
ushort content_length = BitConverter.ToUInt16(data, 20);
|
||||
|
||||
byte[] content = null;
|
||||
@@ -192,38 +267,45 @@ namespace BrewMonster
|
||||
{
|
||||
content = new byte[content_length];
|
||||
Buffer.BlockCopy(data, 22, content, 0, content_length);
|
||||
|
||||
string hexDebug = BitConverter.ToString(content);
|
||||
//Debug.Log($"[OWN_ITEM_INFO] Full Content Hex ({content_length} bytes): {hexDebug}");
|
||||
}
|
||||
|
||||
//Debug.Log($"[OWN_ITEM_INFO] Parsed: package={byPackage}, slot={bySlot}, tid={type}, count={count}, content_len={content_length}");
|
||||
|
||||
EC_Inventory pInventory = GetInventory(byPackage);
|
||||
EC_IvtrItem newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)count);
|
||||
if (pInventory == null)
|
||||
return;
|
||||
|
||||
if (newItem != null)
|
||||
if (bySlot >= pInventory.GetSize())
|
||||
pInventory.Resize(bySlot + 1);
|
||||
|
||||
var pItem = pInventory.GetItem(bySlot, false);
|
||||
if (pItem == null)
|
||||
{
|
||||
newItem.SetProcType(state);
|
||||
|
||||
newItem.GetDetailDataFromLocal();
|
||||
if (content != null && content.Length > 0)
|
||||
{
|
||||
newItem.SetItemInfo(content, content_length);
|
||||
}
|
||||
|
||||
pInventory.SetItem(bySlot, newItem);
|
||||
|
||||
//Debug.Log($"[OWN_ITEM_INFO] Fixed Update: Pack {byPackage} Slot {bySlot} - Type {type}");
|
||||
pItem = EC_IvtrItem.CreateItem(type, expire_date, (int)count);
|
||||
if (pItem == null)
|
||||
return;
|
||||
pItem.Package = byPackage;
|
||||
pItem.Slot = bySlot;
|
||||
pInventory.SetItem(bySlot, pItem);
|
||||
}
|
||||
|
||||
pItem.SetExpireDate(expire_date);
|
||||
pItem.SetProcType(state);
|
||||
pItem.SetAmount((int)count);
|
||||
if (content != null && content.Length > 0)
|
||||
pItem.SetItemInfo(content, content.Length);
|
||||
else
|
||||
pItem.SetItemInfo(null, 0);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Debug.Log($"[Inventory] OWN_ITEM_INFO pkg={byPackage} slot={bySlot} tid={type} count={count} contentLen={content_length}");
|
||||
#endif
|
||||
|
||||
if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK)
|
||||
{
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
else if (byPackage == InventoryConst.IVTRTYPE_PACK)
|
||||
{
|
||||
if (newItem.IsEquipment())
|
||||
if (pItem != null && pItem.IsEquipment())
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
@@ -342,7 +424,7 @@ namespace BrewMonster
|
||||
}
|
||||
|
||||
// Trigger UI refresh if an EC_InventoryUI is present in scene
|
||||
var ui = GameObject.FindObjectOfType<EC_InventoryUI>();
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
if (ui != null)
|
||||
{
|
||||
ui.RefreshAll();
|
||||
@@ -354,208 +436,215 @@ namespace BrewMonster
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message MSG_HST_PICKUPITEM handler. Matches C++ flow: switch only fills idItem/iExpireDate/iAmount/iCmdLastSlot/iCmdSlotAmount/iPack/iMsg;
|
||||
/// then single common path: MergeItem (or PutItemInSlot to match server slot), GetItemInfo request for equipment, notifications, RefreshAll.
|
||||
/// </summary>
|
||||
public void OnMsgHstPickupItem(in ECMSG Msg)
|
||||
{
|
||||
var data = Msg.dwParam1 as byte[];
|
||||
int cmd = Convert.ToInt32(Msg.dwParam2);
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
if (Application.isEditor || Debug.isDebugBuild)
|
||||
Debug.Log($"[INVNET] HST_PICKUPITEM cmd={cmd} bytes={data.Length}");
|
||||
|
||||
bool bDoOther = false;
|
||||
int idItem, iExpireDate = 0, iAmount, iCmdLastSlot, iCmdSlotAmount, iPack, iMsg = -1;
|
||||
int idItem = 0, iExpireDate = 0, iAmount = 0, iCmdLastSlot = 0, iCmdSlotAmount = 0, iPack = 0, iMsg = -1;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CommandID.HOST_OBTAIN_ITEM:
|
||||
{
|
||||
// Parse cmd_host_obtain_item struct data
|
||||
int type = BitConverter.ToInt32(data, 0);
|
||||
int expire_date = BitConverter.ToInt32(data, 4);
|
||||
uint amount = BitConverter.ToUInt32(data, 8);
|
||||
uint slot_amount = BitConverter.ToUInt32(data, 12);
|
||||
byte where = data[16]; // Package index
|
||||
byte index = data[17]; // Slot index in that package
|
||||
var newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)amount);
|
||||
|
||||
// Add item to inventory
|
||||
var ivt = GetInventory(where);
|
||||
if (newItem.Content != null && newItem.Content.Length > 0)
|
||||
{
|
||||
newItem.SetItemInfo(newItem.Content, newItem.Content.Length);
|
||||
}
|
||||
ivt.SetItem(index, newItem);
|
||||
|
||||
Debug.Log(
|
||||
$"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}");
|
||||
|
||||
// Trigger UI refresh if an EC_InventoryUI is present in scene
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
if (ui != null)
|
||||
{
|
||||
ui.RefreshAll();
|
||||
}
|
||||
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
break;
|
||||
case CommandID.PICKUP_ITEM:
|
||||
{
|
||||
int tid = BitConverter.ToInt32(data, 0);
|
||||
int expire_date = BitConverter.ToInt32(data, 4);
|
||||
iAmount = (int)BitConverter.ToUInt32(data, 8);
|
||||
uint iSlotAmount = BitConverter.ToUInt32(data, 12);
|
||||
byte byPackage = data[16];
|
||||
byte bySlot = data[17];
|
||||
|
||||
//Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}");
|
||||
|
||||
// Notify pickupItem script about successful pickup
|
||||
pickupItem pickupScript = pickupItem.Instance;
|
||||
if (pickupScript != null)
|
||||
{
|
||||
//Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}");
|
||||
|
||||
// Notify pickupItem script about successful pickup
|
||||
pickupScript = UnityEngine.Object.FindFirstObjectByType<pickupItem>();
|
||||
if (pickupScript != null)
|
||||
{
|
||||
pickupScript.OnPickupSuccess(tid);
|
||||
}
|
||||
|
||||
// Create new inventory item data
|
||||
var newItem = EC_IvtrItem.CreateItem(tid, expire_date, (int)iAmount);
|
||||
|
||||
// Add item to inventory
|
||||
var ivt = GetInventory(byPackage);
|
||||
ivt.SetItem(bySlot, newItem);
|
||||
|
||||
//Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}");
|
||||
|
||||
// Trigger UI refresh if an EC_InventoryUI is present in scene
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
if (ui != null)
|
||||
{
|
||||
ui.RefreshAll();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length");
|
||||
}
|
||||
|
||||
var pCmdPickup = GPDataTypeHelper.FromBytes<cmd_pickup_item>(data);
|
||||
idItem = pCmdPickup.tid;
|
||||
iExpireDate = pCmdPickup.expire_date;
|
||||
iAmount = (int)pCmdPickup.iAmount;
|
||||
iCmdLastSlot = pCmdPickup.bySlot;
|
||||
iCmdSlotAmount = (int)pCmdPickup.iSlotAmount;
|
||||
iPack = pCmdPickup.byPackage;
|
||||
iMsg = (int)FixedMsg.FIXMSG_PICKUPITEM;
|
||||
break;
|
||||
}
|
||||
case CommandID.HOST_OBTAIN_ITEM:
|
||||
{
|
||||
var pCmdObtain = GPDataTypeHelper.FromBytes<cmd_host_obtain_item>(data);
|
||||
idItem = pCmdObtain.type;
|
||||
iExpireDate = pCmdObtain.expire_date;
|
||||
iAmount = (int)pCmdObtain.amount;
|
||||
iCmdLastSlot = pCmdObtain.index;
|
||||
iCmdSlotAmount = (int)pCmdObtain.slot_amount;
|
||||
iPack = pCmdObtain.where;
|
||||
iMsg = (int)FixedMsg.FIXMSG_GAINITEM;
|
||||
break;
|
||||
}
|
||||
case CommandID.PRODUCE_ONCE:
|
||||
{
|
||||
var pCmdProduce = GPDataTypeHelper.FromBytes<cmd_produce_once>(data);
|
||||
idItem = pCmdProduce.type;
|
||||
iExpireDate = 0;
|
||||
iAmount = (int)pCmdProduce.amount;
|
||||
iCmdLastSlot = pCmdProduce.index;
|
||||
iCmdSlotAmount = (int)pCmdProduce.slot_amount;
|
||||
iPack = pCmdProduce.where;
|
||||
iMsg = (int)FixedMsg.FIXMSG_PRODUCEITEM;
|
||||
var dlgProduce = UnityEngine.Object.FindFirstObjectByType<DlgProduce>();
|
||||
dlgProduce?.OnProduceOnce(pCmdProduce);
|
||||
break;
|
||||
}
|
||||
case CommandID.TASK_DELIVER_ITEM:
|
||||
cmd_task_deliver_item pCmd = GPDataTypeHelper.FromBytes<cmd_task_deliver_item>(data);
|
||||
// ASSERT(pCmd);
|
||||
|
||||
idItem = pCmd.type;
|
||||
iExpireDate = pCmd.expire_date;
|
||||
iAmount = (int)pCmd.amount;
|
||||
iCmdLastSlot = pCmd.index;
|
||||
iCmdSlotAmount = (int)pCmd.slot_amount;
|
||||
iPack = pCmd.where;
|
||||
{
|
||||
var pCmdTask = GPDataTypeHelper.FromBytes<cmd_task_deliver_item>(data);
|
||||
idItem = pCmdTask.type;
|
||||
iExpireDate = pCmdTask.expire_date;
|
||||
iAmount = (int)pCmdTask.amount;
|
||||
iCmdLastSlot = pCmdTask.index;
|
||||
iCmdSlotAmount = (int)pCmdTask.slot_amount;
|
||||
iPack = pCmdTask.where;
|
||||
iMsg = (int)FixedMsg.FIXMSG_GAINITEM;
|
||||
bDoOther = true;
|
||||
|
||||
|
||||
// Create new inventory item data
|
||||
var taskNewItem = EC_IvtrItem.CreateItem(idItem, iExpireDate, (int)iAmount);
|
||||
|
||||
// Add item to inventory
|
||||
var task_ivt = GetInventory((byte)iPack);
|
||||
if (!task_ivt.MergeItem(idItem, iExpireDate, iAmount, out var iLastSlot, out var iSlotNum) ||
|
||||
iLastSlot != iCmdLastSlot || iSlotNum != iCmdSlotAmount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
task_ivt.SetItem(iCmdLastSlot, taskNewItem);
|
||||
|
||||
//Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}");
|
||||
|
||||
// Trigger UI refresh if an EC_InventoryUI is present in scene
|
||||
var task_ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
if (task_ui != null)
|
||||
{
|
||||
task_ui.RefreshAll();
|
||||
}
|
||||
|
||||
break;
|
||||
case CommandID.PRODUCE_ONCE:
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Debug.Log($"[Inventory] PICKUP_FLOW cmd={cmd} pack={iPack} slot={iCmdLastSlot} tid={idItem} amt={iAmount} slotAmt={iCmdSlotAmount}");
|
||||
#endif
|
||||
EC_Inventory pInventory = GetPack(iPack);
|
||||
if (pInventory == null)
|
||||
return;
|
||||
|
||||
if (iCmdLastSlot >= pInventory.GetSize())
|
||||
pInventory.Resize(iCmdLastSlot + 1);
|
||||
|
||||
bool placed = pInventory.PutItemInSlot(iCmdLastSlot, idItem, iExpireDate, iAmount, out int iLastSlot, out int iSlotNum);
|
||||
if (!placed)
|
||||
{
|
||||
placed = pInventory.MergeItem(idItem, iExpireDate, iAmount, out iLastSlot, out iSlotNum);
|
||||
if (!placed || iLastSlot != iCmdLastSlot || iSlotNum != iCmdSlotAmount)
|
||||
{
|
||||
// Parse cmd_produce_once struct data
|
||||
cmd_produce_once produceCmd = GPDataTypeHelper.FromBytes<cmd_produce_once>(data);
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning($"[Inventory] PICKUP_FLOW desync: placed={placed} lastSlot={iLastSlot} slotNum={iSlotNum} expectedSlot={iCmdLastSlot} expectedSlotAmt={iCmdSlotAmount}");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int produceItemId = produceCmd.type;
|
||||
int produceExpireDate = 0;
|
||||
uint produceAmount = produceCmd.amount;
|
||||
byte producePack = produceCmd.where;
|
||||
byte produceSlot = produceCmd.index;
|
||||
if (cmd == CommandID.HOST_OBTAIN_ITEM && iPack == Inventory_type.IVTRTYPE_PACK)
|
||||
{
|
||||
// C++: CECShoppingManager::Instance().OnObtainItem(iPack, idItem, iAmount);
|
||||
}
|
||||
|
||||
Debug.Log(
|
||||
$"[PRODUCE_ONCE] Received: itemId={produceItemId}, amount={produceAmount}, pack={producePack}, slot={produceSlot}");
|
||||
EC_IvtrItem pItem = pInventory.GetItem(iCmdLastSlot, false);
|
||||
if (pItem != null)
|
||||
{
|
||||
pItem.Package = (byte)iPack;
|
||||
pItem.Slot = iCmdLastSlot;
|
||||
int cid = pItem.GetClassID();
|
||||
if (pItem.IsEquipment() ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKNMMATTER ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKITEM ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN_EXPPILL ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGBOOKCARD ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGINVITECARD ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_SKILLTOME ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_PETEGG)
|
||||
{
|
||||
UnityGameSession.c2s_CmdGetItemInfo((byte)iPack, (byte)iCmdLastSlot);
|
||||
}
|
||||
if (iMsg >= 0)
|
||||
{
|
||||
CECGameRun pGameRun = EC_Game.GetGameRun();
|
||||
pGameRun?.AddFixedMessage(iMsg, iAmount, pItem.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
// Get inventory
|
||||
var produce_ivt = GetInventory(producePack);
|
||||
if (produce_ivt == null)
|
||||
if (bDoOther)
|
||||
{
|
||||
// C++: m_pTaskInterface->DoAutoTeamForTask(idItem);
|
||||
}
|
||||
|
||||
if (cmd == CommandID.PICKUP_ITEM)
|
||||
{
|
||||
var pickupScript = UnityEngine.Object.FindFirstObjectByType<pickupItem>();
|
||||
pickupScript?.OnPickupSuccess(idItem);
|
||||
}
|
||||
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
ui?.RefreshAll();
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
|
||||
/// <summary>Buy from NPC/booth: server sends PURCHASE_ITEM (cmd_purchase_item). C++ OnMsgHstPurchaseItems.</summary>
|
||||
public void OnMsgHstPurchaseItems(ECMSG Msg)
|
||||
{
|
||||
var data = Msg.dwParam1 as byte[];
|
||||
if (data == null || data.Length < 11)
|
||||
return;
|
||||
|
||||
var header = GPDataTypeHelper.FromBytes<cmd_purchase_item_header>(data);
|
||||
int index = 11;
|
||||
const int itemSize = 15; // item_id(4) + expire_date(4) + count(4) + inv_index(2) + booth_slot(1)
|
||||
EC_Inventory pPack = GetPack(Inventory_type.IVTRTYPE_PACK);
|
||||
if (pPack == null)
|
||||
return;
|
||||
|
||||
var slotsNeedingDetail = new System.Collections.Generic.List<byte>();
|
||||
|
||||
for (int i = 0; i < header.item_count && index + itemSize <= data.Length; i++)
|
||||
{
|
||||
int item_id = BitConverter.ToInt32(data, index); index += 4;
|
||||
int expire_date = BitConverter.ToInt32(data, index); index += 4;
|
||||
int count = (int)BitConverter.ToUInt32(data, index); index += 4;
|
||||
ushort inv_index = BitConverter.ToUInt16(data, index); index += 2;
|
||||
index += 1; // booth_slot
|
||||
|
||||
if (inv_index >= pPack.GetSize())
|
||||
pPack.Resize(inv_index + 1);
|
||||
|
||||
bool placed = pPack.PutItemInSlot(inv_index, item_id, expire_date, count, out int lastSlot, out int slotNum);
|
||||
if (!placed)
|
||||
{
|
||||
placed = pPack.MergeItem(item_id, expire_date, count, out lastSlot, out slotNum);
|
||||
if (!placed || lastSlot != inv_index)
|
||||
continue;
|
||||
}
|
||||
|
||||
var pItem = pPack.GetItem(inv_index, false);
|
||||
if (pItem != null)
|
||||
{
|
||||
pItem.Package = (byte)Inventory_type.IVTRTYPE_PACK;
|
||||
pItem.Slot = inv_index;
|
||||
int cid = pItem.GetClassID();
|
||||
if (pItem.IsEquipment() ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKNMMATTER ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_TASKITEM ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN_EXPPILL ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGBOOKCARD ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_WEDDINGINVITECARD ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_SKILLTOME ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_GOBLIN ||
|
||||
cid == (int)EC_IvtrItem.InventoryClassId.ICID_PETEGG)
|
||||
{
|
||||
Debug.LogWarning($"[PRODUCE_ONCE] Invalid inventory package {producePack}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the slot already has an item
|
||||
var existingItem = produce_ivt.GetItem(produceSlot, false);
|
||||
|
||||
if (existingItem != null)
|
||||
{
|
||||
if (existingItem.m_tid == produceItemId)
|
||||
{
|
||||
existingItem.m_iCount = (int)produceAmount;
|
||||
Debug.Log(
|
||||
$"[PRODUCE_ONCE] Updated existing item count at slot {produceSlot} to {produceAmount}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[PRODUCE_ONCE] Slot {produceSlot} already has different item (tid={existingItem.m_tid}), not overwriting with {produceItemId}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var produceNewItem = new EC_IvtrItem
|
||||
{
|
||||
Package = producePack,
|
||||
Slot = produceSlot,
|
||||
m_tid = produceItemId,
|
||||
m_expire_date = produceExpireDate,
|
||||
State = 0,
|
||||
m_iCount = (int)produceAmount,
|
||||
Crc = 0,
|
||||
Content = null
|
||||
};
|
||||
|
||||
produce_ivt.SetItem(produceSlot, produceNewItem);
|
||||
Debug.Log($"[PRODUCE_ONCE] Created new item at slot {produceSlot} with count {produceAmount}");
|
||||
}
|
||||
|
||||
// Trigger UI refresh
|
||||
var produce_ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
if (produce_ui != null)
|
||||
{
|
||||
produce_ui.RefreshAll();
|
||||
}
|
||||
|
||||
UpdateEquipSkins();
|
||||
|
||||
// Notify DlgProduce
|
||||
var dlgProduce = GameObject.FindFirstObjectByType<DlgProduce>();
|
||||
if (dlgProduce != null)
|
||||
{
|
||||
dlgProduce.OnProduceOnce(produceCmd);
|
||||
slotsNeedingDetail.Add((byte)inv_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
AddMoneyAmount(-(int)header.cost);
|
||||
|
||||
foreach (byte slot in slotsNeedingDetail)
|
||||
UnityGameSession.c2s_CmdGetItemInfo((byte)Inventory_type.IVTRTYPE_PACK, slot);
|
||||
|
||||
var ui = GameObject.FindFirstObjectByType<EC_InventoryUI>();
|
||||
ui?.RefreshAll();
|
||||
UpdateEquipSkins();
|
||||
}
|
||||
|
||||
private void OnMsgHstUseItem(ECMSG Msg)
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace BrewMonster
|
||||
private CECHPWorkMan m_pWorkMan; // Host work manager
|
||||
private uint m_dwLIES; // Logic-influence extend states
|
||||
private FACTION_FORTRESS_ENTER m_fortressEnter; // ½øÈë»ùµØÐÅÏ¢
|
||||
private PVPINFO m_pvp; // pvp information
|
||||
private bool m_bInSanctuary = false; // true, player is in sanctuary
|
||||
private int m_idFaction = 0; // ID of player's faction
|
||||
//private PVPINFO m_pvp; // pvp information
|
||||
//private bool m_bInSanctuary = false; // true, player is in sanctuary
|
||||
//private int m_idFaction = 0; // ID of player's faction
|
||||
public bool m_bPrepareFight = false; // true, prepare to fight
|
||||
private int m_iJumpCount = 0;
|
||||
private bool m_bJumpInWater = false;
|
||||
@@ -565,6 +565,9 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_PICKUPITEM:
|
||||
OnMsgHstPickupItem(Msg);
|
||||
break;
|
||||
case EC_MsgDef.MSG_HST_PURCHASEITEMS:
|
||||
OnMsgHstPurchaseItems(Msg);
|
||||
break;
|
||||
case EC_MsgDef.MSG_HST_PRODUCEITEM:
|
||||
OnMsgHstProduceItem(Msg);
|
||||
break;
|
||||
@@ -1467,10 +1470,10 @@ namespace BrewMonster
|
||||
}
|
||||
|
||||
// Get faction ID
|
||||
public int GetFactionID()
|
||||
{
|
||||
return m_idFaction;
|
||||
}
|
||||
//public int GetFactionID()
|
||||
//{
|
||||
// return m_idFaction;
|
||||
//}
|
||||
public void SetPrayDistancePlus(float prayDistancePlus)
|
||||
{
|
||||
m_fPrayDistancePlus = prayDistancePlus;
|
||||
|
||||
Reference in New Issue
Block a user