浏览代码

Merge from NGO cleanup branch

/main/staging
nathaniel.buck@unity3d.com 3 年前
当前提交
684cd853
共有 39 个文件被更改,包括 4138 次插入1161 次删除
  1. 8
      Assets/Art/Glyph/Symbols.png.meta
  2. 36
      Assets/Prefabs/UI/UserCardPanel.prefab
  3. 999
      Assets/Prefabs/NGO/SymbolObject.prefab
  4. 1
      Assets/Prefabs/NGO/SymbolContainer.prefab
  5. 222
      Assets/Prefabs/NGO/PlayerCursor.prefab
  6. 945
      Assets/Prefabs/NGO/InGameLogic.prefab
  7. 8
      Assets/Scripts/Game/LocalLobby.cs
  8. 4
      Assets/Scripts/Infrastructure/Messenger.cs
  9. 1
      Assets/Scripts/Lobby/LobbyContentHeartbeat.cs
  10. 5
      Assets/Scripts/Lobby/ToLocalLobby.cs
  11. 89
      Assets/Scripts/Netcode/InGameRunner.cs
  12. 31
      Assets/Scripts/Netcode/PlayerCursor.cs
  13. 34
      Assets/Scripts/Netcode/Scorer.cs
  14. 100
      Assets/Scripts/Netcode/SequenceSelector.cs
  15. 12
      Assets/Scripts/Netcode/SetupInGame.cs
  16. 5
      Assets/Scripts/Netcode/SymbolContainer.cs
  17. 14
      Assets/Scripts/Netcode/SymbolObject.cs
  18. 3
      Assets/Scripts/Relay/RelayUtpHost.cs
  19. 8
      Packages/manifest.json
  20. 26
      Packages/packages-lock.json
  21. 6
      ProjectSettings/Packages/com.unity.services.vivox/Settings.json
  22. 1001
      Assets/Prefabs/NGO/IntroAnimation.anim
  23. 8
      Assets/Prefabs/NGO/IntroAnimation.anim.meta
  24. 213
      Assets/Prefabs/NGO/IntroOutroAnimator.controller
  25. 8
      Assets/Prefabs/NGO/IntroOutroAnimator.controller.meta
  26. 231
      Assets/Prefabs/NGO/OutroAnimation.anim
  27. 8
      Assets/Prefabs/NGO/OutroAnimation.anim.meta
  28. 40
      Assets/Scripts/Netcode/IntroOutroRunner.cs
  29. 11
      Assets/Scripts/Netcode/IntroOutroRunner.cs.meta
  30. 123
      Assets/Scripts/Netcode/NetworkedDataStore.cs
  31. 11
      Assets/Scripts/Netcode/NetworkedDataStore.cs.meta
  32. 24
      Assets/Scripts/Netcode/PlayerData.cs
  33. 11
      Assets/Scripts/Netcode/PlayerData.cs.meta
  34. 34
      Assets/Scripts/Netcode/ResultsUserUI.cs
  35. 11
      Assets/Scripts/Netcode/ResultsUserUI.cs.meta
  36. 1001
      Assets/Prefabs/Runes/icon_bg.prefab
  37. 7
      Assets/Prefabs/Runes/icon_bg.prefab.meta
  38. 0
      /Assets/Prefabs/NGO
  39. 0
      /Assets/Prefabs/NGO.meta

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

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>();

4
Assets/Scripts/Infrastructure/Messenger.cs


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

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()
{

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/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:

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

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

正在加载...
取消
保存