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); }
unsafe public static int Read(ref RawInputStream input, NetworkSchema schema, uint[] outputData, uint[] baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint hash) { 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); }