Unity-WebSocket/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs
2025-06-28 11:28:54 +03:30

468 lines
15 KiB
C#

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.
/// <summary>
/// Reads a boolean.
/// </summary>
[DefaultDeltaReader]
public bool ReadDeltaBoolean(bool valueA)
{
return !valueA;
}
#endregion
#region Whole values.
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public sbyte ReadDeltaInt8(sbyte valueA) => (sbyte)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public byte ReadDeltaUInt8(byte valueA) => (byte)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public short ReadDeltaInt16(short valueA) => (short)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public ushort ReadDeltaUInt16(ushort valueA) => (ushort)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public int ReadDeltaInt32(int valueA) => (int)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public uint ReadDeltaUInt32(uint valueA) => (uint)ReadDifference8_16_32(valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public long ReadDeltaInt64(long valueA) => (long)ReadDeltaUInt64((ulong)valueA);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public ulong ReadDeltaUInt64(ulong valueA)
{
bool bLargerThanA = ReadBoolean();
ulong diff = ReadUnsignedPackedWhole();
return (bLargerThanA) ? (valueA + diff) : (valueA - diff);
}
/// <summary>
/// Returns a new result by reading and applying a difference to a value.
/// </summary>
[DefaultDeltaReader]
private long ReadDifference8_16_32(long valueA)
{
long diff = ReadSignedPackedWhole();
return (valueA + diff);
}
#endregion
#region Single.
/// <summary>
/// Reads a value.
/// </summary>
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();
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
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);
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
public float ReadDeltaSingle(float valueA)
{
const bool unsigned = false;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaSingle(dpt, valueA, unsigned);
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public float ReadUDeltaSingle(float valueA)
{
const bool unsigned = true;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaSingle(dpt, valueA, unsigned);
}
#endregion
#region Double.
/// <summary>
/// Reads a value.
/// </summary>
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;
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
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);
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
public double ReadDeltaDouble(double valueA)
{
const bool unsigned = false;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaDouble(dpt, valueA, unsigned);
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public double ReadUDeltaDouble(double valueA)
{
const bool unsigned = true;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaDouble(dpt, valueA, unsigned);
}
#endregion
#region Decimal.
/// <summary>
/// Reads a value.
/// </summary>
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;
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
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);
}
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public decimal ReadDeltaDecimal(decimal valueA)
{
const bool unsigned = false;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaDecimal(dpt, valueA, unsigned);
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[DefaultDeltaReader]
public decimal ReadUDeltaDecimal(decimal valueA)
{
const bool unsigned = true;
UDeltaPrecisionType dpt = (UDeltaPrecisionType)ReadUInt8Unpacked();
return ReadDeltaDecimal(dpt, valueA, unsigned);
}
#endregion
#region FishNet Types.
/// <summary>
/// Reads a delta value.
/// </summary>
/// <returns>True if written.</returns>
[DefaultDeltaReader]
public NetworkBehaviour WriteDeltaNetworkBehaviour(NetworkBehaviour valueA)
{
return ReadNetworkBehaviour();
}
#endregion
#region Unity.
/// <summary>
/// Reads a difference, appending it onto a value.
/// (not really for Quaternion).
/// </summary>
[DefaultDeltaReader]
public Quaternion ReadDeltaQuaternion(Quaternion valueA, float precision = Writer.QUATERNION_PRECISION) => QuaternionDeltaPrecisionCompression.Decompress(this, valueA, precision);
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[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;
}
/// <summary>
/// Reads a difference, appending it onto a value.
/// </summary>
[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.
/// <summary>
/// Reads a reconcile.
/// </summary>
internal T ReadDeltaReconcile<T>(T lastReconcile) => ReadDelta(lastReconcile);
/// <summary>
/// Reads a replicate.
/// </summary>
internal int ReadDeltaReplicate<T>(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.
/// <summary>
/// Reads a delta of any time.
/// </summary>
public T ReadDelta<T>(T prev)
{
Func<Reader, T, T> del = GenericDeltaReader<T>.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
}
}