Mirror/Unity-Technologies-networking/Runtime/SyncList.cs

418 lines
11 KiB
C#

#if ENABLE_UNET
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
namespace UnityEngine.Networking
{
public sealed class SyncListString : SyncList<string>
{
protected override void SerializeItem(NetworkWriter writer, string item)
{
writer.Write(item);
}
protected override string DeserializeItem(NetworkReader reader)
{
return reader.ReadString();
}
static public void ReadReference(NetworkReader reader, SyncListString syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadString());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListString items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public sealed class SyncListFloat : SyncList<float>
{
protected override void SerializeItem(NetworkWriter writer, float item)
{
writer.Write(item);
}
protected override float DeserializeItem(NetworkReader reader)
{
return reader.ReadSingle();
}
static public void ReadReference(NetworkReader reader, SyncListFloat syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadSingle());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListFloat items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public class SyncListInt : SyncList<int>
{
protected override void SerializeItem(NetworkWriter writer, int item)
{
writer.WritePackedUInt32((uint)item);
}
protected override int DeserializeItem(NetworkReader reader)
{
return (int)reader.ReadPackedUInt32();
}
static public void ReadReference(NetworkReader reader, SyncListInt syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal((int)reader.ReadPackedUInt32());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListInt items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.WritePackedUInt32((uint)items[i]);
}
}
}
public class SyncListUInt : SyncList<uint>
{
protected override void SerializeItem(NetworkWriter writer, uint item)
{
writer.WritePackedUInt32(item);
}
protected override uint DeserializeItem(NetworkReader reader)
{
return reader.ReadPackedUInt32();
}
static public void ReadReference(NetworkReader reader, SyncListUInt syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadPackedUInt32());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListUInt items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.WritePackedUInt32(items[i]);
}
}
}
public class SyncListBool : SyncList<bool>
{
protected override void SerializeItem(NetworkWriter writer, bool item)
{
writer.Write(item);
}
protected override bool DeserializeItem(NetworkReader reader)
{
return reader.ReadBoolean();
}
static public void ReadReference(NetworkReader reader, SyncListBool syncList)
{
ushort count = reader.ReadUInt16();
syncList.Clear();
for (ushort i = 0; i < count; i++)
{
syncList.AddInternal(reader.ReadBoolean());
}
}
static public void WriteInstance(NetworkWriter writer, SyncListBool items)
{
writer.Write((ushort)items.Count);
for (int i = 0; i < items.Count; i++)
{
writer.Write(items[i]);
}
}
}
public class SyncListStruct<T> : SyncList<T> where T : struct
{
new public void AddInternal(T item)
{
base.AddInternal(item);
}
protected override void SerializeItem(NetworkWriter writer, T item)
{
}
protected override T DeserializeItem(NetworkReader reader)
{
return new T();
}
public T GetItem(int i)
{
return base[i];
}
new public ushort Count { get { return (ushort)base.Count; } }
}
[EditorBrowsable(EditorBrowsableState.Never)]
abstract public class SyncList<T> : IList<T>
{
public delegate void SyncListChanged(Operation op, int itemIndex);
List<T> m_Objects = new List<T>();
public int Count { get { return m_Objects.Count; } }
public bool IsReadOnly { get { return false; } }
public SyncListChanged Callback { get { return m_Callback; } set { m_Callback = value; } }
public enum Operation
{
OP_ADD,
OP_CLEAR,
OP_INSERT,
OP_REMOVE,
OP_REMOVEAT,
OP_SET,
OP_DIRTY
};
NetworkBehaviour m_Behaviour;
int m_CmdHash;
SyncListChanged m_Callback;
abstract protected void SerializeItem(NetworkWriter writer, T item);
abstract protected T DeserializeItem(NetworkReader reader);
public void InitializeBehaviour(NetworkBehaviour beh, int cmdHash)
{
m_Behaviour = beh;
m_CmdHash = cmdHash;
}
void SendMsg(Operation op, int itemIndex, T item)
{
if (m_Behaviour == null)
{
if (LogFilter.logError) { Debug.LogError("SyncList not initialized"); }
return;
}
var uv = m_Behaviour.GetComponent<NetworkIdentity>();
if (uv == null)
{
if (LogFilter.logError) { Debug.LogError("SyncList no NetworkIdentity"); }
return;
}
if (!uv.isServer)
{
// object is not spawned yet, so no need to send updates.
return;
}
NetworkWriter writer = new NetworkWriter();
writer.StartMessage((short)MsgType.SyncList);
writer.Write(uv.netId);
writer.WritePackedUInt32((uint)m_CmdHash);
writer.Write((byte)op);
writer.WritePackedUInt32((uint)itemIndex);
SerializeItem(writer, item);
writer.FinishMessage();
NetworkServer.SendWriterToReady(uv.gameObject, writer, m_Behaviour.GetNetworkChannel());
#if UNITY_EDITOR
UnityEditor.NetworkDetailStats.IncrementStat(
UnityEditor.NetworkDetailStats.NetworkDirection.Outgoing,
(short)MsgType.SyncList, op.ToString(), 1);
#endif
// ensure it is invoked on host
if (m_Behaviour.isServer && m_Behaviour.isClient && m_Callback != null)
{
m_Callback.Invoke(op, itemIndex);
}
}
void SendMsg(Operation op, int itemIndex)
{
SendMsg(op, itemIndex, default(T));
}
public void HandleMsg(NetworkReader reader)
{
byte op = reader.ReadByte();
int itemIndex = (int)reader.ReadPackedUInt32();
T item = DeserializeItem(reader);
switch ((Operation)op)
{
case Operation.OP_ADD:
m_Objects.Add(item);
break;
case Operation.OP_CLEAR:
m_Objects.Clear();
break;
case Operation.OP_INSERT:
m_Objects.Insert(itemIndex, item);
break;
case Operation.OP_REMOVE:
m_Objects.Remove(item);
break;
case Operation.OP_REMOVEAT:
m_Objects.RemoveAt(itemIndex);
break;
case Operation.OP_SET:
case Operation.OP_DIRTY:
m_Objects[itemIndex] = item;
break;
}
if (m_Callback != null)
{
m_Callback.Invoke((Operation)op, itemIndex);
}
}
// used to bypass Add message.
internal void AddInternal(T item)
{
m_Objects.Add(item);
}
public void Add(T item)
{
m_Objects.Add(item);
SendMsg(Operation.OP_ADD, m_Objects.Count - 1, item);
}
public void Clear()
{
m_Objects.Clear();
SendMsg(Operation.OP_CLEAR, 0);
}
public bool Contains(T item)
{
return m_Objects.Contains(item);
}
public void CopyTo(T[] array, int index)
{
m_Objects.CopyTo(array, index);
}
public int IndexOf(T item)
{
return m_Objects.IndexOf(item);
}
public void Insert(int index, T item)
{
m_Objects.Insert(index, item);
SendMsg(Operation.OP_INSERT, index, item);
}
public bool Remove(T item)
{
var result = m_Objects.Remove(item);
if (result)
{
SendMsg(Operation.OP_REMOVE, 0, item);
}
return result;
}
public void RemoveAt(int index)
{
m_Objects.RemoveAt(index);
SendMsg(Operation.OP_REMOVEAT, index);
}
public void Dirty(int index)
{
SendMsg(Operation.OP_DIRTY, index, m_Objects[index]);
}
public T this[int i]
{
get { return m_Objects[i]; }
set
{
bool changed = false;
if (m_Objects[i] == null)
{
if (value == null)
return;
else
changed = true;
}
else
{
changed = !m_Objects[i].Equals(value);
}
m_Objects[i] = value;
if (changed)
{
SendMsg(Operation.OP_SET, i, value);
}
}
}
public IEnumerator<T> GetEnumerator()
{
return m_Objects.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
#endif //ENABLE_UNET