This commit is contained in:
Lucastaa
2026-05-02 20:33:34 +07:00
35 changed files with 1617 additions and 2635 deletions

File diff suppressed because one or more lines are too long

View File

@@ -6,8 +6,11 @@
<component name="ChangeListManager">
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scenes/Main Scene.unity" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scenes/Main Scene.unity" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Network/BasicSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Network/BasicSpawner.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Network/PlayerDataManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Network/PlayerDataManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/LobbyController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/LobbyController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/UI/Lobby.uxml" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/Lobby.uxml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -15,7 +18,7 @@
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="EmbeddingIndexingInfo">
<option name="cachedIndexableFilesCount" value="16" />
<option name="cachedIndexableFilesCount" value="18" />
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
</component>
<component name="Git.Settings">
@@ -152,7 +155,9 @@
<workItem from="1777568077522" duration="8613000" />
<workItem from="1777604072510" duration="12724000" />
<workItem from="1777629255838" duration="2209000" />
<workItem from="1777631506531" duration="2045000" />
<workItem from="1777631506531" duration="2333000" />
<workItem from="1777639175483" duration="9746000" />
<workItem from="1777652919998" duration="1890000" />
</task>
<servers />
</component>

View File

@@ -0,0 +1 @@
No previous session history found for this workspace.

15
Assets/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,15 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/.idea.Assets.iml
/modules.xml
/projectSettingsUpdater.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

4
Assets/.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

8
Assets/.idea/indexLayout.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
Assets/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@@ -185,11 +185,6 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::_PlayerDataManager
_Players:
_items: []
--- !u!137 &166789747 stripped
SkinnedMeshRenderer:
m_CorrespondingSourceObject: {fileID: 1058696422167757239, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_PrefabInstance: {fileID: 8240317044381527393}
m_PrefabAsset: {fileID: 0}
--- !u!1 &200732282
GameObject:
m_ObjectHideFlags: 0
@@ -317,27 +312,6 @@ MonoBehaviour:
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!4 &216247148 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_PrefabInstance: {fileID: 8240317044381527393}
m_PrefabAsset: {fileID: 0}
--- !u!114 &216247156 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5600577104145922999, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_PrefabInstance: {fileID: 8240317044381527393}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5962d8f2c8e40e240a4a4907c7b539fa, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.InputReader
--- !u!4 &354406517 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
m_PrefabInstance: {fileID: 1888030338}
m_PrefabAsset: {fileID: 0}
--- !u!1 &390662298
GameObject:
m_ObjectHideFlags: 0
@@ -369,115 +343,11 @@ Transform:
m_Children: []
m_Father: {fileID: 1439162687}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!20 &442028704 stripped
Camera:
m_CorrespondingSourceObject: {fileID: 452500236988029996, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
m_PrefabInstance: {fileID: 3886963620680427248}
m_PrefabAsset: {fileID: 0}
--- !u!4 &442028708 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 2207112960010484425, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
m_PrefabInstance: {fileID: 3886963620680427248}
m_PrefabAsset: {fileID: 0}
--- !u!1 &1001043680
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1001043681}
m_Layer: 0
m_Name: _MAP (1)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1001043681
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1001043680}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: -50.7, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1087174933}
- {fileID: 1605015229}
m_Father: {fileID: 1997343489}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1087174932
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1087174933}
- component: {fileID: 1087174935}
- component: {fileID: 1087174934}
m_Layer: 0
m_Name: MazeController
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1087174933
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1087174932}
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: 1458421390}
m_Father: {fileID: 1001043681}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1087174934
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1087174932}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f30df611110713742ab984f5bead5d88, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.GameSetup.Maze.MazeRenderer
visualProfile: {fileID: 11400000, guid: 15b745b0bb979b84ea937c679ee0f1ed, type: 2}
--- !u!114 &1087174935
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1087174932}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3607adabe0c29c34591af73b414eb17a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.GameSetup.Maze.MazeManager
selectedAlgorithm: 0
width: 30
depth: 30
debugMode: 1
visualizationInterval: 0.05
mazeRenderer: {fileID: 1087174934}
mazeContainer: {fileID: 1458421390}
--- !u!1 &1142785471
GameObject:
m_ObjectHideFlags: 0
@@ -731,9 +601,9 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1437922948}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 3.5546, y: -66, z: 4.39807}
m_LocalScale: {x: 50, y: 1, z: 50}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: -10, z: 0}
m_LocalScale: {x: 100, y: 1, z: 100}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1313417867}
@@ -804,282 +674,6 @@ MonoBehaviour:
visualizationInterval: 0.05
mazeRenderer: {fileID: 1439162688}
mazeContainer: {fileID: 390662299}
--- !u!1 &1458421389
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1458421390}
m_Layer: 0
m_Name: Container
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1458421390
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1458421389}
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: 1087174933}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &1476495806
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalPosition.y
value: -0.91
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalRotation.w
value: 0.7071068
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalRotation.y
value: 0.70710677
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
propertyPath: m_Name
value: Dead_End_Manhole_Down
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
insertIndex: -1
addedObject: {fileID: 354406517}
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
--- !u!1 &1605015228
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1605015229}
- component: {fileID: 1605015232}
- component: {fileID: 1605015231}
- component: {fileID: 1605015230}
m_Layer: 6
m_Name: Ground
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1605015229
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1605015228}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 3.5546, y: -66, z: 4.39807}
m_LocalScale: {x: 50, y: 1, z: 50}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1001043681}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!64 &1605015230
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1605015228}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 5
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1605015231
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1605015228}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: e2e2684e969402049b87d7f81417c603, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &1605015232
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1605015228}
m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &1631120432 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 5188652905305800431, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_PrefabInstance: {fileID: 8240317044381527393}
m_PrefabAsset: {fileID: 0}
--- !u!4 &1732205146 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 8004958684693924044, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_PrefabInstance: {fileID: 8240317044381527393}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &1888030338
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1917154868}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalPosition.y
value: -11.95
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
propertyPath: m_Name
value: Dead_Manhole_Up
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: bfa8e1f953979d34d97530e4c0a07232, type: 3}
--- !u!4 &1917154868 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: c7b8e72ff8d936143a810e1baa494428, type: 3}
m_PrefabInstance: {fileID: 1476495806}
m_PrefabAsset: {fileID: 0}
--- !u!1 &1997343488
GameObject:
m_ObjectHideFlags: 0
@@ -1110,43 +704,10 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 442028708}
- {fileID: 216247148}
- {fileID: 1313417867}
- {fileID: 1001043681}
- {fileID: 1368410213}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &2101138892
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2101138893}
m_Layer: 0
m_Name: Campoint 1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2101138893
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2101138892}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.9727903, z: -0, w: 0.23168753}
m_LocalPosition: {x: -1.8390989, y: -1.7589655, z: 7.503214}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1732205146}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &3886963620680427248
PrefabInstance:
m_ObjectHideFlags: 0
@@ -1206,11 +767,11 @@ PrefabInstance:
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: fpvTarget
value:
objectReference: {fileID: 1631120432}
objectReference: {fileID: 0}
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: inputReader
value:
objectReference: {fileID: 216247156}
objectReference: {fileID: 0}
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: sensitivity
value: 10
@@ -1218,15 +779,15 @@ PrefabInstance:
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: followTarget
value:
objectReference: {fileID: 216247148}
objectReference: {fileID: 0}
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: 'characterRenderers.Array.data[0]'
value:
objectReference: {fileID: 166789747}
objectReference: {fileID: 0}
- target: {fileID: 3657229949309460766, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: 'characterFading.characterRenderers.Array.data[0]'
value:
objectReference: {fileID: 166789747}
objectReference: {fileID: 0}
- target: {fileID: 8391577239842762580, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
propertyPath: m_RenderPostProcessing
value: 1
@@ -1236,157 +797,9 @@ PrefabInstance:
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: fb7874830b9e56341bf88f2a1123c677, type: 3}
--- !u!1001 &8240317044381527393
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1997343489}
m_Modifications:
- target: {fileID: -5076913349690967641, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: SortKey
value: 225553585
objectReference: {fileID: 0}
- target: {fileID: 830356296960548640, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: <InteractionMask>k__BackingField.m_Bits
value: 512
objectReference: {fileID: 0}
- target: {fileID: 1054594849095937263, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_Name
value: Player
objectReference: {fileID: 0}
- target: {fileID: 1054594849095937263, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_TagString
value: Player
objectReference: {fileID: 0}
- target: {fileID: 1058696422167757239, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: 'm_Materials.Array.data[0]'
value:
objectReference: {fileID: 3297912226980038121, guid: 8290c8e8479e3b744b22042adbe32801, type: 3}
- target: {fileID: 1058696422167757239, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: 'm_Materials.Array.data[1]'
value:
objectReference: {fileID: 2100000, guid: 29d8aeef71b97864a9ad6317a4738f26, type: 2}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_Camera
value:
objectReference: {fileID: 442028704}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.size
value: 21
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_ActionId
value: 7e8b9416-0a2d-4652-98d8-e7368560ede9
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_ActionName
value: 'Player/Change View[/Keyboard/f2]'
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.size
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_Mode
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 216247156}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_CallState
value: 2
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_MethodName
value: OnToggleView
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName
value: OnlyScove.Scripts.InputReader, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 3010251870038942475, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_ActionEvents.Array.data[20].m_PersistentCalls.m_Calls.Array.data[0].m_Arguments.m_ObjectArgumentAssemblyTypeName
value: UnityEngine.Object, UnityEngine
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalPosition.x
value: 36.32
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalPosition.y
value: -5.22
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalPosition.z
value: -5.56
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3154409663696148700, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3866929919288054183, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: redSlashPrefab
value:
objectReference: {fileID: 1113287330716207023, guid: 03163717f6c5cad409e7e7f079f06ea5, type: 3}
- target: {fileID: 3866929919288054183, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: blackSlashPrefab
value:
objectReference: {fileID: 7925862234553078923, guid: a9db8dc0d7288b8418ab54e786fbffa7, type: 3}
- target: {fileID: 5073031060995569267, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: autoDetectOnStart
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5773292363125757170, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: cinematicCameraPoint
value:
objectReference: {fileID: 2101138893}
- target: {fileID: 9098752589608501196, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
propertyPath: m_Controller
value:
objectReference: {fileID: 9100000, guid: 09e31034ca0f14f42b3aa81e50326f87, type: 2}
m_RemovedComponents:
- {fileID: 6587788942094262397, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
- {fileID: 5294322338071205561, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
- {fileID: 8541105841172983867, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
m_RemovedGameObjects: []
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: 8004958684693924044, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
insertIndex: -1
addedObject: {fileID: 2101138893}
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 761bdf2e5c0cff4488527355acb975e5, type: 3}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1997343489}
- {fileID: 1142785474}
- {fileID: 1476495806}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,19 @@ namespace Hallucinate.UI
{
public class BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
{
public static BasicSpawner Instance { get; private set; }
private static BasicSpawner _instance;
public static BasicSpawner Instance
{
get
{
if (_instance == null)
{
_instance = UnityEngine.Object.FindFirstObjectByType<BasicSpawner>();
}
return _instance;
}
}
private NetworkRunner _runner;
public NetworkRunner Runner => _runner;
@@ -29,12 +41,15 @@ namespace Hallucinate.UI
private void Awake()
{
if (Instance != null && Instance != this)
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
_instance = this;
// Ensure this is a root object so DontDestroyOnLoad works correctly
transform.SetParent(null);
DontDestroyOnLoad(gameObject);
}
@@ -57,8 +72,13 @@ namespace Hallucinate.UI
await _runner.Shutdown();
}
Debug.Log("[BasicSpawner] Destroying existing runner component.");
Destroy(_runner);
// Check if it still exists (Unity pseudo-null check)
if (_runner != null)
{
// Only log if it's actually a valid object to destroy
// If it's already marked for destruction, Unity == null will be true soon
Destroy(_runner);
}
_runner = null;
await Task.Yield();
@@ -69,6 +89,8 @@ namespace Hallucinate.UI
}
}
if (this == null) return; // BasicSpawner itself might be destroyed
Debug.Log("[BasicSpawner] Creating new NetworkRunner component.");
_runner = gameObject.AddComponent<NetworkRunner>();
_runner.ProvideInput = true;
@@ -103,7 +125,12 @@ namespace Hallucinate.UI
public async Task<bool> StartHost(string sessionName, string displayName, string password = null)
{
if (_isStarting) return false;
// Wait for any existing startup process (like StartLobby) to finish
while (_isStarting)
{
await Task.Yield();
}
_isStarting = true;
try
@@ -274,6 +301,17 @@ namespace Hallucinate.UI
_spawnedCharacters.Remove(player);
}
// Logic Reassign Leader (Logical)
if (runner.IsServer && PlayerDataManager.Instance != null && PlayerDataManager.Instance.Leader == player)
{
var nextLeader = runner.ActivePlayers.FirstOrDefault();
if (nextLeader != PlayerRef.None)
{
PlayerDataManager.Instance.Leader = nextLeader;
Debug.Log($"[BasicSpawner] Leader left. New logical leader: {nextLeader}");
}
}
if (runner.IsServer && player == runner.LocalPlayer)
{
runner.Shutdown();
@@ -292,6 +330,13 @@ namespace Hallucinate.UI
return;
}
// Nếu đang trong quá trình Host Migration, đừng quay về menu
if (shutdownReason == ShutdownReason.HostMigration)
{
Debug.Log("[BasicSpawner] Shutdown due to Host Migration. Waiting for recovery...");
return;
}
if (UIManager.Instance != null)
{
UIManager.Instance.OnBackToMenu();
@@ -327,7 +372,34 @@ namespace Hallucinate.UI
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
public async void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken)
{
Debug.Log("[BasicSpawner] OnHostMigration triggered!");
// 1. Shutdown existing runner properly
await runner.Shutdown(false);
// 2. Create new runner
await EnsureRunnerExists();
// 3. Restart as new Host/Server using the migration token
var result = await _runner.StartGame(new StartGameArgs()
{
HostMigrationToken = hostMigrationToken,
SceneManager = gameObject.GetComponent<NetworkSceneManagerDefault>() ?? gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (result.Ok)
{
Debug.Log("[BasicSpawner] Host Migration SUCCESSFUL");
}
else
{
Debug.LogError($"[BasicSpawner] Host Migration FAILED: {result.ShutdownReason}");
UIManager.Instance?.OnBackToMenu();
}
}
public void OnSceneLoadDone(NetworkRunner runner)
{
@@ -341,17 +413,10 @@ namespace Hallucinate.UI
_spawnedCharacters.Add(player, networkPlayerObject);
}
}
// Removed incorrect UI transition for Lobby/Menu scenes to allow LobbyController to manage its state.
// The original logic incorrectly called UIManager.OnBackToMenu() when entering the Lobby scene,
// causing the redirect to the Main Menu after creating a room.
// This block ensures that only the Main Scene triggers a specific UI transition (OnGameStarted).
// If other scenes like "Lobby" or "Menu" are loaded, no automatic transition is forced from here,
// letting scene-specific controllers (like LobbyController) manage their UI.
if (currentSceneName == "Main Scene")
{
UIManager.Instance?.OnGameStarted();
}
// Removed the problematic else-if block that would incorrectly call OnBackToMenu for "Lobby" or "Menu" scenes.
}

View File

@@ -16,23 +16,46 @@ public class PlayerDataManager : NetworkBehaviour
[Networked]
public NetworkDictionary<PlayerRef, _PlayerMetaData> Players => default;
[Networked]
public PlayerRef Leader { get; set; }
public event Action<PlayerRef, string> OnChatMessageReceived;
public override void Spawned()
{
Instance = this;
if (Object.HasStateAuthority)
{
Leader = Runner.LocalPlayer;
}
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
if (Instance == this) Instance = null;
}
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
public void RPC_TransferLeader(PlayerRef newLeader)
{
if (Players.ContainsKey(newLeader))
{
Leader = newLeader;
}
}
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
public void RPC_UpdatePlayerMetaData(PlayerRef playerRef, _PlayerMetaData metaData)
{
if (Object == null || !Object.IsValid) return;
Players.Set(playerRef, metaData);
}
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
public void RPC_SetReady(PlayerRef playerRef, bool ready)
{
if (Object == null || !Object.IsValid) return;
if (Players.TryGet(playerRef, out var data))
{
data.IsReady = ready;
@@ -48,6 +71,10 @@ public class PlayerDataManager : NetworkBehaviour
public bool TryGetPlayerMetaData(PlayerRef playerRef, out _PlayerMetaData metaData)
{
metaData = default;
// Kiểm tra xem object đã được Spawned chưa trước khi truy cập networked property
if (Object == null || !Object.IsValid) return false;
return Players.TryGet(playerRef, out metaData);
}
}

View File

@@ -1,4 +1,4 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -12,118 +12,89 @@ namespace Hallucinate.UI
private VisualTreeAsset _roomItemTemplate;
private PlayerDataManager _playerDataManager;
// Containers
private VisualElement _joinContainer, _createContainer, _loungeContainer, _passOverlay;
// Create Room Fields
private TextField _roomIDInput, _roomNameInput, _roomPassInput;
private Toggle _passToggle;
// Join Room Fields
private Label _createErrorLabel;
private Button _confirmCreateBtn;
private ScrollView _roomList;
private TextField _joinPassInput;
private Label _joinPassError;
private SessionInfo _selectedSession;
// Lounge Elements
private Label _loungeRoomName;
private Button _readyBtn, _startBtn;
// Host Slot
private Label _hostNameLabel, _hostStatusLabel;
private VisualElement _hostChatBox;
private Label _hostChatMessage;
// Guest Slot
private Label _guestNameLabel, _guestStatusLabel;
private VisualElement _guestChatBox;
private Label _guestChatMessage;
// Chat Input
private TextField _chatInput;
private VisualElement _hostAvatar, _guestAvatar;
private VisualElement _transferHostOverlay;
private Button _confirmTransferBtn, _closeTransferBtn;
private PlayerRef _pendingTransferPlayer;
private bool _isBusy = false;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
base.Initialize(uxmlRoot, manager);
// Query Containers
_joinContainer = root.Q<VisualElement>("JoinContainer");
_createContainer = root.Q<VisualElement>("CreateContainer");
_loungeContainer = root.Q<VisualElement>("LoungeContainer");
_passOverlay = root.Q<VisualElement>("PasswordOverlay");
// Create Room Fields
_roomIDInput = root.Q<TextField>("RoomIDInput");
_roomNameInput = root.Q<TextField>("RoomNameInput");
_roomPassInput = root.Q<TextField>("RoomPassInput");
_passToggle = root.Q<Toggle>("PassToggle");
// Join Room Fields
_createErrorLabel = root.Q<Label>("CreateErrorLabel");
_roomList = root.Q<ScrollView>("RoomList");
_joinPassInput = root.Q<TextField>("JoinPassInput");
_joinPassError = root.Q<Label>("JoinPassError");
// Lounge Elements
_loungeRoomName = root.Q<Label>("LoungeRoomName");
_readyBtn = root.Q<Button>("ReadyBtn");
_startBtn = root.Q<Button>("StartBtn");
// Host Slot
if (_startBtn != null) _startBtn.style.display = DisplayStyle.None; // Default to hidden
_hostNameLabel = root.Q<Label>("HostName");
_hostStatusLabel = root.Q<Label>("HostReadyStatus");
_hostChatBox = root.Q<VisualElement>("HostChatBox");
_hostChatMessage = root.Q<Label>("HostChatMessage");
// Guest Slot
_guestNameLabel = root.Q<Label>("GuestName");
_guestStatusLabel = root.Q<Label>("GuestReadyStatus");
_guestChatBox = root.Q<VisualElement>("GuestChatBox");
_guestChatMessage = root.Q<Label>("GuestChatMessage");
// Chat Input
_chatInput = root.Q<TextField>("ChatInput");
// Event Bindings
_hostAvatar = root.Q<VisualElement>("HostAvatar");
_guestAvatar = root.Q<VisualElement>("GuestAvatar");
_transferHostOverlay = root.Q<VisualElement>("TransferHostOverlay");
_confirmTransferBtn = root.Q<Button>("ConfirmTransferBtn");
_closeTransferBtn = root.Q<Button>("CloseTransferBtn");
root.Q<Button>("GoToCreateBtn").clicked += ShowCreate;
root.Q<Button>("CancelCreateBtn").clicked += ShowJoin;
root.Q<Button>("BackToMenuBtn").clicked += async () => await uiManager.Pop();
root.Q<Button>("ConfirmCreateBtn").clicked += OnCreateRoomClicked;
root.Q<Button>("BackToMenuBtn").clicked += async () => { if (_isBusy) return; await uiManager.Pop(); };
_confirmCreateBtn = root.Q<Button>("ConfirmCreateBtn");
if (_confirmCreateBtn != null) _confirmCreateBtn.clicked += OnCreateRoomClicked;
root.Q<Button>("ConfirmJoinBtn").clicked += OnConfirmPasswordClicked;
root.Q<Button>("ClosePassBtn").clicked += () => { if(_passOverlay != null) _passOverlay.style.display = DisplayStyle.None; };
root.Q<Button>("LeaveLoungeBtn").clicked += OnLeaveLoungeClicked;
if (_readyBtn != null) _readyBtn.clicked += OnReadyClicked;
if (_startBtn != null) _startBtn.clicked += OnStartClicked;
if (_passToggle != null) _passToggle.RegisterValueChangedCallback(evt => { if (_roomPassInput != null) _roomPassInput.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None; });
if (_chatInput != null) _chatInput.RegisterCallback<KeyDownEvent>(OnChatKeyDown, TrickleDown.TrickleDown);
if (_hostAvatar != null) _hostAvatar.RegisterCallback<ClickEvent>(evt => OnAvatarClicked(true));
if (_guestAvatar != null) _guestAvatar.RegisterCallback<ClickEvent>(evt => OnAvatarClicked(false));
if (_confirmTransferBtn != null) _confirmTransferBtn.clicked += OnConfirmTransferHost;
if (_closeTransferBtn != null) _closeTransferBtn.clicked += () => { if(_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.None; };
if (_passToggle != null)
{
_passToggle.RegisterValueChangedCallback(evt =>
{
if (_roomPassInput != null)
_roomPassInput.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
});
}
if (_chatInput != null)
{
_chatInput.RegisterCallback<KeyDownEvent>(OnChatKeyDown, TrickleDown.TrickleDown);
}
if (LocalizationManager.Instance != null)
{
LocalizationManager.Instance.OnLanguageChanged += ApplyLocalization;
ApplyLocalization();
}
// Đăng ký sự kiện từ Spawner
if (BasicSpawner.Instance != null)
{
RegisterSpawnerEvents();
}
else
{
Invoke(nameof(RegisterSpawnerEvents), 0.1f);
}
if (LocalizationManager.Instance != null) { LocalizationManager.Instance.OnLanguageChanged += ApplyLocalization; ApplyLocalization(); }
if (BasicSpawner.Instance != null) RegisterSpawnerEvents();
else Invoke(nameof(RegisterSpawnerEvents), 0.1f);
}
private void RegisterSpawnerEvents()
@@ -131,7 +102,6 @@ namespace Hallucinate.UI
if (BasicSpawner.Instance == null) return;
BasicSpawner.Instance.OnSessionListUpdatedEvent += UpdateRoomList;
BasicSpawner.Instance.OnJoinFailedEvent += () => { if(_joinPassError != null) _joinPassError.style.display = DisplayStyle.Flex; };
BasicSpawner.Instance.OnJoinStartedEvent += () => { };
}
private void OnChatKeyDown(KeyDownEvent evt)
@@ -140,38 +110,23 @@ namespace Hallucinate.UI
{
evt.StopImmediatePropagation();
evt.PreventDefault();
string msg = _chatInput.value.Trim();
if (!string.IsNullOrEmpty(msg) && PlayerDataManager.Instance != null)
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
if (runner != null)
{
PlayerDataManager.Instance.RPC_SendChatMessage(runner.LocalPlayer, msg);
_chatInput.value = "";
// Re-focus after clearing
_chatInput.Focus();
}
var runner = BasicSpawner.Instance.Runner;
if (runner != null) { PlayerDataManager.Instance.RPC_SendChatMessage(runner.LocalPlayer, msg); _chatInput.value = ""; _chatInput.Focus(); }
}
}
}
private void OnChatMessageReceived(PlayerRef sender, string message)
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
var runner = BasicSpawner.Instance.Runner;
if (runner == null) return;
// Kiểm tra sender là Host hay Guest
bool isHost = sender.PlayerId == 1; // Trong Host Mode, người tạo phòng luôn có ID 1
if (isHost)
{
ShowChatBubble(_hostChatBox, _hostChatMessage, message);
}
else
{
ShowChatBubble(_guestChatBox, _guestChatMessage, message);
}
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
bool isHost = sortedPlayers.Count > 0 && sender == sortedPlayers[0];
if (isHost) ShowChatBubble(_hostChatBox, _hostChatMessage, message);
else ShowChatBubble(_guestChatBox, _guestChatMessage, message);
}
private async void ShowChatBubble(VisualElement box, Label label, string msg)
@@ -180,106 +135,18 @@ namespace Hallucinate.UI
label.text = msg;
box.style.display = DisplayStyle.Flex;
await Task.Delay(4000);
if (label.text == msg) // Chỉ ẩn nếu chưa có tin nhắn mới đè lên
box.style.display = DisplayStyle.None;
}
private void OnDestroy()
{
if (LocalizationManager.Instance != null)
{
LocalizationManager.Instance.OnLanguageChanged -= ApplyLocalization;
}
}
private void ApplyLocalization()
{
if (LocalizationManager.Instance == null) return;
// JOIN VIEW
var joinHeading = root.Q<Label>(null, "text-heading"); // Header in JoinContainer
if (joinHeading != null && _joinContainer.Contains(joinHeading)) joinHeading.text = GetT("LOBBY_FIND_SESSIONS");
var searchInput = root.Q<TextField>("SearchInput");
if (searchInput != null) searchInput.textEdition.placeholder = GetT("LOBBY_SEARCH_PLACEHOLDER");
var backBtn = root.Q<Button>("BackToMenuBtn");
if (backBtn != null) backBtn.text = GetT("LOBBY_BACK");
var goToCreateBtn = root.Q<Button>("GoToCreateBtn");
if (goToCreateBtn != null) goToCreateBtn.text = GetT("LOBBY_CREATE_NEW");
// CREATE VIEW
var createHeading = root.Q<Label>(null, "text-heading"); // Header in CreateContainer
// Note: Querying by class might be ambiguous if multiple exist, better to find within container
var createHeader = _createContainer?.Q<Label>(null, "text-heading");
if (createHeader != null) createHeader.text = GetT("LOBBY_CREATE_HEADER");
var roomIdLabel = _createContainer?.Q<Label>(null, "text-label"); // First label is usually ID
// Since they don't have unique names, we'll try to find them by order or text match
_createContainer?.Query<Label>().ForEach(l => {
if (l.text.Contains("ROOM ID")) l.text = GetT("LOBBY_ROOM_ID_LABEL");
if (l.text.Contains("ROOM NAME")) l.text = GetT("LOBBY_ROOM_NAME_LABEL");
});
if (_roomIDInput != null) _roomIDInput.textEdition.placeholder = GetT("LOBBY_ROOM_ID_PLACEHOLDER");
if (_roomNameInput != null) _roomNameInput.textEdition.placeholder = GetT("LOBBY_ROOM_NAME_PLACEHOLDER");
if (_passToggle != null) _passToggle.label = GetT("LOBBY_REQUIRE_PASS");
if (_roomPassInput != null) _roomPassInput.textEdition.placeholder = GetT("LOBBY_PASS_PLACEHOLDER");
var cancelCreateBtn = root.Q<Button>("CancelCreateBtn");
if (cancelCreateBtn != null) cancelCreateBtn.text = GetT("LOBBY_CANCEL");
var confirmCreateBtn = root.Q<Button>("ConfirmCreateBtn");
if (confirmCreateBtn != null) confirmCreateBtn.text = GetT("LOBBY_CREATE_BTN");
// LOUNGE VIEW
if (_loungeRoomName != null && _loungeRoomName.text == "SESSION NAME")
_loungeRoomName.text = GetT("LOBBY_SESSION_NAME_DEFAULT");
var loungeIdLabel = root.Q<Label>("LoungeID");
if (loungeIdLabel != null)
{
string currentId = loungeIdLabel.text.Replace("ID: ", "");
loungeIdLabel.text = GetT("LOBBY_ID_PREFIX") + currentId;
}
var vsLabel = _loungeContainer?.Q<Label>(null); // VS label doesn't have name
_loungeContainer?.Query<Label>().ForEach(l => {
if (l.text == "VS") l.text = GetT("LOBBY_VS");
});
if (_chatInput != null) _chatInput.textEdition.placeholder = GetT("LOBBY_CHAT_PLACEHOLDER");
var leaveLoungeBtn = root.Q<Button>("LeaveLoungeBtn");
if (leaveLoungeBtn != null) leaveLoungeBtn.text = GetT("LOBBY_LEAVE_BTN");
// PASSWORD OVERLAY
var passOverlayTitle = _passOverlay?.Q<Label>(null, "text-subheading");
if (passOverlayTitle != null) passOverlayTitle.text = GetT("LOBBY_PROTECTED_TITLE");
var passOverlayDesc = _passOverlay?.Q<Label>(null, "text-label");
if (passOverlayDesc != null && passOverlayDesc.text.Contains("requires a password"))
passOverlayDesc.text = GetT("LOBBY_PROTECTED_DESC");
if (_joinPassInput != null) _joinPassInput.textEdition.placeholder = GetT("LOBBY_JOIN_PASS_PLACEHOLDER");
if (_joinPassError != null) _joinPassError.text = GetT("LOBBY_JOIN_PASS_ERROR");
var closePassBtn = root.Q<Button>("ClosePassBtn");
if (closePassBtn != null) closePassBtn.text = GetT("LOBBY_CANCEL");
var confirmJoinBtn = root.Q<Button>("ConfirmJoinBtn");
if (confirmJoinBtn != null) confirmJoinBtn.text = GetT("LOBBY_JOIN_BTN");
if (label.text == msg) box.style.display = DisplayStyle.None;
}
private void ApplyLocalization() { if (LocalizationManager.Instance == null) return; }
private string GetT(string key) => LocalizationManager.Instance != null ? LocalizationManager.Instance.GetLocalizedString(key) : key;
public void SetRoomTemplate(VisualTreeAsset template) => _roomItemTemplate = template;
public override async Task PlayTransitionIn()
{
await base.PlayTransitionIn();
ShowJoin();
public override async Task PlayTransitionIn()
{
_isBusy = false;
await base.PlayTransitionIn();
ShowJoin();
}
public void ShowJoin()
@@ -287,19 +154,17 @@ namespace Hallucinate.UI
if (_joinContainer != null) _joinContainer.style.display = DisplayStyle.Flex;
if (_createContainer != null) _createContainer.style.display = DisplayStyle.None;
if (_loungeContainer != null) _loungeContainer.style.display = DisplayStyle.None;
// Chỉ bắt đầu Lobby nếu chưa có session nào đang chạy
var runner = BasicSpawner.Instance?.Runner;
if (runner == null || !runner.IsRunning)
{
_ = BasicSpawner.Instance?.StartLobby();
}
var spawner = BasicSpawner.Instance;
if (spawner != null && (spawner.Runner == null || !spawner.Runner.IsRunning)) _ = spawner.StartLobby();
}
public void ShowCreate()
{
if (_joinContainer != null) _joinContainer.style.display = DisplayStyle.None;
if (_createContainer != null) _createContainer.style.display = DisplayStyle.Flex;
if (_createErrorLabel != null) _createErrorLabel.style.display = DisplayStyle.None;
if (_confirmCreateBtn != null) _confirmCreateBtn.SetEnabled(true);
if (_roomIDInput != null) _roomIDInput.value = "ROOM_" + Random.Range(1000, 9999).ToString();
}
private void ShowLounge(string roomName)
@@ -308,43 +173,57 @@ namespace Hallucinate.UI
if (_createContainer != null) _createContainer.style.display = DisplayStyle.None;
if (_loungeContainer != null) _loungeContainer.style.display = DisplayStyle.Flex;
if (_loungeRoomName != null) _loungeRoomName.text = roomName.ToUpper();
_playerDataManager = Object.FindFirstObjectByType<PlayerDataManager>();
if (_playerDataManager != null)
var spawner = BasicSpawner.Instance;
if (spawner != null && spawner.Runner != null && spawner.Runner.SessionInfo != null)
{
_playerDataManager.OnChatMessageReceived += OnChatMessageReceived;
var loungeIdLabel = root.Q<Label>("LoungeID");
if (loungeIdLabel != null) loungeIdLabel.text = GetT("LOBBY_ID_PREFIX") + spawner.Runner.SessionInfo.Name;
}
_playerDataManager = PlayerDataManager.Instance;
if (_playerDataManager != null) _playerDataManager.OnChatMessageReceived += OnChatMessageReceived;
}
private async void OnCreateRoomClicked()
{
Debug.Log("[LobbyController] Create Room Clicked");
if (_isBusy) return;
_isBusy = true;
if (_confirmCreateBtn != null) _confirmCreateBtn.SetEnabled(false);
if (_createErrorLabel != null) _createErrorLabel.style.display = DisplayStyle.None;
var spawner = BasicSpawner.Instance;
if (spawner == null)
{
Debug.LogError("[LobbyController] Spawner Instance is NULL!");
return;
{
ShowCreateError("System Error: Spawner missing. Please re-enter the Lobby.");
_isBusy = false;
return;
}
string id = _roomIDInput != null && !string.IsNullOrEmpty(_roomIDInput.value)
? _roomIDInput.value.Trim()
: Random.Range(1000, 9999).ToString();
if (_roomIDInput != null) _roomIDInput.value = id;
string name = _roomNameInput != null && !string.IsNullOrEmpty(_roomNameInput.value)
? _roomNameInput.value
: $"Room {id}";
string pass = (_passToggle != null && _passToggle.value && _roomPassInput != null)
? _roomPassInput.value
: null;
bool success = await spawner.StartHost(id, name, pass);
if (success)
string id = (_roomIDInput != null && !string.IsNullOrEmpty(_roomIDInput.value)) ? _roomIDInput.value.Trim() : "ROOM_" + Random.Range(1000, 9999).ToString();
string name = (_roomNameInput != null && !string.IsNullOrEmpty(_roomNameInput.value)) ? _roomNameInput.value.Trim() : id;
string pass = (_passToggle != null && _passToggle.value && _roomPassInput != null) ? _roomPassInput.value : null;
try
{
ShowLounge(name);
bool success = await spawner.StartHost(id, name, pass);
if (success) ShowLounge(name);
else ShowCreateError("Failed to create room. ID might be taken.");
}
catch (System.Exception ex)
{
ShowCreateError("Network Error: " + ex.Message);
}
finally
{
_isBusy = false;
if (_confirmCreateBtn != null) _confirmCreateBtn.SetEnabled(true);
}
}
private void ShowCreateError(string message)
{
if (_createErrorLabel != null) { _createErrorLabel.text = message; _createErrorLabel.style.display = DisplayStyle.Flex; }
if (_confirmCreateBtn != null) _confirmCreateBtn.SetEnabled(true);
}
private void UpdateRoomList(List<SessionInfo> sessions)
@@ -355,37 +234,25 @@ namespace Hallucinate.UI
{
if (_roomItemTemplate == null) continue;
var item = _roomItemTemplate.Instantiate();
// Hiển thị tên phòng thân thiện nếu có
string displayName = session.Name;
if (session.Properties.TryGetValue("rn", out var rnProp))
{
displayName = rnProp;
}
if (session.Properties.TryGetValue("rn", out var rnProp)) displayName = rnProp;
item.Q<Label>("RoomName").text = displayName;
item.Q<Label>("PlayerCount").text = $"{session.PlayerCount}/{session.MaxPlayers}";
var statusBadge = item.Q<Label>("StatusBadge");
if (statusBadge != null) statusBadge.text = GetT("ROOM_STATUS_WAITING");
bool needsPass = session.Properties.ContainsKey("pw");
var lockIcon = item.Q<Label>("LockIcon");
if (lockIcon != null) lockIcon.style.display = needsPass ? DisplayStyle.Flex : DisplayStyle.None;
var joinBtn = item.Q<Button>("JoinBtn");
if (joinBtn != null)
{
joinBtn.text = GetT("ROOM_JOIN_BTN");
joinBtn.clicked += () => OnRoomItemClicked(session);
}
if (joinBtn != null) { joinBtn.text = GetT("ROOM_JOIN_BTN"); joinBtn.clicked += () => OnRoomItemClicked(session); }
_roomList.Add(item);
}
}
private async void OnRoomItemClicked(SessionInfo session)
{
if (_isBusy) return;
bool needsPass = session.Properties.ContainsKey("pw");
if (needsPass)
{
@@ -394,180 +261,228 @@ namespace Hallucinate.UI
if (_joinPassError != null) _joinPassError.style.display = DisplayStyle.None;
if (_joinPassInput != null) _joinPassInput.value = "";
}
else
{
await JoinRoom(session.Name, null);
}
else await JoinRoom(session.Name, null);
}
private async void OnConfirmPasswordClicked()
{
if (_selectedSession == null) return;
if (_isBusy || _selectedSession == null) return;
_isBusy = true;
string pass = _joinPassInput != null ? _joinPassInput.value : "";
if (_passOverlay != null) _passOverlay.style.display = DisplayStyle.None;
await JoinRoom(_selectedSession.Name, pass);
_isBusy = false;
}
private async Task JoinRoom(string sessionName, string password)
private async Task JoinRoom(string sessionName, string password)
{
if (BasicSpawner.Instance != null)
{
if (await BasicSpawner.Instance.StartClient(sessionName, password)) ShowLounge(sessionName);
}
}
private void OnReadyClicked()
{
if (_isBusy) return;
var runner = BasicSpawner.Instance.Runner;
if (runner != null && _playerDataManager != null && _playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData))
_playerDataManager.RPC_SetReady(runner.LocalPlayer, !myData.IsReady);
}
private void OnStartClicked()
{
if (_isBusy) return;
BasicSpawner.Instance?.StartGame();
}
private void OnAvatarClicked(bool isHostSlot)
{
if (BasicSpawner.Instance != null)
if (_playerDataManager == null || _playerDataManager.Leader != BasicSpawner.Instance.Runner.LocalPlayer) return;
var runner = BasicSpawner.Instance.Runner;
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
PlayerRef clickedPlayer = PlayerRef.None;
if (isHostSlot && sortedPlayers.Count > 0) clickedPlayer = sortedPlayers[0];
else if (!isHostSlot && sortedPlayers.Count > 1) clickedPlayer = sortedPlayers[1];
if (clickedPlayer != PlayerRef.None && clickedPlayer != runner.LocalPlayer)
{
bool success = await BasicSpawner.Instance.StartClient(sessionName, password);
if (success) ShowLounge(sessionName);
_pendingTransferPlayer = clickedPlayer;
if (_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.Flex;
}
}
private void OnReadyClicked()
private void OnConfirmTransferHost()
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
if (runner != null && _playerDataManager != null)
if (_pendingTransferPlayer != PlayerRef.None && _playerDataManager != null)
{
if (_playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData))
{
_playerDataManager.RPC_SetReady(runner.LocalPlayer, !myData.IsReady);
}
_playerDataManager.RPC_TransferLeader(_pendingTransferPlayer);
if (_transferHostOverlay != null) _transferHostOverlay.style.display = DisplayStyle.None;
}
}
private async void OnLeaveLoungeClicked()
{
if (_isBusy) return;
_isBusy = true;
var runner = BasicSpawner.Instance.Runner;
if (runner != null) await runner.Shutdown(false);
if (_playerDataManager != null) _playerDataManager.OnChatMessageReceived -= OnChatMessageReceived;
ShowJoin();
_isBusy = false;
}
private void OnStartClicked()
{
BasicSpawner.Instance?.StartGame();
}
private async void OnLeaveLoungeClicked()
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
if (runner != null)
{
await runner.Shutdown();
}
if (_playerDataManager != null)
{
_playerDataManager.OnChatMessageReceived -= OnChatMessageReceived;
}
ShowJoin();
}
public override void Update()
{
if (_loungeContainer != null && _loungeContainer.style.display == DisplayStyle.Flex)
{
UpdateLoungeUI();
}
}
public override void Update() { if (_loungeContainer != null && _loungeContainer.style.display == DisplayStyle.Flex) UpdateLoungeUI(); }
private void UpdateLoungeUI()
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
var spawner = BasicSpawner.Instance;
if (spawner == null) return;
var runner = spawner.Runner;
if (runner == null) return;
if (_playerDataManager == null)
// 1. PlayerDataManager Sync
if (_playerDataManager == null || _playerDataManager.Object == null || !_playerDataManager.Object.IsValid)
{
_playerDataManager = Object.FindFirstObjectByType<PlayerDataManager>();
if (_playerDataManager != null)
_playerDataManager = PlayerDataManager.Instance;
if (_playerDataManager != null)
{
_playerDataManager.OnChatMessageReceived += OnChatMessageReceived;
}
else return; // Still waiting for synchronization
}
if (_playerDataManager == null || _playerDataManager.Object == null || !_playerDataManager.Object.IsValid) return;
PlayerRef hostRef = PlayerRef.None;
PlayerRef guestRef = PlayerRef.None;
// Trong Host Mode, chủ phòng luôn là người có PlayerId = 1
// 2. Identify Players
var sortedPlayers = runner.ActivePlayers.OrderBy(p => p.PlayerId).ToList();
if (sortedPlayers.Count > 0) hostRef = sortedPlayers[0];
if (sortedPlayers.Count > 1) guestRef = sortedPlayers[1];
PlayerRef hostRef = sortedPlayers.Count > 0 ? sortedPlayers[0] : PlayerRef.None;
PlayerRef guestRef = sortedPlayers.Count > 1 ? sortedPlayers[1] : PlayerRef.None;
PlayerRef leaderRef = _playerDataManager.Leader;
// Update Room Name for Guest
if (runner.SessionInfo != null && runner.SessionInfo.Properties.TryGetValue("rn", out var rnProp))
// 3. Strict Visibility Check (Leader Only)
bool isLeader = runner.LocalPlayer == leaderRef;
if (_startBtn != null)
{
_loungeRoomName.text = rnProp.ToString().ToUpper();
_startBtn.style.display = isLeader ? DisplayStyle.Flex : DisplayStyle.None;
}
// Update Host UI
if (runner.SessionInfo != null && runner.SessionInfo.Properties.TryGetValue("rn", out var rnProp)) _loungeRoomName.text = rnProp.ToString().ToUpper();
// Host Display
if (hostRef != PlayerRef.None && _playerDataManager.TryGetPlayerMetaData(hostRef, out var hostData))
{
_hostNameLabel.text = hostData.Name.ToString().ToUpper();
_hostStatusLabel.text = hostData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
string readyStatus = hostData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
string roleLabel = (hostRef == leaderRef) ? GetT("LOBBY_HOST_LABEL") : GetT("LOBBY_PLAYER_LABEL");
_hostStatusLabel.text = $"{roleLabel} - {readyStatus}";
_hostStatusLabel.style.color = hostData.IsReady ? Color.green : Color.red;
// Highlight leader avatar
if (_hostAvatar != null)
{
float width = (hostRef == leaderRef) ? 2f : 0f;
_hostAvatar.style.borderTopWidth = width;
_hostAvatar.style.borderBottomWidth = width;
_hostAvatar.style.borderLeftWidth = width;
_hostAvatar.style.borderRightWidth = width;
}
}
else if (hostRef != PlayerRef.None)
{
_hostNameLabel.text = GetT("LOBBY_SYNCING");
_hostStatusLabel.text = "-";
}
else { _hostNameLabel.text = GetT("LOBBY_SYNCING"); _hostStatusLabel.text = "-"; }
// Update Guest UI
// Guest Display
if (guestRef != PlayerRef.None && _playerDataManager.TryGetPlayerMetaData(guestRef, out var guestData))
{
_guestNameLabel.text = guestData.Name.ToString().ToUpper();
_guestStatusLabel.text = guestData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
string readyStatus = guestData.IsReady ? GetT("LOBBY_READY") : GetT("LOBBY_NOT_READY");
string roleLabel = (guestRef == leaderRef) ? GetT("LOBBY_HOST_LABEL") : GetT("LOBBY_PLAYER_LABEL");
_guestStatusLabel.text = $"{roleLabel} - {readyStatus}";
_guestStatusLabel.style.color = guestData.IsReady ? Color.green : Color.red;
// Highlight leader avatar
if (_guestAvatar != null)
{
float width = (guestRef == leaderRef) ? 2f : 0f;
_guestAvatar.style.borderTopWidth = width;
_guestAvatar.style.borderBottomWidth = width;
_guestAvatar.style.borderLeftWidth = width;
_guestAvatar.style.borderRightWidth = width;
_guestAvatar.style.borderTopColor = Color.white;
_guestAvatar.style.borderBottomColor = Color.white;
_guestAvatar.style.borderLeftColor = Color.white;
_guestAvatar.style.borderRightColor = Color.white;
}
}
else if (runner.ActivePlayers.Count() >= 2)
{
_guestNameLabel.text = GetT("LOBBY_SYNCING");
_guestStatusLabel.text = "-";
}
else
{
_guestNameLabel.text = GetT("LOBBY_WAITING_LABEL");
_guestStatusLabel.text = "-";
_guestStatusLabel.style.color = Color.gray;
else if (runner.ActivePlayers.Count() >= 2) { _guestNameLabel.text = GetT("LOBBY_SYNCING"); _guestStatusLabel.text = "-"; }
else
{
_guestNameLabel.text = GetT("LOBBY_WAITING_LABEL");
_guestStatusLabel.text = "-";
_guestStatusLabel.style.color = Color.gray;
if (_guestAvatar != null)
{
_guestAvatar.style.borderTopWidth = 0;
_guestAvatar.style.borderBottomWidth = 0;
_guestAvatar.style.borderLeftWidth = 0;
_guestAvatar.style.borderRightWidth = 0;
}
}
// Start Button visibility logic
bool allReady = true;
int playerCount = 0;
foreach (var p in runner.ActivePlayers)
// 4. Start Button Logic (Leader Only)
if (_startBtn != null && isLeader)
{
playerCount++;
if (_playerDataManager.TryGetPlayerMetaData(p, out var data))
bool allReady = true;
int playerCount = 0;
foreach (var p in runner.ActivePlayers)
{
playerCount++;
if (_playerDataManager.TryGetPlayerMetaData(p, out var data))
{
if (!data.IsReady) allReady = false;
}
else allReady = false;
}
bool canStart = allReady && playerCount >= 2;
_startBtn.SetEnabled(canStart);
_startBtn.text = GetT("LOBBY_START_BTN");
if (canStart)
{
if (!data.IsReady) allReady = false;
_startBtn.style.backgroundColor = new StyleColor(Color.green);
_startBtn.style.color = new StyleColor(Color.black);
}
else
{
allReady = false;
_startBtn.style.backgroundColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.8f));
_startBtn.style.color = new StyleColor(new Color(1f, 1f, 1f, 0.5f));
}
}
bool isHost = runner.LocalPlayer == hostRef;
if (_startBtn != null)
{
_startBtn.text = GetT("LOBBY_START_BTN");
_startBtn.style.display = isHost ? DisplayStyle.Flex : DisplayStyle.None;
_startBtn.SetEnabled(allReady && playerCount >= 2);
}
// Ready Button Logic (Everyone)
if (_readyBtn != null)
{
if (_playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData))
{
// Style for Ready Button
if (myData.IsReady)
{
_readyBtn.text = GetT("LOBBY_UNREADY_BTN");
_readyBtn.style.backgroundColor = new StyleColor(Color.green);
_readyBtn.style.color = new StyleColor(Color.black);
if (myData.IsReady)
{
_readyBtn.text = GetT("LOBBY_UNREADY_BTN");
_readyBtn.style.backgroundColor = new StyleColor(Color.green);
_readyBtn.style.color = new StyleColor(Color.black);
}
else
{
_readyBtn.text = GetT("LOBBY_READY_BTN");
_readyBtn.style.backgroundColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.8f));
_readyBtn.style.color = new StyleColor(Color.white);
else
{
_readyBtn.text = GetT("LOBBY_READY_BTN");
_readyBtn.style.backgroundColor = new StyleColor(new Color(0.2f, 0.2f, 0.2f, 0.8f));
_readyBtn.style.color = new StyleColor(Color.white);
}
}
}
}
private async void Invoke(string methodName, float delay)
{
await Task.Delay((int)(delay * 1000));
if (methodName == nameof(RegisterSpawnerEvents)) RegisterSpawnerEvents();
}
private async void Invoke(string methodName, float delay) { await Task.Delay((int)(delay * 1000)); if (methodName == nameof(RegisterSpawnerEvents)) RegisterSpawnerEvents(); }
}
}

View File

@@ -22,6 +22,8 @@ namespace Hallucinate.UI
private Tween _rotationTween;
private Texture2D _currentIcon;
private bool _isBusy = false;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
base.Initialize(uxmlRoot, manager);
@@ -42,11 +44,11 @@ namespace Hallucinate.UI
_logo.RegisterCallback<ClickEvent>(OnLogoClicked);
var settingsBtn = root.Q<Button>("SettingsBtn");
if (settingsBtn != null) settingsBtn.clicked += () => uiManager.ToggleSettings();
if (settingsBtn != null) settingsBtn.clicked += () => { if (_isBusy) return; uiManager.ToggleSettings(); };
root.Q<Button>("JoinBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("CreateBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("ProfileBtn").clicked += async () => await uiManager.Push<ProfileController>();
root.Q<Button>("JoinBtn").clicked += async () => { if (_isBusy) return; _isBusy = true; await uiManager.Push<LobbyController>(); };
root.Q<Button>("CreateBtn").clicked += async () => { if (_isBusy) return; _isBusy = true; await uiManager.Push<LobbyController>(); };
root.Q<Button>("ProfileBtn").clicked += async () => { if (_isBusy) return; _isBusy = true; await uiManager.Push<ProfileController>(); };
root.Q<Button>("ExitBtn").clicked += () => Application.Quit();
// Đăng ký Localization
@@ -142,6 +144,7 @@ namespace Hallucinate.UI
public override async Task PlayTransitionIn()
{
_isBusy = false;
_lastInteractionTime = Time.time;
_currentState = MenuState.Idle;
ResetLogoPosition();
@@ -167,9 +170,14 @@ namespace Hallucinate.UI
private async void OnLogoClicked(ClickEvent evt)
{
if (_isBusy) return;
_lastInteractionTime = Time.time;
if (_currentState == MenuState.Idle) TransitionToRibbon();
else await uiManager.Push<LobbyController>();
else
{
_isBusy = true;
await uiManager.Push<LobbyController>();
}
}
private void TransitionToRibbon()

View File

@@ -0,0 +1,76 @@
using UnityEngine.UIElements;
using System.Threading.Tasks;
using OnlyScove.Scripts;
using UnityEngine;
namespace Hallucinate.UI
{
public class PauseMenuController : BaseUIController
{
private Button _resumeBtn;
private Button _quitBtn;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
base.Initialize(uxmlRoot, manager);
_resumeBtn = root.Q<Button>("ResumeBtn");
_quitBtn = root.Q<Button>("QuitBtn");
if (_resumeBtn != null) _resumeBtn.clicked += OnResumeClicked;
if (_quitBtn != null) _quitBtn.clicked += OnQuitClicked;
ApplyLocalization();
if (LocalizationManager.Instance != null)
LocalizationManager.Instance.OnLanguageChanged += ApplyLocalization;
}
private void OnDestroy()
{
if (LocalizationManager.Instance != null)
LocalizationManager.Instance.OnLanguageChanged -= ApplyLocalization;
}
private void ApplyLocalization()
{
if (_resumeBtn != null) _resumeBtn.text = GetLoc("PAUSE_RESUME");
if (_quitBtn != null) _quitBtn.text = GetLoc("PAUSE_QUIT");
var title = root.Q<Label>("PauseTitle");
if (title != null) title.text = GetLoc("PAUSE_TITLE");
}
private void OnResumeClicked()
{
uiManager.TogglePauseMenu();
}
private void OnQuitClicked()
{
Debug.Log("[PauseMenu] Quit clicked - shutting down runner.");
if (BasicSpawner.Instance != null && BasicSpawner.Instance.Runner != null)
{
BasicSpawner.Instance.Runner.Shutdown();
}
else
{
uiManager.OnBackToMenu();
}
}
public override async Task PlayTransitionIn()
{
Show();
root.style.opacity = 0;
PrimeTween.Tween.Custom(0f, 1f, duration: 0.2f, onValueChange: val => root.style.opacity = val);
await Task.Delay(200);
}
public override async Task PlayTransitionOut()
{
PrimeTween.Tween.Custom(1f, 0f, duration: 0.2f, onValueChange: val => root.style.opacity = val);
await Task.Delay(200);
Hide();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a8be766526476e44ea7c5e19567f2568

View File

@@ -39,6 +39,9 @@ namespace Hallucinate.UI
private Action<float> _hoveredOnChanged;
private float _sliderMin, _sliderMax;
// Audio Slider Tracking for Sync
private readonly Dictionary<string, (Slider slider, TextField input)> _audioSliders = new Dictionary<string, (Slider slider, TextField input)>();
// Osu-style Volume Overlay
private VisualElement _volumeContainer;
private VisualElement _masterRing;
@@ -303,6 +306,7 @@ namespace Hallucinate.UI
_sectionHeaders["SOUND"] = header;
_content.Add(header);
_audioSliders.Clear();
_content.Add(CreateSubSection("AUDIO_VOLUMES"));
_content.Add(CreateAudioSlider(GetT("MASTER"), "MasterVolume"));
_content.Add(CreateAudioSlider(GetT("MUSIC"), "MusicVolume"));
@@ -456,20 +460,31 @@ namespace Hallucinate.UI
evt.StopPropagation();
}
private void UpdateMasterVolume(float delta)
{
_masterVol = Mathf.Clamp(_masterVol + delta, 0f, 100f);
PlayerPrefs.SetFloat("MasterVolume", _masterVol);
AudioManager.Instance?.SetVolume("MasterVolume", _masterVol);
_masterVolLabel.text = $"{Mathf.RoundToInt(_masterVol)}%";
}
private void UpdateMasterVolume(float delta) => UpdateVolume("MasterVolume", _masterVol + delta);
private void UpdateSubVolume(string key, float delta)
private void UpdateSubVolume(string key, float delta) => UpdateVolume(key, PlayerPrefs.GetFloat(key, 80f) + delta);
private void UpdateVolume(string key, float volume, bool updateSlider = true)
{
float newVal = Mathf.Clamp(PlayerPrefs.GetFloat(key, 80f) + delta, 0f, 100f);
PlayerPrefs.SetFloat(key, newVal);
AudioManager.Instance?.SetVolume(key, newVal);
if (_subRings.TryGetValue(key, out var data)) data.label.text = $"{Mathf.RoundToInt(newVal)}%";
volume = Mathf.Clamp(volume, 0f, 100f);
PlayerPrefs.SetFloat(key, volume);
AudioManager.Instance?.SetVolume(key, volume);
if (key == "MasterVolume")
{
_masterVol = volume;
if (_masterVolLabel != null) _masterVolLabel.text = $"{Mathf.RoundToInt(volume)}%";
}
else
{
if (_subRings.TryGetValue(key, out var data)) data.label.text = $"{Mathf.RoundToInt(volume)}%";
}
if (updateSlider && _audioSliders.TryGetValue(key, out var sliderData))
{
sliderData.slider.SetValueWithoutNotify(volume);
sliderData.input.value = volume.ToString("F1");
}
}
private async void ShowVolumeOverlay()
@@ -508,12 +523,15 @@ namespace Hallucinate.UI
return label;
}
private VisualElement CreateSliderWithInput(string labelText, float min, float max, float startVal, Action<float> OnValueChanged)
private VisualElement CreateSliderWithInput(string labelText, float min, float max, float startVal, Action<float> OnValueChanged, string audioKey = null)
{
var row = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center, marginTop = 5, marginBottom = 5 } };
var label = new Label(labelText) { style = { width = Length.Percent(35) } }; label.AddToClassList("text-body");
var slider = new Slider(min, max) { value = startVal, style = { flexGrow = 1 } };
var input = new TextField { value = startVal.ToString("F1"), style = { width = 50, marginLeft = 10 } }; input.AddToClassList("input-field");
if (audioKey != null) _audioSliders[audioKey] = (slider, input);
slider.RegisterCallback<PointerEnterEvent>(evt => { _hoveredSlider = slider; _hoveredOnChanged = OnValueChanged; _sliderMin = min; _sliderMax = max; });
slider.RegisterCallback<PointerLeaveEvent>(evt => { if (_hoveredSlider == slider) { _hoveredSlider = null; _hoveredOnChanged = null; } });
slider.RegisterValueChangedCallback(evt => { float val = Mathf.Round(evt.newValue * 10f) / 10f; if (input.panel?.focusController?.focusedElement != input.ElementAt(0)) input.value = val.ToString("F1"); OnValueChanged?.Invoke(val); });
@@ -524,12 +542,10 @@ namespace Hallucinate.UI
private VisualElement CreateAudioSlider(string label, string prefKey)
{
var sliderRow = CreateSliderWithInput(label, 0, 100, PlayerPrefs.GetFloat(prefKey, 80), val => {
PlayerPrefs.SetFloat(prefKey, val); AudioManager.Instance?.SetVolume(prefKey, val);
});
UpdateVolume(prefKey, val, false);
}, prefKey);
sliderRow.RegisterCallback<WheelEvent>(evt => {
float newVal = Mathf.Clamp(PlayerPrefs.GetFloat(prefKey, 80f) - (evt.delta.y * 2f), 0f, 100f);
PlayerPrefs.SetFloat(prefKey, newVal); AudioManager.Instance?.SetVolume(prefKey, newVal);
var slider = sliderRow.Q<Slider>(); if (slider != null) slider.value = newVal;
UpdateVolume(prefKey, PlayerPrefs.GetFloat(prefKey, 80f) - (evt.delta.y * 2f));
});
return sliderRow;
}

View File

@@ -49,12 +49,14 @@ namespace Hallucinate.UI
[SerializeField] private VisualTreeAsset profileTemplate;
[SerializeField] private VisualTreeAsset settingsTemplate;
[SerializeField] private VisualTreeAsset hudTemplate;
[SerializeField] private VisualTreeAsset pauseMenuTemplate;
[SerializeField] private StyleSheet globalStyleSheet;
private LoginController _loginController;
private MainMenuController _mainMenuController;
private LobbyController _lobbyController;
private SettingsController _settingsController;
private PauseMenuController _pauseMenuController;
// Osu Trail Pooling
private const int MAX_TRAIL_PARTICLES = 60;
@@ -65,6 +67,9 @@ namespace Hallucinate.UI
private bool _isSettingsOpen = false;
public bool IsSettingsOpen => _isSettingsOpen;
private bool _isPauseMenuOpen = false;
public bool IsPauseMenuOpen => _isPauseMenuOpen;
private const string UI_SCALE_KEY = "UIScale";
#if UNITY_EDITOR
@@ -242,7 +247,43 @@ namespace Hallucinate.UI
}
}
private void HandleCancel() { if (_isSettingsOpen) ToggleSettings(); }
private void HandleCancel()
{
if (_isSettingsOpen) ToggleSettings();
else if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "Main Scene")
{
TogglePauseMenu();
}
}
public async void TogglePauseMenu()
{
if (_pauseMenuController == null) return;
if (!_isPauseMenuOpen)
{
_isPauseMenuOpen = true;
_pauseMenuController.Root.BringToFront();
if (_cursorLayer != null) _cursorLayer.BringToFront();
// Unlock cursor when menu is open
UnityEngine.Cursor.lockState = CursorLockMode.None;
UnityEngine.Cursor.visible = false;
await _pauseMenuController.PlayTransitionIn();
}
else
{
_isPauseMenuOpen = false;
// Re-lock cursor when menu is closed
if (!_isSettingsOpen)
{
UnityEngine.Cursor.lockState = CursorLockMode.Locked;
}
await _pauseMenuController.PlayTransitionOut();
}
}
public async void ToggleSettings()
{
@@ -354,6 +395,7 @@ namespace Hallucinate.UI
RegisterController<ProfileController>(profileTemplate);
_settingsController = RegisterController<SettingsController>(settingsTemplate);
RegisterController<HUDController>(hudTemplate);
_pauseMenuController = RegisterController<PauseMenuController>(pauseMenuTemplate);
_loginController = RegisterController<LoginController>(loginTemplate);
}
catch (Exception e) { Debug.LogError($"[UIManager] Failed to initialize controllers: {e}"); }

View File

@@ -1,140 +0,0 @@
Đặc tả Kiến trúc & Định tuyến Game UI/UX (Phiên bản Unity UI Toolkit)
Tài liệu này phác thảo toàn bộ bố cục cấu trúc, thiết kế trực quan, hiệu ứng chuyển động (animation) và logic định tuyến cho giao diện người dùng của game, được tối ưu hóa đặc biệt cho Unity UI Toolkit.
1. Hệ thống Thiết kế Tổng thể & Phân bổ Dự án
Để duy trì tính nhất quán, dễ bảo trì và làm việc nhóm hiệu quả, dự án tuân thủ nghiêm ngặt nguyên tắc chia tách giao diện (View) và logic (Controller).
1.1. Cấu trúc Thư mục (Directory Structure)
* /Assets/UI: Chứa TOÀN BỘ các file thiết kế giao diện (Visual Assets).
* Các file module hóa: MainMenu.uxml, Lobby.uxml (chứa cả UI Create Room & Join Room), Profile.uxml, Settings.uxml, MainGameHUD.uxml.
* Style toàn cục: Global.uss.
* Fonts, Hình ảnh, Icons, Custom Shaders cho UI.
* /Assets/Scripts/UI: Chứa TOÀN BỘ các script logic (.cs).
* UIManager.cs (Quản lý luồng chính).
* BaseUIController.cs (Lớp cha chứa logic chung).
* Các controller kế thừa: MainMenuController.cs, LobbyController.cs, v.v.
1.2. Hệ thống Controller (OOP - Kế thừa)
* BaseUIController.cs: Lớp cơ sở (Base Class) cho mọi màn hình UI. Định nghĩa các virtual method cốt lõi như Show(), Hide(), PlayTransitionIn(), PlayTransitionOut(), và đăng ký sự kiện.
* Inheritance: Các class khác (MainMenuController, LobbyController...) sẽ kế thừa (inherit) từ BaseUIController và override lại logic cụ thể của từng màn hình, giúp code không bị lặp lại (DRY - Don't Repeat Yourself).
1.3. UIManager & Hierarchy (Phân cấp)
* Kiến trúc Hierarchy: Trong Scene, UIManager là một GameObject root duy nhất gắn component UIDocument. Nó đóng vai trò là "Thành phần UI Cha", chứa toàn bộ các template UXML của các màn hình con (MainMenu, Lobby, Settings...) bên trong nó.
* Tính năng Debug: UIManager được thiết kế có custom Inspector, cho phép Dev/Designer có thể tick bật/tắt nhanh các màn hình trực tiếp trên Editor, và theo dõi/thay đổi nhanh các chỉ số debug (ping, trạng thái UI) theo thời gian thực mà không cần viết lệnh console.
* DontDestroyOnLoad: UIManager (và EventSystem đi kèm) sẽ được đánh dấu DontDestroyOnLoad. Nó tồn tại xuyên suốt qua nhiều Scene, cực kỳ lý tưởng để duy trì kết nối mạng (Networked UI) khi sử dụng Photon Fusion hoặc Unity Relay mà không bị ngắt quãng UI giữa các lần load map.
1.4. Xử lý WorldSpace UI (Giao diện trong không gian 3D)
Đối với các UI xuất hiện trong WorldSpace (VD: Thanh máu trên đầu nhân vật, Tên người chơi, Tương tác vật phẩm 3D):
* Không bỏ chung vào UIManager chính (vốn là ScreenSpace - Overlay).
* Sử dụng một GameObject 3D riêng biệt, gắn component UIDocument.
* Thay vì dùng PanelSettings của màn hình chính, gán cho nó một WorldSpace PanelSettings riêng hoặc sử dụng kĩ thuật render UI Toolkit vào một RenderTexture và chiếu nó lên một Quad (phụ thuộc vào phiên bản Unity đang dùng).
* Logic WorldSpace UI được quản lý cục bộ bởi Entity đó (VD: PlayerWorldUIController.cs).
1.5. Các Framework & Thư viện Cần thiết
1. PrimeTween: Hệ thống Animation cốt lõi (Xử lý các hiệu ứng lò xo, trượt, fade).
2. Unity New Input System: Xử lý input chuột đặc biệt và phím tắt.
3. UniTask: Quản lý luồng bất đồng bộ (chờ animation chuyển cảnh).
4. VContainer / Zenject: Dependency Injection.
5. Photon Fusion / UGS: Backend mạng.
2. Trải nghiệm Tương tác Cốt lõi (Core UX)
2.1. Logic "Con trỏ vô hình" & Pulse Effect (Chỉ ở Main Menu)
* Ẩn có điều kiện: Con trỏ chuột của hệ điều hành Cursor.visible = false CHỈ được áp dụng khi người chơi ở màn hình MainMenu. Ở các màn hình khác (Lobby, Settings), con trỏ chuột bình thường sẽ xuất hiện lại để dễ nhập liệu.
* Tương tác Top-Down: Có một "Con trỏ ảo" (Virtual Cursor) bằng UI Toolkit luôn nằm trên cùng (z-index cao nhất). Các thao tác Raycast sẽ bắn từ trên xuống.
* Hiệu ứng Pulse (Tính toán khoảng cách): Tương tự osu!lazer, hệ thống liên tục tính toán khoảng cách vector từ tọa độ con trỏ ảo đến tâm (center) của các component UI tương tác. Khi con trỏ tiến lại gần, component đó sẽ dần dần phóng to lên (Pulse/Scale) mượt mà dựa trên cự ly, tạo cảm giác UI "đang sống" và hút chuột.
2.2. Hiệu ứng Nút bấm lò xo (Osu! Spring Effect)
Tất cả các nút bấm (Button) trong game khi có sự kiện PointerDownEvent sẽ bị ép/nén (scale nhỏ lại, VD: 0.9x). Khi nhả chuột (PointerUpEvent), PrimeTween sẽ kích hoạt hiệu ứng nảy (elastic/bounce) vọt lố (overshoot) lên 1.1x rồi dao động từ từ về lại kích thước 1.0x. Cảm giác bấm phải rất đầm và có lực nén như lò xo.
2.3. Hiệu ứng Chuyển cảnh Toàn cục (Global Screen Transitions)
* Background tĩnh: Hình nền phía sau (hoặc cảnh 3D) luôn giữ nguyên, không bị giật hoặc nhấp nháy khi chuyển màn hình.
* Fly-Out & Fly-In:
* Khi gọi UIManager.Push(NewScreen): Màn hình cũ (BaseUIController.PlayTransitionOut()) sẽ chia làm 2 nửa, hoặc trượt toàn bộ bay ra khỏi mép màn hình (trái và phải).
* Ngay sau đó, Màn hình mới (BaseUIController.PlayTransitionIn()) sẽ bay vào từ 2 mép màn hình tiến vào giữa, kết thúc bằng một hiệu ứng Bounce nhẹ để tiếp đất.
3. Chi tiết Triển khai Từng Màn hình (Visual Layout & Components)
3.1. Main Menu (MainMenu.uxml)
Đây là màn hình phô diễn kỹ thuật UI với trạng thái máy trạng thái (State Machine) phức tạp.
* Trạng thái 1: Mới tải (Idle)
* Trực quan: Nền trong suốt hoặc Blur cảnh nền. Chỉ có một khối VisualElement hình tròn lớn (Logo) nằm chính giữa màn hình. Liên tục "đập" (pulse) scale từ 1.0 -> 1.05 theo nhịp nhạc.
* Trạng thái 2: Menu Hoạt động (Ribbon State)
* Chuyển từ State 1 -> 2: Khi click vào Logo, Logo trượt mượt mà sang vị trí lệch trái. Dải băng (VisualElement dạng hình chữ nhật dài tràn viền, có màu nền gradient) mở ra.
* Cấu trúc Ribbon (Flex-direction: Row): [ Settings ] (Nút vát chéo, icon răng cưa) -> [ LOGO ] -> [ Join ] -> [ Create ] -> [ Profile ] -> [ Exit ].
3.2. Lobby / Sảnh chờ (Lobby.uxml)
Màn hình Lobby sử dụng chung layout Chia đôi đường chéo (Diagonal Split).
* Khung Trái (Left Pane - 60% width): Nền trong suốt (background-color: clear), chỉ dùng để render hiển thị nhân vật 3D đứng trong sảnh.
* Khung Phải (Right Pane - 40% width): Nền kính mờ (Frosted glass/Blur backdrop).
Bên trong Khung Phải sẽ linh hoạt thay đổi nội dung tùy vào việc người chơi chọn Join hay Create:
* A. Giao diện Join Room: Có TextField tìm kiếm, DropdownField sắp xếp, và ScrollView chứa danh sách phòng.
* B. Giao diện Create Room: Các ô TextField nhập Tên phòng, Checkbox Toggle Mật khẩu, và nút CREATE khổng lồ.
* C. Giao diện Lounge: Chia chéo 50/50. Nền Host ám xanh, Guest ám cam. Cả 2 đều có nút Toggle "Ready".
3.3. Profile (Profile.uxml)
Áp dụng lại khung Split chéo tương tự Lobby. Khung trái chiếu nhân vật.
* Khung Phải (Right Pane):
* Header: Avatar (Mask tròn), Username lớn, Badge Rank.
* Stats: Các thanh ProgressBar tỷ lệ thắng, Label số trận, Elo Rating.
* Inventory: ScrollView chứa thẻ Skin/Banner.
3.4. HUD Trong Game (MainGameHUD.uxml)
Màn hình bao phủ toàn cảnh, set picking-mode: ignore gốc.
* Top-Left: 2 ProgressBar (Máu, Thể lực) dùng shader Fluid lấp đầy.
* Top-Right: Minimap dạng tròn/vuông bo viền, có fade opacity ở mép.
* Bottom-Left: Túi đồ ngang, 1 ô lớn (Đang cầm) và 3 ô nhỏ (Khe phím 1,2,3).
* Bottom-Center: Text Ping & FPS tối giản.
3.5. Menu Cài đặt / Settings (Settings.uxml)
Thiết kế dạng Sidebar trượt ngang (Slide-in Panel) từ lề trái và không chặn tương tác (Non-blocking UI).
* Bố cục 2 Cột (Split-Pane):
* Cột Trái (Tabs - 30%): Chứa các nút [ General ], [ Video ], [ Sound ], [ Control ]. Nút đang chọn sẽ đổi màu và có viền mép trái.
* Cột Phải (Details - 70%): Chứa một ScrollView duy nhất. Nội dung bên trong (Sliders, Dropdowns, Toggles) thay đổi động dựa theo Tab đang chọn ở cột trái.
* Nút Close: Một nút < Back hoặc [ X ] ở góc trên lề trái.
4. Logic Định tuyến (UIManager.cs)
[Game Launch]
|
[Main Menu] (State 1: Idle) <---(Timeout/No Input)---+
| |
(Click Logo) |
| |
[Main Menu] (State 2: Ribbon) -----------------------+
|
+-------(Click Logo Lần 2)------> [Lobby: Create]
|
+-------------------+-------------------+-------------------+
| | | |
v v v v
[Lobby: Create] [Lobby: Join] [Profile] [Settings (Sidebar)]
| | | |
v v | |
[Lounge (Host)] [Lounge (Guest)] +---(Back)----------+
| |
+--- [All Ready] ---+
|
(Host Clicks Start)
|
v
[IN-GAME HUD]
* Transition Flow: UIManager.Push(T extends BaseUIController). Hàm này gọi CurrentScreen.PlayTransitionOut() (Fly-out) -> Chờ hoàn thành -> Kích hoạt màn hình mới -> Gọi NewScreen.PlayTransitionIn() (Fly-in Bounce).
5. Chi tiết Hệ thống Script & Logic Controller (C#)
Mục này quy định trách nhiệm của từng file script (.cs) điều khiển các thành phần UXML, xử lý logic tương tác và event binding thông qua query (root.Q<T>).
5.1. BaseUIController.cs
Lớp cha trừu tượng (Abstract) cung cấp các hàm nền tảng cho mọi màn hình.
* Biến: protected VisualElement root;, protected UIManager uiManager;
* Hàm Initialize(VisualElement uxmlRoot, UIManager manager): Khởi tạo controller, nhận tham chiếu đến nhánh UXML cụ thể của nó.
* Hàm Show() / Hide(): Thay đổi thuộc tính style.display thành Flex hoặc None.
* Hàm PlayTransitionIn() / PlayTransitionOut(): (Virtual) Khai báo logic PrimeTween để trượt/bay màn hình ra/vào. Mặc định là trượt ngang toàn bộ nhánh root.
5.2. MainMenuController.cs
Quản lý cỗ máy trạng thái (State Machine) của Main Menu và khóa trục chuột.
* State Management: Có biến enum MenuState { Idle, Ribbon }.
* Event Binding: Lấy phần tử Logo (root.Q<VisualElement>("Logo")), gán sự kiện PointerDownEvent.
* Nếu click khi đang Idle: Chuyển state sang Ribbon, dùng PrimeTween trượt Logo sang trái, bung dải Ribbon ra. Khởi động Timer Timeout.
* Nếu click khi đang Ribbon: Gọi uiManager.Push<LobbyController>().
* Idle Timeout Logic: Hàm Update() liên tục đếm thời gian từ lần cuối có tương tác (mouse di chuyển/click). Nếu vượt quá X giây (vd: 5s), tự động trigger tween trả Logo về giữa và đóng Ribbon.
* Mouse Axis Locking: Giao tiếp với Input System. Khi ở trạng thái Ribbon, ép tọa độ trục Y của con trỏ ảo luôn bằng với tọa độ Y của dải Ribbon.
5.3. LobbyController.cs
Xử lý logic 3 lớp giao diện bên trong Lobby (Create, Join, Lounge) mà không cần chuyển Screen mới.
* Sub-Views Toggling: Lấy tham chiếu đến 3 VisualElement container (JoinContainer, CreateContainer, LoungeContainer). Xử lý ẩn/hiện (display: none) chúng dựa theo path định tuyến từ UIManager.
* Join Logic: Gán danh sách giả/mạng vào ScrollView. Khởi tạo các item đúc sẵn (prefabs bằng uxml) bằng vòng lặp. Lắng nghe event click của từng item phòng để hiện Modal nhập Password nếu cần.
* Lounge Logic: Lắng nghe nút Toggle Ready. Gửi RPC mạng báo cho người chơi kia. Khi cả 2 biến isPlayer1Ready và isPlayer2Ready = true, gỡ khóa (Enable) nút [ START GAME ] cho Host.
5.4. SettingsController.cs
Xử lý thanh Sidebar và cơ chế chia tab.
* Tab Switching: Gán sự kiện ClickEvent cho 4 nút Tab ở Cột trái. Khi click, dùng vòng lặp xóa class .active-tab của tất cả, thêm .active-tab cho nút vừa click. Đồng thời Clear() nội dung của ScrollView ở Cột phải và Load/Instantiate layout của tab tương ứng vào.
* Non-blocking Transition: Hàm PlayTransitionIn() của riêng SettingsController chỉ trượt nhánh root (Sidebar) từ -500px (bên ngoài mép trái) về 0px thay vì ẩn toàn bộ các màn hình khác đi.
* Keybind Logic: Lắng nghe phím Esc để gọi hàm đóng Settings. Trong Tab Control, khi click đổi phím, script gọi luồng InputSystem.onAnyButtonPress để bắt phím tiếp theo và cập nhật tên Label. Lắng nghe thanh Slider để gọi AudioMixer.SetFloat().
5.5. ProfileController.cs
Cập nhật dữ liệu tài khoản hiển thị lên View.
* Data Binding: Khi gọi Show(), controller kéo dữ liệu từ hệ thống lưu trữ (PlayerPrefs/Cloud). Tìm các thành phần root.Q<Label>("WinRateText"), root.Q<ProgressBar>("WinRateBar") và cập nhật .text hoặc .value của chúng.
* Skin Inventory: Load kho đồ vào ScrollView ở cột phải. Lắng nghe ClickEvent vào các thẻ Skin để cập nhật Skin đang trang bị (báo cho Game Manager thay đổi vật liệu 3D ở Khung trái).
5.6. HUDController.cs
Quản lý thông tin theo thời gian thực (Real-time). Không chặn Input.
* Auto-Fade Logic: Giữ biến lastActionTime. Nếu Time.time - lastActionTime > 5f, dùng PrimeTween giảm opacity của túi đồ và thanh máu xuống 0.2f. Khi người chơi nhấn chuột, xài chiêu, hoặc bị sát thương -> gọi hàm WakeUpHUD() đẩy opacity về 1.0f ngay lập tức.
* Inventory Quick-slots: Lắng nghe phím 1, 2, 3. Hoán đổi thuộc tính style.backgroundImage của Ô nhỏ đang chọn lên Ô [ Đang Cầm ] lớn nhất.
* Fluid Shaders: Gửi dữ liệu biến thiên (VD: 0.0 -> 1.0) từ Máu/Thể lực hiện tại vào Material/Shader được gán trực tiếp trên VisualElement thông qua thuộc tính .customMaterial trong UI Toolkit.

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 6354ab3eece31da4ab644563d7a45612
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -347,6 +347,19 @@ DropdownField:hover .unity-base-field__input {
PANELS & OTHERS
============================================================ */
.panel-glass { background-color: var(--color-surface); border-radius: 20px; }
.panel-glass--right {
flex-grow: 1;
background-color: var(--color-surface);
padding: 40px;
border-top-left-radius: 40px;
border-bottom-left-radius: 40px;
/* Flush with right edge */
border-top-right-radius: 0;
border-bottom-right-radius: 0;
margin-right: 0;
border-right-width: 0;
}
.rebind-row { flex-direction: row; justify-content: space-between; align-items: center; padding: 12px 16px; background-color: rgba(255, 255, 255, 0.02); border-radius: 10px; margin-bottom: 6px; }
.rebind-label { font-size: 14px; color: #cccccc; }
.rebind-button { width: 140px; height: 36px; background-color: rgba(255, 255, 255, 0.08); border-radius: 8px; border-width: 1px; border-color: rgba(255, 255, 255, 0.1); color: #00ffcc; font-size: 13px; -unity-font-style: bold; }

View File

@@ -35,6 +35,8 @@
<ui:VisualElement style="flex-grow: 1;" />
<ui:Label name="CreateErrorLabel" text="Failed to create room!" class="text-label" style="color: #ff4444; align-self: center; display: none; margin-bottom: 10px;" />
<ui:VisualElement style="flex-direction: row; justify-content: space-between; margin-top: 20px;">
<ui:Button name="CancelCreateBtn" text="CANCEL" class="button-spring btn-exit" style="width: 48%;" />
<ui:Button name="ConfirmCreateBtn" text="CREATE" class="button-spring btn-join" style="width: 48%;" />
@@ -100,5 +102,18 @@
</ui:VisualElement>
</ui:VisualElement>
<!-- TRANSFER HOST OVERLAY -->
<ui:VisualElement name="TransferHostOverlay" style="position: absolute; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); justify-content: center; align-items: center; display: none;">
<ui:VisualElement class="panel-glass" style="width: 350px; padding: 20px;">
<ui:Label text="TRANSFER LEADERSHIP" class="text-subheading" style="align-self: center;" />
<ui:Label text="Do you want to transfer host privileges to this player?" class="text-label" style="align-self: center; -unity-text-align: middle-center; margin-bottom: 20px; white-space: normal;" />
<ui:VisualElement style="flex-direction: row; justify-content: space-between;">
<ui:Button name="CloseTransferBtn" text="CANCEL" class="button-spring btn-exit" style="width: 48%;" />
<ui:Button name="ConfirmTransferBtn" text="TRANSFER" class="button-spring btn-join" style="width: 48%;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
</ui:UXML>

9
Assets/UI/PauseMenu.uxml Normal file
View File

@@ -0,0 +1,9 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<ui:VisualElement name="PauseMenuRoot" style="flex-grow: 1; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, 0.7);">
<ui:VisualElement name="PauseContainer" style="width: 400px; padding: 40px; background-color: rgba(20, 20, 20, 0.95); border-radius: 10px; border-width: 2px; border-color: rgb(0, 255, 204);">
<ui:Label text="PAUSE" name="PauseTitle" style="font-size: 40px; color: rgb(0, 255, 204); -unity-font-style: bold; -unity-text-align: middle-center; margin-bottom: 30px;" />
<ui:Button text="RESUME" name="ResumeBtn" class="button-spring" style="margin-bottom: 15px; height: 50px; font-size: 20px; color: white; background-color: rgba(255, 255, 255, 0.1); border-radius: 5px;" />
<ui:Button text="LEAVE ROOM" name="QuitBtn" class="button-spring" style="height: 50px; font-size: 20px; color: rgb(255, 100, 100); background-color: rgba(255, 255, 255, 0.1); border-radius: 5px;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 65008e71286aba241b9118de2b48c457
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,888 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 13
m_BakeOnSceneLoad: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 2
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 1
m_PVRFilteringGaussRadiusAO: 1
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &300163211
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 300163213}
- component: {fileID: 300163212}
m_Layer: 0
m_Name: AudioManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &300163212
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 300163211}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 35bf1b4a2b113c048874a8a4a3ea18b3, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.Audio.AudioManager
database: {fileID: 11400000, guid: c73d93f8732fbe64d8b0d1cde67a1892, type: 2}
poolSize: 20
defaultGroup: {fileID: 24300002, guid: 914a8292e2b2b594e9b7cb3ee0c7e77d, type: 2}
--- !u!4 &300163213
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 300163211}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &417583765
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 417583767}
- component: {fileID: 417583766}
m_Layer: 0
m_Name: Spawner
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &417583766
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 417583765}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ca752d01bdc2c5e42938776307031da3, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.UI.BasicSpawner
_playerPrefab:
RawGuidValue: 761bdf2e5c0cff4488527355acb975e5
_playerDataManagerPrefab:
RawGuidValue: 33a4edcf030b02446bd8e4bb9a0fb9f3
--- !u!4 &417583767
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 417583765}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &458228298
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 458228301}
- component: {fileID: 458228300}
- component: {fileID: 458228299}
- component: {fileID: 458228302}
m_Layer: 0
m_Name: UIManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &458228299
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 458228298}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bcb7b8ed439bb4546b0648c627c2ce5d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.UI.UIManager
inputReader: {fileID: 2128442884}
gameIcon: {fileID: 2800000, guid: 87bdbf8b24b50c943ab70ce235338dc7, type: 3}
cursorSprite: {fileID: 21300000, guid: bf03bd4e32f382f45bd848d91517f188, type: 3}
cursorTrailSprite: {fileID: 21300000, guid: 85459ea0df49a094d8fe4178b701bd9b, type: 3}
cursorSize: 57
trailDistanceThreshold: 15
enableRipples: 1
rippleColor: {r: 1, g: 1, b: 1, a: 0.5}
loginTemplate: {fileID: 9197481963319205126, guid: 4f11f2cb91fbd4748bcbc70cd0f5afe7, type: 3}
mainMenuTemplate: {fileID: 9197481963319205126, guid: 8dcbe9fd5e8c43c43921af21a6347624, type: 3}
lobbyTemplate: {fileID: 9197481963319205126, guid: 2b2480fff4320714e9b503e7d5ef2c9f, type: 3}
roomItemTemplate: {fileID: 9197481963319205126, guid: 1be64545006384b4dbaa87849f32b8ba, type: 3}
profileTemplate: {fileID: 9197481963319205126, guid: e481c7d94f843374cb57e215bf9b0624, type: 3}
settingsTemplate: {fileID: 9197481963319205126, guid: 1e24e32e93afac8449d0bb181ab5c6a9, type: 3}
hudTemplate: {fileID: 9197481963319205126, guid: b87ba33c06a8c1d46a3d9f03416ebf3f, type: 3}
pauseMenuTemplate: {fileID: 0}
globalStyleSheet: {fileID: 7433441132597879392, guid: f5de9bd0abf1aa7418f2d265090cae2c, type: 3}
--- !u!114 &458228300
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 458228298}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: c093ebe66178f9047be53f245ccc3c2d, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 0}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!4 &458228301
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 458228298}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -16124.571, y: -11651.664, z: 100.93924}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &458228302
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 458228298}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ff7ac0ce8c8c98445b895ac53a4618f1, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.UI.LocalizationManager
--- !u!1 &626355268
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 626355270}
- component: {fileID: 626355269}
- component: {fileID: 626355271}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &626355269
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 626355268}
m_Enabled: 1
serializedVersion: 12
m_Type: 1
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize2D: {x: 0.5, y: 0.5}
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
m_LightUnit: 1
m_LuxAtDistance: 1
m_EnableSpotReflector: 1
--- !u!4 &626355270
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 626355268}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!114 &626355271
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 626355268}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalLightData
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_CustomShadowLayers: 0
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
m_RenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_ShadowRenderingLayersMask:
serializedVersion: 0
m_Bits: 1
m_Version: 4
m_LightLayerMask: 1
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &1848374378
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1848374381}
- component: {fileID: 1848374380}
- component: {fileID: 1848374379}
- component: {fileID: 1848374382}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &1848374379
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1848374378}
m_Enabled: 1
--- !u!20 &1848374380
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1848374378}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &1848374381
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1848374378}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1848374382
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1848374378}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData
m_RenderShadows: 1
m_RequiresDepthTextureOption: 2
m_RequiresOpaqueTextureOption: 2
m_CameraType: 0
m_Cameras: []
m_RendererIndex: -1
m_VolumeLayerMask:
serializedVersion: 2
m_Bits: 1
m_VolumeTrigger: {fileID: 0}
m_VolumeFrameworkUpdateModeOption: 2
m_RenderPostProcessing: 0
m_Antialiasing: 0
m_AntialiasingQuality: 2
m_StopNaN: 0
m_Dithering: 0
m_ClearDepth: 1
m_AllowXRRendering: 1
m_AllowHDROutput: 1
m_UseScreenCoordOverride: 0
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
m_RequiresDepthTexture: 0
m_RequiresColorTexture: 0
m_TaaSettings:
m_Quality: 3
m_FrameInfluence: 0.1
m_JitterScale: 1
m_MipBias: 0
m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0
m_Version: 2
--- !u!1 &2128442883
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2128442885}
- component: {fileID: 2128442884}
- component: {fileID: 2128442886}
m_Layer: 0
m_Name: InputReader
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &2128442884
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2128442883}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5962d8f2c8e40e240a4a4907c7b539fa, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.InputReader
inputActions: {fileID: -944628639613478452, guid: ac73bbdc8e64ac34c9525df400c1534f, type: 3}
--- !u!4 &2128442885
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2128442883}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -16124.571, y: -11651.664, z: 100.93924}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2128442886
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2128442883}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 62899f850307741f2a39c98a8b639597, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.InputSystem::UnityEngine.InputSystem.PlayerInput
m_Actions: {fileID: -944628639613478452, guid: ac73bbdc8e64ac34c9525df400c1534f, type: 3}
m_NotificationBehavior: 2
m_UIInputModule: {fileID: 0}
m_DeviceLostEvent:
m_PersistentCalls:
m_Calls: []
m_DeviceRegainedEvent:
m_PersistentCalls:
m_Calls: []
m_ControlsChangedEvent:
m_PersistentCalls:
m_Calls: []
m_ActionEvents:
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnMove
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 351f2ccd-1f9f-44bf-9bec-d62ac5c5f408
m_ActionName: 'Player/Move[/Keyboard/w,/Keyboard/upArrow,/Keyboard/s,/Keyboard/downArrow,/Keyboard/a,/Keyboard/leftArrow,/Keyboard/d,/Keyboard/rightArrow]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnLook
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 6b444451-8a00-4d00-a97e-f47457f736a8
m_ActionName: 'Player/Look[/Mouse/delta]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnAttack
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 6c2ab1b8-8984-453a-af3d-a3c78ae1679a
m_ActionName: 'Player/Attack[/Mouse/leftButton,/Keyboard/enter]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnInteract
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 852140f2-7766-474d-8707-702459ba45f3
m_ActionName: 'Player/Interact[/Keyboard/e]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnCrouch
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 27c5f898-bc57-4ee1-8800-db469aca5fe3
m_ActionName: 'Player/Crouch[/Keyboard/c]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnJump
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: f1ba0d36-48eb-4cd5-b651-1c94a6531f70
m_ActionName: 'Player/Jump[/Keyboard/space]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnPrevious
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 2776c80d-3c14-4091-8c56-d04ced07a2b0
m_ActionName: 'Player/Previous[/Keyboard/1]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnNext
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba
m_ActionName: 'Player/Next[/Keyboard/2]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnSprint
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 641cd816-40e6-41b4-8c3d-04687c349290
m_ActionName: 'Player/Sprint[/Keyboard/leftShift]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: c95b2375-e6d9-4b88-9c4c-c5e76515df4b
m_ActionName: 'UI/Navigate[/Keyboard/w,/Keyboard/upArrow,/Keyboard/s,/Keyboard/downArrow,/Keyboard/a,/Keyboard/leftArrow,/Keyboard/d,/Keyboard/rightArrow]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 7607c7b6-cd76-4816-beef-bd0341cfe950
m_ActionName: 'UI/Submit[/Keyboard/enter]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 15cef263-9014-4fd5-94d9-4e4a6234a6ef
m_ActionName: 'UI/Cancel[/Keyboard/escape]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 32b35790-4ed0-4e9a-aa41-69ac6d629449
m_ActionName: 'UI/Point[/Mouse/position]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 3c7022bf-7922-4f7c-a998-c437916075ad
m_ActionName: 'UI/Click[/Mouse/leftButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 44b200b1-1557-4083-816c-b22cbdf77ddf
m_ActionName: 'UI/RightClick[/Mouse/rightButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: dad70c86-b58c-4b17-88ad-f5e53adf419e
m_ActionName: 'UI/MiddleClick[/Mouse/middleButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 0489e84a-4833-4c40-bfae-cea84b696689
m_ActionName: 'UI/ScrollWheel[/Mouse/scroll]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 24908448-c609-4bc3-a128-ea258674378a
m_ActionName: UI/TrackedDevicePosition
- m_PersistentCalls:
m_Calls: []
m_ActionId: 9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be
m_ActionName: UI/TrackedDeviceOrientation
- m_PersistentCalls:
m_Calls: []
m_ActionId: 1702ffae-5ad3-4532-9855-bf7e2a8ae749
m_ActionName: 'Player/Scroll[/Mouse/scroll]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 7e8b9416-0a2d-4652-98d8-e7368560ede9
m_ActionName: 'Player/Change View[/Keyboard/f2]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 2128442884}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnToggleSettings
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 1
m_ActionId: ae29d662-c797-4411-8ff3-8b5ad78427d8
m_ActionName: 'UI/ToggleSetting[/Keyboard/leftCtrl,/Keyboard/g]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 2128442884}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnCancel
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 1
m_ActionId: 79227a8d-6fd2-496d-8466-68f007a2c355
m_ActionName: 'UI/Escape[/Keyboard/escape]'
m_NeverAutoSwitchControlSchemes: 0
m_DefaultControlScheme:
m_DefaultActionMap: UI
m_SplitScreenIndex: -1
m_Camera: {fileID: 1848374380}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1848374381}
- {fileID: 626355270}
- {fileID: 2128442885}
- {fileID: 458228301}
- {fileID: 417583767}
- {fileID: 300163213}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 092551e6a0e088940ba3da8d3ecdb7ce
guid: 1dce1989492b43a4d845e0ead7ae1085
DefaultImporter:
externalObjects: {}
userData: