-
Notifications
You must be signed in to change notification settings - Fork 450
feat!: Network Prefab Overrides, Inspector View, and the default Player Prefab #749
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c729148
677b49e
d873ecc
59511f1
a217e7a
2559481
84f0942
b78403e
c600724
97a41bc
9558732
e799b47
5926c3c
481e862
7f2781c
3de2cac
bb91f17
0e11960
5c22c63
5046892
67f8e66
02a726d
4cbde7c
a2fe29d
df7b111
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,7 +4,6 @@ | |||||
using System.ComponentModel; | ||||||
using System.Diagnostics; | ||||||
using UnityEngine; | ||||||
using System.Linq; | ||||||
using MLAPI.Logging; | ||||||
using MLAPI.Configuration; | ||||||
using MLAPI.Internal; | ||||||
|
@@ -216,7 +215,7 @@ private void OnValidate() | |||||
{ | ||||||
if (NetworkConfig == null) | ||||||
{ | ||||||
return; //May occur when the component is added | ||||||
return; // May occur when the component is added | ||||||
} | ||||||
|
||||||
if (GetComponentInChildren<NetworkObject>() != null) | ||||||
|
@@ -247,39 +246,58 @@ private void OnValidate() | |||||
}; | ||||||
} | ||||||
|
||||||
// During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Clear(); | ||||||
|
||||||
// Check network prefabs and assign to dictionary for quick look up | ||||||
for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) | ||||||
{ | ||||||
if (NetworkConfig.NetworkPrefabs[i] != null && NetworkConfig.NetworkPrefabs[i].Prefab != null) | ||||||
{ | ||||||
if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>() == null) | ||||||
var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>(); | ||||||
if (networkObject == null) | ||||||
{ | ||||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||||||
{ | ||||||
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} [{i}] does not have a {nameof(NetworkObject)} component"); | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
else | ||||||
{ | ||||||
// Default to the standard NetworkPrefab.Prefab's NetworkObject first | ||||||
var globalObjectIdHash = networkObject.GlobalObjectIdHash; | ||||||
|
||||||
int playerPrefabCount = NetworkConfig.NetworkPrefabs.Count(x => x.IsPlayer); | ||||||
// Now check to see if it has an override | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
over-commenting, isn't it obvious? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, comments help guide people as to what is happening. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree :P Let's discuss internally :) |
||||||
switch (NetworkConfig.NetworkPrefabs[i].Override) | ||||||
{ | ||||||
case NetworkPrefabOverride.Prefab: | ||||||
{ | ||||||
if (NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) | ||||||
{ | ||||||
NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride = NetworkConfig.NetworkPrefabs[i].Prefab; | ||||||
} | ||||||
globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride.GetComponent<NetworkObject>().GlobalObjectIdHash; | ||||||
} | ||||||
break; | ||||||
case NetworkPrefabOverride.Hash: | ||||||
globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].SourceHashToOverride; | ||||||
break; | ||||||
} | ||||||
|
||||||
if (playerPrefabCount == 0 && !NetworkConfig.ConnectionApproval && NetworkConfig.CreatePlayerPrefab) | ||||||
{ | ||||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||||||
{ | ||||||
NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); | ||||||
} | ||||||
} | ||||||
else if (playerPrefabCount > 1) | ||||||
{ | ||||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) | ||||||
{ | ||||||
NetworkLog.LogWarning($"Only one {nameof(NetworkPrefab)} can be marked as a {nameof(NetworkPrefab.IsPlayer)}"); | ||||||
// Add to the NetworkPrefabOverrideLinks or handle a new (blank) entries | ||||||
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(globalObjectIdHash)) | ||||||
{ | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Add(globalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); | ||||||
} | ||||||
else | ||||||
{ | ||||||
// Duplicate entries can happen when adding a new entry into a list of existing entries | ||||||
// Either this is user error or a new entry, either case we replace it with a new, blank, NetworkPrefab under this condition | ||||||
NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab(); | ||||||
} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
var networkPrefab = NetworkConfig.NetworkPrefabs.FirstOrDefault(x => x.IsPlayer); | ||||||
NetworkConfig.PlayerPrefabHash = networkPrefab?.Hash ?? (uint)0; | ||||||
} | ||||||
#endif | ||||||
|
||||||
|
@@ -326,7 +344,7 @@ private void Init(bool server) | |||||
return; | ||||||
} | ||||||
|
||||||
//This 'if' should never enter | ||||||
// This 'if' should never enter | ||||||
if (NetworkTickSystem != null) | ||||||
{ | ||||||
NetworkTickSystem.Dispose(); | ||||||
|
@@ -335,16 +353,16 @@ private void Init(bool server) | |||||
|
||||||
NetworkTickSystem = new NetworkTickSystem(NetworkConfig.NetworkTickIntervalSec); | ||||||
|
||||||
//This should never happen, but in the event that it does there should be (at a minimum) a unity error logged. | ||||||
// This should never happen, but in the event that it does there should be (at a minimum) a unity error logged. | ||||||
if (RpcQueueContainer != null) | ||||||
{ | ||||||
UnityEngine.Debug.LogError("Init was invoked, but rpcQueueContainer was already initialized! (destroying previous instance)"); | ||||||
RpcQueueContainer.Dispose(); | ||||||
RpcQueueContainer = null; | ||||||
} | ||||||
|
||||||
//The RpcQueueContainer must be initialized within the Init method ONLY | ||||||
//It should ONLY be shutdown and destroyed in the Shutdown method (other than just above) | ||||||
// The RpcQueueContainer must be initialized within the Init method ONLY | ||||||
// It should ONLY be shutdown and destroyed in the Shutdown method (other than just above) | ||||||
RpcQueueContainer = new RpcQueueContainer(this); | ||||||
|
||||||
// Register INetworkUpdateSystem (always register this after rpcQueueContainer has been instantiated) | ||||||
|
@@ -365,23 +383,98 @@ private void Init(bool server) | |||||
SceneManager.SetCurrentSceneIndex(); | ||||||
} | ||||||
|
||||||
// This is used to remove entries not needed or invalid | ||||||
var removeEmptyPrefabs = new List<int>(); | ||||||
|
||||||
// Always clear our prefab override links before building | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Clear(); | ||||||
|
||||||
// Build the NetworkPrefabOverrideLinks dictionary | ||||||
for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) | ||||||
{ | ||||||
if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) | ||||||
{ | ||||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Error) | ||||||
{ | ||||||
NetworkLog.LogError($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); | ||||||
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); | ||||||
} | ||||||
|
||||||
// Provide the name of the prefab with issues so the user can more easily find the prefab and fix it | ||||||
UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); | ||||||
removeEmptyPrefabs.Add(i); | ||||||
|
||||||
continue; | ||||||
} | ||||||
else if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>() == null) | ||||||
{ | ||||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Error) | ||||||
{ | ||||||
NetworkLog.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); | ||||||
NetworkLog.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); | ||||||
} | ||||||
|
||||||
// Provide the name of the prefab with issues so the user can more easily find the prefab and fix it | ||||||
UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); | ||||||
removeEmptyPrefabs.Add(i); | ||||||
|
||||||
continue; | ||||||
} | ||||||
|
||||||
var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>(); | ||||||
|
||||||
// Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab | ||||||
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash)) | ||||||
{ | ||||||
switch (NetworkConfig.NetworkPrefabs[i].Override) | ||||||
{ | ||||||
default: | ||||||
case NetworkPrefabOverride.None: | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); | ||||||
break; | ||||||
case NetworkPrefabOverride.Prefab: | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride.GetComponent<NetworkObject>().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); | ||||||
break; | ||||||
case NetworkPrefabOverride.Hash: | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].SourceHashToOverride, NetworkConfig.NetworkPrefabs[i]); | ||||||
break; | ||||||
} | ||||||
} | ||||||
else | ||||||
{ | ||||||
// This should never happen, but in the case it somehow does log an error and remove the duplicate entry | ||||||
UnityEngine.Debug.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} {networkObject.GlobalObjectIdHash} entry! Removing entry from list!"); | ||||||
removeEmptyPrefabs.Add(i); | ||||||
} | ||||||
} | ||||||
|
||||||
// If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. | ||||||
if (NetworkConfig.PlayerPrefab != null) | ||||||
{ | ||||||
var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>(); | ||||||
if (playerPrefabNetworkObject != null) | ||||||
{ | ||||||
//In the event there is no NetworkPrefab entry (i.e. no override for default player prefab) | ||||||
if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject.GlobalObjectIdHash)) | ||||||
{ | ||||||
//Then add a new entry for the player prefab | ||||||
var playerNetworkPrefab = new NetworkPrefab(); | ||||||
playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; | ||||||
NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab); | ||||||
NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); | ||||||
} | ||||||
} | ||||||
else | ||||||
{ | ||||||
// Provide the name of the prefab with issues so the user can more easily find the prefab and fix it | ||||||
UnityEngine.Debug.LogError($"{nameof(NetworkConfig.PlayerPrefab)} (\"{NetworkConfig.PlayerPrefab.name}\") has no NetworkObject assigned to it!."); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
// Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) | ||||||
foreach (var networkPrefabIndexToRemove in removeEmptyPrefabs) | ||||||
{ | ||||||
NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); | ||||||
} | ||||||
removeEmptyPrefabs.Clear(); | ||||||
|
||||||
NetworkConfig.NetworkTransport.OnTransportEvent += HandleRawTransportPoll; | ||||||
|
||||||
|
@@ -604,7 +697,7 @@ public SocketTasks StartHost() | |||||
} | ||||||
else | ||||||
{ | ||||||
HandleApproval(ServerClientId, NetworkConfig.CreatePlayerPrefab, null, true, null, null); | ||||||
HandleApproval(ServerClientId, NetworkConfig.PlayerPrefab != null, null, true, null, null); | ||||||
} | ||||||
|
||||||
SpawnManager.ServerSpawnSceneObjectsOnStartSweep(); | ||||||
|
@@ -1477,7 +1570,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? | |||||
|
||||||
if (createPlayerObject) | ||||||
{ | ||||||
var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefabHash, ownerClientId, null, position, rotation); | ||||||
var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash, ownerClientId, null, position, rotation); | ||||||
SpawnManager.SpawnNetworkObjectLocally(networkObject, SpawnManager.GetNetworkObjectId(), false, true, ownerClientId, null, false, 0, false, false); | ||||||
|
||||||
ConnectedClients[ownerClientId].PlayerObject = networkObject; | ||||||
|
@@ -1566,7 +1659,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? | |||||
|
||||||
OnClientConnectedCallback?.Invoke(ownerClientId); | ||||||
|
||||||
if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefabHash == 0)) | ||||||
if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefab == null)) | ||||||
{ | ||||||
return; | ||||||
} | ||||||
|
@@ -1594,7 +1687,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? | |||||
// This is not a scene object | ||||||
writer.WriteBool(false); | ||||||
|
||||||
writer.WriteUInt32Packed(playerPrefabHash ?? NetworkConfig.PlayerPrefabHash); | ||||||
writer.WriteUInt32Packed(playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent<NetworkObject>().GlobalObjectIdHash); | ||||||
|
||||||
if (ConnectedClients[ownerClientId].PlayerObject.IncludeTransformWhenSpawning == null || ConnectedClients[ownerClientId].PlayerObject.IncludeTransformWhenSpawning(ownerClientId)) | ||||||
{ | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,7 +81,7 @@ public void HandleConnectionRequest(ulong clientId, Stream stream) | |
} | ||
else | ||
{ | ||
NetworkManager.HandleApproval(clientId, NetworkManager.NetworkConfig.CreatePlayerPrefab, null, true, null, null); | ||
NetworkManager.HandleApproval(clientId, NetworkManager.NetworkConfig.PlayerPrefab != null, null, true, null, null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❤️ |
||
} | ||
} | ||
#if DEVELOPMENT_BUILD || UNITY_EDITOR | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️