Skip to content

Commit

Permalink
added World.NotifyChanged method
Browse files Browse the repository at this point in the history
  • Loading branch information
Doraku committed Jan 31, 2023
1 parent 2107dea commit 508033c
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 5 deletions.
1 change: 1 addition & 0 deletions documentation/NEXT_RELEASENOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- added World.SubscribeWorldComponentAdded method (#165)
- added World.SubscribeWorldComponentChanged method (#165)
- added World.SubscribeWorldComponentRemoved method (#165)
- added World.NotifyChanged method
- added generic WithAttribute
- added generic WithoutAttribute
- added generic WhenAddedAttribute
Expand Down
30 changes: 30 additions & 0 deletions source/DefaultEcs.Test/WorldTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,36 @@ public void Remove_Should_not_throw_When_no_component()
Check.ThatCode(world.Remove<bool>).DoesNotThrow();
}

[Fact]
public void NotifyChanged_Should_throw_When_no_component()
{
using World world = new();

Check.ThatCode(world.NotifyChanged<bool>).Throws<InvalidOperationException>();
}

[Fact]
public void NotifyChanged_Should_notify_world_component_changed()
{
using World world = new();

world.Set(false);
bool notified = false;

world.SubscribeWorldComponentChanged((World sender, in bool oldValue, in bool newValue) =>
{
Check.That(sender).IsEqualTo(world);
Check.That(oldValue).IsFalse();
Check.That(newValue).IsTrue();
notified = true;
});

world.Get<bool>() = true;
world.NotifyChanged<bool>();

Check.That(notified).IsTrue();
}

[Fact]
public void Has_Should_return_true_when_has_component()
{
Expand Down
6 changes: 3 additions & 3 deletions source/DefaultEcs/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public void SetSameAs<T>(in Entity reference)
ThrowIf(WorldId != reference.WorldId, "Reference Entity comes from a different World");

ComponentPool<T> pool = ComponentManager<T>.Get(WorldId);
ThrowIf(!(pool?.Has(reference.EntityId) ?? false), $"Reference Entity does not have a component of type {nameof(T)}");
ThrowIf(!(pool?.Has(reference.EntityId) ?? false), $"Reference Entity does not have a component of type {typeof(T)}");

InnerSet<T>(pool.SetSameAs(EntityId, reference.EntityId));
}
Expand All @@ -247,7 +247,7 @@ public void SetSameAsWorld<T>()
ThrowIf(WorldId == 0, "Entity was not created from a World");

ComponentPool<T> pool = ComponentManager<T>.Get(WorldId);
ThrowIf(!(pool?.Has(0) ?? false), $"World does not have a component of type {nameof(T)}");
ThrowIf(!(pool?.Has(0) ?? false), $"World does not have a component of type {typeof(T)}");

InnerSet<T>(pool.SetSameAs(EntityId, 0));
}
Expand Down Expand Up @@ -278,7 +278,7 @@ public void Remove<T>()
public void NotifyChanged<T>()
{
ThrowIf(WorldId == 0, "Entity was not created from a World");
ThrowIf(!Has<T>(), $"Entity does not have a component of type {nameof(T)}");
ThrowIf(!Has<T>(), $"Entity does not have a component of type {typeof(T)}");

Publisher.Publish(WorldId, new EntityComponentChangedMessage<T>(EntityId, Components));

Expand Down
2 changes: 1 addition & 1 deletion source/DefaultEcs/Internal/ComponentPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private void On(in ComponentReadMessage message)
#region Methods

[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowMaxNumberOfComponentReached() => throw new InvalidOperationException($"Max number of component of type {nameof(T)} reached");
private static void ThrowMaxNumberOfComponentReached() => throw new InvalidOperationException($"Max number of component of type {typeof(T)} reached");

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityId) => entityId < _mapping.Length && _mapping[entityId] != -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static string GetFriendlyName(string name)

writeExpressions.Add(writeField);

DynamicMethod readMethod = new($"Set_{nameof(T)}_{fieldInfo.Name}", typeof(void), new[] { typeof(StreamReaderWrapper), typeof(T).MakeByRefType() }, typeof(ObjectConverter<T>), true);
DynamicMethod readMethod = new($"Set_{typeof(T)}_{fieldInfo.Name}", typeof(void), new[] { typeof(StreamReaderWrapper), typeof(T).MakeByRefType() }, typeof(ObjectConverter<T>), true);
ILGenerator readGenerator = readMethod.GetILGenerator();
readGenerator.Emit(OpCodes.Ldarg_1);
if (!typeInfo.IsValueType)
Expand Down
21 changes: 21 additions & 0 deletions source/DefaultEcs/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,27 @@ public void Set<T>(in T component)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get<T>() => ref ComponentManager<T>.Pools[WorldId].Get(0);

/// <summary>
/// Notifies the value of the component of type <typeparamref name="T"/> has changed.
/// This method is not thread safe.
/// </summary>
/// <typeparam name="T">The type of the component.</typeparam>
/// <exception cref="InvalidOperationException"><see cref="World"/> does not have a component of type <typeparamref name="T"/>.</exception>
public void NotifyChanged<T>()
{
if (!Has<T>())
{
throw new InvalidOperationException($"World does not have a component of type {typeof(T)}");
}

Publish(new WorldComponentChangedMessage<T>());

if (ComponentManager<T>.GetPrevious(WorldId) is ComponentPool<T> previousPool && Has<T>())
{
previousPool.Set(0, Get<T>());
}
}

/// <summary>
/// Removes the component of type <typeparamref name="T"/> on the current <see cref="World"/>.
/// This method is not thread safe.
Expand Down

0 comments on commit 508033c

Please sign in to comment.