Пример #1
0
 public void FromStream(ref ByteInputStream reader)
 {
     Header.FromStream(ref reader);
     Version       = reader.ReadUInt16_NBO();
     CurrentPacket = reader.ReadUInt8();
     LastPacket    = reader.ReadUInt8();
     Length        = reader.ReadUInt16_NBO();
 }
Пример #2
0
    static public unsafe void Write <TOutputStream>(ref TOutputStream output, NetworkSchema schema, byte[] inputData, byte[] baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint entity_hash) where TOutputStream : NetworkCompression.IOutputStream
    {
        GameDebug.Assert(baselineData != null);
        var inputStream    = new ByteInputStream(inputData);
        var baselineStream = new ByteInputStream(baselineData);

        int numFields = schema.fields.Count;

        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;
        }

        // calculate bitmask of fields that need to be encoded
        for (int fieldIndex = 0; fieldIndex < schema.fields.Count; ++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    = inputStream.ReadBits(1);
                uint baseline = baselineStream.ReadUInt8();

                if (!masked)
                {
                    entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value);
                    if (value != baseline)
                    {
                        fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }

                break;
            }

            case NetworkSchema.FieldType.Int:
            {
                uint value    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                if (!masked)
                {
                    entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value);
                    if (value != baseline)
                    {
                        fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }
                break;
            }

            case NetworkSchema.FieldType.UInt:
            {
                uint value    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                if (!masked)
                {
                    entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value);
                    if (value != baseline)
                    {
                        fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }
                break;
            }

            case NetworkSchema.FieldType.Float:
            {
                uint value    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                if (!masked)
                {
                    entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value);
                    if (value != baseline)
                    {
                        fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }
                break;
            }

            case NetworkSchema.FieldType.Vector2:
            {
                uint vx = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();

                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 = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);
                uint vz = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();
                uint bz = baselineStream.ReadUInt32();

                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 = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);
                uint vz = inputStream.ReadBits(field.bits);
                uint vw = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();
                uint bz = baselineStream.ReadUInt32();
                uint bw = baselineStream.ReadUInt32();

                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:
            {
                // TODO : Do a better job of string and buffer diffs?
                byte[] valueBuffer;
                int    valueOffset;
                int    valueLength;
                inputStream.GetByteArray(out valueBuffer, out valueOffset, out valueLength, field.arraySize);

                byte[] baselineBuffer = null;
                int    baselineOffset = 0;
                int    baselineLength = 0;
                baselineStream.GetByteArray(out baselineBuffer, out baselineOffset, out baselineLength, field.arraySize);

                if (!masked)
                {
                    entity_hash += 0;         // TODO client side has no easy way to hash strings. enable this when possible: NetworkUtils.SimpleHash(valueBuffer, valueLength);
                    if (valueLength != baselineLength || NetworkUtils.MemCmp(valueBuffer, valueOffset, baselineBuffer, baselineOffset, valueLength) != 0)
                    {
                        fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }
            }
            break;
            }
        }

        inputStream.Reset();
        baselineStream.Reset();

        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 = inputStream.ReadBits(1);
                /*uint unused_baseline = */ baselineStream.ReadUInt8();

                if (notPredicted)
                {
                    output.WriteRawBits(value, 1);
                    NetworkSchema.AddStatsToFieldBool(field, (value != 0), false, output.GetBitPosition2() - startBitPosition);
                }
                break;
            }

            case NetworkSchema.FieldType.Int:
            {
                uint value    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                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    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                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    = inputStream.ReadBits(field.bits);
                uint baseline = (uint)baselineStream.ReadBits(field.bits);

                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 = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();

                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 = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);
                uint vz = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();
                uint bz = baselineStream.ReadUInt32();

                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 = inputStream.ReadBits(field.bits);
                uint vy = inputStream.ReadBits(field.bits);
                uint vz = inputStream.ReadBits(field.bits);
                uint vw = inputStream.ReadBits(field.bits);

                uint bx = baselineStream.ReadUInt32();
                uint by = baselineStream.ReadUInt32();
                uint bz = baselineStream.ReadUInt32();
                uint bw = baselineStream.ReadUInt32();

                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:
            {
                // TODO : Do a better job of string and buffer diffs?
                byte[] valueBuffer;
                int    valueOffset;
                int    valueLength;
                inputStream.GetByteArray(out valueBuffer, out valueOffset, out valueLength, field.arraySize);

                byte[] baselineBuffer = null;
                int    baselineOffset = 0;
                int    baselineLength = 0;
                baselineStream.GetByteArray(out baselineBuffer, out baselineOffset, out baselineLength, field.arraySize);

                if (notPredicted)
                {
                    output.WritePackedUInt((uint)valueLength, fieldStartContext);
                    output.WriteRawBytes(valueBuffer, valueOffset, valueLength);

                    if (field.fieldType == NetworkSchema.FieldType.String)
                    {
                        NetworkSchema.AddStatsToFieldString(field, valueBuffer, valueOffset, valueLength, output.GetBitPosition2() - startBitPosition);
                    }
                    else
                    {
                        NetworkSchema.AddStatsToFieldByteArray(field, valueBuffer, valueOffset, valueLength, output.GetBitPosition2() - startBitPosition);
                    }
                }
            }
            break;
            }
        }
    }
Пример #3
0
 public void FromStream(ref ByteInputStream reader)
 {
     Type        = reader.ReadUInt8();
     ChallangeId = reader.ReadUInt32_NBO();
 }
Пример #4
0
 public void FromStream(ref ByteInputStream reader)
 {
     Header.FromStream(ref reader);
     Version         = reader.ReadUInt16_NBO();
     RequestedChunks = reader.ReadUInt8();
 }
Пример #5
0
    // Predict snapshot from baselines. Returns true if prediction is different from baseline 0 (if it need to be automatically predicted next frame).
    public static void PredictSnapshot(byte[] outputData, byte[] fieldsChangedPrediction, NetworkSchema schema, uint numBaselines, uint time0, byte[] baselineData0, uint time1, byte[] baselineData1, uint time2, byte[] baselineData2, uint time, byte fieldMask)
    {
        for (int i = 0, l = fieldsChangedPrediction.Length; i < l; ++i)
        {
            fieldsChangedPrediction[i] = 0;
        }

        if (numBaselines < 3)
        {
            System.Array.Copy(baselineData0, outputData, schema.GetByteSize());
            return;
        }

        var baselineStream0 = new ByteInputStream(baselineData0);
        var baselineStream1 = new ByteInputStream(baselineData1);
        var baselineStream2 = new ByteInputStream(baselineData2);
        var outputStream    = new ByteOutputStream(outputData);

        for (int i = 0; i < schema.fields.Count; ++i)
        {
            GameDebug.Assert(schema.fields[i].byteOffset == baselineStream0.GetBytePosition());
            GameDebug.Assert(schema.fields[i].byteOffset == baselineStream1.GetBytePosition());
            GameDebug.Assert(schema.fields[i].byteOffset == baselineStream2.GetBytePosition());

            var field = schema.fields[i];

            byte fieldByteOffset = (byte)((uint)i >> 3);
            byte fieldBitOffset  = (byte)((uint)i & 0x7);

            bool masked = (field.fieldMask & fieldMask) != 0;

            switch (field.fieldType)
            {
            case NetworkSchema.FieldType.Bool:
            {
                uint baseline0  = baselineStream0.ReadUInt8();
                uint baseline1  = baselineStream1.ReadUInt8();
                uint baseline2  = baselineStream2.ReadUInt8();
                uint prediction = baseline0;

                if (!masked)
                {
                    if (baseline0 != baseline1 && baseline1 != baseline2)
                    {
                        fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                    }
                }

                outputStream.WriteUInt8((byte)prediction);
                break;
            }

            case NetworkSchema.FieldType.UInt:
            case NetworkSchema.FieldType.Int:
            case NetworkSchema.FieldType.Float:
            {
                uint baseline0 = (uint)baselineStream0.ReadBits(field.bits);
                uint baseline1 = (uint)baselineStream1.ReadBits(field.bits);
                uint baseline2 = (uint)baselineStream2.ReadBits(field.bits);

                uint prediction = baseline0;
                if (!masked)
                {
                    if (field.delta)
                    {
                        bool predictionLikelyWrong;
                        prediction = NetworkPrediction.PredictUint(numBaselines, time0, baseline0, time1, baseline1, time2, baseline2, time, out predictionLikelyWrong);
                        if (predictionLikelyWrong)
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                    else
                    {
                        if (baseline0 != baseline1 && baseline1 != baseline2)
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                }

                outputStream.WriteBits(prediction, field.bits);          //RUTODO: fix this
                break;
            }

            case NetworkSchema.FieldType.Vector2:
            {
                uint bx0 = baselineStream0.ReadUInt32();
                uint by0 = baselineStream0.ReadUInt32();

                uint bx1 = baselineStream1.ReadUInt32();
                uint by1 = baselineStream1.ReadUInt32();

                uint bx2 = baselineStream2.ReadUInt32();
                uint by2 = baselineStream2.ReadUInt32();

                uint px = bx0;
                uint py = by0;
                if (!masked)
                {
                    if (field.delta)
                    {
                        bool predictionLikelyWrongX;
                        bool predictionLikelyWrongY;
                        px = NetworkPrediction.PredictUint(numBaselines, time0, bx0, time1, bx1, time2, bx2, time, out predictionLikelyWrongX);
                        py = NetworkPrediction.PredictUint(numBaselines, time0, by0, time1, by1, time2, by2, time, out predictionLikelyWrongY);
                        if (predictionLikelyWrongX || predictionLikelyWrongY)
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                    else
                    {
                        if ((bx0 != bx1 || by0 != by1) && (bx1 != bx2 || by1 != by2))
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                }

                outputStream.WriteUInt32(px);
                outputStream.WriteUInt32(py);
                break;
            }

            case NetworkSchema.FieldType.Vector3:
            {
                uint bx0 = baselineStream0.ReadUInt32();
                uint by0 = baselineStream0.ReadUInt32();
                uint bz0 = baselineStream0.ReadUInt32();

                uint bx1 = baselineStream1.ReadUInt32();
                uint by1 = baselineStream1.ReadUInt32();
                uint bz1 = baselineStream1.ReadUInt32();

                uint bx2 = baselineStream2.ReadUInt32();
                uint by2 = baselineStream2.ReadUInt32();
                uint bz2 = baselineStream2.ReadUInt32();

                uint px = bx0;
                uint py = by0;
                uint pz = bz0;

                if (!masked)
                {
                    if (field.delta)
                    {
                        bool predictionLikelyWrongX;
                        bool predictionLikelyWrongY;
                        bool predictionLikelyWrongZ;
                        px = NetworkPrediction.PredictUint(numBaselines, time0, bx0, time1, bx1, time2, bx2, time, out predictionLikelyWrongX);
                        py = NetworkPrediction.PredictUint(numBaselines, time0, by0, time1, by1, time2, by2, time, out predictionLikelyWrongY);
                        pz = NetworkPrediction.PredictUint(numBaselines, time0, bz0, time1, bz1, time2, bz2, time, out predictionLikelyWrongZ);

                        if (predictionLikelyWrongX || predictionLikelyWrongY || predictionLikelyWrongZ)
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                    else
                    {
                        if ((bx0 != bx1 || by0 != by1 || bz0 != bz1) && (bx1 != bx2 || by1 != by2 || bz1 != bz2))
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                }

                outputStream.WriteUInt32(px);
                outputStream.WriteUInt32(py);
                outputStream.WriteUInt32(pz);
                break;
            }

            case NetworkSchema.FieldType.Quaternion:
            {
                uint bx0 = baselineStream0.ReadUInt32();
                uint by0 = baselineStream0.ReadUInt32();
                uint bz0 = baselineStream0.ReadUInt32();
                uint bw0 = baselineStream0.ReadUInt32();

                uint bx1 = baselineStream1.ReadUInt32();
                uint by1 = baselineStream1.ReadUInt32();
                uint bz1 = baselineStream1.ReadUInt32();
                uint bw1 = baselineStream1.ReadUInt32();

                uint bx2 = baselineStream2.ReadUInt32();
                uint by2 = baselineStream2.ReadUInt32();
                uint bz2 = baselineStream2.ReadUInt32();
                uint bw2 = baselineStream2.ReadUInt32();

                uint px = bx0;
                uint py = by0;
                uint pz = bz0;
                uint pw = bw0;

                if (!masked)
                {
                    if (field.delta)
                    {
                        bool predictionLikelyWrongX;
                        bool predictionLikelyWrongY;
                        bool predictionLikelyWrongZ;
                        bool predictionLikelyWrongW;
                        px = NetworkPrediction.PredictUint(numBaselines, time0, bx0, time1, bx1, time2, bx2, time, out predictionLikelyWrongX);
                        py = NetworkPrediction.PredictUint(numBaselines, time0, by0, time1, by1, time2, by2, time, out predictionLikelyWrongY);
                        pz = NetworkPrediction.PredictUint(numBaselines, time0, bz0, time1, bz1, time2, bz2, time, out predictionLikelyWrongZ);
                        pw = NetworkPrediction.PredictUint(numBaselines, time0, bw0, time1, bw1, time2, bw2, time, out predictionLikelyWrongW);

                        if (predictionLikelyWrongX || predictionLikelyWrongY || predictionLikelyWrongZ || predictionLikelyWrongW)
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                    else
                    {
                        if ((bx0 != bx1 || by0 != by1 || bz0 != bz1 || bw0 != bw1) && (bx1 != bx2 || by1 != by2 || bz1 != bz2 || bw1 != bw2))
                        {
                            fieldsChangedPrediction[fieldByteOffset] |= (byte)(1 << fieldBitOffset);
                        }
                    }
                }

                outputStream.WriteUInt32(px);
                outputStream.WriteUInt32(py);
                outputStream.WriteUInt32(pz);
                outputStream.WriteUInt32(pw);
                break;
            }

            case NetworkSchema.FieldType.String:
            case NetworkSchema.FieldType.ByteArray:
            {
                baselineStream1.SkipByteArray(field.arraySize);
                baselineStream2.SkipByteArray(field.arraySize);
                outputStream.CopyByteArray(ref baselineStream0, field.arraySize);
                //TODO: predict me!
            }
            break;
            }
        }

        //fieldsChangedPrediction = 0;

        outputStream.Flush();
    }
Пример #6
0
    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());
    }