2using System.Collections;
3using System.Collections.Generic;
9 public delegate
void SyncListChanged(Operation op,
int itemIndex, T oldItem, T newItem);
11 readonly IList<T> objects;
12 readonly IEqualityComparer<T> comparer;
14 public int Count => objects.Count;
15 public bool IsReadOnly {
get;
private set; }
16 public event SyncListChanged Callback;
18 public enum Operation :
byte
29 internal Operation operation;
38 readonly List<Change> changes =
new List<Change>();
46 public SyncList() :
this(EqualityComparer<T>.Default) {}
48 public SyncList(IEqualityComparer<T> comparer)
50 this.comparer = comparer ?? EqualityComparer<T>.Default;
51 objects =
new List<T>();
54 public SyncList(IList<T> objects, IEqualityComparer<T> comparer =
null)
56 this.comparer = comparer ?? EqualityComparer<T>.Default;
57 this.objects = objects;
72 void AddOperation(Operation op,
int itemIndex, T oldItem, T newItem)
76 throw new InvalidOperationException(
"Synclists can only be modified at the server");
79 Change change =
new Change
92 Callback?.Invoke(op, itemIndex, oldItem, newItem);
98 writer.WriteUInt((uint)objects.Count);
100 for (
int i = 0; i < objects.Count; i++)
110 writer.WriteUInt((uint)changes.Count);
116 writer.WriteUInt((uint)changes.Count);
118 for (
int i = 0; i < changes.Count; i++)
120 Change change = changes[i];
121 writer.WriteByte((
byte)change.operation);
123 switch (change.operation)
125 case Operation.OP_ADD:
126 writer.Write(change.item);
129 case Operation.OP_CLEAR:
132 case Operation.OP_REMOVEAT:
133 writer.WriteUInt((uint)change.index);
136 case Operation.OP_INSERT:
137 case Operation.OP_SET:
138 writer.WriteUInt((uint)change.index);
139 writer.Write(change.item);
151 int count = (int)reader.ReadUInt();
156 for (
int i = 0; i < count; i++)
158 T obj = reader.Read<T>();
165 changesAhead = (int)reader.ReadUInt();
173 int changesCount = (int)reader.ReadUInt();
175 for (
int i = 0; i < changesCount; i++)
177 Operation operation = (Operation)reader.ReadByte();
181 bool apply = changesAhead == 0;
188 case Operation.OP_ADD:
189 newItem = reader.Read<T>();
192 index = objects.Count;
193 objects.Add(newItem);
197 case Operation.OP_CLEAR:
204 case Operation.OP_INSERT:
205 index = (int)reader.ReadUInt();
206 newItem = reader.Read<T>();
209 objects.Insert(index, newItem);
213 case Operation.OP_REMOVEAT:
214 index = (int)reader.ReadUInt();
217 oldItem = objects[index];
218 objects.RemoveAt(index);
222 case Operation.OP_SET:
223 index = (int)reader.ReadUInt();
224 newItem = reader.Read<T>();
227 oldItem = objects[index];
228 objects[index] = newItem;
235 Callback?.Invoke(operation, index, oldItem, newItem);
245 public void Add(T item)
248 AddOperation(Operation.OP_ADD, objects.Count - 1,
default, item);
251 public void AddRange(IEnumerable<T> range)
253 foreach (T entry
in range)
262 AddOperation(Operation.OP_CLEAR, 0,
default,
default);
265 public bool Contains(T item) => IndexOf(item) >= 0;
267 public void CopyTo(T[] array,
int index) => objects.CopyTo(array, index);
269 public int IndexOf(T item)
271 for (
int i = 0; i < objects.Count; ++i)
272 if (comparer.Equals(item, objects[i]))
277 public int FindIndex(Predicate<T> match)
279 for (
int i = 0; i < objects.Count; ++i)
280 if (match(objects[i]))
285 public T Find(Predicate<T> match)
287 int i = FindIndex(match);
288 return (i != -1) ? objects[i] :
default;
291 public List<T> FindAll(Predicate<T> match)
293 List<T> results =
new List<T>();
294 for (
int i = 0; i < objects.Count; ++i)
295 if (match(objects[i]))
296 results.Add(objects[i]);
300 public void Insert(
int index, T item)
302 objects.Insert(index, item);
303 AddOperation(Operation.OP_INSERT, index,
default, item);
306 public void InsertRange(
int index, IEnumerable<T> range)
308 foreach (T entry
in range)
310 Insert(index, entry);
315 public bool Remove(T item)
317 int index = IndexOf(item);
318 bool result = index >= 0;
326 public void RemoveAt(
int index)
328 T oldItem = objects[index];
329 objects.RemoveAt(index);
330 AddOperation(Operation.OP_REMOVEAT, index, oldItem,
default);
333 public int RemoveAll(Predicate<T> match)
335 List<T> toRemove =
new List<T>();
336 for (
int i = 0; i < objects.Count; ++i)
337 if (match(objects[i]))
338 toRemove.Add(objects[i]);
340 foreach (T entry
in toRemove)
345 return toRemove.Count;
353 if (!comparer.Equals(objects[i], value))
355 T oldItem = objects[i];
357 AddOperation(Operation.OP_SET, i, oldItem, value);
362 public Enumerator GetEnumerator() =>
new Enumerator(
this);
364 IEnumerator<T> IEnumerable<T>.GetEnumerator() =>
new Enumerator(
this);
366 IEnumerator IEnumerable.GetEnumerator() =>
new Enumerator(
this);
382 public T Current {
get;
private set; }
391 public bool MoveNext()
393 if (++index >= list.Count)
397 Current = list[index];
401 public void Reset() => index = -1;
402 object IEnumerator.Current => Current;
403 public void Dispose() {}
Network Reader for most simple types like floats, ints, buffers, structs, etc. Use NetworkReaderPool....
Network Writer for most simple types like floats, ints, buffers, structs, etc. Use NetworkWriterPool....
override void Reset()
Resets the SyncObject so that it can be re-used
override void OnSerializeAll(NetworkWriter writer)
Write a full copy of the object
override void OnDeserializeDelta(NetworkReader reader)
Reads the changes made to the object since last sync
override void OnSerializeDelta(NetworkWriter writer)
Write the changes made to the object since last sync
override void OnDeserializeAll(NetworkReader reader)
Reads a full copy of the object
override void ClearChanges()
Discard all the queued changes
SyncObjects sync state between server and client. E.g. SyncLists.
Action OnDirty
Used internally to set owner NetworkBehaviour's dirty mask bit when changed.
Func< bool > IsRecording
Used internally to check if we are currently tracking changes.