Skip to content

Commit aeab5bc

Browse files
update
Finalized readme and migrated images to local directory. Cleaned up some minor issues including renaming of some properties, handling resetting of camera when running in server mode and a client being followed disconnects, and some other minor clean up.
1 parent 160ca89 commit aeab5bc

16 files changed

+228
-82
lines changed

Examples/OverridingScenesAndPrefabs/Assets/Scenes/BootstrapScene.unity

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ MonoBehaviour:
229229
TargetFrameRate: 100
230230
EnableVSync: 0
231231
m_OriginalVSyncCount: 1
232+
m_ServicesRegistered: 1
232233
--- !u!114 &455857873
233234
MonoBehaviour:
234235
m_ObjectHideFlags: 0
@@ -272,8 +273,8 @@ MonoBehaviour:
272273
m_Script: {fileID: 11500000, guid: 5c472ff64b067344893ed2e632d0f9f1, type: 3}
273274
m_Name:
274275
m_EditorClassIdentifier:
275-
ClientNetworkPrefab: {fileID: 6472733969592893139, guid: 3e5167b6e6bcb5645abb2dbc0078091e, type: 3}
276-
ServerNetworkPrefab: {fileID: 4710599683293591777, guid: 90bfa3cd2cce8f14ead59b4dbdae92bb, type: 3}
276+
NetworkPrefab: {fileID: 4710599683293591777, guid: 90bfa3cd2cce8f14ead59b4dbdae92bb, type: 3}
277+
NetworkPrefabOverride: {fileID: 6472733969592893139, guid: 3e5167b6e6bcb5645abb2dbc0078091e, type: 3}
277278
--- !u!1660057539 &9223372036854775807
278279
SceneRoots:
279280
m_ObjectHideFlags: 0

Examples/OverridingScenesAndPrefabs/Assets/Scripts/InstanceTypeLocalBehavior.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/// </summary>
1010
public class InstanceTypeLocalBehavior : MonoBehaviour, INetworkUpdateSystem
1111
{
12-
[Tooltip("When enabled, this will run only on a server or host.")]
12+
[Tooltip("When enabled, this will run only on a server or host. When disabled, this will only run on the owner of the local client player (including host).")]
1313
public bool ServerOnly;
1414

1515
[Tooltip("This is the unique message example text displayed when running locally.")]
@@ -25,6 +25,38 @@ private void Awake()
2525
m_MoverScriptNoRigidbody.NotifySpawnStatusChanged += OnSpawnStatusChanged;
2626
}
2727

28+
/// <summary>
29+
/// Adjust this logic to fit your needs.
30+
/// This example makes the InstanceTypeLocalBehavior only update if:
31+
/// - It is a server (including host) and is marked for ServerOnly
32+
/// - It is a client (including host), is not marked for ServerOnly, and the local client is the owner of MoverScriptNoRigidbody.
33+
/// - It is in distributed authority mode, is not marked for ServerOnly, and the local client has authority of the MoverScriptNoRigidbody.
34+
/// </summary>
35+
private bool HasAuthority()
36+
{
37+
if (m_NetworkManager == null)
38+
{
39+
return false;
40+
}
41+
42+
if (!ServerOnly && m_NetworkManager.DistributedAuthorityMode && m_MoverScriptNoRigidbody.HasAuthority)
43+
{
44+
return true;
45+
}
46+
else
47+
{
48+
if (ServerOnly && m_NetworkManager.IsServer)
49+
{
50+
return true;
51+
}
52+
else if (!ServerOnly && m_MoverScriptNoRigidbody.IsOwner)
53+
{
54+
return true;
55+
}
56+
}
57+
return false;
58+
}
59+
2860
/// <summary>
2961
/// <see cref="MoverScriptNoRigidbody.NotifySpawnStatusChanged"/>
3062
/// Isolate the spawning status to the <see cref="NetworkBehaviour"/> and just
@@ -37,18 +69,24 @@ private void OnSpawnStatusChanged(bool spawned)
3769
if (spawned)
3870
{
3971
m_NetworkManager = m_MoverScriptNoRigidbody.NetworkManager;
40-
if (ServerOnly && m_NetworkManager.IsServer)
72+
if (HasAuthority())
4173
{
4274
NetworkUpdateLoop.RegisterNetworkUpdate(this, NetworkUpdateStage.Update);
4375
}
4476
}
4577
else
4678
{
79+
// Whether registered or not, it is easier to just unregister always.
4780
NetworkUpdateLoop.UnregisterAllNetworkUpdates(this);
4881
m_NetworkManager = null;
4982
}
5083
}
5184

85+
/// <summary>
86+
/// Invoked only on the instance(s) that have authority to update.
87+
/// <see cref="HasAuthority"/>
88+
/// </summary>
89+
/// <param name="updateStage"></param>
5290
public void NetworkUpdate(NetworkUpdateStage updateStage)
5391
{
5492
if (updateStage == NetworkUpdateStage.Update)

Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public class MoverScriptNoRigidbody : NetworkTransform
113113
private CharacterController m_CharacterController;
114114
private PlayerBallMotion m_PlayerBallMotion;
115115

116-
public Action<bool> NotifySpawnStatusChanged;
116+
public event Action<bool> NotifySpawnStatusChanged;
117117

118118
protected override void Awake()
119119
{
@@ -150,10 +150,7 @@ protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
150150
protected override void OnNetworkPostSpawn()
151151
{
152152
// Authority of this object sends local notifications to any non-networkbehaviour subscribers
153-
if (HasAuthority)
154-
{
155-
NotifySpawnStatusChanged?.Invoke(true);
156-
}
153+
NotifySpawnStatusChanged?.Invoke(true);
157154

158155
m_CharacterController.enabled = CanCommitToTransform;
159156
if (CanCommitToTransform)

Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,21 @@ public override void OnInspectorGUI()
5555
/// </summary>
5656
public class NetworkManagerBootstrapper : NetworkManager
5757
{
58+
#region Validation
5859
#if UNITY_EDITOR
5960
// Inspector view expand/collapse settings for this derived child class
6061
[HideInInspector]
6162
public bool NetworkManagerBootstrapperExpanded;
6263
protected override void OnValidateComponent()
6364
{
6465
m_OriginalVSyncCount = QualitySettings.vSyncCount;
66+
m_ServicesRegistered = CloudProjectSettings.organizationName != string.Empty && CloudProjectSettings.organizationId != string.Empty;
6567
base.OnValidateComponent();
6668
}
6769
#endif
70+
#endregion
6871

72+
#region Properties
6973
public static NetworkManagerBootstrapper Instance;
7074

7175
public int TargetFrameRate = 100;
@@ -91,12 +95,17 @@ private enum ConnectionStates
9195
}
9296

9397
private ConnectionStates m_ConnectionState;
98+
99+
[SerializeField]
94100
private bool m_ServicesRegistered;
95101
private ISession m_CurrentSession;
96102
private string m_SessionName;
97103
private string m_ProfileName;
98104
private Task m_SessionTask;
99105

106+
#endregion
107+
108+
#region Initialization and Destroy
100109
public static string GetRandomString(int length)
101110
{
102111
var r = new System.Random();
@@ -115,8 +124,6 @@ private void Awake()
115124
SetFrameRate(TargetFrameRate, EnableVSync);
116125
SetSingleton();
117126
m_SceneBootstrapLoader = GetComponent<SceneBootstrapLoader>();
118-
119-
m_ServicesRegistered = CloudProjectSettings.organizationName != string.Empty && CloudProjectSettings.organizationId != string.Empty;
120127
}
121128

122129
private async void Start()
@@ -153,8 +160,9 @@ private void OnDestroy()
153160
OnClientDisconnectCallback -= OnClientDisconnect;
154161
OnConnectionEvent -= OnClientConnectionEvent;
155162
}
163+
#endregion
156164

157-
165+
#region Session and Connection Event Handling
158166
private void OnClientConnectionEvent(NetworkManager networkManager, ConnectionEventData eventData)
159167
{
160168
LogMessage($"[{Time.realtimeSinceStartup}] Connection event {eventData.EventType} for Client-{eventData.ClientId}.");
@@ -207,6 +215,29 @@ private void SessionStopped(bool isHost)
207215
}
208216
}
209217

218+
private async Task<ISession> ConnectThroughLiveService()
219+
{
220+
try
221+
{
222+
var options = new SessionOptions()
223+
{
224+
Name = m_SessionName,
225+
MaxPlayers = 32
226+
}.WithDistributedAuthorityNetwork();
227+
228+
m_CurrentSession = await MultiplayerService.Instance.CreateOrJoinSessionAsync(m_SessionName, options);
229+
return m_CurrentSession;
230+
}
231+
catch (Exception e)
232+
{
233+
LogMessage($"{e.Message}");
234+
Debug.LogException(e);
235+
}
236+
return null;
237+
}
238+
#endregion
239+
240+
#region GUI Menu
210241
public void StartOrConnectToDistributedAuthoritySession()
211242
{
212243
m_SessionTask = ConnectThroughLiveService();
@@ -333,37 +364,21 @@ private void OnGUI()
333364
}
334365
GUILayout.EndArea();
335366
}
367+
#endregion
336368

337-
338-
private async Task<ISession> ConnectThroughLiveService()
339-
{
340-
try
341-
{
342-
var options = new SessionOptions()
343-
{
344-
Name = m_SessionName,
345-
MaxPlayers = 32
346-
}.WithDistributedAuthorityNetwork();
347-
348-
m_CurrentSession = await MultiplayerService.Instance.CreateOrJoinSessionAsync(m_SessionName, options);
349-
return m_CurrentSession;
350-
}
351-
catch (Exception e)
352-
{
353-
LogMessage($"{e.Message}");
354-
Debug.LogException(e);
355-
}
356-
return null;
357-
}
358-
359-
369+
#region Server Camera Handling
360370
private Vector3 m_CameraOriginalPosition;
361371
private Quaternion m_CameraOriginalRotation;
362372
private int m_CurrentFollowPlayerIndex = -1;
373+
private MoverScriptNoRigidbody m_CurrentPlayerFollowed;
363374

364375
private void ResetMainCamera()
365376
{
366377
m_CurrentFollowPlayerIndex = -1;
378+
SetCameraDefaults();
379+
}
380+
private void SetCameraDefaults()
381+
{
367382
if (Camera.main != null && Camera.main.transform.parent != null)
368383
{
369384
Camera.main.transform.SetParent(null, false);
@@ -372,14 +387,15 @@ private void ResetMainCamera()
372387
}
373388
}
374389

375-
#region Update Methods and Properties
376-
377390
/// <summary>
378-
/// General update for server-side
391+
/// Server only (i.e. not host), follow players as they move around
379392
/// </summary>
380-
private void ServerSideUpdate()
393+
private void ServerFollowPlayerCheck()
381394
{
382-
if (Input.GetKeyDown(KeyCode.P) && ConnectedClientsIds.Count > 0)
395+
bool leftBracket = Input.GetKeyDown(KeyCode.LeftBracket);
396+
bool rightBracket = Input.GetKeyDown(KeyCode.RightBracket);
397+
398+
if ((leftBracket || rightBracket) && ConnectedClientsIds.Count > 0)
383399
{
384400
// Capture the main camera's original position and rotation the first time the server-side
385401
// follows a player.
@@ -388,21 +404,53 @@ private void ServerSideUpdate()
388404
m_CameraOriginalPosition = Camera.main.transform.position;
389405
m_CameraOriginalRotation = Camera.main.transform.rotation;
390406
}
391-
m_CurrentFollowPlayerIndex++;
407+
408+
if (leftBracket)
409+
{
410+
m_CurrentFollowPlayerIndex--;
411+
if (m_CurrentFollowPlayerIndex < 0)
412+
{
413+
m_CurrentFollowPlayerIndex = ConnectedClientsIds.Count - 1;
414+
}
415+
}
416+
else
417+
{
418+
m_CurrentFollowPlayerIndex++;
419+
}
420+
392421
m_CurrentFollowPlayerIndex %= ConnectedClientsIds.Count;
393422

394423
var playerId = ConnectedClientsIds[m_CurrentFollowPlayerIndex];
395-
var playerObject = ConnectedClients[playerId];
396-
Camera.main.transform.SetParent(playerObject.PlayerObject.transform, false);
424+
var playerNetworkClient = ConnectedClients[playerId];
425+
m_CurrentPlayerFollowed = playerNetworkClient.PlayerObject.GetComponent<MoverScriptNoRigidbody>();
426+
Camera.main.transform.SetParent(playerNetworkClient.PlayerObject.transform, false);
397427
}
398428
else if (Input.GetKeyDown(KeyCode.Backspace))
399429
{
400-
Camera.main.transform.SetParent(null, false);
401-
Camera.main.transform.position = m_CameraOriginalPosition;
402-
Camera.main.transform.rotation = m_CameraOriginalRotation;
430+
ClearFollowPlayer();
431+
}
432+
}
433+
public void ClearFollowPlayer()
434+
{
435+
if (m_CurrentPlayerFollowed != null)
436+
{
437+
m_CurrentPlayerFollowed = null;
438+
SetCameraDefaults();
403439
}
404440
}
441+
#endregion
405442

443+
#region Update Methods and Properties
444+
/// <summary>
445+
/// General update for server-side
446+
/// </summary>
447+
private void ServerSideUpdate()
448+
{
449+
if (!IsHost)
450+
{
451+
ServerFollowPlayerCheck();
452+
}
453+
}
406454

407455
/// <summary>
408456
/// General update for client-side
@@ -441,8 +489,7 @@ private void Update()
441489
}
442490
#endregion
443491

444-
445-
#region Message Logging Methods and Properties
492+
#region Message Logging
446493

447494
private List<MessageLog> m_MessageLogs = new List<MessageLog>();
448495

Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkPrefabOverrideHandler.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,35 @@
1414
[RequireComponent(typeof(NetworkPrefabOverrideHandler))]
1515
public class NetworkPrefabOverrideHandler : MonoBehaviour, INetworkPrefabInstanceHandler
1616
{
17-
public GameObject ClientNetworkPrefab;
17+
public GameObject NetworkPrefab;
18+
public GameObject NetworkPrefabOverride;
1819

19-
public GameObject ServerNetworkPrefab;
20-
21-
private NetworkManager m_NetworkManager;
20+
private NetworkManagerBootstrapper m_NetworkManager;
2221

2322
private void Start()
2423
{
25-
m_NetworkManager = GetComponent<NetworkManager>();
26-
m_NetworkManager.PrefabHandler.AddHandler(ServerNetworkPrefab, this);
24+
m_NetworkManager = GetComponent<NetworkManagerBootstrapper>();
25+
m_NetworkManager.PrefabHandler.AddHandler(NetworkPrefab, this);
2726
NetworkManager.OnDestroying += NetworkManager_OnDestroying;
2827
}
2928

3029
private void NetworkManager_OnDestroying(NetworkManager obj)
3130
{
32-
m_NetworkManager.PrefabHandler.RemoveHandler(ServerNetworkPrefab);
31+
m_NetworkManager.PrefabHandler.RemoveHandler(NetworkPrefab);
3332
}
3433

3534
/// <summary>
3635
/// Invoked on both server and clients when the prefab is spawned.
37-
/// Server-side will spawn the server version.
38-
/// Client-side will spawn the client version.
36+
/// Server-side will spawn the default network prefab.
37+
/// Client-side will spawn the network prefab override version.
3938
/// </summary>
4039
/// <param name="ownerClientId">the client identifier that will own this network prefab instance</param>
4140
/// <param name="position">optional to use the position passed in</param>
4241
/// <param name="rotation">optional to use the rotation passed in</param>
4342
/// <returns></returns>
4443
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
4544
{
46-
var gameObject = m_NetworkManager.IsClient ? Instantiate(ClientNetworkPrefab) : Instantiate(ServerNetworkPrefab);
45+
var gameObject = m_NetworkManager.IsClient ? Instantiate(NetworkPrefabOverride) : Instantiate(NetworkPrefab);
4746
// You could integrate spawn locations here and on the server side apply the spawn position at
4847
// this stage of the spawn process.
4948
gameObject.transform.position = position;
@@ -53,6 +52,13 @@ public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaterni
5352

5453
public void Destroy(NetworkObject networkObject)
5554
{
55+
// Another useful thing about handling this instantiation and destruction of a NetworkObject is that you can do house cleaning
56+
// prior to the object being destroyed. This handles the scenario where the server is following a player and the player disconnects.
57+
// Before destroying the player object, we want to unparent the camera and reset the player being followed.
58+
if (m_NetworkManager.IsServer && !m_NetworkManager.IsHost && Camera.main != null && Camera.main.transform.parent == networkObject.transform)
59+
{
60+
m_NetworkManager.ClearFollowPlayer();
61+
}
5662
Destroy(networkObject.gameObject);
5763
}
5864
}

0 commit comments

Comments
 (0)