Files
test/Assets/PerfectWorld/Scripts/UI/NPCShopDetailPanel.cs
T
VuNgocHaiC7 a609ebda1c fix some UI
2026-04-07 17:00:48 +07:00

303 lines
9.2 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.
// Filename : NPCShopDetailPanel.cs
// Creator : Converted from C++ EC_Shop
// Date : 2024
using BrewMonster.Network;
using BrewMonster.Scripts;
using CSNetwork.C2SCommand;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class NPCShopDetailPanel : MonoBehaviour
{
[Header("UI Components")]
public TextOutlet itemDescriptionText;
public Image itemIconImage;
//public TextMeshProUGUI itemPriceText;
[Header("Action Buttons")]
public Button closeButton;
public Button buyButton;
private GShopItem currentItem;
private NPCShopUIManager shopManager;
private int shopItemIndex;
void Start()
{
SetupEventListeners();
}
void SetupEventListeners()
{
if (closeButton != null)
closeButton.onClick.AddListener(OnCloseClicked);
if (buyButton != null)
buyButton.onClick.AddListener(OnBuyButtonClicked);
}
public void SetupDetailPanel(GShopItem item, NPCShopUIManager manager, int index)
{
currentItem = item;
shopManager = manager;
shopItemIndex = index;
UpdateDisplay();
}
public void UpdateDisplay()
{
if (currentItem.id == 0)
{
Debug.LogWarning("[NPCShopDetailPanel] Current item ID is 0, skipping display update");
return;
}
// Set item description
if (itemDescriptionText != null)
{
string description = GetItemDescription((int)currentItem.id);
Debug.Log("[NPCShopDetail] RAW:\n" + description);
description = SanitizeDescription(description);
Debug.Log("[NPCShopDetail] Sanitized:\n" + description);
itemDescriptionText.Set(description);
}
// Set price (use first available price)
uint price = 0;
if (currentItem.buy != null && currentItem.buy.Length > 0)
{
for (int i = 0; i < currentItem.buy.Length; i++)
{
if (currentItem.buy[i].price > 0)
{
price = currentItem.buy[i].price;
break;
}
}
}
// if (itemPriceText != null)
// itemPriceText.text = price > 0 ? $"Price: {price}" : "Price: N/A";
// Load icon
if (itemIconImage != null)
{
LoadItemIcon(itemIconImage, (int)currentItem.id);
}
}
private string SanitizeDescription(string desc)
{
if (string.IsNullOrWhiteSpace(desc))
return string.Empty;
// Normalize escaped + real line breaks (including unicode line separators)
desc = Regex.Replace(
desc,
@"\\r\\n|\\n|\\r|\r\n|\r|\u2028|\u2029",
"\n",
RegexOptions.CultureInvariant);
desc = Regex.Replace(
desc,
@"\^[0-9A-Fa-f]{6}",
string.Empty,
RegexOptions.CultureInvariant);
string[] lines = desc.Split('\n');
var sb = new System.Text.StringBuilder();
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
if (string.IsNullOrWhiteSpace(line))
continue;
line = Regex.Replace(line, @"[\u200B-\u200D\uFEFF]", string.Empty, RegexOptions.CultureInvariant);
string plain = Regex.Replace(line, @"<[^>]*>", string.Empty, RegexOptions.CultureInvariant)
.Replace('', ':')
.Trim();
if (Regex.IsMatch(plain, @"^(?:ID|Price)\s*:", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
continue;
line = Regex.Replace(
line,
@"(?i)\b(?:ID|Price)\b\s*[:]\s*\d+\b",
string.Empty,
RegexOptions.CultureInvariant).Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
if (sb.Length > 0)
sb.AppendLine();
sb.Append(line);
}
return sb.ToString().Trim();
}
void LoadItemIcon(Image iconImage, int itemId)
{
if (itemId <= 0 || iconImage == null)
return;
// Ensure the Image component is enabled and properly configured
iconImage.enabled = true;
iconImage.preserveAspect = true;
iconImage.type = Image.Type.Simple;
// Use the existing icon loading system from EC_IvtrItemUtils
Sprite iconSprite = EC_IvtrItemUtils.Instance.ResolveItemIconSprite(itemId);
if (iconSprite != null)
{
iconImage.sprite = iconSprite;
iconImage.color = Color.white;
}
else
{
iconImage.sprite = null;
}
}
string GetItemDescription(int itemId)
{
// First check if description is already in the item data
if (!string.IsNullOrEmpty(currentItem.desc))
{
return currentItem.desc;
}
// Try to use EC_IvtrEquip description for equipment items (like EC_InventoryUI does)
try
{
// Create EC_IvtrEquip for equipment items - this will work for weapons and armor
EC_IvtrEquip equipment = (EC_IvtrEquip)EC_IvtrItem.CreateItem(itemId, 0, 1);
// For NPC shop items, we typically have static data only
// Try to get description using GetNormalDesc() which works with base stats
string equipDesc = equipment.GetDesc();
if (!string.IsNullOrEmpty(equipDesc))
{
// Replace C++ style "\r" line separators with real newlines for TMP
return equipDesc.Replace("\\r", "\n");
}
}
catch (System.Exception ex)
{
// If EC_IvtrEquip fails, fall through to EC_IvtrItem method
Debug.LogWarning($"[NPCShopDetailPanel] Failed to get equipment description for item {itemId}: {ex.Message}");
}
// Fallback: build description using EC_IvtrItem (for non-equipment items)
try
{
EC_IvtrItem item = EC_IvtrItem.CreateItem(itemId, 0, 1);
if (item != null)
{
// For NPC shop, we typically have static data only, so load from local DB
item.GetDetailDataFromLocal();
string description = item.GetDesc();
if (!string.IsNullOrEmpty(description))
{
return description.Replace("\\r", "\n");
}
}
}
catch (System.Exception ex)
{
Debug.LogWarning($"[NPCShopDetailPanel] Failed to get description for item {itemId}: {ex.Message}");
}
return "No description available.";
}
public void ClearText()
{
if(itemDescriptionText != null)
itemDescriptionText.Set(string.Empty);
}
void OnCloseClicked()
{
gameObject.SetActive(false);
}
void OnBuyButtonClicked()
{
if (currentItem.id == 0)
{
Debug.LogWarning("[NPCShopDetailPanel] Cannot buy item with ID 0");
return;
}
// Get price from item
uint price = 0;
if (currentItem.buy != null && currentItem.buy.Length > 0)
{
for (int i = 0; i < currentItem.buy.Length; i++)
{
if (currentItem.buy[i].price > 0)
{
price = currentItem.buy[i].price;
break;
}
}
}
// 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 = (uint)shopItemIndex,
count = 1
};
UnityGameSession.c2s_CmdNPCSevBuy(1, items);
Debug.Log($"[NPCShopDetailPanel] Sent buy command for item {currentItem.id}, price {price}");
}
void OnDestroy()
{
// Clean up event listeners
if (closeButton != null)
closeButton.onClick.RemoveListener(OnCloseClicked);
if (buyButton != null)
buyButton.onClick.RemoveListener(OnBuyButtonClicked);
}
// === Text Outlet Helper ===
[System.Serializable]
public class TextOutlet
{
[SerializeField] public Text legacy;
[SerializeField] public TMPro.TextMeshProUGUI tmp;
Color myColorDecimal = new Color(1f, 0.816f, 0.365f, 1f);
public void Set(string value)
{
if (legacy != null)
{
legacy.text = EC_Utility.FormatForLegacyText(value ?? string.Empty);
}
if (tmp != null)
{
tmp.text = EC_Utility.FormatForTextMeshPro(value ?? string.Empty);
Debug.Log($"[TextOutlet] Set text: {tmp.text}");
}
}
}
}