您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
224 行
9.1 KiB
224 行
9.1 KiB
using System;
|
|
using UnityEngine;
|
|
|
|
|
|
public struct DeltaReader
|
|
{
|
|
static byte[] fieldsNotPredicted = new byte[(NetworkConfig.maxFieldsPerSchema + 7 ) / 8];
|
|
public static int Read<TInputStream>(ref TInputStream input, NetworkSchema schema, byte[] outputData, byte[] baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint hash) where TInputStream : NetworkCompression.IInputStream
|
|
{
|
|
GameDebug.Assert(baselineData != null);
|
|
var outputStream = new ByteOutputStream(outputData);
|
|
var baselineStream = new ByteInputStream(baselineData);
|
|
|
|
int numFields = schema.fields.Count;
|
|
|
|
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)
|
|
{
|
|
GameDebug.Assert(schema.fields[i].byteOffset == baselineStream.GetBytePosition());
|
|
int fieldStartContext = schema.fields[i].startContext;
|
|
|
|
var field = schema.fields[i];
|
|
|
|
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 = baselineStream.ReadUInt8();
|
|
if(!skip)
|
|
value = input.ReadRawBits(1);
|
|
|
|
if (!masked)
|
|
hash = NetworkUtils.SimpleHashStreaming(hash, value);
|
|
|
|
outputStream.WriteUInt8((byte)value);
|
|
break;
|
|
}
|
|
|
|
case NetworkSchema.FieldType.UInt:
|
|
case NetworkSchema.FieldType.Int:
|
|
case NetworkSchema.FieldType.Float:
|
|
{
|
|
uint baseline = (uint)baselineStream.ReadBits(field.bits);
|
|
|
|
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);
|
|
|
|
outputStream.WriteBits(value, field.bits); //RUTODO: fix this
|
|
break;
|
|
}
|
|
|
|
case NetworkSchema.FieldType.Vector2:
|
|
{
|
|
uint bx = baselineStream.ReadUInt32();
|
|
uint by = baselineStream.ReadUInt32();
|
|
|
|
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);
|
|
}
|
|
|
|
outputStream.WriteUInt32(vx);
|
|
outputStream.WriteUInt32(vy);
|
|
|
|
break;
|
|
}
|
|
|
|
case NetworkSchema.FieldType.Vector3:
|
|
{
|
|
uint bx = baselineStream.ReadUInt32();
|
|
uint by = baselineStream.ReadUInt32();
|
|
uint bz = baselineStream.ReadUInt32();
|
|
|
|
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);
|
|
}
|
|
|
|
outputStream.WriteUInt32(vx);
|
|
outputStream.WriteUInt32(vy);
|
|
outputStream.WriteUInt32(vz);
|
|
break;
|
|
}
|
|
|
|
case NetworkSchema.FieldType.Quaternion:
|
|
{
|
|
uint bx = baselineStream.ReadUInt32();
|
|
uint by = baselineStream.ReadUInt32();
|
|
uint bz = baselineStream.ReadUInt32();
|
|
uint bw = baselineStream.ReadUInt32();
|
|
|
|
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);
|
|
}
|
|
|
|
outputStream.WriteUInt32(vx);
|
|
outputStream.WriteUInt32(vy);
|
|
outputStream.WriteUInt32(vz);
|
|
outputStream.WriteUInt32(vw);
|
|
break;
|
|
}
|
|
|
|
case NetworkSchema.FieldType.String:
|
|
case NetworkSchema.FieldType.ByteArray:
|
|
{
|
|
// TODO : Do a better job with deltaing strings and buffers
|
|
if (!skip)
|
|
{
|
|
baselineStream.SkipByteArray(field.arraySize);
|
|
outputStream.CopyByteArray<TInputStream>(ref input, field.arraySize, fieldStartContext);
|
|
}
|
|
else
|
|
{
|
|
outputStream.CopyByteArray(ref baselineStream, field.arraySize);
|
|
}
|
|
|
|
if (!masked)
|
|
{
|
|
hash += 0; // TODO (hash strings and bytearrays as well)
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
outputStream.Flush();
|
|
return outputStream.GetBytePosition();
|
|
}
|
|
}
|