#if UNITY_EDITOR || DEVELOPMENT_BUILD
#define DEVELOPMENT
#endif
using FishNet.Managing;
using FishNet.Managing.Predicting;
using FishNet.Managing.Timing;
using FishNet.Managing.Transporting;
using FishNet.Serializing;
using FishNet.Transporting;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace FishNet.Connection
{
///
/// A container for a connected client used to perform actions on and gather information for the declared client.
///
public partial class NetworkConnection
{
///
/// Approximate replicate tick on the server for this connection.
/// This also contains the last set value for local and remote.
///
public EstimatedTick ReplicateTick { get; private set; } = new();
///
/// Writers for states.
///
internal List PredictionStateWriters = new();
internal void Prediction_Initialize(NetworkManager manager, bool asServer) { }
///
/// Writes a prediction state.
///
///
internal void WriteState(PooledWriter data)
{
#if !DEVELOPMENT
// Do not send states to clientHost.
if (IsLocalClient)
return;
#endif
TimeManager timeManager = NetworkManager.TimeManager;
TransportManager transportManager = NetworkManager.TransportManager;
uint ticksBehind = IsLocalClient ? 0 : PacketTick.LocalTickDifference(timeManager);
/* If it's been a really long while the client could just be setting up
* or dropping. Only send if they've communicated within 5 seconds. */
if (ticksBehind > timeManager.TickRate * 5)
return;
int mtu = transportManager.GetLowestMTU((byte)Channel.Unreliable);
PooledWriter stateWriter;
int writerCount = PredictionStateWriters.Count;
//If there are no writers then get a new writer.
if (writerCount == 0 || data.Length > mtu)
{
AddNewStateWriter();
}
/* If a current writer exist and
* if the data length + existing written data will exceed
* MTU then get a new writer. */
else
{
int lengthInCurrentWriter = PredictionStateWriters[writerCount - 1].Length;
int totalLength = lengthInCurrentWriter + data.Length;
if (totalLength > mtu)
AddNewStateWriter();
}
void AddNewStateWriter()
{
stateWriter = WriterPool.Retrieve(mtu);
PredictionStateWriters.Add(stateWriter);
stateWriter.Skip(PredictionManager.STATE_HEADER_RESERVE_LENGTH);
/// 2 PacketId.
/// 4 Last replicate tick run for connection.
/// 4 Length unpacked.
writerCount++;
}
stateWriter = PredictionStateWriters[writerCount - 1];
stateWriter.WriteArraySegment(data.GetArraySegment());
}
///
/// Stores prediction writers to be re-used later.
///
internal void StorePredictionStateWriters()
{
for (int i = 0; i < PredictionStateWriters.Count; i++)
WriterPool.Store(PredictionStateWriters[i]);
PredictionStateWriters.Clear();
}
///
/// Sets the last tick a NetworkBehaviour replicated with.
///
/// True to set unordered value, false to set ordered.
internal void SetReplicateTick(uint value, EstimatedTick.OldTickOption oldTickOption = EstimatedTick.OldTickOption.Discard)
{
ReplicateTick.Update(value, oldTickOption);
}
///
/// Resets NetworkConnection.
///
private void Prediction_Reset()
{
StorePredictionStateWriters();
ReplicateTick.Reset();
}
}
}