using System; using FishNet.CodeGenerating; using System.Runtime.CompilerServices; using FishNet.Managing; using FishNet.Object; using FishNet.Object.Prediction; using FishNet.Serializing.Helping; using UnityEngine; namespace FishNet.Serializing { public partial class Reader { internal double DOUBLE_ACCURACY => Writer.DOUBLE_ACCURACY; internal decimal DECIMAL_ACCURACY => Writer.DECIMAL_ACCURACY; #region Other. /// /// Reads a boolean. /// [DefaultDeltaReader] public bool ReadDeltaBoolean(bool valueA) { return !valueA; } #endregion #region Whole values. /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public sbyte ReadDeltaInt8(sbyte valueA) => (sbyte)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public byte ReadDeltaUInt8(byte valueA) => (byte)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public short ReadDeltaInt16(short valueA) => (short)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public ushort ReadDeltaUInt16(ushort valueA) => (ushort)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public int ReadDeltaInt32(int valueA) => (int)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public uint ReadDeltaUInt32(uint valueA) => (uint)ReadDifference8_16_32(valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public long ReadDeltaInt64(long valueA) => (long)ReadDeltaUInt64((ulong)valueA); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public ulong ReadDeltaUInt64(ulong valueA) { bool bLargerThanA = ReadBoolean(); ulong diff = ReadUnsignedPackedWhole(); return (bLargerThanA) ? (valueA + diff) : (valueA - diff); } /// /// Returns a new result by reading and applying a difference to a value. /// [DefaultDeltaReader] private long ReadDifference8_16_32(long valueA) { long diff = ReadSignedPackedWhole(); return (valueA + diff); } #endregion #region Single. /// /// Reads a value. /// public float ReadDeltaSingle(UDeltaPrecisionType dpt, bool unsigned) { if (dpt.FastContains(UDeltaPrecisionType.UInt8)) { if (unsigned) return (ReadUInt8Unpacked() / (float)DOUBLE_ACCURACY); else return (ReadInt8Unpacked() / (float)DOUBLE_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt16)) { if (unsigned) return (ReadUInt16Unpacked() / (float)DOUBLE_ACCURACY); else return (ReadInt16Unpacked() / (float)DOUBLE_ACCURACY); } //Everything else is unpacked. else { return ReadSingleUnpacked(); } } /// /// Reads a difference, appending it onto a value. /// public float ReadDeltaSingle(UDeltaPrecisionType dpt, float valueA, bool unsigned) { float diff = ReadDeltaSingle(dpt, unsigned); if (unsigned) { bool bLargerThanA = dpt.FastContains(UDeltaPrecisionType.NextValueIsLarger); return (bLargerThanA) ? (valueA + diff) : (valueA - diff); } else { return (valueA + diff); } } /// /// Reads a difference, appending it onto a value. /// public float ReadDeltaSingle(float valueA) { const bool unsigned = false; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaSingle(dpt, valueA, unsigned); } /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public float ReadUDeltaSingle(float valueA) { const bool unsigned = true; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaSingle(dpt, valueA, unsigned); } #endregion #region Double. /// /// Reads a value. /// public double ReadDeltaDouble(UDeltaPrecisionType dpt, bool unsigned) { if (dpt.FastContains(UDeltaPrecisionType.UInt8)) { if (unsigned) return (ReadUInt8Unpacked() / DOUBLE_ACCURACY); else return (ReadInt8Unpacked() / DOUBLE_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt16)) { if (unsigned) return (ReadUInt16Unpacked() / DOUBLE_ACCURACY); else return (ReadInt16Unpacked() / DOUBLE_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt32)) { if (unsigned) return (ReadUInt32Unpacked() / DOUBLE_ACCURACY); else return (ReadInt32Unpacked() / DOUBLE_ACCURACY); } //Unpacked. else if (dpt.FastContains(UDeltaPrecisionType.Unset)) { return ReadDoubleUnpacked(); } else { NetworkManager.LogError($"Unhandled precision type of {dpt}."); return 0d; } } /// /// Reads a difference, appending it onto a value. /// public double ReadDeltaDouble(UDeltaPrecisionType dpt, double valueA, bool unsigned) { double diff = ReadDeltaDouble(dpt, unsigned); //8. if (unsigned) { bool bLargerThanA = dpt.FastContains(UDeltaPrecisionType.NextValueIsLarger); return (bLargerThanA) ? (valueA + diff) : (valueA - diff); } else { return (valueA + diff); } } /// /// Reads a difference, appending it onto a value. /// public double ReadDeltaDouble(double valueA) { const bool unsigned = false; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaDouble(dpt, valueA, unsigned); } /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public double ReadUDeltaDouble(double valueA) { const bool unsigned = true; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaDouble(dpt, valueA, unsigned); } #endregion #region Decimal. /// /// Reads a value. /// public decimal ReadDeltaDecimal(UDeltaPrecisionType dpt, bool unsigned) { if (dpt.FastContains(UDeltaPrecisionType.UInt8)) { if (unsigned) return (ReadUInt8Unpacked() / DECIMAL_ACCURACY); else return (ReadInt8Unpacked() / DECIMAL_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt16)) { if (unsigned) return (ReadUInt16Unpacked() / DECIMAL_ACCURACY); else return (ReadInt16Unpacked() / DECIMAL_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt32)) { if (unsigned) return (ReadUInt32Unpacked() / DECIMAL_ACCURACY); else return (ReadInt32Unpacked() / DECIMAL_ACCURACY); } else if (dpt.FastContains(UDeltaPrecisionType.UInt64)) { if (unsigned) return (ReadUInt64Unpacked() / DECIMAL_ACCURACY); else return (ReadInt64Unpacked() / DECIMAL_ACCURACY); } //Unpacked. else if (dpt.FastContains(UDeltaPrecisionType.Unset)) { return ReadDecimalUnpacked(); } else { NetworkManager.LogError($"Unhandled precision type of {dpt}."); return 0m; } } /// /// Reads a difference, appending it onto a value. /// public decimal ReadDeltaDecimal(UDeltaPrecisionType dpt, decimal valueA, bool unsigned) { decimal diff = ReadDeltaDecimal(dpt, unsigned); if (unsigned) { bool bLargerThanA = dpt.FastContains(UDeltaPrecisionType.NextValueIsLarger); return (bLargerThanA) ? (valueA + diff) : (valueA - diff); } else { return (valueA + diff); } } /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public decimal ReadDeltaDecimal(decimal valueA) { const bool unsigned = false; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaDecimal(dpt, valueA, unsigned); } /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public decimal ReadUDeltaDecimal(decimal valueA) { const bool unsigned = true; UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked(); return ReadDeltaDecimal(dpt, valueA, unsigned); } #endregion #region FishNet Types. /// /// Reads a delta value. /// /// True if written. [DefaultDeltaReader] public NetworkBehaviour WriteDeltaNetworkBehaviour(NetworkBehaviour valueA) { return ReadNetworkBehaviour(); } #endregion #region Unity. /// /// Reads a difference, appending it onto a value. /// (not really for Quaternion). /// [DefaultDeltaReader] public Quaternion ReadDeltaQuaternion(Quaternion valueA, float precision = Writer.QUATERNION_PRECISION) => QuaternionDeltaPrecisionCompression.Decompress(this, valueA, precision); /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public Vector2 ReadDeltaVector2(Vector2 valueA) { byte allFlags = ReadUInt8Unpacked(); if ((allFlags & 1) == 1) valueA.x = ReadUDeltaSingle(valueA.x); if ((allFlags & 2) == 2) valueA.y = ReadUDeltaSingle(valueA.y); return valueA; } /// /// Reads a difference, appending it onto a value. /// [DefaultDeltaReader] public Vector3 ReadDeltaVector3(Vector3 valueA) { byte allFlags = ReadUInt8Unpacked(); if ((allFlags & 1) == 1) valueA.x = ReadUDeltaSingle(valueA.x); if ((allFlags & 2) == 2) valueA.y = ReadUDeltaSingle(valueA.y); if ((allFlags & 4) == 4) valueA.z = ReadUDeltaSingle(valueA.z); return valueA; } #endregion #region Prediction. /// /// Reads a reconcile. /// internal T ReadDeltaReconcile(T lastReconcile) => ReadDelta(lastReconcile); /// /// Reads a replicate. /// internal int ReadDeltaReplicate(T lastReadReplicate, ref T[] collection, uint tick) where T : IReplicateData { int startRemaining = Remaining; //Number of entries written. int count = (int)ReadUInt8Unpacked(); if (collection == null || collection.Length < count) collection = new T[count]; /* Subtract count total minus 1 * from starting tick. This sets the tick to what the first entry would be. * EG packet came in as tick 100, so that was passed as tick. * if there are 3 replicates then 2 would be subtracted (count - 1). * The new tick would be 98. * Ticks would be assigned to read values from oldest to * newest as 98, 99, 100. Which is the correct result. In order for this to * work properly past replicates cannot skip ticks. This will be ensured * in another part of the code. */ tick -= (uint)(count - 1); uint lastReadTick = lastReadReplicate.GetTick(); T prev = lastReadReplicate; for (int i = 0; i < count; i++) { //Tick read is for. uint readTick = (tick + (uint)i); /* If readTick is equal or lesser than lastReadReplicate * then there is no reason to process the data other than getting * it out of the reader. */ if (readTick <= lastReadTick) { ReadDelta(prev); } else { T value = ReadDelta(prev); //Apply tick. value.SetTick(readTick); //Assign to collection. collection[i] = value; //Update previous. prev = value; } } return count; } #endregion #region Generic. /// /// Reads a delta of any time. /// public T ReadDelta(T prev) { Func del = GenericDeltaReader.Read; if (del == null) { NetworkManager.LogError($"Read delta method not found for {typeof(T).FullName}. Use a supported type or create a custom serializer."); return default; } else { return del.Invoke(this, prev); } } #endregion } }