private void OnReceiveGameState(NetworkedGameState receivedGameState) { if (!ShouldApplyStateSnapshots) { return; } if (OsFps.Instance.IsRemoteClient) { Profiler.BeginSample("Client Get Current Networked Game State"); var oldComponentInfoLists = NetLib.GetComponentInfosToSynchronize( receivedGameState.NetworkedComponentTypeInfos ); Profiler.EndSample(); Profiler.BeginSample("Client Apply Networked Game State"); for (var i = 0; i < receivedGameState.NetworkedComponentInfoLists.Count; i++) { var componentInfos = receivedGameState.NetworkedComponentInfoLists[i]; var networkedComponentTypeInfo = receivedGameState.NetworkedComponentTypeInfos[i]; var componentType = networkedComponentTypeInfo.StateType; var oldComponentInfos = oldComponentInfoLists[i]; NetLib.ApplyState( networkedComponentTypeInfo, oldComponentInfos, componentInfos, createGameObjectFromState ); } Profiler.EndSample(); } }
public static void SerializeNetworkedGameState( BinaryWriter writer, NetworkedGameState networkedGameState, NetworkedGameState oldNetworkedGameState ) { for (var i = 0; i < networkedGameState.NetworkedComponentInfoLists.Count; i++) { var networkedComponentTypeInfo = networkedGameState.NetworkedComponentTypeInfos[i]; var componentInfos = networkedGameState.NetworkedComponentInfoLists[i]; var oldComponentInfos = oldNetworkedGameState.NetworkedComponentInfoLists[i]; Serialize(writer, componentInfos, (binaryWriter, componentInfo, index) => { var componentStateId = NetLib.GetIdFromState(networkedComponentTypeInfo, componentInfo.ComponentState); binaryWriter.Write(componentStateId); var oldComponentInfoIndex = oldComponentInfos .FindIndex(oci => NetLib.GetIdFromState(networkedComponentTypeInfo, oci.ComponentState) == componentStateId ); var oldComponentState = (oldComponentInfoIndex >= 0) ? oldComponentInfos[oldComponentInfoIndex].ComponentState : null; var changeMask = GetChangeMask(networkedComponentTypeInfo, componentInfo.ComponentState, oldComponentState); binaryWriter.Write(changeMask); SerializeGivenChangeMask( binaryWriter, networkedComponentTypeInfo, componentInfo.ComponentState, changeMask ); }); } }
private void OnReceiveDataFromServer(int channelId, byte[] bytesReceived, int numBytesReceived) { Profiler.BeginSample("OnReceiveDataFromServer"); using (var memoryStream = new MemoryStream(bytesReceived, 0, numBytesReceived)) { using (var reader = new BinaryReader(memoryStream)) { var messageTypeAsByte = reader.ReadByte(); RpcInfo rpcInfo; if (messageTypeAsByte == NetLib.StateSynchronizationMessageId) { OnReceiveDeltaGameStateFromServer(reader, bytesReceived, numBytesReceived); } else if (NetLib.rpcInfoById.TryGetValue(messageTypeAsByte, out rpcInfo)) { Profiler.BeginSample("Deserialize & Execute RPC"); var rpcArguments = NetworkSerializationUtils.DeserializeRpcCallArguments(rpcInfo, reader); NetLib.ExecuteRpc(rpcInfo.Id, null, ObjectContainingRpcs, rpcArguments); Profiler.EndSample(); } else { throw new NotImplementedException("Unknown message type: " + messageTypeAsByte); } } } Profiler.EndSample(); }
public static NetworkedGameState DeserializeNetworkedGameState( BinaryReader reader, uint sequenceNumber, NetworkedGameState networkedGameStateRelativeTo ) { var networkedComponentTypeInfos = networkedGameStateRelativeTo.NetworkedComponentTypeInfos; var networkedComponentInfoLists = networkedComponentTypeInfos .Select((networkedComponentTypeInfo, networkedComponentTypeInfosIndex) => { var oldComponentInfos = networkedGameStateRelativeTo .NetworkedComponentInfoLists[networkedComponentTypeInfosIndex]; var componentInfos = new List <NetworkedComponentInfo>(); Deserialize(reader, componentInfos, (binaryReader, componentInfoIndex) => { var componentStateId = reader.ReadUInt32(); var oldComponentInfoIndex = oldComponentInfos .FindIndex(oci => NetLib.GetIdFromState(networkedComponentTypeInfo, oci.ComponentState) == componentStateId ); NetworkedComponentInfo oldComponentInfo; if (oldComponentInfoIndex < 0) { var stateType = networkedComponentTypeInfo.StateType; oldComponentInfo = new NetworkedComponentInfo { ComponentState = Activator.CreateInstance(stateType) }; } else { oldComponentInfo = oldComponentInfos[oldComponentInfoIndex]; oldComponentInfo = new NetworkedComponentInfo { ComponentState = ObjectExtensions.DeepCopy(oldComponentInfo.ComponentState) }; } DeserializeDelta( binaryReader, networkedComponentTypeInfo, ref oldComponentInfo ); return(oldComponentInfo); }); return(componentInfos); }) .ToList(); return(new NetworkedGameState { SequenceNumber = sequenceNumber, NetworkedComponentTypeInfos = networkedComponentTypeInfos, NetworkedComponentInfoLists = networkedComponentInfoLists }); }
private NetworkedGameState GetNetworkedGameStateRelativeTo(uint sequenceNumberRelativeTo) { var indexOfGameStateRelativeTo = cachedReceivedGameStates .FindIndex(ngs => ngs.SequenceNumber == sequenceNumberRelativeTo); Assert.IsTrue((indexOfGameStateRelativeTo >= 0) || (sequenceNumberRelativeTo == 0)); return((indexOfGameStateRelativeTo >= 0) ? cachedReceivedGameStates[indexOfGameStateRelativeTo] : NetLib.GetEmptyNetworkedGameStateForDiffing()); }
public NetworkedGameState GetNetworkedGameStateToDiffAgainst(uint playerId) { var playersLatestAcknowledgedGameStateSequenceNumber = latestAcknowledgedGameStateSequenceNumberByPlayerId.GetValueOrDefault(playerId); var indexOfPlayersLatestAcknowledgedGameState = cachedSentGameStates .FindIndex(ngs => ngs.SequenceNumber == playersLatestAcknowledgedGameStateSequenceNumber); var playersLatestAcknowledgedGameState = (indexOfPlayersLatestAcknowledgedGameState >= 0) ? cachedSentGameStates[indexOfPlayersLatestAcknowledgedGameState] : NetLib.GetEmptyNetworkedGameStateForDiffing(); return(playersLatestAcknowledgedGameState); }
private void SendGameState() { // Get the current game state. var currentGameState = NetLib.GetCurrentNetworkedGameState(generateSequenceNumber: true); // Send the game state deltas. foreach (var connectionId in connectionIds) { var oldGameState = networkedGameStateCache.GetNetworkedGameStateToDiffAgainst((uint)connectionId); SendGameStateDiff(connectionId, currentGameState, oldGameState); } // Cache the game state for future deltas. networkedGameStateCache.AddGameState(currentGameState); }
public void Start( ushort?portNumber, int maxPlayerCount, object objectContainingRpcs, float sendGameStateInterval ) { ObjectContainingRpcs = objectContainingRpcs; ShouldSendStateSnapshots = true; sendGameStatePeriodicFunction = new ThrottledAction(SendGameState, sendGameStateInterval); this.maxPlayerCount = maxPlayerCount; var connectionConfig = NetLib.CreateConnectionConfig( out reliableSequencedChannelId, out reliableChannelId, out unreliableStateUpdateChannelId, out unreliableFragmentedChannelId, out unreliableChannelId ); var hostTopology = new HostTopology(connectionConfig, maxPlayerCount); Start(portNumber, hostTopology); }
public void Start(object objectContainingRpcs, Func <object, UnityEngine.GameObject> createGameObjectFromState) { Assert.IsTrue(!IsStarted); ObjectContainingRpcs = objectContainingRpcs; this.createGameObjectFromState = createGameObjectFromState; ShouldApplyStateSnapshots = true; var maxConnectionCount = 1; // The client only connects to the server. var connectionConfig = NetLib.CreateConnectionConfig( out reliableSequencedChannelId, out reliableChannelId, out unreliableStateUpdateChannelId, out unreliableFragmentedChannelId, out unreliableChannelId ); var hostTopology = new HostTopology( connectionConfig, maxConnectionCount ); Start(null, hostTopology); }
private void OnReceiveDataFromClient(int connectionId, int channelId, byte[] bytesReceived, int numBytesReceived) { using (var memoryStream = new MemoryStream(bytesReceived, 0, numBytesReceived)) { using (var reader = new BinaryReader(memoryStream)) { var messageTypeAsByte = reader.ReadByte(); RpcInfo rpcInfo; if (messageTypeAsByte == NetLib.StateSynchronizationMessageId) { throw new System.NotImplementedException("Servers don't support receiving state synchronization messages."); } else if (NetLib.rpcInfoById.TryGetValue(messageTypeAsByte, out rpcInfo)) { var rpcArguments = NetworkSerializationUtils.DeserializeRpcCallArguments(rpcInfo, reader); CurrentRpcSenderConnectionId = connectionId; if (rpcInfo.Name != "ServerOnReceiveClientGameStateAck") { NetLib.ExecuteRpc(rpcInfo.Id, ObjectContainingRpcs, null, rpcArguments); } else { NetLib.ExecuteRpc(rpcInfo.Id, this, null, rpcArguments); } } else { throw new System.NotImplementedException("Unknown message type: " + messageTypeAsByte); } } } }
public static object Deserialize( BinaryReader reader, Type type, bool isNullableIfReferenceType, bool areElementsNullableIfReferenceType ) { var nullableUnderlyingType = Nullable.GetUnderlyingType(type); if ((nullableUnderlyingType == null) && isNullableIfReferenceType && type.IsClass) { nullableUnderlyingType = type; } if (nullableUnderlyingType != null) { var objHasValue = reader.ReadBoolean(); return(objHasValue ? Deserialize( reader, nullableUnderlyingType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: areElementsNullableIfReferenceType ) : null); } else if (type == typeof(bool)) { return(reader.ReadBoolean()); } else if (type == typeof(sbyte)) { return(reader.ReadSByte()); } else if (type == typeof(byte)) { return(reader.ReadByte()); } else if (type == typeof(ushort)) { return(reader.ReadUInt16()); } else if (type == typeof(short)) { return(reader.ReadInt16()); } else if (type == typeof(uint)) { return(reader.ReadUInt32()); } else if (type == typeof(int)) { return(reader.ReadInt32()); } else if (type == typeof(ulong)) { return(reader.ReadUInt64()); } else if (type == typeof(long)) { return(reader.ReadInt64()); } else if (type == typeof(float)) { return(reader.ReadSingle()); } else if (type == typeof(double)) { return(reader.ReadDouble()); } else if (type == typeof(decimal)) { return(reader.ReadDecimal()); } else if (type == typeof(char)) { return(reader.ReadChar()); } else if (type == typeof(string)) { return(reader.ReadString()); } else if (type == typeof(float2)) { var result = new float2(); Deserialize(reader, ref result); return(result); } else if (type == typeof(float3)) { var result = new float3(); Deserialize(reader, ref result); return(result); } else if (type == typeof(float4)) { var result = new float4(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector2)) { var result = new Vector2(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector3)) { var result = new Vector3(); Deserialize(reader, ref result); return(result); } else if (type == typeof(Vector4)) { var result = new Vector4(); Deserialize(reader, ref result); return(result); } else if (typeof(INetworkSerializable).IsAssignableFrom(type)) { var result = Activator.CreateInstance(type); ((INetworkSerializable)result).Deserialize(reader); return(result); } else if (typeof(IEnumerable).IsAssignableFrom(type)) { if (typeof(Array).IsAssignableFrom(type)) { var elementType = type.GetElementType(); var elementCount = reader.ReadUInt32(); var array = Array.CreateInstance(elementType, elementCount); for (var i = 0; i < elementCount; i++) { var element = Deserialize( reader, elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); array.SetValue(element, i); } return(array); } else if (typeof(IList).IsAssignableFrom(type)) { var list = (IList)Activator.CreateInstance(type); var elementType = type.GenericTypeArguments[0]; var elementCount = reader.ReadUInt32(); for (var i = 0; i < elementCount; i++) { var element = Deserialize( reader, elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); list.Add(element); } return(list); } else { throw new NotImplementedException(); } } else { if (type.IsEnum) { var smallestTypeToHoldEnumValues = GetSmallestUIntTypeToHoldEnumValues(type); var enumValueAsInt = Deserialize( reader, smallestTypeToHoldEnumValues, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); return(Enum.ToObject(type, enumValueAsInt)); } else if (type.IsClass || type.IsValueType) { var result = Activator.CreateInstance(type); var objFields = NetLib.GetFieldInfosToSerialize(type); foreach (var objField in objFields) { var fieldValue = Deserialize( reader, objField.FieldType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); objField.SetValue(result, fieldValue); } var objProperties = NetLib.GetPropertyInfosToSerialize(type); foreach (var objProperty in objProperties) { if (!objProperty.CanRead || !objProperty.CanWrite) { continue; } var propertyValue = Deserialize( reader, objProperty.PropertyType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); objProperty.SetValue(result, propertyValue); } return(result); } else { throw new NotImplementedException($"Cannot deserialize type: {type.AssemblyQualifiedName}"); } } }
public static void SerializeObject( BinaryWriter writer, object obj, Type overrideType, bool isNullableIfReferenceType, bool areElementsNullableIfReferenceType ) { Assert.IsTrue(!isNullableIfReferenceType || (overrideType != null)); var objType = overrideType ?? obj?.GetType(); Assert.IsNotNull(objType); Assert.IsTrue((obj != null) || !objType.IsClass || isNullableIfReferenceType); var nullableUnderlyingType = Nullable.GetUnderlyingType(objType); if ((nullableUnderlyingType == null) && isNullableIfReferenceType && objType.IsClass) { nullableUnderlyingType = objType; } if (nullableUnderlyingType != null) { writer.Write(obj != null); if (obj != null) { objType = nullableUnderlyingType; } else { return; } } if (objType == typeof(bool)) { writer.Write((bool)obj); } else if (objType == typeof(sbyte)) { writer.Write((sbyte)obj); } else if (objType == typeof(byte)) { writer.Write((byte)obj); } else if (objType == typeof(ushort)) { writer.Write((ushort)obj); } else if (objType == typeof(short)) { writer.Write((short)obj); } else if (objType == typeof(uint)) { writer.Write((uint)obj); } else if (objType == typeof(int)) { writer.Write((int)obj); } else if (objType == typeof(ulong)) { writer.Write((ulong)obj); } else if (objType == typeof(long)) { writer.Write((long)obj); } else if (objType == typeof(float)) { writer.Write((float)obj); } else if (objType == typeof(double)) { writer.Write((double)obj); } else if (objType == typeof(decimal)) { writer.Write((decimal)obj); } else if (objType == typeof(char)) { writer.Write((char)obj); } else if (objType == typeof(string)) { writer.Write((string)obj); } else if (objType == typeof(float2)) { Serialize(writer, (float2)obj); } else if (objType == typeof(float3)) { Serialize(writer, (float3)obj); } else if (objType == typeof(float4)) { Serialize(writer, (float4)obj); } else if (objType == typeof(Vector2)) { Serialize(writer, (Vector2)obj); } else if (objType == typeof(Vector3)) { Serialize(writer, (Vector3)obj); } else if (objType == typeof(Vector4)) { Serialize(writer, (Vector4)obj); } else if (typeof(INetworkSerializable).IsAssignableFrom(obj.GetType())) { ((INetworkSerializable)obj).Serialize(writer); } else if (typeof(ICollection).IsAssignableFrom(objType)) { Type elementType; if (objType.IsArray) { elementType = objType.GetElementType(); } else if (objType.IsGenericType) { elementType = objType.GetGenericArguments()[0]; } else { throw new NotImplementedException("Non-generic collections aren't supported."); } var collection = (ICollection)obj; writer.Write((uint)collection.Count); foreach (var element in collection) { SerializeObject( writer, element, overrideType: elementType, isNullableIfReferenceType: areElementsNullableIfReferenceType, areElementsNullableIfReferenceType: false ); } } else { if (objType.IsEnum) { var smallestTypeToHoldEnumValues = GetSmallestUIntTypeToHoldEnumValues(objType); var objToSerialize = Convert.ChangeType(obj, smallestTypeToHoldEnumValues); SerializeObject( writer, objToSerialize, overrideType: null, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } else if (objType.IsClass || objType.IsValueType) { var objFields = NetLib.GetFieldInfosToSerialize(objType); foreach (var objField in objFields) { SerializeObject( writer, objField.GetValue(obj), objField.FieldType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } var objProperties = NetLib.GetPropertyInfosToSerialize(objType); foreach (var objProperty in objProperties) { if (!objProperty.CanRead || !objProperty.CanWrite) { continue; } SerializeObject( writer, objProperty.GetValue(obj), objProperty.PropertyType, isNullableIfReferenceType: false, areElementsNullableIfReferenceType: false ); } } else { throw new NotImplementedException($"Cannot serialize type: {objType.AssemblyQualifiedName}"); } } }