internal static void HandleNetworkVariableUpdate(List <INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance) { using (var reader = PooledNetworkReader.Get(stream)) { for (int i = 0; i < networkVariableList.Count; i++) { ushort varSize = 0; if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety) { varSize = reader.ReadUInt16Packed(); if (varSize == 0) { continue; } } else { if (!reader.ReadBool()) { continue; } } if (IsServer && !networkVariableList[i].CanClientWrite(clientId)) { if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Client wrote to {nameof(NetworkVariable)} without permission. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}"); } stream.Position += varSize; continue; } //This client wrote somewhere they are not allowed. This is critical //We can't just skip this field. Because we don't actually know how to dummy read //That is, we don't know how many bytes to skip. Because the interface doesn't have a //Read that gives us the value. Only a Read that applies the value straight away //A dummy read COULD be added to the interface for this situation, but it's just being too nice. //This is after all a developer fault. A critical error should be fine. // - TwoTen if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { NetworkLog.LogError($"Client wrote to {nameof(NetworkVariable)} 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)}"); } return; } long readStartPos = stream.Position; networkVariableList[i].ReadField(stream, NetworkTickSystem.NoTick, NetworkTickSystem.NoTick); PerformanceDataManager.Increment(ProfilerConstants.NetworkVarUpdates); ProfilerStatManager.NetworkVarsRcvd.Record(); if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (stream is NetworkBuffer networkBuffer) { networkBuffer.SkipPadBits(); } if (stream.Position > (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { 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)}"); } stream.Position = readStartPos + varSize; } else if (stream.Position < (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { 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)}"); } stream.Position = readStartPos + varSize; } } } } }
internal static void SetNetworkVariableData(List <INetworkVariable> networkVariableList, Stream stream) { if (networkVariableList.Count == 0) { return; } using (var reader = PooledNetworkReader.Get(stream)) { for (int j = 0; j < networkVariableList.Count; j++) { ushort varSize = 0; if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety) { varSize = reader.ReadUInt16Packed(); if (varSize == 0) { continue; } } else { if (!reader.ReadBool()) { continue; } } long readStartPos = stream.Position; networkVariableList[j].ReadField(stream, NetworkTickSystem.NoTick, NetworkTickSystem.NoTick); if (NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (stream is NetworkBuffer networkBuffer) { networkBuffer.SkipPadBits(); } if (stream.Position > (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var data read too far. {stream.Position - (readStartPos + varSize)} bytes."); } stream.Position = readStartPos + varSize; } else if (stream.Position < (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var data read too little. {(readStartPos + varSize) - stream.Position} bytes."); } stream.Position = readStartPos + varSize; } } } } }
/// <inheritdoc /> public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { ushort deltaCount = reader.ReadUInt16Packed(); for (int i = 0; i < deltaCount; i++) { NetworkSetEvent <T> .EventType eventType = (NetworkSetEvent <T> .EventType)reader.ReadBits(2); switch (eventType) { case NetworkSetEvent <T> .EventType.Add: { T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Add(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType, Value = value }); } } break; case NetworkSetEvent <T> .EventType.Remove: { T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Remove(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType, Value = value }); } } break; case NetworkSetEvent <T> .EventType.Clear: { //Read nothing m_Set.Clear(); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType }); } } break; } } } }