浏览代码

Merge from the NGO minigame cleanup branch. This is partial but stable progress on that front.

/main/staging
nathaniel.buck@unity3d.com 3 年前
当前提交
cf118508
共有 27 个文件被更改,包括 338 次插入270 次删除
  1. 3
      Assets/Prefabs/GameManager.prefab
  2. 181
      Assets/Prefabs/InGame/InGameLogic.prefab
  3. 1
      Assets/Prefabs/InGame/SymbolContainer.prefab
  4. 4
      Assets/Prefabs/InGame/SymbolObject.prefab
  5. 2
      Assets/Scripts/Game/GameManager.cs
  6. 13
      Assets/Scripts/Game/LocalLobby.cs
  7. 6
      Assets/Scripts/Infrastructure/Locator.cs
  8. 1
      Assets/Scripts/Lobby/LobbyContentHeartbeat.cs
  9. 1
      Assets/Scripts/Lobby/ToLocalLobby.cs
  10. 11
      Assets/Scripts/Relay/RelayUtpSetup.cs
  11. 3
      Assets/Scripts/UI/CreateMenuUI.cs
  12. 2
      Assets/Scripts/Netcode/SymbolObject.cs
  13. 2
      Assets/Scripts/Netcode/SymbolKillVolume.cs
  14. 2
      Assets/Scripts/Netcode/SymbolData.cs
  15. 58
      Assets/Scripts/Netcode/SymbolContainer.cs
  16. 62
      Assets/Scripts/Netcode/SetupInGame.cs
  17. 2
      Assets/Scripts/Netcode/SequenceSelector.cs
  18. 2
      Assets/Scripts/Netcode/Scorer.cs
  19. 3
      Assets/Scripts/Netcode/PlayerCursor.cs
  20. 26
      Assets/Scripts/Netcode/InGameRunner.cs
  21. 2
      Assets/Scripts/Netcode/IInGameInputHandler.cs
  22. 88
      Assets/Scripts/Netcode/RelayNGOUtpSetup.cs
  23. 11
      Assets/Scripts/Netcode/RelayNGOUtpSetup.cs.meta
  24. 115
      Assets/Prefabs/Runes/starfield_bg.prefab
  25. 7
      Assets/Prefabs/Runes/starfield_bg.prefab.meta
  26. 0
      /Assets/Scripts/Netcode.meta
  27. 0
      /Assets/Scripts/Netcode

3
Assets/Prefabs/GameManager.prefab


m_Name:
m_EditorClassIdentifier:
m_prefabNetworkManager: {fileID: 238192747445020667, guid: 73173c97c128d614aa2a1167a2eaea68, type: 3}
m_lobbyObserver: {fileID: 5235782363599194820}
m_disableWhileInGame: []
--- !u!114 &5235782363599194820
MonoBehaviour:

m_Calls:
- m_Target: {fileID: 6265861362966661484}
m_TargetAssemblyTypeName: LobbyRelaySample.inGame.SetupInGame, LobbyRelaySample
m_MethodName: SetRelayAddress
m_MethodName: OnLobbyChange
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}

181
Assets/Prefabs/InGame/InGameLogic.prefab


m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &5218423057724036860
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8262658662678090917}
- component: {fileID: 6998838418292830641}
m_Layer: 0
m_Name: StarfieldSprite
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8262658662678090917
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5218423057724036860}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 30, y: 30, z: 1}
m_Children: []
m_Father: {fileID: 365796668369407178}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &6998838418292830641
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5218423057724036860}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 68d15da6f7b6a8c4a83a150375d3b735, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 1
m_Sprite: {fileID: 7482667652216324306, guid: 48e93eef0688c4a259cb0eddcd8661f7, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 1
m_SpriteSortPoint: 0
--- !u!1 &6206372352141055644
GameObject:
m_ObjectHideFlags: 0

m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!1 &8632503885742220332
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 365796668369407178}
m_Layer: 0
m_Name: StarfieldBG
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &365796668369407178
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8632503885742220332}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 8262658662678090917}
m_Father: {fileID: 485451675458297819}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &9019482255774987314
GameObject:
m_ObjectHideFlags: 0

m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_ProtocolType: 0
m_ProtocolType: 1
m_MaximumPacketSize: 1400
m_MaxPacketQueueSize: 128
m_SendQueueBatchSize: 6144

m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1001 &4607169615917618597
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 485451675458297819}
m_Modifications:
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_RootOrder
value: 3
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5198038901144826249, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_Name
value: starfield_bg
objectReference: {fileID: 0}
- target: {fileID: 6831725540459504660, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
propertyPath: m_SortingOrder
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
--- !u!4 &365796668369407178 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 4250384825297410415, guid: 16a5f484d0695604ea71ba774d5194e5, type: 3}
m_PrefabInstance: {fileID: 4607169615917618597}
m_PrefabAsset: {fileID: 0}

1
Assets/Prefabs/InGame/SymbolContainer.prefab


m_Script: {fileID: 11500000, guid: 73a6c5df5c3139e448d76f8918fece73, type: 3}
m_Name:
m_EditorClassIdentifier:
m_rb: {fileID: 6367926983050135602}

4
Assets/Prefabs/InGame/SymbolObject.prefab


m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8828823320646980938}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 10, z: 40}
m_LocalPosition: {x: 0, y: 10, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 1523494045356209839}

m_IsTrigger: 1
m_Enabled: 1
serializedVersion: 2
m_Size: {x: 2, y: 2, z: 0.2}
m_Size: {x: 1.75, y: 1.75, z: 0.2}
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &-8192876538761676823
MonoBehaviour:

2
Assets/Scripts/Game/GameManager.cs


{
if (type == MessageType.CreateLobbyRequest)
{
var createLobbyData = (LocalLobby)msg;
LocalLobby.LobbyData createLobbyData = (LocalLobby.LobbyData)msg;
LobbyAsyncRequests.Instance.CreateLobbyAsync(createLobbyData.LobbyName, createLobbyData.MaxPlayerCount, createLobbyData.Private, m_localUser, (r) =>
{ lobby.ToLocalLobby.Convert(r, m_localLobby);
OnCreatedLobby();

13
Assets/Scripts/Game/LocalLobby.cs


public string LobbyID { get; set; }
public string LobbyCode { get; set; }
public string RelayCode { get; set; }
public string RelayNGOCode { get; set; }
public string LobbyName { get; set; }
public bool Private { get; set; }
public int MaxPlayerCount { get; set; }

LobbyID = existing.LobbyID;
LobbyCode = existing.LobbyCode;
RelayCode = existing.RelayCode;
RelayNGOCode = existing.RelayNGOCode;
LobbyName = existing.LobbyName;
Private = existing.Private;
MaxPlayerCount = existing.MaxPlayerCount;

LobbyID = null;
LobbyCode = lobbyCode;
RelayCode = null;
RelayNGOCode = null;
LobbyName = null;
Private = false;
MaxPlayerCount = -1;

set
{
m_data.RelayCode = value;
OnChanged(this);
}
}
public string RelayNGOCode
{
get => m_data.RelayNGOCode;
set
{
m_data.RelayNGOCode = value;
OnChanged(this);
}
}

6
Assets/Scripts/Infrastructure/Locator.cs


Provide(new Messenger());
Provide(new UpdateSlowNoop());
Provide(new IdentityNoop());
Provide(new inGame.InGameInputHandlerNoop());
Provide(new ngo.InGameInputHandlerNoop());
FinishConstruction();
}

public IIdentity Identity => Locate<IIdentity>();
public void Provide(IIdentity identity) { ProvideAny(identity); }
public inGame.IInGameInputHandler InGameInputHandler => Locate<inGame.IInGameInputHandler>();
public void Provide(inGame.IInGameInputHandler inputHandler) { ProvideAny(inputHandler); }
public ngo.IInGameInputHandler InGameInputHandler => Locate<ngo.IInGameInputHandler>();
public void Provide(ngo.IInGameInputHandler inputHandler) { ProvideAny(inputHandler); }
// As you add more Provided types, be sure their default implementations are included in the constructor.
}

1
Assets/Scripts/Lobby/LobbyContentHeartbeat.cs


{
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("RelayCode", lobby.RelayCode);
data.Add("RelayNGOCode", lobby.RelayNGOCode);
data.Add("State", ((int)lobby.State).ToString()); // Using an int is smaller than using the enum state's name.
data.Add("Color", ((int)lobby.Color).ToString());
data.Add("State_LastEdit", lobby.Data.State_LastEdit.ToString());

1
Assets/Scripts/Lobby/ToLocalLobby.cs


LobbyName = lobby.Name,
MaxPlayerCount = lobby.MaxPlayers,
RelayCode = lobby.Data?.ContainsKey("RelayCode") == true ? lobby.Data["RelayCode"].Value : null, // By providing RelayCode through the lobby data with Member visibility, we ensure a client is connected to the lobby before they could attempt a relay connection, preventing timing issues between them.
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,

11
Assets/Scripts/Relay/RelayUtpSetup.cs


protected LobbyUser m_localUser;
protected Action<bool, RelayUtpClient> m_onJoinComplete;
public static string AddressFromEndpoint(NetworkEndPoint endpoint)
{
return endpoint.Address.Split(':')[0];
}
public void BeginRelayJoin(LocalLobby localLobby, LobbyUser localUser, Action<bool, RelayUtpClient> onJoinComplete)
{
m_localLobby = localLobby;

/// Determine the server endpoint for connecting to the Relay server, for either an Allocation or a JoinAllocation.
/// If DTLS encryption is available, and there's a secure server endpoint available, use that as a secure connection. Otherwise, just connect to the Relay IP unsecured.
/// </summary>
protected NetworkEndPoint GetEndpointForAllocation(List<RelayServerEndpoint> endpoints, string ip, int port, out bool isSecure)
public static NetworkEndPoint GetEndpointForAllocation(List<RelayServerEndpoint> endpoints, string ip, int port, out bool isSecure)
{
#if ENABLE_MANAGED_UNITYTLS
foreach (RelayServerEndpoint endpoint in endpoints)

private void OnRelayCode(string relayCode)
{
m_localLobby.RelayCode = relayCode;
m_localLobby.RelayServer = new ServerAddress(m_endpointForServer.Address.Split(':')[0], m_endpointForServer.Port);
m_localLobby.RelayServer = new ServerAddress(AddressFromEndpoint(m_endpointForServer), m_endpointForServer.Port);
m_joinState |= JoinState.Joined;
CheckForComplete();
}

bool isSecure = false;
m_endpointForServer = GetEndpointForAllocation(joinAllocation.ServerEndpoints, joinAllocation.RelayServer.IpV4, joinAllocation.RelayServer.Port, out isSecure);
BindToAllocation(m_endpointForServer, joinAllocation.AllocationIdBytes, joinAllocation.ConnectionData, joinAllocation.HostConnectionData, joinAllocation.Key, 1, isSecure);
m_localLobby.RelayServer = new ServerAddress(m_endpointForServer.Address.Split(':')[0], m_endpointForServer.Port);
m_localLobby.RelayServer = new ServerAddress(AddressFromEndpoint(m_endpointForServer), m_endpointForServer.Port);
}
protected override void OnBindingComplete()

3
Assets/Scripts/UI/CreateMenuUI.cs


/// </summary>
public class CreateMenuUI : UIPanelBase
{
[SerializeField]
LocalLobby m_ServerRequestData = new LocalLobby { LobbyName = "New Lobby", MaxPlayerCount = 4 };
private LocalLobby.LobbyData m_ServerRequestData = new LocalLobby.LobbyData{ LobbyName = "New Lobby", MaxPlayerCount = 4 };
public override void Start()
{

2
Assets/Scripts/Netcode/SymbolObject.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// This holds the logic and data for an individual symbol, which can be "clicked" if the server detects the collision with a player who sends a click input.

2
Assets/Scripts/Netcode/SymbolKillVolume.cs


using System;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Used by the host to deactivate symbol objects once they're off-screen.

2
Assets/Scripts/Netcode/SymbolData.cs


using System.Collections.Generic;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
public class SymbolData : ScriptableObject
{

58
Assets/Scripts/Netcode/SymbolContainer.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
// Note: The SymbolObjects, which will be children of this object, need their NetworkTransforms to have IsLocalSpace set to true. Otherwise, they might get desynced.
// (This would manifest as packet loss errors.)
// Also note: The initial position of the SymbolObject prefab is set to be outside the camera view in the Z-direction, so that it doesn't interpolate past the actual
// position when it spawns on a client (as opposed to in the Y-direction, since this SymbolContainer is also moving downward).
/// <summary>
/// Rather than track movement data for every symbol object, the symbols will all be parented under one container that will move.
/// It will not begin that movement until it both has been Spawned on the network and it has been informed that the game has started.
/// </summary>
public class SymbolContainer : NetworkBehaviour
public class SymbolContainer : NetworkBehaviour, IReceiveMessages
[SerializeField] private Rigidbody m_rb = default;
private bool m_isConnected = false;
private bool m_hasGameStarted = false;
private void OnGameStarted()
{
m_hasGameStarted = true;
if (m_isConnected)
BeginMotion();
}
public void Awake() // If there's just one player, Start would occur after the GameBeginning message is sent, so use Awake/OnEnable instead.
{
Locator.Get.Messenger.Subscribe(this);
}
if (IsHost)
GetComponent<NetworkObject>().Spawn();
if (!IsHost)
{ this.enabled = false; // Just disabling this script, not the whole GameObject.
return;
}
GetComponent<NetworkObject>().Spawn();
}
public override void OnNetworkSpawn()

// Note: The SymbolObjects, which will be children of this object, need their NetworkTransforms to have IsLocalSpace set to true. Otherwise, they might get desynced.
// (This would manifest as packet loss errors.)
// Also note: The initial position of the SymbolObject prefab is set to be outside the camera view in the Z-direction, so that it doesn't interpolate past the actual
// position when it spawns on a client (as opposed to in the Y-direction, since this SymbolContainer is also moving downward).
// TODO: Does that matter if we delay for the instructions?
Rigidbody m_rb = this.GetComponent<Rigidbody>();
m_isConnected = true;
m_rb.velocity = Vector3.down;
if (m_hasGameStarted)
BeginMotion();
}
}
private void BeginMotion()
{
m_rb.velocity = Vector3.down;
}
public void OnReceiveMessage(MessageType type, object msg)
{
if (type == MessageType.GameBeginning)
{ Locator.Get.Messenger.Unsubscribe(this);
OnGameStarted();
}
}
}

62
Assets/Scripts/Netcode/SetupInGame.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Once the local player is in a lobby and that lobby has entered the In-Game state, this will load in whatever is necessary to actually run the game part.

{
[SerializeField] private GameObject m_prefabNetworkManager = default;
[SerializeField] private LocalLobbyObserver m_lobbyObserver = default;
private int m_playerCount; // The server will need to know this.
// TEMP? Relay stuff
private ServerAddress m_serverAddress;
private LocalLobby m_lobby;
/*
* Things to do:
*
* x Disable whatever menu behaviors. Maintain a back button with additional RPC calls?
* --- Need to make RelayUtpClient not an MB so I can freely disable the menus? It is on the GameManager, as it happens, but...
* x Spawn the object with the NetworkManager and allow that to connect.
* - Wait for all players to connect, or boot a player after a few seconds (via Relay) if they did not connect.
* x While waiting, server selects the target sequence, spawns the symbol container, and starts pooling/spawning the symbol objects.
* - Once all players are in, show the target sequence and instructions, and then the server starts moving the symbol container and listening to click events.
* - After the symbols are all passed (I guess tracking the symbol container position or a timeout), finish the game (set the winner flag).
* x Clients clean up and return to the lobby screen. Host sets the lobby back to the regular state.
*
*/
{
Locator.Get.Messenger.Subscribe(this);
m_lobbyObserver.OnObservedUpdated.AddListener(UpdatePlayerCount);
{ Locator.Get.Messenger.Subscribe(this);
{
Locator.Get.Messenger.Unsubscribe(this);
m_lobbyObserver.OnObservedUpdated.RemoveListener(UpdatePlayerCount);
{ Locator.Get.Messenger.Unsubscribe(this);
}
private void SetMenuVisibility(bool areVisible)

m_inGameManagerObj = GameObject.Instantiate(m_prefabNetworkManager);
m_networkManager = m_inGameManagerObj.GetComponentInChildren<NetworkManager>();
m_inGameRunner = m_inGameManagerObj.GetComponentInChildren<InGameRunner>();
m_inGameRunner.Initialize(OnConnectionVerified, m_playerCount, OnGameEnd);
// TODO: I'll need this when we switch to the Relay Unity Transport option.
//UnityTransport transport = m_inGameManagerObj.GetComponentInChildren<UnityTransport>();
//transport.SetConnectionData(m_serverAddress.IP, (ushort)m_serverAddress.Port);
//m_initializeTransport(transport);
m_inGameRunner.Initialize(OnConnectionVerified, m_lobby.PlayerCount, OnGameEnd);
UnityTransport transport = m_inGameManagerObj.GetComponentInChildren<UnityTransport>();
m_networkManager.StartHost();
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupHost>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartHost(); });
m_networkManager.StartClient();
m_inGameManagerObj.AddComponent<RelayUtpNGOSetupClient>().Initialize(this, m_lobby, () => { m_initializeTransport(transport); m_networkManager.StartClient(); });
private void UpdatePlayerCount(LocalLobby lobby)
{ m_playerCount = lobby.PlayerCount;
}
{
m_hasConnectedViaNGO = true;
{ m_hasConnectedViaNGO = true;
public void SetRelayAddress(LocalLobby changed)
{
m_serverAddress = changed.RelayServer; // Note that this could be null.
// These are public for use in the Inspector.
public void OnLobbyChange(LocalLobby lobby)
{ 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.
{
m_isHost = user.IsHost;
{ m_isHost = user.IsHost;
}
public void SetRelayServerData(string address, int port, byte[] allocationBytes, byte[] key, byte[] connectionData, byte[] hostConnectionData, bool isSecure)

Locator.Get.Messenger.OnReceiveMessage(MessageType.DisplayErrorPopup, "Failed to join the game.");
// TODO: Need to handle both failing to connect and connecting but failing to initialize.
// I.e. cleaning up networked objects *might* be necessary.
OnGameEnd();
}
}

}
}
/// <summary>
/// Return to the lobby after the game, whether due to the game ending or due to a failed connection.
/// </summary>
private void OnGameEnd()
{
if (m_doesNeedCleanup)

m_lobby.RelayNGOCode = null;
m_doesNeedCleanup = false;
}
}

2
Assets/Scripts/Netcode/SequenceSelector.cs


using UnityEngine;
using UnityEngine.UI;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Handles selecting the randomized sequence of symbols to spawn. This also selects a subset of the selected symbols to be the target

2
Assets/Scripts/Netcode/Scorer.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
// TODO: I'm using host and server interchangeably...

3
Assets/Scripts/Netcode/PlayerCursor.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Each player's cursor needs to be controlled by them and visible to the other players.

if (m_currentlyCollidingSymbols.Count > 0)
{
SymbolObject symbol = m_currentlyCollidingSymbols[0];
m_currentlyCollidingSymbols.RemoveAt(0);
Locator.Get.InGameInputHandler.OnPlayerInput(id, symbol);
}
OnInputVisuals_ClientRpc();

26
Assets/Scripts/Netcode/InGameRunner.cs


using Unity.Netcode;
using UnityEngine;
namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
/// <summary>
/// Once the NetworkManager has been spawned, we need something to manage the game state and setup other in-game objects

private Transform m_symbolContainerInstance;
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 float m_timeout = 10;
public void Initialize(Action onConnectionVerified, int expectedPlayerCount, Action onGameEnd)
{

private void VerifyConnection_ServerRpc(ulong clientId)
{
VerifyConnection_ClientRpc(clientId);
// If not spawning things in the background, start doing so.
m_canSpawnInGameObjects = true;
// While we could start pooling symbol objects now, incoming clients would be flooded with the Spawn calls.
// This could lead to dropped packets such that the InGameRunner's Spawn call fails to occur, so we'll wait until all players join.
}
[ClientRpc]
private void VerifyConnection_ClientRpc(ulong clientId)

if (clientId == m_localId)
m_onConnectionVerified?.Invoke();
if (shouldStartImmediately)
Locator.Get.Messenger.OnReceiveMessage(MessageType.GameBeginning, null);
{
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).
if (m_timeout >= 0)
{
m_timeout -= Time.deltaTime;
if (m_timeout < 0)
BeginGame();
}
// TODO: BSP for choosing symbol spawn positions?
// TODO: Remove the timer to test for packet loss.

2
Assets/Scripts/Netcode/IInGameInputHandler.cs


namespace LobbyRelaySample.inGame
namespace LobbyRelaySample.ngo
{
public interface IInGameInputHandler : IProvidable<IInGameInputHandler>
{

88
Assets/Scripts/Netcode/RelayNGOUtpSetup.cs


using System;
using Unity.Services.Relay.Models;
using UnityEngine;
using LobbyRelaySample.relay;
namespace LobbyRelaySample.ngo
{
/*
* When using the Relay adapter for UTP to connect the NetworkManager for Netcode for GameObjects (NGO), we need to provide the Allocation info without manually binding to it.
* In actual use, if you are using NGO for your game's networking, you would not also use the RelayUtpSetupHost/RelayUtpSetupClient at all, since their direct data transmission would be unnecessary.
* We keep both versions for this sample to demonstrate how each is set up, whether you want to just use Lobby + Relay or use NGO as well.
*/
/// <summary>
/// Host logic: Request a new Allocation, and then pass its info to the UTP adapter for NGO.
/// </summary>
public class RelayUtpNGOSetupHost : MonoBehaviour // If this is a MonoBehaviour, it can be added to the InGameRunner object for easier cleanup on game end.
{
private SetupInGame m_setupInGame;
private LocalLobby m_localLobby;
private Action m_onJoin;
public void Initialize(SetupInGame setupInGame, LocalLobby lobby, Action onJoin)
{
m_setupInGame = setupInGame;
m_localLobby = lobby;
m_onJoin = onJoin;
RelayAPIInterface.AllocateAsync(m_localLobby.MaxPlayerCount, OnAllocation);
}
private void OnAllocation(Allocation allocation)
{
RelayAPIInterface.GetJoinCodeAsync(allocation.AllocationId, OnRelayCode);
bool isSecure = false;
var endpoint = RelayUtpSetup.GetEndpointForAllocation(allocation.ServerEndpoints, allocation.RelayServer.IpV4, allocation.RelayServer.Port, out isSecure);
m_setupInGame.SetRelayServerData(RelayUtpSetup.AddressFromEndpoint(endpoint), endpoint.Port, allocation.AllocationIdBytes, allocation.Key, allocation.ConnectionData, allocation.ConnectionData, isSecure);
m_onJoin?.Invoke();
}
private void OnRelayCode(string relayCode)
{
m_localLobby.RelayNGOCode = relayCode;
}
}
/// <summary>
/// Client logic: Wait to receive the Relay code for NGO, and then pass the allocation info to the UTP adapter.
/// </summary>
public class RelayUtpNGOSetupClient : MonoBehaviour // This is also a MonoBehaviour for access to OnDestroy, to ensure unsubscription from the local lobby on game end.
{
private SetupInGame m_setupInGame;
private LocalLobby m_localLobby;
private Action m_onJoin;
public void Initialize(SetupInGame setupInGame, LocalLobby lobby, Action onJoin)
{
m_setupInGame = setupInGame;
m_localLobby = lobby;
m_onJoin = onJoin;
m_localLobby.onChanged += OnLobbyChange;
}
public void OnDestroy()
{
m_localLobby.onChanged -= OnLobbyChange;
}
private void OnLobbyChange(LocalLobby lobby)
{
if (m_localLobby.RelayNGOCode != null)
{
RelayAPIInterface.JoinAsync(m_localLobby.RelayNGOCode, OnJoin);
m_localLobby.onChanged -= OnLobbyChange;
}
}
private void OnJoin(JoinAllocation joinAllocation)
{
if (joinAllocation == null || this == null) // The returned JoinAllocation is null if allocation failed. this would be destroyed already if you quit the lobby while Relay is connecting.
return;
bool isSecure = false;
var endpoint = RelayUtpSetup.GetEndpointForAllocation(joinAllocation.ServerEndpoints, joinAllocation.RelayServer.IpV4, joinAllocation.RelayServer.Port, out isSecure);
m_setupInGame.SetRelayServerData(RelayUtpSetup.AddressFromEndpoint(endpoint), endpoint.Port, joinAllocation.AllocationIdBytes, joinAllocation.Key, joinAllocation.ConnectionData, joinAllocation.HostConnectionData, isSecure);
m_onJoin?.Invoke();
}
}
}

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


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

115
Assets/Prefabs/Runes/starfield_bg.prefab


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5198038901144826249
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4250384825297410415}
m_Layer: 0
m_Name: starfield_bg
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4250384825297410415
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5198038901144826249}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 5567900622042513664}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &8612118632738538329
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5567900622042513664}
- component: {fileID: 6831725540459504660}
m_Layer: 0
m_Name: starfield_sprite
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5567900622042513664
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8612118632738538329}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 30, y: 30, z: 1}
m_Children: []
m_Father: {fileID: 4250384825297410415}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &6831725540459504660
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8612118632738538329}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 68d15da6f7b6a8c4a83a150375d3b735, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_Sprite: {fileID: 7482667652216324306, guid: 48e93eef0688c4a259cb0eddcd8661f7, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 1
m_SpriteSortPoint: 0

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


fileFormatVersion: 2
guid: 16a5f484d0695604ea71ba774d5194e5
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

/Assets/Scripts/Game/InGame.meta → /Assets/Scripts/Netcode.meta

/Assets/Scripts/Game/InGame → /Assets/Scripts/Netcode

正在加载...
取消
保存