浏览代码

Completing the game state shift from lobby to relay. This adjusts the countdown to be interruptible and to properly handle exiting the game and restarting it. I'm also starting to trim a bit from the GameStateManager and the main scene, though most of that is pending.

/main/staging
nathaniel.buck@unity3d.com 3 年前
当前提交
90d3890c
共有 21 个文件被更改,包括 342 次插入679 次删除
  1. 47
      Assets/Prefabs/UI/GameCanvas.prefab
  2. 32
      Assets/Prefabs/UI/LobbyGameCanvas.prefab
  3. 194
      Assets/Prefabs/UI/PlayerInteractionPanel.prefab
  4. 109
      Assets/Scenes/mainScene.unity
  5. 126
      Assets/Scripts/Entities/GameStateManager.cs
  6. 14
      Assets/Scripts/Entities/LocalLobby.cs
  7. 8
      Assets/Scripts/Infrastructure/Messenger.cs
  8. 6
      Assets/Scripts/Infrastructure/ObserverBehaviour.cs
  9. 19
      Assets/Scripts/Lobby/LobbyContentHeartbeat.cs
  10. 2
      Assets/Scripts/Lobby/ToLocalLobby.cs
  11. 22
      Assets/Scripts/Relay/RelayUtpClient.cs
  12. 68
      Assets/Scripts/Relay/RelayUtpHost.cs
  13. 2
      Assets/Scripts/Relay/RelayUtpSetup.cs
  14. 12
      Assets/Scripts/UI/CountdownUI.cs
  15. 2
      Assets/Scripts/UI/EndGameButtonUI.cs
  16. 2
      Assets/Scripts/UI/InLobbyUserUI.cs
  17. 2
      Assets/Scripts/UI/ReadyCheckUI.cs
  18. 273
      Assets/Prefabs/UI/CountDownUI.prefab
  19. 7
      Assets/Prefabs/UI/CountDownUI.prefab.meta
  20. 63
      Assets/Scripts/Lobby/ReadyCheck.cs
  21. 11
      Assets/Scripts/Lobby/ReadyCheck.cs.meta

47
Assets/Prefabs/UI/GameCanvas.prefab


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: 7198558056059429223}
m_Father: {fileID: 2637199315522059511}

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: 5835473579278904550}
- {fileID: 2637199315361559713}

m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2637199316888954227}
- {fileID: 2637199315522059511}

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: 2637199317172016811}
m_Father: {fileID: 2637199315671523625}

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: 2637199316546086228}
- {fileID: 5992334104032192704}

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: 2637199315599437355}
m_Father: {fileID: 2637199315671523625}

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: 8705625668171953304}
m_Father: {fileID: 2637199315522059511}

objectReference: {fileID: 0}
- target: {fileID: 5713552561910003945, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_fontSize
value: 31.3
value: 18
objectReference: {fileID: 0}
- target: {fileID: 5749901921003950368, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_AnchorMax.y

objectReference: {fileID: 0}
- target: {fileID: 6281383251298602143, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_fontSize
value: 31.3
value: 18
objectReference: {fileID: 0}
- target: {fileID: 6701676754128905643, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_AnchorMax.y

- target: {fileID: 8694871130870774657, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8737752538827170250, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_fontSize
value: 18.2
objectReference: {fileID: 0}
- target: {fileID: 8941493459590097871, guid: 247f79ab5aefc6d40bcbdade4d9467b7, type: 3}
propertyPath: m_AnchorMax.y

propertyPath: m_fontSize
value: 17.45
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_MinWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_MinHeight
value: 100
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_FlexibleWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_FlexibleHeight
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_LayoutPriority
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_PreferredWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 2755841879706393458, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_PreferredHeight
value: 300
objectReference: {fileID: 0}
- target: {fileID: 2828520451782533824, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_Size
value: 1

objectReference: {fileID: 0}
- target: {fileID: 3638764283281205412, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_Size
value: 1
value: 0
value: 0
value: 0.9999999
objectReference: {fileID: 0}
- target: {fileID: 3675426980811071808, guid: 404728f5cffe43940b290121bd31f601, type: 3}
propertyPath: m_AnchorMax.x

32
Assets/Prefabs/UI/LobbyGameCanvas.prefab


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: 1906352097507614706}
m_RootOrder: 0

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: 466693923092094802}
- {fileID: 2244251208239780121}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &3403950992349691351
MonoBehaviour:
m_ObjectHideFlags: 0

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: 4212636328457333019}
m_Father: {fileID: 2244251207921394025}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &6860436446719602335
MonoBehaviour:
m_ObjectHideFlags: 0

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: 466693923092094802}
m_RootOrder: 0

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: 7445706979321241619}
m_Father: {fileID: 2244251207921394025}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &279783410280127446
MonoBehaviour:
m_ObjectHideFlags: 0

propertyPath: m_Name
value: RelayCodeCanvas
objectReference: {fileID: 0}
- target: {fileID: 7546827419935918100, guid: 27536a164837c9141bbe1adf7ba37dde, type: 3}
propertyPath: m_fontSize
value: 18.2
objectReference: {fileID: 0}
- target: {fileID: 7676491730539518990, guid: 27536a164837c9141bbe1adf7ba37dde, type: 3}
propertyPath: m_Alpha
value: 0

propertyPath: m_Name
value: PlayerInteractionPanel
objectReference: {fileID: 0}
- target: {fileID: 7303921398628037483, guid: 2ff073ec9c74c8942bd90a541dc41bfc, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7303921398628037483, guid: 2ff073ec9c74c8942bd90a541dc41bfc, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7303921398628037483, guid: 2ff073ec9c74c8942bd90a541dc41bfc, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7303921398628037483, guid: 2ff073ec9c74c8942bd90a541dc41bfc, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8979361099148208042, guid: 2ff073ec9c74c8942bd90a541dc41bfc, type: 3}
propertyPath: m_AnchorMax.y
value: 0

objectReference: {fileID: 0}
- target: {fileID: 4463750083940306578, guid: e269788e17cbca145bf78e8971aeb223, type: 3}
propertyPath: m_Enabled
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4463750083940306578, guid: e269788e17cbca145bf78e8971aeb223, type: 3}
propertyPath: m_PresetInfoIsWorld
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4463750083940306589, guid: e269788e17cbca145bf78e8971aeb223, type: 3}

194
Assets/Prefabs/UI/PlayerInteractionPanel.prefab


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &580481917308754637
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7303921398628037483}
- component: {fileID: 4155147274821193738}
- component: {fileID: 4969504009400302254}
- component: {fileID: 8388542991005336197}
m_Layer: 5
m_Name: CountDownUI
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7303921398628037483
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580481917308754637}
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_Children: []
m_Father: {fileID: 1611213509401803489}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4155147274821193738
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580481917308754637}
m_CullTransparentMesh: 1
--- !u!114 &4969504009400302254
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580481917308754637}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5b3b588e7ae40ec4ca35fdb9404513ab, type: 3}
m_Name:
m_EditorClassIdentifier:
OnObservedUpdated:
m_PersistentCalls:
m_Calls: []
m_CountDownText: {fileID: 4467363028704636643}
--- !u!225 &8388542991005336197
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580481917308754637}
m_Enabled: 1
m_Alpha: 0
m_Interactable: 0
m_BlocksRaycasts: 0
m_IgnoreParentGroups: 0
--- !u!1 &609596107351326384
GameObject:
m_ObjectHideFlags: 0

m_Children:
- {fileID: 8979361099148208042}
- {fileID: 1135759803389522016}
- {fileID: 7303921398628037483}
m_Father: {fileID: 1108938163892239274}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!225 &4811792094336013573
CanvasGroup:
m_ObjectHideFlags: 0

m_PersistentCalls:
m_Calls: []
showing: 0
m_ShowThisWhen: 5
m_ShowThisWhen: -1
--- !u!1 &1032235666708655174
GameObject:
m_ObjectHideFlags: 0

- component: {fileID: 4467363028704636643}
- component: {fileID: 2302135311448425839}
m_Layer: 5
m_Name: WaitingText
m_Name: StateText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0

m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Waiting for ReadyCheck Countdown...
m_text: <This shows countdown state>
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}

m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 12.85
m_fontSize: 14.9
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &9048520512602473890
MonoBehaviour:
m_ObjectHideFlags: 0

m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 1611213509401803489}
- {fileID: 7303921398628037483}
m_Father: {fileID: 4558362294547660329}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &5998684818406589344
MonoBehaviour:
m_ObjectHideFlags: 0

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
observeOnStart: 1
--- !u!114 &5356355227050787427
MonoBehaviour:
m_ObjectHideFlags: 0

m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1001 &5118553947161812946
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 1108938163892239274}
m_Modifications:
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_AnchorMax.x
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3702758058023689559, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_Alpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3702758058023689559, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_Interactable
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3702758058023689559, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_BlocksRaycasts
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5694388898566309151, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
propertyPath: m_Name
value: CountDownUI
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
--- !u!224 &7303921398628037483 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 2473738857440996537, guid: f90e4035352c7ce40b68e50109a9bb4f, type: 3}
m_PrefabInstance: {fileID: 5118553947161812946}
m_PrefabAsset: {fileID: 0}

109
Assets/Scenes/mainScene.unity


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: 0}
m_RootOrder: 2

m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
--- !u!114 &648562208 stripped
--- !u!114 &883450645 stripped
m_CorrespondingSourceObject: {fileID: 6939937855246394599, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
m_CorrespondingSourceObject: {fileID: 6961224259983233844, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
m_Script: {fileID: 11500000, guid: 70dfc2fde0a9ef04eaff29a138f0bf45, type: 3}
m_Script: {fileID: 11500000, guid: 51373dc3c6ac79b4f8e36ac7c4419205, type: 3}
--- !u!114 &883450645 stripped
--- !u!114 &1014339014 stripped
m_CorrespondingSourceObject: {fileID: 6961224259983233844, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
m_CorrespondingSourceObject: {fileID: 7853401853899595651, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
m_Script: {fileID: 11500000, guid: 51373dc3c6ac79b4f8e36ac7c4419205, type: 3}
m_Script: {fileID: 11500000, guid: 5b3b588e7ae40ec4ca35fdb9404513ab, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1217229506 stripped

m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 70dfc2fde0a9ef04eaff29a138f0bf45, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1583737884 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 857969996410458156, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
m_PrefabInstance: {fileID: 2637199315837045693}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a03b37d5b8df06948b36dfbc430a1ea5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1886099429 stripped

- target: {fileID: 741689626084393640, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 774903988744295172, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: 15
objectReference: {fileID: 0}
- target: {fileID: 901738327287436208, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y

objectReference: {fileID: 0}
- target: {fileID: 4822032080772604407, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.x
value: -0.00005787611
value: -0.0000030994415
value: 0.0000018929122
value: 0.000013391712
objectReference: {fileID: 0}
- target: {fileID: 4824240073023402834, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y

propertyPath: m_BlocksRaycasts
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5573036458859714118, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5573036458859714118, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5573036458859714118, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5573036458859714118, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5674629351396617348, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_Alpha
value: 0

propertyPath: m_AnchoredPosition.x
value: -9.757019
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_MinWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_MinHeight
value: 100
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_FlexibleWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_FlexibleHeight
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_LayoutPriority
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_PreferredWidth
value: -1
objectReference: {fileID: 0}
- target: {fileID: 5933581043558999113, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_PreferredHeight
value: 300
objectReference: {fileID: 0}
- target: {fileID: 5991488785009139195, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_Size
value: 1

propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6656827769630762920, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_Alpha
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6664893525864283123, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.x
value: -19.000122

propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6910946530474729345, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_Alpha
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6970381027661675607, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y
value: 0

- target: {fileID: 6970381027661675607, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7088175716995442510, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: showing
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7198558056629795013, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_fontSize

propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7824982990876343133, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_fontSize
value: 18
objectReference: {fileID: 0}
- target: {fileID: 7864410018658149118, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y
value: 0

propertyPath: m_fontSize
value: 35.8
objectReference: {fileID: 0}
- target: {fileID: 8428070622252142379, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_fontSize
value: 18
objectReference: {fileID: 0}
- target: {fileID: 8726787022963647593, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: showing
value: 1

- target: {fileID: 8740957582409016033, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8806225834216904879, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_fontSize
value: 18
objectReference: {fileID: 0}
- target: {fileID: 8889734615304832804, guid: f1d618bdc6f1813449d428126e640aa5, type: 3}
propertyPath: m_AnchorMax.y

objectReference: {fileID: 0}
- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LocalUserObservers.Array.size
value: 3
value: 4
objectReference: {fileID: 0}
- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LocalLobbyObservers.Array.size

- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LobbyDataObservers.Array.data[5]
value:
objectReference: {fileID: 648562208}
objectReference: {fileID: 0}
- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LobbyDataObservers.Array.data[6]
value:

- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LocalUserObservers.Array.data[3]
value:
objectReference: {fileID: 0}
objectReference: {fileID: 1583737884}
- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LocalLobbyObservers.Array.data[0]
value:

value:
objectReference: {fileID: 648562208}
objectReference: {fileID: 1014339014}
- target: {fileID: 7716713811812636910, guid: f80fc24bab3dcda459a2669321e2e5a4, type: 3}
propertyPath: m_LocalLobbyObservers.Array.data[2]
value:

126
Assets/Scripts/Entities/GameStateManager.cs


namespace LobbyRelaySample
{
// TODO: This is pretty bloated. Additionally, it needs a pass for removing redundant calls and organizing things in a more intuitive way and whatnot
public class GameStateManager : MonoBehaviour, IReceiveMessages
{
[SerializeField]

LocalLobby m_localLobby;
LobbyServiceData m_lobbyServiceData = new LobbyServiceData();
LocalGameState m_localGameState = new LocalGameState();
ReadyCheck m_readyCheck;
RelayUtpSetup m_relaySetup;
RelayUtpClient m_relayClient;

var unused = Locator.Get;
#pragma warning restore IDE0059 // Unnecessary assignment of a value
Locator.Get.Provide(new Auth.Identity(OnAuthSignIn));
m_readyCheck = new ReadyCheck(7);
Application.wantsToQuit += OnWantToQuit;
}

m_localLobby.AddPlayer(m_localUser); // The local LobbyUser object will be hooked into UI before the LocalLobby is populated during lobby join, so the LocalLobby must know about it already when that happens.
}
/// <summary>
/// Primarily used for UI elements to communicate state changes, this will receive messages from arbitrary providers for user interactions.
/// </summary>
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.RenameRequest)

{
SetGameState((GameState)msg);
}
else if (type == MessageType.UserSetEmote) // TODO: oh what are these doing here
else if (type == MessageType.UserSetEmote)
else if (type == MessageType.ChangeLobbyUserState)
else if (type == MessageType.LobbyUserStatus)
else if (type == MessageType.Client_EndReadyCountdownAt)
else if (type == MessageType.StartCountdown)
m_localLobby.TargetEndTime = (DateTime)msg;
else if (type == MessageType.ToLobby)
else if (type == MessageType.CancelCountdown)
ToLobby();
m_localLobby.State = LobbyState.Lobby;
m_localLobby.CountDownTime = 0;
}
else if (type == MessageType.ConfirmInGameState)
{
m_localUser.UserStatus = UserStatus.InGame;
m_localLobby.State = LobbyState.InGame;
}
else if (type == MessageType.EndGame)
{
m_localLobby.State = LobbyState.Lobby;
m_localLobby.CountDownTime = 0;
SetUserLobbyState();
m_localLobby = new LocalLobby
{
State = LobbyState.Lobby
};
m_localLobby = new LocalLobby { State = LobbyState.Lobby };
DefaultObserverSetup();
/// <summary>
/// We find and validate that the scene has all the Observers we expect
/// </summary>
void DefaultObserverSetup()
{
foreach (var gameStateObs in FindObjectsOfType<LocalGameStateObserver>())
{
if (!gameStateObs.observeOnStart)
continue;
if (!m_GameStateObservers.Contains(gameStateObs))
m_GameStateObservers.Add(gameStateObs);
}
foreach (var localLobby in FindObjectsOfType<LocalLobbyObserver>())
{
if (!localLobby.observeOnStart)
continue;
if (!m_LocalLobbyObservers.Contains(localLobby))
m_LocalLobbyObservers.Add(localLobby);
}
foreach (var lobbyUserObs in FindObjectsOfType<LobbyUserObserver>())
{
if (!lobbyUserObs.observeOnStart)
continue;
if (!m_LocalUserObservers.Contains(lobbyUserObs))
m_LocalUserObservers.Add(lobbyUserObs);
}
foreach (var lobbyServiceObs in FindObjectsOfType<LobbyServiceDataObserver>())
{
if (!lobbyServiceObs.observeOnStart)
continue;
if (!m_LobbyServiceObservers.Contains(lobbyServiceObs))
m_LobbyServiceObservers.Add(lobbyServiceObs);
}
if (m_GameStateObservers.Count < 4)
Debug.LogWarning($"Scene has less than the default expected Game State Observers, ensure all the observers in the scene that need to watch the gameState are registered in the LocalGameStateObservers List.");
if (m_LocalLobbyObservers.Count < 8)
Debug.LogWarning($"Scene has less than the default expected Local Lobby Observers, ensure all the observers in the scene that need to watch the Local Lobby are registered in the LocalLobbyObservers List.");
if (m_LocalUserObservers.Count < 3)
Debug.LogWarning($"Scene has less than the default expected Local User Observers, ensure all the observers in the scene that need to watch the gameState are registered in the LocalUserObservers List.");
if (m_LobbyServiceObservers.Count < 2)
Debug.LogWarning($"Scene has less than the default expected Lobby Service Observers, ensure all the observers in the scene that need to watch the lobby service state are registered in the LobbyServiceObservers List.");
}
void BeginObservers()
{
foreach (var gameStateObs in m_GameStateObservers)

m_relaySetup = gameObject.AddComponent<RelayUtpSetupHost>();
else
m_relaySetup = gameObject.AddComponent<RelayUtpSetupClient>();
OnReceiveMessage(MessageType.LobbyUserStatus, UserStatus.Connecting);
m_relaySetup.BeginRelayJoin(m_localLobby, m_localUser, OnRelayConnected);
}

return;
}
m_relayClient = client;
OnReceiveMessage(MessageType.LobbyUserStatus, UserStatus.Lobby);
}
IEnumerator RetryRelayConnection()

{
SetGameState(GameState.JoinMenu);
}
// Only start the countdown once.
// We want to do all the Relay Allocation calls in quick succession, as waiting too long
// (10s) will cause the Relay server to get cleaned up by the service
m_localLobby.CountDownTime = m_localLobby.TargetEndTime.Subtract(DateTime.Now).Seconds;
m_localLobby.CountDownTime = 4;
/// This is currently a countdown to Connection, once we have our transport integrated, this will be a countdown to Game Start
/// The CountdownUI will pick up on changes to the lobby's countdown timer. This can be interrupted if the lobby leaves the countdown state (via a CancelCountdown message).
m_readyCheck.EndCheckingForReady();
yield return new WaitForSeconds(0.2f);
yield return null;
m_localLobby.CountDownTime = m_localLobby.TargetEndTime.Subtract(DateTime.Now).Seconds;
m_localLobby.CountDownTime -= Time.deltaTime;
m_localUser.UserStatus = UserStatus.InGame;
m_localLobby.State = LobbyState.InGame;
// TODO TRANSPORT: Move Relay Join to Pre-Countdown, and do connection and health checks before counting down for the game start.
//RelayInterface.JoinAsync(m_localLobby.RelayCode, OnJoinedRelay);
}
void ToLobby() // TODO: What to make of this?
{
m_localLobby.State = LobbyState.Lobby;
m_localLobby.CountDownTime = 0;
SetUserLobbyState();
if (m_relayClient is RelayUtpHost)
(m_relayClient as RelayUtpHost).SendInGameState();
m_localUser.UserStatus = UserStatus.Lobby;
if (m_localUser.IsHost)
m_readyCheck.BeginCheckingForReady();
OnReceiveMessage(MessageType.LobbyUserStatus, UserStatus.Lobby);
}
void ResetLocalLobby()

m_localLobby.RelayServer = null;
m_readyCheck.EndCheckingForReady();
}
void OnDestroy()

14
Assets/Scripts/Entities/LocalLobby.cs


}
}
DateTime m_TargetEndTime;
public DateTime TargetEndTime
{
get => m_TargetEndTime;
set
{
m_TargetEndTime = value;
OnChanged(this);
}
}
ServerAddress m_relayServer;
public ServerAddress RelayServer

/// -1 Count means you need all Lobbyusers
/// </summary>
/// <returns>True if enough players are of the input status.</returns>
public bool PlayersOfState(UserStatus status, int playersCount = -1)
public bool PlayersOfState(UserStatus status, int playersCount = -1) // TODO: Remove test-only API.
{
var statePlayers = m_LobbyUsers.Values.Count(user => user.UserStatus == status);

8
Assets/Scripts/Infrastructure/Messenger.cs


PlayerJoinedLobby = 5,
PlayerLeftLobby = 6,
ChangeGameState = 7,
ChangeLobbyUserState = 8,
LobbyUserStatus = 8,
ToLobby = 12,
Client_EndReadyCountdownAt = 13,
EndGame = 12,
StartCountdown = 13,
CancelCountdown = 14,
ConfirmInGameState = 15,
}
/// <summary>

6
Assets/Scripts/Infrastructure/ObserverBehaviour.cs


public abstract class ObserverBehaviour<T> : MonoBehaviour where T : Observed<T>
{
public T observed { get; set; }
/// <summary>
/// Option to allow certain observers to not be registered by the GameStateManager automatically.
/// </summary>
public bool observeOnStart = true;
protected virtual void UpdateObserver(T obs)
{

19
Assets/Scripts/Lobby/LobbyContentHeartbeat.cs


var prevState = m_localLobby.State;
lobby.ToLocalLobby.Convert(lobbyRemote, m_localLobby);
m_shouldPushData = prevShouldPush;
CheckForAllPlayersReady();
if (prevState != LobbyState.Lobby && m_localLobby.State == LobbyState.Lobby)
Locator.Get.Messenger.OnReceiveMessage(MessageType.ToLobby, null);
}
void CheckForAllPlayersReady()
{
bool areAllPlayersReady = m_localLobby.AllPlayersReadyTime != null;
if (areAllPlayersReady)
{
long targetTimeTicks = m_localLobby.AllPlayersReadyTime.Value;
DateTime targetTime = new DateTime(targetTimeTicks);
if (targetTime.Subtract(DateTime.Now).Seconds < 0)
return;
Locator.Get.Messenger.OnReceiveMessage(MessageType.Client_EndReadyCountdownAt, targetTime); // Note that this could be called multiple times.
}
}
}

2
Assets/Scripts/Lobby/ToLocalLobby.cs


incomingData.IsHost = lobby.HostId.Equals(player.Id);
incomingData.DisplayName = player.Data?.ContainsKey("DisplayName") == true ? player.Data["DisplayName"].Value : default;
incomingData.Emote = player.Data?.ContainsKey("Emote") == true ? (EmoteType)int.Parse(player.Data["Emote"].Value) : default;
incomingData.UserStatus = player.Data?.ContainsKey("UserStatus") == true ? (UserStatus)int.Parse(player.Data["UserStatus"].Value) : default;
incomingData.UserStatus = player.Data?.ContainsKey("UserStatus") == true ? (UserStatus)int.Parse(player.Data["UserStatus"].Value) : UserStatus.Connecting;
incomingData.ID = player.Id;
lobbyUsers.Add(incomingData.ID, incomingData);
}

22
Assets/Scripts/Relay/RelayUtpClient.cs


protected NetworkDriver m_networkDriver;
protected List<NetworkConnection> m_connections; // For clients, this has just one member, but for hosts it will have more.
private bool m_hasSentInitialMessage = false;
protected bool m_hasSentInitialMessage = false;
public void Initialize(NetworkDriver networkDriver, List<NetworkConnection> connections, LobbyUser localUser, LocalLobby localLobby)
public virtual void Initialize(NetworkDriver networkDriver, List<NetworkConnection> connections, LobbyUser localUser, LocalLobby localLobby)
{
m_localUser = localUser;
m_localLobby = localLobby;

Locator.Get.UpdateSlow.Subscribe(UpdateSlow);
if (this is RelayUtpHost) // The host will be alone in the lobby at first, so they need not send any messages right away.
m_hasSentInitialMessage = true;
public void OnDestroy()
protected virtual void Uninitialize()
}
public void OnDestroy()
{
Uninitialize();
}
private void OnLocalChange(LobbyUser localUser)

UserStatus status = (UserStatus)strm.ReadByte();
m_localLobby.LobbyUsers[id].UserStatus = status;
}
else if (msgType == MsgType.StartCountdown)
Locator.Get.Messenger.OnReceiveMessage(MessageType.StartCountdown, null);
else if (msgType == MsgType.CancelCountdown)
Locator.Get.Messenger.OnReceiveMessage(MessageType.CancelCountdown, null);
else if (msgType == MsgType.ConfirmInGame)
Locator.Get.Messenger.OnReceiveMessage(MessageType.ConfirmInGameState, null);
else if (msgType == MsgType.EndInGame)
Locator.Get.Messenger.OnReceiveMessage(MessageType.EndGame, null);
ProcessNetworkEventDataAdditional(conn, strm, msgType, id);
}
}

68
Assets/Scripts/Relay/RelayUtpHost.cs


using Unity.Networking.Transport;
using System.Collections.Generic;
using Unity.Networking.Transport;
using MsgType = LobbyRelaySample.Relay.RelayUtpSetup.MsgType;
namespace LobbyRelaySample.Relay

/// from clients to all other clients, since they don't connect to each other.
/// </summary>
public class RelayUtpHost : RelayUtpClient
public class RelayUtpHost : RelayUtpClient, IReceiveMessages
public override void Initialize(NetworkDriver networkDriver, List<NetworkConnection> connections, LobbyUser localUser, LocalLobby localLobby)
{
base.Initialize(networkDriver, connections, localUser, localLobby);
m_hasSentInitialMessage = true; // The host will be alone in the lobby at first, so they need not send any messages right away.
Locator.Get.Messenger.Subscribe(this);
}
protected override void Uninitialize()
{
base.Uninitialize();
Locator.Get.Messenger.Unsubscribe(this);
}
protected override void OnUpdate()
{
base.OnUpdate();

protected override void ProcessNetworkEventDataAdditional(NetworkConnection conn, DataStreamReader strm, MsgType msgType, string id)
{
// Note that the strm contents might have already been consumed, depending on the msgType.
// Forward messages from clients to other clients.
if (msgType == MsgType.PlayerName)
{
string name = m_localLobby.LobbyUsers[id].DisplayName;

}
}
// Note that the strm contents might have already been consumed, depending on the msgType.
// If a client has changed state, check if this changes whether all players have readied.
CheckIfAllUsersReady();
}
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.LobbyUserStatus)
CheckIfAllUsersReady();
else if (type == MessageType.EndGame) // This assumes that only the host will have the End Game button available; otherwise, clients need to be able to send this message, too.
// TODO: Check if all players have readied.
foreach (NetworkConnection connection in m_connections)
WriteByte(m_networkDriver, connection, m_localUser.ID, MsgType.EndInGame, 0);
}
private void CheckIfAllUsersReady()
{
bool haveAllReadied = true;
foreach (var user in m_localLobby.LobbyUsers)
{
if (user.Value.UserStatus != UserStatus.Ready)
{ haveAllReadied = false;
break;
}
}
if (haveAllReadied && m_localLobby.State == LobbyState.Lobby) // Need to notify both this client and all others that all players have readied.
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.StartCountdown, null);
foreach (NetworkConnection connection in m_connections)
WriteByte(m_networkDriver, connection, m_localUser.ID, MsgType.StartCountdown, 0);
}
else if (!haveAllReadied && m_localLobby.State == LobbyState.CountDown) // Someone cancelled during the countdown, so abort the countdown.
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.CancelCountdown, null);
foreach (NetworkConnection connection in m_connections)
WriteByte(m_networkDriver, connection, m_localUser.ID, MsgType.CancelCountdown, 0);
}
}
/// <summary>
/// In an actual game, after the countdown, there would be some step here where the host and all clients sync up on game state, load assets, etc.
/// Here, we will instead just signal an "in game" state that can be ended by the host.
/// </summary>
public void SendInGameState()
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.ConfirmInGameState, null);
foreach (NetworkConnection connection in m_connections)
WriteByte(m_networkDriver, connection, m_localUser.ID, MsgType.ConfirmInGame, 0);
}
/// <summary>

2
Assets/Scripts/Relay/RelayUtpSetup.cs


protected LobbyUser m_localUser;
protected Action<bool, RelayUtpClient> m_onJoinComplete;
public enum MsgType { NewPlayer = 0, Ping = 1, ReadyState = 2, PlayerName = 3, Emote = 4 }
public enum MsgType { NewPlayer = 0, Ping = 1, ReadyState = 2, PlayerName = 3, Emote = 4, StartCountdown = 5, CancelCountdown = 6, ConfirmInGame = 7, EndInGame = 8 }
public void BeginRelayJoin(LocalLobby localLobby, LobbyUser localUser, Action<bool, RelayUtpClient> onJoinComplete)
{

12
Assets/Scripts/UI/CountdownUI.cs


{
/// <summary>
/// After all players ready up for the game, this will show the countdown that occurs.
/// This countdown is purely visual, to give clients a moment if they need to un-ready before entering the game;
/// clients will actually wait for a message from the host confirming that they are in the game, instead of assuming the game is ready to go when the countdown ends.
public class CountdownUI : ObserverPanel<LocalLobby>
public class CountdownUI : LocalLobbyObserver
public override void ObservedUpdated(LocalLobby observed)
protected override void UpdateObserver(LocalLobby obs)
base.UpdateObserver(obs);
return;
m_CountDownText.SetText($"Starting in: {observed.CountDownTime}");
m_CountDownText.SetText("Waiting for all players...");
else
m_CountDownText.SetText($"Starting in: {observed.CountDownTime:0}");
}
}
}

2
Assets/Scripts/UI/EndGameButtonUI.cs


{
public void EndGame()
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.ToLobby, null);
Locator.Get.Messenger.OnReceiveMessage(MessageType.EndGame, null);
}
}
}

2
Assets/Scripts/UI/InLobbyUserUI.cs


case UserStatus.Ready:
return "<color=#009E73>Ready</color>"; // Light Mint
case UserStatus.Connecting:
return "<color=#F0E442>Connecting</color>"; // Bright Yellow
return "<color=#F0E442>Connecting...</color>"; // Bright Yellow
case UserStatus.InGame:
return "<color=#005500>In Game</color>"; //Orange
default:

2
Assets/Scripts/UI/ReadyCheckUI.cs


}
private void ChangeState(UserStatus status)
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.ChangeLobbyUserState, status);
Locator.Get.Messenger.OnReceiveMessage(MessageType.LobbyUserStatus, status);
}
}
}

273
Assets/Prefabs/UI/CountDownUI.prefab


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5694388898566309151
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2473738857440996537}
- component: {fileID: 9125082141416656856}
- component: {fileID: 288221731430065532}
- component: {fileID: 1604604243888226905}
- component: {fileID: 1102405501498744344}
- component: {fileID: 3702758058023689559}
m_Layer: 5
m_Name: CountDownUI
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2473738857440996537
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
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: 2508362878409625140}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -77.436}
m_SizeDelta: {x: -50, y: -404.7342}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &9125082141416656856
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
m_CullTransparentMesh: 1
--- !u!114 &288221731430065532
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5b3b588e7ae40ec4ca35fdb9404513ab, type: 3}
m_Name:
m_EditorClassIdentifier:
m_onVisibilityChange:
m_PersistentCalls:
m_Calls: []
showing: 0
m_CountDownText: {fileID: 6871324529924300226}
--- !u!114 &1604604243888226905
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f38cf340acfcd4c64a6968b7386ad570, type: 3}
m_Name:
m_EditorClassIdentifier:
m_onVisibilityChange:
m_PersistentCalls:
m_Calls: []
showing: 0
m_ShowThisWhen: 2
--- !u!114 &1102405501498744344
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 70dfc2fde0a9ef04eaff29a138f0bf45, type: 3}
m_Name:
m_EditorClassIdentifier:
OnObservedUpdated:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 288221731430065532}
m_TargetAssemblyTypeName: CountdownUI, LobbyRooms
m_MethodName: ObservedUpdated
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_Target: {fileID: 1604604243888226905}
m_TargetAssemblyTypeName: LobbyRooms.UI.LobbyStateVisibilityUI, LobbyRooms
m_MethodName: ObservedUpdated
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
observeOnStart: 0
--- !u!225 &3702758058023689559
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5694388898566309151}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!1 &6120000553027287259
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2508362878409625140}
- component: {fileID: 3642688559417843241}
- component: {fileID: 6871324529924300226}
m_Layer: 5
m_Name: CountdownText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2508362878409625140
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6120000553027287259}
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: 2473738857440996537}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3642688559417843241
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6120000553027287259}
m_CullTransparentMesh: 1
--- !u!114 &6871324529924300226
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6120000553027287259}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: 'Starting in:'
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 21
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 18
m_fontSizeMax: 21
m_fontStyle: 0
m_HorizontalAlignment: 1
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 5, y: 5, z: 5, w: 5}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}

7
Assets/Prefabs/UI/CountDownUI.prefab.meta


fileFormatVersion: 2
guid: f90e4035352c7ce40b68e50109a9bb4f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

63
Assets/Scripts/Lobby/ReadyCheck.cs


using System;
using System.Collections.Generic;
using System.Linq;
namespace LobbyRelaySample
{
/// <summary>
/// On the host, this will watch for all players to ready, and once they have, it will prepare for a synchronized countdown.
/// </summary>
public class ReadyCheck : IDisposable
{
float m_ReadyTime = 5;
public ReadyCheck(float readyTime = 5)
{
m_ReadyTime = readyTime;
}
public void BeginCheckingForReady()
{
Locator.Get.UpdateSlow.Subscribe(OnUpdate);
}
public void EndCheckingForReady()
{
Locator.Get.UpdateSlow.Unsubscribe(OnUpdate);
}
/// <summary>
/// Checks the lobby to see if we have all Readied up. If so, send out a message with the target time at which to end a countdown.
/// </summary>
void OnUpdate(float dt)
{
var lobby = LobbyAsyncRequests.Instance.CurrentLobby;
if (lobby == null || lobby.Players.Count == 0)
return;
int readyCount = lobby.Players.Count((p) =>
{
if (p.Data?.ContainsKey("UserStatus") != true) // Needs to be "!= true" to handle null properly.
return false;
UserStatus status;
if (Enum.TryParse(p.Data["UserStatus"].Value, out status))
return status == UserStatus.Ready;
return false;
});
if (readyCount == lobby.Players.Count)
{
Dictionary<string, string> data = new Dictionary<string, string>();
DateTime targetTime = DateTime.Now.AddSeconds(m_ReadyTime);
data.Add("AllPlayersReady", targetTime.Ticks.ToString());
LobbyAsyncRequests.Instance.UpdateLobbyDataAsync(data, null);
EndCheckingForReady();
}
}
public void Dispose()
{
EndCheckingForReady();
}
}
}

11
Assets/Scripts/Lobby/ReadyCheck.cs.meta


fileFormatVersion: 2
guid: c16ed59d99a3d22468478da00327e666
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存