浏览代码

Merge from staging. This breaks behavior for this fix, will investigate.

/main/staging/ready_when_player_leaves
nathaniel.buck@unity3d.com 3 年前
当前提交
8816a3db
共有 55 个文件被更改,包括 5300 次插入2243 次删除
  1. 8
      Assets/Art/Glyph/Symbols.png.meta
  2. 98
      Assets/Prefabs/UI/JoinCreateCanvas.prefab
  3. 20
      Assets/Prefabs/UI/RenamePopup.prefab
  4. 36
      Assets/Prefabs/UI/UserCardPanel.prefab
  5. 999
      Assets/Prefabs/NGO/SymbolObject.prefab
  6. 1
      Assets/Prefabs/NGO/SymbolContainer.prefab
  7. 222
      Assets/Prefabs/NGO/PlayerCursor.prefab
  8. 945
      Assets/Prefabs/NGO/InGameLogic.prefab
  9. 8
      Assets/Scripts/Game/LocalLobby.cs
  10. 8
      Assets/Scripts/Infrastructure/AsyncRequest.cs
  11. 4
      Assets/Scripts/Infrastructure/Messenger.cs
  12. 4
      Assets/Scripts/Lobby/LobbyAPIInterface.cs
  13. 17
      Assets/Scripts/Lobby/LobbyAsyncRequests.cs
  14. 1
      Assets/Scripts/Lobby/LobbyContentHeartbeat.cs
  15. 5
      Assets/Scripts/Lobby/ToLocalLobby.cs
  16. 89
      Assets/Scripts/Netcode/InGameRunner.cs
  17. 31
      Assets/Scripts/Netcode/PlayerCursor.cs
  18. 34
      Assets/Scripts/Netcode/Scorer.cs
  19. 100
      Assets/Scripts/Netcode/SequenceSelector.cs
  20. 12
      Assets/Scripts/Netcode/SetupInGame.cs
  21. 5
      Assets/Scripts/Netcode/SymbolContainer.cs
  22. 14
      Assets/Scripts/Netcode/SymbolObject.cs
  23. 3
      Assets/Scripts/Relay/RelayUtpHost.cs
  24. 4
      Assets/Scripts/Tests/PlayMode/LobbyRoundtripTests.cs
  25. 18
      Assets/Scripts/UI/CreateMenuUI.cs
  26. 36
      Assets/Scripts/UI/JoinCreateLobbyUI.cs
  27. 19
      Assets/Scripts/UI/JoinMenuUI.cs
  28. 2
      Assets/Scripts/UI/UserNameUI.cs
  29. 16
      Assets/Scripts/Vivox/VivoxUserHandler.cs
  30. 8
      Packages/manifest.json
  31. 26
      Packages/packages-lock.json
  32. 6
      ProjectSettings/Packages/com.unity.services.vivox/Settings.json
  33. 1001
      Assets/Prefabs/UI/UserInteractionPanel.prefab
  34. 1001
      Assets/Prefabs/NGO/IntroAnimation.anim
  35. 8
      Assets/Prefabs/NGO/IntroAnimation.anim.meta
  36. 213
      Assets/Prefabs/NGO/IntroOutroAnimator.controller
  37. 8
      Assets/Prefabs/NGO/IntroOutroAnimator.controller.meta
  38. 231
      Assets/Prefabs/NGO/OutroAnimation.anim
  39. 8
      Assets/Prefabs/NGO/OutroAnimation.anim.meta
  40. 40
      Assets/Scripts/Netcode/IntroOutroRunner.cs
  41. 11
      Assets/Scripts/Netcode/IntroOutroRunner.cs.meta
  42. 123
      Assets/Scripts/Netcode/NetworkedDataStore.cs
  43. 11
      Assets/Scripts/Netcode/NetworkedDataStore.cs.meta
  44. 24
      Assets/Scripts/Netcode/PlayerData.cs
  45. 11
      Assets/Scripts/Netcode/PlayerData.cs.meta
  46. 34
      Assets/Scripts/Netcode/ResultsUserUI.cs
  47. 11
      Assets/Scripts/Netcode/ResultsUserUI.cs.meta
  48. 1001
      Assets/Prefabs/Runes/icon_bg.prefab
  49. 7
      Assets/Prefabs/Runes/icon_bg.prefab.meta
  50. 1001
      Assets/Prefabs/UI/PlayerInteractionPanel.prefab
  51. 0
      /Assets/Prefabs/UI/UserInteractionPanel.prefab.meta
  52. 0
      /Assets/Prefabs/NGO
  53. 0
      /Assets/Prefabs/NGO.meta
  54. 0
      /Assets/Scripts/UI/UserNameUI.cs.meta
  55. 0
      /Assets/Scripts/UI/UserNameUI.cs

8
Assets/Art/Glyph/Symbols.png.meta


second: 14_moon
- first:
213: -431797579490579562
second: 15_god
second: 15_good
second: 16_devil
second: 16_evil
- first:
213: -2657090017763772448
second: 17_elemental

edges: []
weights: []
- serializedVersion: 2
name: 15_god
name: 15_good
rect:
serializedVersion: 2
x: 0

edges: []
weights: []
- serializedVersion: 2
name: 16_devil
name: 16_evil
rect:
serializedVersion: 2
x: 588

98
Assets/Prefabs/UI/JoinCreateCanvas.prefab


m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 1034500561768382320}
m_TargetAssemblyTypeName: LobbyRooms.UI.UIPanelBase, LobbyRooms
m_MethodName: Show
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 1
m_CallState: 2
- m_Target: {fileID: 5643181761482593758}
m_TargetAssemblyTypeName: LobbyRooms.UI.UIPanelBase, LobbyRooms
m_MethodName: Hide
- m_Target: {fileID: 4578721078997909056}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.JoinCreateLobbyUI, LobbyRelaySample
m_MethodName: SetCreateTab
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}

m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 29.1
m_fontSize: 40
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 1

m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 1034500561768382320}
m_TargetAssemblyTypeName: LobbyRooms.UI.UIPanelBase, LobbyRooms
m_MethodName: Hide
- m_Target: {fileID: 4578721078997909056}
m_TargetAssemblyTypeName: LobbyRelaySample.UI.JoinCreateLobbyUI, LobbyRelaySample
m_MethodName: SetJoinTab
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}

m_StringArgument:
m_BoolArgument: 1
m_CallState: 2
- m_Target: {fileID: 5643181761482593758}
m_TargetAssemblyTypeName: LobbyRooms.UI.UIPanelBase, LobbyRooms
m_MethodName: Show
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 1
m_BoolArgument: 0
m_CallState: 2
--- !u!114 &201442509941519423
MonoBehaviour:

m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 29.1
m_fontSize: 40
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 1

- component: {fileID: 5836614391142406753}
- component: {fileID: 5836614391142406752}
- component: {fileID: 4578721078997909056}
- component: {fileID: 6102798993520257211}
- component: {fileID: 6102798993520257211}
m_Layer: 5
m_Name: JoinCreateCanvas
m_TagString: Untagged

m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 1
m_PresetInfoIsWorld: 0
--- !u!114 &5836614391142406752
MonoBehaviour:
m_ObjectHideFlags: 0

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!225 &6102798993520257211
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5836614391142406755}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
m_CurrentTab: 0
--- !u!114 &1512606419251751951
MonoBehaviour:
m_ObjectHideFlags: 0

m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!225 &6102798993520257211
CanvasGroup:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5836614391142406755}
m_Enabled: 1
m_Alpha: 1
m_Interactable: 1
m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0
--- !u!1 &7348548600648247480
GameObject:
m_ObjectHideFlags: 0

value: 0
objectReference: {fileID: 0}
- target: {fileID: 6473743066396215718, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
propertyPath: m_JoinCreateLobbyUI
value:
objectReference: {fileID: 4578721078997909056}
- target: {fileID: 6473743066396215718, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.size
value: 1
objectReference: {fileID: 0}

propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7501121940441885946, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
propertyPath: m_fontSize
value: 21.3
objectReference: {fileID: 0}
- target: {fileID: 8319084566339912016, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
propertyPath: m_AnchorMax.y
value: 0

m_CorrespondingSourceObject: {fileID: 7255335463425698201, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
m_PrefabInstance: {fileID: 6308438907748136662}
m_PrefabAsset: {fileID: 0}
--- !u!114 &1034500561768382320 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 6473743066396215718, guid: 328b912adedf1bc41a44f60a12723cc0, type: 3}
m_PrefabInstance: {fileID: 6308438907748136662}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8bea15db614f57749bb2bac5ae7811fa, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &6492536299820417403
PrefabInstance:
m_ObjectHideFlags: 0

propertyPath: m_JoinCodeField
value:
objectReference: {fileID: 2465479314273514634}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_JoinCreateLobbyUI
value:
objectReference: {fileID: 4578721078997909056}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.size
value: 2
objectReference: {fileID: 0}
- target: {fileID: 1462126939442648229, guid: c308ffc2a02e5ab4bbe70a8b2e8108c6, type: 3}
propertyPath: m_onVisibilityChange.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
value: 0

20
Assets/Prefabs/UI/RenamePopup.prefab


- component: {fileID: 7751582925205826323}
- component: {fileID: 8901675253147492441}
m_Layer: 5
m_Name: Panel
m_Name: icon_highlights
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0

m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 4299827590990313863}
m_RootOrder: 1
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}

m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: -10}
m_SizeDelta: {x: -200, y: 50}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &8624457953407905708

- component: {fileID: 8314980018121597183}
- component: {fileID: 7056713423232892002}
m_Layer: 5
m_Name: Panel
m_Name: icon_back
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0

m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 4299827590990313863}
m_RootOrder: 2
m_RootOrder: 1
m_SizeDelta: {x: -10, y: -4}
m_SizeDelta: {x: -4, y: -4}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8314980018121597183
CanvasRenderer:

m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 4354914e98ed5184596c36700cb95cd6, type: 3}
m_Sprite: {fileID: 21300000, guid: 36961dea3482e5842938e6c4d5d8570a, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1

m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 557953118367534400}
- {fileID: 3886665443646860209}
- {fileID: 3886665443646860209}
m_Father: {fileID: 1113109783147550039}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: 50
m_MinWidth: 40
m_PreferredWidth: 50
m_PreferredWidth: 40
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1

36
Assets/Prefabs/UI/UserCardPanel.prefab


serializedVersion: 6
m_Component:
- component: {fileID: 5804120253616419419}
- component: {fileID: 2300860716923514497}
- component: {fileID: 77300716038833936}
m_Layer: 5
m_Name: NameArea

m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2300860716923514497
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 48478561380765136}
m_CullTransparentMesh: 1
--- !u!114 &77300716038833936
MonoBehaviour:
m_ObjectHideFlags: 0

serializedVersion: 6
m_Component:
- component: {fileID: 3081577339344251787}
- component: {fileID: 7240929418107909207}
- component: {fileID: 5467963549174563591}
- component: {fileID: 6569968321909521185}
- component: {fileID: 5564390157418853622}

m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 1, y: 0.5}
--- !u!222 &7240929418107909207
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010031715874034773}
m_CullTransparentMesh: 1
--- !u!114 &5467963549174563591
MonoBehaviour:
m_ObjectHideFlags: 0

serializedVersion: 6
m_Component:
- component: {fileID: 5951250847120169819}
- component: {fileID: 478472562358024413}
- component: {fileID: 1918995816743806069}
- component: {fileID: 7750493951695561362}
- component: {fileID: 6299655602247130973}

m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &478472562358024413
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4809966060551735762}
m_CullTransparentMesh: 1
--- !u!114 &1918995816743806069
MonoBehaviour:
m_ObjectHideFlags: 0

serializedVersion: 6
m_Component:
- component: {fileID: 2599817509811505645}
- component: {fileID: 2767003350947099766}
- component: {fileID: 3258164575509591423}
m_Layer: 5
m_Name: HostIconArea

m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 1, y: 0.5}
--- !u!222 &2767003350947099766
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6496917371405060994}
m_CullTransparentMesh: 1
--- !u!114 &3258164575509591423
MonoBehaviour:
m_ObjectHideFlags: 0

999
Assets/Prefabs/NGO/SymbolObject.prefab
文件差异内容过多而无法显示
查看文件

1
Assets/Prefabs/NGO/SymbolContainer.prefab


m_Name:
m_EditorClassIdentifier:
m_rb: {fileID: 6367926983050135602}
m_speed: 2

222
Assets/Prefabs/NGO/PlayerCursor.prefab


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &604286645995213136
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 708127520262250088}
- component: {fileID: 5352723520210415014}
- component: {fileID: 1472899085118295698}
m_Layer: 5
m_Name: NameText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &708127520262250088
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 604286645995213136}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.01, y: 0.01, z: 0.01}
m_Children: []
m_Father: {fileID: 8458688300638924921}
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 &5352723520210415014
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 604286645995213136}
m_CullTransparentMesh: 1
--- !u!114 &1472899085118295698
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 604286645995213136}
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:
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 008daa1b26adf2b4ba0fbd11b7f79b6e, type: 2}
m_sharedMaterial: {fileID: 7878303141229832600, guid: 008daa1b26adf2b4ba0fbd11b7f79b6e, 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: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
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: 0
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: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &3227847727972158006
GameObject:
m_ObjectHideFlags: 0

m_EditorClassIdentifier:
m_renderer: {fileID: 3936431673663208488}
m_onClickParticles: {fileID: 8199063143616850966}
m_nameOutput: {fileID: 1472899085118295698}
--- !u!65 &-1476701697690489341
BoxCollider:
m_ObjectHideFlags: 0

serializedVersion: 2
m_Size: {x: 0.2, y: 0.2, z: 0.2}
m_Center: {x: 0, y: 0, z: 0}
--- !u!1 &4674889942549093605
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8458688300638924921}
- component: {fileID: 5020605847119323726}
- component: {fileID: 407076462024115991}
m_Layer: 5
m_Name: NameCanvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8458688300638924921
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4674889942549093605}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 33.333336, y: 33.333336, z: 33.333336}
m_Children:
- {fileID: 708127520262250088}
m_Father: {fileID: 6055385295167824334}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 16, y: -40}
m_SizeDelta: {x: 1, y: 1}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!223 &5020605847119323726
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4674889942549093605}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_AdditionalShaderChannelsFlag: 25
m_SortingLayerID: 0
m_SortingOrder: 3
m_TargetDisplay: 0
--- !u!114 &407076462024115991
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4674889942549093605}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 1
--- !u!1 &6446591093953186703
GameObject:
m_ObjectHideFlags: 0

m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -0.5}
m_LocalScale: {x: 0.03, y: 0.03, z: 0.03}
m_Children: []
m_Children:
- {fileID: 8458688300638924921}
m_Father: {fileID: 3227847727972158004}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

m_LightmapParameters: {fileID: 0}
m_SortingLayerID: -253801995
m_SortingLayer: 2
m_SortingOrder: 1
m_SortingOrder: 5
m_Sprite: {fileID: 21300000, guid: 9367b4ce9024f5b4090fabc2941d2116, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0

945
Assets/Prefabs/NGO/InGameLogic.prefab
文件差异内容过多而无法显示
查看文件

8
Assets/Scripts/Game/LocalLobby.cs


public LobbyColor Color { get; set; }
public long State_LastEdit { get; set; }
public long Color_LastEdit { get; set; }
public long RelayNGOCode_LastEdit { get; set; }
public LobbyData(LobbyData existing)
{

Color = existing.Color;
State_LastEdit = existing.State_LastEdit;
Color_LastEdit = existing.Color_LastEdit;
RelayNGOCode_LastEdit = existing.RelayNGOCode_LastEdit;
}
public LobbyData(string lobbyCode)

Color = LobbyColor.None;
State_LastEdit = 0;
Color_LastEdit = 0;
RelayNGOCode_LastEdit = 0;
}
}

set
{
m_data.RelayNGOCode = value;
m_data.RelayNGOCode_LastEdit = DateTime.Now.Ticks;
OnChanged(this);
}
}

// If that happens, the edit will be lost, so instead we maintain the time of last edit to detect that case.
var pendingState = data.State;
var pendingColor = data.Color;
var pendingNgoCode = data.RelayNGOCode;
if (m_data.RelayNGOCode_LastEdit > data.RelayNGOCode_LastEdit)
pendingNgoCode = m_data.RelayNGOCode;
m_data.RelayNGOCode = pendingNgoCode;
if (currUsers == null)
m_LobbyUsers = new Dictionary<string, LobbyUser>();

8
Assets/Scripts/Infrastructure/AsyncRequest.cs


catch (Exception e)
{
ParseServiceException(e);
Exception eFull = new Exception($"Call stack before async call:\n{currentTrace}\n", e); // TODO: Are we still missing Relay exceptions after the update?
throw eFull;
UnityEngine.Debug.LogError($"AsyncRequest threw an exception. Call stack before async call:\n{currentTrace}\n"); // Note that we log here instead of creating a new Exception in case of a change in calling context during the async call. E.g. Relay has its own exception handling that would intercept this call stack.
throw;
}
finally
{ onComplete?.Invoke();

catch (Exception e)
{
ParseServiceException(e);
Exception eFull = new Exception($"Call stack before async call:\n{currentTrace}\n", e);
throw eFull;
UnityEngine.Debug.LogError($"AsyncRequest threw an exception. Call stack before async call:\n{currentTrace}\n");
throw;
}
finally
{ onComplete?.Invoke(result);

4
Assets/Scripts/Infrastructure/Messenger.cs


StartCountdown = 200,
CancelCountdown = 201,
CompleteCountdown = 202,
GameBeginning = 203,
MinigameBeginning = 203,
InstructionsShown = 204,
MinigameEnding = 205,
DisplayErrorPopup = 300,
}

4
Assets/Scripts/Lobby/LobbyAPIInterface.cs


AsyncRequestLobby.Instance.DoRequest(task, onComplete);
}
public static void UpdateLobbyAsync(string lobbyId, Dictionary<string, DataObject> data, Action<Lobby> onComplete)
public static void UpdateLobbyAsync(string lobbyId, Dictionary<string, DataObject> data, bool shouldLock, Action<Lobby> onComplete)
UpdateLobbyOptions updateOptions = new UpdateLobbyOptions { Data = data };
UpdateLobbyOptions updateOptions = new UpdateLobbyOptions { Data = data , IsLocked = shouldLock};
var task = Lobbies.Instance.UpdateLobbyAsync(lobbyId, updateOptions);
AsyncRequestLobby.Instance.DoRequest(task, onComplete);
}

17
Assets/Scripts/Lobby/LobbyAsyncRequests.cs


Lobby lobby = m_lastKnownLobby;
Dictionary<string, DataObject> dataCurr = lobby.Data ?? new Dictionary<string, DataObject>();
var shouldLock = false;
foreach (var dataNew in data)
{
// Special case: We want to be able to filter on our color data, so we need to supply an arbitrary index to retrieve later. Uses N# for numerics, instead of S# for strings.

dataCurr[dataNew.Key] = dataObj;
else
dataCurr.Add(dataNew.Key, dataObj);
//Special Use: Get the state of the Local lobby so we can lock it from appearing in queries if it's not in the "Lobby" State
if (dataNew.Key == "State")
{
Enum.TryParse(dataNew.Value, out LobbyState lobbyState);
shouldLock = lobbyState != LobbyState.Lobby;
}
LobbyAPIInterface.UpdateLobbyAsync(lobby.Id, dataCurr, (result) => {
LobbyAPIInterface.UpdateLobbyAsync(lobby.Id, dataCurr, shouldLock, (result) =>
{
if (result != null)
m_lastKnownLobby = result;
onComplete?.Invoke();

}
}
public override void CopyObserved(RateLimitCooldown oldObserved){/* This behavior isn't needed; we're just here for the OnChanged event management. */}
public override void CopyObserved(RateLimitCooldown oldObserved)
{
/* This behavior isn't needed; we're just here for the OnChanged event management. */
}
}
}
}

1
Assets/Scripts/Lobby/LobbyContentHeartbeat.cs


data.Add("Color", ((int)lobby.Color).ToString());
data.Add("State_LastEdit", lobby.Data.State_LastEdit.ToString());
data.Add("Color_LastEdit", lobby.Data.Color_LastEdit.ToString());
data.Add("RelayNGOCode_LastEdit", lobby.Data.RelayNGOCode_LastEdit.ToString());
return data;
}

5
Assets/Scripts/Lobby/ToLocalLobby.cs


RelayNGOCode = lobby.Data?.ContainsKey("RelayNGOCode") == true ? lobby.Data["RelayNGOCode"].Value : null,
State = lobby.Data?.ContainsKey("State") == true ? (LobbyState) int.Parse(lobby.Data["State"].Value) : LobbyState.Lobby,
Color = lobby.Data?.ContainsKey("Color") == true ? (LobbyColor) int.Parse(lobby.Data["Color"].Value) : LobbyColor.None,
State_LastEdit = lobby.Data?.ContainsKey("State_LastEdit") == true ? long.Parse(lobby.Data["State_LastEdit"].Value) : 0,
Color_LastEdit = lobby.Data?.ContainsKey("Color_LastEdit") == true ? long.Parse(lobby.Data["Color_LastEdit"].Value) : 0
State_LastEdit = lobby.Data?.ContainsKey("State_LastEdit") == true ? long.Parse(lobby.Data["State_LastEdit"].Value) : 0,
Color_LastEdit = lobby.Data?.ContainsKey("Color_LastEdit") == true ? long.Parse(lobby.Data["Color_LastEdit"].Value) : 0,
RelayNGOCode_LastEdit = lobby.Data?.ContainsKey("RelayNGOCode_LastEdit") == true ? long.Parse(lobby.Data["RelayNGOCode_LastEdit"].Value) : 0,
};
Dictionary<string, LobbyUser> lobbyUsers = new Dictionary<string, LobbyUser>();

89
Assets/Scripts/Netcode/InGameRunner.cs


private Queue<Vector2> m_pendingSymbolPositions = new Queue<Vector2>();
private float m_symbolSpawnTimer = 0.5f; // Initial time buffer to ensure connectivity before loading objects.
private int m_remainingSymbolCount = 0; // Only used by the host.
private float m_timeout = 10;
private bool m_hasConnected = false;
[SerializeField] private NetworkObject m_playerCursorPrefab = default;
[SerializeField] private NetworkObject m_symbolContainerPrefab = default;
[SerializeField] private NetworkObject m_symbolObjectPrefab = default;
[SerializeField] private SequenceSelector m_sequenceSelector = default;
[SerializeField] private Scorer m_scorer = default;
[SerializeField] private SymbolKillVolume m_killVolume = default;
[SerializeField] private NetworkObject m_playerCursorPrefab = default;
[SerializeField] private NetworkObject m_symbolContainerPrefab = default;
[SerializeField] private NetworkObject m_symbolObjectPrefab = default;
[SerializeField] private SequenceSelector m_sequenceSelector = default;
[SerializeField] private Scorer m_scorer = default;
[SerializeField] private SymbolKillVolume m_killVolume = default;
[SerializeField] private IntroOutroRunner m_introOutroRunner = default;
[SerializeField] private NetworkedDataStore m_dataStore = default;
private ulong m_localId; // This is not necessarily the same as the OwnerClientId, since all clients will see all spawned objects regardless of ownership.
private PlayerData m_localUserData; // This has an ID that's not necessarily the OwnerClientId, since all clients will see all spawned objects regardless of ownership.
private float m_timeout = 10;
public void Initialize(Action onConnectionVerified, int expectedPlayerCount, Action onGameEnd)
public void Initialize(Action onConnectionVerified, int expectedPlayerCount, Action onGameEnd, LobbyUser localUser)
m_localUserData = new PlayerData(localUser.DisplayName, 0);
Locator.Get.Provide(this); // Simplifies access since some networked objects can't easily communicate locally (e.g. the host might call a ClientRpc without that client knowing where the call originated).
}

FinishInitialize();
m_localId = NetworkManager.Singleton.LocalClientId;
VerifyConnection_ServerRpc(m_localId);
m_localUserData = new PlayerData(m_localUserData.name, NetworkManager.Singleton.LocalClientId);
VerifyConnection_ServerRpc(m_localUserData.id);
}
public override void OnNetworkDespawn()

private void ResetPendingSymbolPositions()
{
m_pendingSymbolPositions.Clear();
for (int n = 0; n < SequenceSelector.k_symbolCount; n++)
{
// TEMP we need to do a BSP or some such to mix up the positions.
m_pendingSymbolPositions.Enqueue(new Vector2(-9 + (n % 10) * 2, n / 10 * 3));
}
IList<Vector2> points = m_sequenceSelector.GenerateRandomSpawnPoints(new Rect(-15, 0, 30, 120), 2);
foreach (Vector2 point in points)
m_pendingSymbolPositions.Enqueue(point);
}
/// <summary>

[ClientRpc]
private void VerifyConnection_ClientRpc(ulong clientId)
{
if (clientId == m_localId)
VerifyConnectionConfirm_ServerRpc(m_localId);
if (clientId == m_localUserData.id)
VerifyConnectionConfirm_ServerRpc(m_localUserData);
private void VerifyConnectionConfirm_ServerRpc(ulong clientId)
private void VerifyConnectionConfirm_ServerRpc(PlayerData clientData)
playerCursor.SpawnWithOwnership(clientId);
playerCursor.name += clientId;
playerCursor.SpawnWithOwnership(clientData.id);
playerCursor.name += clientData.name;
m_dataStore.AddPlayer(clientData.id, clientData.name);
VerifyConnectionConfirm_ClientRpc(clientId, areAllPlayersConnected);
VerifyConnectionConfirm_ClientRpc(clientData.id, areAllPlayersConnected);
private void VerifyConnectionConfirm_ClientRpc(ulong clientId, bool shouldStartImmediately)
private void VerifyConnectionConfirm_ClientRpc(ulong clientId, bool canBeginGame)
if (clientId == m_localId)
if (clientId == m_localUserData.id)
{
if (shouldStartImmediately)
m_hasConnected = true;
}
if (canBeginGame && m_hasConnected)
{
m_timeout = -1;
BeginGame();

private void BeginGame()
{
m_canSpawnInGameObjects = true;
Locator.Get.Messenger.OnReceiveMessage(MessageType.GameBeginning, null); // TODO: Might need to delay this a frame to ensure the client finished initializing (since I sometimes hit the "failed to join" message even when joining).
Locator.Get.Messenger.OnReceiveMessage(MessageType.MinigameBeginning, null);
m_introOutroRunner.DoIntro();
}
public void Update()

BeginGame();
}
// TODO: BSP for choosing symbol spawn positions?
// TODO: Remove the timer to test for packet loss.
void CheckIfCanSpawnNewSymbol()
{
if (!m_canSpawnInGameObjects.GetValueOrDefault() || m_remainingSymbolCount >= SequenceSelector.k_symbolCount || !IsHost)

{
if (m_sequenceSelector.ConfirmSymbolCorrect(id, selectedSymbol.symbolIndex.Value))
{
selectedSymbol.OnSelectConfirmed_ClientRpc();
selectedSymbol.Destroy_ServerRpc();
m_scorer.ScoreSuccess(id);
OnSymbolDeactivated();

public void OnSymbolDeactivated()
{
if (--m_remainingSymbolCount <= 0)
EndGame_ServerRpc();
WaitForEndingSequence_ClientRpc();
}
/// <summary>

[ServerRpc]
private void EndGame_ServerRpc()
[ClientRpc]
private void WaitForEndingSequence_ClientRpc()
// TODO: Display results
this.StartCoroutine(EndGame());
m_scorer.OnGameEnd();
m_introOutroRunner.DoOutro(EndGame);
private IEnumerator EndGame()
private void EndGame()
{
if (IsHost)
StartCoroutine(EndGame_ClientsFirst());
}
private IEnumerator EndGame_ClientsFirst()
m_onGameEnd();
SendEndGameSignal();
}
[ClientRpc]

return;
SendEndGameSignal();
}
private void SendEndGameSignal()
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.EndGame, null); // We only send this message if the game completes, since the player remains in the lobby. If the player leaves with the back button, that instead sends them to the menu.
m_onGameEnd();
}

31
Assets/Scripts/Netcode/PlayerCursor.cs


using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

/// Each player's cursor needs to be controlled by them and visible to the other players.
/// </summary>
[RequireComponent(typeof(Collider))]
public class PlayerCursor : NetworkBehaviour
public class PlayerCursor : NetworkBehaviour, IReceiveMessages
[SerializeField] private TMPro.TMP_Text m_nameOutput = default;
private Action<ulong, Action<PlayerData>> m_retrieveName;
public void Awake()
{
Locator.Get.Messenger.Subscribe(this);
}
m_retrieveName = NetworkedDataStore.Instance.GetPlayerData;
m_mainCamera = GameObject.Find("InGameCamera").GetComponent<Camera>();
if (IsHost)
m_currentlyCollidingSymbols = new List<SymbolObject>();

}
}
[ClientRpc]
private void SetName_ClientRpc(PlayerData data)
{
if (!IsOwner)
m_nameOutput.text = data.name;
}
// Don't love having the input here, but it doesn't need to be anywhere else.
private bool IsSelectInputHit()
{

public void Update() // TODO: FixedUpdate?
public void Update()
{
transform.position = m_position.Value;
if (m_mainCamera == null || !IsOwner)

return;
if (m_currentlyCollidingSymbols.Contains(symbol))
m_currentlyCollidingSymbols.Remove(symbol);
}
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.MinigameBeginning)
{
m_retrieveName.Invoke(OwnerClientId, SetName_ClientRpc);
Locator.Get.Messenger.Unsubscribe(this);
}
}
}
}

34
Assets/Scripts/Netcode/Scorer.cs


using System.Collections.Generic;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Events;
// TODO: I'm using host and server interchangeably...
// TODO: I'm using host and server interchangeably...which in part I have to since it's ServerRpc but I think IsHost vs. IsServer yield different results in some places?
/// <summary>
/// Used by the host to actually track scores for all players, and by each client to monitor for updates to their own score.

// TODO: Most of the ints could be bytes?
private Dictionary<ulong, int> m_scoresByClientId = new Dictionary<ulong, int>();
[SerializeField] private NetworkedDataStore m_dataStore = default;
[Tooltip("When the game ends, this will be provided the results in order of rank (1st-place first, and so on).")]
[SerializeField] private UnityEvent<PlayerData> m_onGameEnd = default;
AddClient_ServerRpc(m_localId);
[ServerRpc(RequireOwnership = false)]
private void AddClient_ServerRpc(ulong id)
{
if (!m_scoresByClientId.ContainsKey(id))
m_scoresByClientId.Add(id, 0);
}
// Called on the host.
m_scoresByClientId[id] += 5;
UpdateScoreOutput_ClientRpc(id, m_scoresByClientId[id]);
int newScore = m_dataStore.UpdateScore(id, 1);
UpdateScoreOutput_ClientRpc(id, newScore);
m_scoresByClientId[id] -= 1;
UpdateScoreOutput_ClientRpc(id, m_scoresByClientId[id]);
int newScore = m_dataStore.UpdateScore(id, -1);
UpdateScoreOutput_ClientRpc(id, newScore);
}
[ClientRpc]

m_scoreOutputText.text = score.ToString("00");
}
public void OnGameEnd()
{
m_dataStore.GetAllPlayerData(m_onGameEnd);
}
}
}

100
Assets/Scripts/Netcode/SequenceSelector.cs


using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;
using Random = UnityEngine.Random;
namespace LobbyRelaySample.ngo
{

/// </summary>
public class SequenceSelector : NetworkBehaviour
public class SequenceSelector : NetworkBehaviour, IReceiveMessages
public const int k_symbolCount = 100;
public const int k_symbolCount = 200;
private bool m_canAnimateTargets = false;
private List<int> m_fullSequence = new List<int>(); // This is owned by the host, and each index is assigned as a NetworkVariable to each SymbolObject.
private NetworkList<int> m_targetSequence; // This is owned by the host but needs to be available to all clients, so it's a NetworkedList here.

{
m_targetSequence = new NetworkList<int>();
Locator.Get.Messenger.Subscribe(this);
}
public override void OnDestroy()
{
base.OnDestroy();
Locator.Get.Messenger.Unsubscribe(this);
}
public override void OnNetworkSpawn()

m_targetSequence.Add(symbolsForThisGame[2]);
// Then, ensure that the target sequence is present in order throughout most of the full set of symbols to spawn.
int numTargetSequences = k_symbolCount / 6; // About 1/2 of the 3 symbols will be definitely part of the target sequence.
int numTargetSequences = (int)(k_symbolCount * 2/3f) / 3; // About 2/3 of the symbols will be definitely part of the target sequence.
for (; numTargetSequences >= 0; numTargetSequences--)
{ m_fullSequence.Add(m_targetSequence[2]); // We want a List instead of a Queue or Stack for faster insertion, but we will remove indices backwards so as to not reshift other entries.
m_fullSequence.Add(m_targetSequence[1]);

{
if (NetworkManager.Singleton.LocalClientId == id)
for (int i = 0; i < m_targetSequenceOutput.Length; i++)
m_targetSequenceOutput[i].transform.localScale = Vector3.one * (sequenceIndex == i ? 1 : 0.7f);
m_targetSequenceOutput[i].transform.localScale = Vector3.one * (sequenceIndex == i || !m_canAnimateTargets ? 1 : 0.7f);
}
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.InstructionsShown)
{
m_canAnimateTargets = true;
ScaleTargetUi(m_localId, 0);
}
}
/// <summary>
/// Used for the binary space partition (BSP) algorithm, which makes alternating "cuts" to subdivide rectangles.
/// </summary>
private struct RectCut
{
public Rect rect;
// The spawn region will be much taller than it is wide, so we'll do more horizontal cuts (instead of just alternating between horizontal and vertical).
public int cutIndex;
public bool isVertCut { get { return cutIndex % 3 == 2; } }
public RectCut(Rect rect, int cutIndex) { this.rect = rect; this.cutIndex = cutIndex; }
public RectCut(float xMin, float xMax, float yMin, float yMax, int cutIndex)
{
this.rect = new Rect(xMin, yMin, xMax - xMin, yMax - yMin);
this.cutIndex = cutIndex;
}
}
/// <summary>
/// Selects a randomized series of spawn positions within the provided xy-bounds, or just a simple grid of positions if selection fails.
/// </summary>
/// <param name="bounds">Rectangle of space to subdivide.</param>
/// <param name="extent">The minimum space between points, to ensure that spawned symbol objects won't overlap.</param>
/// <param name="count">How many positions to choose.</param>
/// <returns>Position list in arbitrary order.</returns>
public List<Vector2> GenerateRandomSpawnPoints(Rect bounds, float extent, int count = k_symbolCount)
{
int numTries = 3;
List<Vector2> points = new List<Vector2>();
while (numTries > 0)
{
Queue<RectCut> rects = new Queue<RectCut>();
points.Clear();
rects.Enqueue(new RectCut(bounds, -1)); // Start with an extra horizontal cut since the space is so tall.
// For each rect, subdivide it with an alternating cut, and then enqueue for recursion until enough points are chosen or the rects are all too small.
// This ensures a reasonable distribution of points which won't cause overlaps, though it will not necessarily be uniform.
while (rects.Count + points.Count < count && rects.Count > 0)
{
RectCut currRect = rects.Dequeue();
bool isLargeEnough = (currRect.isVertCut && currRect.rect.width > extent * 2) || (!currRect.isVertCut && currRect.rect.height > extent * 2);
if (!isLargeEnough)
{ points.Add(currRect.rect.center);
continue;
}
float xMin = currRect.rect.xMin, xMax = currRect.rect.xMax, yMin = currRect.rect.yMin, yMax = currRect.rect.yMax;
if (currRect.isVertCut)
{ float cutPosX = Random.Range(xMin + extent, xMax - extent);
rects.Enqueue( new RectCut(xMin, cutPosX, yMin, yMax, currRect.cutIndex + 1) );
rects.Enqueue( new RectCut(cutPosX, xMax, yMin, yMax, currRect.cutIndex + 1) );
}
else
{ float cutPosY = Random.Range(yMin + extent, yMax - extent);
rects.Enqueue( new RectCut(xMin, xMax, yMin, cutPosY, currRect.cutIndex + 1) );
rects.Enqueue( new RectCut(xMin, xMax, cutPosY, yMax, currRect.cutIndex + 1) );
}
}
while (rects.Count > 0)
points.Add(rects.Dequeue().rect.center);
if (points.Count >= count)
return points;
numTries--;
}
Debug.LogError("Failed to generate symbol spawn points. Defaulting to a simple grid of points.");
points.Clear();
int numPerLine = Mathf.CeilToInt(bounds.width / (extent * 1.5f));
for (int n = 0; n < count; n++)
points.Add(new Vector2(Mathf.Lerp(bounds.xMin, bounds.xMax, (n % numPerLine) / (numPerLine - 1f)), n / numPerLine * extent * 1.5f));
return points;
}
}
}

12
Assets/Scripts/Netcode/SetupInGame.cs


private NetworkManager m_networkManager;
private InGameRunner m_inGameRunner;
private bool m_isHost;
private LobbyUser m_localUser;
public void Start()

m_inGameManagerObj = GameObject.Instantiate(m_prefabNetworkManager);
m_networkManager = m_inGameManagerObj.GetComponentInChildren<NetworkManager>();
m_inGameRunner = m_inGameManagerObj.GetComponentInChildren<InGameRunner>();
m_inGameRunner.Initialize(OnConnectionVerified, m_lobby.PlayerCount, OnGameEnd);
m_inGameRunner.Initialize(OnConnectionVerified, m_lobby.PlayerCount, OnGameEnd, m_localUser);
if (m_isHost)
if (m_localUser.IsHost)
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupHost>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartHost(); });
else
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupClient>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartClient(); });

{ m_lobby = lobby; // Most of the time this is redundant, but we need to get multiple members of the lobby to the Relay setup components, so might as well just hold onto the whole thing.
}
public void OnLocalUserChange(LobbyUser user)
{ m_isHost = user.IsHost;
{ m_localUser = user; // Same, regarding redundancy.
}
public void SetRelayServerData(string address, int port, byte[] allocationBytes, byte[] key, byte[] connectionData, byte[] hostConnectionData, bool isSecure)

CreateNetworkManager();
}
else if (type == MessageType.GameBeginning)
else if (type == MessageType.MinigameBeginning)
// TODO: Need to handle both failing to connect and connecting but failing to initialize.
// I.e. cleaning up networked objects *might* be necessary.
OnGameEnd();
}
}

5
Assets/Scripts/Netcode/SymbolContainer.cs


public class SymbolContainer : NetworkBehaviour, IReceiveMessages
{
[SerializeField] private Rigidbody m_rb = default;
[SerializeField] private float m_speed = 1;
private bool m_isConnected = false;
private bool m_hasGameStarted = false;
private void OnGameStarted()

private void BeginMotion()
{
m_rb.velocity = Vector3.down;
m_rb.velocity = Vector3.down * m_speed;
if (type == MessageType.GameBeginning)
if (type == MessageType.InstructionsShown)
{ Locator.Get.Messenger.Unsubscribe(this);
OnGameStarted();
}

14
Assets/Scripts/Netcode/SymbolObject.cs


[SerializeField] private SymbolData m_symbolData;
[SerializeField] private SpriteRenderer m_renderer;
[HideInInspector] public NetworkVariable<int> symbolIndex; // The index into SymbolData, not the index of this object.
private ulong m_localId;
m_localId = NetworkManager.Singleton.LocalClientId;
}
/// <summary>

symbolIndex.OnValueChanged -= OnSymbolIndexSet;
}
/// <summary>
/// The host has confirmed this symbol as a valid selection (this player's cursor collides with it and it's also next in their target sequence), so handle any visual feedback.
/// </summary>
[ClientRpc]
public void OnSelectConfirmed_ClientRpc()
{
// TODO: Visual effects here.
}
[ServerRpc]
public void Destroy_ServerRpc()
{

this.transform.localPosition = Vector3.down * 500;
// TODO: Visually disappear immediately.
this.transform.localPosition += Vector3.forward * 500;
}
}
}

3
Assets/Scripts/Relay/RelayUtpHost.cs


}
/// <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.
/// After the countdown, the host and all clients need to be alerted to sync up on game state, load assets, etc.
/// </summary>
public void SendInGameState()
{

4
Assets/Scripts/Tests/PlayMode/LobbyRoundtripTests.cs


[UnityTest]
public IEnumerator OnCompletesOnFailure()
{
LogAssert.Expect(LogType.Exception, new Regex(".*400 Bad Request.*"));
if (!m_didSigninComplete)
yield return new WaitForSeconds(3);
if (!m_didSigninComplete)

LogAssert.ignoreFailingMessages = true; // Multiple errors will appears for the exception.
LobbyAPIInterface.CreateLobbyAsync("ThisStringIsInvalidHere", "lobby name", 123, false, m_mockUserData, (r) => { didComplete = (r == null); });
float timeout = 5;
while (didComplete == null && timeout > 0)

LogAssert.ignoreFailingMessages = false;
Assert.Greater(timeout, 0, "Timeout check");
Assert.NotNull(didComplete, "Should have called onComplete, even if the async request failed.");
Assert.True(didComplete, "The returned object will be null, so expect to need to handle it.");

18
Assets/Scripts/UI/CreateMenuUI.cs


/// </summary>
public class CreateMenuUI : UIPanelBase
{
private LocalLobby.LobbyData m_ServerRequestData = new LocalLobby.LobbyData{ LobbyName = "New Lobby", MaxPlayerCount = 4 };
public JoinCreateLobbyUI m_JoinCreateLobbyUI;
private LocalLobby.LobbyData m_ServerRequestData = new LocalLobby.LobbyData { LobbyName = "New Lobby", MaxPlayerCount = 4 };
Hide();
m_JoinCreateLobbyUI.m_OnTabChanged.AddListener(OnTabChanged);
void OnTabChanged(JoinCreateTabs tabState)
{
if (tabState == JoinCreateTabs.Create)
{
Show();
}
else
{
Hide();
}
}
public void SetServerName(string serverName)
{
m_ServerRequestData.LobbyName = serverName;

36
Assets/Scripts/UI/JoinCreateLobbyUI.cs


using System;
using UnityEngine;
using UnityEngine.Events;
public enum JoinCreateTabs
{
Join,
Create
}
public UnityEvent<JoinCreateTabs> m_OnTabChanged;
[SerializeField] //Serialized for Visisbility in Editor
JoinCreateTabs m_CurrentTab = JoinCreateTabs.Join;
public JoinCreateTabs CurrentTab
{
get => m_CurrentTab;
set
{
m_CurrentTab = value;
m_OnTabChanged?.Invoke(m_CurrentTab);
}
}
public void SetJoinTab()
{
CurrentTab = JoinCreateTabs.Join;
}
public void SetCreateTab()
{
CurrentTab = JoinCreateTabs.Create;
}
m_OnTabChanged?.Invoke(m_CurrentTab);
Show(false);
}
else

19
Assets/Scripts/UI/JoinMenuUI.cs


[SerializeField]
TMP_InputField m_JoinCodeField;
public JoinCreateLobbyUI m_JoinCreateLobbyUI;
/// <summary>
/// Key: Lobby ID, Value Lobby UI
/// </summary>

/// <summary>Contains some amount of information used to join an existing lobby.</summary>
LocalLobby.LobbyData m_LocalLobbySelected;
public override void Start()
{
base.Start();
m_JoinCreateLobbyUI.m_OnTabChanged.AddListener(OnTabChanged);
}
void OnTabChanged(JoinCreateTabs tabState)
{
if (tabState == JoinCreateTabs.Join)
{
Show();
}
else
{
Hide();
}
}
public void LobbyButtonSelected(LocalLobby lobby)
{

2
Assets/Scripts/UI/UserNameUI.cs


/// <summary>
/// Displays the player's name.
/// </summary>
public class PlayerNameUI : ObserverPanel<LobbyUser>
public class UserNameUI : ObserverPanel<LobbyUser>
{
[SerializeField]
TMP_Text m_TextField;

16
Assets/Scripts/Vivox/VivoxUserHandler.cs


public void OnChannelJoined(IChannelSession channelSession) // Called after a connection is established, which begins once a lobby is joined.
{
//Check if we are muted or not
m_channelSession = channelSession;
m_channelSession.Participants.AfterKeyAdded += OnParticipantAdded;
m_channelSession.Participants.BeforeKeyRemoved += BeforeParticipantRemoved;

if (isThisUser)
{ m_vivoxId = keyEventArg.Key; // Since we couldn't construct the Vivox ID earlier, retrieve it here.
m_lobbyUserVolumeUI.IsLocalPlayer = participant.IsSelf;
m_lobbyUserVolumeUI.EnableVoice(true);
if(!participant.IsMutedForAll)
m_lobbyUserVolumeUI.EnableVoice(false);//Should check if user is muted or not.
else
m_lobbyUserVolumeUI.DisableVoice(false);
}
else
{
if(!participant.LocalMute)
m_lobbyUserVolumeUI.EnableVoice(false);//Should check if user is muted or not.
else
m_lobbyUserVolumeUI.DisableVoice(false);
private void BeforeParticipantRemoved(object sender, KeyEventArg<string> keyEventArg)
{
var source = (VivoxUnity.IReadOnlyDictionary<string, IParticipant>)sender;

8
Packages/manifest.json


"com.unity.ide.rider": "3.0.7",
"com.unity.ide.visualstudio": "2.0.11",
"com.unity.ide.vscode": "1.2.4",
"com.unity.netcode.adapter.utp": "1.0.0-pre.2",
"com.unity.netcode.adapter.utp": "1.0.0-pre.3",
"com.unity.services.core": "1.1.0-pre.10",
"com.unity.services.core": "1.1.0-pre.11",
"com.unity.services.relay": "1.0.1-pre.2",
"com.unity.services.relay": "1.0.1-pre.3",
"com.unity.transport": "1.0.0-pre.5",
"com.unity.transport": "1.0.0-pre.9",
"com.unity.ugui": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",

26
Packages/packages-lock.json


"url": "https://packages.unity.com"
},
"com.unity.collections": {
"version": "1.0.0-pre.6",
"depth": 0,
"version": "1.1.0",
"depth": 1,
"com.unity.test-framework": "1.1.22"
"com.unity.test-framework": "1.1.29"
},
"url": "https://packages.unity.com"
},

"url": "https://packages.unity.com"
},
"com.unity.netcode.adapter.utp": {
"version": "1.0.0-pre.2",
"version": "1.0.0-pre.3",
"com.unity.netcode.gameobjects": "1.0.0-pre.2",
"com.unity.transport": "1.0.0-pre.6"
"com.unity.netcode.gameobjects": "1.0.0-pre.3",
"com.unity.transport": "1.0.0-pre.7"
"version": "1.0.0-pre.2",
"depth": 0,
"version": "1.0.0-pre.3",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.ai": "1.0.0",

"url": "https://packages.unity.com"
},
"com.unity.services.core": {
"version": "1.1.0-pre.10",
"version": "1.1.0-pre.11",
"depth": 0,
"source": "registry",
"dependencies": {

"url": "https://packages.unity.com"
},
"com.unity.services.relay": {
"version": "1.0.1-pre.2",
"version": "1.0.1-pre.3",
"depth": 0,
"source": "registry",
"dependencies": {

"url": "https://packages.unity.com"
},
"com.unity.transport": {
"version": "1.0.0-pre.6",
"depth": 1,
"version": "1.0.0-pre.9",
"depth": 0,
"com.unity.collections": "1.0.0-pre.5",
"com.unity.collections": "1.1.0",
"com.unity.burst": "1.5.5",
"com.unity.mathematics": "1.2.1"
},

6
ProjectSettings/Packages/com.unity.services.vivox/Settings.json


{
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "server",
"value": "{\"m_Value\":\"https://unity.vivox.com/appconfig/0bf04-com_u-76576-test\"}"
"value": "{\"m_Value\":\"https://unity.vivox.com/appconfig/13746-com_u-21128-test\"}"
"value": "{\"m_Value\":\"0bf04-com_u-76576-test\"}"
"value": "{\"m_Value\":\"13746-com_u-21128-test\"}"
"value": "{\"m_Value\":\"jQr72GjGtoB2lpdtK1GmV1BgtOsFUzK6\"}"
"value": "{\"m_Value\":\"FDIlna7382W91CMCoztXRWK12KcxJRZu\"}"
},
{
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",

1001
Assets/Prefabs/UI/UserInteractionPanel.prefab
文件差异内容过多而无法显示
查看文件

1001
Assets/Prefabs/NGO/IntroAnimation.anim
文件差异内容过多而无法显示
查看文件

8
Assets/Prefabs/NGO/IntroAnimation.anim.meta


fileFormatVersion: 2
guid: 3a2b72af2ce1fa542abc8f6966bb93ff
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

213
Assets/Prefabs/NGO/IntroOutroAnimator.controller


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1102 &-4718454066486239908
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: IntroAnimation
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: -2422862649711649101}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 3a2b72af2ce1fa542abc8f6966bb93ff, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1101 &-3457292013045787442
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: DoIntro
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: -4718454066486239908}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 0.75
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1101 &-2422862649711649101
AnimatorStateTransition:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: DoOutro
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 6302186184720228616}
m_Solo: 0
m_Mute: 0
m_IsExit: 0
serializedVersion: 3
m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 0
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1
m_CanTransitionToSelf: 1
--- !u!1102 &-915027616136477805
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Idle
m_Speed: 1
m_CycleOffset: 0
m_Transitions:
- {fileID: -3457292013045787442}
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 0}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: IntroOutroAnimator
serializedVersion: 5
m_AnimatorParameters:
- m_Name: DoIntro
m_Type: 9
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
- m_Name: DoOutro
m_Type: 9
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 6276916818762604846}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1107 &5144759055998950383
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: New Layer
m_ChildStates: []
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 0}
--- !u!1107 &6276916818762604846
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -915027616136477805}
m_Position: {x: 330, y: 120, z: 0}
- serializedVersion: 1
m_State: {fileID: -4718454066486239908}
m_Position: {x: 330, y: 210, z: 0}
- serializedVersion: 1
m_State: {fileID: 6302186184720228616}
m_Position: {x: 330, y: 300, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -915027616136477805}
--- !u!1102 &6302186184720228616
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: OutroAnimation
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 0114c447b277a3647946290240759633, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:

8
Assets/Prefabs/NGO/IntroOutroAnimator.controller.meta


fileFormatVersion: 2
guid: c01005020548c754c81f738e21ae2217
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

231
Assets/Prefabs/NGO/OutroAnimation.anim


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: OutroAnimation
serializedVersion: 6
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 3
value: 1
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_IsActive
path: InfoText/OutroText
classID: 1
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 0.15
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Alpha
path: ScoreAndTargetPanel
classID: 225
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_IsActive
path: InfoText/WaitingText
classID: 1
script: {fileID: 0}
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 2389439745
attribute: 2086281974
script: {fileID: 0}
typeID: 1
customType: 0
isPPtrCurve: 0
- serializedVersion: 2
path: 2885466011
attribute: 1574349066
script: {fileID: 0}
typeID: 225
customType: 0
isPPtrCurve: 0
- serializedVersion: 2
path: 3489324656
attribute: 2086281974
script: {fileID: 0}
typeID: 1
customType: 0
isPPtrCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 6
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 3
value: 1
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_IsActive
path: InfoText/OutroText
classID: 1
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 0.15
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Alpha
path: ScoreAndTargetPanel
classID: 225
script: {fileID: 0}
- curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: Infinity
outSlope: Infinity
tangentMode: 103
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_IsActive
path: InfoText/WaitingText
classID: 1
script: {fileID: 0}
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events:
- time: 6
functionName: OnOutroComplete
data:
objectReferenceParameter: {fileID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0

8
Assets/Prefabs/NGO/OutroAnimation.anim.meta


fileFormatVersion: 2
guid: 0114c447b277a3647946290240759633
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

40
Assets/Scripts/Netcode/IntroOutroRunner.cs


using System;
using UnityEngine;
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Handles any visual tasks for running the NGO minigame's intro and outro.
/// </summary>
public class IntroOutroRunner : MonoBehaviour
{
[SerializeField] private Animator m_animator;
private Action m_onOutroComplete;
public void DoIntro()
{
m_animator.SetTrigger("DoIntro");
}
public void DoOutro(Action onOutroComplete)
{
m_onOutroComplete = onOutroComplete;
m_animator.SetTrigger("DoOutro");
}
/// <summary>
/// Called via an AnimationEvent.
/// </summary>
public void OnIntroComplete()
{
Locator.Get.Messenger.OnReceiveMessage(MessageType.InstructionsShown, null);
}
/// <summary>
/// Called via an AnimationEvent.
/// </summary>
public void OnOutroComplete()
{
m_onOutroComplete?.Invoke();
}
}
}

11
Assets/Scripts/Netcode/IntroOutroRunner.cs.meta


fileFormatVersion: 2
guid: 9f7a308a72bf6ce4a862a246eaed82cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

123
Assets/Scripts/Netcode/NetworkedDataStore.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Netcode;
using UnityEngine.Events;
namespace LobbyRelaySample.ngo
{
/// <summary>
/// A place to store data needed by networked behaviors. Each client has an instance, but the server's instance stores the actual data.
/// </summary>
public class NetworkedDataStore : NetworkBehaviour
{
// Using a singleton here since we need spawned PlayerCursors to be able to find it, but we don't need the flexibility offered by the Locator.
public static NetworkedDataStore Instance;
private Dictionary<ulong, PlayerData> m_playerData = new Dictionary<ulong, PlayerData>();
private ulong m_localId;
// Clients will need to retrieve the host's player data since it isn't synchronized. During that process, they will supply these callbacks
private Action<PlayerData> m_onGetCurrentCallback;
private UnityEvent<PlayerData> m_onEachPlayerCallback;
public void Awake()
{
Instance = this;
}
public override void OnDestroy()
{
base.OnDestroy();
if (Instance == this)
Instance = null;
}
public override void OnNetworkSpawn()
{
m_localId = NetworkManager.Singleton.LocalClientId;
}
public void AddPlayer(ulong id, string name)
{
if (!IsServer)
return;
if (!m_playerData.ContainsKey(id))
m_playerData.Add(id, new PlayerData(name, id, 0));
else
m_playerData[id] = new PlayerData(name, id, 0);
}
/// <returns>The updated score for the player matching the id after adding the delta, or int.MinValue otherwise.</returns>
public int UpdateScore(ulong id, int delta)
{
if (!IsServer)
return int.MinValue;
if (m_playerData.ContainsKey(id))
{
m_playerData[id].score += delta;
return m_playerData[id].score;
}
return int.MinValue;
}
/// <summary>
/// Retrieve the data for all players from 1st to last place, calling onEachPlayer for each.
/// </summary>
public void GetAllPlayerData(UnityEvent<PlayerData> onEachPlayer)
{
m_onEachPlayerCallback = onEachPlayer;
GetAllPlayerData_ServerRpc(m_localId);
}
[ServerRpc(RequireOwnership = false)]
private void GetAllPlayerData_ServerRpc(ulong callerId)
{
var sortedData = m_playerData.Select(kvp => kvp.Value).OrderByDescending(data => data.score);
GetAllPlayerData_ClientRpc(callerId, sortedData.ToArray());
}
[ClientRpc]
private void GetAllPlayerData_ClientRpc(ulong callerId, PlayerData[] sortedData)
{
if (callerId != m_localId)
return;
int rank = 1;
foreach (var data in sortedData)
{
m_onEachPlayerCallback.Invoke(data);
rank++;
}
m_onEachPlayerCallback = null;
}
/// <summary>
/// Retreive the data for one player, passing it to the onGet callback.
/// </summary>
public void GetPlayerData(ulong targetId, Action<PlayerData> onGet)
{
m_onGetCurrentCallback = onGet;
GetPlayerData_ServerRpc(targetId, m_localId);
}
[ServerRpc(RequireOwnership = false)]
private void GetPlayerData_ServerRpc(ulong id, ulong callerId)
{
if (m_playerData.ContainsKey(id))
GetPlayerData_ClientRpc(callerId, m_playerData[id]);
else
GetPlayerData_ClientRpc(callerId, new PlayerData(null, 0));
}
[ClientRpc]
public void GetPlayerData_ClientRpc(ulong callerId, PlayerData data)
{
if (callerId == m_localId)
{ m_onGetCurrentCallback?.Invoke(data);
m_onGetCurrentCallback = null;
}
}
}
}

11
Assets/Scripts/Netcode/NetworkedDataStore.cs.meta


fileFormatVersion: 2
guid: 5a054eb742dd9f748afc05982dc263b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

24
Assets/Scripts/Netcode/PlayerData.cs


using Unity.Netcode;
namespace LobbyRelaySample.ngo
{
/// <summary>
/// An example of a custom type serialized for use in RPC calls. This represents the state of a player as far as NGO is concerned,
/// with relevant fields copied in or modified directly.
/// </summary>
public class PlayerData : INetworkSerializable
{
public string name;
public ulong id;
public int score;
public PlayerData() { } // A default constructor is explicitly required for serialization.
public PlayerData(string name, ulong id, int score = 0) { this.name = name; this.id = id; this.score = score; }
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref name);
serializer.SerializeValue(ref id);
serializer.SerializeValue(ref score);
}
}
}

11
Assets/Scripts/Netcode/PlayerData.cs.meta


fileFormatVersion: 2
guid: 3e81b917b9edfc64f95cebddd2deb7b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

34
Assets/Scripts/Netcode/ResultsUserUI.cs


using UnityEngine;
using Unity.Netcode;
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Displays the results for all players after the NGO minigame.
/// </summary>
public class ResultsUserUI : NetworkBehaviour
{
[Tooltip("The containers for the player data outputs, in order, to be hidden until the game ends.")]
[SerializeField] private CanvasGroup[] m_containers;
[Tooltip("These should be in order of appearance, i.e. the 0th entry is the 1st-place player, and so on.")]
[SerializeField] private TMPro.TMP_Text[] m_playerNameOutputs;
[Tooltip("These should also be in order of appearance.")]
[SerializeField] private TMPro.TMP_Text[] m_playerScoreOutputs;
private int m_index = 0;
public void Start()
{
foreach (var container in m_containers)
container.alpha = 0;
}
// Assigned to an event in the Inspector.
public void ReceiveScoreInOrder(PlayerData data)
{
m_containers[m_index].alpha = 1;
m_playerNameOutputs[m_index].text = data.name;
m_playerScoreOutputs[m_index].text = data.score.ToString("00");
m_index++;
}
}
}

11
Assets/Scripts/Netcode/ResultsUserUI.cs.meta


fileFormatVersion: 2
guid: 3a4ddeb182a27644480e6c47c065924e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

1001
Assets/Prefabs/Runes/icon_bg.prefab
文件差异内容过多而无法显示
查看文件

7
Assets/Prefabs/Runes/icon_bg.prefab.meta


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

1001
Assets/Prefabs/UI/PlayerInteractionPanel.prefab
文件差异内容过多而无法显示
查看文件

/Assets/Prefabs/UI/PlayerInteractionPanel.prefab.meta → /Assets/Prefabs/UI/UserInteractionPanel.prefab.meta

/Assets/Prefabs/InGame → /Assets/Prefabs/NGO

/Assets/Prefabs/InGame.meta → /Assets/Prefabs/NGO.meta

/Assets/Scripts/UI/PlayerNameUI.cs.meta → /Assets/Scripts/UI/UserNameUI.cs.meta

/Assets/Scripts/UI/PlayerNameUI.cs → /Assets/Scripts/UI/UserNameUI.cs

正在加载...
取消
保存