From a26ec4acc351c741fcab6cb751bb121e75b1acc9 Mon Sep 17 00:00:00 2001 From: CuongNV <> Date: Mon, 18 May 2026 16:10:23 +0700 Subject: [PATCH] fix show model in inventory --- Assets/PerfectWorld/Scene/Bootstrap.unity | 4 +- .../Scripts/Managers/EC_InventoryUI.cs | 36 +- .../Scripts/Players/PlayerModelPreview.cs | 241 ++++-- .../UI/Inventory/InventoryCharacterPreview.cs | 687 ------------------ .../InventoryCharacterPreview.cs.meta | 2 - Assets/Prefabs/UI/InventoryUI.prefab | 187 +++-- 6 files changed, 310 insertions(+), 847 deletions(-) delete mode 100644 Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs delete mode 100644 Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs.meta diff --git a/Assets/PerfectWorld/Scene/Bootstrap.unity b/Assets/PerfectWorld/Scene/Bootstrap.unity index 01f75cbb7c..bc0fc63f29 100644 --- a/Assets/PerfectWorld/Scene/Bootstrap.unity +++ b/Assets/PerfectWorld/Scene/Bootstrap.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20826e4631ccd8df95267f53f85e8dd91287f8a8b5c61eeeb700e7f859c7b35e -size 304738 +oid sha256:118edff57ce13d46edc50acb1387bca1d79d66795958be304ef1e9d017cff634 +size 309966 diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs index 8743a04f9c..590926e83f 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs @@ -15,7 +15,6 @@ using System.Text; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; -using BrewMonster.Scripts.UI.Inventory; using CSNetwork.Protocols.RPCData; namespace BrewMonster.Scripts.Managers @@ -168,9 +167,26 @@ namespace BrewMonster.Scripts.Managers ShowDetailPanel(false); ShowSplitPanel(false); RefreshAll(); + BeginInventoryCharacterPreview(); RefreshCharacterModelPreview(); } + private void OnDisable() + { + PlayerModelPreview.Instance?.EndInventoryPreview(); + } + + private void BeginInventoryCharacterPreview() + { + var preview = PlayerModelPreview.Instance; + if (preview == null) + return; + + RoleInfo roleInfo = UnityGameSession.Instance != null ? UnityGameSession.Instance.GetRoleInfo() : null; + if (roleInfo != null) + preview.BeginInventoryPreview(roleInfo.roleid); + } + private void WireSplitUI() { if (splitOpenButton != null) @@ -1626,20 +1642,12 @@ namespace BrewMonster.Scripts.Managers public void RefreshCharacterModelPreview() { var preview = PlayerModelPreview.Instance; - if (preview != null) - { - RoleInfo roleInfo = BuildCurrentPreviewRoleInfo(); - if (roleInfo != null) - { - preview.ReloadRoleModel(roleInfo); - } - } + if (preview == null) + return; - var inventoryPreview = FindFirstObjectByType(); - if (inventoryPreview != null) - { - inventoryPreview.QueueRefresh(); - } + RoleInfo roleInfo = BuildCurrentPreviewRoleInfo(); + if (roleInfo != null) + preview.ReloadRoleModel(roleInfo); } private RoleInfo BuildCurrentPreviewRoleInfo() diff --git a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs index 654a61b03b..bafcb42139 100644 --- a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs +++ b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs @@ -10,6 +10,7 @@ namespace BrewMonster.Scripts public class PlayerModelPreview : MonoSingleton { [SerializeField] private Transform modelRoot; + [SerializeField] private bool enablePreviewCameraWithInventory = true; public List playerModels = new(); public List playerModelIds = new(); @@ -26,10 +27,21 @@ namespace BrewMonster.Scripts private bool _hasRequestedPlayerModelId; private int _requestedPlayerModelId; + private bool _inventoryPreviewActive; + private bool _suppressHierarchyWatch; + private bool _refreshQueued; + private RoleInfo _lastPreviewRoleInfo; + private Transform _lastOriginModelRoot; + private int _lastOriginModelChildCount; + + private Camera _previewCamera; + private void Awake() { if (modelRoot == null) modelRoot = transform; + + _previewCamera = GetComponent(); } private void OnDestroy() @@ -37,6 +49,64 @@ namespace BrewMonster.Scripts ClearModelsImmediate(); } + private void LateUpdate() + { + if (!_inventoryPreviewActive || _suppressHierarchyWatch) + return; + + Transform activeRoot = GetActivePreviewModelTransform(); + if (activeRoot == null) + { + if (_refreshQueued) + { + _refreshQueued = false; + TryRefreshFromCachedRole(); + } + + return; + } + + int currentChildCount = CountAllChildren(activeRoot); + if (_lastOriginModelRoot != activeRoot || _lastOriginModelChildCount != currentChildCount) + { + bool hierarchyChanged = _lastOriginModelRoot != null; + _lastOriginModelRoot = activeRoot; + _lastOriginModelChildCount = currentChildCount; + + if (hierarchyChanged && _lastPreviewRoleInfo != null) + _refreshQueued = true; + } + + if (_refreshQueued) + { + _refreshQueued = false; + TryRefreshFromCachedRole(); + } + } + + /// Called when Inventory UI opens — shows the host preview model on shared Bootstrap camera. + public void BeginInventoryPreview(int roleId) + { + _inventoryPreviewActive = true; + ResetHierarchyWatch(); + + if (enablePreviewCameraWithInventory && _previewCamera != null) + _previewCamera.enabled = true; + + ShowPlayerModel(roleId); + } + + /// Called when Inventory UI closes — hides preview models. Camera stays enabled for login/character-select reuse. + public void EndInventoryPreview() + { + _inventoryPreviewActive = false; + _refreshQueued = false; + _suppressHierarchyWatch = false; + ResetHierarchyWatch(); + + HideAllPlayerModels(); + } + /// /// Loads one preview instance per role (via ). /// All instances stay hidden until is called. @@ -50,6 +120,7 @@ namespace BrewMonster.Scripts if (roleInfos == null || roleInfos.Count == 0 || NPCManager.Instance == null) { ClearModels(); + _suppressHierarchyWatch = false; return; } @@ -82,13 +153,17 @@ namespace BrewMonster.Scripts ApplyRequestedModelVisibility(); } - for(int i=0; i < oldModels.Count; i++) + for (int i = 0; i < oldModels.Count; i++) { if (oldModels[i] != null) { Destroy(oldModels[i]); } } + + _suppressHierarchyWatch = false; + if (_inventoryPreviewActive) + SyncHierarchyBaseline(); } /// @@ -96,14 +171,6 @@ namespace BrewMonster.Scripts /// public void ShowPlayerModel(int playerModelId) { - //int n = Mathf.Min(playerModels.Count, playerModelIds.Count); - //for (int i = 0; i < n; i++) - //{ - // GameObject go = playerModels[i]; - // if (go == null) - // continue; - // go.SetActive(playerModelIds[i] == playerModelId); - //} _hasRequestedPlayerModelId = true; _requestedPlayerModelId = playerModelId; @@ -128,13 +195,15 @@ namespace BrewMonster.Scripts continue; bool shouldBeActive = playerModelIds[i] == _requestedPlayerModelId; - bool wasActive = go.activeSelf; + bool wasActive = go.activeSelf; go.SetActive(shouldBeActive); - // Fire once when this model first becomes visible if (shouldBeActive && !wasActive) OnModelReady?.Invoke(playerModelIds[i]); } + + if (_inventoryPreviewActive) + SyncHierarchyBaseline(); } public void HideAllPlayerModels() @@ -151,14 +220,6 @@ namespace BrewMonster.Scripts public void ClearModels() { - //for (int i = 0; i < playerModels.Count; i++) - //{ - // if (playerModels[i] != null) - // { - // Destroy(playerModels[i]); - // } - //} - for (int i = 0; i < playerModels.Count; i++) { if (playerModels[i] != null) @@ -177,9 +238,9 @@ namespace BrewMonster.Scripts { if (modelRoot != null) { - if(playerModels[i] != null) + if (playerModels[i] != null) { - if(Application.isPlaying) + if (Application.isPlaying) Destroy(playerModels[i]); else DestroyImmediate(playerModels[i]); @@ -193,9 +254,9 @@ namespace BrewMonster.Scripts private async UniTask LoadPlayerModel(RoleInfo role) { - var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); + var elemendataman = ElementDataManProvider.GetElementDataMan(); GameObject model = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender); - if(model == null) + if (model == null) return null; model.SetActive(false); @@ -209,6 +270,7 @@ namespace BrewMonster.Scripts { return null; } + DATA_TYPE DataType = default; bool useDefaultUpper = true; bool useDefaultLower = true; @@ -217,7 +279,7 @@ namespace BrewMonster.Scripts GRoleInventory equipment; - for(int i = 0; i < role.equipment.Count; i++) + for (int i = 0; i < role.equipment.Count; i++) { equipment = role.equipment[i]; @@ -265,7 +327,6 @@ namespace BrewMonster.Scripts if (equipData == null) break; 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")) @@ -281,7 +342,6 @@ namespace BrewMonster.Scripts armorObject.transform.localRotation = Quaternion.identity; armorObject.transform.localScale = Vector3.one; - var skinnedMeshRenderer = armorObject.GetComponent(); var skinnedMeshRenderereFromDataList = armorObject.GetComponentsInChildren(); foreach (var skinnedMeshRenderereFromData in skinnedMeshRenderereFromDataList) { @@ -292,7 +352,6 @@ namespace BrewMonster.Scripts } } - // disable/enable the default equipment switch (nLocation) { case (uint)CECPlayer.SkinIndex.SKIN_UPPER_BODY_INDEX: @@ -310,49 +369,22 @@ namespace BrewMonster.Scripts } } 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: + 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; - - - - 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; - } } } @@ -371,12 +403,14 @@ namespace BrewMonster.Scripts { return child.gameObject; } + var childObject = FindChildObjectRecursive(child, name); if (childObject != null) { return childObject; } } + return null; } @@ -386,12 +420,8 @@ namespace BrewMonster.Scripts { return null; } - SkeletonBuilder skeletonBuilder = null; - if (skeletonBuilder == null) - { - skeletonBuilder = characterModel.GetComponentInChildren(); - } - return skeletonBuilder; + + return characterModel.GetComponentInChildren(); } public void ReloadRoleModel(RoleInfo roleInfo) @@ -399,8 +429,71 @@ namespace BrewMonster.Scripts if (roleInfo == null) return; + _lastPreviewRoleInfo = roleInfo; + _suppressHierarchyWatch = true; ShowAllPlayerModels(new List { roleInfo }); ShowPlayerModel(roleInfo.roleid); } + + private Transform GetActivePreviewModelTransform() + { + if (!_hasRequestedPlayerModelId) + return null; + + int n = Mathf.Min(playerModels.Count, playerModelIds.Count); + for (int i = 0; i < n; i++) + { + GameObject model = playerModels[i]; + if (model != null && model.activeSelf && playerModelIds[i] == _requestedPlayerModelId) + return model.transform; + } + + for (int i = 0; i < n; i++) + { + GameObject model = playerModels[i]; + if (model != null && playerModelIds[i] == _requestedPlayerModelId) + return model.transform; + } + + return null; + } + + private void TryRefreshFromCachedRole() + { + if (_lastPreviewRoleInfo == null || !_inventoryPreviewActive || _suppressHierarchyWatch) + return; + + ReloadRoleModel(_lastPreviewRoleInfo); + } + + private void SyncHierarchyBaseline() + { + Transform activeRoot = GetActivePreviewModelTransform(); + if (activeRoot == null) + return; + + _lastOriginModelRoot = activeRoot; + _lastOriginModelChildCount = CountAllChildren(activeRoot); + } + + private void ResetHierarchyWatch() + { + _lastOriginModelRoot = null; + _lastOriginModelChildCount = 0; + } + + private static 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/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs deleted file mode 100644 index a16ce4351a..0000000000 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs +++ /dev/null @@ -1,687 +0,0 @@ -using Animancer; -using BrewMonster; -using UnityEngine; -using UnityEngine.UI; - -namespace BrewMonster.Scripts.UI.Inventory -{ - public enum PreviewDistanceScaleMode - { - AspectRatio, - ViewportHeight - } - - /// - /// Clones the current host-player visual model into a dedicated preview rig for the inventory UI. - /// - [DisallowMultipleComponent] - public class InventoryCharacterPreview : MonoBehaviour - { - [Header("Player Binding")] - [SerializeField] private CECHostPlayer hostPlayer; - [Tooltip("Auto locate the active host player if none is assigned.")] - [SerializeField] private bool autoBindHostPlayer = true; - [Tooltip("Optional manual override for the visual root. Leave empty to auto detect the PlayerVisual/host root.")] - [SerializeField] private Transform sourceModelRoot; - [Tooltip("Clone the entire CECHostPlayer hierarchy instead of just the PlayerVisual child.")] - [SerializeField] private bool cloneWholeHostHierarchy = true; - [Tooltip("Remove gameplay scripts/colliders from the preview clone when duplicating the full hierarchy.")] - [SerializeField] private bool stripRuntimeComponents = true; - - [Header("Preview Rig")] - [SerializeField] private Transform previewRoot; - [SerializeField] private Vector3 previewLocalPosition = Vector3.zero; - [SerializeField] private Vector3 previewLocalEuler; - [SerializeField] private Vector3 previewLocalScale = Vector3.one; - - [Header("Camera Output")] - [SerializeField] private RawImage previewFrame; - [SerializeField] private RenderTexture previewRenderTexture; - [SerializeField] private bool autoFocusCamera = true; - [SerializeField] private Vector3 cameraFocusOffset = new Vector3(0f, 0f, 0f); - - [Header("Camera Framing")] - [SerializeField] private float previewCameraDistance = 3.3f; - [SerializeField] private Vector3 previewCameraOffset = new Vector3(0.15f, 0.8f, 0f); - [SerializeField] private bool overrideFieldOfView = true; - [SerializeField][Range(10f, 60f)] private float previewFieldOfView = 33f; - - [SerializeField] private bool autoFrameByBounds = true; - [SerializeField][Range(1f, 2f)] private float autoFramePadding = 1.15f; - [SerializeField] private float minAutoCameraDistance = 1.25f; - [SerializeField] private float maxAutoCameraDistance = 8f; - - [Header("Device Framing")] - [Tooltip("Design-time screen width (1920x1080 baseline); previewCameraDistance/offset tuned for this.")] - [SerializeField] private float referenceScreenWidth = 1920f; - [Tooltip("Design-time screen height (1920x1080 baseline); previewCameraDistance/offset tuned for this.")] - [SerializeField] private float referenceScreenHeight = 1080f; - [Tooltip("Use previewFrame pixel size when available; otherwise Screen.width/height.")] - [SerializeField] private bool useRawImageViewport = true; - [SerializeField] private PreviewDistanceScaleMode distanceScaleMode = PreviewDistanceScaleMode.AspectRatio; - [Tooltip("Scale previewCameraOffset.y by viewport height vs 1080p reference (1.0 at 1920x1080).")] - [SerializeField] private bool scaleCameraOffsetYByViewport = true; - - private bool _cameraStateCached; - private Vector3 _cachedCameraPosition; - private Quaternion _cachedCameraRotation; - private float _cachedCameraFov; - - //[Header("Behaviour")] - //[Tooltip("Disable PlayerVisual/Animancer components on the clone so it stays in a frozen idle pose.")] - //[SerializeField] private bool freezeAnimation = true; - - private GameObject _previewInstance; - private bool _refreshQueued; - private int _lastOriginModelChildCount; - private Transform _lastOriginModelRoot; - private Camera _previewCamera; - private PlayerModelPreview _playerModelPreview; - private RenderTexture _cachedTargetTexture; - - private void Awake() - { - - if (previewRoot == null) - { - previewRoot = transform; - } - - TryBindPreviewSystem(); - TryBindHostPlayer(); - EnsureCameraBindings(); - } - - private void OnEnable() - { - TryBindPreviewSystem(); - EnsureCameraBindings(); - QueueRefresh(); - } - - private void OnDisable() - { - RestoreCameraTargetTexture(); - RestoreSharedCameraState(); - ReleasePreviewReference(); - } - - private void LateUpdate() - { - TryBindPreviewSystem(); - 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 - Transform currentOriginRoot = ResolveSourceModelRoot(); - if (currentOriginRoot == null) - { - if (_previewInstance == null) - { - QueueRefresh(); - } - if(_refreshQueued) - { - _refreshQueued = false; - BuildPreviewModel(); - } - return; - } - - int currentChildCount = CountAllChildren(currentOriginRoot); - - if (_lastOriginModelRoot != currentOriginRoot || _lastOriginModelChildCount != currentChildCount) - { - _lastOriginModelRoot = currentOriginRoot; - _lastOriginModelChildCount = currentChildCount; - QueueRefresh(); - } - - if (_refreshQueued) - { - _refreshQueued = false; - BuildPreviewModel(); - } - - if(_previewInstance != null) - { - EnsureCameraFocus(_previewInstance.transform); - } - } - - /// Allows manual binding from external UI scripts. - public void BindPlayer(CECHostPlayer player) - { - if (player == null || player == hostPlayer) - { - return; - } - - hostPlayer = player; - QueueRefresh(); - } - - /// Forces an immediate rebuild of the preview model. - public void ForceRefreshNow() - { - _refreshQueued = false; - BuildPreviewModel(); - } - - /// Marks the clone dirty so it gets recreated next LateUpdate. - public void QueueRefresh() - { - _refreshQueued = true; - } - - private void TryBindPreviewSystem() - { - if (_playerModelPreview == null) - { - _playerModelPreview = PlayerModelPreview.Instance; - } - - if (_playerModelPreview == null) - { - return; - } - - if (_previewCamera == null) - { - _previewCamera = _playerModelPreview.GetComponent(); - } - } - - private void TryBindHostPlayer() - { - if (!autoBindHostPlayer || hostPlayer != null) - { - return; - } - - hostPlayer = FindFirstObjectByType(); - if (hostPlayer != null) - { - QueueRefresh(); - } - } - - private void EnsureCameraBindings() - { - if (_previewCamera == null) - { - TryBindPreviewSystem(); - } - - if (_previewCamera == null || previewFrame == null) - { - return; - } - - if (_cachedTargetTexture == null) - { - _cachedTargetTexture = _previewCamera.targetTexture; - } - - if (previewRenderTexture != null) - { - _previewCamera.targetTexture = previewRenderTexture; - } - - if(previewFrame != null) - previewFrame.texture = _previewCamera.targetTexture; - } - - private void RestoreCameraTargetTexture() - { - if (_previewCamera == null) - { - return; - } - - if (_cachedTargetTexture != null) - { - _previewCamera.targetTexture = _cachedTargetTexture; - } - } - - private void BuildPreviewModel() - { - if (previewRoot == null) - { - return; - } - - Transform sourceRoot = ResolveSourceModelRoot(); - if (sourceRoot == null) - { - _previewInstance = null; - _lastOriginModelRoot = null; - _lastOriginModelChildCount = 0; - - QueueRefresh(); - return; - } - - if (_previewInstance != null && _previewInstance != sourceRoot.gameObject) - { - DestroyPreviewInstance(); - } - - if (!sourceRoot.gameObject.activeSelf) - { - sourceRoot.gameObject.SetActive(true); - } - - // Use resolved source root, not sourceModelRoot field directly. - _previewInstance = sourceRoot.gameObject; - Transform instanceTransform = _previewInstance.transform; - - if (instanceTransform.parent != previewRoot) - { - instanceTransform.SetParent(previewRoot, false); - } - - instanceTransform.localPosition = previewLocalPosition + Vector3.up; - instanceTransform.localRotation = Quaternion.Euler(previewLocalEuler); - instanceTransform.localScale = previewLocalScale; - - ApplyLayerRecursive(instanceTransform, previewRoot.gameObject.layer); - EnsureCameraFocus(instanceTransform); - EnsureCameraBindings(); - } - - private void DestroyPreviewInstance() - { - if (_previewInstance != null) - { - Destroy(_previewInstance); - _previewInstance = null; - } - } - - - private Transform ResolveSourceModelRoot() - { - if (sourceModelRoot != null) - { - return sourceModelRoot; - } - - if (_playerModelPreview == null) - { - return null; - } - - // Prefer active model. - for (int i = 0; i < _playerModelPreview.playerModels.Count; i++) - { - GameObject model = _playerModelPreview.playerModels[i]; - if (model != null && model.activeSelf) - { - return model.transform; - } - } - - // Fallback to first available model. - for (int i = 0; i < _playerModelPreview.playerModels.Count; i++) - { - GameObject model = _playerModelPreview.playerModels[i]; - if (model != null) - { - return model.transform; - } - } - - return null; - } - - private void ReleasePreviewReference() - { - _previewInstance = null; - } - - //private void DestroyPreviewInstance() - //{ - // if (_previewInstance != null) - // { - // Destroy(_previewInstance); - // _previewInstance = null; - // } - //} - - //private static void DisableComponentInChildren(GameObject root) where T : Behaviour - //{ - // if (root == null) - // { - // return; - // } - - // var components = root.GetComponentsInChildren(true); - // for (int i = 0; i < components.Length; i++) - // { - // var component = components[i]; - // if (component == null) - // continue; - - // component.enabled = false; - - // if (component is PlayerVisual) - // { - // Destroy(component); - // } - // } - //} - - private void ApplyLayerRecursive(Transform root, int layer) - { - if (root == null) - { - return; - } - - root.gameObject.layer = layer; - for (int i = 0; i < root.childCount; i++) - { - ApplyLayerRecursive(root.GetChild(i), layer); - } - } - - private void EnsureCameraFocus(Transform modelRoot) - { - if (_previewCamera == null) - { - return; - } - - if (!_cameraStateCached) - { - _cachedCameraPosition = _previewCamera.transform.position; - _cachedCameraRotation = _previewCamera.transform.rotation; - _cachedCameraFov = _previewCamera.fieldOfView; - _cameraStateCached = true; - } - - // Apply FOV override independently from auto focus. - if (overrideFieldOfView) - { - _previewCamera.fieldOfView = previewFieldOfView; - } - - if (!autoFocusCamera || modelRoot == null) - { - return; - } - - Vector3 effectiveOffset = ComputeEffectiveCameraOffset(); - Vector3 focusPoint = modelRoot.TransformPoint(cameraFocusOffset) + effectiveOffset; - - Vector3 viewDirection = modelRoot.forward; - viewDirection.y = 0f; - if (viewDirection.sqrMagnitude < 0.0001f) - { - viewDirection = Vector3.back; - } - - viewDirection.Normalize(); - - float effectiveDistance = ComputeEffectiveCameraDistance(modelRoot, focusPoint, viewDirection); - _previewCamera.transform.position = focusPoint + viewDirection * effectiveDistance; - _previewCamera.transform.LookAt(focusPoint); - } - - private bool TryGetViewportSize(out float width, out float height) - { - if (useRawImageViewport && previewFrame != null) - { - RectTransform rt = previewFrame.rectTransform; - Canvas canvas = previewFrame.canvas; - float scale = canvas != null ? canvas.scaleFactor : 1f; - width = rt.rect.width * scale; - height = rt.rect.height * scale; - - if (width > 1f && height > 1f) - { - return true; - } - } - - width = Screen.width; - height = Screen.height; - return width > 0f && height > 0f; - } - - private float ComputeAspectScaledDistance() - { - float distance = previewCameraDistance * ComputeViewportFramingScale(); - return Mathf.Clamp(distance, minAutoCameraDistance, maxAutoCameraDistance); - } - - private float ComputeViewportFramingScale() - { - if (!TryGetViewportSize(out float viewportWidth, out float viewportHeight)) - { - return 1f; - } - - float refWidth = Mathf.Max(1f, referenceScreenWidth); - float refHeight = Mathf.Max(1f, referenceScreenHeight); - - switch (distanceScaleMode) - { - case PreviewDistanceScaleMode.ViewportHeight: - return viewportHeight / refHeight; - default: - float refAspect = refWidth / refHeight; - float viewAspect = viewportWidth / viewportHeight; - return viewAspect / refAspect; - } - } - - private float ComputeViewportHeightScale() - { - if (!TryGetViewportSize(out _, out float viewportHeight)) - { - return 1f; - } - - float refHeight = Mathf.Max(1f, referenceScreenHeight); - return viewportHeight / refHeight; - } - - private Vector3 ComputeEffectiveCameraOffset() - { - if (!scaleCameraOffsetYByViewport) - { - return previewCameraOffset; - } - - // Tuned at 1920x1080: scale is 1.0 so previewCameraOffset.y is unchanged on reference resolution. - float offsetYScale = ComputeViewportHeightScale(); - return new Vector3( - previewCameraOffset.x, - previewCameraOffset.y * offsetYScale, - previewCameraOffset.z); - } - - private float ComputeBoundsFitDistance(Transform modelRoot, Vector3 focusPoint, Vector3 viewDirection) - { - if (modelRoot == null) - { - return previewCameraDistance; - } - - var renderers = modelRoot.GetComponentsInChildren(true); - if (renderers == null || renderers.Length == 0) - { - return previewCameraDistance; - } - - Bounds bounds = renderers[0].bounds; - for (int i = 1; i < renderers.Length; i++) - { - if (renderers[i] != null) - { - bounds.Encapsulate(renderers[i].bounds); - } - } - - if (bounds.size.sqrMagnitude < 0.0001f) - { - return previewCameraDistance; - } - - if (!TryGetViewportSize(out float viewportWidth, out float viewportHeight)) - { - return previewCameraDistance; - } - - Vector3 cameraForward = -viewDirection; - Vector3 cameraRight = Vector3.Cross(cameraForward, Vector3.up); - if (cameraRight.sqrMagnitude < 0.0001f) - { - cameraRight = Vector3.Cross(cameraForward, Vector3.forward); - } - cameraRight.Normalize(); - Vector3 cameraUp = Vector3.Cross(cameraRight, cameraForward).normalized; - - Vector3 boundsMin = bounds.min; - Vector3 boundsMax = bounds.max; - float maxHorizontal = 0f; - float maxVertical = 0f; - - for (int x = 0; x <= 1; x++) - { - for (int y = 0; y <= 1; y++) - { - for (int z = 0; z <= 1; z++) - { - Vector3 corner = new Vector3( - x == 0 ? boundsMin.x : boundsMax.x, - y == 0 ? boundsMin.y : boundsMax.y, - z == 0 ? boundsMin.z : boundsMax.z); - Vector3 offset = corner - focusPoint; - maxHorizontal = Mathf.Max(maxHorizontal, Mathf.Abs(Vector3.Dot(offset, cameraRight))); - maxVertical = Mathf.Max(maxVertical, Mathf.Abs(Vector3.Dot(offset, cameraUp))); - } - } - } - - float viewAspect = viewportWidth / viewportHeight; - float verticalFovRad = previewFieldOfView * Mathf.Deg2Rad; - float halfVerticalTan = Mathf.Tan(verticalFovRad * 0.5f); - if (halfVerticalTan < 0.0001f) - { - return previewCameraDistance; - } - - float halfHorizontalTan = halfVerticalTan * viewAspect; - float distanceForHeight = maxVertical / halfVerticalTan; - float distanceForWidth = maxHorizontal / Mathf.Max(halfHorizontalTan, 0.0001f); - float boundsDistance = Mathf.Max(distanceForHeight, distanceForWidth); - - return boundsDistance * autoFramePadding; - } - - private float ComputeEffectiveCameraDistance(Transform modelRoot, Vector3 focusPoint, Vector3 viewDirection) - { - float aspectScaledDistance = ComputeAspectScaledDistance(); - float effectiveDistance = aspectScaledDistance; - - if (autoFrameByBounds) - { - float boundsDistance = ComputeBoundsFitDistance(modelRoot, focusPoint, viewDirection); - effectiveDistance = Mathf.Max(aspectScaledDistance, boundsDistance); - } - - return Mathf.Clamp(effectiveDistance, minAutoCameraDistance, maxAutoCameraDistance); - } - - //private void StripRuntimeScripts(GameObject cloneRoot) - //{ - // if (cloneRoot == null) - // { - // return; - // } - - // var monoBehaviours = cloneRoot.GetComponentsInChildren(true); - // for (int i = 0; i < monoBehaviours.Length; i++) - // { - // var behaviour = monoBehaviours[i]; - // if (behaviour == null) - // continue; - - // Destroy(behaviour); - // } - - // var colliders = cloneRoot.GetComponentsInChildren(true); - // for (int i = 0; i < colliders.Length; i++) - // { - // var collider = colliders[i]; - // if (collider == null) - // continue; - - // Destroy(collider); - // } - - // var rigidbodies = cloneRoot.GetComponentsInChildren(true); - // for (int i = 0; i < rigidbodies.Length; i++) - // { - // var body = rigidbodies[i]; - // if (body == null) - // continue; - - // Destroy(body); - // } - //} - - private void RestoreSharedCameraState() - { - if (!_cameraStateCached || _previewCamera == null) - { - return; - } - - _previewCamera.transform.position = _cachedCameraPosition; - _previewCamera.transform.rotation = _cachedCameraRotation; - _previewCamera.fieldOfView = _cachedCameraFov; - _cameraStateCached = false; - } - - //private void FreezeAnimators(GameObject cloneRoot) - //{ - // if (cloneRoot == null) - // { - // return; - // } - - // var animators = cloneRoot.GetComponentsInChildren(true); - // for (int i = 0; i < animators.Length; i++) - // { - // var animator = animators[i]; - // if (animator == null) - // continue; - - // 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/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs.meta b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs.meta deleted file mode 100644 index 59dd924a0b..0000000000 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 693e85b6242cc8f4ea4c161aa42dfb1f \ No newline at end of file diff --git a/Assets/Prefabs/UI/InventoryUI.prefab b/Assets/Prefabs/UI/InventoryUI.prefab index 0c16515ba0..f0d4e3e737 100644 --- a/Assets/Prefabs/UI/InventoryUI.prefab +++ b/Assets/Prefabs/UI/InventoryUI.prefab @@ -500,10 +500,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 588.35, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &9112205963990496432 CanvasRenderer: @@ -907,10 +907,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 479.18, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &3997873020355048166 CanvasRenderer: @@ -1238,10 +1238,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 370.01, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4479228720555407959 CanvasRenderer: @@ -4929,10 +4929,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 42.5, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &7052320096474271168 CanvasRenderer: @@ -6208,6 +6208,78 @@ MonoBehaviour: m_FillOrigin: 2 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2704868524884608902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1881134003886110467} + - component: {fileID: 402641304906908385} + - component: {fileID: 7868692572267099838} + m_Layer: 5 + m_Name: RawImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1881134003886110467 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2704868524884608902} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.65, y: 0.65, z: 0.65} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 6778274724352405780} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1024, y: 1024} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &402641304906908385 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2704868524884608902} + m_CullTransparentMesh: 1 +--- !u!114 &7868692572267099838 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2704868524884608902} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 8400000, guid: 7b35d3c1ebbb32d47a5ed61606928730, type: 2} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 --- !u!1 &2741252180928514397 GameObject: m_ObjectHideFlags: 0 @@ -11013,9 +11085,9 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 6778274724352405780} - - component: {fileID: 5765354275366674162} - - component: {fileID: 6707240765686952970} - - component: {fileID: 2036361547023377128} + - component: {fileID: 1379908071248080112} + - component: {fileID: 1721909722328673308} + - component: {fileID: 3977902385666770241} m_Layer: 5 m_Name: character_preview m_TagString: Untagged @@ -11034,7 +11106,8 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 1881134003886110467} m_Father: {fileID: 3289674559629147232} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -11042,7 +11115,7 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 304.4946, y: 608.9891} m_Pivot: {x: 1, y: 1} ---- !u!222 &5765354275366674162 +--- !u!222 &1379908071248080112 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -11050,7 +11123,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5468137454250289500} m_CullTransparentMesh: 1 ---- !u!114 &6707240765686952970 +--- !u!114 &1721909722328673308 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -11059,25 +11132,28 @@ MonoBehaviour: m_GameObject: {fileID: 5468137454250289500} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 0 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Texture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2} - m_UVRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 ---- !u!114 &2036361547023377128 + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &3977902385666770241 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -11086,35 +11162,10 @@ MonoBehaviour: m_GameObject: {fileID: 5468137454250289500} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 693e85b6242cc8f4ea4c161aa42dfb1f, type: 3} + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} m_Name: m_EditorClassIdentifier: - hostPlayer: {fileID: 0} - autoBindHostPlayer: 1 - sourceModelRoot: {fileID: 0} - cloneWholeHostHierarchy: 1 - stripRuntimeComponents: 1 - previewRoot: {fileID: 6778274724352405780} - previewLocalPosition: {x: 0, y: 0, z: 100} - previewLocalEuler: {x: 0, y: 0, z: 0} - previewLocalScale: {x: 1, y: 1, z: 1} - previewFrame: {fileID: 6707240765686952970} - previewRenderTexture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2} - autoFocusCamera: 1 - cameraFocusOffset: {x: 0, y: 0, z: 0} - previewCameraDistance: 3.3 - previewCameraOffset: {x: 0.06, y: 2.04, z: 0} - overrideFieldOfView: 1 - previewFieldOfView: 44 - autoFrameByBounds: 1 - autoFramePadding: 1.15 - minAutoCameraDistance: 1.25 - maxAutoCameraDistance: 8 - referenceScreenWidth: 1920 - referenceScreenHeight: 1080 - useRawImageViewport: 1 - distanceScaleMode: 0 - scaleCameraOffsetYByViewport: 1 + m_ShowMaskGraphic: 1 --- !u!1 &5473020210238587200 GameObject: m_ObjectHideFlags: 0 @@ -14080,10 +14131,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 151.67, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &4452551064742165538 CanvasRenderer: @@ -19527,10 +19578,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 7166820878650541780} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 260.84, y: -59.5} + m_SizeDelta: {x: 85, y: 85} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &5155025384962724770 CanvasRenderer: