Merge pull request 'fixbug/npc-dialog' (#333) from fixbug/npc-dialog into develop

Reviewed-on: https://git.pthub.vn/Unity/perfect-world-unity/pulls/333
This commit is contained in:
hungdk
2026-04-13 06:40:00 +00:00
5 changed files with 143 additions and 11 deletions
@@ -17,6 +17,12 @@ public class GShopLoader : MonoBehaviour
[Header("Loaded Data")]
public GShopData primaryShop = new GShopData();
public GShopData secondaryShop = new GShopData();
/// <summary>True after gshop.txt has been loaded and parsed successfully.</summary>
public bool IsPrimaryShopLoaded { get; private set; }
/// <summary>Invoked once when <see cref="primaryShop"/> data is ready.</summary>
public event Action OnPrimaryShopLoaded;
async void Start()
{
@@ -37,6 +43,8 @@ public class GShopLoader : MonoBehaviour
if (await LoadShopData(GSHOP_ADDRESS, primaryShop))
{
Debug.Log($"Primary shop loaded: {primaryShop.items.Count} items, {primaryShop.mainTypes.Count} categories");
IsPrimaryShopLoaded = true;
OnPrimaryShopLoaded?.Invoke();
//LogShopData("Primary Shop", primaryShop);
}
@@ -1036,9 +1036,9 @@ namespace BrewMonster.Scripts.Task.UI
// Only update description and name if task changed
if( idTask != m_idLastTask )
{
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(GetTaskNameWithColor(pTemp)));
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(CECUIHelper.FormatCoordText(GetTaskNameWithColor(pTemp))));
//pTextDesc->SetText(FormatTaskText(pTemp->GetDescription(), pTextDesc->GetColor()));
pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(pTemp.GetDescription()));
pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(CECUIHelper.FormatCoordText(pTemp.GetDescription())));
m_idLastTask = idTask;
bLastTaskChanged = true;
}
@@ -1154,9 +1154,9 @@ namespace BrewMonster.Scripts.Task.UI
// Update description when the selected task changes
if (idTask != m_idLastTask)
{
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(GetTaskNameWithColor(pTemp)));
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(CECUIHelper.FormatCoordText(GetTaskNameWithColor(pTemp))));
Debug.Log("[DlgTask] SearchForTask name task: " + _nameTaskText.text);
if (pTextDesc != null) pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(pTemp.GetDescription()));
if (pTextDesc != null) pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(CECUIHelper.FormatCoordText(pTemp.GetDescription())));
m_idLastTask = idTask;
bLastTaskChanged = true;
}
@@ -1619,7 +1619,7 @@ namespace BrewMonster.Scripts.Task.UI
// UnityEngine.UI.ScrollRect scrollRect = pTextItem.GetComponentInParent<UnityEngine.UI.ScrollRect>();
// float oldNormPos = scrollRect != null ? scrollRect.verticalNormalizedPosition : 0f;
string formatted = EC_Utility.FormatForTextMeshPro(strNewTextItem ?? string.Empty);
string formatted = EC_Utility.FormatForTextMeshPro(CECUIHelper.FormatCoordText(strNewTextItem ?? string.Empty));
if (!string.Equals(formatted, pTextItem.text))
{
pTextItem.text = formatted;
@@ -602,7 +602,7 @@ namespace BrewMonster.Scripts.Task.UI
bool bCanContributionFinish = !hasContributionAward;
// ACString strTask = pTempl->GetName();
string strTask = pTempl.GetDescription();
string strTask = CECUIHelper.FormatCoordText(pTempl.GetDescription());
// ʾһ
if (topLevel)
{
+94 -1
View File
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using BrewMonster.Network;
using BrewMonster.Managers;
using ModelRenderer.Scripts.Common;
using ModelRenderer.Scripts.GameData;
using BrewMonster.Scripts.Task;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Chat;
@@ -102,7 +105,7 @@ namespace BrewMonster.Scripts.UI
// Fallback to coord_data.txt (C++: Configs/Coord_data.txt via CECGame::GetObjectCoord)
// 回退到 coord_data.txtC++Configs/Coord_data.txt,通过 CECGame::GetObjectCoord
if (BrewMonster.Network.EC_Game.TryGetFirstObjectCoord(id.ToString(), out var coordPos, out var mapName))
if (global::BrewMonster.Network.EC_Game.TryGetFirstObjectCoord(id.ToString(), out var coordPos, out var mapName))
{
in_table = true;
BMLogger.Log(
@@ -372,6 +375,96 @@ namespace BrewMonster.Scripts.UI
EC_ManMessage.PostMessage(0, 0, 0, msg);
}
/// <summary>
/// PW client: <c>CECUIHelper::FormatCoordText</c> — replaces <c>@essenceId@</c> (monster template) and
/// <c>$essenceId$</c> (NPC or mine template) with display names; when coordinates exist, wraps the name in a TMP
/// coord link like the main quest UI.
/// </summary>
public static string FormatCoordText(string szText)
{
if (string.IsNullOrEmpty(szText))
return string.Empty;
var sb = new StringBuilder(szText.Length + 48);
int len = szText.Length;
int i = 0;
elementdataman edm = global::BrewMonster.ElementDataManProvider.GetElementDataMan();
while (i < len)
{
int segStart = i;
while (i < len && szText[i] != '@' && szText[i] != '$')
i++;
sb.Append(szText, segStart, i - segStart);
if (i >= len)
break;
char open = szText[i];
i++;
int idStart = i;
while (i < len && szText[i] != '@' && szText[i] != '$')
i++;
if (i >= len)
{
sb.Append(open);
sb.Append(szText, idStart, i - idStart);
break;
}
char flag = szText[i];
string keyword = szText.Substring(idStart, i - idStart);
i++;
if (!uint.TryParse(keyword, out uint essenceId))
{
sb.Append(open);
sb.Append(keyword);
sb.Append(flag);
continue;
}
AppendEssencePlaceholder(sb, edm, essenceId, flag);
}
return sb.ToString();
}
static void AppendEssencePlaceholder(StringBuilder sb, elementdataman edm, uint essenceId, char flag)
{
string strName = null;
if (edm != null)
{
DATA_TYPE dt = default;
object p = edm.get_data_ptr(essenceId, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (flag == '$')
{
if (dt == DATA_TYPE.DT_NPC_ESSENCE && p is NPC_ESSENCE npc)
strName = npc.Name;
else if (dt == DATA_TYPE.DT_MINE_ESSENCE && p is MINE_ESSENCE mine)
strName = ByteToStringUtils.UshortArrayToUnicodeString(mine.name);
}
else if (flag == '@')
{
if (dt == DATA_TYPE.DT_MONSTER_ESSENCE && p is MONSTER_ESSENCE mon)
strName = mon.Name;
}
}
if (string.IsNullOrEmpty(strName))
{
sb.Append("^00FF00?????^FFFFFF");
return;
}
bool inTable = false;
GetTaskObjectCoordinates((int)essenceId, ref inTable);
if (inTable)
sb.Append("<link=\"coord_").Append(essenceId).Append("\"><color=#00FF00>").Append(strName)
.Append("</color></link>");
else
sb.Append(strName);
}
public static string PolicySpecialCharReplace(
string szText,
CHAT_S2C.PolicyChatParameter pPolicyChatPara)
@@ -52,11 +52,37 @@ public class ShopUIManager : MonoBehaviour
//-1 means all sub types
public SubTypeShop subTypeShop;
private int currentSubType = -1;
private bool _shopLoaderEventsSubscribed;
void Start()
{
InitializeUI();
SetupEventListeners();
InitializePool();
SubscribeShopLoaderEvents();
}
void SubscribeShopLoaderEvents()
{
if (_shopLoaderEventsSubscribed)
return;
if (shopLoader == null)
shopLoader = FindFirstObjectByType<GShopLoader>();
if (shopLoader == null)
return;
shopLoader.OnPrimaryShopLoaded += OnPrimaryShopDataReady;
_shopLoaderEventsSubscribed = true;
// Load may have finished before we subscribed (e.g. script order).
if (shopLoader.IsPrimaryShopLoaded)
OnPrimaryShopDataReady();
}
void OnPrimaryShopDataReady()
{
if (shopMainPanel != null && shopMainPanel.activeSelf)
RefreshShopDisplay();
}
void InitializePool()
@@ -106,8 +132,10 @@ public class ShopUIManager : MonoBehaviour
{
if (shopMainPanel != null)
{
OnCategorySelected(0);
RefreshShopDisplay();
SubscribeShopLoaderEvents();
shopMainPanel.SetActive(true);
// Always apply category 0 when opening; OnCategorySelected(0) no-ops if currentCategory is already 0.
OnCategorySelected(0, forceRefresh: true);
ApplyPendingCash();
UnityGameSession.RequesrQueryPlayerCash();
}
@@ -175,9 +203,9 @@ public class ShopUIManager : MonoBehaviour
shopDetailPanel.SetActive(false);
}
void OnCategorySelected(int categoryIndex)
void OnCategorySelected(int categoryIndex, bool forceRefresh = false)
{
if (categoryIndex == currentCategory)
if (!forceRefresh && categoryIndex == currentCategory)
return;
float startTime = Time.realtimeSinceStartup;
@@ -572,6 +600,9 @@ public class ShopUIManager : MonoBehaviour
void OnDestroy()
{
if (shopLoader != null && _shopLoaderEventsSubscribed)
shopLoader.OnPrimaryShopLoaded -= OnPrimaryShopDataReady;
// Clean up pooled objects
if (useObjectPooling && itemPanelPool != null)
{