Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 159 additions & 86 deletions com.unity.multiplayer.mlapi/Runtime/Core/NetworkedBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ internal void EndSendClientRpc(BitWriter writer, ClientRpcSendParams sendParams,
/// <summary>
/// Gets if we are executing as server
/// </summary>
protected bool IsServer => IsRunning && NetworkingManager.Singleton.IsServer;
protected static bool IsServer => IsRunning && NetworkingManager.Singleton.IsServer;
/// <summary>
/// Gets if we are executing as client
/// </summary>
Expand All @@ -195,7 +195,7 @@ internal void EndSendClientRpc(BitWriter writer, ClientRpcSendParams sendParams,
/// Gets if we are executing as Host, I.E Server and Client
/// </summary>
protected bool IsHost => IsRunning && NetworkingManager.Singleton.IsHost;
private bool IsRunning => NetworkingManager.Singleton != null && NetworkingManager.Singleton.IsListening;
private static bool IsRunning => NetworkingManager.Singleton != null && NetworkingManager.Singleton.IsListening;
/// <summary>
/// Gets Whether or not the object has a owner
/// </summary>
Expand Down Expand Up @@ -330,6 +330,7 @@ protected NetworkedBehaviour GetBehaviour(ushort id)
private readonly List<string> channelsForNetworkedVarGroups = new List<string>();
internal readonly List<INetworkedVar> networkedVarFields = new List<INetworkedVar>();

private static HashSet<MLAPI.NetworkedObject> touched = new HashSet<MLAPI.NetworkedObject>();
private static readonly Dictionary<Type, FieldInfo[]> fieldTypes = new Dictionary<Type, FieldInfo[]>();

private static FieldInfo[] GetFieldInfoForType(Type type)
Expand Down Expand Up @@ -415,122 +416,194 @@ internal void InitializeVars()
}
}

internal void VarUpdate()
#if DEVELOPMENT_BUILD || UNITY_EDITOR
public static ProfilerMarker s_NetworkedBehaviourUpdate = new ProfilerMarker("MLAPI.NetworkedObject.NetworkedBehaviourUpdate");
#endif

internal static void NetworkedBehaviourUpdate()
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
s_NetworkedBehaviourUpdate.Begin();
#endif
try
{
if (IsServer)
{
touched.Clear();
for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++)
{
var client = NetworkingManager.Singleton.ConnectedClientsList[i];
var spawnedObjs = SpawnManager.SpawnedObjectsList;
touched.UnionWith(spawnedObjs);
foreach (var sobj in spawnedObjs)
{
// Sync just the variables for just the objects this client sees
for (int k = 0; k < sobj.childNetworkedBehaviours.Count; k++)
{
sobj.childNetworkedBehaviours[k].VarUpdate(client.ClientId);
}
}
}

// Now, reset all the no-longer-dirty variables
foreach (var sobj in touched)
{
for (int k = 0; k < sobj.childNetworkedBehaviours.Count; k++)
{
sobj.childNetworkedBehaviours[k].PostNetworkVariableWrite();
}
}
}
else
{

// when client updates the sever, it tells it about all its objects
foreach (var sobj in SpawnManager.SpawnedObjectsList)
{
for (int k = 0; k < sobj.childNetworkedBehaviours.Count; k++)
{
sobj.childNetworkedBehaviours[k].VarUpdate(NetworkingManager.Singleton.ServerClientId);
}
}

// Now, reset all the no-longer-dirty variables
foreach (var sobj in SpawnManager.SpawnedObjectsList)
{
for (int k = 0; k < sobj.childNetworkedBehaviours.Count; k++)
{
sobj.childNetworkedBehaviours[k].PostNetworkVariableWrite();
}
}
}

}
finally
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
s_NetworkedBehaviourUpdate.End();
#endif
}
}


internal void PreNetworkVariableWrite()
{
// reset our "which variables got written" data
networkedVarIndexesToReset.Clear();
networkedVarIndexesToResetSet.Clear();
}

internal void PostNetworkVariableWrite()
{
// mark any variables we wrote as no longer dirty
for (int i = 0; i < networkedVarIndexesToReset.Count; i++)
{
networkedVarFields[networkedVarIndexesToReset[i]].ResetDirty();
}
}

internal void VarUpdate(ulong clientId)
{
if (!varInit)
InitializeVars();

NetworkedVarUpdate();
PreNetworkVariableWrite();
NetworkedVarUpdate(clientId);
}

private readonly List<int> networkedVarIndexesToReset = new List<int>();
private readonly HashSet<int> networkedVarIndexesToResetSet = new HashSet<int>();

private void NetworkedVarUpdate()
private void NetworkedVarUpdate(ulong clientId)
{
if (!CouldHaveDirtyNetworkedVars())
return;
if (!CouldHaveDirtyNetworkedVars())
return;

networkedVarIndexesToReset.Clear();
networkedVarIndexesToResetSet.Clear();

for (int i = 0; i < (IsServer ? NetworkingManager.Singleton.ConnectedClientsList.Count : 1); i++)
for (int j = 0; j < channelMappedNetworkedVarIndexes.Count; j++)
{
// Do this check here to prevent doing all the expensive dirty checks
if (!IsServer || this.NetworkedObject.observers.Contains(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId))
using (PooledBitStream stream = PooledBitStream.Get())
{
// This iterates over every "channel group".
for (int j = 0; j < channelMappedNetworkedVarIndexes.Count; j++)
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
{
using (PooledBitStream stream = PooledBitStream.Get())
writer.WriteUInt64Packed(NetworkId);
writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this));

bool writtenAny = false;
for (int k = 0; k < networkedVarFields.Count; k++)
{
using (PooledBitWriter writer = PooledBitWriter.Get(stream))
if (!channelMappedNetworkedVarIndexes[j].Contains(k))
{
writer.WriteUInt64Packed(NetworkId);
writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this));
// This var does not belong to the currently iterating channel group.
if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
writer.WriteUInt16Packed(0);
}
else
{
writer.WriteBool(false);
}
continue;
}

ulong clientId = IsServer ? NetworkingManager.Singleton.ConnectedClientsList[i].ClientId : NetworkingManager.Singleton.ServerClientId;
bool writtenAny = false;
for (int k = 0; k < networkedVarFields.Count; k++)
bool isDirty = networkedVarFields[k].IsDirty(); // cache this here. You never know what operations users will do in the dirty methods

// if I'm dirty AND a client, write (server always has all permissions)
// if I'm dirty AND the server AND the client can read me, send.
bool shouldWrite = isDirty && (!IsServer || networkedVarFields[k].CanClientRead(clientId));

if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
if (!shouldWrite)
{
if (!channelMappedNetworkedVarIndexes[j].Contains(k))
{
// This var does not belong to the currently iterating channel group.
if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
writer.WriteUInt16Packed(0);
}
else
{
writer.WriteBool(false);
}
continue;
}
writer.WriteUInt16Packed(0);
}
}
else
{
writer.WriteBool(shouldWrite);
}

bool isDirty = networkedVarFields[k].IsDirty(); // cache this here. You never know what operations users will do in the dirty methods
bool shouldWrite = isDirty && (!IsServer || networkedVarFields[k].CanClientRead(clientId));
if (shouldWrite)
{
writtenAny = true;

if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
if (!shouldWrite)
{
writer.WriteUInt16Packed(0);
}
}
else
if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
using (PooledBitStream varStream = PooledBitStream.Get())
{
writer.WriteBool(shouldWrite);
}
networkedVarFields[k].WriteDelta(varStream);
varStream.PadStream();

if (shouldWrite)
{
writtenAny = true;

if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
using (PooledBitStream varStream = PooledBitStream.Get())
{
networkedVarFields[k].WriteDelta(varStream);
varStream.PadStream();

writer.WriteUInt16Packed((ushort)varStream.Length);
stream.CopyFrom(varStream);
}
}
else
{
networkedVarFields[k].WriteDelta(stream);
}

if (!networkedVarIndexesToResetSet.Contains(k))
{
networkedVarIndexesToResetSet.Add(k);
networkedVarIndexesToReset.Add(k);
}
writer.WriteUInt16Packed((ushort)varStream.Length);
stream.CopyFrom(varStream);
}
}
else
{
networkedVarFields[k].WriteDelta(stream);
}

if (writtenAny)
if (!networkedVarIndexesToResetSet.Contains(k))
{
if (IsServer)
InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForNetworkedVarGroups[j], stream, SecuritySendFlags.None);
else
InternalMessageSender.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForNetworkedVarGroups[j], stream, SecuritySendFlags.None);
networkedVarIndexesToResetSet.Add(k);
networkedVarIndexesToReset.Add(k);
}
}
}

if (writtenAny)
{
InternalMessageSender.Send(clientId,
MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA,
channelsForNetworkedVarGroups[j], stream, SecuritySendFlags.None);
}
}
}
}

for (int i = 0; i < networkedVarIndexesToReset.Count; i++)
{
networkedVarFields[networkedVarIndexesToReset[i]].ResetDirty();
}
}

private bool CouldHaveDirtyNetworkedVars()
{
// TODO: There should be a better way by reading one dirty variable vs. 'n'
for (int i = 0; i < networkedVarFields.Count; i++)
{
if (networkedVarFields[i].IsDirty())
Expand Down Expand Up @@ -561,7 +634,7 @@ internal static void HandleNetworkedVarDeltas(List<INetworkedVar> networkedVarLi
continue;
}

if (NetworkingManager.Singleton.IsServer && !networkedVarList[i].CanClientWrite(clientId))
if (IsServer && !networkedVarList[i].CanClientWrite(clientId))
{
if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
Expand All @@ -586,7 +659,7 @@ internal static void HandleNetworkedVarDeltas(List<INetworkedVar> networkedVarLi

long readStartPos = stream.Position;

networkedVarList[i].ReadDelta(stream, NetworkingManager.Singleton.IsServer);
networkedVarList[i].ReadDelta(stream, IsServer);
ProfilerStatManager.networkVarsRcvd.Record();

if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
Expand Down Expand Up @@ -629,7 +702,7 @@ internal static void HandleNetworkedVarUpdate(List<INetworkedVar> networkedVarLi
continue;
}

if (NetworkingManager.Singleton.IsServer && !networkedVarList[i].CanClientWrite(clientId))
if (IsServer && !networkedVarList[i].CanClientWrite(clientId))
{
if (NetworkingManager.Singleton.NetworkConfig.EnsureNetworkedVarLengthSafety)
{
Expand Down
34 changes: 0 additions & 34 deletions com.unity.multiplayer.mlapi/Runtime/Core/NetworkedObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ namespace MLAPI
[AddComponentMenu("MLAPI/NetworkedObject", -99)]
public sealed class NetworkedObject : MonoBehaviour
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
public static ProfilerMarker s_NetworkedBehaviourUpdate = new ProfilerMarker("MLAPI.NetworkedObject.NetworkedBehaviourUpdate");
#endif

private void OnValidate()
{
// Set this so the hash can be serialized on Scene objects. For prefabs, they are generated at runtime.
Expand Down Expand Up @@ -540,36 +536,6 @@ internal List<NetworkedBehaviour> childNetworkedBehaviours
}
}

internal static void NetworkedBehaviourUpdate()
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
s_NetworkedBehaviourUpdate.Begin();
#endif

try
{
if (SpawnManager.SpawnedObjectsList.Count == 0)
return;

foreach (var sobj in SpawnManager.SpawnedObjectsList)
{
// Sync all vars
for (int j = 0;
j < sobj.childNetworkedBehaviours.Count;
j++)
{
sobj.childNetworkedBehaviours[j].VarUpdate();
}
}
}
finally
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
s_NetworkedBehaviourUpdate.End();
#endif
}
}

internal void WriteNetworkedVarData(Stream stream, ulong clientId)
{
for (int i = 0; i < childNetworkedBehaviours.Count; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ private void Update()
if (NetworkConfig.EnableNetworkedVar)
{
// Do NetworkedVar updates
NetworkedObject.NetworkedBehaviourUpdate();
NetworkedBehaviour.NetworkedBehaviourUpdate();
}

if (!IsServer && NetworkConfig.EnableMessageBuffering)
Expand Down
Loading