feat(entity): added SetAll() which takes a params list
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/manual/woodpecker Pipeline was successful

- added unit test to verify
- minor code clean up to get the tests running

closes #1
This commit is contained in:
D. Moonfire 2023-01-14 17:13:01 -06:00
parent e4c9e82b99
commit fb0a03e963
9 changed files with 93 additions and 22 deletions

View file

@ -10,6 +10,17 @@ namespace MfGames.Gallium;
/// </summary> /// </summary>
public record Entity public record Entity
{ {
public Entity()
: this(Interlocked.Increment(ref nextId))
{
}
private Entity(int id)
{
this.Id = id;
this.Components = ImmutableDictionary.Create<Type, object>();
}
/// <inheritdoc /> /// <inheritdoc />
public virtual bool Equals(Entity? other) public virtual bool Equals(Entity? other)
{ {
@ -29,10 +40,10 @@ public record Entity
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
return this.Id; return this.Id.GetHashCode();
} }
private ImmutableDictionary<Type, object> Components { get; set; } private ImmutableDictionary<Type, object> Components { get; init; }
/// <summary> /// <summary>
/// The internal ID to ensure the entities are unique. Since we are not /// The internal ID to ensure the entities are unique. Since we are not
@ -42,17 +53,6 @@ public record Entity
/// </summary> /// </summary>
private static int nextId; private static int nextId;
public Entity()
: this(Interlocked.Increment(ref nextId))
{
}
private Entity(int id)
{
this.Id = id;
this.Components = ImmutableDictionary.Create<Type, object>();
}
/// <summary> /// <summary>
/// Gets a value indicating whether the entity has a specific type of /// Gets a value indicating whether the entity has a specific type of
/// component registered. /// component registered.
@ -354,7 +354,43 @@ public record Entity
return this with return this with
{ {
Components = this.Components.SetItem(typeof(T1), component) Components = this.Components.SetItem(typeof(T1), component),
};
}
/// <summary>
/// Sets zero or more components into an entity in a single call. This does
/// not allow for specifying the data type; each item will be added with
/// the result of `component.GetType()`.
/// </summary>
/// <param name="components">
/// The components to add to the entity. Any null objects
/// will be ignored.
/// </param>
/// <returns>
/// A new Entity with the modified component collection if there is at
/// least one component to set, otherwise the same entity.
/// </returns>
public Entity SetAll(params object?[] components)
{
if (components.Length == 0)
{
return this;
}
ImmutableDictionary<Type, object> collection = this.Components;
foreach (object? component in components)
{
if (component != null)
{
collection = collection.SetItem(component.GetType(), component);
}
}
return this with
{
Components = collection,
}; };
} }

View file

@ -5,7 +5,7 @@ using MfGames.Gallium;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class EntityTests : GalliumTestsBase public class EntityTests : GalliumTestsBase
{ {
@ -151,6 +151,41 @@ public class EntityTests : GalliumTestsBase
Assert.Equal(0, entity2.Count); Assert.Equal(0, entity2.Count);
} }
[Fact]
public void SetAllSkipsNull()
{
var component1 = new TestComponent1();
var component2 = new TestComponent2();
Entity entity1 = new Entity().SetAll(component1, null);
Assert.Equal(1, entity1.Count);
Assert.True(entity1.Has<TestComponent1>());
Assert.False(entity1.Has<TestComponent2>());
}
[Fact]
public void SetAllWithNothingWorks()
{
Entity entity1 = new Entity().SetAll();
Assert.Equal(0, entity1.Count);
Assert.False(entity1.Has<TestComponent1>());
Assert.False(entity1.Has<TestComponent2>());
}
[Fact]
public void SetAllWorks()
{
var component1 = new TestComponent1();
var component2 = new TestComponent2();
Entity entity1 = new Entity().SetAll(component1, component2);
Assert.Equal(2, entity1.Count);
Assert.True(entity1.Has<TestComponent1>());
Assert.True(entity1.Has<TestComponent2>());
Assert.False(entity1.Has<TestComponent3a>());
}
[Fact] [Fact]
public void SettingComponentsWorks() public void SettingComponentsWorks()
{ {

View file

@ -4,7 +4,7 @@ using MfGames.Gallium;
using Xunit; using Xunit;
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class EnumerableEntityTests public class EnumerableEntityTests
{ {

View file

@ -3,7 +3,7 @@ using Serilog.Core;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
/// <summary> /// <summary>
/// Common initialization logic for Gallium-based tests including setting /// Common initialization logic for Gallium-based tests including setting

View file

@ -1,4 +1,4 @@
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public interface ITestComponent3 public interface ITestComponent3
{ {

View file

@ -1,4 +1,4 @@
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class TestComponent1 public class TestComponent1
{ {

View file

@ -1,4 +1,4 @@
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class TestComponent2 public class TestComponent2
{ {

View file

@ -1,4 +1,4 @@
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class TestComponent3a : ITestComponent3 public class TestComponent3a : ITestComponent3
{ {

View file

@ -1,4 +1,4 @@
namespace Gallium.Tests; namespace MfGames.Gallium.Tests;
public class TestComponent3b : ITestComponent3 public class TestComponent3b : ITestComponent3
{ {