encompass-cs/test/EngineTest.cs

1979 lines
63 KiB
C#
Raw Normal View History

2019-06-15 00:51:06 +00:00
using NUnit.Framework;
using FluentAssertions;
2019-06-15 00:51:06 +00:00
using Encompass;
2019-06-15 01:13:24 +00:00
using System;
using System.Linq;
using System.Collections.Generic;
using Encompass.Exceptions;
2019-06-15 00:51:06 +00:00
2019-06-15 19:32:56 +00:00
namespace Tests
{
struct MockComponent
{
2019-07-17 18:24:21 +00:00
public int myInt;
}
2019-06-15 00:51:06 +00:00
public class EngineTest
{
2019-06-15 18:40:42 +00:00
static MockComponent resultComponent;
static MockComponent[] resultComponents = new MockComponent[1];
2019-06-15 00:51:06 +00:00
static MockMessage resultMessage;
static MockMessage[] resultMessages = new MockMessage[1];
2019-06-16 01:55:35 +00:00
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-15 01:13:24 +00:00
public class ReadComponentsTestEngine : Engine
2019-06-15 00:51:06 +00:00
{
public override void Update(double dt)
2019-06-15 00:51:06 +00:00
{
2020-03-23 02:10:28 +00:00
resultComponents = ReadComponents<MockComponent>().ToArray();
2019-06-15 00:51:06 +00:00
}
}
2020-03-23 02:10:28 +00:00
static List<(MockComponent, Entity)> resultComponentsIncludingEntity = new List<(MockComponent, Entity)>();
2019-11-21 03:01:29 +00:00
static (MockComponent, Entity) resultComponentIncludingEntity;
2019-11-14 18:57:13 +00:00
[Reads(typeof(MockComponent))]
public class ReadComponentsIncludingEntityEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
{
ref readonly var mockComponent = ref GetComponent<MockComponent>(entity);
resultComponentsIncludingEntity.Add((mockComponent, entity));
}
2019-11-14 18:57:13 +00:00
}
}
2019-07-18 01:53:31 +00:00
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-15 01:13:24 +00:00
public class ReadComponentTestEngine : Engine
{
public override void Update(double dt)
2019-06-15 01:13:24 +00:00
{
2019-11-21 03:01:29 +00:00
resultComponent = ReadComponent<MockComponent>();
2019-06-15 01:13:24 +00:00
}
}
2019-11-14 18:57:13 +00:00
[Reads(typeof(MockComponent))]
public class ReadComponentIncludingEntityEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
ref readonly var entity = ref ReadEntity<MockComponent>();
ref readonly var mockComponent = ref GetComponent<MockComponent>(entity);
resultComponentIncludingEntity = (mockComponent, entity);
2019-11-14 18:57:13 +00:00
}
}
2019-06-15 00:51:06 +00:00
[Test]
public void ReadComponents()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentsTestEngine());
2019-06-15 00:51:06 +00:00
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
2019-06-15 00:51:06 +00:00
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 2;
2019-06-15 00:51:06 +00:00
MockComponent mockComponentB;
mockComponentB.myInt = 1;
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entity, mockComponent);
worldBuilder.SetComponent(entityB, mockComponentB);
2019-06-15 00:51:06 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
2019-11-21 03:01:29 +00:00
resultComponents.Should().Contain(mockComponent);
resultComponents.Should().Contain(mockComponentB);
2019-06-15 00:51:06 +00:00
}
2019-06-15 01:13:24 +00:00
2019-11-14 18:57:13 +00:00
[Test]
public void ReadComponentsIncludingEntity()
{
2020-03-23 02:10:28 +00:00
resultComponentsIncludingEntity.Clear();
2019-11-14 18:57:13 +00:00
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentsIncludingEntityEngine());
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 2;
2019-11-14 18:57:13 +00:00
MockComponent mockComponentB;
mockComponentB.myInt = 1;
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entity, mockComponent);
worldBuilder.SetComponent(entityB, mockComponentB);
2019-11-14 18:57:13 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
2019-11-21 03:01:29 +00:00
var resultComponentValues = resultComponentsIncludingEntity.Select((kv) => kv.Item1);
2019-11-14 18:57:13 +00:00
resultComponentValues.Should().Contain(mockComponent);
resultComponentValues.Should().Contain(mockComponentB);
2019-11-21 03:01:29 +00:00
var resultEntities = resultComponentsIncludingEntity.Select((kv) => kv.Item2);
2019-11-14 18:57:13 +00:00
resultEntities.Should().Contain(entity);
resultEntities.Should().Contain(entityB);
2019-11-21 03:01:29 +00:00
resultComponentsIncludingEntity.Should().Contain((mockComponent, entity));
resultComponentsIncludingEntity.Should().Contain((mockComponentB, entityB));
2019-11-14 18:57:13 +00:00
}
2019-06-15 01:13:24 +00:00
[Test]
public void ReadComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentTestEngine());
2019-06-15 01:13:24 +00:00
var entity = worldBuilder.CreateEntity();
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 3;
2019-06-15 01:13:24 +00:00
worldBuilder.SetComponent(entity, mockComponent);
2019-06-15 01:13:24 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
2019-06-15 18:40:42 +00:00
Assert.AreEqual(mockComponent, resultComponent);
2019-06-15 01:13:24 +00:00
}
[Test]
public void ReadComponentThrowsWhenNoneExist()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentTestEngine());
var world = worldBuilder.Build();
Assert.Throws<NoComponentOfTypeException>(() => world.Update(0.01f), "No component of type MockComponent exists");
}
2019-06-15 01:13:24 +00:00
[Test]
public void ReadComponentWhenMultipleComponents()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentTestEngine());
2019-06-15 01:13:24 +00:00
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
2019-06-15 01:13:24 +00:00
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 2;
2019-06-15 01:13:24 +00:00
MockComponent mockComponentB;
mockComponentB.myInt = 1;
worldBuilder.SetComponent(entity, mockComponent);
worldBuilder.SetComponent(entityB, mockComponentB);
2019-06-15 01:13:24 +00:00
var world = worldBuilder.Build();
2019-08-01 23:24:57 +00:00
world.Update(0.01);
Assert.That(resultComponent, Is.EqualTo(mockComponent).Or.EqualTo(mockComponentB));
2019-06-15 01:13:24 +00:00
}
2019-06-15 07:39:08 +00:00
2019-11-14 18:57:13 +00:00
[Test]
public void ReadComponentWithEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentIncludingEntityEngine());
var entity = worldBuilder.CreateEntity();
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 2;
2019-11-14 18:57:13 +00:00
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entity, mockComponent);
2019-11-14 18:57:13 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
2019-11-21 03:01:29 +00:00
(mockComponent, entity).Should().BeEquivalentTo(resultComponentIncludingEntity);
2019-11-14 18:57:13 +00:00
}
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
2019-06-15 07:39:08 +00:00
public class UpdateComponentTestEngine : Engine
{
public override void Update(double dt)
2019-06-15 07:39:08 +00:00
{
2020-03-23 02:10:28 +00:00
ref readonly var entity = ref ReadEntity<MockComponent>();
SetComponent(entity, new MockComponent { myInt = 420 });
2019-06-15 07:39:08 +00:00
}
}
2019-07-18 01:53:31 +00:00
// this test needs to be improved...
2019-06-15 07:39:08 +00:00
[Test]
public void UpdateComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new UpdateComponentTestEngine());
2019-07-18 01:53:31 +00:00
worldBuilder.AddEngine(new ReadComponentTestEngine());
2019-06-15 07:39:08 +00:00
var entity = worldBuilder.CreateEntity();
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 3;
2019-06-15 07:39:08 +00:00
worldBuilder.SetComponent(entity, mockComponent);
2019-06-15 07:39:08 +00:00
var world = worldBuilder.Build();
2019-07-18 01:53:31 +00:00
world.Update(0.01);
world.Update(0.01);
2019-06-15 07:39:08 +00:00
2019-06-15 18:40:42 +00:00
Assert.AreEqual(420, resultComponent.myInt);
2019-06-15 07:39:08 +00:00
}
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-15 07:39:08 +00:00
public class UndeclaredUpdateComponentTestEngine : Engine
{
public override void Update(double dt)
2019-06-15 07:39:08 +00:00
{
2020-03-23 02:10:28 +00:00
ref readonly var entity = ref ReadEntity<MockComponent>();
SetComponent(entity, new MockComponent { myInt = 420 });
2019-06-15 07:39:08 +00:00
}
}
[Test]
public void UpdateUndeclaredComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new UndeclaredUpdateComponentTestEngine());
2019-06-15 07:39:08 +00:00
var entity = worldBuilder.CreateEntity();
MockComponent mockComponent;
2020-03-20 22:45:58 +00:00
mockComponent.myInt = 3;
2019-06-15 07:39:08 +00:00
worldBuilder.SetComponent(entity, mockComponent);
2019-06-15 07:39:08 +00:00
var world = worldBuilder.Build();
var ex = Assert.Throws<IllegalWriteException>(() => world.Update(0.01f));
2019-07-19 23:15:48 +00:00
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
2019-06-15 07:39:08 +00:00
}
2019-06-16 01:55:35 +00:00
struct MockMessage
2019-06-16 01:55:35 +00:00
{
public string myString;
}
2019-07-19 01:20:38 +00:00
[Sends(typeof(MockMessage))]
2019-06-16 01:55:35 +00:00
public class MessageEmitEngine : Engine
{
public override void Update(double dt)
2019-06-16 01:55:35 +00:00
{
MockMessage message;
message.myString = "howdy";
this.SendMessage(message);
2019-06-16 01:55:35 +00:00
}
}
2019-07-19 19:47:17 +00:00
[Receives(typeof(MockMessage))]
public class ReadMessagesEngine : Engine
2019-06-16 01:55:35 +00:00
{
public override void Update(double dt)
2019-06-16 01:55:35 +00:00
{
2020-03-22 20:41:55 +00:00
resultMessages = ReadMessages<MockMessage>().ToArray();
2019-06-16 01:55:35 +00:00
}
}
[Receives(typeof(MockMessage))]
public class ReadMessageEngine : Engine
{
public override void Update(double dt)
{
resultMessage = ReadMessage<MockMessage>();
}
}
2019-06-16 01:55:35 +00:00
[Test]
public void EmitAndReadMessage()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new MessageEmitEngine());
worldBuilder.AddEngine(new ReadMessageEngine());
2019-06-16 01:55:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
Assert.AreEqual(resultMessage.myString, "howdy");
}
[Test]
public void ReadMessageThrowsWhenNoneOfTypeExist()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadMessageEngine());
var world = worldBuilder.Build();
Assert.Throws<NoMessageOfTypeException>(() => world.Update(0.01), "No Message of type MockMessage exists");
2019-06-16 01:55:35 +00:00
}
public class UndeclaredMessageEmitEngine : Engine
{
public override void Update(double dt)
2019-06-16 01:55:35 +00:00
{
MockMessage message;
message.myString = "howdy";
this.SendMessage(message);
2019-06-16 01:55:35 +00:00
}
}
2020-03-22 20:41:55 +00:00
static MockMessage[] emptyReadMessagesResult;
2019-07-19 19:47:17 +00:00
[Receives(typeof(MockMessage))]
2019-06-22 00:23:52 +00:00
class ReadMessagesWhenNoneExistEngine : Engine
{
2019-06-24 19:40:40 +00:00
public override void Update(double dt)
2019-06-22 00:23:52 +00:00
{
2020-03-22 20:41:55 +00:00
emptyReadMessagesResult = ReadMessages<MockMessage>().ToArray();
2019-06-22 00:23:52 +00:00
}
}
[Test]
public void ReadMessagesWhenNoneHaveBeenEmitted()
{
var worldBuilder = new WorldBuilder();
2019-06-24 19:40:40 +00:00
worldBuilder.AddEngine(new ReadMessagesWhenNoneExistEngine());
2019-06-22 00:23:52 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
emptyReadMessagesResult.Should().BeEmpty();
}
2019-06-16 01:55:35 +00:00
[Test]
public void EmitUndeclaredMessage()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new UndeclaredMessageEmitEngine());
2019-06-16 01:55:35 +00:00
var world = worldBuilder.Build();
2019-07-19 19:47:17 +00:00
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
2019-07-19 23:15:48 +00:00
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to send undeclared Message MockMessage"));
2019-06-16 01:55:35 +00:00
}
2019-06-17 01:11:35 +00:00
static bool someTest;
2019-07-19 01:20:38 +00:00
[Sends(typeof(MockMessage))]
2019-06-17 01:11:35 +00:00
class EmitMockMessageEngine : Engine
{
public override void Update(double dt)
2019-06-17 01:11:35 +00:00
{
MockMessage message;
message.myString = "howdy";
this.SendMessage(message);
2019-06-17 01:11:35 +00:00
}
}
2019-07-19 19:47:17 +00:00
[Receives(typeof(MockMessage))]
class SomeMessageTestEngine : Engine
2019-06-17 01:11:35 +00:00
{
public override void Update(double dt)
2019-06-17 01:11:35 +00:00
{
someTest = this.SomeMessage<MockMessage>();
2019-06-17 01:11:35 +00:00
}
}
[Test]
public void SomeMessage()
2019-06-17 01:11:35 +00:00
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new EmitMockMessageEngine());
worldBuilder.AddEngine(new SomeMessageTestEngine());
2019-06-17 01:11:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
Assert.That(someTest, Is.True);
}
2019-06-17 01:16:45 +00:00
class UndeclaredSomeMessageEngine : Engine
2019-06-17 01:16:45 +00:00
{
public override void Update(double dt)
2019-06-17 01:16:45 +00:00
{
someTest = this.SomeMessage<MockMessage>();
2019-06-17 01:16:45 +00:00
}
}
[Test]
public void UndeclaredSomeMessage()
2019-06-17 01:16:45 +00:00
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new EmitMockMessageEngine());
worldBuilder.AddEngine(new UndeclaredSomeMessageEngine());
2019-06-17 01:16:45 +00:00
var world = worldBuilder.Build();
Assert.Throws<IllegalReadException>(() => world.Update(0.01f));
2019-06-17 01:16:45 +00:00
}
2019-06-17 19:12:07 +00:00
struct EntityMessage : IHasEntity
{
public EntityMessage(Entity entity, int myInt)
{
Entity = entity;
MyInt = myInt;
}
public Entity Entity { get; }
public int MyInt { get; }
}
[Sends(typeof(EntityMessage), typeof(MockMessage))]
class EntityMessageEmitterEngine : Engine
{
private Entity _entity;
public EntityMessageEmitterEngine(Entity entity)
{
_entity = entity;
}
public override void Update(double dt)
{
SendMessage(new EntityMessage(_entity, 2));
SendMessage(new EntityMessage(_entity, 4));
SendMessage(new EntityMessage(_entity, 5));
SendMessage(new MockMessage());
}
}
static List<EntityMessage> entityMessageResults;
[Receives(typeof(EntityMessage))]
class EntityMessageReceiverEngine : Engine
{
private Entity _entity;
public EntityMessageReceiverEngine(Entity entity)
{
_entity = entity;
}
public override void Update(double dt)
{
2019-12-30 07:55:48 +00:00
entityMessageResults = ReadMessagesWithEntity<EntityMessage>(_entity).ToList();
}
}
[Test]
public void MessagesWithEntity()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new EntityMessageEmitterEngine(entity));
worldBuilder.AddEngine(new EntityMessageReceiverEngine(entity));
var world = worldBuilder.Build();
world.Update(0.01);
entityMessageResults.Should().HaveCount(3);
entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 2));
entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 4));
entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 5));
}
[Test]
public void NoMessagesWithEntity()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new EntityMessageReceiverEngine(entity));
var world = worldBuilder.Build();
world.Update(0.01);
entityMessageResults.Should().BeEmpty();
}
[Sends(typeof(EntityMessage), typeof(MockMessage))]
class EntityMessageSingularEmitterEngine : Engine
{
private Entity _entity;
public EntityMessageSingularEmitterEngine(Entity entity)
{
_entity = entity;
}
public override void Update(double dt)
{
SendMessage(new EntityMessage(_entity, 2));
SendMessage(new MockMessage());
}
}
static EntityMessage entityMessageResult;
[Receives(typeof(EntityMessage))]
class SingularMessageWithEntityEngine : Engine
{
private Entity _entity;
public SingularMessageWithEntityEngine(Entity entity)
{
_entity = entity;
}
public override void Update(double dt)
{
entityMessageResult = ReadMessageWithEntity<EntityMessage>(_entity);
}
}
[Test]
public void MessageWithEntity()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new EntityMessageSingularEmitterEngine(entity));
worldBuilder.AddEngine(new SingularMessageWithEntityEngine(entity));
var world = worldBuilder.Build();
world.Update(0.01);
entityMessageResult.Should().Be(new EntityMessage(entity, 2));
}
class SomeComponentTestEngine : Engine
{
public override void Update(double dt)
{
Assert.IsTrue(SomeComponent<MockComponent>());
}
}
[Test]
public void SomeComponent()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
world.Update(0.01);
}
2019-11-21 03:01:29 +00:00
static (MockComponent, Entity) pairA;
static (MockComponent, Entity) pairB;
2019-06-17 19:12:07 +00:00
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-17 19:12:07 +00:00
class SameValueComponentReadEngine : Engine
{
public override void Update(double dt)
2019-06-17 19:12:07 +00:00
{
2020-03-23 02:10:28 +00:00
var entities = ReadEntities<MockComponent>();
2019-06-17 19:12:07 +00:00
2020-03-23 02:10:28 +00:00
pairA = (GetComponent<MockComponent>(entities[0]), entities[0]);
pairB = (GetComponent<MockComponent>(entities[1]), entities[1]);
2019-06-17 19:12:07 +00:00
}
}
2019-11-21 03:01:29 +00:00
// Tests that components with identical values should be distinguishable by their entities
2019-06-17 19:12:07 +00:00
[Test]
public void SameValueComponents()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new SameValueComponentReadEngine());
2019-06-17 19:12:07 +00:00
MockComponent componentA;
componentA.myInt = 20;
MockComponent componentB;
componentB.myInt = 20;
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, componentA);
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, componentB);
2019-06-17 19:12:07 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
2019-11-21 03:01:29 +00:00
Assert.That(EngineTest.pairA, Is.Not.EqualTo(EngineTest.pairB));
Assert.That(EngineTest.pairA.Item1, Is.EqualTo(EngineTest.pairB.Item1));
2019-06-17 19:12:07 +00:00
}
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-17 19:12:07 +00:00
class ReadEmptyMockComponentsEngine : Engine
{
public override void Update(double dt)
2019-06-17 19:12:07 +00:00
{
2020-03-23 02:10:28 +00:00
ReadEntities<MockComponent>().ToArray().Should().BeEmpty();
2019-06-17 19:12:07 +00:00
}
}
[Test]
public void ReadComponentsOfTypeWhereNoneExist()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEmptyMockComponentsEngine());
2019-06-17 19:12:07 +00:00
var world = worldBuilder.Build();
world.Update(0.01f);
}
2019-06-20 03:37:46 +00:00
struct DestroyerComponent { }
2019-06-20 03:37:46 +00:00
2019-07-18 21:02:57 +00:00
[Reads(typeof(DestroyerComponent))]
2019-06-20 03:37:46 +00:00
class DestroyerEngine : Engine
{
public override void Update(double dt)
2019-06-20 03:37:46 +00:00
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<DestroyerComponent>())
2019-06-20 03:37:46 +00:00
{
2019-11-21 03:01:29 +00:00
Destroy(entity);
2019-06-20 03:37:46 +00:00
}
}
}
2020-03-23 02:10:28 +00:00
static List<(MockComponent, Entity)> results = new List<(MockComponent, Entity)>();
2019-07-18 21:02:57 +00:00
[Reads(typeof(MockComponent))]
2019-06-20 03:37:46 +00:00
class ReaderEngine : Engine
{
public override void Update(double dt)
2019-06-20 03:37:46 +00:00
{
2020-03-23 02:10:28 +00:00
results.Clear();
foreach (ref readonly var entity in ReadEntities<MockComponent>())
{
ref readonly var mockComponent = ref GetComponent<MockComponent>(entity);
results.Add((mockComponent, entity));
}
2019-06-20 03:37:46 +00:00
}
}
[Test]
public void DestroyEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new DestroyerEngine());
worldBuilder.AddEngine(new ReaderEngine());
2019-06-20 03:37:46 +00:00
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
2019-06-20 03:37:46 +00:00
DestroyerComponent destroyerComponent;
MockComponent mockComponent;
mockComponent.myInt = 2;
worldBuilder.SetComponent(entity, destroyerComponent);
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entity, mockComponent);
2019-06-20 03:37:46 +00:00
worldBuilder.SetComponent(entityB, destroyerComponent);
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entityB, mockComponent);
2019-06-20 03:37:46 +00:00
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entityC, mockComponent);
2019-06-20 03:37:46 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01);
2019-06-20 03:37:46 +00:00
2019-11-21 03:01:29 +00:00
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
2019-12-05 22:59:55 +00:00
Assert.That(results, Does.Not.Contain((mockComponent, entityB)));
2019-11-21 03:01:29 +00:00
Assert.That(results, Does.Contain((mockComponent, entityC)));
}
[Receives(typeof(DestroyComponentMessage))]
class DestroyEntityEngine : Engine
{
public override void Update(double dt)
{
foreach (ref readonly var message in ReadMessages<DestroyComponentMessage>())
{
Destroy(message.entity);
}
}
}
[Test]
public void DestroyEntityWithoutID()
{
2020-03-23 02:10:28 +00:00
results.Clear();
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddComponentEngine());
worldBuilder.AddEngine(new DestroyEntityEngine());
worldBuilder.AddEngine(new ReaderEngine());
var mockComponent = new MockComponent { };
var entity = worldBuilder.CreateEntity();
2019-11-21 03:01:29 +00:00
worldBuilder.SetComponent(entity, mockComponent);
worldBuilder.SendMessage(new DestroyComponentMessage { entity = entity });
var world = worldBuilder.Build();
world.Update(0.01);
Assert.DoesNotThrow(() => world.Update(0.01));
2019-11-21 03:01:29 +00:00
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
}
[Reads(typeof(DestroyerComponent))]
[Writes(typeof(MockComponent))]
class DestroyAndAddComponentEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<DestroyerComponent>())
{
2019-11-21 03:01:29 +00:00
RemoveComponent<MockComponent>(entity);
Destroy(entity);
}
}
}
[Test]
public void DestroyEntityWhileRemovingComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new DestroyAndAddComponentEngine());
worldBuilder.AddEngine(new ReaderEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new DestroyerComponent());
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.01));
2019-06-20 03:37:46 +00:00
}
[Reads(typeof(MockComponent))]
2019-12-24 03:04:26 +00:00
[WritesImmediate(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
class AddAndRemoveMockComponentEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
{
2019-11-21 03:01:29 +00:00
RemoveComponent<MockComponent>(entity);
SetComponent(entity, new MockComponent());
}
}
}
2019-11-21 03:01:29 +00:00
static Entity entityResult;
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponent))]
class GetEntityFromImmediateReadComponents : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
ref readonly var entity = ref ReadEntity<MockComponent>();
}
}
[Test]
2019-12-24 03:04:26 +00:00
public void GetEntityFromImmediateComponentID()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddAndRemoveMockComponentEngine());
2019-12-24 03:04:26 +00:00
worldBuilder.AddEngine(new GetEntityFromImmediateReadComponents());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.01));
}
2019-08-20 02:05:18 +00:00
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
2019-08-20 02:05:18 +00:00
class DelayedMessageEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
2019-08-20 02:05:18 +00:00
{
2019-11-21 03:01:29 +00:00
RemoveComponent<MockComponent>(entity);
2019-11-21 22:22:10 +00:00
SendMessage(new MockMessage { }, 1);
2019-08-20 02:05:18 +00:00
}
}
}
[Test]
public void EngineSendMessageDelayed()
{
2020-03-22 20:41:55 +00:00
Array.Clear(resultMessages, 0, resultMessages.Length);
2019-08-20 02:05:18 +00:00
var worldBuilder = new WorldBuilder();
2019-11-21 22:22:10 +00:00
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
2019-08-20 02:05:18 +00:00
worldBuilder.AddEngine(new DelayedMessageEngine());
worldBuilder.AddEngine(new ReadMessagesEngine());
2019-08-20 02:05:18 +00:00
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
2019-08-20 02:05:18 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
resultMessages.Should().BeEmpty();
world.Update(0.5);
resultMessages.Should().BeEmpty();
world.Update(0.5);
2019-11-21 22:22:10 +00:00
resultMessages.Should().BeEmpty();
world.Update(2);
resultMessages.Should().NotBeEmpty();
resultMessages.First().Should().BeOfType<MockMessage>();
}
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
2019-11-21 22:22:10 +00:00
class DelayedMessageIgnoringTimeDilationEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
2019-11-21 22:22:10 +00:00
{
RemoveComponent<MockComponent>(entity);
SendMessageIgnoringTimeDilation(new MockMessage { }, 1);
}
}
}
[Test]
public void EngineSendMessageDelayedIgnoringTimeDilation()
{
2020-03-22 20:41:55 +00:00
Array.Clear(resultMessages, 0, resultMessages.Length);
2019-11-21 22:22:10 +00:00
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageIgnoringTimeDilationEngine());
worldBuilder.AddEngine(new ReadMessagesEngine());
2019-11-21 22:22:10 +00:00
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var world = worldBuilder.Build();
world.Update(0.01);
resultMessages.Should().BeEmpty();
world.Update(0.5);
resultMessages.Should().BeEmpty();
world.Update(0.5);
2019-08-20 02:05:18 +00:00
resultMessages.Should().NotBeEmpty();
resultMessages.First().Should().BeOfType<MockMessage>();
}
[Receives(typeof(MockMessage))]
2019-12-24 03:04:26 +00:00
[WritesImmediate(typeof(MockComponent))]
[Writes(typeof(MockComponent), 1)]
class ActivateComponentEngine : Engine
{
public override void Update(double dt)
{
foreach (ref readonly var message in ReadMessages<MockMessage>())
{
var entity = CreateEntity();
SetComponent(entity, new MockComponent { });
}
}
}
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponent))]
[Writes(typeof(MockComponent), 0)]
class RemoveComponentEngine : Engine
{
public override void Update(double dt)
{
2019-11-21 03:01:29 +00:00
foreach (var entity in ReadEntities<MockComponent>())
{
2019-11-21 03:01:29 +00:00
RemoveComponent<MockComponent>(entity);
}
}
}
[Test]
public void EngineAddAndRemoveComponentSameFrameWithRemovePriority()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateComponentEngine());
worldBuilder.AddEngine(new RemoveComponentEngine());
worldBuilder.AddEngine(new ReadComponentsTestEngine());
worldBuilder.SendMessage(new MockMessage { });
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.01));
world.Update(0.01); // update again for the read
resultComponents.Should().BeEmpty();
}
struct DestroyComponentMessage { public Entity entity; }
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
class AddComponentEngine : Engine
{
public override void Update(double dt)
{
2019-11-21 03:01:29 +00:00
foreach (var entity in ReadEntities<MockComponent>())
{
2019-11-21 03:01:29 +00:00
SetComponent(entity, new MockComponent { });
}
}
}
static Entity readEntity;
[Reads(typeof(MockComponent))]
class ReadEntityByComponentTypeEngine : Engine
{
public override void Update(double dt)
{
readEntity = ReadEntity<MockComponent>();
}
}
[Test]
public void ReadEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
world.Update(0.01);
entity.Should().BeEquivalentTo(readEntity);
}
[Test]
public void ReadEntityThrowsWhenNoComponentOfTypeExists()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine());
var world = worldBuilder.Build();
Assert.Throws<NoComponentOfTypeException>(() => world.Update(0.01), "No component of type MockComponent exists");
}
struct MockComponentB
{
2020-03-20 22:45:58 +00:00
private int value;
public MockComponentB(int value)
{
this.value = value;
}
}
static MockComponentB getComponentResult;
[Reads(typeof(MockComponent), typeof(MockComponentB))]
class GetComponentEngine : Engine
{
public override void Update(double dt)
{
getComponentResult = GetComponent<MockComponentB>(ReadEntity<MockComponent>());
}
}
[Test]
public void GetComponent()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.SetComponent(entity, new MockComponentB(3));
worldBuilder.AddEngine(new GetComponentEngine());
var world = worldBuilder.Build();
world.Update(0.01);
getComponentResult.Should().BeEquivalentTo(new MockComponentB(3));
}
[Reads(typeof(MockComponent), typeof(MockComponentB))]
class GetComponentExceptionEngine : Engine
{
public override void Update(double dt)
{
foreach (var entity in ReadEntities<MockComponent>())
{
GetComponent<MockComponentB>(entity);
}
}
}
[Test]
public void GetComponentWhenComponentIsNotOnEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new GetComponentExceptionEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.Throws<Encompass.Exceptions.NoComponentOfTypeOnEntityException>(() => world.Update(0.01));
}
static Entity[] readEntities;
[Reads(typeof(MockComponent))]
class ReadEntitiesWithComponentTypeEngine : Engine
{
public override void Update(double dt)
{
readEntities = ReadEntities<MockComponent>().ToArray();
}
}
[Test]
public void ReadEntities()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntitiesWithComponentTypeEngine());
worldBuilder.AddEngine(new DestroyAllWithEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, new MockComponent { });
var world = worldBuilder.Build();
world.Update(0.01);
readEntities.Should().Contain(entity);
readEntities.Should().Contain(entityB);
}
[Reads(typeof(MockComponent))]
class DestroyWithEngine : Engine
{
public override void Update(double dt)
{
if (SomeComponent<MockComponent>())
{
DestroyWith<MockComponent>();
}
}
}
[Test]
public void DestroyWith()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntitiesWithComponentTypeEngine());
worldBuilder.AddEngine(new DestroyWithEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01); // update twice so the read happens after destroy
readEntities.Should().BeEmpty();
}
[Reads(typeof(MockComponent))]
class DestroyAllWithEngine : Engine
{
public override void Update(double dt)
{
DestroyAllWith<MockComponent>();
}
}
[Test]
public void DestroyAllWith()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntitiesWithComponentTypeEngine());
worldBuilder.AddEngine(new DestroyAllWithEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, new MockComponent { });
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01); // update twice so the read happens after destroy
readEntities.Should().BeEmpty();
}
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
class RemoveComponentByTypeEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
{
RemoveComponent<MockComponent>(entity);
}
}
}
[Test]
public void RemoveComponentByType()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentsTestEngine());
worldBuilder.AddEngine(new RemoveComponentByTypeEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01);
resultComponents.Should().BeEmpty();
}
static double dilatedDeltaTime;
class ActivateTimeDilationEngine : Engine
{
public override void Update(double dt)
{
if (!TimeDilationActive)
{
ActivateTimeDilation(0.2, 1, 1, 1);
}
else
{
dilatedDeltaTime = dt;
}
}
}
[Test]
public void ActivateTimeDilation()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
var world = worldBuilder.Build();
world.Update(0.01); // activate time dilation
world.Update(0.5);
dilatedDeltaTime.Should().BeApproximately(0.3, 0.01);
world.Update(0.5);
dilatedDeltaTime.Should().BeApproximately(0.1, 0.01);
world.Update(1);
world.Update(0.5);
dilatedDeltaTime.Should().BeApproximately(0.3, 0.01);
}
class ActivateTimeDilationLowerFactorEngine : Engine
{
private bool activated = false;
public override void Update(double dt)
{
if (!activated)
{
ActivateTimeDilation(0.2, 1, 1, 1);
activated = true;
}
}
}
class ActivateTimeDilationHigherFactorEngine : Engine
{
private bool activated = false;
public override void Update(double dt)
{
if (!activated)
{
ActivateTimeDilation(0.5, 1, 1, 1);
activated = true;
}
}
}
2019-11-22 21:18:43 +00:00
static bool timeDilationActive;
class ReadDilatedDeltaTimeEngine : Engine
{
public override void Update(double dt)
{
dilatedDeltaTime = dt;
2019-11-22 21:18:43 +00:00
timeDilationActive = TimeDilationActive;
}
}
[Test]
public void MultipleActivateTimeDilation()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadDilatedDeltaTimeEngine());
worldBuilder.AddEngine(new ActivateTimeDilationLowerFactorEngine());
worldBuilder.AddEngine(new ActivateTimeDilationHigherFactorEngine());
var world = worldBuilder.Build();
world.Update(0.01); // activate time dilation
world.Update(0.5); // 0.3 and 0.375
dilatedDeltaTime.Should().BeApproximately(0.3375, 0.01);
2019-11-22 21:18:43 +00:00
timeDilationActive.Should().BeTrue();
world.Update(5);
dilatedDeltaTime.Should().BeApproximately(5, 0.01);
2019-11-22 21:18:43 +00:00
timeDilationActive.Should().BeFalse();
}
static double undilatedDeltaTime;
[IgnoresTimeDilation]
class IgnoresTimeDilationEngine : Engine
{
public override void Update(double dt)
{
undilatedDeltaTime = dt;
}
}
[Test]
public void IgnoresTimeDilation()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new IgnoresTimeDilationEngine());
var world = worldBuilder.Build();
world.Update(0.01); // activate time dilation
world.Update(0.5);
undilatedDeltaTime.Should().Be(0.5);
}
[Adds(typeof(MockComponent))]
class AddComponentWithoutPriorityEngine : Engine
{
public override void Update(double dt)
{
var entity = CreateEntity();
AddComponent(entity, new MockComponent());
var entityB = CreateEntity();
AddComponent(entityB, new MockComponent());
}
}
[Test]
public void AddComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddComponentWithoutPriorityEngine());
worldBuilder.AddEngine(new ReadComponentsTestEngine());
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01);
resultComponents.Should().HaveCount(2);
world.Update(0.01);
resultComponents.Should().HaveCount(4);
}
[Reads(typeof(MockComponent))]
class AddComponentToPreviouslyExistingEntityEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
ref readonly var entity = ref ReadEntity<MockComponent>();
AddComponent(entity, new MockComponent());
}
}
[Test]
public void AddComponentToPreviouslyExistingEntityTest()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddComponentToPreviouslyExistingEntityEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.Throws<IllegalWriteException>(() => world.Update(0.01));
}
[Adds(typeof(MockComponentB))]
[WritesImmediate(typeof(MockComponentB))]
class AddImmediateComponentEngine : Engine
{
public override void Update(double dt)
{
var entity = CreateEntity();
AddComponent(entity, new MockComponentB(5));
}
}
[ReadsImmediate(typeof(MockComponentB))]
class ReadImmediateComponentEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
ref readonly var component = ref ReadComponent<MockComponentB>();
getComponentResult = component;
}
}
[Test]
public void AddImmediateComponentTest()
{
getComponentResult = default(MockComponentB);
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddImmediateComponentEngine());
worldBuilder.AddEngine(new ReadImmediateComponentEngine());
var world = worldBuilder.Build();
world.Update(0.01);
getComponentResult.Should().Be(new MockComponentB(5));
}
2020-03-18 00:40:11 +00:00
static bool entityExistsResult;
class EntityExistsEngine : Engine
{
private int _id;
public EntityExistsEngine(int id)
{
_id = id;
}
public override void Update(double dt)
{
entityExistsResult = EntityExists(_id);
}
}
[Test]
public void PruneEmptyEntities()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var id = entity.ID;
var world = worldBuilder.Build();
world.Update(0.01);
entityExistsResult.Should().BeFalse();
}
2019-12-22 09:15:58 +00:00
public class QueryTests
{
struct MockComponentB { }
struct MockComponentC { }
struct MockComponentD { }
2019-12-28 22:30:26 +00:00
[Writes(typeof(MockComponentB))]
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
2019-12-22 09:15:58 +00:00
class EntityQueryWithComponentsEngine : Engine
{
private List<Entity> entities;
2019-12-22 09:15:58 +00:00
public EntityQueryWithComponentsEngine(List<Entity> entities)
{
this.entities = entities;
}
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
foreach (var entity in TrackedEntities)
{
entities.Add(entity);
2019-12-28 22:30:26 +00:00
RemoveComponent<MockComponentB>(entity);
}
2019-12-22 09:15:58 +00:00
}
}
[Test]
public void EntitiesWithComponents()
{
2019-12-22 09:15:58 +00:00
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.SetComponent(entity, new MockComponentB());
worldBuilder.SetComponent(entityB, new MockComponent());
worldBuilder.SetComponent(entityB, new MockComponentB());
worldBuilder.SetComponent(entityC, new MockComponentB());
var queriedEntities = new List<Entity>();
worldBuilder.AddEngine(new EntityQueryWithComponentsEngine(queriedEntities));
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.Should().BeEquivalentTo(new Entity[] { entity, entityB });
2019-12-28 22:30:26 +00:00
world.Update(0.01);
queriedEntities.Should().BeEmpty();
}
2019-12-28 22:30:26 +00:00
[Writes(typeof(MockComponent))]
[QueryWithout(typeof(MockComponent))]
2019-12-22 09:15:58 +00:00
class EntityQueryWithoutComponentsEngine : Engine
{
private List<Entity> entities;
2019-12-22 09:15:58 +00:00
public EntityQueryWithoutComponentsEngine(List<Entity> entities)
{
this.entities = entities;
}
2019-12-22 09:15:58 +00:00
public override void Update(double dt)
{
entities.Clear();
2019-12-28 22:30:26 +00:00
foreach (var entity in TrackedEntities)
{
entities.Add(entity);
SetComponent(entity, new MockComponent());
}
2019-12-22 09:15:58 +00:00
}
}
2019-12-22 09:15:58 +00:00
[Test]
public void EntitiesWithoutComponents()
{
var worldBuilder = new WorldBuilder();
2019-12-22 09:15:58 +00:00
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
2019-12-22 09:15:58 +00:00
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.SetComponent(entity, new MockComponentB());
2019-12-22 09:15:58 +00:00
worldBuilder.SetComponent(entityB, new MockComponent());
worldBuilder.SetComponent(entityB, new MockComponentB());
worldBuilder.SetComponent(entityC, new MockComponentB());
var queriedEntities = new List<Entity>();
worldBuilder.AddEngine(new EntityQueryWithoutComponentsEngine(queriedEntities));
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityC });
2019-12-28 22:30:26 +00:00
world.Update(0.01);
queriedEntities.Should().BeEmpty();
2019-12-22 09:15:58 +00:00
}
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
[QueryWithout(typeof(MockComponentD))]
2019-12-22 09:15:58 +00:00
class EntityQueryWithandWithoutComponentsEngine : Engine
{
private List<Entity> entities;
public EntityQueryWithandWithoutComponentsEngine(List<Entity> entities)
{
this.entities = entities;
}
2019-12-22 09:15:58 +00:00
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
entities.AddRange(TrackedEntities);
2019-12-22 09:15:58 +00:00
}
}
[Test]
public void EntitiesWithAndWithoutComponents()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
var entityD = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.SetComponent(entity, new MockComponentB());
worldBuilder.SetComponent(entity, new MockComponentD());
worldBuilder.SetComponent(entityB, new MockComponent());
worldBuilder.SetComponent(entityC, new MockComponent());
worldBuilder.SetComponent(entityC, new MockComponentB());
worldBuilder.SetComponent(entityC, new MockComponentC());
worldBuilder.SetComponent(entityC, new MockComponentD());
worldBuilder.SetComponent(entityD, new MockComponent());
worldBuilder.SetComponent(entityD, new MockComponentB());
worldBuilder.SetComponent(entityD, new MockComponentC());
var queriedEntities = new List<Entity>();
worldBuilder.AddEngine(new EntityQueryWithandWithoutComponentsEngine(queriedEntities));
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityD });
}
2019-12-22 19:44:35 +00:00
[Reads(typeof(MockComponent))]
2019-12-24 03:04:26 +00:00
[WritesImmediate(typeof(MockComponentB))]
2019-12-22 19:44:35 +00:00
[Writes(typeof(MockComponentB), 0)]
2019-12-24 03:04:26 +00:00
class AddImmediateComponentEngine : Engine
2019-12-22 19:44:35 +00:00
{
public override void Update(double dt)
{
foreach (var entity in ReadEntities<MockComponent>())
2019-12-22 19:44:35 +00:00
{
SetComponent(entity, new MockComponentB());
}
}
}
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponentB))]
[QueryWith(typeof(MockComponentB))]
2019-12-24 03:04:26 +00:00
class EntityQueryWithImmediateComponentsEngine : Engine
2019-12-22 19:44:35 +00:00
{
private List<Entity> entities;
2019-12-24 03:04:26 +00:00
public EntityQueryWithImmediateComponentsEngine(List<Entity> entities)
2019-12-22 19:44:35 +00:00
{
this.entities = entities;
}
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
entities.AddRange(TrackedEntities);
2019-12-22 19:44:35 +00:00
}
}
[Test]
2019-12-24 03:04:26 +00:00
public void EntitiesWithImmediateComponents()
2019-12-22 19:44:35 +00:00
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var queriedEntities = new List<Entity>();
2019-12-24 03:04:26 +00:00
worldBuilder.AddEngine(new AddImmediateComponentEngine());
worldBuilder.AddEngine(new EntityQueryWithImmediateComponentsEngine(queriedEntities));
2019-12-22 19:44:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entity });
}
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponentB))]
[QueryWithout(typeof(MockComponentB))]
2019-12-24 03:04:26 +00:00
class EntityQueryWithoutImmediateComponentsEngine : Engine
2019-12-22 19:44:35 +00:00
{
private List<Entity> entities;
2019-12-24 03:04:26 +00:00
public EntityQueryWithoutImmediateComponentsEngine(List<Entity> entities)
2019-12-22 19:44:35 +00:00
{
this.entities = entities;
}
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
entities.AddRange(TrackedEntities);
2019-12-22 19:44:35 +00:00
}
}
[Test]
2019-12-24 03:04:26 +00:00
public void EntitiesWithoutImmediateComponents()
2019-12-22 19:44:35 +00:00
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
var queriedEntities = new List<Entity>();
2019-12-24 03:04:26 +00:00
worldBuilder.AddEngine(new AddImmediateComponentEngine());
worldBuilder.AddEngine(new EntityQueryWithoutImmediateComponentsEngine(queriedEntities));
2019-12-22 19:44:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB });
}
[Reads(typeof(MockComponentC), typeof(MockComponentD))]
2019-12-24 03:04:26 +00:00
[WritesImmediate(typeof(MockComponent), typeof(MockComponentB))]
2019-12-22 19:44:35 +00:00
[Writes(typeof(MockComponent), 0)]
[Writes(typeof(MockComponentB), 0)]
2019-12-24 03:04:26 +00:00
class ConditionallyAddImmediateComponentsEngine : Engine
2019-12-22 19:44:35 +00:00
{
public override void Update(double dt)
{
foreach (var entity in ReadEntities<MockComponentC>())
2019-12-22 19:44:35 +00:00
{
SetComponent(entity, new MockComponent());
}
foreach (var entity in ReadEntities<MockComponentD>())
2019-12-22 19:44:35 +00:00
{
SetComponent(entity, new MockComponent());
SetComponent(entity, new MockComponentB());
}
}
}
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponent), typeof(MockComponentB))]
[QueryWith(typeof(MockComponent))]
[QueryWithout(typeof(MockComponentB))]
2019-12-24 03:04:26 +00:00
class EntityQueryWithAndWithoutImmediateComponentsEngine : Engine
2019-12-22 19:44:35 +00:00
{
private List<Entity> entities;
2019-12-24 03:04:26 +00:00
public EntityQueryWithAndWithoutImmediateComponentsEngine(List<Entity> entities)
2019-12-22 19:44:35 +00:00
{
this.entities = entities;
}
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
entities.AddRange(TrackedEntities);
2019-12-22 19:44:35 +00:00
}
}
[Test]
2019-12-24 03:04:26 +00:00
public void EntitiesWithAndWithoutImmediateComponents()
2019-12-22 19:44:35 +00:00
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, new MockComponentC());
worldBuilder.SetComponent(entityC, new MockComponentD());
var queriedEntities = new List<Entity>();
2019-12-24 03:04:26 +00:00
worldBuilder.AddEngine(new ConditionallyAddImmediateComponentsEngine());
worldBuilder.AddEngine(new EntityQueryWithAndWithoutImmediateComponentsEngine(queriedEntities));
2019-12-22 19:44:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB });
}
[Reads(typeof(MockComponentC))]
2019-12-24 03:04:26 +00:00
[WritesImmediate(typeof(MockComponentB))]
2019-12-22 19:44:35 +00:00
[Writes(typeof(MockComponentB), 0)]
2019-12-24 03:04:26 +00:00
class ConditionallyAddImmediateComponentEngine : Engine
2019-12-22 19:44:35 +00:00
{
public override void Update(double dt)
{
foreach (var entity in ReadEntities<MockComponentC>())
2019-12-22 19:44:35 +00:00
{
SetComponent(entity, new MockComponentB());
}
}
}
2019-12-24 03:04:26 +00:00
[ReadsImmediate(typeof(MockComponentB))]
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
2019-12-24 03:04:26 +00:00
class EntityQueryWithImmediateAndNonImmediateComponents : Engine
2019-12-22 19:44:35 +00:00
{
private List<Entity> entities;
2019-12-24 03:04:26 +00:00
public EntityQueryWithImmediateAndNonImmediateComponents(List<Entity> entities)
2019-12-22 19:44:35 +00:00
{
this.entities = entities;
}
public override void Update(double dt)
{
entities.Clear();
2019-12-28 21:53:02 +00:00
entities.AddRange(TrackedEntities);
2019-12-22 19:44:35 +00:00
}
}
[Test]
2019-12-24 03:04:26 +00:00
public void EntitiesWithImmediateAndNonImmediateComponents()
2019-12-22 19:44:35 +00:00
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
var entityC = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, new MockComponent());
worldBuilder.SetComponent(entityB, new MockComponentC());
worldBuilder.SetComponent(entityC, new MockComponentD());
var queriedEntities = new List<Entity>();
2019-12-24 03:04:26 +00:00
worldBuilder.AddEngine(new ConditionallyAddImmediateComponentEngine());
worldBuilder.AddEngine(new EntityQueryWithImmediateAndNonImmediateComponents(queriedEntities));
2019-12-22 19:44:35 +00:00
var world = worldBuilder.Build();
world.Update(0.01);
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB });
}
2019-12-27 04:18:46 +00:00
[ReadsImmediate(typeof(MockComponentB))]
class ReadImmediateComponentsEngine : Engine
{
private List<MockComponentB> _components;
public ReadImmediateComponentsEngine(List<MockComponentB> components)
{
_components = components;
}
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
_components.AddRange(ReadComponents<MockComponentB>().ToArray());
2019-12-27 04:18:46 +00:00
}
}
[Test]
public void ReadImmediateComponents()
{
var worldBuilder = new WorldBuilder();
var _components = new List<MockComponentB>();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.AddEngine(new AddImmediateComponentEngine());
worldBuilder.AddEngine(new ReadImmediateComponentsEngine(_components));
var world = worldBuilder.Build();
world.Update(0.01);
_components.Should().NotBeEmpty();
}
[ReadsImmediate(typeof(MockComponentB))]
[Reads(typeof(MockComponent))]
class HasAndGetImmediateComponentEngine : Engine
{
private List<MockComponentB> _components;
public HasAndGetImmediateComponentEngine(List<MockComponentB> components)
{
_components = components;
}
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockComponent>())
2019-12-27 04:18:46 +00:00
{
if (HasComponent<MockComponentB>(entity))
{
_components.Add(GetComponent<MockComponentB>(entity));
}
}
}
}
[Test]
public void HasAndGetImmediateComponent()
{
var worldBuilder = new WorldBuilder();
var _components = new List<MockComponentB>();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.AddEngine(new AddImmediateComponentEngine());
worldBuilder.AddEngine(new HasAndGetImmediateComponentEngine(_components));
var world = worldBuilder.Build();
world.Update(0.01);
_components.Should().NotBeEmpty();
}
2019-12-27 05:25:24 +00:00
struct MockTimerComponent
2019-12-27 05:25:24 +00:00
{
2020-03-23 02:10:28 +00:00
public double Timer { get; }
2020-03-20 22:45:58 +00:00
2019-12-27 05:25:24 +00:00
public MockTimerComponent(double time)
{
Timer = time;
}
}
[Reads(typeof(MockTimerComponent))]
[Writes(typeof(MockTimerComponent))]
class ReadWhileRemovingComponentsEngine : Engine
{
public override void Update(double dt)
{
2020-03-23 02:10:28 +00:00
foreach (ref readonly var entity in ReadEntities<MockTimerComponent>())
2019-12-27 05:25:24 +00:00
{
2020-03-23 02:10:28 +00:00
ref readonly var component = ref GetComponent<MockTimerComponent>(entity);
2019-12-27 05:25:24 +00:00
2020-03-23 02:10:28 +00:00
if (component.Timer - dt <= 0)
2019-12-27 05:25:24 +00:00
{
RemoveComponent<MockTimerComponent>(entity);
}
else
{
2020-03-23 02:10:28 +00:00
SetComponent<MockTimerComponent>(entity, new MockTimerComponent(component.Timer - dt));
2019-12-27 05:25:24 +00:00
}
}
}
}
[Test]
public void ReadWhileRemovingComponents()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockTimerComponent(0.5));
var entityB = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityB, new MockTimerComponent(0.4));
worldBuilder.AddEngine(new ReadWhileRemovingComponentsEngine());
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.2));
Assert.DoesNotThrow(() => world.Update(0.25));
}
[Test]
public void DestroyedEntitiesAreRemovedFromTracking()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent());
worldBuilder.AddEngine(new DestroyWithEngine());
worldBuilder.AddEngine(new ReadEntitiesWithComponentTypeEngine());
var world = worldBuilder.Build();
world.Update(0.01);
world.Update(0.01);
readEntities.Should().BeEmpty();
}
}
2019-06-15 00:51:06 +00:00
}
}