From 4e1e74c5adafa4296e074df8db9d06273847c84e Mon Sep 17 00:00:00 2001 From: CuongNV <> Date: Mon, 6 Apr 2026 17:50:20 +0700 Subject: [PATCH 1/3] fix bug fomat info --- .../Scripts/Network/CSNetwork/AUICommon.cs | 46 ------------------- .../Scripts/Network/CSNetwork/GameSession.cs | 17 +++---- Assets/Scripts/CECHostPlayer.cs | 2 +- Assets/Scripts/ChatInputHandler.cs | 2 +- Assets/Scripts/EC_GameRun.cs | 24 ++++------ 5 files changed, 19 insertions(+), 72 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs index 49e29e4a5f..2cc27dfac0 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs @@ -321,52 +321,6 @@ namespace CSNetwork return sb.ToString(); } - /// - /// Chuyển đổi định dạng printf (C-style: %s, %d) sang string.Format (C#-style: {0}, {1}) - /// - public static string ConvertPrintfToCSharpFormat(string format) - { - if (string.IsNullOrEmpty(format)) return ""; - - StringBuilder sb = new StringBuilder(); - int argIndex = 0; - for (int i = 0; i < format.Length; i++) - { - if (format[i] == '%' && i + 1 < format.Length) - { - char next = format[i + 1]; - if (next == '%') // Trường hợp %% -> % - { - sb.Append('%'); - i++; - } - else - { - sb.Append('{').Append(argIndex++).Append('}'); - - i++; - // Nhảy qua các ký tự định dạng (ví dụ: %02d, %ls, %f) - while (i < format.Length && (char.IsDigit(format[i]) || format[i] == '.' || format[i] == 'l' || format[i] == 'u' || format[i] == 'd' || format[i] == 's' || format[i] == 'f' || format[i] == 'x')) - { - // Nếu gặp ký tự kết thúc định dạng (s, d, f, ...) thì dừng lại sau ký tự đó - char c = format[i]; - if (c == 's' || c == 'd' || c == 'f' || c == 'u' || c == 'x' || c == 'g') - { - // i++; // Đã ở đúng vị trí để vòng lặp cha thực hiện i++ tiếp theo - break; - } - i++; - } - } - } - else - { - sb.Append(format[i]); - } - } - return sb.ToString(); - } - /// /// [Port] CECGameUIMan::FilterInvalidTags (EC_GameUIMan.cpp:6424) /// Lọc bỏ các tag đặc biệt không hợp lệ trong nội dung chat nhận từ server. diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index 7fa763edc0..ce0b9c4e3e 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -1948,7 +1948,8 @@ namespace CSNetwork string szName = pHost.GetName(); char[] szText = new char[80]; AUICommon.AUI_ConvertChatString(ref szName, ref szText, false); - string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); + Debug.Log($"[Cuong] {szText}"); + string fmt = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); string str; try { str = string.Format(fmt, szName, szMsg); @@ -2043,8 +2044,8 @@ namespace CSNetwork string strMsg = Encoding.Unicode.GetString(p.Msg.ToArray()); string strSrcName = Encoding.Unicode.GetString(p.Name.ToArray()); - - string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); + Debug.Log($"[Cuong] {strMsg}"); + string fmt = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); string formatted; try { formatted = string.Format(fmt, strSrcName, strMsg); @@ -2194,13 +2195,14 @@ namespace CSNetwork { char[] szText = new char[80]; AUICommon.AUI_ConvertChatString(ref szName,ref szText, false); - - string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); + Debug.Log($"[Cuong] {szText}"); + string fmt = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT), szText); string str = string.Format( fmt, szName, szMsg ); + Debug.Log($"[Cuong] {str} {fmt}"); // [Port] Gọi AddChatMessage để hiển thị lên UI Chat Box. // AddChatMessage bên trong đã tự publish ChatMessageEvent (cho ChatPanelUI) // VÀ EventChatMessageOnTopPlayer (cho Head Bubble) nếu channel thuộc nhóm @@ -2217,8 +2219,7 @@ namespace CSNetwork if (pNPC != null) { - string str; - string template = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT2)); + string template = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT2)); string message = string.Format( template, @@ -2261,7 +2262,7 @@ namespace CSNetwork if (p.Channel == 0 /* CHANNEL_NORMAL */ || p.Channel == 1 /* CHANNEL_NORMALRE */) { // Format: "[Name] whispers to [You]: [Message]" - string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_PRIVATECHAT1)); + string fmt = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_PRIVATECHAT1)); BMLogger.Log($"[Cuong] OnPrtcPrivateChat {fmt}"); string formatted; try { diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 9d94d64bc5..bd12ed5487 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -649,7 +649,7 @@ namespace BrewMonster cmd_pickup_money pCmd = GPDataTypeHelper.FromBytes(data); AddMoneyAmount(pCmd.amount); CECGameRun pGameRun = EC_Game.GetGameRun(); - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PICKUPMONEY); + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PICKUPMONEY, pCmd.amount); BubbleText((int)BubbleTextType.BUBBLE_MONEY, (uint)pCmd.amount); } diff --git a/Assets/Scripts/ChatInputHandler.cs b/Assets/Scripts/ChatInputHandler.cs index 09226d7ebf..b696e24255 100644 --- a/Assets/Scripts/ChatInputHandler.cs +++ b/Assets/Scripts/ChatInputHandler.cs @@ -457,7 +457,7 @@ namespace BrewMonster.Scripts.ChatUI // Tránh truyền "&target&" vì kết quả sẽ là "&&target&&" → regex chỉ match "target" // nhưng để lại & dư ở ngoài → UI hiển thị "&target&" thay vì link sạch. CECStringTab pStrTab = EC_Game.GetFixedMsgs(); - string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_PRIVATECHAT2)); + string fmt = AUIDialog.FormatPrintf(pStrTab.GetWideString((int)FixedMsg.FIXMSG_PRIVATECHAT2)); string localMsg; try { diff --git a/Assets/Scripts/EC_GameRun.cs b/Assets/Scripts/EC_GameRun.cs index 0932be7aba..71b267d14b 100644 --- a/Assets/Scripts/EC_GameRun.cs +++ b/Assets/Scripts/EC_GameRun.cs @@ -773,23 +773,19 @@ public partial class CECGameRun : ITickable return; } - // Format the message with provided arguments + // fixed_msg.txt uses printf-style (%d, %s); not C# {0} placeholders string szFormattedMsg; try { if (args != null && args.Length > 0) - { - szFormattedMsg = string.Format(szFixMsg, args); - } + szFormattedMsg = AUIDialog.FormatPrintf(szFixMsg, args); else - { szFormattedMsg = szFixMsg; - } } - catch (System.FormatException ex) + catch (Exception ex) { Debug.LogError($"[AddFixedMessage] Format error for message {iMsg}: {ex.Message}"); - szFormattedMsg = szFixMsg; // Use unformatted message as fallback + szFormattedMsg = szFixMsg; } // Try to add to in-game UI chat @@ -828,23 +824,19 @@ public partial class CECGameRun : ITickable return; } - // Format the message with provided arguments + // fixed_msg.txt uses printf-style (%d, %s); not C# {0} placeholders string szFormattedMsg; try { if (args != null && args.Length > 0) - { - szFormattedMsg = string.Format(szFixMsg, args); - } + szFormattedMsg = AUIDialog.FormatPrintf(szFixMsg, args); else - { szFormattedMsg = szFixMsg; - } } - catch (System.FormatException ex) + catch (Exception ex) { Debug.LogError($"[AddFixedChannelMsg] Format error for message {iMsg}: {ex.Message}"); - szFormattedMsg = szFixMsg; // Use unformatted message as fallback + szFormattedMsg = szFixMsg; } // Try to add to in-game UI chat with specific channel From ec632f192c797714a242b68643279241f9228d3d Mon Sep 17 00:00:00 2001 From: Le Duc Anh Date: Mon, 6 Apr 2026 17:53:25 +0700 Subject: [PATCH 2/3] show equipment --- .../Scripts/Players/PlayerModelPreview.cs | 203 +++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs index 7724b5e1d1..d6a9a17567 100644 --- a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs +++ b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using BrewMonster.Scripts.Managers; using CSNetwork.Protocols.RPCData; +using Cysharp.Threading.Tasks; using UnityEngine; namespace BrewMonster.Scripts @@ -42,7 +43,10 @@ namespace BrewMonster.Scripts for (int i = 0; i < roleInfos.Count; i++) { RoleInfo role = roleInfos[i]; - GameObject model = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender); + GameObject model = await LoadPlayerModel(role); + + if (model == null) + continue; if (version != _loadVersion) { @@ -104,5 +108,202 @@ namespace BrewMonster.Scripts playerModels.Clear(); playerModelIds.Clear(); } + + private async UniTask LoadPlayerModel(RoleInfo role) + { + var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); + GameObject prefab = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender); + if (prefab == null) + { + return null; + } + GameObject model = Instantiate(prefab); + var playerDefaultEquipments = model.GetComponentInChildren(); + if (playerDefaultEquipments == null) + { + return null; + } + DATA_TYPE DataType = default; + bool useDefaultUpper = true; + bool useDefaultLower = true; + bool useDefaultWrist = true; + bool useDefaultFoot = true; + + GRoleInventory equipment; + + for(int i = 0; i < role.equipment.Count; i++) + { + equipment = role.equipment[i]; + + var equipData = elemendataman.get_data_ptr((uint)equipment.id, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); + + switch (DataType) + { + case DATA_TYPE.DT_WEAPON_ESSENCE: + var weaponData = (WEAPON_ESSENCE)equipData; + + string fileModelRight = AFile.NormalizePath(weaponData.FileModelRight, true).ToLower(); + string fileModelLeft = AFile.NormalizePath(weaponData.FileModelLeft, true).ToLower(); + + GameObject weaponPrefab = null; + if (!string.IsNullOrEmpty(fileModelRight)) + { + weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelRight); + var weaponObject = Instantiate(weaponPrefab); + if (weaponObject != null) + { + weaponObject.transform.SetParent(FindChildObjectRecursive(model.transform, CECPlayer._hh_right_hand_weapon).transform); + weaponObject.transform.localPosition = weaponPrefab.transform.localPosition; + weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; + weaponObject.transform.localScale = Vector3.one; + weaponObject.SetActive(true); + } + } + + if (!string.IsNullOrEmpty(fileModelLeft)) + { + weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelLeft); + var weaponObject = Instantiate(weaponPrefab); + if (weaponObject != null) + { + weaponObject.transform.SetParent(FindChildObjectRecursive(model.transform, CECPlayer._hh_left_hand_weapon).transform); + weaponObject.transform.localPosition = weaponPrefab.transform.localPosition; + weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; + weaponObject.transform.localScale = Vector3.one; + weaponObject.SetActive(true); + } + } + break; + case DATA_TYPE.DT_ARMOR_ESSENCE: + var pArmor = (ARMOR_ESSENCE)equipData; + var nLocation = pArmor.equip_location; + // BMLogger.Log($"ShowEquipments():: Armor Essence: {pArmor.RealName}"); + + var armorSkinPath = CECPlayer._GenEquipmentSkinPath(role.occupation, role.gender, pArmor.RealName); + if (!armorSkinPath.EndsWith(".ecm")) + { + armorSkinPath += ".ecm"; + } + var armorPrefab = await AddressableManager.Instance.LoadPrefabAsync(armorSkinPath); + if (armorPrefab != null) + { + var armorObject = Instantiate(armorPrefab); + armorObject.transform.SetParent(GetSkeletonBuilder(model)?.transform); + armorObject.transform.localPosition = Vector3.zero; + armorObject.transform.localRotation = Quaternion.identity; + armorObject.transform.localScale = Vector3.one; + + var skinnedMeshRenderer = armorObject.GetComponent(); + var skinnedMeshRenderereFromDataList = armorObject.GetComponentsInChildren(); + foreach (var skinnedMeshRenderereFromData in skinnedMeshRenderereFromDataList) + { + if (skinnedMeshRenderereFromData != null) + { + skinnedMeshRenderereFromData._skinnedMeshRenderer.bones = GetSkeletonBuilder(model).GetBones(skinnedMeshRenderereFromData.BoneNames); + skinnedMeshRenderereFromData._skinnedMeshRenderer.rootBone = skinnedMeshRenderereFromData._skinnedMeshRenderer.bones[^1]; + } + } + + // disable/enable the default equipment + switch (nLocation) + { + case (uint)CECPlayer.SkinIndex.SKIN_UPPER_BODY_INDEX: + useDefaultUpper = false; + break; + case (uint)CECPlayer.SkinIndex.SKIN_LOWER_INDEX: + useDefaultLower = false; + break; + case (uint)CECPlayer.SkinIndex.SKIN_WRIST_INDEX: + useDefaultWrist = false; + break; + case (uint)CECPlayer.SkinIndex.SKIN_FOOT_INDEX: + useDefaultFoot = false; + break; + } + } + break; + //TODO: Handle Wings later + // case DATA_TYPE.DT_WINGMANWING_ESSENCE: + // m_wingType = enumWingType.WINGTYPE_WING; + // //ChangeWing(pResult, static_cast(pEquip)->file_model); + // var pWingData = (WINGMANWING_ESSENCE)equipData; + // //string path1 = "models/players/通用装备/翅膀/天鹅之翼/天鹅之翼_Test.ecm"; + // //var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(path1); + // var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(pWingData.FileModel.ToLower().Replace('\\', '/')); + // //Transform parentWing = FindChildRecursive(_pPlayerModel.transform, "HH_chibang"); + // if(pWingPrefab != null) + // { + // var pflySwordObject = Instantiate(pWingPrefab).transform; + // pflySwordObject.parent = m_pPlayerCECModel.m_skeletonBuilder.GetHook("HH_chibang").transform; + // pflySwordObject.localPosition = Vector3.zero; + // pflySwordObject.localRotation = Quaternion.identity; + // pflySwordObject.localScale = Vector3.one; + + // m_Wing = pflySwordObject.transform; + + // m_Wing.gameObject.SetActive(false); + // } + // BMLogger.Log($"ShowEquipments():: Wingman Wing Essence: {pWingData.id} {pWingData.Name} -- {pWingData.FileModel}"); + // break; + default: + break; + + + + switch (equipment.pos) + { + case InventoryConst.EQUIPIVTR_BODY: + useDefaultUpper = false; + break; + case InventoryConst.EQUIPIVTR_LEG: + useDefaultLower = false; + break; + case InventoryConst.EQUIPIVTR_WRIST: + useDefaultWrist = false; + break; + case InventoryConst.EQUIPIVTR_FOOT: + useDefaultFoot = false; + break; + } + } + } + + playerDefaultEquipments.DefaultUpper.SetActive(useDefaultUpper); + playerDefaultEquipments.DefaultLower.SetActive(useDefaultLower); + playerDefaultEquipments.DefaultWirst.SetActive(useDefaultWrist); + playerDefaultEquipments.DefaultFoot.SetActive(useDefaultFoot); + return model; + } + + private GameObject FindChildObjectRecursive(Transform parent, string name) + { + foreach (Transform child in parent) + { + if (child.name == name) + { + return child.gameObject; + } + var childObject = FindChildObjectRecursive(child, name); + if (childObject != null) + { + return childObject; + } + } + return null; + } + + private SkeletonBuilder GetSkeletonBuilder(GameObject characterModel) + { + if (characterModel == null) + { + return null; + } + SkeletonBuilder skeletonBuilder = null; + if (skeletonBuilder == null) + { + skeletonBuilder = characterModel.GetComponentInChildren(); + } + return skeletonBuilder; + } } } From d6eb7f00ebdfbba47396d1529a7ba0906a0e2cdf Mon Sep 17 00:00:00 2001 From: Tungdv Date: Mon, 6 Apr 2026 18:39:48 +0700 Subject: [PATCH 3/3] fix: Update UI name EP. --- Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index 8b7cbe0ea4..6b697df049 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -19,6 +19,9 @@ using PerfectWorld.Scripts.Managers; using UnityEngine; using BrewMonster.Scripts.Managers; using System.Collections.Generic; +using static BrewMonster.CECHostPlayer; +using TMPro; +using BrewMonster.PerfectWorld.Scripts.UI; namespace BrewMonster { @@ -995,6 +998,7 @@ namespace BrewMonster m_bBaseInfoReady = true; SetPlayerName(szName ?? ""); EC_Game.GetGameRun().AddPlayerName(m_PlayerInfo.cid, szName, true); + GetComponentInChildren().RefreshName(); } // Level up public void LevelUp()