using FishNet.Utility; using System.Runtime.CompilerServices; using FishNet.CodeGenerating; using FishNet.Transporting; using GameKit.Dependencies.Utilities; [assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)] namespace FishNet.Object.Prediction { [MakePublic] internal struct ReplicateDataContainer where T : IReplicateData, new() { #region Types private enum DataCachingType { Unset, ValueType, IResettableReferenceType, ReferenceType, } #endregion /// /// Replicate data. /// public T Data; /// /// True if the data was created locally or came through the network as created. /// public bool IsCreated; /// /// Channel the data came in on. /// public readonly Channel Channel; /// /// True if populated. /// public bool IsValid { get; private set; } /// /// How data should be cached and retrieved when not set. /// private static DataCachingType _dataCachingType = DataCachingType.Unset; public ReplicateDataContainer(T data, Channel channel) : this(data, channel, tick: 0, isCreated: false) { } public ReplicateDataContainer(T data, Channel channel, bool isCreated) : this(data, channel, tick: 0, isCreated) { } public ReplicateDataContainer(T data, Channel channel, uint tick, bool isCreated = false) { Data = data; Channel = channel; IsCreated = isCreated; IsValid = true; SetDataTick(tick); } /// /// A shortcut to calling Data.SetTick. /// public void SetDataTick(uint tick) { SetDataIfNull(ref Data); Data.SetTick(tick); } /// /// Sets data to new() if is nullable type, and is null. /// /// private void SetDataIfNull(ref T data) { //Only figure out data caching type once to save perf. if (_dataCachingType == DataCachingType.Unset) { if (typeof(T).IsValueType) _dataCachingType = DataCachingType.ValueType; else if (typeof(IResettable).IsAssignableFrom(typeof(T))) _dataCachingType = DataCachingType.IResettableReferenceType; else _dataCachingType = DataCachingType.ReferenceType; } if (_dataCachingType != DataCachingType.ValueType && data == null) data = ObjectCaches.Retrieve(); } public void Dispose() { if (Data != null) Data.Dispose(); IsValid = false; } public static ReplicateDataContainer GetDefault(uint tick) => new(default(T), Channel.Unreliable, tick); public static ReplicateDataContainer GetDefault() => GetDefault(tick: 0); } }