// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.Persistence; using System.Collections.Concurrent; using System.Threading; /// /// A generator which generates id which should be unique within an instance of a generator. /// Ids which are no longer used can be given back to the generator, e.g. when an object joins a game map, /// it gets an id, later when it leaves the map, it gives the id back, so another player can use it. /// /// /// The namespace for this class is probably not the right one - we're missing something like a "Utility" namespace for things like that. /// public class IdGenerator { private readonly int _maxValue; private readonly ConcurrentQueue _givenBack = new(); private int _currentValue; /// /// Initializes a new instance of the class. /// /// The first value. /// The maximum value. public IdGenerator(int firstValue, int maxValue) { this._maxValue = maxValue; this._currentValue = firstValue - 1; // will be increased by 1 by GenerateId } /// /// Defines how ids are reused, which were given back with . /// public enum ReUsePolicy { /// /// The given back id is reused on the next call of . /// ReUseOnNextRetrieve, /// /// The given back id is reused when all of the available ids were exceeded. /// ReUseWhenExceeded, } /// /// Gets or sets the which defines how ids are reused, which were given back with . /// public ReUsePolicy ReUseSetting { get; set; } /// /// Gets an identifier which is unique within this generator instance. /// /// An identifier which is unique within this generator instance. /// Maximum object id exceeded. public int GenerateId() { if (this.ReUseSetting == ReUsePolicy.ReUseOnNextRetrieve && this._givenBack.TryDequeue(out int next)) { return next; } if (this._currentValue == this._maxValue) { if (this._givenBack.TryDequeue(out next)) { return next; } throw new InvalidOperationException("Maximum object id exceeded"); } return Interlocked.Increment(ref this._currentValue); } /// /// Gives the id back for further usage by the next object. /// /// The identifier. public void GiveBack(int id) { if (id <= this._maxValue) { this._givenBack.Enqueue(id); } } }