1+ using Mirror ;
2+
3+ using System . Collections ;
4+ using System . Collections . ObjectModel ;
5+
6+ namespace LabExtended . Core . Storage
7+ {
8+ /// <summary>
9+ /// Represents a collection of items of type <typeparamref name="T"/> that supports read-only access, modification
10+ /// tracking, and common collection operations.
11+ /// </summary>
12+ /// <remarks>This class provides a wrapper around a <see cref="List{T}"/> with additional functionality,
13+ /// such as: <list type="bullet"> <item>Exposing the collection as a read-only view through the <see
14+ /// cref="Collection"/> property.</item> <item>Tracking modifications to the collection via the <see
15+ /// cref="StorageValue.IsDirty"/> property.</item> <item>Implementing common collection interfaces, including <see
16+ /// cref="IList{T}"/>, <see cref="ICollection{T}"/>, and <see cref="IReadOnlyList{T}"/>.</item> </list> The
17+ /// collection is not thread-safe and must be synchronized externally if accessed concurrently.</remarks>
18+ /// <typeparam name="T">The type of elements in the collection.</typeparam>
19+ public class CollectionValue < T > : StorageValue ,
20+
21+ IList < T > ,
22+ ICollection < T > ,
23+ IReadOnlyList < T >
24+ {
25+ private List < T > collection ;
26+
27+ /// <summary>
28+ /// Gets a read-only collection of items of type <typeparamref name="T"/>.
29+ /// </summary>
30+ /// <remarks>This property provides a thread-safe way to access the collection. Any attempt to
31+ /// modify the collection will result in a runtime exception.</remarks>
32+ public ReadOnlyCollection < T > Collection { get ; }
33+
34+ /// <summary>
35+ /// Gets the number of elements contained in the collection.
36+ /// </summary>
37+ public int Count => collection . Count ;
38+
39+ /// <summary>
40+ /// Gets a value indicating whether the collection is read-only.
41+ /// </summary>
42+ public bool IsReadOnly => false ;
43+
44+ /// <summary>
45+ /// Gets or sets the element at the specified index in the collection.
46+ /// </summary>
47+ /// <param name="index">The zero-based index of the element to get or set.</param>
48+ /// <returns></returns>
49+ public T this [ int index ]
50+ {
51+ get
52+ {
53+ return collection [ index ] ;
54+ }
55+ set
56+ {
57+ collection [ index ] = value ;
58+
59+ IsDirty = true ;
60+ }
61+ }
62+
63+ /// <summary>
64+ /// Initializes a new instance of the <see cref="CollectionValue{T}"/> class with an optional initial capacity.
65+ /// </summary>
66+ /// <param name="size">The initial number of elements that the underlying collection can contain. Defaults to 0.</param>
67+ public CollectionValue ( int size = 0 )
68+ : this ( new List < T > ( size ) ) { }
69+
70+ /// <summary>
71+ /// Initializes a new instance of the <see cref="CollectionValue{T}"/> class with the specified collection.
72+ /// </summary>
73+ /// <remarks>If the provided collection is a <see cref="List{T}"/>, it is used directly.
74+ /// Otherwise, the collection is copied into a new list. The resulting collection is exposed as a read-only
75+ /// collection through the <c>Collection</c> property.</remarks>
76+ /// <param name="collection">The collection of items to initialize the instance with. Cannot be <see langword="null"/>.</param>
77+ /// <exception cref="ArgumentNullException">Thrown if <paramref name="collection"/> is <see langword="null"/>.</exception>
78+ public CollectionValue ( IEnumerable < T > collection )
79+ {
80+ if ( collection is null )
81+ throw new ArgumentNullException ( nameof ( collection ) ) ;
82+
83+ if ( collection is List < T > list )
84+ {
85+ this . collection = list ;
86+ }
87+ else
88+ {
89+ this . collection = new ( collection ) ;
90+ }
91+
92+ Collection = this . collection . AsReadOnly ( ) ;
93+ }
94+
95+ /// <summary>
96+ /// Determines the zero-based index of the first occurrence of the specified item in the collection.
97+ /// </summary>
98+ /// <param name="item">The item to locate in the collection.</param>
99+ /// <returns>The zero-based index of the first occurrence of <paramref name="item"/> in the collection, or -1 if the
100+ /// item is not found.</returns>
101+ public int IndexOf ( T item )
102+ => collection . IndexOf ( item ) ;
103+
104+ /// <summary>
105+ /// Determines whether the collection contains the specified item.
106+ /// </summary>
107+ /// <remarks>The method uses the default equality comparer to determine item equality.</remarks>
108+ /// <param name="item">The item to locate in the collection.</param>
109+ /// <returns><see langword="true"/> if the specified item is found in the collection; otherwise, <see langword="false"/>.</returns>
110+ public bool Contains ( T item )
111+ => collection . Contains ( item ) ;
112+
113+ /// <summary>
114+ /// Copies the elements of the collection to the specified array, starting at the specified index.
115+ /// </summary>
116+ /// <param name="array">The one-dimensional array that is the destination of the elements copied from the collection. The array must
117+ /// have zero-based indexing.</param>
118+ /// <param name="arrayIndex">The zero-based index in the destination array at which copying begins.</param>
119+ public void CopyTo ( T [ ] array , int arrayIndex )
120+ => collection . CopyTo ( array , arrayIndex ) ;
121+
122+ /// <summary>
123+ /// Returns an enumerator that iterates through the collection.
124+ /// </summary>
125+ /// <remarks>The enumerator provides a simple way to iterate over the elements in the
126+ /// collection.</remarks>
127+ /// <returns>An <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.</returns>
128+ public IEnumerator < T > GetEnumerator ( )
129+ => collection . GetEnumerator ( ) ;
130+
131+ /// <summary>
132+ /// Returns an enumerator that iterates through the collection.
133+ /// </summary>
134+ /// <remarks>This method is an explicit implementation of the <see
135+ /// cref="IEnumerable.GetEnumerator"/> method and provides support for non-generic iteration over the
136+ /// collection.</remarks>
137+ /// <returns>An <see cref="IEnumerator"/> that can be used to iterate through the collection.</returns>
138+ IEnumerator IEnumerable . GetEnumerator ( )
139+ => collection . GetEnumerator ( ) ;
140+
141+ /// <summary>
142+ /// Inserts an item into the collection at the specified index.
143+ /// </summary>
144+ /// <remarks>After the item is inserted, the collection is marked as modified.</remarks>
145+ /// <param name="index">The zero-based index at which the item should be inserted.</param>
146+ /// <param name="item">The item to insert into the collection.</param>
147+ public void Insert ( int index , T item )
148+ {
149+ collection . Insert ( index , item ) ;
150+
151+ IsDirty = true ;
152+ }
153+
154+ /// <summary>
155+ /// Adds the specified item to the collection and marks the collection as modified.
156+ /// </summary>
157+ /// <param name="item">The item to add to the collection. Cannot be null.</param>
158+ public void Add ( T item )
159+ {
160+ collection . Add ( item ) ;
161+
162+ IsDirty = true ;
163+ }
164+
165+ /// <summary>
166+ /// Removes the specified item from the collection.
167+ /// </summary>
168+ /// <remarks>After a successful removal, the <c>IsDirty</c> property is set to <see
169+ /// langword="true"/> to indicate that the collection's state has changed.</remarks>
170+ /// <param name="item">The item to remove from the collection.</param>
171+ /// <returns><see langword="true"/> if the item was successfully removed from the collection; otherwise, <see
172+ /// langword="false"/> if the item was not found in the collection.</returns>
173+ public bool Remove ( T item )
174+ {
175+ if ( collection . Remove ( item ) )
176+ {
177+ IsDirty = true ;
178+ return true ;
179+ }
180+
181+ return false ;
182+ }
183+
184+ /// <summary>
185+ /// Removes the element at the specified index from the collection.
186+ /// </summary>
187+ /// <remarks>After the element is removed, the collection is marked as modified by setting the
188+ /// <see cref="StorageValue.IsDirty"/> property to <see langword="true"/>.</remarks>
189+ /// <param name="index">The zero-based index of the element to remove.</param>
190+ public void RemoveAt ( int index )
191+ {
192+ collection . RemoveAt ( index ) ;
193+
194+ IsDirty = true ;
195+ }
196+
197+ /// <summary>
198+ /// Clears all items from the collection and marks the state as modified.
199+ /// </summary>
200+ /// <remarks>If the collection is already empty, this method has no effect. After clearing, the
201+ /// <see cref="StorageValue.IsDirty"/> property is set to <see langword="true"/>.</remarks>
202+ public void Clear ( )
203+ {
204+ if ( collection . Count > 0 )
205+ {
206+ collection . Clear ( ) ;
207+
208+ IsDirty = true ;
209+ }
210+ }
211+
212+ /// <inheritdoc/>
213+ public override void ReadValue ( NetworkReader reader )
214+ {
215+ if ( Reader < T > . read is not null )
216+ {
217+ if ( collection . Count > 0 )
218+ collection . Clear ( ) ;
219+
220+ var count = reader . ReadInt ( ) ;
221+
222+ for ( var i = 0 ; i < count ; i ++ )
223+ {
224+ var item = Reader < T > . read ( reader ) ;
225+
226+ collection . Add ( item ) ;
227+ }
228+ }
229+ }
230+
231+ /// <inheritdoc/>
232+ public override void WriteValue ( NetworkWriter writer )
233+ {
234+ if ( Writer < T > . write is not null )
235+ {
236+ writer . WriteInt ( collection . Count ) ;
237+
238+ foreach ( var item in collection )
239+ Writer < T > . write ( writer , item ) ;
240+ }
241+ }
242+
243+ /// <inheritdoc/>
244+ public override string ToString ( )
245+ {
246+ return string . Concat (
247+ "CollectionValue{" , typeof ( T ) . Name , "} [Count = " , Count . ToString ( ) , "]" ) ;
248+ }
249+ }
250+ }
0 commit comments