From 7ba4c0fed5a397be2cc21f10db1e916da2d84867 Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Mon, 1 Dec 2025 14:49:41 +0700 Subject: [PATCH] Update equipment preview show, hide --- .../UI/Inventory/InventoryCharacterPreview.cs | 52 ++++++-- Assets/Scripts/CECHostPlayer.cs | 4 +- Assets/Scripts/CECPlayer_Inventory.cs | 117 +++++++++++++++++- 3 files changed, 157 insertions(+), 16 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs index b48f4ffe55..bc05107be6 100644 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs +++ b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs @@ -43,6 +43,8 @@ namespace BrewMonster.Scripts.UI.Inventory private GameObject _previewInstance; private bool _refreshQueued; + private int _lastOriginModelChildCount; + private Transform _lastOriginModelRoot; private void Awake() { @@ -55,22 +57,36 @@ namespace BrewMonster.Scripts.UI.Inventory EnsureCameraBindings(); } - /*private void OnEnable() + private void OnEnable() { - EventBus.Subscribe(OnEquipmentChanged); QueueRefresh(); - }*/ + } - /*private void OnDisable() + private void OnDisable() { - EventBus.Unsubscribe(OnEquipmentChanged); DestroyPreviewInstance(); - }*/ + } private void LateUpdate() { TryBindHostPlayer(); + // Check if origin model structure has changed (equipment models are child objects) + // This detects equipment changes in realtime since all equipment is attached as children + var currentOriginRoot = ResolveSourceModelRoot(); + if (currentOriginRoot != null) + { + int currentChildCount = CountAllChildren(currentOriginRoot); + + // Refresh if origin model changed or child count changed (equipment added/removed) + if (_lastOriginModelRoot != currentOriginRoot || _lastOriginModelChildCount != currentChildCount) + { + _lastOriginModelRoot = currentOriginRoot; + _lastOriginModelChildCount = currentChildCount; + QueueRefresh(); + } + } + if (_refreshQueued) { _refreshQueued = false; @@ -103,13 +119,6 @@ namespace BrewMonster.Scripts.UI.Inventory _refreshQueued = true; } - /*private void OnEquipmentChanged(PlayerEquipmentChangedEvent evt) - { - if (hostPlayer != null && evt.Player == hostPlayer) - { - QueueRefresh(); - } - }*/ private void TryBindHostPlayer() { @@ -317,6 +326,23 @@ namespace BrewMonster.Scripts.UI.Inventory animator.speed = 0f; } } + + /// + /// Counts all children recursively in the transform hierarchy. + /// Used to detect when equipment (child objects) are added or removed from the origin model. + /// + private int CountAllChildren(Transform root) + { + if (root == null) + return 0; + + int count = root.childCount; + for (int i = 0; i < root.childCount; i++) + { + count += CountAllChildren(root.GetChild(i)); + } + return count; + } } } diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 7b87514c5d..f120e3b775 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -861,6 +861,7 @@ namespace BrewMonster { ui.RefreshAll(); } + UpdateEquipSkins(); } break; case CommandID.PICKUP_ITEM: @@ -979,6 +980,7 @@ namespace BrewMonster var equipInv = GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK); var invItem = packInv?.GetItem(index_inv, true); var equipItem = equipInv?.GetItem(index_equip, true); + UpdateEquipSkins(); if (invItem != null) { invItem.Package = InventoryConst.IVTRTYPE_EQUIPPACK; @@ -999,7 +1001,7 @@ namespace BrewMonster { ui.RefreshAll(); } - + UpdateEquipSkins(); break; } } diff --git a/Assets/Scripts/CECPlayer_Inventory.cs b/Assets/Scripts/CECPlayer_Inventory.cs index 99cde3da52..3e56f0d7a6 100644 --- a/Assets/Scripts/CECPlayer_Inventory.cs +++ b/Assets/Scripts/CECPlayer_Inventory.cs @@ -115,6 +115,16 @@ public partial class CECPlayer // We use this to setup the bones for the equipment skinned mesh renderers private SkeletonBuilder _skeletonBuilder; private PlayerDefaultEquipments _playerDefaultEquipments; + + // Track instantiated armor objects for each slot + private GameObject _currentUpperArmor; + private GameObject _currentLowerArmor; + private GameObject _currentWristArmor; + private GameObject _currentFootArmor; + + // Track instantiated weapon objects + private GameObject _currentRightHandWeapon; + private GameObject _currentLeftHandWeapon; private PlayerDefaultEquipments PlayerDefaultEquipments { get @@ -211,6 +221,21 @@ public partial class CECPlayer string fileModelRight = AFile.NormalizePath(weaponData.FileModelRight, true).ToLower(); string fileModelLeft = AFile.NormalizePath(weaponData.FileModelLeft, true).ToLower(); // BMLogger.Log($"ShowEquipments():: Weapon Essence: {fileModelRight} -- {fileModelLeft}"); + + // Destroy existing right hand weapon before creating new one + if (_currentRightHandWeapon != null) + { + Destroy(_currentRightHandWeapon); + _currentRightHandWeapon = null; + } + + // Destroy existing left hand weapon before creating new one + if (_currentLeftHandWeapon != null) + { + Destroy(_currentLeftHandWeapon); + _currentLeftHandWeapon = null; + } + GameObject weaponPrefab = null; if (!string.IsNullOrEmpty(fileModelRight)) { @@ -223,6 +248,7 @@ public partial class CECPlayer weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; weaponObject.transform.localScale = Vector3.one; weaponObject.SetActive(true); + _currentRightHandWeapon = weaponObject; } } @@ -237,6 +263,7 @@ public partial class CECPlayer weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; weaponObject.transform.localScale = Vector3.one; weaponObject.SetActive(true); + _currentLeftHandWeapon = weaponObject; } } break; @@ -253,6 +280,39 @@ public partial class CECPlayer var armorPrefab = await AddressableManager.Instance.LoadPrefabAsync(armorSkinPath); if (armorPrefab != null) { + // Destroy existing armor for this slot before creating new one + switch (nLocation) + { + case (uint)SkinIndex.SKIN_UPPER_BODY_INDEX: + if (_currentUpperArmor != null) + { + Destroy(_currentUpperArmor); + _currentUpperArmor = null; + } + break; + case (uint)SkinIndex.SKIN_LOWER_INDEX: + if (_currentLowerArmor != null) + { + Destroy(_currentLowerArmor); + _currentLowerArmor = null; + } + break; + case (uint)SkinIndex.SKIN_WRIST_INDEX: + if (_currentWristArmor != null) + { + Destroy(_currentWristArmor); + _currentWristArmor = null; + } + break; + case (uint)SkinIndex.SKIN_FOOT_INDEX: + if (_currentFootArmor != null) + { + Destroy(_currentFootArmor); + _currentFootArmor = null; + } + break; + } + var armorObject = Instantiate(armorPrefab); armorObject.transform.SetParent(GetSkeletonBuilder()?.transform); armorObject.transform.localPosition = Vector3.zero; @@ -270,19 +330,23 @@ public partial class CECPlayer } } - // disable/enable the default equipment + // Store the armor object for this slot switch (nLocation) { case (uint)SkinIndex.SKIN_UPPER_BODY_INDEX: + _currentUpperArmor = armorObject; useDefaultUpper = false; break; case (uint)SkinIndex.SKIN_LOWER_INDEX: + _currentLowerArmor = armorObject; useDefaultLower = false; break; case (uint)SkinIndex.SKIN_WRIST_INDEX: + _currentWristArmor = armorObject; useDefaultWrist = false; break; case (uint)SkinIndex.SKIN_FOOT_INDEX: + _currentFootArmor = armorObject; useDefaultFoot = false; break; } @@ -319,6 +383,19 @@ public partial class CECPlayer { switch (i) { + case InventoryConst.EQUIPIVTR_WEAPON: + // Destroy weapons when weapon slot is empty + if (_currentRightHandWeapon != null) + { + Destroy(_currentRightHandWeapon); + _currentRightHandWeapon = null; + } + if (_currentLeftHandWeapon != null) + { + Destroy(_currentLeftHandWeapon); + _currentLeftHandWeapon = null; + } + break; case InventoryConst.EQUIPIVTR_BODY: useDefaultUpper = true; break; @@ -336,9 +413,45 @@ public partial class CECPlayer } // enable/disable the default equipment + // If using default, destroy non-default equipment if it exists + if (useDefaultUpper) + { + if (_currentUpperArmor != null) + { + Destroy(_currentUpperArmor); + _currentUpperArmor = null; + } + } PlayerDefaultEquipments.DefaultUpper.SetActive(useDefaultUpper); + + if (useDefaultLower) + { + if (_currentLowerArmor != null) + { + Destroy(_currentLowerArmor); + _currentLowerArmor = null; + } + } PlayerDefaultEquipments.DefaultLower.SetActive(useDefaultLower); + + if (useDefaultWrist) + { + if (_currentWristArmor != null) + { + Destroy(_currentWristArmor); + _currentWristArmor = null; + } + } PlayerDefaultEquipments.DefaultWirst.SetActive(useDefaultWrist); + + if (useDefaultFoot) + { + if (_currentFootArmor != null) + { + Destroy(_currentFootArmor); + _currentFootArmor = null; + } + } PlayerDefaultEquipments.DefaultFoot.SetActive(useDefaultFoot); } @@ -376,4 +489,4 @@ public partial class CECPlayer { return string.Format(_equipment_skin[nProfession * NUM_GENDER + nGender], szSkinName, szSkinName); } -} \ No newline at end of file +}