#if !NET35 using System.Collections; using System.Collections.Generic; using System.IO; using MLAPI.Serialization.Pooled; using MLAPI.Transports; namespace MLAPI.NetworkVariable.Collections { /// /// Event based NetworkVariable container for syncing Sets /// /// The type for the set public class NetworkSet : ISet, INetworkVariable { private readonly ISet m_Set = new HashSet(); private readonly List> m_DirtyEvents = new List>(); private NetworkBehaviour m_NetworkBehaviour; /// /// Gets the last time the variable was synced /// public float LastSyncedTime { get; internal set; } /// /// The settings for this container /// public readonly NetworkVariableSettings Settings = new NetworkVariableSettings(); /// /// Delegate type for set changed event /// /// Struct containing information about the change event public delegate void OnSetChangedDelegate(NetworkSetEvent changeEvent); /// /// The callback to be invoked when the set gets changed /// public event OnSetChangedDelegate OnSetChanged; /// /// Creates a NetworkSet with the default value and settings /// public NetworkSet() { } /// /// Creates a NetworkSet with the default value and custom settings /// /// The settings to use for the NetworkList public NetworkSet(NetworkVariableSettings settings) { Settings = settings; } /// /// Creates a NetworkSet with a custom value and custom settings /// /// The settings to use for the NetworkSet /// The initial value to use for the NetworkSet public NetworkSet(NetworkVariableSettings settings, ISet value) { Settings = settings; m_Set = value; } /// /// Creates a NetworkSet with a custom value and the default settings /// /// The initial value to use for the NetworkList public NetworkSet(ISet value) { m_Set = value; } /// public void ResetDirty() { m_DirtyEvents.Clear(); LastSyncedTime = NetworkManager.Singleton.NetworkTime; } /// public bool IsDirty() { if (m_DirtyEvents.Count == 0) return false; if (Settings.SendTickrate == 0) return true; if (Settings.SendTickrate < 0) return false; if (NetworkManager.Singleton.NetworkTime - LastSyncedTime >= (1f / Settings.SendTickrate)) return true; return false; } /// public NetworkChannel GetChannel() { return Settings.SendNetworkChannel; } /// public bool CanClientWrite(ulong clientId) { switch (Settings.WritePermission) { case NetworkVariablePermission.Everyone: return true; case NetworkVariablePermission.ServerOnly: return false; case NetworkVariablePermission.OwnerOnly: return m_NetworkBehaviour.OwnerClientId == clientId; case NetworkVariablePermission.Custom: { if (Settings.WritePermissionCallback == null) return false; return Settings.WritePermissionCallback(clientId); } } return true; } /// public bool CanClientRead(ulong clientId) { switch (Settings.ReadPermission) { case NetworkVariablePermission.Everyone: return true; case NetworkVariablePermission.ServerOnly: return false; case NetworkVariablePermission.OwnerOnly: return m_NetworkBehaviour.OwnerClientId == clientId; case NetworkVariablePermission.Custom: { if (Settings.ReadPermissionCallback == null) return false; return Settings.ReadPermissionCallback(clientId); } } return true; } /// public void WriteDelta(Stream stream) { using (var writer = PooledNetworkWriter.Get(stream)) { writer.WriteUInt16Packed((ushort)m_DirtyEvents.Count); for (int i = 0; i < m_DirtyEvents.Count; i++) { writer.WriteBits((byte)m_DirtyEvents[i].Type, 2); switch (m_DirtyEvents[i].Type) { case NetworkSetEvent.EventType.Add: { writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX } break; case NetworkSetEvent.EventType.Remove: { writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX } break; case NetworkSetEvent.EventType.Clear: { //Nothing has to be written } break; } } } } /// public void WriteField(Stream stream) { using (var writer = PooledNetworkWriter.Get(stream)) { writer.WriteUInt16Packed((ushort)m_Set.Count); foreach (T value in m_Set) { writer.WriteObjectPacked(value); //BOX } } } /// public void ReadField(Stream stream, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { m_Set.Clear(); ushort count = reader.ReadUInt16Packed(); for (int i = 0; i < count; i++) { m_Set.Add((T)reader.ReadObjectPacked(typeof(T))); //BOX } } } /// public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { ushort deltaCount = reader.ReadUInt16Packed(); for (int i = 0; i < deltaCount; i++) { NetworkSetEvent.EventType eventType = (NetworkSetEvent.EventType)reader.ReadBits(2); switch (eventType) { case NetworkSetEvent.EventType.Add: { T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Add(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent() { Type = eventType, Value = value }); } } break; case NetworkSetEvent.EventType.Remove: { T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Remove(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent() { Type = eventType, Value = value }); } } break; case NetworkSetEvent.EventType.Clear: { //Read nothing m_Set.Clear(); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent { Type = eventType, }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent() { Type = eventType }); } } break; } } } } /// public void SetNetworkBehaviour(NetworkBehaviour behaviour) { m_NetworkBehaviour = behaviour; } /// public IEnumerator GetEnumerator() { return m_Set.GetEnumerator(); } /// IEnumerator IEnumerable.GetEnumerator() { return m_Set.GetEnumerator(); } /// void ICollection.Add(T item) { if (NetworkManager.Singleton.IsServer) m_Set.Add(item); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Add, Value = item }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); } /// public void ExceptWith(IEnumerable other) { foreach (T value in other) { if (m_Set.Contains(value)) { Remove(value); } } } /// public void IntersectWith(IEnumerable other) { HashSet otherSet = new HashSet(other); foreach (T value in m_Set) { if (!otherSet.Contains(value)) { Remove(value); } } } /// public bool IsProperSubsetOf(IEnumerable other) { return m_Set.IsProperSubsetOf(other); } /// public bool IsProperSupersetOf(IEnumerable other) { return m_Set.IsProperSupersetOf(other); } /// public bool IsSubsetOf(IEnumerable other) { return m_Set.IsSubsetOf(other); } /// public bool IsSupersetOf(IEnumerable other) { return m_Set.IsSupersetOf(other); } /// public bool Overlaps(IEnumerable other) { return m_Set.Overlaps(other); } /// public bool SetEquals(IEnumerable other) { return m_Set.SetEquals(other); } /// public void SymmetricExceptWith(IEnumerable other) { foreach (T value in other) { if (m_Set.Contains(value)) { Remove(value); } else { if (NetworkManager.Singleton.IsServer) m_Set.Add(value); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Add, Value = value }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); } } } /// public void UnionWith(IEnumerable other) { foreach (T value in other) { if (!m_Set.Contains(value)) { if (NetworkManager.Singleton.IsServer) m_Set.Add(value); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Add, Value = value }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); } } } /// bool ISet.Add(T item) { if (NetworkManager.Singleton.IsServer) m_Set.Add(item); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Add, Value = item }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); return true; } /// public void Clear() { if (NetworkManager.Singleton.IsServer) m_Set.Clear(); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Clear }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); } /// public bool Contains(T item) { return m_Set.Contains(item); } /// public void CopyTo(T[] array, int arrayIndex) { m_Set.CopyTo(array, arrayIndex); } /// public bool Remove(T item) { if (NetworkManager.Singleton.IsServer) m_Set.Remove(item); NetworkSetEvent setEvent = new NetworkSetEvent() { Type = NetworkSetEvent.EventType.Remove, Value = item }; m_DirtyEvents.Add(setEvent); if (NetworkManager.Singleton.IsServer && OnSetChanged != null) OnSetChanged(setEvent); return true; } /// public int Count => m_Set.Count; /// public bool IsReadOnly => m_Set.IsReadOnly; public ushort RemoteTick { get { // todo: implement proper network tick for NetworkSet return NetworkTickSystem.NoTick; } } } /// /// Struct containing event information about changes to a NetworkSet. /// /// The type for the set that the event is about public struct NetworkSetEvent { /// /// Enum representing the different operations available for triggering an event. /// public enum EventType { /// /// Add /// Add, /// /// Remove /// Remove, /// /// Clear /// Clear } /// /// Enum representing the operation made to the set. /// public EventType Type; /// /// The value changed, added or removed if available. /// public T Value; } } #endif