diff --git a/src/Arch/Core/Buffers/Buffer.cs b/src/Arch/Core/Buffers/Buffer.cs new file mode 100644 index 00000000..2e7c86ef --- /dev/null +++ b/src/Arch/Core/Buffers/Buffer.cs @@ -0,0 +1,20 @@ +using CommunityToolkit.HighPerformance; + +namespace Arch.Core.Buffers; + +public struct Buffer +{ + public List Elements; + + public Buffer() + { + Elements = new List(); + } + +#if NET5_0_OR_GREATER + public Span AsSpan() + { + return Elements.AsSpan(); + } +#endif +} diff --git a/src/Arch/Core/Buffers/World.BufferElements.cs b/src/Arch/Core/Buffers/World.BufferElements.cs new file mode 100644 index 00000000..fa7b2807 --- /dev/null +++ b/src/Arch/Core/Buffers/World.BufferElements.cs @@ -0,0 +1,72 @@ +using System.Diagnostics.Contracts; +using Arch.Core.Buffers; + +namespace Arch.Core; + +public partial class World +{ + /// + /// Adds an element to the buffer of an . + /// + /// The . + /// The buffer's element type. + /// The buffer instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddToBuffer(Entity entity, in T value = default) + { + AddOrGetBuffer(entity).Elements.Add(value); + } + + /// + /// Ensures the existence of a value in a buffer on an . + /// + /// The buffer's element type. + /// The . + /// The value to ensure the existence of. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddOrGetFromBuffer(Entity entity, in T value = default) + { + ref var elements = ref AddOrGetBuffer(entity).Elements; + if (!elements.Contains(value)) + { + elements.Add(value); + } + } + + /// + /// Checks if an 's buffer has a certain element. + /// + /// The buffer's element type. + /// The . + /// The value to check. + /// True if the buffer has the desired element, otherwise false. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public bool HasInBuffer(Entity entity, in T value) + { + ref var buffer = ref TryGetRefBuffer(entity, out var exists); + if (!exists) + { + return false; + } + + return buffer.Elements.Contains(value); + } + + /// + /// Removes an element from a buffer in a . + /// + /// The buffer's element type. + /// The . + /// The value to remove from the buffer. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveFromBuffer(Entity entity, in T value) + { + ref var buffer = ref TryGetRef>(entity, out var exists); + if (!exists) + { + return; + } + + buffer.Elements.Remove(value); + } +} diff --git a/src/Arch/Core/Buffers/World.Buffers.cs b/src/Arch/Core/Buffers/World.Buffers.cs new file mode 100644 index 00000000..6a36fb83 --- /dev/null +++ b/src/Arch/Core/Buffers/World.Buffers.cs @@ -0,0 +1,116 @@ +using System.Diagnostics.Contracts; +using Arch.Core.Buffers; + +namespace Arch.Core; + +public partial class World +{ + /// + /// Adds an new buffer to the and moves it to the new . + /// + /// The . + /// The buffer's element type. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddBuffer(Entity entity) + { + Add(entity, new Buffer()); + } + + /// + /// Ensures the existence of an buffer on an . + /// + /// The buffer's element type. + /// The . + /// A reference to the buffer. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref Buffer AddOrGetBuffer(Entity entity) + { + return ref AddOrGet(entity, static () => new Buffer()); + } + + /// + /// Returns a reference to the buffer of an . + /// + /// The buffer's element type. + /// The . + /// A reference to the buffer. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public ref Buffer GetBuffer(Entity entity) + { + return ref Get>(entity); + } + + /// + /// Checks if an has a certain buffer. + /// + /// The buffer's element type. + /// The . + /// True if it has the desired buffer, otherwise false. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public bool HasBuffer(Entity entity) + { + return Has>(entity); + } + + /// + /// Removes a buffer from an and moves it to a different . + /// + /// The buffer's element type. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveBuffer(Entity entity) + { + Remove>(entity); + } + + /// + /// Trys to return a reference to the buffer of an . + /// Will copy the buffer. + /// + /// The buffer's element type. + /// The . + /// The found buffer. + /// True if it exists, otherwise false. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public bool TryGetBuffer(Entity entity, out Buffer buffer) + { + return TryGet(entity, out buffer); + } + + /// + /// Tries to return a reference to the buffer of an . + /// + /// The buffer's element type. + /// The . + /// True if it exists, otherwise false. + /// A reference to the buffer. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public ref Buffer TryGetRefBuffer(Entity entity, out bool exists) + { + return ref TryGetRef>(entity, out exists); + } + + /// + /// Removes a buffer of the given type from an if it is empty. + /// + /// The buffer's element type. + /// The . + /// True if the buffer was empty and removed, false otherwise.. + [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] + public bool TrimBuffer(Entity entity) + { + ref var buffer = ref TryGetRefBuffer(entity, out var exists); + if (!exists) + { + return false; + } + + if (buffer.Elements.Count != 0) + { + return false; + } + + RemoveBuffer(entity); + return true; + } +} diff --git a/src/Arch/Core/World.cs b/src/Arch/Core/World.cs index 5489342b..d40c631b 100644 --- a/src/Arch/Core/World.cs +++ b/src/Arch/Core/World.cs @@ -890,6 +890,26 @@ public ref T AddOrGet(Entity entity, T cmp = default) return ref Get(entity); } + /// + /// Ensures the existence of an component on an . + /// + /// The component type. + /// The . + /// The component value used if its being added. + /// A reference to the component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref T AddOrGet(Entity entity, Func cmp) + { + ref var component = ref TryGetRef(entity, out var exists); + if (exists) + { + return ref component; + } + + Add(entity, cmp()); + return ref Get(entity); + } + /// /// Adds an new component to the and moves it to the new . ///