Skip to content

Commit 611678a

Browse files
feat!: network variables - client auth, permission cleanup, containers (#1074)
* refactor!: convert NetworkTransform.NetworkState to `struct` * feat!: remove client network permissions [MTT-1019] * NetworkList is now a derived class * de-interface * removed valueRef * added host tests * updated NetworkVarBufferCopyTest * container cleanup * channel cleanup * fixed client perm, more perm tests * INetworkVariable -> NetworkVariableBase * remove NetworkVariableBase.SetNetworkBehaviour() * fix tools project tests Co-authored-by: M. Fatih MAR <mfatihmar@gmail.com>
1 parent fbfcc94 commit 611678a

24 files changed

+716
-1199
lines changed

com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,15 @@ private void RenderNetworkVariable(int index)
5858
if (value == null)
5959
{
6060
var fieldType = m_NetworkVariableFields[m_NetworkVariableNames[index]].FieldType;
61-
var networkVariable = (INetworkVariable)Activator.CreateInstance(fieldType, true);
61+
var networkVariable = (NetworkVariableBase)Activator.CreateInstance(fieldType, true);
6262
m_NetworkVariableFields[m_NetworkVariableNames[index]].SetValue(target, networkVariable);
6363
}
6464

6565
var type = m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target).GetType();
6666
var genericType = type.GetGenericArguments()[0];
6767

6868
EditorGUILayout.BeginHorizontal();
69-
if (genericType == typeof(string))
70-
{
71-
var networkVariable = (NetworkVariable<string>)m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target);
72-
networkVariable.Value = EditorGUILayout.TextField(m_NetworkVariableNames[index], networkVariable.Value);
73-
}
74-
else if (genericType.IsValueType)
69+
if (genericType.IsValueType)
7570
{
7671
var method = typeof(NetworkBehaviourEditor).GetMethod("RenderNetworkVariableValueType", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic);
7772
var genericMethod = method.MakeGenericMethod(genericType);
@@ -86,7 +81,7 @@ private void RenderNetworkVariable(int index)
8681
EditorGUILayout.EndHorizontal();
8782
}
8883

89-
private void RenderNetworkVariableValueType<T>(int index) where T : struct
84+
private void RenderNetworkVariableValueType<T>(int index) where T : unmanaged
9085
{
9186
var networkVariable = (NetworkVariable<T>)m_NetworkVariableFields[m_NetworkVariableNames[index]].GetValue(target);
9287
var type = typeof(T);

com.unity.netcode.gameobjects/Prototyping/NetworkTransform.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,6 @@ public void NetworkSerialize(NetworkSerializer serializer)
128128
}
129129
}
130130

131-
/// <summary>
132-
/// The network channel to use send updates
133-
/// </summary>
134-
[Tooltip("The network channel to use send updates")]
135-
public NetworkChannel Channel = NetworkChannel.NetworkVariable;
136-
137131
/// <summary>
138132
/// Sets whether this transform should sync in local space or in world space.
139133
/// This is important to set since reparenting this transform could have issues,
@@ -156,6 +150,7 @@ public void NetworkSerialize(NetworkSerializer serializer)
156150
public float FixedSendsPerSecond = 30f;
157151

158152
private Transform m_Transform; // cache the transform component to reduce unnecessary bounce between managed and native
153+
internal NetworkState LocalNetworkState;
159154
internal readonly NetworkVariable<NetworkState> ReplNetworkState = new NetworkVariable<NetworkState>(new NetworkState());
160155
internal NetworkState PrevNetworkState;
161156

@@ -364,10 +359,6 @@ private void OnNetworkStateChanged(NetworkState oldState, NetworkState newState)
364359
private void Awake()
365360
{
366361
m_Transform = transform;
367-
368-
ReplNetworkState.Settings.SendNetworkChannel = Channel;
369-
ReplNetworkState.Settings.SendTickrate = FixedSendsPerSecond;
370-
371362
ReplNetworkState.OnValueChanged += OnNetworkStateChanged;
372363
}
373364

@@ -385,7 +376,13 @@ private void FixedUpdate()
385376

386377
if (IsServer)
387378
{
388-
ReplNetworkState.SetDirty(UpdateNetworkState(ref ReplNetworkState.ValueRef));
379+
// try to update local NetworkState
380+
if (UpdateNetworkState(ref LocalNetworkState))
381+
{
382+
// if updated (dirty), change NetVar, mark it dirty
383+
ReplNetworkState.Value = LocalNetworkState;
384+
ReplNetworkState.SetDirty(true);
385+
}
389386
}
390387
// try to update previously consumed NetworkState
391388
// if we have any changes, that means made some updates locally

com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs

Lines changed: 13 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ public virtual void OnNetworkObjectParentChanged(NetworkObject parentNetworkObje
366366

367367
private readonly List<HashSet<int>> m_ChannelMappedNetworkVariableIndexes = new List<HashSet<int>>();
368368
private readonly List<NetworkChannel> m_ChannelsForNetworkVariableGroups = new List<NetworkChannel>();
369-
internal readonly List<INetworkVariable> NetworkVariableFields = new List<INetworkVariable>();
369+
internal readonly List<NetworkVariableBase> NetworkVariableFields = new List<NetworkVariableBase>();
370370

371371
private static Dictionary<Type, FieldInfo[]> s_FieldTypes = new Dictionary<Type, FieldInfo[]>();
372372

@@ -415,19 +415,19 @@ internal void InitializeVariables()
415415
{
416416
Type fieldType = sortedFields[i].FieldType;
417417

418-
if (fieldType.HasInterface(typeof(INetworkVariable)))
418+
if (fieldType.IsSubclassOf(typeof(NetworkVariableBase)))
419419
{
420-
var instance = (INetworkVariable)sortedFields[i].GetValue(this);
420+
var instance = (NetworkVariableBase)sortedFields[i].GetValue(this);
421421

422422
if (instance == null)
423423
{
424-
instance = (INetworkVariable)Activator.CreateInstance(fieldType, true);
424+
instance = (NetworkVariableBase)Activator.CreateInstance(fieldType, true);
425425
sortedFields[i].SetValue(this, instance);
426426
}
427427

428-
instance.SetNetworkBehaviour(this);
428+
instance.NetworkBehaviour = this;
429429

430-
var instanceNameProperty = fieldType.GetProperty(nameof(INetworkVariable.Name));
430+
var instanceNameProperty = fieldType.GetProperty(nameof(NetworkVariableBase.Name));
431431
var sanitizedVariableName = sortedFields[i].Name.Replace("<", string.Empty).Replace(">k__BackingField", string.Empty);
432432
instanceNameProperty?.SetValue(instance, sanitizedVariableName);
433433

@@ -442,7 +442,7 @@ internal void InitializeVariables()
442442

443443
for (int i = 0; i < NetworkVariableFields.Count; i++)
444444
{
445-
NetworkChannel networkChannel = NetworkVariableFields[i].GetChannel();
445+
var networkChannel = NetworkVariableBase.NetworkVariableChannel;
446446

447447
if (!firstLevelIndex.ContainsKey(networkChannel))
448448
{
@@ -514,6 +514,7 @@ private void NetworkVariableUpdate(ulong clientId, int behaviourIndex)
514514
{
515515
using (var writer = PooledNetworkWriter.Get(buffer))
516516
{
517+
// TODO: could skip this if no variables dirty, though obsolete w/ Snapshot
517518
writer.WriteUInt64Packed(NetworkObjectId);
518519
writer.WriteUInt16Packed(NetworkObject.GetNetworkBehaviourOrderIndex(this));
519520

@@ -537,14 +538,9 @@ private void NetworkVariableUpdate(ulong clientId, int behaviourIndex)
537538
continue;
538539
}
539540

540-
bool isDirty =
541-
NetworkVariableFields[k]
542-
.IsDirty(); // cache this here. You never know what operations users will do in the dirty methods
543-
544541
// if I'm dirty AND a client, write (server always has all permissions)
545542
// if I'm dirty AND the server AND the client can read me, send.
546-
bool shouldWrite = isDirty &&
547-
(!IsServer || NetworkVariableFields[k].CanClientRead(clientId));
543+
bool shouldWrite = NetworkVariableFields[k].ShouldWrite(clientId, IsServer);
548544

549545
if (NetworkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
550546
{
@@ -628,7 +624,7 @@ private bool CouldHaveDirtyNetworkVariables()
628624
return false;
629625
}
630626

631-
internal static void HandleNetworkVariableDeltas(List<INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance, NetworkManager networkManager)
627+
internal static void HandleNetworkVariableDeltas(List<NetworkVariableBase> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance, NetworkManager networkManager)
632628
{
633629
using (var reader = PooledNetworkReader.Get(stream))
634630
{
@@ -655,6 +651,7 @@ internal static void HandleNetworkVariableDeltas(List<INetworkVariable> networkV
655651

656652
if (networkManager.IsServer && !networkVariableList[i].CanClientWrite(clientId))
657653
{
654+
// we are choosing not to fire an exception here, because otherwise a malicious client could use this to crash the server
658655
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
659656
{
660657
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
@@ -674,7 +671,6 @@ internal static void HandleNetworkVariableDeltas(List<INetworkVariable> networkV
674671
//A dummy read COULD be added to the interface for this situation, but it's just being too nice.
675672
//This is after all a developer fault. A critical error should be fine.
676673
// - TwoTen
677-
678674
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
679675
{
680676
NetworkLog.LogError($"Client wrote to {typeof(NetworkVariable<>).Name} without permission. No more variables can be read. This is critical. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
@@ -683,7 +679,6 @@ internal static void HandleNetworkVariableDeltas(List<INetworkVariable> networkV
683679

684680
return;
685681
}
686-
687682
long readStartPos = stream.Position;
688683

689684
networkVariableList[i].ReadDelta(stream, networkManager.IsServer);
@@ -722,95 +717,7 @@ internal static void HandleNetworkVariableDeltas(List<INetworkVariable> networkV
722717
}
723718
}
724719

725-
internal static void HandleNetworkVariableUpdate(List<INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance, NetworkManager networkManager)
726-
{
727-
using (var reader = PooledNetworkReader.Get(stream))
728-
{
729-
for (int i = 0; i < networkVariableList.Count; i++)
730-
{
731-
ushort varSize = 0;
732-
733-
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
734-
{
735-
varSize = reader.ReadUInt16Packed();
736-
737-
if (varSize == 0)
738-
{
739-
continue;
740-
}
741-
}
742-
else
743-
{
744-
if (!reader.ReadBool())
745-
{
746-
continue;
747-
}
748-
}
749-
750-
if (networkManager.IsServer && !networkVariableList[i].CanClientWrite(clientId))
751-
{
752-
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
753-
{
754-
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
755-
{
756-
NetworkLog.LogWarning($"Client wrote to {typeof(NetworkVariable<>).Name} without permission. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
757-
}
758-
759-
stream.Position += varSize;
760-
continue;
761-
}
762-
763-
//This client wrote somewhere they are not allowed. This is critical
764-
//We can't just skip this field. Because we don't actually know how to dummy read
765-
//That is, we don't know how many bytes to skip. Because the interface doesn't have a
766-
//Read that gives us the value. Only a Read that applies the value straight away
767-
//A dummy read COULD be added to the interface for this situation, but it's just being too nice.
768-
//This is after all a developer fault. A critical error should be fine.
769-
// - TwoTen
770-
if (NetworkLog.CurrentLogLevel <= LogLevel.Error)
771-
{
772-
NetworkLog.LogError($"Client wrote to {typeof(NetworkVariable<>).Name} without permission. No more variables can be read. This is critical. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
773-
}
774-
775-
return;
776-
}
777-
778-
long readStartPos = stream.Position;
779-
780-
networkVariableList[i].ReadField(stream);
781-
782-
if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety)
783-
{
784-
if (stream is NetworkBuffer networkBuffer)
785-
{
786-
networkBuffer.SkipPadBits();
787-
}
788-
789-
if (stream.Position > (readStartPos + varSize))
790-
{
791-
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
792-
{
793-
NetworkLog.LogWarning($"Var update read too far. {stream.Position - (readStartPos + varSize)} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
794-
}
795-
796-
stream.Position = readStartPos + varSize;
797-
}
798-
else if (stream.Position < (readStartPos + varSize))
799-
{
800-
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
801-
{
802-
NetworkLog.LogWarning($"Var update read too little. {(readStartPos + varSize) - stream.Position} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}");
803-
}
804-
805-
stream.Position = readStartPos + varSize;
806-
}
807-
}
808-
}
809-
}
810-
}
811-
812-
813-
internal static void WriteNetworkVariableData(List<INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkManager networkManager)
720+
internal static void WriteNetworkVariableData(List<NetworkVariableBase> networkVariableList, Stream stream, ulong clientId, NetworkManager networkManager)
814721
{
815722
if (networkVariableList.Count == 0)
816723
{
@@ -858,7 +765,7 @@ internal static void WriteNetworkVariableData(List<INetworkVariable> networkVari
858765
}
859766
}
860767

861-
internal static void SetNetworkVariableData(List<INetworkVariable> networkVariableList, Stream stream, NetworkManager networkManager)
768+
internal static void SetNetworkVariableData(List<NetworkVariableBase> networkVariableList, Stream stream, NetworkManager networkManager)
862769
{
863770
if (networkVariableList.Count == 0)
864771
{

com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviourUpdater.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@ internal void NetworkBehaviourUpdate(NetworkManager networkManager)
5050
// when client updates the server, it tells it about all its objects
5151
foreach (var sobj in networkManager.SpawnManager.SpawnedObjectsList)
5252
{
53-
for (int k = 0; k < sobj.ChildNetworkBehaviours.Count; k++)
53+
if (sobj.IsOwner)
5454
{
55-
sobj.ChildNetworkBehaviours[k].VariableUpdate(networkManager.ServerClientId);
55+
for (int k = 0; k < sobj.ChildNetworkBehaviours.Count; k++)
56+
{
57+
sobj.ChildNetworkBehaviours[k].VariableUpdate(networkManager.ServerClientId);
58+
}
5659
}
5760
}
5861

com.unity.netcode.gameobjects/Runtime/Core/SnapshotSystem.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ internal void ProcessSingleAck(ushort ackSequence, ulong clientId, ClientData cl
558558
/// This will look into all spawned objects
559559
/// </summary>
560560
/// <param name="key">The key to search for</param>
561-
private INetworkVariable FindNetworkVar(VariableKey key)
561+
private NetworkVariableBase FindNetworkVar(VariableKey key)
562562
{
563563
var spawnedObjects = NetworkManager.SpawnManager.SpawnedObjects;
564564

@@ -895,7 +895,7 @@ internal void Despawn(SnapshotDespawnCommand command)
895895
/// Might not happen for all variable on every frame. Might even happen more than once.
896896
/// </summary>
897897
/// <param name="networkVariable">The NetworkVariable to write, or rather, its INetworkVariable</param>
898-
internal void Store(ulong networkObjectId, int behaviourIndex, int variableIndex, INetworkVariable networkVariable)
898+
internal void Store(ulong networkObjectId, int behaviourIndex, int variableIndex, NetworkVariableBase networkVariable)
899899
{
900900
VariableKey k;
901901
k.NetworkObjectId = networkObjectId;
@@ -914,7 +914,7 @@ internal void Store(ulong networkObjectId, int behaviourIndex, int variableIndex
914914
WriteVariableToSnapshot(m_Snapshot, networkVariable, pos);
915915
}
916916

917-
private void WriteVariableToSnapshot(Snapshot snapshot, INetworkVariable networkVariable, int index)
917+
private void WriteVariableToSnapshot(Snapshot snapshot, NetworkVariableBase networkVariable, int index)
918918
{
919919
// write var into buffer, possibly adjusting entry's position and Length
920920
using (var varBuffer = PooledNetworkBuffer.Get())

0 commit comments

Comments
 (0)