From 4d87997a66553ffe8bb558fe2f5021771318aa5c Mon Sep 17 00:00:00 2001 From: JaXt0r Date: Thu, 22 Oct 2026 22:28:07 +0200 Subject: [PATCH 1/3] feat: chests and NPC loot on the Xri backend - using a chest lid swings it open, the content spawns silently into slots laid out to the chest mesh, items can be taken out and dropped back into the open chest (VrContainerDropZone), closing hides the slots and reopening shows the same items; looting an NPC shows its items in XRI "VR Socket Slot"s, equipped weapons with [E], taking one removes it from the NPC (inventory, equipped list, weapon mesh). VRVobContainerPhysicsChest split: backend-neutral VrChestSlots (layout, content, silent spawn, one slot inventory per backend in oCMobContainer.prefab) and HvrPhysicsChest as HVR lid only; interim Xri lid VrChestLidToggle (IVrHinge, lock picking and open/close sounds) until VrHinge in Phase 4; IVrHinge.IsActive + VrHinges.FindActive, IVrBackend.Kind, IVrSocketContainer.IsActive/IsSilent; slots keep their items while deactivated (XRI let go of them when a chest closed); no weapon draw sounds while a chest spawns its content (also on HVR) (HVR phase 3c). Otherwise no player-visible change on the default Hvr backend. Co-Authored-By: Claude Opus 5.5 --- .../VR/Prefabs/Vobs/oCMobContainer.prefab | 1447 ++++++++++++++++- .../Resources/VR/Prefabs/Vobs/oCNpc.prefab | 1 + .../Gothic-VR/Scripts/Adapters/VRNpcLoot.cs | 12 +- .../VRVobContainerSocketInventory.cs | 10 +- .../VRContainerDoorPickingInteraction.cs | 13 +- .../Scripts/Adapters/Vob/VRVobContainer.cs | 6 +- .../Scripts/Adapters/Vob/VRVobDoor.cs | 6 +- .../Interaction/Backends/Hvr/HvrBackend.cs | 2 + .../Backends/Hvr/HvrHingeBridge.cs | 4 + .../Backends/Hvr/HvrPhysicsChest.cs | 304 +--- .../Backends/Hvr/HvrSocketContainerBridge.cs | 6 + .../Interaction/Backends/Xri/XriBackend.cs | 11 +- .../Components/VrChestLidToggle.cs | 162 ++ .../Components/VrChestLidToggle.cs.meta | 2 + .../Interaction/Components/VrChestSlots.cs | 275 ++++ .../Components/VrChestSlots.cs.meta | 2 + .../Interaction/Components/VrHinges.cs | 29 + .../Interaction/Components/VrHinges.cs.meta | 2 + .../Components/VrSocketContainer.cs | 19 + .../Interaction/Components/VrSocketSlot.cs | 28 + .../Scripts/Interaction/Ports/IVrBackend.cs | 6 + .../Scripts/Interaction/Ports/IVrHinge.cs | 6 + .../Interaction/Ports/IVrSocketContainer.cs | 11 + .../phase-3-sockets-inventory.md | 55 +- .../phase-4-doors-chests-ladders.md | 2 + 25 files changed, 2062 insertions(+), 359 deletions(-) create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs.meta create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs.meta create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs create mode 100644 Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs.meta diff --git a/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCMobContainer.prefab b/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCMobContainer.prefab index 2592d8fd0..fcabb65ab 100644 --- a/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCMobContainer.prefab +++ b/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCMobContainer.prefab @@ -754,6 +754,7 @@ Transform: m_Children: - {fileID: 7540743326042314200} - {fileID: 5958767219285650984} + - {fileID: 4433186368314570406} m_Father: {fileID: 2022050282646122291} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3172860016353300812 @@ -1773,6 +1774,73 @@ AudioSource: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 +--- !u!1 &4346627333414460749 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8655296546618503778} + - component: {fileID: 6391945242380171386} + - component: {fileID: 7892604921471703786} + m_Layer: 1 + m_Name: DropZone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8655296546618503778 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4346627333414460749} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4433186368314570406} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!65 &6391945242380171386 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4346627333414460749} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 1 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 0.3, z: 0.75} + m_Center: {x: 0, y: 0.1, z: 0} +--- !u!114 &7892604921471703786 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4346627333414460749} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7941123ebdc7d646a9e2268240bc009, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Components.VrContainerDropZone + _containerGo: {fileID: 0} --- !u!1 &4544068122292998800 GameObject: m_ObjectHideFlags: 0 @@ -2152,6 +2220,9 @@ GameObject: - component: {fileID: 172510743831141755} - component: {fileID: 8269181727875358990} - component: {fileID: 1469359342129423611} + - component: {fileID: 6745565813121138959} + - component: {fileID: 7611355444731811914} + - component: {fileID: 8346136834463750903} m_Layer: 11 m_Name: BIP01 CHEST_.*_1 m_TagString: Untagged @@ -2428,9 +2499,6 @@ MonoBehaviour: PreviousClosed: 0 VerboseLogging: 0 Locked: 0 - _rootGo: {fileID: 6503575194566409312} - _socketContainer: {fileID: 923689649037191229} - _collectorCollider: {fileID: 9145350332021062103} --- !u!114 &172510743831141755 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2467,6 +2535,106 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9fca5660b7d87044b9f6309422813386, type: 3} m_Name: m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Backends.Hvr.HvrHingeBridge +--- !u!114 &6745565813121138959 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5980433150175133251} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8a35f6cfbfba9b548aaa00d52cfe8a50, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.XR.Interaction.Toolkit::UnityEngine.XR.Interaction.Toolkit.Interactables.XRSimpleInteractable + m_InteractionManager: {fileID: 0} + m_Colliders: [] + m_InteractionLayers: + m_Bits: 1 + m_DistanceCalculationMode: 1 + m_SelectMode: 0 + m_FocusMode: 1 + m_CustomReticle: {fileID: 0} + m_AllowGazeInteraction: 0 + m_AllowGazeSelect: 0 + m_OverrideGazeTimeToSelect: 0 + m_GazeTimeToSelect: 0.5 + m_OverrideTimeToAutoDeselectGaze: 0 + m_TimeToAutoDeselectGaze: 3 + m_AllowGazeAssistance: 0 + m_FirstHoverEntered: + m_PersistentCalls: + m_Calls: [] + m_LastHoverExited: + m_PersistentCalls: + m_Calls: [] + m_HoverEntered: + m_PersistentCalls: + m_Calls: [] + m_HoverExited: + m_PersistentCalls: + m_Calls: [] + m_FirstSelectEntered: + m_PersistentCalls: + m_Calls: [] + m_LastSelectExited: + m_PersistentCalls: + m_Calls: [] + m_SelectEntered: + m_PersistentCalls: + m_Calls: [] + m_SelectExited: + m_PersistentCalls: + m_Calls: [] + m_FirstFocusEntered: + m_PersistentCalls: + m_Calls: [] + m_LastFocusExited: + m_PersistentCalls: + m_Calls: [] + m_FocusEntered: + m_PersistentCalls: + m_Calls: [] + m_FocusExited: + m_PersistentCalls: + m_Calls: [] + m_Activated: + m_PersistentCalls: + m_Calls: [] + m_Deactivated: + m_PersistentCalls: + m_Calls: [] + m_StartingHoverFilters: [] + m_StartingSelectFilters: [] + m_StartingInteractionStrengthFilters: [] + m_AutoFindParentInteractableInHierarchy: 0 + m_ParentInteractableObject: {fileID: 0} +--- !u!114 &7611355444731811914 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5980433150175133251} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d53defac19fbb474d81910e60e275fd7, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Backends.Xri.XriInteractableBridge +--- !u!114 &8346136834463750903 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5980433150175133251} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0ba712f1856779441b7ab647bc58f884, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Components.VrChestLidToggle + _openAngle: 110 + _swingTime: 0.4 --- !u!1 &6389233531767616918 GameObject: m_ObjectHideFlags: 0 @@ -2568,6 +2736,7 @@ GameObject: - component: {fileID: 2022050282646122291} - component: {fileID: 3928131288078199320} - component: {fileID: 7775892214903187319} + - component: {fileID: 98959399746428057} m_Layer: 0 m_Name: oCMobContainer m_TagString: GothicVob @@ -2618,6 +2787,22 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _injectionStrategy: 2 +--- !u!114 &98959399746428057 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6503575194566409312} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7038de71bad13264db57802c214cea67, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Components.VrChestSlots + _inventories: + - {fileID: 3405583761693813258} + - {fileID: 6878871074265092263} + _silentAfterSpawnTime: 1 --- !u!1 &6624039968105045667 GameObject: m_ObjectHideFlags: 0 @@ -3160,6 +3345,78 @@ MeshRenderer: m_SortingOrder: 0 m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} +--- !u!1 &6878871074265092263 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4433186368314570406} + - component: {fileID: 8693254405057511817} + - component: {fileID: 11089349496924240} + m_Layer: 0 + m_Name: Inventory XRI + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4433186368314570406 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6878871074265092263} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8655296546618503778} + - {fileID: 4482608820626094088} + - {fileID: 3505978642530898950} + - {fileID: 4817701778405511749} + - {fileID: 1985322522373786713} + - {fileID: 5810689853334014054} + - {fileID: 670284975210572744} + - {fileID: 8078386763284985711} + - {fileID: 11478428076491956} + - {fileID: 2374912704674468940} + - {fileID: 5876822858495877538} + - {fileID: 9178993993575104986} + - {fileID: 358648452475629578} + m_Father: {fileID: 4265338153244332921} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8693254405057511817 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6878871074265092263} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94103fbff7b07d64fb8a87c5cc6e1a54, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Interaction.Components.VrSocketContainer + _slots: [] +--- !u!114 &11089349496924240 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6878871074265092263} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d33b9b45f9124f6b8afdb52a10613db0, type: 3} + m_Name: + m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Adapters.Vob.Container.VRVobContainerSocketInventory + _additionalSockets: [] --- !u!1 &7330976607743722592 GameObject: m_ObjectHideFlags: 0 @@ -4088,95 +4345,173 @@ MeshRenderer: m_SortingOrder: 0 m_MaskInteraction: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!1001 &6500207459066028785 +--- !u!1001 &1400001637806226801 PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: serializedVersion: 3 - m_TransformParent: {fileID: 5958767219285650984} + m_TransformParent: {fileID: 4433186368314570406} m_Modifications: - - target: {fileID: 1590612086424736195, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_Name - value: NameCanvas + value: Slot (6) objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_Pivot.x - value: 0.5 + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_Pivot.y - value: 0.5 + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchorMax.x + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchorMax.y + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchorMin.x + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchorMin.y + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_SizeDelta.x - value: 150 + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_SizeDelta.y - value: 25 + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &8078386763284985711 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 1400001637806226801} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2023147025575119812 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (10) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalPosition.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalPosition.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalPosition.z - value: 0 + value: -0.2 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalRotation.w value: 1 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalRotation.x - value: -0 + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalRotation.y - value: -0 + value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchoredPosition.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - propertyPath: m_AnchoredPosition.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalEulerAnglesHint.x value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalEulerAnglesHint.y value: 0 objectReference: {fileID: 0} - - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} @@ -4184,14 +4519,1016 @@ PrefabInstance: m_RemovedGameObjects: [] m_AddedGameObjects: [] m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} ---- !u!224 &2651072820911968425 stripped -RectTransform: + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &9178993993575104986 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 2023147025575119812} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2425775376582498395 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (2) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &4817701778405511749 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 2425775376582498395} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &3674748899295030204 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (9) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &5876822858495877538 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 3674748899295030204} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &3734126502942786168 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (4) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.4 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &5810689853334014054 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 3734126502942786168} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &4865186542019747410 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (8) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.4 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &2374912704674468940 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 4865186542019747410} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &6041089721858203160 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (1) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &3505978642530898950 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 6041089721858203160} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &6500207459066028785 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 5958767219285650984} + m_Modifications: + - target: {fileID: 1590612086424736195, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_Name + value: NameCanvas + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_SizeDelta.x + value: 150 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_SizeDelta.y + value: 25 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} +--- !u!224 &2651072820911968425 stripped +RectTransform: m_CorrespondingSourceObject: {fileID: 9151279884836745816, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} m_PrefabInstance: {fileID: 6500207459066028785} m_PrefabAsset: {fileID: 0} ---- !u!1 &5487527833069925170 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 1590612086424736195, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} - m_PrefabInstance: {fileID: 6500207459066028785} +--- !u!1 &5487527833069925170 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 1590612086424736195, guid: 2e45e4d4621c88147b3ce7a589bc548c, type: 3} + m_PrefabInstance: {fileID: 6500207459066028785} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &6720658306400350742 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (0) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.4 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &4482608820626094088 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 6720658306400350742} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7158815164180090538 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (7) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &11478428076491956 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 7158815164180090538} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7461289452602374676 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (11) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &358648452475629578 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 7461289452602374676} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7655181781611782614 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (5) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: -0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &670284975210572744 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 7655181781611782614} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &8718044975475590727 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4433186368314570406} + m_Modifications: + - target: {fileID: 2951849760368368205, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Radius + value: 0.1 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.x + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.y + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalScale.z + value: 1.33 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6494516477512632141, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0.7071068 + objectReference: {fileID: 0} + - target: {fileID: 6523535316780004576, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: _size + value: 0.18 + objectReference: {fileID: 0} + - target: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_Name + value: Slot (3) + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.x + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalPosition.z + value: 0.2 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} +--- !u!4 &1985322522373786713 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 7165789852774304286, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} + m_PrefabInstance: {fileID: 8718044975475590727} m_PrefabAsset: {fileID: 0} diff --git a/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCNpc.prefab b/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCNpc.prefab index c6c9198ea..6f72a9c72 100644 --- a/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCNpc.prefab +++ b/Assets/Gothic-VR/Resources/VR/Prefabs/Vobs/oCNpc.prefab @@ -163,6 +163,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Gothic.VR::Gothic.VR.Adapters.VRNpcLoot _socketPrefab: {fileID: 5861164055357080340, guid: 2dd29fe4a7e819740af535267b7cc113, type: 3} + _slotPrefab: {fileID: 7034454508457674463, guid: e970795bd5895ed4d8a7686f050c5832, type: 3} --- !u!1 &2815092147823170342 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Gothic-VR/Scripts/Adapters/VRNpcLoot.cs b/Assets/Gothic-VR/Scripts/Adapters/VRNpcLoot.cs index 9f62cb045..fe5f10401 100644 --- a/Assets/Gothic-VR/Scripts/Adapters/VRNpcLoot.cs +++ b/Assets/Gothic-VR/Scripts/Adapters/VRNpcLoot.cs @@ -8,6 +8,7 @@ using Gothic.Core.Extensions; using Gothic.Core.Manager; using Gothic.Core.Models.Container; +using Gothic.Core.Models.Context; using Gothic.Core.Models.Vm; using Gothic.Core.Models.Vob; using Gothic.Core.Services; @@ -33,8 +34,14 @@ public class VRNpcLoot : MonoBehaviour private const float SocketHeight = 0.8f; private const float SocketSpacing = 0.22f; + [Tooltip("Loot slot on the HVR backend (HVR socket).")] [SerializeField] private GameObject _socketPrefab; + [Tooltip("Loot slot on the other backends (VrSocketSlot, e.g. \"VR Socket Slot.prefab\" for XRI).")] + [SerializeField] private GameObject _slotPrefab; + + [Inject] private readonly IVrBackend _vrBackend; + [Inject] private readonly NpcInventoryService _npcInventoryService; [Inject] private readonly VobService _vobService; [Inject] private readonly AudioService _audioService; @@ -108,10 +115,13 @@ private void PlayOpenSound() private void CreateSockets() { var totalWidth = (MaxVisibleSlots - 1) * SocketSpacing; + var prefab = _vrBackend == null || _vrBackend.Kind == VrInteractionBackend.Hvr + ? _socketPrefab + : _slotPrefab; for (var i = 0; i < MaxVisibleSlots; i++) { - var socketGo = Instantiate(_socketPrefab, transform); + var socketGo = Instantiate(prefab, transform); var xOffset = -totalWidth / 2f + i * SocketSpacing; socketGo.transform.localPosition = new Vector3(xOffset, SocketHeight, 0f); socketGo.transform.localRotation = Quaternion.identity; diff --git a/Assets/Gothic-VR/Scripts/Adapters/Vob/Container/VRVobContainerSocketInventory.cs b/Assets/Gothic-VR/Scripts/Adapters/Vob/Container/VRVobContainerSocketInventory.cs index 5b021549f..274c5bef2 100644 --- a/Assets/Gothic-VR/Scripts/Adapters/Vob/Container/VRVobContainerSocketInventory.cs +++ b/Assets/Gothic-VR/Scripts/Adapters/Vob/Container/VRVobContainerSocketInventory.cs @@ -13,6 +13,8 @@ namespace Gothic.VR.Adapters.Vob.Container /// /// Handle Socket-events for a whole Container (e.g., chest) and its corresponding sockets (rings where we put items into). /// Plays the weapon (un)draw sound when a weapon is put into or taken out of a socket. + /// No sound is played while the IVrSocketContainer on this GameObject (if any) is silent, e.g. while a chest + /// spawns its content. /// public class VRVobContainerSocketInventory : MonoBehaviour { @@ -23,9 +25,11 @@ public class VRVobContainerSocketInventory : MonoBehaviour [SerializeField] private GameObject[] _additionalSockets; private readonly List _sockets = new(); + private IVrSocketContainer _container; private void Awake() { + _container = GetComponent(); _sockets.AddRange(GetComponentsInChildren(true)); foreach (var socketGo in _additionalSockets) { @@ -51,7 +55,7 @@ private void OnDestroy() private void OnBeforeGrabbed(VrGrabArgs args) { - if (args.Interactable == null) + if (args.Interactable == null || IsSilent) return; var container = args.Interactable.GetComponentInParent()?.Container; @@ -62,7 +66,7 @@ private void OnBeforeGrabbed(VrGrabArgs args) private void OnReleased(VrGrabArgs args) { - if (args.Interactable == null) + if (args.Interactable == null || IsSilent) return; var container = args.Interactable.GetComponentInParent()?.Container; @@ -71,6 +75,8 @@ private void OnReleased(VrGrabArgs args) _vrWeaponService.PlayDrawSound(container); } + private bool IsSilent => _container != null && _container.IsSilent; + private bool IsWeapon(VobContainer container) { var itemInstance = container?.GetItemInstance(); diff --git a/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs b/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs index 495250201..857ffd190 100644 --- a/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs +++ b/Assets/Gothic-VR/Scripts/Adapters/Vob/LockPicking/VRContainerDoorPickingInteraction.cs @@ -8,6 +8,7 @@ using Gothic.Core.Services.Vm; using Gothic.VR.Services; using Gothic.VR.Adapters.Vob.VobItem; +using Gothic.VR.Interaction.Components; using Gothic.VR.Interaction.Models; using Gothic.VR.Interaction.Ports; using Reflex.Attributes; @@ -52,8 +53,8 @@ private void Start() { var vobLoader = GetComponentInParent(); _lockable = vobLoader.Container; - // Every door and chest has exactly one hinge (the door wing or the chest lid). - _hinge = vobLoader.GetComponentInChildren(true); + // Every door and chest has one hinge (the door wing or the chest lid) per backend which supports it. + _hinge = VrHinges.FindActive(vobLoader); switch (_lockable.Vob) { case IDoor door: @@ -86,7 +87,7 @@ private IEnumerator StartDelayed() yield return null; // Deactivate rotation - _hinge.Lock(); + _hinge?.Lock(); } private void OnTriggerEnter(Collider other) @@ -235,6 +236,12 @@ private void TryUnlockWithKey(Collider other) private void UnlockAndPushOpen() { // Reactivate rotation + if (_hinge == null) + { + gameObject.SetActive(false); + return; + } + _hinge.Unlock(); // Apply force in the door's forward direction (world space) diff --git a/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobContainer.cs b/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobContainer.cs index e617d160d..e96a5a0ae 100644 --- a/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobContainer.cs +++ b/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobContainer.cs @@ -7,7 +7,7 @@ using Gothic.Core.Logging; using Gothic.Core.Manager; using Gothic.Core.Services.Caches; -using Gothic.VR.Interaction.Ports; +using Gothic.VR.Interaction.Components; using Reflex.Attributes; using UnityEngine; using UnityEngine.SceneManagement; @@ -74,8 +74,8 @@ private void PrepareSounds(IContainer vobContainer) } // We leverage the same "door" script for containers (As it's also just an object to be rotated. - var hinge = GetComponentInChildren(); - hinge.SetSounds(_containerOpenedClips[mdsName.ToLower()], _containerClosedClips[mdsName.ToLower()]); + var hinge = VrHinges.FindActive(this); + hinge?.SetSounds(_containerOpenedClips[mdsName.ToLower()], _containerClosedClips[mdsName.ToLower()]); } } } diff --git a/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobDoor.cs b/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobDoor.cs index a7a33f233..e5e8d8973 100644 --- a/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobDoor.cs +++ b/Assets/Gothic-VR/Scripts/Adapters/Vob/VRVobDoor.cs @@ -5,7 +5,7 @@ using Gothic.Core.Services.Caches; using Gothic.Core; using Gothic.Core.Extensions; -using Gothic.VR.Interaction.Ports; +using Gothic.VR.Interaction.Components; using Reflex.Attributes; using UnityEngine; using ZenKit.Vobs; @@ -64,8 +64,8 @@ private void PrepareSounds(IDoor props) _doorClosedClips.Add(mdsName.ToLower(), _audioService.GetRandomSoundClip(closeSoundEffect)); } - var hinge = GetComponentInChildren(); - hinge.SetSounds(_doorOpenedClips[mdsName.ToLower()], _doorClosedClips[mdsName.ToLower()]); + var hinge = VrHinges.FindActive(this); + hinge?.SetSounds(_doorOpenedClips[mdsName.ToLower()], _doorClosedClips[mdsName.ToLower()]); } } } diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrBackend.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrBackend.cs index 35bc8c9ef..dbd0eab26 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrBackend.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrBackend.cs @@ -1,4 +1,5 @@ #if GOTHIC_HVR_INSTALLED +using Gothic.Core.Models.Context; using Gothic.VR.Interaction.Ports; using Reflex.Core; @@ -7,6 +8,7 @@ namespace Gothic.VR.Interaction.Backends.Hvr public class HvrBackend : IVrBackend { public string Name => "HurricaneVR"; + public VrInteractionBackend Kind => VrInteractionBackend.Hvr; public void InstallBindings(ContainerBuilder containerBuilder) { diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrHingeBridge.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrHingeBridge.cs index e0d4d3c87..a144ed501 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrHingeBridge.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrHingeBridge.cs @@ -1,6 +1,7 @@ #if GOTHIC_HVR_INSTALLED using Gothic.VR.Interaction.Ports; using HurricaneVR.Framework.Components; +using Reflex.Attributes; using UnityEngine; namespace Gothic.VR.Interaction.Backends.Hvr @@ -10,6 +11,8 @@ namespace Gothic.VR.Interaction.Backends.Hvr /// public class HvrHingeBridge : MonoBehaviour, IVrHinge { + [Inject] private readonly IVrBackend _vrBackend; + private HVRPhysicsDoor _door; private HVRPhysicsDoor Door @@ -22,6 +25,7 @@ private HVRPhysicsDoor Door } } + public bool IsActive => _vrBackend == null || _vrBackend is HvrBackend; public Transform Transform => transform; public Rigidbody Rigidbody => GetComponent(); diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrPhysicsChest.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrPhysicsChest.cs index 183b9f351..ab6becfa1 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrPhysicsChest.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrPhysicsChest.cs @@ -1,83 +1,45 @@ #if GOTHIC_HVR_INSTALLED -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Gothic.Core.Adapters.Vob; -using Gothic.Core; -using Gothic.Core.Extensions; using Gothic.Core.Logging; -using Gothic.Core.Models.Caches; -using Gothic.Core.Models.Container; -using Gothic.Core.Services.Caches; -using Gothic.Core.Services.Meshes; -using Gothic.Core.Services.Vobs; using Gothic.VR.Interaction.Components; using Gothic.VR.Interaction.Ports; using HurricaneVR.Framework.Components; -using HurricaneVR.Framework.Core; -using HurricaneVR.Framework.Core.Sockets; -using MyBox; using Reflex.Attributes; -using UnityEngine; -using ZenKit.Daedalus; -using ZenKit.Vobs; using Logger = Gothic.Core.Logging.Logger; namespace Gothic.VR.Interaction.Backends.Hvr { /// - /// Chest lid (HVR physics door) which fills the chest's sockets with its content when opened for the first time. - /// Temporarily in the HVR backend as it subclasses HVRPhysicsDoor. The sockets are used via IVrSocketContainer. + /// Chest lid (HVR physics door). Opening it shows the chest's slots (VrChestSlots, which spawns the content on + /// the first open), closing it hides them. + /// Temporarily in the HVR backend as it subclasses HVRPhysicsDoor (VrHinge in Phase 4). On other backends it + /// switches itself off before the door is set up (VrChestLidToggle is the lid there). /// public class HvrPhysicsChest : HVRPhysicsDoor { - [Inject] private readonly MeshService _meshService; - [Inject] private readonly VobService _vobService; - [Inject] private readonly ResourceCacheService _resourceCacheService; + [Inject] private readonly IVrBackend _vrBackend; - - private readonly char[] _itemNameSeparators = { ';', ',' }; - private readonly char[] _itemCountSeparators = { ':', '.' }; - - // Need to be updated if ocMobContainer.prefab is changed. - private const int _socketRows = 3; - private const int _socketsPerRow = 4; - private const float _socketRadius = 0.1f; - private const float _socketCollectionMargin = _socketRadius / 2; - - [Separator("Gothic - Settings")] - [SerializeField] private GameObject _rootGo; - [SerializeField] private HVRSocketContainer _socketContainer; - [SerializeField] private BoxCollider _collectorCollider; - private IContainer _vobContainer; - private IVrSocketContainer _sockets; + private VrChestSlots _chestSlots; // Flags to ensure we always call On*() once, everytime open/close status changes. - private bool _openingForTheFirstTime = true; private bool _onOpenedHandled; private bool _onClosedHandled; - - - [Serializable] - [Obsolete("Moved to Gothic.Core.Data.Vobs.ContentItem")] - public struct ContentItem - { - public string Name; - public int Amount; - } - - + + public override void Start() { + if (_vrBackend != null && _vrBackend is not HvrBackend) + { + enabled = false; + return; + } + base.Start(); - _sockets = _socketContainer.GetComponent(); - _socketContainer.gameObject.SetActive(false); - - _vobContainer = _rootGo.GetComponentInParent().Container.VobAs(); + _chestSlots = GetComponentInParent(); + if (_chestSlots == null) + Logger.LogError($"[HVR] Chest lid {name} has no VrChestSlots in its parents.", LogCat.VR); } - + protected override void Update() { base.Update(); @@ -92,238 +54,24 @@ protected override void Update() OnClosed(); } } - + private void OnOpened() { - if (_openingForTheFirstTime) - { - AlignSockets(); - StartCoroutine(InitializeContent()); - _openingForTheFirstTime = false; - } - - // Render items if opened for the first time. - _socketContainer.gameObject.SetActive(true); - + if (_chestSlots != null) + _chestSlots.Open(); + _onOpenedHandled = true; _onClosedHandled = false; } - + private void OnClosed() { - _socketContainer.gameObject.SetActive(false); - + if (_chestSlots != null) + _chestSlots.Close(); + _onOpenedHandled = false; _onClosedHandled = true; } - - /// - /// Containers have different sizes. Re-align the prefab's HVR sockets to match their actual sizes. - /// - private void AlignSockets() - { - var sockets = _sockets.Sockets; - - // We need to dynamically fetch the bounding box of main mesh as some chests have the correct one inside BIP01 "CHEST_*_0" and others inside "ZM_CHEST*" - var meshFilters = _rootGo - .GetComponentsInChildren() // Find all meshes - .Where(i => !i.TryGetComponent(typeof(HVRGrabbable), out _)) // Filter out meshe, which is the lid - .Where(i => i.gameObject.name.StartsWithIgnoreCase("ZM_") || i.gameObject.name.StartsWithIgnoreCase("BIP01")) // Use Gothic elements only. Ignore elements like HVR sockets. - .Where(i => !i.gameObject.name.ContainsIgnoreCase("LOCK")) // Ignore lock element - .ToArray(); - - MeshFilter usedMesh; - if (meshFilters.IsEmpty()) - { - Logger.LogError($"No suitable mesh found for HVR Socket size calculation in {_rootGo.name}. Skipping...", LogCat.VR); - return; - } - else if (meshFilters.Length >= 2) - { - Logger.LogWarning($"More than one feasible MeshFilter for HVR Socket size calculation found in {_rootGo.name}. Leveraging first (1)ZM_* or (2)BIP01 one.", LogCat.VR); - - // Based on mesh check of all containers in G1, the highest priority for the right mesh is a ZM_* GO if existing. - var zmMesh = meshFilters.FirstOrDefault(i => i.gameObject.name.StartsWithIgnoreCase("ZM_")); - usedMesh = zmMesh ?? meshFilters.First(); - } - else - { - usedMesh = meshFilters.First(); - } - - var mainMeshBounds = usedMesh!.sharedMesh.bounds; - - // Set collectorCollider's size to perfectly align with container. - _collectorCollider.size = new Vector3(mainMeshBounds.size.x, _collectorCollider.size.y, mainMeshBounds.size.z); - - // Move all Slots nearly towards height of container (*1,5 == 75% close to top). - _socketContainer.transform.localPosition = new (0, mainMeshBounds.center.y * 1.5f, 0); - - var centeredMainBound = new Bounds(Vector3.zero, mainMeshBounds.size); - - // Align all sockets in row+column based on actual sizes. - var rowWidth = (centeredMainBound.size.x - 2*_socketCollectionMargin) / _socketsPerRow; - var rowDepth = (centeredMainBound.size.z - 2*_socketCollectionMargin) / _socketRows; - - // Calculate center of a grid-element for a socket ring entry. - var middleAlignmentX = (rowWidth - _socketRadius * 2) / 2; - var middleAlignmentZ = (rowDepth - _socketRadius * 2) / 2; - - // Loop variables - var currentRow = 0; - var currentColumn = 0; - - foreach (var socket in sockets) - { - // Calculation - // _socketCollectionMargin - Left aligned margin for the whole collection - // _socketRadius - Location is based on a 50% shift into the desired area as the drawing of a circle starts centered - // middleAlignment* - Centered location within a grid for an element - // min.x - Start point to calculate from left top - socket.Transform.localPosition = new ( - _socketCollectionMargin + _socketRadius + middleAlignmentX + centeredMainBound.min.x + rowWidth * currentColumn, - 0, - _socketCollectionMargin + _socketRadius + middleAlignmentZ + centeredMainBound.min.z + rowDepth * currentRow - ); - - currentColumn++; - if (currentColumn >= _socketsPerRow) - { - currentColumn = 0; - currentRow++; - } - } - } - - private IEnumerator InitializeContent() - { - var contents = _vobContainer.Contents; - - if (string.IsNullOrEmpty(contents)) - { - yield break; - } - - var contentItems = ParseContent(contents); - - PreSpawnContent(out AudioClip grabAudio, out AudioClip releaseAudio); - yield return SpawnContent(contentItems); - yield return PostSpawnContent(grabAudio, releaseAudio); - } - - private List ParseContent(string contents) - { - List result = new(); - - var items = contents.Split(_itemNameSeparators); - - foreach (var item in items) - { - var count = 1; - var nameCountSplit = item.Split(_itemCountSeparators); - - if (nameCountSplit.Length != 1) - { - count = int.Parse(nameCountSplit[1]); - } - - result.Add(new ContentItem - { - Name = nameCountSplit[0], - Amount = count - }); - } - - return result; - } - - - /// - /// When we spawn items later, they will be automatically collected by the HVR Collector. It will put their meshes - /// into place. But it will also play an audio file. We will temporarily remove this file until we're done adding the items. - /// - private void PreSpawnContent(out AudioClip grabAudio, out AudioClip releaseAudio) - { - // We assume that all Slots have the same sound. Therefore fetching first only. - var firstSocket = _sockets.Sockets.First(); - grabAudio = firstSocket.PlacedSoundFallback; - releaseAudio = firstSocket.RemovedSoundFallback; - - foreach (var socket in _sockets.Sockets) - { - socket.PlacedSoundFallback = null; - socket.RemovedSoundFallback = null; - } - } - - private IEnumerator SpawnContent(List contentItems) - { - var sockets = _sockets.Sockets; - - if (contentItems.Count > sockets.Count) - { - Logger.LogError("There are more items in a container than HVRSockets available. Please implement pagination to ensure everything is visible and can be grabbed!", LogCat.VR); - } - - for (var i = 0; i < Math.Min(contentItems.Count, sockets.Count); i++) - { - var currentItem = contentItems[i]; - - var zkVob = new Item - { - Name = currentItem.Name, - Amount = currentItem.Amount, - Visual = new VisualMesh - { - Name = currentItem.Name - } - }; - - var vobContainer = _vobService.CreateItem(zkVob); - - // Wait 1 frame to ensure our mesh bounds can be calculated by HVR Socket. - yield return null; - - PlaceObjectIntoContainer(vobContainer); - } - } - - private void PlaceObjectIntoContainer(VobContainer vobContainer) - { - var interactable = vobContainer.Go.GetComponentInChildren(true); - if (_sockets.TryFindFree(interactable, out var socket)) - { - socket.TryPlace(interactable, true); - // We need to reset position as the element won't be placed inside it's parent in the chest. - vobContainer.Go.transform.localPosition = Vector3.zero; - } - } - - private IEnumerator PostSpawnContent(AudioClip grabAudio, AudioClip releaseAudio) - { - // We wait for some time to ensure the objects are automatically snapped into place. - yield return new WaitForSeconds(1f); - - foreach (var socket in _sockets.Sockets) - { - socket.PlacedSoundFallback = grabAudio; - socket.RemovedSoundFallback = releaseAudio; - } - } - - /// - /// FIXME - Only temporary function. In the future we need to create a new Item to use it (e.g.) for saving later. - /// FIXME - For now we stick with the mesh without properties only. - /// 1. Create a new ZenKit.Vob.Item object - /// 2. Call VobCreator.CreateItem(vob, ...) - /// - private GameObject TempCreateItem(ItemInstance itemInstance) - { - var go = _resourceCacheService.TryGetPrefabObject(PrefabType.VobItem); - - var mrm = _resourceCacheService.TryGetMultiResolutionMesh(itemInstance.Visual); - return _meshService.CreateVob(itemInstance.Name, mrm, default, default, true, rootGo: go, useTextureArray: false); - } } } #endif diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrSocketContainerBridge.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrSocketContainerBridge.cs index ab571cff9..26c5cebaf 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrSocketContainerBridge.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Hvr/HvrSocketContainerBridge.cs @@ -5,6 +5,7 @@ using Gothic.VR.Interaction.Ports; using HurricaneVR.Framework.Core; using HurricaneVR.Framework.Core.Sockets; +using Reflex.Attributes; using UnityEngine; using Logger = Gothic.Core.Logging.Logger; @@ -15,6 +16,8 @@ namespace Gothic.VR.Interaction.Backends.Hvr /// public class HvrSocketContainerBridge : MonoBehaviour, IVrSocketContainer { + [Inject] private readonly IVrBackend _vrBackend; + private HVRSocketContainer _container; private readonly Dictionary _savedSounds = new(); private bool _isSilent; @@ -29,6 +32,9 @@ private HVRSocketContainer Container } } + public bool IsActive => _vrBackend == null || _vrBackend is HvrBackend; + public bool IsSilent => _isSilent; + public IReadOnlyList Sockets { get diff --git a/Assets/Gothic-VR/Scripts/Interaction/Backends/Xri/XriBackend.cs b/Assets/Gothic-VR/Scripts/Interaction/Backends/Xri/XriBackend.cs index 7efb2f32d..dde1666ea 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Backends/Xri/XriBackend.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Backends/Xri/XriBackend.cs @@ -1,4 +1,5 @@ using Gothic.Core.Logging; +using Gothic.Core.Models.Context; using Gothic.VR.Interaction.Ports; using Reflex.Core; using Logger = Gothic.Core.Logging.Logger; @@ -11,19 +12,21 @@ namespace Gothic.VR.Interaction.Backends.Xri /// with ScreenFade/WallFade on its camera), the XR Interaction Simulator and item grabbing (Near-Far interactor /// per hand, GothicGrabInteractable + XriInteractableBridge on oCItem), using mobs/NPCs and the socket core /// (VrSocketSlot + XriSocketBridge, "VR Socket Slot.prefab"), the backpack ("BackPack XRI.prefab") on the - /// shoulder and the hip/shoulder holsters (VrBodyAnchor "Shoulders"/"Waist" on the rig). - /// Missing: chests/NPC loot (3c), doors/chests/ladders (4) and hands (5). + /// shoulder and the hip/shoulder holsters (VrBodyAnchor "Shoulders"/"Waist" on the rig), chest slots + /// (VrChestSlots, lid opened by using it: VrChestLidToggle) and NPC loot slots. + /// Missing: physical doors/chest lids/ladders (4) and hands (5). /// public class XriBackend : IVrBackend { public string Name => "XR Interaction Toolkit"; + public VrInteractionBackend Kind => VrInteractionBackend.Xri; public void InstallBindings(ContainerBuilder containerBuilder) { Logger.LogWarning("XRI backend is work in progress: rig, locomotion, input, haptics, UI laser pointers, " + "screen fades, the XR Interaction Simulator, grabbing (items, mobs, NPCs), the " + - "backpack and holsters work. Chests/NPC loot (phase 3c), doors/chests/ladders (4) and " + - "hands (5) are missing.", LogCat.VR); + "backpack, holsters, chest slots (lid opens by using it) and NPC loot work. " + + "Physical doors/chest lids/ladders (4) and hands (5) are missing.", LogCat.VR); containerBuilder.AddSingleton(typeof(XriInput), typeof(IVrInput), typeof(XriInput)); containerBuilder.AddSingleton(typeof(XriHaptics), typeof(IVrHaptics)); diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs new file mode 100644 index 000000000..5a0e0dfbf --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs @@ -0,0 +1,162 @@ +using System.Collections; +using Gothic.Core.Logging; +using Gothic.Core.Models.Context; +using Gothic.VR.Interaction.Models; +using Gothic.VR.Interaction.Ports; +using Reflex.Attributes; +using UnityEngine; +using Logger = Gothic.Core.Logging.Logger; + +namespace Gothic.VR.Interaction.Components +{ + /// + /// Interim chest lid for the XRI backend until Phase 4 (VrHinge): using the lid (select-only grab, like a mob) + /// swings it open and shows the chest's slots (VrChestSlots), using it again closes it. The lid is kinematic, + /// there is no physical pushing/pulling yet. Respects Lock()/Unlock() of the lock picking and plays the + /// open/close sounds of VRVobContainer. + /// Inactive on HVR, where HvrPhysicsChest (HVR physics door) is the lid. + /// + public class VrChestLidToggle : MonoBehaviour, IVrHinge + { + [Tooltip("Rotation around the lid's local X axis when open (degrees).")] + [SerializeField] private float _openAngle = 110f; + + [Tooltip("Seconds the lid needs to swing open or closed.")] + [SerializeField] private float _swingTime = 0.4f; + + [Inject] private readonly IVrBackend _vrBackend; + [Inject] private readonly IVrSfxPlayer _sfxPlayer; + + private VrInteractable _interactable; + private VrChestSlots _chestSlots; + private Rigidbody _rigidbody; + private Quaternion _closedRotation; + private AudioClip _openedClip; + private AudioClip _closedClip; + private Coroutine _swingRoutine; + private bool _isSubscribed; + private bool _isLocked; + private bool _isOpen; + + public bool IsActive => _vrBackend != null && _vrBackend.Kind == VrInteractionBackend.Xri; + public bool IsOpen => _isOpen; + public bool IsLocked => _isLocked; + public Transform Transform => transform; + public Rigidbody Rigidbody => GetComponent(); + + private void Start() + { + if (!IsActive) + { + enabled = false; + return; + } + + // No joint holds the lid (HvrPhysicsChest doesn't set up its door on XRI). + _rigidbody = GetComponent(); + if (_rigidbody != null) + _rigidbody.isKinematic = true; + + _closedRotation = transform.localRotation; + _chestSlots = GetComponentInParent(); + _interactable = GetComponent(); + if (_interactable == null || _chestSlots == null) + { + Logger.LogError($"[Chest] {name} needs a VrInteractable and a VrChestSlots in its parents.", + LogCat.VR); + return; + } + + _interactable.Grabbed += OnGrabbed; + _isSubscribed = true; + } + + private void OnDestroy() + { + if (_isSubscribed && _interactable != null) + _interactable.Grabbed -= OnGrabbed; + } + + public void Lock() + { + _isLocked = true; + } + + public void Unlock() + { + _isLocked = false; + } + + public void SetSounds(AudioClip opened, AudioClip closed) + { + _openedClip = opened; + _closedClip = closed; + } + + public void Toggle() + { + if (_isOpen) + Close(); + else + Open(); + } + + public void Open() + { + if (_isOpen || !isActiveAndEnabled) + return; + + if (_isLocked) + { + Logger.Log($"[Chest] {name} is locked.", LogCat.VR); + return; + } + + _isOpen = true; + Swing(_closedRotation * Quaternion.Euler(_openAngle, 0, 0), _openedClip); + _chestSlots.Open(); + } + + public void Close() + { + if (!_isOpen || !isActiveAndEnabled) + return; + + _isOpen = false; + _chestSlots.Close(); + Swing(_closedRotation, _closedClip); + } + + private void OnGrabbed(VrGrabArgs args) + { + // Hands "use" the lid (XRSimpleInteractable). Sockets never hold it. + if (!args.IsHandOrDistance) + return; + + Toggle(); + } + + private void Swing(Quaternion target, AudioClip clipAtEnd) + { + if (_swingRoutine != null) + StopCoroutine(_swingRoutine); + _swingRoutine = StartCoroutine(SwingTo(target, clipAtEnd)); + } + + private IEnumerator SwingTo(Quaternion target, AudioClip clipAtEnd) + { + var start = transform.localRotation; + for (var time = 0f; time < _swingTime; time += Time.deltaTime) + { + transform.localRotation = Quaternion.Slerp(start, target, time / _swingTime); + yield return null; + } + + transform.localRotation = target; + _swingRoutine = null; + + if (clipAtEnd != null && _sfxPlayer != null) + _sfxPlayer.Play(clipAtEnd, transform.position); + } + } +} diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs.meta new file mode 100644 index 000000000..dfa3b4965 --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestLidToggle.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0ba712f1856779441b7ab647bc58f884 \ No newline at end of file diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs new file mode 100644 index 000000000..3a5bd6c55 --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Gothic.Core.Adapters.Vob; +using Gothic.Core.Extensions; +using Gothic.Core.Logging; +using Gothic.Core.Models.Container; +using Gothic.Core.Models.Vob; +using Gothic.Core.Services.Vobs; +using Gothic.VR.Interaction.Ports; +using Reflex.Attributes; +using UnityEngine; +using ZenKit.Vobs; +using Logger = Gothic.Core.Logging.Logger; + +namespace Gothic.VR.Interaction.Components +{ + /// + /// Content of a chest (oCMobContainer), independent of the lid: the lid (HvrPhysicsChest on HVR, + /// VrChestLidToggle on XRI until VrHinge in Phase 4) calls Open()/Close(). + /// - The prefab carries one slot inventory (IVrSocketContainer) per VR backend. The active one is used, the + /// others stay hidden. + /// - First open: the slots are laid out to the size of the chest mesh and the content (IContainer.Contents) is + /// spawned into them, without socket sounds. + /// - Closing hides the slots (and the items inside). + /// + public class VrChestSlots : MonoBehaviour + { + // Need to be updated if oCMobContainer.prefab is changed. + private const int SlotRows = 3; + private const int SlotsPerRow = 4; + private const float SlotRadius = 0.1f; + private const float SlotCollectionMargin = SlotRadius / 2; + + [Tooltip("Slot inventories (with an IVrSocketContainer), one per VR backend. The first active one is used. " + + "A BoxCollider below it (drop zone / collector) is resized to the chest.")] + [SerializeField] private List _inventories = new(); + + [Tooltip("Seconds after spawning the content until socket sounds play again (HVR snaps items in later).")] + [SerializeField] private float _silentAfterSpawnTime = 1f; + + [Inject] private readonly VobService _vobService; + + private GameObject _inventoryGo; + private IVrSocketContainer _container; + private BoxCollider _collector; + private bool _isResolved; + private bool _isContentSpawned; + private bool _isSpawning; + private bool _isOpen; + + public bool IsOpen => _isOpen; + + /// + /// Slots of the active backend. Null if the chest has no active inventory. + /// + public IVrSocketContainer Container + { + get + { + Resolve(); + return _container; + } + } + + private void Start() + { + Resolve(); + if (!_isOpen && _inventoryGo != null) + _inventoryGo.SetActive(false); + } + + public void Open() + { + Resolve(); + if (_inventoryGo == null) + return; + + _isOpen = true; + _inventoryGo.SetActive(true); + + if (_isContentSpawned) + return; + + _isContentSpawned = true; + AlignSlots(); + StartCoroutine(SpawnContent()); + } + + public void Close() + { + _isOpen = false; + + // Items are put into active slots only. The inventory is hidden once the spawning is done. + if (_inventoryGo != null && !_isSpawning) + _inventoryGo.SetActive(false); + } + + private void Resolve() + { + if (_isResolved) + return; + + _isResolved = true; + foreach (var inventory in _inventories) + { + if (inventory == null) + continue; + + var container = inventory.GetComponent(); + if (_container == null && container != null && container.IsActive) + { + _container = container; + _inventoryGo = inventory; + _collector = inventory.GetComponentInChildren(true); + continue; + } + + inventory.SetActive(false); + } + + if (_container == null) + Logger.LogWarning($"[Chest] {name} has no slot inventory for the active VR backend.", LogCat.VR); + } + + /// + /// Containers have different sizes. Re-align the prefab's slots to match their actual sizes. + /// + private void AlignSlots() + { + // We need to dynamically fetch the bounding box of main mesh as some chests have the correct one inside + // BIP01 "CHEST_*_0" and others inside "ZM_CHEST*". + var meshFilters = GetComponentsInChildren() + .Where(i => i.GetComponentInParent() == null) // Not the lid, not items inside. + .Where(i => i.gameObject.name.StartsWithIgnoreCase("ZM_") || + i.gameObject.name.StartsWithIgnoreCase("BIP01")) // Gothic meshes only, no slot rings. + .Where(i => !i.gameObject.name.ContainsIgnoreCase("LOCK")) // Ignore lock element + .ToArray(); + + MeshFilter usedMesh; + if (meshFilters.Length == 0) + { + Logger.LogError($"No suitable mesh found for chest slot size calculation in {name}. Skipping...", + LogCat.VR); + return; + } + else if (meshFilters.Length >= 2) + { + Logger.LogWarning($"More than one feasible MeshFilter for chest slot size calculation found in " + + $"{name}. Leveraging first (1)ZM_* or (2)BIP01 one.", LogCat.VR); + + // Based on mesh check of all containers in G1, the highest priority for the right mesh is a ZM_* GO + // if existing. + var zmMesh = meshFilters.FirstOrDefault(i => i.gameObject.name.StartsWithIgnoreCase("ZM_")); + usedMesh = zmMesh ?? meshFilters.First(); + } + else + { + usedMesh = meshFilters.First(); + } + + var mainMeshBounds = usedMesh!.sharedMesh.bounds; + + // Set the collector's/drop zone's size to perfectly align with container. + if (_collector != null) + _collector.size = new Vector3(mainMeshBounds.size.x, _collector.size.y, mainMeshBounds.size.z); + + // Move all Slots nearly towards height of container (*1,5 == 75% close to top). + _inventoryGo.transform.localPosition = new(0, mainMeshBounds.center.y * 1.5f, 0); + + var centeredMainBound = new Bounds(Vector3.zero, mainMeshBounds.size); + + // Align all slots in row+column based on actual sizes. + var rowWidth = (centeredMainBound.size.x - 2 * SlotCollectionMargin) / SlotsPerRow; + var rowDepth = (centeredMainBound.size.z - 2 * SlotCollectionMargin) / SlotRows; + + // Calculate center of a grid-element for a slot ring entry. + var middleAlignmentX = (rowWidth - SlotRadius * 2) / 2; + var middleAlignmentZ = (rowDepth - SlotRadius * 2) / 2; + + var currentRow = 0; + var currentColumn = 0; + + foreach (var socket in _container.Sockets) + { + // SlotCollectionMargin - Left aligned margin for the whole collection + // SlotRadius - Location is based on a 50% shift into the desired area as the drawing of a circle + // starts centered + // middleAlignment* - Centered location within a grid for an element + // min.x - Start point to calculate from left top + socket.Transform.localPosition = new( + SlotCollectionMargin + SlotRadius + middleAlignmentX + centeredMainBound.min.x + + rowWidth * currentColumn, + 0, + SlotCollectionMargin + SlotRadius + middleAlignmentZ + centeredMainBound.min.z + + rowDepth * currentRow + ); + + currentColumn++; + if (currentColumn >= SlotsPerRow) + { + currentColumn = 0; + currentRow++; + } + } + } + + private IEnumerator SpawnContent() + { + var vobContainer = GetComponentInParent()?.Container?.VobAs(); + var contentItems = _vobService.UnpackItems(vobContainer?.Contents); + if (contentItems.Count == 0) + yield break; + + _isSpawning = true; + _container.SetSilent(true); + + var sockets = _container.Sockets; + if (contentItems.Count > sockets.Count) + { + Logger.LogError("There are more items in a container than slots available. Please implement " + + "pagination to ensure everything is visible and can be grabbed!", LogCat.VR); + } + + for (var i = 0; i < Math.Min(contentItems.Count, sockets.Count); i++) + { + var item = SpawnItem(contentItems[i]); + + // Wait 1 frame to ensure our mesh bounds can be calculated by the slot. + yield return null; + + PlaceIntoSlot(item); + } + + // HVR snaps the items into place a bit later. They stay silent until then. + yield return new WaitForSeconds(_silentAfterSpawnTime); + + _container.SetSilent(false); + _isSpawning = false; + if (!_isOpen) + _inventoryGo.SetActive(false); + } + + private VobContainer SpawnItem(ContentItem contentItem) + { + var zkVob = new Item + { + Name = contentItem.Name, + Amount = contentItem.Amount, + Visual = new VisualMesh + { + Name = contentItem.Name + } + }; + + return _vobService.CreateItem(zkVob); + } + + private void PlaceIntoSlot(VobContainer vobContainer) + { + var interactable = vobContainer?.Go.GetComponentInChildren(true); + if (interactable == null || !_container.TryFindFree(interactable, out var socket) || + !socket.TryPlace(interactable, true)) + { + Logger.LogWarning($"[Chest] Couldn't put {vobContainer?.Go.name} into a slot of {name}.", LogCat.VR); + return; + } + + // HVR sockets don't put the VobLoader at the slot's origin. VrSocketSlot centers the item itself. + if (socket is not VrSocketSlot) + vobContainer.Go.transform.localPosition = Vector3.zero; + } + } +} diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs.meta new file mode 100644 index 000000000..5f8bf215d --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrChestSlots.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7038de71bad13264db57802c214cea67 \ No newline at end of file diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs b/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs new file mode 100644 index 000000000..32347bbe0 --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs @@ -0,0 +1,29 @@ +using Gothic.VR.Interaction.Ports; +using UnityEngine; + +namespace Gothic.VR.Interaction.Components +{ + /// + /// Finds the hinge (door wing, chest lid) of the active VR backend. Shared prefabs may carry one per backend. + /// + public static class VrHinges + { + /// + /// The first active IVrHinge on or below the component. Null if none of them is active (e.g. a door on a + /// backend without hinges yet). + /// + public static IVrHinge FindActive(Component root) + { + if (root == null) + return null; + + foreach (var hinge in root.GetComponentsInChildren(true)) + { + if (hinge.IsActive) + return hinge; + } + + return null; + } + } +} diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs.meta b/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs.meta new file mode 100644 index 000000000..70d01df2e --- /dev/null +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrHinges.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e32b5ce0da1d32f44b6b8b1f3dd722f2 \ No newline at end of file diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketContainer.cs b/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketContainer.cs index ea15b5287..91671225c 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketContainer.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketContainer.cs @@ -27,6 +27,25 @@ public IReadOnlyList Sockets } } + /// + /// True if one of the slots has a backend part of the active VR backend (e.g. XriSocketBridge on XRI). + /// + public bool IsActive + { + get + { + foreach (var slot in Slots) + { + if (slot != null && slot.HasActiveBackend) + return true; + } + + return false; + } + } + + public bool IsSilent => _isSilent; + public IReadOnlyList Slots { get diff --git a/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketSlot.cs b/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketSlot.cs index 239c37cef..890304116 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketSlot.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Components/VrSocketSlot.cs @@ -94,6 +94,7 @@ public class VrSocketSlot : MonoBehaviour, IVrSocket private Rigidbody _heldRigidbody; private bool _wasKinematic; private bool _isPlacedEventRaised; + private bool _isReselectNeeded; private Coroutine _fitRoutine; public VrGrabberKind Kind => VrGrabberKind.Socket; @@ -106,6 +107,11 @@ public class VrSocketSlot : MonoBehaviour, IVrSocket public bool IsHovered => _hovered.Count > 0; public Transform AttachPoint => _attachPoint != null ? _attachPoint : transform; + /// + /// True if a backend part of the active VR backend sits next to this slot (it detects items). + /// + public bool HasActiveBackend => Backend != null; + public float Size { get => _size; @@ -190,6 +196,19 @@ private void Awake() _ = Backend; } + private void OnEnable() + { + if (!_isReselectNeeded) + return; + + _isReselectNeeded = false; + if (_held == null || Backend == null || Backend.TryPlace(_held)) + return; + + Logger.LogWarning($"[Socket] Backend couldn't hold {_held.name} in {name} again. Taken out.", LogCat.VR); + Remove(true); + } + private void OnDisable() { // Hover exits of a disabled backend may not arrive anymore. @@ -319,6 +338,14 @@ internal void OnBackendRemoved(VrInteractable interactable) if (interactable == null || interactable != _held) return; + // The slot is being deactivated (e.g. a chest is closed): the backend lets go of everything, but the item + // stays inside (and hidden with the slot). The backend holds it again once the slot is enabled. + if (!gameObject.activeInHierarchy) + { + _isReselectNeeded = true; + return; + } + Remove(false); } @@ -429,6 +456,7 @@ private void Detach(Transform root) var previousParent = _previousParent; var previousScale = _previousScale; + _isReselectNeeded = false; _held = null; _heldRoot = null; _heldRigidbody = null; diff --git a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrBackend.cs b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrBackend.cs index bd7c4dc4c..d9a310e20 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrBackend.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrBackend.cs @@ -1,3 +1,4 @@ +using Gothic.Core.Models.Context; using Reflex.Core; namespace Gothic.VR.Interaction.Ports @@ -10,6 +11,11 @@ public interface IVrBackend { string Name { get; } + /// + /// Which DeveloperConfig.VrInteractionBackend this is. + /// + VrInteractionBackend Kind { get; } + /// /// Registers the backend's implementations of IVrInput, IVrHaptics, IVrUiPointers and IVrSfxPlayer. /// IVrRig isn't registered here, as it lives on the player prefab. diff --git a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrHinge.cs b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrHinge.cs index db138b212..100e8500f 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrHinge.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrHinge.cs @@ -4,9 +4,15 @@ namespace Gothic.VR.Interaction.Ports { /// /// A physically rotating door or chest lid. + /// Shared prefabs may carry one hinge per backend: use the active one (VrHinges.FindActive). /// public interface IVrHinge { + /// + /// Whether this hinge belongs to the active VR backend. + /// + bool IsActive { get; } + Transform Transform { get; } Rigidbody Rigidbody { get; } diff --git a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrSocketContainer.cs b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrSocketContainer.cs index 44b24a4b2..d166b1274 100644 --- a/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrSocketContainer.cs +++ b/Assets/Gothic-VR/Scripts/Interaction/Ports/IVrSocketContainer.cs @@ -10,6 +10,17 @@ public interface IVrSocketContainer { IReadOnlyList Sockets { get; } + /// + /// Whether this container belongs to the active VR backend. Shared prefabs (e.g. chests) carry one container + /// per backend. + /// + bool IsActive { get; } + + /// + /// See SetSilent. + /// + bool IsSilent { get; } + /// /// Finds the first free socket which accepts the interactable. /// diff --git a/Docs/HVR-replacement/phase-3-sockets-inventory.md b/Docs/HVR-replacement/phase-3-sockets-inventory.md index 53dc36e26..2b24aa4b2 100644 --- a/Docs/HVR-replacement/phase-3-sockets-inventory.md +++ b/Docs/HVR-replacement/phase-3-sockets-inventory.md @@ -17,12 +17,21 @@ PlayMode test), **3b** backpack + shoulder socket + hip holsters + HeadRelativeI flip), save → load.) - [x] Hip/back holsters keep weapons; drawing and holstering updates the inventory as today. (3b; holster, teleport while holstered, draw played on Xri with an item. Not played: swimming, walking with real tracking.) -- [ ] Chests: the content spawns into slots (scaled down), items can be taken and put back; dropping an item into the - open chest stores it. -- [ ] NPC loot: equipped and inventory items appear in loot slots, taking one moves it to the player. -- [ ] Hover feedback on slots (scale and valid/invalid material) is equivalent to HVR. -- [ ] Socket sounds: Gothic `InvOpen`/`InvClose` for the backpack, socket fallback sounds for slots, silent bulk - spawning. +- [x] Chests: the content spawns into slots (scaled down), items can be taken and put back; dropping an item into the + open chest stores it. (3c; played on Xri with a G1 chest near the start: open → 5 items in slots laid out to + the chest mesh, take one by hand, release over the chest → back into a free slot (drop zone, also with slot + detection off), close → hidden, reopen → same items, nothing spawned twice. The lid is not physical on Xri + until Phase 4: using it (grab = use, like a mob) swings it open/closed, see `VrChestLidToggle`. Hvr: lid + opened by physics → HVR sockets filled as before.) +- [x] NPC loot: equipped and inventory items appear in loot slots, taking one moves it to the player. (3c; played on + Xri: Orry's sword and crossbow with `[E]`, bolts, apple, nugget; taking the nugget removes it from his + inventory and refills the slots, taking the sword removes it from `EquippedItems` and the mesh from + `ZS_SWORD`; closing destroys the slots. Opened via `VRNpcLoot.Open`, not via a kill.) +- [x] Hover feedback on slots (scale and valid/invalid material) is equivalent to HVR. (3a/3b; the invalid material + over a full slot was not played.) +- [x] Socket sounds: Gothic `InvOpen`/`InvClose` for the backpack, socket fallback sounds for slots, silent bulk + spawning. (3b backpack; 3c chests spawn with `SetSilent(true)`, also no weapon draw sounds of + `VRVobContainerSocketInventory` while silent - on HVR too. Sounds were not listened to, only the code path.) ## What HVR does for us today (behaviour spec, write new code from this, not from HVR source) @@ -139,14 +148,35 @@ as HVR's head-relative inventory). `VRBackpack.OnItemPutIntoHolster/OutOfHolster it doesn't move socketed items. Teleporting with a holstered item and a held backpack keeps both in place. - `VR Socket Slot.prefab` is on layer `TransparentFX` (1) now, like the mouth: its trigger meets held items (layers 6 and 7, which don't collide with Default), but neither the player nor hands' raycasts. -- [ ] `VRVobContainerPhysicsChest`: split into `VrChestLid` (Phase 4) + `VrChestSlots` (this phase: resize slots to the +- [x] `VRVobContainerPhysicsChest`: split into `VrChestLid` (Phase 4) + `VrChestSlots` (this phase: resize slots to the chest mesh, as today's `AlignSockets` logic, bulk spawn silently, pagination still TODO as logged today). -- [ ] `VRNpcLoot`: create `VrSocketSlot`s at runtime instead of `HVRSocket`s; `Removed` → `OnItemTakenFromLoot`. -- [ ] `VRVobContainerSocketInventory`: subscribe to container events. + (3c: `HvrPhysicsChest` is only the HVR lid now and calls `VrChestSlots.Open()/Close()`; on other backends it + switches itself off before the HVR door sets up its joint. `VrChestSlots` sits on the `oCMobContainer` root, + lists one inventory per backend (`Inventory` = HVR, `Inventory XRI`) and uses the first whose + `IVrSocketContainer.IsActive`; the others are deactivated. Layout = old `AlignSockets`, content via + `VobService.UnpackItems`, one frame per item, silent until 1 s after the spawn; a chest closed while spawning + hides its slots when the spawn is done. Interim lid on Xri: `VrChestLidToggle` (implements `IVrHinge`, so + lock picking locks/unlocks it and `VRVobContainer` gives it the open/close sounds; kinematic, swings to + 110°). Phase 4 replaces it with `VrHinge`. Callers now take the active hinge (`VrHinges.FindActive`, new + `IVrHinge.IsActive`) and are null-safe (no hinge on Xri doors yet).) +- [x] `VRNpcLoot`: create `VrSocketSlot`s at runtime instead of `HVRSocket`s; `Removed` → `OnItemTakenFromLoot`. + (3c: new `_slotPrefab` = `VR Socket Slot.prefab`, used when `IVrBackend.Kind` isn't Hvr (new property); + `_socketPrefab` stays the HVR slot. `Released` → `OnItemTakenFromLoot` unchanged.) +- [x] `VRVobContainerSocketInventory`: subscribe to container events. (3c: still subscribes to the sockets below it; + new: no weapon (un)draw sound while the `IVrSocketContainer` next to it is silent. `IVrSocketContainer` got + `IsActive` and `IsSilent`.) +- [x] Slots keep their items while deactivated (3c, found while testing): XRI releases a socket's selection when the + socket is disabled (closing a chest), and `VrSocketSlot` tried to re-parent the item during the deactivation. + Now the slot keeps the item and re-selects it in the backend on enable. - [ ] **Assets (UnityMCP):** (3a done: `Resources/VR/Prefabs/Player-Elements/VR Socket Slot.prefab` - slot, XriSocketBridge, sphere trigger r=0.07, hover feedback, GameObjectSelfInjector; `Gothic-VR/Meshes/SocketRing.asset` procedural torus; `Gothic-VR/Materials/SocketRing(-Valid/-Invalid).mat` URP Unlit transparent. 3b: backpack - prefab and rig anchors, see above. Rest: 3c) + prefab and rig anchors, see above. 3c: `oCMobContainer.prefab` got `VrChestSlots` on the root, + `BIP01 CHEST_.*_0/Inventory XRI` (`VrSocketContainer`, `VRVobContainerSocketInventory`, 12 `VR Socket Slot` + instances "Slot (0..11)" with Size 0.18, sphere r 0.1, ring flat and 1.33x like HVR's chest ring, and + `DropZone` = trigger box on layer TransparentFX with `VrContainerDropZone`, resized to the chest like HVR's + collector, 0.3 m high); the lid got `XRSimpleInteractable` (disabled) + `XriInteractableBridge` + + `VrChestLidToggle`. `oCNpc.prefab`: `VRNpcLoot._slotPrefab`.) new `VR Socket Slot.prefab` (replaces `VRBackpack(Large)InventorySlot` + HVR's `LargeInventorySlot` / `SocketOval`), ring mesh (simple torus, our own) + `SocketRing/Valid/Invalid` URP materials, add slots to `oCMobContainer.prefab` and the backpack prefab, shoulder + hip anchors on the XRI rig. @@ -155,6 +185,11 @@ as HVR's head-relative inventory). `VRBackpack.OnItemPutIntoHolster/OutOfHolster ## Test plan +Status after 3c (Xri + simulator, programmatic input via MCP): 1-3 played in 3b (no save → load), 4 partly (no +swimming), 5 and 6 played (G1 chest with 5 items; the "no sound burst" not listened to), 7 played without killing +(loot opened directly), 8 not played. Hvr: boots, chest opens via physics and fills its HVR sockets, NPC loot uses +the HVR slots. Not played on a headset. + 1. New game: backpack on the shoulder; grab it off → slots show the current category; flip pages/categories; put it back on the shoulder → `InvClose` sound. 2. Pick up an apple, put it into the backpack → inventory +1, the vob disappears from the world (save → load: not in diff --git a/Docs/HVR-replacement/phase-4-doors-chests-ladders.md b/Docs/HVR-replacement/phase-4-doors-chests-ladders.md index 1f0fddb4c..d00abf11a 100644 --- a/Docs/HVR-replacement/phase-4-doors-chests-ladders.md +++ b/Docs/HVR-replacement/phase-4-doors-chests-ladders.md @@ -77,6 +77,8 @@ as a code reference.) - [ ] `VrHinge` (+ `IVrHinge` implementation), `VrLadderExit`. - [ ] `VRVobContainerPhysicsChest` → `VrChestSlots` (logic) + `VrHinge` (lid); delete the subclassing on the Xri path. + (3c: `VrChestSlots` exists and has `Open()`/`Close()`; `HvrPhysicsChest` is only the HVR lid. On Xri the lid is + the interim `VrChestLidToggle` (use = swing open/closed, kinematic, `IVrHinge`) - replace it with `VrHinge`.) - [ ] **Prefabs (UnityMCP):** `oCMobDoor.prefab` (VrHinge + grab interactable + bridge), `oCMobContainer.prefab` (lid), `oCMobLadder.prefab` (ClimbInteractable + bridge). - [ ] `VRContextInteractionService.KeepPlayerWithin` uses `IVrRig.IsClimbing`; verify with a dialog at a ladder. From 119a85c9ed107757e6d71c0aec1348aa13afc520 Mon Sep 17 00:00:00 2001 From: JaXt0r Date: Sat, 24 Oct 2026 20:40:58 +0200 Subject: [PATCH 2/3] docs: bugs. --- Docs/HVR-replacement/found-bugs.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/HVR-replacement/found-bugs.md b/Docs/HVR-replacement/found-bugs.md index 38824178e..5553c6205 100644 --- a/Docs/HVR-replacement/found-bugs.md +++ b/Docs/HVR-replacement/found-bugs.md @@ -53,3 +53,4 @@ Move them to GitHub issues when the branch is merged, if they are still open. - Backpack grab point is too small. Hard to grab it. Should be aligned with the size on how HVR handled it. - Rotation of long backack-slot at the bottom is wrong. Should be like before. - Simulator: Very complex to traverse. Why not having it like the one from https://github.com/AdrielHercules/hvr-simulator (aka Controller handling etc.) +- Rotation + Scaling of objects inside Slots is broken From 7410064c575cc45ce9bef070bf509a6b85b7093b Mon Sep 17 00:00:00 2001 From: JaXt0r Date: Sat, 24 Oct 2026 20:59:25 +0200 Subject: [PATCH 3/3] docs: bugs. --- Docs/HVR-replacement/found-bugs.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/HVR-replacement/found-bugs.md b/Docs/HVR-replacement/found-bugs.md index 5553c6205..888e6e717 100644 --- a/Docs/HVR-replacement/found-bugs.md +++ b/Docs/HVR-replacement/found-bugs.md @@ -54,3 +54,4 @@ Move them to GitHub issues when the branch is merged, if they are still open. - Rotation of long backack-slot at the bottom is wrong. Should be like before. - Simulator: Very complex to traverse. Why not having it like the one from https://github.com/AdrielHercules/hvr-simulator (aka Controller handling etc.) - Rotation + Scaling of objects inside Slots is broken +- Lockpicking - finalizing the minigame should open the door directly. Currently: Nothing.