From 80a3a48abe1ae9fbd71d3d10d416a10603d44be7 Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Wed, 27 May 2026 10:55:35 +0700 Subject: [PATCH 1/2] Add storage password logic, ui --- .../UI/DialogScriptTableObject.asset | 4 + .../CSNetwork/C2SCommand/C2SCommand.cs | 8 + .../CSNetwork/C2SCommand/C2SCommandFactory.cs | 21 + .../Scripts/Network/CSNetwork/GameSession.cs | 9 + .../Scripts/Network/UnityGameSession.cs | 5 + .../PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs | 6 +- .../Scripts/UI/Dialogs/DlgStorageChangePW.cs | 243 ++ .../UI/Dialogs/DlgStorageChangePW.cs.meta | 11 + .../Scripts/UI/Dialogs/DlgStoragePW.cs | 82 + .../Scripts/UI/Dialogs/DlgStoragePW.cs.meta | 11 + Assets/Prefabs/UI/WinStorageChangePW.prefab | 2827 +++++++++++++++++ .../Prefabs/UI/WinStorageChangePW.prefab.meta | 7 + Assets/Prefabs/UI/WinStoragePW.prefab | 1431 +++++++++ Assets/Prefabs/UI/WinStoragePW.prefab.meta | 7 + Assets/Scripts/CECHostPlayer.Storage.cs | 1 + Assets/Scripts/CECUIManager.cs | 64 +- 16 files changed, 4724 insertions(+), 13 deletions(-) create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStorageChangePW.cs create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStorageChangePW.cs.meta create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStoragePW.cs create mode 100644 Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStoragePW.cs.meta create mode 100644 Assets/Prefabs/UI/WinStorageChangePW.prefab create mode 100644 Assets/Prefabs/UI/WinStorageChangePW.prefab.meta create mode 100644 Assets/Prefabs/UI/WinStoragePW.prefab create mode 100644 Assets/Prefabs/UI/WinStoragePW.prefab.meta diff --git a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset index dcea317564..4d7fc453f8 100644 --- a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset +++ b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset @@ -69,3 +69,7 @@ MonoBehaviour: prefab: {fileID: 8147986291757959694, guid: 11d09ee52b0c5f24fb3ef21e177ebe2d, type: 3} - id: EC_AccountStorageUI prefab: {fileID: 3837460183159982207, guid: 52c6d600a10af6b46a93fdc0ab719198, type: 3} + - id: DlgStoragePW + prefab: {fileID: 3837460183159982207, guid: 54acd8492cecae04aaf22d12852c19b4, type: 3} + - id: DlgStorageChangePW + prefab: {fileID: 3837460183159982207, guid: ebb0c4a44747f664f9e9071c09b83370, type: 3} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs index edcbe3b20b..386ea621b7 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs @@ -1732,6 +1732,14 @@ namespace CSNetwork.S2CCommand { public uint psw_size; } + + // PW_CPP: EC_SendC2SCmds.cpp c2s_SendCmdNPCSevChgTrashPsw CONTENT + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ChgTrashPswCONTENT + { + public ushort origin_size; + public ushort new_size; + } } // Player and NPC state \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs index 54eeed262e..c2af4fec4c 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs @@ -1268,6 +1268,27 @@ namespace CSNetwork.C2SCommand return octets; } + public static Octets CreateNPCSevChgTrashPswCmd(string oldPassword, string newPassword) + { + byte[] oldBytes = string.IsNullOrEmpty(oldPassword) ? null : Encoding.UTF8.GetBytes(oldPassword); + byte[] newBytes = string.IsNullOrEmpty(newPassword) ? null : Encoding.UTF8.GetBytes(newPassword); + ushort oldLen = (ushort)(oldBytes?.Length ?? 0); + ushort newLen = (ushort)(newBytes?.Length ?? 0); + + var cmd = new cmd_sevnpc_serve + { + service_type = NPC_service_type.GP_NPCSEV_TRASHPSW, + len = (uint)Marshal.SizeOf() + oldLen + newLen + }; + var content = new ChgTrashPswCONTENT { origin_size = oldLen, new_size = newLen }; + var octets = SerializeCommand(CommandID.SEVNPC_SERVE, cmd, content); + if (oldLen > 0 && oldBytes != null) + octets.Insert(octets.Size, oldBytes); + if (newLen > 0 && newBytes != null) + octets.Insert(octets.Size, newBytes); + return octets; + } + public static Octets CreateNPCSevOpenAccountBoxCmd() { var cmd = new cmd_sevnpc_serve diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index e842f2d6e2..f6d5f27583 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -3129,6 +3129,15 @@ namespace CSNetwork SendProtocol(req); } + public void c2s_CmdNPCSevChgTrashPsw(string oldPassword, string newPassword) + { + var req = new gamedatasend + { + Data = C2SCommandFactory.CreateNPCSevChgTrashPswCmd(oldPassword ?? "", newPassword ?? "") + }; + SendProtocol(req); + } + public void c2s_CmdNPCSevOpenAccountBox() { var req = new gamedatasend { Data = C2SCommandFactory.CreateNPCSevOpenAccountBoxCmd() }; diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs index 5bb555c408..ddf1ab04ef 100644 --- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs @@ -979,6 +979,11 @@ namespace BrewMonster.Network Instance._gameSession.c2s_CmdNPCSevOpenTrash(password); } + public static void c2s_CmdNPCSevChgTrashPsw(string oldPassword, string newPassword) + { + Instance._gameSession.c2s_CmdNPCSevChgTrashPsw(oldPassword, newPassword); + } + public static void c2s_CmdNPCSevOpenAccountBox() { Instance._gameSession.c2s_CmdNPCSevOpenAccountBox(); diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs index 601c8f3da4..91fbdb224d 100644 --- a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs @@ -3767,8 +3767,7 @@ namespace BrewMonster.UI { if (GetHostPlayer().TrashBoxHasPsw()) { - dialogue1 = "Win_InputString"; - // PW_TODO: password input → c2s_CmdNPCSevOpenTrash(password) + dialogue1 = DlgStoragePW.DialogId; } else { @@ -3778,8 +3777,7 @@ namespace BrewMonster.UI } else if (idFunction == (int)SERVICE_TYPE.NPC_STORAGE_PASSWORD) { - dialogue1 = "Win_InputString3"; - // pShow1 = m_pAUIManager.GetDialog("Win_InputString3"); + dialogue1 = DlgStorageChangePW.DialogId; } else if (idFunction == (int)SERVICE_TYPE.NPC_ACCOUNT_STORAGE) { diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStorageChangePW.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStorageChangePW.cs new file mode 100644 index 0000000000..ce276be7cd --- /dev/null +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgStorageChangePW.cs @@ -0,0 +1,243 @@ +using BrewMonster.Network; +using BrewMonster.Scripts; +using System; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace BrewMonster.UI +{ + /// + /// Change warehouse password (C++ CDlgStorageChangePW / Win_InputString3). + /// Dialog id for : . + /// + public class DlgStorageChangePW : AUIDialog + { + public const string DialogId = "DlgStorageChangePW"; + + const int StringIdPasswordMismatch = 254; + + [SerializeField] private TMP_InputField oldPasswordInput; + [SerializeField] private TMP_InputField newPasswordInput; + [SerializeField] private TMP_InputField confirmPasswordInput; + [SerializeField] private Button confirmButton; + [SerializeField] private Button cancelButton; + [SerializeField] private Button closeButton; + + public static DlgStorageChangePW GetDialog() + { + return EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan()?.GetDialog(DialogId) as DlgStorageChangePW; + } + + public override void Awake() + { + base.Awake(); + ResolveControls(); + WireButtons(); + } + + public override void OnShowDialogue() + { + base.OnShowDialogue(); + WireButtons(); + ClearFields(); + } + + void ResolveControls() + { + oldPasswordInput = DlgStoragePasswordUiHelper.FindInputField(transform, oldPasswordInput, "DEFAULT_Txt_Input"); + newPasswordInput = DlgStoragePasswordUiHelper.FindInputField(transform, newPasswordInput, "Txt_New"); + confirmPasswordInput = DlgStoragePasswordUiHelper.FindInputField(transform, confirmPasswordInput, "Txt_NewConfirm"); + EnsurePasswordFieldLayout(); + + DlgStoragePasswordUiHelper.ConfigurePasswordField(oldPasswordInput); + DlgStoragePasswordUiHelper.ConfigurePasswordField(newPasswordInput); + DlgStoragePasswordUiHelper.ConfigurePasswordField(confirmPasswordInput); + + DlgStoragePasswordUiHelper.ResolveButton(ref confirmButton, transform, "confirm", "btn_decide", "btn_confirm", "ok"); + DlgStoragePasswordUiHelper.ResolveButton(ref cancelButton, transform, "cancel", "idcanel", "btn_cancel", "btn_exit"); + DlgStoragePasswordUiHelper.ResolveButton(ref closeButton, transform, "btn_close", "close"); + } + + void WireButtons() + { + DlgStoragePasswordUiHelper.ResolveButton(ref confirmButton, transform, "confirm", "btn_decide", "btn_confirm", "ok"); + DlgStoragePasswordUiHelper.WireConfirmButton(transform, OnConfirm, confirmButton); + DlgStoragePasswordUiHelper.WireCancelButtons(transform, OnCancel); + } + + void EnsurePasswordFieldLayout() + { + if (oldPasswordInput == null) + return; + if (newPasswordInput == null) + newPasswordInput = DlgStoragePasswordUiHelper.ClonePasswordField(oldPasswordInput, "Txt_New", new Vector2(0f, -22f)); + if (confirmPasswordInput == null) + confirmPasswordInput = DlgStoragePasswordUiHelper.ClonePasswordField(oldPasswordInput, "Txt_NewConfirm", new Vector2(0f, -44f)); + } + + void ClearFields() + { + if (oldPasswordInput != null) + oldPasswordInput.SetTextWithoutNotify(string.Empty); + if (newPasswordInput != null) + newPasswordInput.SetTextWithoutNotify(string.Empty); + if (confirmPasswordInput != null) + confirmPasswordInput.SetTextWithoutNotify(string.Empty); + } + + void OnConfirm() + { + string oldPw = oldPasswordInput != null ? oldPasswordInput.text : string.Empty; + string newPw = newPasswordInput != null ? newPasswordInput.text : string.Empty; + string confirmPw = confirmPasswordInput != null ? confirmPasswordInput.text : string.Empty; + + if (newPw != confirmPw) + { + var gameUi = EC_Game.GetGameRun()?.GetUIManager()?.GetInGameUIMan(); + gameUi?.ShowErrorMsg(GetStringFromTable(StringIdPasswordMismatch), string.Empty); + return; + } + + UnityGameSession.c2s_CmdNPCSevChgTrashPsw(oldPw, newPw); + CloseDialog(); + } + + void OnCancel() + { + CECUIManager.Instance?.EndNpcTalkAfterStorageService(); + } + + void CloseDialog() + { + CECUIManager.Instance?.EndNpcTalkAfterStorageService(); + } + } + + static class DlgStoragePasswordUiHelper + { + public static TMP_InputField FindInputField(Transform root, TMP_InputField assigned, string controlName) + { + if (assigned != null) + return assigned; + + var direct = root.Find(controlName); + if (direct != null && direct.TryGetComponent(out TMP_InputField directField)) + return directField; + + var all = root.GetComponentsInChildren(true); + for (int i = 0; i < all.Length; i++) + { + if (all[i] != null && string.Equals(all[i].name, controlName, StringComparison.OrdinalIgnoreCase)) + return all[i]; + } + + if (all.Length == 1 && string.Equals(controlName, "DEFAULT_Txt_Input", StringComparison.OrdinalIgnoreCase)) + return all[0]; + + return null; + } + + public static void ConfigurePasswordField(TMP_InputField field) + { + if (field == null) + return; + field.contentType = TMP_InputField.ContentType.Password; + field.inputType = TMP_InputField.InputType.Password; + } + + public static TMP_InputField ClonePasswordField(TMP_InputField template, string name, Vector2 anchoredOffset) + { + if (template == null) + return null; + + var clone = UnityEngine.Object.Instantiate(template, template.transform.parent); + clone.name = name; + var rt = clone.GetComponent(); + if (rt != null) + rt.anchoredPosition += anchoredOffset; + ConfigurePasswordField(clone); + return clone; + } + + public static void ResolveButton(ref Button field, Transform root, params string[] nameHints) + { + if (field != null) + return; + + var buttons = root.GetComponentsInChildren