您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
243 行
8.9 KiB
243 行
8.9 KiB
using System;
|
|
using Unity.Sample.Core;
|
|
using UnityEngine;
|
|
|
|
|
|
public struct DeltaReader
|
|
{
|
|
static byte[] fieldsNotPredicted = new byte[(NetworkConfig.maxFieldsPerSchema + 7) / 8];
|
|
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;
|
|
}
|
|
}
|