Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add buffers #114

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Arch/Core/Buffers/Buffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using CommunityToolkit.HighPerformance;

namespace Arch.Core.Buffers;

public struct Buffer<T>
{
public List<T> Elements;

public Buffer()
{
Elements = new List<T>();
}

#if NET5_0_OR_GREATER
public Span<T> AsSpan()
{
return Elements.AsSpan();
}
#endif
}
72 changes: 72 additions & 0 deletions src/Arch/Core/Buffers/World.BufferElements.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Diagnostics.Contracts;
using Arch.Core.Buffers;

namespace Arch.Core;

public partial class World
{
/// <summary>
/// Adds an element to the buffer of an <see cref="Entity"/>.
/// </summary>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="value">The buffer instance.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddToBuffer<T>(Entity entity, in T value = default)
{
AddOrGetBuffer<T>(entity).Elements.Add(value);
}

/// <summary>
/// Ensures the existence of a value in a buffer on an <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="value">The value to ensure the existence of.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddOrGetFromBuffer<T>(Entity entity, in T value = default)
{
ref var elements = ref AddOrGetBuffer<T>(entity).Elements;
if (!elements.Contains(value))
{
elements.Add(value);
}
}

/// <summary>
/// Checks if an <see cref="Entity"/>'s buffer has a certain element.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="value">The value to check.</param>
/// <returns>True if the buffer has the desired element, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool HasInBuffer<T>(Entity entity, in T value)
{
ref var buffer = ref TryGetRefBuffer<T>(entity, out var exists);
if (!exists)
{
return false;
}

return buffer.Elements.Contains(value);
}

/// <summary>
/// Removes an element from a buffer in a <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="value">The value to remove from the buffer.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveFromBuffer<T>(Entity entity, in T value)
{
ref var buffer = ref TryGetRef<Buffer<T>>(entity, out var exists);
if (!exists)
{
return;
}

buffer.Elements.Remove(value);
}
}
116 changes: 116 additions & 0 deletions src/Arch/Core/Buffers/World.Buffers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System.Diagnostics.Contracts;
using Arch.Core.Buffers;

namespace Arch.Core;

public partial class World
{
/// <summary>
/// Adds an new buffer to the <see cref="Entity"/> and moves it to the new <see cref="Archetype"/>.
/// </summary>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <typeparam name="T">The buffer's element type.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddBuffer<T>(Entity entity)
{
Add(entity, new Buffer<T>());
}

/// <summary>
/// Ensures the existence of an buffer on an <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <returns>A reference to the buffer.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Buffer<T> AddOrGetBuffer<T>(Entity entity)
{
return ref AddOrGet(entity, static () => new Buffer<T>());
}

/// <summary>
/// Returns a reference to the buffer of an <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <returns>A reference to the buffer.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public ref Buffer<T> GetBuffer<T>(Entity entity)
{
return ref Get<Buffer<T>>(entity);
}

/// <summary>
/// Checks if an <see cref="Entity"/> has a certain buffer.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <returns>True if it has the desired buffer, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool HasBuffer<T>(Entity entity)
{
return Has<Buffer<T>>(entity);
}

/// <summary>
/// Removes a buffer from an <see cref="Entity"/> and moves it to a different <see cref="Archetype"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveBuffer<T>(Entity entity)
{
Remove<Buffer<T>>(entity);
}

/// <summary>
/// Trys to return a reference to the buffer of an <see cref="Entity"/>.
/// Will copy the buffer.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="buffer">The found buffer.</param>
/// <returns>True if it exists, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool TryGetBuffer<T>(Entity entity, out Buffer<T> buffer)
{
return TryGet(entity, out buffer);
}

/// <summary>
/// Tries to return a reference to the buffer of an <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="exists">True if it exists, otherwise false.</param>
/// <returns>A reference to the buffer.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public ref Buffer<T> TryGetRefBuffer<T>(Entity entity, out bool exists)
{
return ref TryGetRef<Buffer<T>>(entity, out exists);
}

/// <summary>
/// Removes a buffer of the given type from an <see cref="Entity"/> if it is empty.
/// </summary>
/// <typeparam name="T">The buffer's element type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <returns>True if the buffer was empty and removed, false otherwise..</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining), Pure]
public bool TrimBuffer<T>(Entity entity)
{
ref var buffer = ref TryGetRefBuffer<T>(entity, out var exists);
if (!exists)
{
return false;
}

if (buffer.Elements.Count != 0)
{
return false;
}

RemoveBuffer<T>(entity);
return true;
}
}
20 changes: 20 additions & 0 deletions src/Arch/Core/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,26 @@ public ref T AddOrGet<T>(Entity entity, T cmp = default)
return ref Get<T>(entity);
}

/// <summary>
/// Ensures the existence of an component on an <see cref="Entity"/>.
/// </summary>
/// <typeparam name="T">The component type.</typeparam>
/// <param name="entity">The <see cref="Entity"/>.</param>
/// <param name="cmp">The component value used if its being added.</param>
/// <returns>A reference to the component.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T AddOrGet<T>(Entity entity, Func<T> cmp)
{
ref var component = ref TryGetRef<T>(entity, out var exists);
if (exists)
{
return ref component;
}

Add(entity, cmp());
return ref Get<T>(entity);
}

/// <summary>
/// Adds an new component to the <see cref="Entity"/> and moves it to the new <see cref="Archetype"/>.
/// </summary>
Expand Down