public NetworkReader(byte[] buffer, NetworkSchema schema) { m_Input = new ByteInputStream(buffer); m_Schema = schema; m_CurrentField = null; m_NextFieldIndex = 0; }
public CreateNetworkDialog(NetworkSchema schema) { InitializeComponent(); this.m_networkSchema = schema; this.cbHiddenLayerNumber.DataSource = new int[] { 0, 1, 2, 3, 4 }; }
static void TestDelta <TInputStream, TOutputStream>(NetworkSchema schema, List <object> values, List <object> baselineValues) where TInputStream : NetworkCompression.IInputStream, new() where TOutputStream : NetworkCompression.IOutputStream, new() { var inputBuffer = new byte[1024 * 64]; var baselineBuffer = new byte[1024 * 64]; var deltaBuffer = new byte[1024 * 64]; var outputBuffer = new byte[1024 * 64]; NetworkTestUtils.WriteValues(values, inputBuffer, schema); if (baselineValues != null) { NetworkTestUtils.WriteValues(baselineValues, baselineBuffer, schema); } else { baselineBuffer = new byte[1024 * 64]; } var outputStream = new TOutputStream(); outputStream.Initialize(NetworkCompressionModel.DefaultModel, deltaBuffer, 0, null); uint hash = 0; DeltaWriter.Write(ref outputStream, schema, inputBuffer, baselineBuffer, zeroFieldsChanged, 0, ref hash); outputStream.Flush(); var inputStream = new TInputStream(); inputStream.Initialize(NetworkCompressionModel.DefaultModel, deltaBuffer, 0); hash = 0; DeltaReader.Read(ref inputStream, schema, outputBuffer, baselineBuffer, zeroFieldsChanged, 0, ref hash); NetworkTestUtils.ReadAndAssertValues(values, outputBuffer, schema); }
public void Delta_Vector3Compressed <TInputStream, TOutputStream>() where TInputStream : NetworkCompression.IInputStream, new() where TOutputStream : NetworkCompression.IOutputStream, new() { var schema = new NetworkSchema(0); schema.AddField(new NetworkSchema.FieldInfo() { name = "field_0", fieldType = NetworkSchema.FieldType.Vector3, bits = 32, delta = true, precision = 3 }); var values = new List <object>() { new Vector3() { x = 0.07870922f, y = 0.0479902327f, z = 0.16897355f } }; var baseline = new List <object>() { new Vector3() { x = -122.123f, y = 112.32112f, z = 0.0235f } }; TestDelta <TInputStream, TOutputStream>(schema, values, baseline); }
// private NetworkSchema m_networkSchema; //--------------------------------------------- #region Constructor public CreateNetworkDialog(NetworkSchema schema) { InitializeComponent(); this.m_networkSchema = schema; this.cbHiddenLayerNumber.DataSource = new int[] { 0, 1, 2, 3, 4 }; }
void ReadCommands(ref RawInputStream input) { counters.commandsIn++; var schema = input.ReadRawBits(1) != 0; if (schema) { commandSchema = NetworkSchema.ReadSchema(ref input); // might be overridden } // NETTODO Reconstruct the wide sequence // NETTODO Rename to commandMessageSequence? var sequence = Sequence.FromUInt16((ushort)input.ReadRawBits(16), commandSequenceIn); if (sequence > commandSequenceIn) { commandSequenceIn = sequence; } CommandInfo previous = defaultCommandInfo; while (input.ReadRawBits(1) != 0) { var command = commandsIn.Acquire(sequence); command.time = (int)input.ReadPackedIntDelta(previous.time, NetworkConfig.commandTimeContext); uint hash = 0; DeltaReader.Read(ref input, commandSchema, command.data, previous.data, zeroFieldsChanged, 0, ref hash); previous = command; --sequence; } }
public NetworkReader(uint *buffer, NetworkSchema schema) { m_Input = buffer; m_Position = 0; m_Schema = schema; m_CurrentField = null; m_NextFieldIndex = 0; }
public NetworkWriter(byte[] buffer, NetworkSchema schema, bool generateSchema = false) { m_Output = new ByteOutputStream(buffer); m_Schema = schema; m_CurrentField = null; m_NextFieldIndex = 0; m_GenerateSchema = generateSchema; m_FieldMask = 0; }
public NetworkWriter(uint *buffer, int bufferSize, NetworkSchema schema, bool generateSchema = false) { m_Output = buffer; m_BufferSize = bufferSize; m_Position = 0; m_Schema = schema; m_CurrentField = null; m_NextFieldIndex = 0; m_GenerateSchema = generateSchema; m_FieldMask = 0; }
public static void CopyFieldsFromBuffer <TOutputStream>(NetworkSchema schema, byte[] inputBuffer, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { var input = new ByteInputStream(inputBuffer); int fieldIndex = 0; for (; fieldIndex < schema.fields.Count; ++fieldIndex) { var field = schema.fields[fieldIndex]; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: output.WriteRawBits(input.ReadBits(field.bits), field.bits); break; case NetworkSchema.FieldType.Vector2: output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); break; case NetworkSchema.FieldType.Vector3: output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); break; case NetworkSchema.FieldType.Quaternion: output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); output.WriteRawBits(input.ReadUInt32(), field.bits); break; case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { byte[] data; int dataIndex; int dataSize; input.GetByteArray(out data, out dataIndex, out dataSize, field.arraySize); output.WritePackedUInt((uint)dataSize, field.startContext); output.WriteRawBytes(data, dataIndex, dataSize); } break; default: GameDebug.Assert(false); break; } } }
unsafe public static void CopyFieldsFromBuffer <TOutputStream>(NetworkSchema schema, uint *inputBuffer, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { int index = 0; int fieldIndex = 0; for (; fieldIndex < schema.fieldsInternal.Count; ++fieldIndex) { var field = schema.fieldsInternal[fieldIndex]; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); break; case NetworkSchema.FieldType.Vector2: output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); break; case NetworkSchema.FieldType.Vector3: output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); break; case NetworkSchema.FieldType.Quaternion: output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); output.WritePackedUInt(inputBuffer[index++], NetworkConfig.miscContext); break; case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { uint dataSize = inputBuffer[index++]; output.WritePackedUInt(dataSize, field.startContext); output.WriteRawBytes((byte *)(inputBuffer + index), (int)dataSize); index += field.arraySize / 4; } break; default: GameDebug.Assert(false); break; } } }
public static void WriteSchema <TOutputStream>(NetworkSchema schema, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { output.WritePackedUInt((uint)schema.fields.Count, NetworkConfig.miscContext); output.WritePackedUInt((uint)schema.id, NetworkConfig.miscContext); foreach (var field in schema.fields) { output.WriteRawBits((uint)field.fieldType, 4); output.WriteRawBits(field.delta ? 1U : 0, 1); output.WriteRawBits((uint)field.bits, 6); output.WriteRawBits((uint)field.precision, 2); output.WriteRawBits((uint)field.arraySize, 16); output.WriteRawBits((uint)field.fieldMask, 8); } }
public static void WriteSchema <TOutputStream>(NetworkSchema schema, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { output.WritePackedUInt((uint)schema.fieldsInternal.Count, NetworkConfig.miscContext); output.WritePackedUInt((uint)schema.id, NetworkConfig.miscContext); for (int i = 0; i < schema.numFields; ++i) { var field = schema.fields[i]; output.WritePackedNibble((uint)field.fieldType, NetworkConfig.miscContext); output.WriteRawBits(field.delta ? 1U : 0, 1); output.WritePackedUInt((uint)field.bits, NetworkConfig.miscContext); output.WritePackedUInt((uint)field.precision, NetworkConfig.miscContext); output.WritePackedUInt((uint)field.arraySize, NetworkConfig.miscContext); output.WritePackedUInt((uint)field.fieldMask, NetworkConfig.miscContext); } }
unsafe private void WriteMapInfo(ref RawOutputStream output) { AddMessageContentFlag(NetworkMessage.MapInfo); output.WriteRawBits(_server.m_MapInfo.mapId, 16); // Write schema if client haven't acked it output.WriteRawBits(mapSchemaAcked ? 0 : 1U, 1); if (!mapSchemaAcked) { NetworkSchema.WriteSchema(_server.m_MapInfo.schema, ref output); } // Write map data NetworkSchema.CopyFieldsFromBuffer(_server.m_MapInfo.schema, _server.m_MapInfo.data, ref output); }
public void Delta_FloatCompressedNoBaseline <TInputStream, TOutputStream>() where TInputStream : NetworkCompression.IInputStream, new() where TOutputStream : NetworkCompression.IOutputStream, new() { var schema = new NetworkSchema(0); schema.AddField(new NetworkSchema.FieldInfo() { name = "field_0", fieldType = NetworkSchema.FieldType.Float, bits = 32, delta = true, precision = 3 }); var values = new List <object>() { 0.123f }; TestDelta <TInputStream, TOutputStream>(schema, values, null); }
public void QueueCommand(int time, DataGenerator generator) { var generateSchema = (commandSchema == null); if (generateSchema) { commandSchema = new NetworkSchema(NetworkConfig.networkClientQueueCommandSchemaId); } var info = commandsOut.Acquire(++commandSequence); info.time = time; var writer = new NetworkWriter(info.data, commandSchema, generateSchema); generator(ref writer); writer.Flush(); }
public static void CopyFieldsToBuffer <TInputStream>(NetworkSchema schema, ref TInputStream input, byte[] outputBuffer) where TInputStream : NetworkCompression.IInputStream { var output = new ByteOutputStream(outputBuffer); for (var fieldIndex = 0; fieldIndex < schema.fields.Count; ++fieldIndex) { var field = schema.fields[fieldIndex]; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: output.WriteBits(input.ReadRawBits(field.bits), field.bits); break; case NetworkSchema.FieldType.Vector2: output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); break; case NetworkSchema.FieldType.Vector3: output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); break; case NetworkSchema.FieldType.Quaternion: output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); output.WriteUInt32(input.ReadRawBits(field.bits)); break; case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: output.CopyByteArray(ref input, field.arraySize, field.startContext); break; default: GameDebug.Assert(false); break; } } }
public static NetworkSchema ReadSchema <TInputStream>(ref TInputStream input) where TInputStream : NetworkCompression.IInputStream { int count = (int)input.ReadPackedUInt(NetworkConfig.miscContext); int id = (int)input.ReadPackedUInt(NetworkConfig.miscContext); var schema = new NetworkSchema(id); for (int i = 0; i < count; ++i) { var field = new FieldInfo(); field.fieldType = (FieldType)input.ReadRawBits(4); field.delta = input.ReadRawBits(1) != 0; field.bits = (int)input.ReadRawBits(6); field.precision = (int)input.ReadRawBits(2); field.arraySize = (int)input.ReadRawBits(16); field.startContext = schema.fields.Count * NetworkConfig.maxContextsPerField + schema.id * NetworkConfig.maxContextsPerSchema + NetworkConfig.firstSchemaContext; field.fieldMask = (byte)input.ReadRawBits(8); schema.AddField(field); } return(schema); }
public static void SkipFields <TInputStream>(NetworkSchema schema, ref TInputStream input) where TInputStream : NetworkCompression.IInputStream { for (var fieldIndex = 0; fieldIndex < schema.fieldsInternal.Count; ++fieldIndex) { var field = schema.fieldsInternal[fieldIndex]; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: input.ReadRawBits(field.bits); break; case NetworkSchema.FieldType.Vector2: input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); break; case NetworkSchema.FieldType.Vector3: input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); break; case NetworkSchema.FieldType.Quaternion: input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); input.ReadRawBits(field.bits); break; case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: input.SkipRawBytes((int)input.ReadPackedUInt(field.startContext)); break; default: GameDebug.Assert(false); break; } } }
public static NetworkSchema ReadSchema(ref RawInputStream input) { int count = (int)input.ReadPackedUInt(NetworkConfig.miscContext); int id = (int)input.ReadPackedUInt(NetworkConfig.miscContext); var schema = new NetworkSchema(id); for (int i = 0; i < count; ++i) { var field = new FieldInfo(); field.fieldType = (FieldType)input.ReadPackedNibble(NetworkConfig.miscContext); field.delta = input.ReadRawBits(1) != 0; field.bits = (int)input.ReadPackedUInt(NetworkConfig.miscContext); field.precision = (int)input.ReadPackedUInt(NetworkConfig.miscContext); field.arraySize = (int)input.ReadPackedUInt(NetworkConfig.miscContext); field.startContext = schema.fieldsInternal.Count * NetworkConfig.maxContextsPerField + schema.id * NetworkConfig.maxContextsPerSchema + NetworkConfig.firstSchemaContext; field.fieldMask = (byte)input.ReadPackedUInt(NetworkConfig.miscContext); schema.AddField(field); } schema.Finalize(); return(schema); }
public static void WriteEvents <TOutputStream>(List <NetworkEvent> events, List <NetworkEventType> knownEventTypes, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { output.WritePackedUInt((uint)events.Count, NetworkConfig.eventCountContext); foreach (var info in events) { // Write event schema if the client haven't acked this event type output.WritePackedUInt(info.type.typeId, NetworkConfig.eventCountContext); if (!knownEventTypes.Contains(info.type)) { output.WriteRawBits(1, 1); NetworkSchema.WriteSchema(info.type.schema, ref output); } else { output.WriteRawBits(0, 1); } // Write event data NetworkSchema.CopyFieldsFromBuffer(info.type.schema, info.data, ref output); } }
public void Delta_FloatCompressed <TInputStream, TOutputStream>() where TInputStream : NetworkCompression.IInputStream, new() where TOutputStream : NetworkCompression.IOutputStream, new() { var schema = new NetworkSchema(0); schema.AddField(new NetworkSchema.FieldInfo() { name = "field_0", fieldType = NetworkSchema.FieldType.Float, bits = 32, delta = true, precision = 3 }); schema.Finalize(); var values = new List <object>() { 0.637160838f }; var baseline = new List <object>() { 0.538469732f }; TestDelta <TInputStream, TOutputStream>(schema, values, baseline); }
unsafe public static void WriteEvents(List <NetworkEvent> events, List <NetworkEventType> knownEventTypes, ref RawOutputStream output) { output.WritePackedUInt((uint)events.Count, NetworkConfig.eventCountContext); foreach (var info in events) { // Write event schema if the client haven't acked this event type output.WritePackedUInt(info.type.typeId, NetworkConfig.eventCountContext); if (!knownEventTypes.Contains(info.type)) { output.WriteRawBits(1, 1); NetworkSchema.WriteSchema(info.type.schema, ref output); } else output.WriteRawBits(0, 1); // Write event data fixed(uint *data = info.data) { NetworkSchema.CopyFieldsFromBuffer(info.type.schema, data, ref output); } } }
void ReadMapInfo(ref RawInputStream input) { //input.SetStatsType(NetworkCompressionReader.Type.MapInfo); var mapSequence = (ushort)input.ReadRawBits(16); var schemaIncluded = input.ReadRawBits(1) != 0; if (schemaIncluded) { mapInfo.schema = NetworkSchema.ReadSchema(ref input); // might override previous definition } if (mapSequence > mapInfo.mapSequence) { mapInfo.mapSequence = mapSequence; mapInfo.ackSequence = inSequence; mapInfo.processed = false; NetworkSchema.CopyFieldsToBuffer(mapInfo.schema, ref input, mapInfo.data); } else { NetworkSchema.SkipFields(mapInfo.schema, ref input); } }
public void Delta_FloatCompressedNoDrift <TInputStream, TOutputStream>() where TInputStream : NetworkCompression.IInputStream, new() where TOutputStream : NetworkCompression.IOutputStream, new() { var schema = new NetworkSchema(0); schema.AddField(new NetworkSchema.FieldInfo() { name = "field_0", fieldType = NetworkSchema.FieldType.Float, bits = 32, delta = true, precision = 3 }); var values = new List <object>(1); var baseline = new List <object>(1); values.Add(0.0f); baseline.Add(0.0f); for (int i = 0; i < 1024; ++i) { values[0] = (float)Math.Sin(i / 1024.0f * Math.PI); TestDelta <TInputStream, TOutputStream>(schema, values, baseline); baseline[0] = values[0]; } }
public static int ReadEvents <TInputStream>(Dictionary <ushort, NetworkEventType> eventTypesIn, int connectionId, ref TInputStream input, INetworkCallbacks networkConsumer) where TInputStream : NetworkCompression.IInputStream { var eventCount = input.ReadPackedUInt(NetworkConfig.eventCountContext); for (var eventCounter = 0; eventCounter < eventCount; ++eventCounter) { var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.eventTypeIdContext); var schemaIncluded = input.ReadRawBits(1) != 0; if (schemaIncluded) { var eventType = new NetworkEventType() { typeId = typeId }; eventType.schema = NetworkSchema.ReadSchema(ref input); if (!eventTypesIn.ContainsKey(typeId)) { eventTypesIn.Add(typeId, eventType); } } // TODO (petera) do we need to Create an info (as we are just releasing it right after?) var type = eventTypesIn[typeId]; var info = Create(type); NetworkSchema.CopyFieldsToBuffer(type.schema, ref input, info.data); if (NetworkConfig.netDebug.IntValue > 0) { GameDebug.Log("Received event " + ((GameNetworkEvents.EventType)info.type.typeId + ":" + info.sequence)); } networkConsumer.OnEvent(connectionId, info); info.Release(); } return((int)eventCount); }
void WriteCommands <TOutputStream>(ClientPackageInfo packageInfo, ref TOutputStream output) where TOutputStream : NetworkCompression.IOutputStream { AddMessage(NetworkMessage.Commands); counters.commandsOut++; var includeSchema = commandSequenceAck == 0; output.WriteRawBits(includeSchema ? 1U : 0, 1); if (includeSchema) { NetworkSchema.WriteSchema(commandSchema, ref output); } var sequence = commandSequence; output.WriteRawBits(Sequence.ToUInt16(commandSequence), 16); packageInfo.commandSequence = commandSequence; packageInfo.commandTime = commandsOut[commandSequence].time; CommandInfo previous = defaultCommandInfo; CommandInfo command; while (commandsOut.TryGetValue(sequence, out command)) { // 1 bit to tell there is a command output.WriteRawBits(1, 1); output.WritePackedIntDelta(command.time, previous.time, NetworkConfig.commandTimeContext); uint hash = 0; DeltaWriter.Write(ref output, commandSchema, command.data, previous.data, zeroFieldsChanged, 0, ref hash); previous = command; --sequence; } output.WriteRawBits(0, 1); }
unsafe void ReadSnapshot <TInputStream>(int sequence, ref TInputStream input, ISnapshotConsumer consumer) where TInputStream : NetworkCompression.IInputStream { //input.SetStatsType(NetworkCompressionReader.Type.SnapshotSchema); counters.snapshotsIn++; // Snapshot may be delta compressed against one or more baselines // Baselines are indicated by sequence number of the package it was in var haveBaseline = input.ReadRawBits(1) == 1; var baseSequence = (int)input.ReadPackedIntDelta(sequence - 1, NetworkConfig.baseSequenceContext); bool enableNetworkPrediction = input.ReadRawBits(1) != 0; bool enableHashing = input.ReadRawBits(1) != 0; int baseSequence1 = 0; int baseSequence2 = 0; if (enableNetworkPrediction) { baseSequence1 = (int)input.ReadPackedIntDelta(baseSequence - 1, NetworkConfig.baseSequence1Context); baseSequence2 = (int)input.ReadPackedIntDelta(baseSequence1 - 1, NetworkConfig.baseSequence2Context); } if (clientDebug.IntValue > 2) { if (enableNetworkPrediction) { GameDebug.Log((haveBaseline ? "Snap [BL]" : "Snap [ ]") + "(" + sequence + ") " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2); } else { GameDebug.Log((haveBaseline ? "Snap [BL]" : "Snap [ ]") + "(" + sequence + ") " + baseSequence); } } if (!haveBaseline) { counters.fullSnapshotsIn++; } GameDebug.Assert(!haveBaseline || (sequence > baseSequence && sequence - baseSequence < NetworkConfig.snapshotDeltaCacheSize), "Attempting snapshot encoding with invalid baseline: {0}:{1}", sequence, baseSequence); var snapshotInfo = snapshots.Acquire(sequence); snapshotInfo.serverTime = (int)input.ReadPackedIntDelta(haveBaseline ? snapshots[baseSequence].serverTime : 0, NetworkConfig.serverTimeContext); var temp = (int)input.ReadRawBits(8); serverSimTime = temp * 0.1f; // Only update time if received in-order.. // TODO consider dropping out of order snapshots // TODO detecting out-of-order on pack sequences if (snapshotInfo.serverTime > serverTime) { serverTime = snapshotInfo.serverTime; snapshotReceivedTime = NetworkUtils.stopwatch.ElapsedMilliseconds; } else { GameDebug.Log(string.Format("NetworkClient. Dropping out of order snaphot. Server time:{0} snapshot time:{1}", serverTime, snapshotInfo.serverTime)); } counters.AddSectionStats("snapShotHeader", input.GetBitPosition2(), new Color(0.5f, 0.5f, 0.5f)); // Used by thinclient that wants to very cheaply just do minimal handling of // snapshots if (m_DropSnapshots) { return; } // Read schemas var schemaCount = input.ReadPackedUInt(NetworkConfig.schemaCountContext); for (int schemaIndex = 0; schemaIndex < schemaCount; ++schemaIndex) { var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.schemaTypeIdContext); var entityType = new EntityTypeInfo() { typeId = typeId }; entityType.schema = NetworkSchema.ReadSchema(ref input); counters.AddSectionStats("snapShotSchemas", input.GetBitPosition2(), new Color(0.0f, (schemaIndex & 1) == 1 ? 0.5f : 1.0f, 1.0f)); entityType.baseline = new uint[NetworkConfig.maxEntitySnapshotDataSize]; NetworkSchema.CopyFieldsToBuffer(entityType.schema, ref input, entityType.baseline); if (!entityTypes.ContainsKey(typeId)) { entityTypes.Add(typeId, entityType); } counters.AddSectionStats("snapShotSchemas", input.GetBitPosition2(), new Color(1.0f, (schemaIndex & 1) == 1 ? 0.5f : 1.0f, 1.0f)); } // Remove any despawning entities that belong to older base sequences for (int i = 0; i < entities.Count; i++) { var e = entities[i]; if (e.type == null) { continue; } if (e.despawnSequence > 0 && e.despawnSequence <= baseSequence) { e.Reset(); } } // Read new spawns m_TempSpawnList.Clear(); var previousId = 1; var spawnCount = input.ReadPackedUInt(NetworkConfig.spawnCountContext); for (var spawnIndex = 0; spawnIndex < spawnCount; ++spawnIndex) { var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext); previousId = id; // Register the entity var typeId = (ushort)input.ReadPackedUInt(NetworkConfig.spawnTypeIdContext); //TODO: use another encoding GameDebug.Assert(entityTypes.ContainsKey(typeId), "Spawn request with unknown type id {0}", typeId); byte fieldMask = (byte)input.ReadRawBits(8); // TODO (petera) need an max entity id for safety while (id >= entities.Count) { entities.Add(new EntityInfo()); } // Incoming spawn of different type than what we have for this id, so immediately nuke // the one we have to make room for the incoming if (entities[id].type != null && entities[id].type.typeId != typeId) { // This should only ever happen in case of no baseline as normally the server will // not reuse an id before all clients have acknowledged its despawn. GameDebug.Assert(haveBaseline == false, "Spawning entity but we already have with different type?"); GameDebug.Log("REPLACING old entity: " + id + " because snapshot gave us new type for this id"); despawns.Add(id); entities[id].Reset(); } // We can receive spawn information in several snapshots before our ack // has reached the server. Only pass on spawn to game layer once if (entities[id].type == null) { var e = entities[id]; e.type = entityTypes[typeId]; e.fieldMask = fieldMask; spawns.Add(id); } m_TempSpawnList.Add(id); } counters.AddSectionStats("snapShotSpawns", input.GetBitPosition2(), new Color(0, 0.58f, 0)); // Read despawns var despawnCount = input.ReadPackedUInt(NetworkConfig.despawnCountContext); // If we have no baseline, we need to clear all entities that are not being spawned if (!haveBaseline) { GameDebug.Assert(despawnCount == 0, "There should not be any despawns in a non-baseline snapshot"); for (int i = 0, c = entities.Count; i < c; ++i) { var e = entities[i]; if (e.type == null) { continue; } if (m_TempSpawnList.Contains(i)) { continue; } GameDebug.Log("NO BL SO PRUNING Stale entity: " + i); despawns.Add(i); e.Reset(); } } for (var despawnIndex = 0; despawnIndex < despawnCount; ++despawnIndex) { var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext); previousId = id; // we may see despawns many times, only handle if we still have the entity GameDebug.Assert(id < entities.Count, "Getting despawn for id {0} but we only know about entities up to {1}", id, entities.Count); if (entities[id].type == null) { continue; } var entity = entities[id]; // Already in the process of being despawned. This happens with same-snapshot spawn/despawn cases if (entity.despawnSequence > 0) { continue; } // If we are spawning and despawning in same snapshot, delay actual deletion of // entity as we need it around to be able to read the update part of the snapshot if (m_TempSpawnList.Contains(id)) { entity.despawnSequence = sequence; // keep until baseSequence >= despawnSequence } else { entity.Reset(); // otherwise remove right away; no further updates coming, not even in this snap } // Add to despawns list so we can request despawn from game later GameDebug.Assert(!despawns.Contains(id), "Double despawn in same snaphot? {0}", id); despawns.Add(id); } counters.AddSectionStats("snapShotDespawns", input.GetBitPosition2(), new Color(0.49f, 0, 0)); // Predict all active entities for (var id = 0; id < entities.Count; id++) { var info = entities[id]; if (info.type == null) { continue; } // NOTE : As long as the server haven't gotten the spawn acked, it will keep sending // delta relative to 0, so we need to check if the entity was in the spawn list to determine // if the delta is relative to the last update or not int baseline0Time = 0; uint[] baseline0 = info.type.baseline; GameDebug.Assert(baseline0 != null, "Unable to find schema baseline for type {0}", info.type.typeId); if (haveBaseline && !m_TempSpawnList.Contains(id)) { baseline0 = info.baselines.FindMax(baseSequence); GameDebug.Assert(baseline0 != null, "Unable to find baseline for seq {0} for id {1}", baseSequence, id); baseline0Time = snapshots[baseSequence].serverTime; } if (enableNetworkPrediction) { uint num_baselines = 1; // 1 because either we have schema baseline or we have a real baseline int baseline1Time = 0; int baseline2Time = 0; uint[] baseline1 = null; uint[] baseline2 = null; if (baseSequence1 != baseSequence) { baseline1 = info.baselines.FindMax(baseSequence1); if (baseline1 != null) { num_baselines = 2; baseline1Time = snapshots[baseSequence1].serverTime; } if (baseSequence2 != baseSequence1) { baseline2 = info.baselines.FindMax(baseSequence2); if (baseline2 != null) { num_baselines = 3; baseline2Time = snapshots[baseSequence2].serverTime; } } } // TODO (petera) are these clears needed? for (int i = 0, c = info.fieldsChangedPrediction.Length; i < c; ++i) { info.fieldsChangedPrediction[i] = 0; } for (int i = 0; i < NetworkConfig.maxEntitySnapshotDataSize; i++) { info.prediction[i] = 0; fixed(uint *prediction = info.prediction, baseline0p = baseline0, baseline1p = baseline1, baseline2p = baseline2) { NetworkPrediction.PredictSnapshot(prediction, info.fieldsChangedPrediction, info.type.schema, num_baselines, (uint)baseline0Time, baseline0p, (uint)baseline1Time, baseline1p, (uint)baseline2Time, baseline2p, (uint)snapshotInfo.serverTime, info.fieldMask); } } else { var f = info.fieldsChangedPrediction; for (var i = 0; i < f.Length; ++i) { f[i] = 0; } for (int i = 0, c = info.type.schema.GetByteSize() / 4; i < c; ++i) { info.prediction[i] = baseline0[i]; } } } // Read updates var updateCount = input.ReadPackedUInt(NetworkConfig.updateCountContext); for (var updateIndex = 0; updateIndex < updateCount; ++updateIndex) { var id = (int)input.ReadPackedIntDelta(previousId, NetworkConfig.idContext); previousId = id; var info = entities[id]; uint hash = 0; // Copy prediction to temp buffer as we now overwrite info.prediction with fully unpacked // state by applying incoming delta to prediction. for (int i = 0, c = info.type.schema.GetByteSize() / 4; i < c; ++i) { tempSnapshotBuffer[i] = info.prediction[i]; } DeltaReader.Read(ref input, info.type.schema, info.prediction, tempSnapshotBuffer, info.fieldsChangedPrediction, info.fieldMask, ref hash); if (enableHashing) { uint hashCheck = input.ReadRawBits(32); if (hash != hashCheck) { GameDebug.Log("Hash check fail for entity " + id); if (enableNetworkPrediction) { GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (haveBaseline ? "Snap [BL]" : "Snap [ ]") + " " + baseSequence + " - " + baseSequence1 + " - " + baseSequence2 + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount); } else { GameDebug.Assert(false, "Snapshot (" + snapshotInfo.serverTime + ") " + (haveBaseline ? "Snap [BL]" : "Snap [ ]") + " " + baseSequence + ". Sche: " + schemaCount + " Spwns: " + spawnCount + " Desp: " + despawnCount + " Upd: " + updateCount); } } } } if (enableNetworkPrediction) { counters.AddSectionStats("snapShotUpdatesPredict", input.GetBitPosition2(), haveBaseline ? new Color(0.09f, 0.38f, 0.93f) : Color.cyan); } else { counters.AddSectionStats("snapShotUpdatesNoPredict", input.GetBitPosition2(), haveBaseline ? new Color(0.09f, 0.38f, 0.93f) : Color.cyan); } uint snapshotHash = 0; // sum of hash for all (updated or not) entity snapshots uint numEnts = 0; for (int id = 0; id < entities.Count; id++) { var info = entities[id]; if (info.type == null) { continue; } // Skip despawned that have not also been spawned in this snapshot if (info.despawnSequence > 0 && !spawns.Contains(id)) { continue; } // If just spawned or if new snapshot is different from the last we deserialized, // we need to deserialize. Otherwise just ignore; no reason to deserialize the same // values again int schemaSize = info.type.schema.GetByteSize(); if (info.baselines.GetSize() == 0 || NetworkUtils.MemCmp(info.prediction, 0, info.lastUpdate, 0, schemaSize) != 0) { var data = info.baselines.Insert(sequence); for (int i = 0; i < schemaSize / 4; ++i) data[i] = info.prediction[i]; } if (sequence > info.lastUpdateSequence) { if (!updates.Contains(id)) { updates.Add(id); } for (int i = 0; i < schemaSize / 4; ++i) { info.lastUpdate[i] = info.prediction[i]; } info.lastUpdateSequence = sequence; } } if (enableHashing && info.despawnSequence == 0) { snapshotHash += NetworkUtils.SimpleHash(info.prediction, schemaSize); numEnts++; } }
unsafe public static int Read <TInputStream>(ref TInputStream input, NetworkSchema schema, uint[] outputData, uint[] baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint hash) where TInputStream : NetworkCompression.IInputStream { GameDebug.Assert(baselineData != null); var index = 0; int numFields = schema.numFields; int skipContext = schema.id * NetworkConfig.maxContextsPerSchema + NetworkConfig.firstSchemaContext; for (int i = 0; i * 8 < numFields; i++) { uint value = input.ReadPackedNibble(skipContext + 2 * i + 0); value |= input.ReadPackedNibble(skipContext + 2 * i + 1) << 4; fieldsNotPredicted[i] = (byte)(value ^ fieldsChangedPrediction[i]); } for (int i = 0; i < numFields; ++i) { var field = schema.fields[i]; GameDebug.Assert(field.byteOffset == index * 4); int fieldStartContext = field.startContext; byte fieldByteOffset = (byte)((uint)i >> 3); byte fieldBitOffset = (byte)((uint)i & 0x7); bool skip = (fieldsNotPredicted[fieldByteOffset] & (1 << fieldBitOffset)) == 0; bool masked = ((field.fieldMask & fieldMask) != 0); skip = skip || masked; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: { uint value = baselineData[index]; if (!skip) { value = input.ReadRawBits(1); } if (!masked) { hash = NetworkUtils.SimpleHashStreaming(hash, value); } outputData[index] = value; index++; break; } case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: { uint baseline = (uint)baselineData[index]; uint value = baseline; if (!skip) { if (field.delta) { value = input.ReadPackedUIntDelta(baseline, fieldStartContext); } else { value = input.ReadRawBits(field.bits); } } if (!masked) { hash = NetworkUtils.SimpleHashStreaming(hash, value); } outputData[index] = value; index++; break; } case NetworkSchema.FieldType.Vector2: { uint bx = baselineData[index]; uint by = baselineData[index + 1]; uint vx = bx; uint vy = by; if (!skip) { if (field.delta) { vx = input.ReadPackedUIntDelta(bx, fieldStartContext + 0); vy = input.ReadPackedUIntDelta(by, fieldStartContext + 1); } else { vx = input.ReadRawBits(field.bits); vy = input.ReadRawBits(field.bits); } } if (!masked) { hash = NetworkUtils.SimpleHashStreaming(hash, vx); hash = NetworkUtils.SimpleHashStreaming(hash, vy); } outputData[index] = vx; outputData[index + 1] = vy; index += 2; break; } case NetworkSchema.FieldType.Vector3: { uint bx = baselineData[index]; uint by = baselineData[index + 1]; uint bz = baselineData[index + 2]; uint vx = bx; uint vy = by; uint vz = bz; if (!skip) { if (field.delta) { vx = input.ReadPackedUIntDelta(bx, fieldStartContext + 0); vy = input.ReadPackedUIntDelta(by, fieldStartContext + 1); vz = input.ReadPackedUIntDelta(bz, fieldStartContext + 2); } else { vx = input.ReadRawBits(field.bits); vy = input.ReadRawBits(field.bits); vz = input.ReadRawBits(field.bits); } } if (!masked) { hash = NetworkUtils.SimpleHashStreaming(hash, vx); hash = NetworkUtils.SimpleHashStreaming(hash, vy); hash = NetworkUtils.SimpleHashStreaming(hash, vz); } outputData[index] = vx; outputData[index + 1] = vy; outputData[index + 2] = vz; index += 3; break; } case NetworkSchema.FieldType.Quaternion: { uint bx = baselineData[index]; uint by = baselineData[index + 1]; uint bz = baselineData[index + 2]; uint bw = baselineData[index + 3]; uint vx = bx; uint vy = by; uint vz = bz; uint vw = bw; if (!skip) { if (field.delta) { vx = input.ReadPackedUIntDelta(bx, fieldStartContext + 0); vy = input.ReadPackedUIntDelta(by, fieldStartContext + 1); vz = input.ReadPackedUIntDelta(bz, fieldStartContext + 2); vw = input.ReadPackedUIntDelta(bw, fieldStartContext + 3); //RUTODO: normalize } else { vx = input.ReadRawBits(field.bits); vy = input.ReadRawBits(field.bits); vz = input.ReadRawBits(field.bits); vw = input.ReadRawBits(field.bits); } } if (!masked) { hash = NetworkUtils.SimpleHashStreaming(hash, vx); hash = NetworkUtils.SimpleHashStreaming(hash, vy); hash = NetworkUtils.SimpleHashStreaming(hash, vz); hash = NetworkUtils.SimpleHashStreaming(hash, vw); } outputData[index] = vx; outputData[index + 1] = vy; outputData[index + 2] = vz; outputData[index + 3] = vw; index += 4; break; } case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { // TODO : Do a better job with deltaing strings and buffers if (!skip) { uint count = input.ReadPackedUInt(fieldStartContext); outputData[index] = count; index++; fixed(uint *buf = outputData) { byte *dst = (byte *)(buf + index); int idx = 0; for (; idx < count; ++idx) { *dst++ = (byte)input.ReadRawBits(8); } for (; idx < field.arraySize / 4; ++idx) { *dst++ = 0; } } index += field.arraySize / 4; } else { for (int idx = 0, c = field.arraySize / 4; idx < c; ++idx) { outputData[index + idx] = baselineData[index + idx]; } index += field.arraySize / 4 + 1; } if (!masked) { hash += 0; // TODO (hash strings and bytearrays as well) } } break; } } return(index * 4); }
unsafe public static void CopyFieldsToBuffer <TInputStream>(NetworkSchema schema, ref TInputStream input, uint[] outputBuffer) where TInputStream : NetworkCompression.IInputStream { var index = 0; for (var fieldIndex = 0; fieldIndex < schema.fieldsInternal.Count; ++fieldIndex) { var field = schema.fieldsInternal[fieldIndex]; switch (field.fieldType) { case NetworkSchema.FieldType.Bool: case NetworkSchema.FieldType.UInt: case NetworkSchema.FieldType.Int: case NetworkSchema.FieldType.Float: outputBuffer[index++] = input.ReadPackedUInt(NetworkConfig.miscContext); break; case NetworkSchema.FieldType.Vector2: outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); break; case NetworkSchema.FieldType.Vector3: outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); break; case NetworkSchema.FieldType.Quaternion: outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); outputBuffer[index++] = (input.ReadPackedUInt(NetworkConfig.miscContext)); break; case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: var dataSize = input.ReadPackedUInt(NetworkConfig.miscContext); outputBuffer[index++] = dataSize; fixed(uint *buf = outputBuffer) { byte *dst = (byte *)(buf + index); int i = 0; for (; i < dataSize; i++) { *dst++ = (byte)input.ReadRawBits(8); } for (; i < field.arraySize; i++) { *dst++ = 0; } } index += field.arraySize / 4; break; default: GameDebug.Assert(false); break; } } }
unsafe static public void Write <TOutputStream>(ref TOutputStream output, NetworkSchema schema, uint *inputData, uint *baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint entity_hash) where TOutputStream : NetworkCompression.IOutputStream { GameDebug.Assert(baselineData != null); int numFields = schema.numFields; GameDebug.Assert(fieldsChangedPrediction.Length >= numFields / 8, "Not enough bits in fieldsChangedPrediction for all fields"); for (int i = 0, l = fieldsNotPredicted.Length; i < l; ++i) { fieldsNotPredicted[i] = 0; } int index = 0; // calculate bitmask of fields that need to be encoded for (int fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) { var field = schema.fields[fieldIndex]; // Skip fields that are masked out bool masked = (field.fieldMask & fieldMask) != 0; byte fieldByteOffset = (byte)((uint)fieldIndex >> 3); byte fieldBitOffset = (byte)((uint)fieldIndex & 0x7); switch (field.fieldType) { case NetworkSchema.FieldType.Bool: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Int: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.UInt: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Float: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Vector2: { uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); if (vx != bx || vy != by) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Vector3: { uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; uint vz = inputData[index]; uint bz = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vz); if (vx != bx || vy != by || vz != bz) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Quaternion: { uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; uint vz = inputData[index]; uint bz = baselineData[index]; index++; uint vw = inputData[index]; uint bw = baselineData[index]; index++; if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vz); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vw); if (vx != bx || vy != by || vz != bz || vw != bw) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { if (!masked) { entity_hash += 0; // TODO client side has no easy way to hash strings. enable this when possible: NetworkUtils.SimpleHash(valueBuffer, valueLength); bool same = true; for (int i = 0; i < field.arraySize; i++) { if (inputData[index + i] != baselineData[index + i]) { same = false; break; } } if (!same) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } index += field.arraySize / 4 + 1; } break; } } index = 0; int skipContext = schema.id * NetworkConfig.maxContextsPerSchema + NetworkConfig.firstSchemaContext; // Client needs fieldsNotPredicted. We send the delta between it and fieldsChangedPrediction { for (int i = 0; i * 8 < numFields; i++) { byte deltaFields = (byte)(fieldsNotPredicted[i] ^ fieldsChangedPrediction[i]); output.WritePackedNibble((uint)(deltaFields & 0xF), skipContext + i * 2); output.WritePackedNibble((uint)((deltaFields >> 4) & 0xF), skipContext + i * 2 + 1); } } int startBitPosition = 0; for (int fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) { var field = schema.fields[fieldIndex]; int fieldStartContext = field.startContext; startBitPosition = output.GetBitPosition2(); byte fieldByteOffset = (byte)((uint)fieldIndex >> 3); byte fieldBitOffset = (byte)((uint)fieldIndex & 0x7); var notPredicted = ((fieldsNotPredicted[fieldByteOffset] & (1 << fieldBitOffset)) != 0); switch (field.fieldType) { case NetworkSchema.FieldType.Bool: { uint value = inputData[index]; index++; if (notPredicted) { output.WriteRawBits(value, 1); NetworkSchema.AddStatsToFieldBool(field, (value != 0), false, output.GetBitPosition2() - startBitPosition); } break; } case NetworkSchema.FieldType.Int: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldInt(field, (int)value, (int)baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldInt(field, (int)value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.UInt: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldUInt(field, value, baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldUInt(field, value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Float: { uint value = inputData[index]; uint baseline = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldFloat(field, value, baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldFloat(field, value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Vector2: { uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); NetworkSchema.AddStatsToFieldVector2(field, vx, vy, bx, by, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); NetworkSchema.AddStatsToFieldVector2(field, vx, vy, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Vector3: { uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; uint vz = inputData[index]; uint bz = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); output.WritePackedUIntDelta(vz, bz, fieldStartContext + 2); NetworkSchema.AddStatsToFieldVector3(field, vx, vy, vz, bx, by, bz, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); output.WriteRawBits(vz, field.bits); NetworkSchema.AddStatsToFieldVector3(field, vx, vy, vz, 0, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Quaternion: { // TODO : Figure out what to do with quaternions uint vx = inputData[index]; uint bx = baselineData[index]; index++; uint vy = inputData[index]; uint by = baselineData[index]; index++; uint vz = inputData[index]; uint bz = baselineData[index]; index++; uint vw = inputData[index]; uint bw = baselineData[index]; index++; if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); output.WritePackedUIntDelta(vz, bz, fieldStartContext + 2); output.WritePackedUIntDelta(vw, bw, fieldStartContext + 3); NetworkSchema.AddStatsToFieldQuaternion(field, vx, vy, vz, vw, bx, by, bz, bw, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); output.WriteRawBits(vz, field.bits); output.WriteRawBits(vw, field.bits); NetworkSchema.AddStatsToFieldQuaternion(field, vx, vy, vz, vw, 0, 0, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { uint valueLength = inputData[index]; index++; if (notPredicted) { output.WritePackedUInt(valueLength, fieldStartContext); byte *bytes = (byte *)(inputData + index); output.WriteRawBytes(bytes, (int)valueLength); if (field.fieldType == NetworkSchema.FieldType.String) { NetworkSchema.AddStatsToFieldString(field, bytes, (int)valueLength, output.GetBitPosition2() - startBitPosition); } else { NetworkSchema.AddStatsToFieldByteArray(field, bytes, (int)valueLength, output.GetBitPosition2() - startBitPosition); } } index += field.arraySize / 4; } break; } } }