Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 614a7000210157648b54dd16914b97b5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,598 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MLAPI.Serialization.Pooled;
|
||||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Event based NetworkVariable container for syncing Dictionaries
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type for the dictionary keys</typeparam>
|
||||
/// <typeparam name="TValue">The type for the dictionary values</typeparam>
|
||||
public class NetworkDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the last time the variable was synced
|
||||
/// </summary>
|
||||
public float LastSyncedTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings for this container
|
||||
/// </summary>
|
||||
public readonly NetworkVariableSettings Settings = new NetworkVariableSettings();
|
||||
|
||||
private readonly IDictionary<TKey, TValue> m_Dictionary = new Dictionary<TKey, TValue>();
|
||||
private NetworkBehaviour m_NetworkBehaviour;
|
||||
private readonly List<NetworkDictionaryEvent<TKey, TValue>> m_DirtyEvents = new List<NetworkDictionaryEvent<TKey, TValue>>();
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for dictionary changed event
|
||||
/// </summary>
|
||||
/// <param name="changeEvent">Struct containing information about the change event</param>
|
||||
public delegate void OnDictionaryChangedDelegate(NetworkDictionaryEvent<TKey, TValue> changeEvent);
|
||||
|
||||
/// <summary>
|
||||
/// The callback to be invoked when the dictionary gets changed
|
||||
/// </summary>
|
||||
public event OnDictionaryChangedDelegate OnDictionaryChanged;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkDictionary with the default value and settings
|
||||
/// </summary>
|
||||
public NetworkDictionary() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkDictionary with the default value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkDictionary</param>
|
||||
public NetworkDictionary(NetworkVariableSettings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkDictionary with a custom value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkDictionary</param>
|
||||
/// <param name="value">The initial value to use for the NetworkDictionary</param>
|
||||
public NetworkDictionary(NetworkVariableSettings settings, IDictionary<TKey, TValue> value)
|
||||
{
|
||||
Settings = settings;
|
||||
m_Dictionary = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkDictionary with a custom value and the default settings
|
||||
/// </summary>
|
||||
/// <param name="value">The initial value to use for the NetworkDictionary</param>
|
||||
public NetworkDictionary(IDictionary<TKey, TValue> value)
|
||||
{
|
||||
m_Dictionary = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetDirty()
|
||||
{
|
||||
m_DirtyEvents.Clear();
|
||||
LastSyncedTime = NetworkManager.Singleton.NetworkTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkChannel GetChannel()
|
||||
{
|
||||
return Settings.SendNetworkChannel;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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++)
|
||||
{
|
||||
NetworkDictionaryEvent<TKey, TValue>.EventType eventType = (NetworkDictionaryEvent<TKey, TValue>.EventType)reader.ReadBits(3);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Add:
|
||||
{
|
||||
TKey key = (TKey)reader.ReadObjectPacked(typeof(TKey));
|
||||
TValue value = (TValue)reader.ReadObjectPacked(typeof(TValue));
|
||||
m_Dictionary.Add(key, value);
|
||||
|
||||
if (OnDictionaryChanged != null)
|
||||
{
|
||||
OnDictionaryChanged(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Remove:
|
||||
{
|
||||
TKey key = (TKey)reader.ReadObjectPacked(typeof(TKey));
|
||||
TValue value;
|
||||
m_Dictionary.TryGetValue(key, out value);
|
||||
m_Dictionary.Remove(key);
|
||||
|
||||
if (OnDictionaryChanged != null)
|
||||
{
|
||||
OnDictionaryChanged(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.RemovePair:
|
||||
{
|
||||
TKey key = (TKey)reader.ReadObjectPacked(typeof(TKey));
|
||||
TValue value = (TValue)reader.ReadObjectPacked(typeof(TValue));
|
||||
m_Dictionary.Remove(new KeyValuePair<TKey, TValue>(key, value));
|
||||
|
||||
if (OnDictionaryChanged != null)
|
||||
{
|
||||
OnDictionaryChanged(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Clear:
|
||||
{
|
||||
//read nothing
|
||||
m_Dictionary.Clear();
|
||||
|
||||
if (OnDictionaryChanged != null)
|
||||
{
|
||||
OnDictionaryChanged(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Value:
|
||||
{
|
||||
TKey key = (TKey)reader.ReadObjectPacked(typeof(TKey));
|
||||
TValue value = (TValue)reader.ReadObjectPacked(typeof(TValue));
|
||||
|
||||
m_Dictionary[key] = value;
|
||||
|
||||
if (OnDictionaryChanged != null)
|
||||
{
|
||||
OnDictionaryChanged(new NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = eventType,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReadField(Stream stream, ushort localTick, ushort remoteTick)
|
||||
{
|
||||
using (var reader = PooledNetworkReader.Get(stream))
|
||||
{
|
||||
m_Dictionary.Clear();
|
||||
ushort entryCount = reader.ReadUInt16Packed();
|
||||
for (int i = 0; i < entryCount; i++)
|
||||
{
|
||||
TKey key = (TKey)reader.ReadObjectPacked(typeof(TKey));
|
||||
TValue value = (TValue)reader.ReadObjectPacked(typeof(TValue));
|
||||
m_Dictionary.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetNetworkBehaviour(NetworkBehaviour behaviour)
|
||||
{
|
||||
m_NetworkBehaviour = behaviour;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
return m_Dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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, 3);
|
||||
switch (m_DirtyEvents[i].Type)
|
||||
{
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Add:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Key);
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value);
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Remove:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Key);
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.RemovePair:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Key);
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value);
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Clear:
|
||||
{
|
||||
//write nothing
|
||||
}
|
||||
break;
|
||||
case NetworkDictionaryEvent<TKey, TValue>.EventType.Value:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Key);
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteField(Stream stream)
|
||||
{
|
||||
using (var writer = PooledNetworkWriter.Get(stream))
|
||||
{
|
||||
writer.WriteUInt16Packed((ushort)m_Dictionary.Count);
|
||||
foreach (KeyValuePair<TKey, TValue> pair in m_Dictionary)
|
||||
{
|
||||
writer.WriteObjectPacked(pair.Key);
|
||||
writer.WriteObjectPacked(pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get => m_Dictionary[key];
|
||||
set
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Dictionary[key] = value;
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Value,
|
||||
Key = key,
|
||||
Value = value
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<TKey> Keys => m_Dictionary.Keys;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<TValue> Values => m_Dictionary.Values;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => m_Dictionary.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => m_Dictionary.IsReadOnly;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Dictionary.Add(key, value);
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Add,
|
||||
Key = key,
|
||||
Value = value
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Dictionary.Add(item);
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Add,
|
||||
Key = item.Key,
|
||||
Value = item.Value
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Dictionary.Clear();
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Clear
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return m_Dictionary.Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return m_Dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
m_Dictionary.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return m_Dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer)
|
||||
m_Dictionary.Remove(key);
|
||||
|
||||
TValue value;
|
||||
m_Dictionary.TryGetValue(key, out value);
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.Remove,
|
||||
Key = key,
|
||||
Value = value
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Dictionary.Remove(item);
|
||||
|
||||
NetworkDictionaryEvent<TKey, TValue> dictionaryEvent = new NetworkDictionaryEvent<TKey, TValue>()
|
||||
{
|
||||
Type = NetworkDictionaryEvent<TKey, TValue>.EventType.RemovePair,
|
||||
Key = item.Key,
|
||||
Value = item.Value
|
||||
};
|
||||
|
||||
HandleAddDictionaryEvent(dictionaryEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return m_Dictionary.GetEnumerator();
|
||||
}
|
||||
|
||||
private void HandleAddDictionaryEvent(NetworkDictionaryEvent<TKey, TValue> dictionaryEvent)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer)
|
||||
{
|
||||
if (NetworkManager.Singleton.ConnectedClients.Count > 0)
|
||||
{
|
||||
m_DirtyEvents.Add(dictionaryEvent);
|
||||
}
|
||||
|
||||
OnDictionaryChanged?.Invoke(dictionaryEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DirtyEvents.Add(dictionaryEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public ushort RemoteTick
|
||||
{
|
||||
get
|
||||
{
|
||||
// todo: implement proper network tick for NetworkDictionary
|
||||
return NetworkTickSystem.NoTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Struct containing event information about changes to a NetworkDictionary.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type for the dictionary key that the event is about</typeparam>
|
||||
/// <typeparam name="TValue">The type for the dictionary value that the event is about</typeparam>
|
||||
public struct NetworkDictionaryEvent<TKey, TValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum representing the different operations available for triggering an event.
|
||||
/// </summary>
|
||||
public enum EventType
|
||||
{
|
||||
/// <summary>
|
||||
/// Add
|
||||
/// </summary>
|
||||
Add,
|
||||
|
||||
/// <summary>
|
||||
/// Remove
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Remove pair
|
||||
/// </summary>
|
||||
RemovePair,
|
||||
|
||||
/// <summary>
|
||||
/// Clear
|
||||
/// </summary>
|
||||
Clear,
|
||||
|
||||
/// <summary>
|
||||
/// Value changed
|
||||
/// </summary>
|
||||
Value
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the operation made to the dictionary.
|
||||
/// </summary>
|
||||
public EventType Type;
|
||||
|
||||
/// <summary>
|
||||
/// the key changed, added or removed if available.
|
||||
/// </summary>
|
||||
public TKey Key;
|
||||
|
||||
/// <summary>
|
||||
/// The value changed, added or removed if available.
|
||||
/// </summary>
|
||||
public TValue Value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 262db7b2db1128748a2e88dd7e20a764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,602 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MLAPI.Serialization.Pooled;
|
||||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Event based NetworkVariable container for syncing Lists
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the list</typeparam>
|
||||
public class NetworkList<T> : IList<T>, INetworkVariable
|
||||
{
|
||||
private readonly IList<T> m_List = new List<T>();
|
||||
private readonly List<NetworkListEvent<T>> m_DirtyEvents = new List<NetworkListEvent<T>>();
|
||||
private NetworkBehaviour m_NetworkBehaviour;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time the variable was synced
|
||||
/// </summary>
|
||||
public float LastSyncedTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings for this container
|
||||
/// </summary>
|
||||
public readonly NetworkVariableSettings Settings = new NetworkVariableSettings();
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for list changed event
|
||||
/// </summary>
|
||||
/// <param name="changeEvent">Struct containing information about the change event</param>
|
||||
public delegate void OnListChangedDelegate(NetworkListEvent<T> changeEvent);
|
||||
|
||||
/// <summary>
|
||||
/// The callback to be invoked when the list gets changed
|
||||
/// </summary>
|
||||
public event OnListChangedDelegate OnListChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkList with the default value and settings
|
||||
/// </summary>
|
||||
public NetworkList() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkList with the default value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkList</param>
|
||||
public NetworkList(NetworkVariableSettings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkList with a custom value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkList</param>
|
||||
/// <param name="value">The initial value to use for the NetworkList</param>
|
||||
public NetworkList(NetworkVariableSettings settings, IList<T> value)
|
||||
{
|
||||
Settings = settings;
|
||||
m_List = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkList with a custom value and the default settings
|
||||
/// </summary>
|
||||
/// <param name="value">The initial value to use for the NetworkList</param>
|
||||
public NetworkList(IList<T> value)
|
||||
{
|
||||
m_List = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetDirty()
|
||||
{
|
||||
m_DirtyEvents.Clear();
|
||||
LastSyncedTime = NetworkManager.Singleton.NetworkTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkChannel GetChannel()
|
||||
{
|
||||
return Settings.SendNetworkChannel;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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, 3);
|
||||
switch (m_DirtyEvents[i].Type)
|
||||
{
|
||||
case NetworkListEvent<T>.EventType.Add:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Insert:
|
||||
{
|
||||
writer.WriteInt32Packed(m_DirtyEvents[i].Index);
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Remove:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.RemoveAt:
|
||||
{
|
||||
writer.WriteInt32Packed(m_DirtyEvents[i].Index);
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Value:
|
||||
{
|
||||
writer.WriteInt32Packed(m_DirtyEvents[i].Index);
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Clear:
|
||||
{
|
||||
//Nothing has to be written
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteField(Stream stream)
|
||||
{
|
||||
using (var writer = PooledNetworkWriter.Get(stream))
|
||||
{
|
||||
writer.WriteUInt16Packed((ushort)m_List.Count);
|
||||
for (int i = 0; i < m_List.Count; i++)
|
||||
{
|
||||
writer.WriteObjectPacked(m_List[i]); //BOX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReadField(Stream stream, ushort localTick, ushort remoteTick)
|
||||
{
|
||||
using (var reader = PooledNetworkReader.Get(stream))
|
||||
{
|
||||
m_List.Clear();
|
||||
ushort count = reader.ReadUInt16Packed();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
m_List.Add((T)reader.ReadObjectPacked(typeof(T))); //BOX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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++)
|
||||
{
|
||||
NetworkListEvent<T>.EventType eventType = (NetworkListEvent<T>.EventType)reader.ReadBits(3);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetworkListEvent<T>.EventType.Add:
|
||||
{
|
||||
m_List.Add((T)reader.ReadObjectPacked(typeof(T))); //BOX
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Index = m_List.Count - 1,
|
||||
Value = m_List[m_List.Count - 1]
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Index = m_List.Count - 1,
|
||||
Value = m_List[m_List.Count - 1]
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Insert:
|
||||
{
|
||||
int index = reader.ReadInt32Packed();
|
||||
m_List.Insert(index, (T)reader.ReadObjectPacked(typeof(T))); //BOX
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = m_List[index]
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = m_List[index]
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Remove:
|
||||
{
|
||||
T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX
|
||||
int index = m_List.IndexOf(value);
|
||||
m_List.RemoveAt(index);
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.RemoveAt:
|
||||
{
|
||||
int index = reader.ReadInt32Packed();
|
||||
T value = m_List[index];
|
||||
m_List.RemoveAt(index);
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Value:
|
||||
{
|
||||
int index = reader.ReadInt32Packed();
|
||||
T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX
|
||||
if (index < m_List.Count) m_List[index] = value;
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Index = index,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkListEvent<T>.EventType.Clear:
|
||||
{
|
||||
//Read nothing
|
||||
m_List.Clear();
|
||||
|
||||
if (OnListChanged != null)
|
||||
{
|
||||
OnListChanged(new NetworkListEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkListEvent<T>()
|
||||
{
|
||||
Type = eventType
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetNetworkBehaviour(NetworkBehaviour behaviour)
|
||||
{
|
||||
m_NetworkBehaviour = behaviour;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return m_List.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)m_List).GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_List.Add(item);
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.Add,
|
||||
Value = item,
|
||||
Index = m_List.Count - 1
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_List.Clear();
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.Clear
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return m_List.Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
m_List.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_List.Remove(item);
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.Remove,
|
||||
Value = item
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => m_List.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => m_List.IsReadOnly;
|
||||
|
||||
/// <inheritdoc />
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
return m_List.IndexOf(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_List.Insert(index, item);
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.Insert,
|
||||
Index = index,
|
||||
Value = item
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_List.RemoveAt(index);
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.RemoveAt,
|
||||
Index = index
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public T this[int index]
|
||||
{
|
||||
get => m_List[index];
|
||||
set
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer)
|
||||
m_List[index] = value;
|
||||
|
||||
NetworkListEvent<T> listEvent = new NetworkListEvent<T>()
|
||||
{
|
||||
Type = NetworkListEvent<T>.EventType.Value,
|
||||
Index = index,
|
||||
Value = value
|
||||
};
|
||||
|
||||
HandleAddListEvent(listEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAddListEvent(NetworkListEvent<T> listEvent)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer)
|
||||
{
|
||||
if (NetworkManager.Singleton.ConnectedClients.Count > 0)
|
||||
{
|
||||
m_DirtyEvents.Add(listEvent);
|
||||
}
|
||||
|
||||
OnListChanged?.Invoke(listEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DirtyEvents.Add(listEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public ushort RemoteTick
|
||||
{
|
||||
get
|
||||
{
|
||||
// todo: implement proper network tick for NetworkList
|
||||
return NetworkTickSystem.NoTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Struct containing event information about changes to a NetworkList.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the list that the event is about</typeparam>
|
||||
public struct NetworkListEvent<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum representing the different operations available for triggering an event.
|
||||
/// </summary>
|
||||
public enum EventType
|
||||
{
|
||||
/// <summary>
|
||||
/// Add
|
||||
/// </summary>
|
||||
Add,
|
||||
|
||||
/// <summary>
|
||||
/// Insert
|
||||
/// </summary>
|
||||
Insert,
|
||||
|
||||
/// <summary>
|
||||
/// Remove
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Remove at
|
||||
/// </summary>
|
||||
RemoveAt,
|
||||
|
||||
/// <summary>
|
||||
/// Value changed
|
||||
/// </summary>
|
||||
Value,
|
||||
|
||||
/// <summary>
|
||||
/// Clear
|
||||
/// </summary>
|
||||
Clear
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the operation made to the list.
|
||||
/// </summary>
|
||||
public EventType Type;
|
||||
|
||||
/// <summary>
|
||||
/// The value changed, added or removed if available.
|
||||
/// </summary>
|
||||
public T Value;
|
||||
|
||||
/// <summary>
|
||||
/// the index changed, added or removed if available
|
||||
/// </summary>
|
||||
public int Index;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 42fb86f9389141347856337e3c62ad80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,548 @@
|
|||
#if !NET35
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MLAPI.Serialization.Pooled;
|
||||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Event based NetworkVariable container for syncing Sets
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the set</typeparam>
|
||||
public class NetworkSet<T> : ISet<T>, INetworkVariable
|
||||
{
|
||||
private readonly ISet<T> m_Set = new HashSet<T>();
|
||||
private readonly List<NetworkSetEvent<T>> m_DirtyEvents = new List<NetworkSetEvent<T>>();
|
||||
private NetworkBehaviour m_NetworkBehaviour;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time the variable was synced
|
||||
/// </summary>
|
||||
public float LastSyncedTime { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings for this container
|
||||
/// </summary>
|
||||
public readonly NetworkVariableSettings Settings = new NetworkVariableSettings();
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for set changed event
|
||||
/// </summary>
|
||||
/// <param name="changeEvent">Struct containing information about the change event</param>
|
||||
public delegate void OnSetChangedDelegate(NetworkSetEvent<T> changeEvent);
|
||||
|
||||
/// <summary>
|
||||
/// The callback to be invoked when the set gets changed
|
||||
/// </summary>
|
||||
public event OnSetChangedDelegate OnSetChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkSet with the default value and settings
|
||||
/// </summary>
|
||||
public NetworkSet() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkSet with the default value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkList</param>
|
||||
public NetworkSet(NetworkVariableSettings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkSet with a custom value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkSet</param>
|
||||
/// <param name="value">The initial value to use for the NetworkSet</param>
|
||||
public NetworkSet(NetworkVariableSettings settings, ISet<T> value)
|
||||
{
|
||||
Settings = settings;
|
||||
m_Set = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkSet with a custom value and the default settings
|
||||
/// </summary>
|
||||
/// <param name="value">The initial value to use for the NetworkList</param>
|
||||
public NetworkSet(ISet<T> value)
|
||||
{
|
||||
m_Set = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetDirty()
|
||||
{
|
||||
m_DirtyEvents.Clear();
|
||||
LastSyncedTime = NetworkManager.Singleton.NetworkTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkChannel GetChannel()
|
||||
{
|
||||
return Settings.SendNetworkChannel;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<T>.EventType.Add:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkSetEvent<T>.EventType.Remove:
|
||||
{
|
||||
writer.WriteObjectPacked(m_DirtyEvents[i].Value); //BOX
|
||||
}
|
||||
break;
|
||||
case NetworkSetEvent<T>.EventType.Clear:
|
||||
{
|
||||
//Nothing has to be written
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<T>.EventType eventType = (NetworkSetEvent<T>.EventType)reader.ReadBits(2);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetworkSetEvent<T>.EventType.Add:
|
||||
{
|
||||
T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX
|
||||
m_Set.Add(value);
|
||||
|
||||
if (OnSetChanged != null)
|
||||
{
|
||||
OnSetChanged(new NetworkSetEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkSetEvent<T>.EventType.Remove:
|
||||
{
|
||||
T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX
|
||||
m_Set.Remove(value);
|
||||
|
||||
if (OnSetChanged != null)
|
||||
{
|
||||
OnSetChanged(new NetworkSetEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = eventType,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkSetEvent<T>.EventType.Clear:
|
||||
{
|
||||
//Read nothing
|
||||
m_Set.Clear();
|
||||
|
||||
if (OnSetChanged != null)
|
||||
{
|
||||
OnSetChanged(new NetworkSetEvent<T>
|
||||
{
|
||||
Type = eventType,
|
||||
});
|
||||
}
|
||||
|
||||
if (keepDirtyDelta)
|
||||
{
|
||||
m_DirtyEvents.Add(new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = eventType
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetNetworkBehaviour(NetworkBehaviour behaviour)
|
||||
{
|
||||
m_NetworkBehaviour = behaviour;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return m_Set.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return m_Set.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Add(item);
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Add,
|
||||
Value = item
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ExceptWith(IEnumerable<T> other)
|
||||
{
|
||||
foreach (T value in other)
|
||||
{
|
||||
if (m_Set.Contains(value))
|
||||
{
|
||||
Remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void IntersectWith(IEnumerable<T> other)
|
||||
{
|
||||
HashSet<T> otherSet = new HashSet<T>(other);
|
||||
|
||||
foreach (T value in m_Set)
|
||||
{
|
||||
if (!otherSet.Contains(value))
|
||||
{
|
||||
Remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsProperSubsetOf(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.IsProperSubsetOf(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsProperSupersetOf(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.IsProperSupersetOf(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsSubsetOf(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.IsSubsetOf(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsSupersetOf(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.IsSupersetOf(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Overlaps(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.Overlaps(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SetEquals(IEnumerable<T> other)
|
||||
{
|
||||
return m_Set.SetEquals(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SymmetricExceptWith(IEnumerable<T> other)
|
||||
{
|
||||
foreach (T value in other)
|
||||
{
|
||||
if (m_Set.Contains(value))
|
||||
{
|
||||
Remove(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Add(value);
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Add,
|
||||
Value = value
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void UnionWith(IEnumerable<T> other)
|
||||
{
|
||||
foreach (T value in other)
|
||||
{
|
||||
if (!m_Set.Contains(value))
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Add(value);
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Add,
|
||||
Value = value
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
bool ISet<T>.Add(T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Add(item);
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Add,
|
||||
Value = item
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Clear();
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Clear
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return m_Set.Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
m_Set.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(T item)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer) m_Set.Remove(item);
|
||||
|
||||
NetworkSetEvent<T> setEvent = new NetworkSetEvent<T>()
|
||||
{
|
||||
Type = NetworkSetEvent<T>.EventType.Remove,
|
||||
Value = item
|
||||
};
|
||||
m_DirtyEvents.Add(setEvent);
|
||||
|
||||
if (NetworkManager.Singleton.IsServer && OnSetChanged != null)
|
||||
OnSetChanged(setEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => m_Set.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => m_Set.IsReadOnly;
|
||||
|
||||
public ushort RemoteTick
|
||||
{
|
||||
get
|
||||
{
|
||||
// todo: implement proper network tick for NetworkSet
|
||||
return NetworkTickSystem.NoTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Struct containing event information about changes to a NetworkSet.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the set that the event is about</typeparam>
|
||||
public struct NetworkSetEvent<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum representing the different operations available for triggering an event.
|
||||
/// </summary>
|
||||
public enum EventType
|
||||
{
|
||||
/// <summary>
|
||||
/// Add
|
||||
/// </summary>
|
||||
Add,
|
||||
|
||||
/// <summary>
|
||||
/// Remove
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Clear
|
||||
/// </summary>
|
||||
Clear
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the operation made to the set.
|
||||
/// </summary>
|
||||
public EventType Type;
|
||||
|
||||
/// <summary>
|
||||
/// The value changed, added or removed if available.
|
||||
/// </summary>
|
||||
public T Value;
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 245b489a4e4f2174fbdeb27b9cdee07b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using System.IO;
|
||||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for network value containers
|
||||
/// </summary>
|
||||
public interface INetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the name of the channel to be used for syncing
|
||||
/// </summary>
|
||||
/// <returns>The name of the channel to be used for syncing</returns>
|
||||
NetworkChannel GetChannel();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the dirty state and marks the variable as synced / clean
|
||||
/// </summary>
|
||||
void ResetDirty();
|
||||
|
||||
/// <summary>
|
||||
/// Gets Whether or not the container is dirty
|
||||
/// </summary>
|
||||
/// <returns>Whether or not the container is dirty</returns>
|
||||
bool IsDirty();
|
||||
|
||||
/// <summary>
|
||||
/// Gets Whether or not a specific client can write to the varaible
|
||||
/// </summary>
|
||||
/// <param name="clientId">The clientId of the remote client</param>
|
||||
/// <returns>Whether or not the client can write to the variable</returns>
|
||||
bool CanClientWrite(ulong clientId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets Whether or not a specific client can read to the varaible
|
||||
/// </summary>
|
||||
/// <param name="clientId">The clientId of the remote client</param>
|
||||
/// <returns>Whether or not the client can read to the variable</returns>
|
||||
bool CanClientRead(ulong clientId);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the dirty changes, that is, the changes since the variable was last dirty, to the writer
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write the dirty changes to</param>
|
||||
void WriteDelta(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the complete state of the variable to the writer
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write the state to</param>
|
||||
void WriteField(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the complete state from the reader and applies it
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read the state from</param>
|
||||
/// <param name="localTick">The local network tick at which this var was written, on the machine it was written </param>
|
||||
/// <param name="remoteTick">The remote network tick at which this var was sent by the host </param>
|
||||
void ReadField(Stream stream, ushort localTick, ushort remoteTick);
|
||||
|
||||
/// <summary>
|
||||
/// Reads delta from the reader and applies them to the internal value
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read the delta from</param>
|
||||
/// <param name="keepDirtyDelta">Whether or not the delta should be kept as dirty or consumed</param>
|
||||
/// <param name="localTick">The local network tick at which this var was written, on the machine it was written </param>
|
||||
/// <param name="remoteTick">The remote network tick at which this var was sent by the host </param>
|
||||
void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick);
|
||||
|
||||
/// <summary>
|
||||
/// Sets NetworkBehaviour the container belongs to.
|
||||
/// </summary>
|
||||
/// <param name="behaviour">The behaviour the container behaves to</param>
|
||||
void SetNetworkBehaviour(NetworkBehaviour behaviour);
|
||||
|
||||
/// <summary>
|
||||
/// Accessor for the RemoteTick stored in the networkVariable, list, set or dictionary
|
||||
/// </summary>
|
||||
ushort RemoteTick { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87f1fd4778c2dab4b8bc02c738cade25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,585 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System;
|
||||
using MLAPI.Serialization.Pooled;
|
||||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// A variable that can be synchronized over the network.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariable<T> : INetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// The settings for this var
|
||||
/// </summary>
|
||||
public readonly NetworkVariableSettings Settings = new NetworkVariableSettings();
|
||||
|
||||
/// <summary>
|
||||
/// The last time the variable was written to locally
|
||||
/// </summary>
|
||||
public ushort LocalTick { get; internal set; }
|
||||
/// <summary>
|
||||
/// The last time the variable was written to remotely. Uses the remote timescale
|
||||
/// </summary>
|
||||
public ushort RemoteTick { get; internal set; }
|
||||
/// <summary>
|
||||
/// Delegate type for value changed event
|
||||
/// </summary>
|
||||
/// <param name="previousValue">The value before the change</param>
|
||||
/// <param name="newValue">The new value</param>
|
||||
public delegate void OnValueChangedDelegate(T previousValue, T newValue);
|
||||
/// <summary>
|
||||
/// The callback to be invoked when the value gets changed
|
||||
/// </summary>
|
||||
public OnValueChangedDelegate OnValueChanged;
|
||||
|
||||
private NetworkBehaviour m_NetworkBehaviour;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkVariable with the default value and settings
|
||||
/// </summary>
|
||||
public NetworkVariable() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkVariable with the default value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkVariable</param>
|
||||
public NetworkVariable(NetworkVariableSettings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkVariable with a custom value and custom settings
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings to use for the NetworkVariable</param>
|
||||
/// <param name="value">The initial value to use for the NetworkVariable</param>
|
||||
public NetworkVariable(NetworkVariableSettings settings, T value)
|
||||
{
|
||||
Settings = settings;
|
||||
m_InternalValue = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a NetworkVariable with a custom value and the default settings
|
||||
/// </summary>
|
||||
/// <param name="value">The initial value to use for the NetworkVariable</param>
|
||||
public NetworkVariable(T value)
|
||||
{
|
||||
m_InternalValue = value;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private T m_InternalValue;
|
||||
|
||||
/// <summary>
|
||||
/// The value of the NetworkVariable container
|
||||
/// </summary>
|
||||
public T Value
|
||||
{
|
||||
get => m_InternalValue;
|
||||
set
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(m_InternalValue, value)) return;
|
||||
|
||||
// Setter is assumed to be called locally, by game code.
|
||||
// When used by the host, it is its responsibility to set the RemoteTick
|
||||
RemoteTick = NetworkTickSystem.NoTick;
|
||||
|
||||
m_IsDirty = true;
|
||||
T previousValue = m_InternalValue;
|
||||
m_InternalValue = value;
|
||||
OnValueChanged?.Invoke(previousValue, m_InternalValue);
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_IsDirty = false;
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether or not the variable needs to be delta synced
|
||||
/// </summary>
|
||||
public void SetDirty(bool isDirty)
|
||||
{
|
||||
m_IsDirty = isDirty;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsDirty()
|
||||
{
|
||||
return m_IsDirty;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetDirty()
|
||||
{
|
||||
m_IsDirty = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the variable to the writer
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to write the value to</param>
|
||||
public void WriteDelta(Stream stream)
|
||||
{
|
||||
WriteField(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads value from the reader and applies it
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read the value from</param>
|
||||
/// <param name="keepDirtyDelta">Whether or not the container should keep the dirty delta, or mark the delta as consumed</param>
|
||||
public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick)
|
||||
{
|
||||
// todo: This allows the host-returned value to be set back to an old value
|
||||
// this will need to be adjusted to check if we're have a most recent value
|
||||
LocalTick = localTick;
|
||||
RemoteTick = remoteTick;
|
||||
|
||||
using (var reader = PooledNetworkReader.Get(stream))
|
||||
{
|
||||
T previousValue = m_InternalValue;
|
||||
m_InternalValue = (T)reader.ReadObjectPacked(typeof(T));
|
||||
|
||||
if (keepDirtyDelta) m_IsDirty = true;
|
||||
|
||||
OnValueChanged?.Invoke(previousValue, m_InternalValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetNetworkBehaviour(NetworkBehaviour behaviour)
|
||||
{
|
||||
m_NetworkBehaviour = behaviour;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReadField(Stream stream, ushort localTick, ushort remoteTick)
|
||||
{
|
||||
ReadDelta(stream, false, localTick, remoteTick);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteField(Stream stream)
|
||||
{
|
||||
// Store the local tick at which this NetworkVariable was modified
|
||||
LocalTick = NetworkBehaviour.CurrentTick;
|
||||
using (var writer = PooledNetworkWriter.Get(stream))
|
||||
{
|
||||
writer.WriteObjectPacked(m_InternalValue); //BOX
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkChannel GetChannel()
|
||||
{
|
||||
return Settings.SendNetworkChannel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds strings and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableString : NetworkVariable<string>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableString() : base(string.Empty) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableString(NetworkVariableSettings settings) : base(settings, string.Empty) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableString(string value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableString(NetworkVariableSettings settings, string value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds bools and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableBool : NetworkVariable<bool>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableBool() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableBool(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableBool(bool value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableBool(NetworkVariableSettings settings, bool value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds bytes and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableByte : NetworkVariable<byte>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableByte() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableByte(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableByte(byte value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableByte(NetworkVariableSettings settings, byte value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds sbytes and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableSByte : NetworkVariable<sbyte>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableSByte() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableSByte(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableSByte(sbyte value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableSByte(NetworkVariableSettings settings, sbyte value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds ushorts and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableUShort : NetworkVariable<ushort>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUShort() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUShort(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUShort(ushort value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUShort(NetworkVariableSettings settings, ushort value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds shorts and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableShort : NetworkVariable<short>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableShort() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableShort(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableShort(short value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableShort(NetworkVariableSettings settings, short value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds uints and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableUInt : NetworkVariable<uint>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUInt() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUInt(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUInt(uint value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableUInt(NetworkVariableSettings settings, uint value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds ints and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableInt : NetworkVariable<int>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableInt() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableInt(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableInt(int value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableInt(NetworkVariableSettings settings, int value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds ulongs and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableULong : NetworkVariable<ulong>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableULong() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableULong(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableULong(ulong value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableULong(NetworkVariableSettings settings, ulong value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds longs and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableLong : NetworkVariable<long>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableLong() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableLong(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableLong(long value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableLong(NetworkVariableSettings settings, long value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds floats and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableFloat : NetworkVariable<float>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableFloat() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableFloat(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableFloat(float value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableFloat(NetworkVariableSettings settings, float value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds doubles and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableDouble : NetworkVariable<double>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableDouble() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableDouble(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableDouble(double value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableDouble(NetworkVariableSettings settings, double value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds vector2s and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableVector2 : NetworkVariable<Vector2>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector2() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector2(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector2(Vector2 value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector2(NetworkVariableSettings settings, Vector2 value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds vector3s and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableVector3 : NetworkVariable<Vector3>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector3() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector3(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector3(Vector3 value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector3(NetworkVariableSettings settings, Vector3 value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds vector4s and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableVector4 : NetworkVariable<Vector4>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector4() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector4(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector4(Vector4 value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableVector4(NetworkVariableSettings settings, Vector4 value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds colors and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableColor : NetworkVariable<Color>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor(Color value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor(NetworkVariableSettings settings, Color value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds color32s and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableColor32 : NetworkVariable<Color32>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor32() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor32(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor32(Color32 value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableColor32(NetworkVariableSettings settings, Color32 value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds rays and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableRay : NetworkVariable<Ray>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableRay() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableRay(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableRay(Ray value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableRay(NetworkVariableSettings settings, Ray value) : base(settings, value) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A NetworkVariable that holds quaternions and support serialization
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class NetworkVariableQuaternion : NetworkVariable<Quaternion>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableQuaternion() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableQuaternion(NetworkVariableSettings settings) : base(settings) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableQuaternion(Quaternion value) : base(value) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public NetworkVariableQuaternion(NetworkVariableSettings settings, Quaternion value) : base(settings, value) { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f6bd4b05b09e604986db16876d2cd4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,28 @@
|
|||
namespace MLAPI.NetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Permission type
|
||||
/// </summary>
|
||||
public enum NetworkVariablePermission
|
||||
{
|
||||
/// <summary>
|
||||
/// Everyone
|
||||
/// </summary>
|
||||
Everyone,
|
||||
|
||||
/// <summary>
|
||||
/// Server-only operation
|
||||
/// </summary>
|
||||
ServerOnly,
|
||||
|
||||
/// <summary>
|
||||
/// Owner-ownly
|
||||
/// </summary>
|
||||
OwnerOnly,
|
||||
|
||||
/// <summary>
|
||||
/// Custom delegate
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bc753a77be3d7e846b7bb2612a67ac62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
using MLAPI.Transports;
|
||||
|
||||
namespace MLAPI.NetworkVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate type for permission checking
|
||||
/// </summary>
|
||||
/// <param name="clientId">The clientId whose permissions to check</param>
|
||||
public delegate bool NetworkVariablePermissionsDelegate(ulong clientId);
|
||||
|
||||
/// <summary>
|
||||
/// The settings class used by the build in NetworkVar implementations
|
||||
/// </summary>
|
||||
public class NetworkVariableSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the write permissions for this var
|
||||
/// </summary>
|
||||
public NetworkVariablePermission WritePermission = NetworkVariablePermission.ServerOnly;
|
||||
/// <summary>
|
||||
/// Defines the read permissions for this var
|
||||
/// </summary>
|
||||
public NetworkVariablePermission ReadPermission = NetworkVariablePermission.Everyone;
|
||||
/// <summary>
|
||||
/// The delegate used to evaluate write permission when the "Custom" mode is used
|
||||
/// </summary>
|
||||
public NetworkVariablePermissionsDelegate WritePermissionCallback = null;
|
||||
/// <summary>
|
||||
/// The delegate used to evaluate read permission when the "Custom" mode is used
|
||||
/// </summary>
|
||||
public NetworkVariablePermissionsDelegate ReadPermissionCallback = null;
|
||||
/// <summary>
|
||||
/// The maximum times per second this var will be synced.
|
||||
/// A value of 0 will cause the variable to sync as soon as possible after being changed.
|
||||
/// A value of less than 0 will cause the variable to sync only at once at spawn and not update again.
|
||||
/// </summary>
|
||||
public float SendTickrate = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the channel to use for this variable.
|
||||
/// Variables with different channels will be split into different packets
|
||||
/// </summary>
|
||||
public NetworkChannel SendNetworkChannel = NetworkChannel.DefaultMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new NetworkVariableSettings instance
|
||||
/// </summary>
|
||||
public NetworkVariableSettings() { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06315503f26247d4aaa786326d12ecdc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue