Goodies #2
|
@ -1,46 +0,0 @@
|
|||
version: 2.1
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: mcr.microsoft.com/dotnet/core/sdk:3.0
|
||||
environment:
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
|
||||
jobs:
|
||||
test:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- run: dotnet restore
|
||||
- run: dotnet build -c Release
|
||||
- run: dotnet test -c Release
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: ./encompass-cs/bin
|
||||
|
||||
deploy:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: dotnet nuget push ./encompass-cs/bin/Release/EncompassECS.Framework.*.nupkg -k $API_KEY -s $NUGET_SOURCE
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
test_and_deploy:
|
||||
jobs:
|
||||
- test:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- deploy:
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^\d+\.\d+\.\d+(-preview\d+)?$/
|
|
@ -0,0 +1,24 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
|
||||
workspace:
|
||||
path: /build
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: mcr.microsoft.com/dotnet/core/sdk:3.1
|
||||
commands:
|
||||
- dotnet build -c Release
|
||||
- dotnet test -c Release
|
||||
|
||||
- name: deploy
|
||||
image: mcr.microsoft.com/dotnet/core/sdk:3.1
|
||||
environment:
|
||||
API_KEY:
|
||||
from_secret: API_KEY
|
||||
commands:
|
||||
- dotnet nuget push /build/encompass-cs/bin/Release/EncompassECS.Framework.*.nupkg -s https://api.nuget.org/v3/index.json -k $API_KEY
|
||||
when:
|
||||
ref:
|
||||
- refs/tags/*.*.*
|
4
TODO
4
TODO
|
@ -3,9 +3,5 @@
|
|||
- method to remove all components of a type without destroying Entities
|
||||
- method to remove a component of a type without destroying entity
|
||||
|
||||
- auto destroy entities that no longer have components
|
||||
|
||||
- fast lookup for messages that contain entity references instead of `Where` loop?
|
||||
|
||||
- look at test coverage
|
||||
- docs
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace Encompass
|
|||
|
||||
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
//RegisterComponentType<TComponent>();
|
||||
return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ namespace Encompass
|
|||
return Lookup<TMessage>().WithEntity(entityID);
|
||||
}
|
||||
|
||||
public bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
return Lookup<TMessage>().SomeWithEntity(entityID);
|
||||
}
|
||||
|
||||
public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta)
|
||||
{
|
||||
foreach (var store in Stores.Values)
|
||||
|
|
|
@ -93,6 +93,11 @@ namespace Encompass
|
|||
return entityToMessage.ContainsKey(entityID) ? entityToMessage[entityID] : System.Linq.Enumerable.Empty<TMessage>();
|
||||
}
|
||||
|
||||
public bool SomeWithEntity(int entityID)
|
||||
{
|
||||
return entityToMessage.ContainsKey(entityID) && entityToMessage[entityID].Count > 0;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
store.Clear();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MoonTools.FastCollections;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
|
@ -73,7 +74,14 @@ namespace Encompass
|
|||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateComponent<TComponent>(int entityID, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
internal void AddImmediateComponent<TComponent>(int entityID, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
immediateComponentStore.Set(entityID, component);
|
||||
replayStore.Set(entityID, component);
|
||||
upToDateComponentStore.Set(entityID, component);
|
||||
}
|
||||
|
||||
internal bool UpdateComponent<TComponent>(int entityID, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
{
|
||||
var result = upToDateComponentStore.Set(entityID, component, priority);
|
||||
if (result)
|
||||
|
@ -83,6 +91,12 @@ namespace Encompass
|
|||
return result;
|
||||
}
|
||||
|
||||
internal void AddComponent<TComponent>(int entityID, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
upToDateComponentStore.Set(entityID, component);
|
||||
replayStore.Set(entityID, component);
|
||||
}
|
||||
|
||||
// existing or immediate reads
|
||||
|
||||
internal IEnumerable<(TComponent, int)> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
|
@ -249,5 +263,10 @@ namespace Encompass
|
|||
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpToDateEntityIsEmpty(int entityID)
|
||||
{
|
||||
return upToDateComponentStore.EntityBitArray(entityID).AllFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
private HashSet<int> _newlyCreatedEntities = new HashSet<int>();
|
||||
|
||||
protected Engine()
|
||||
{
|
||||
ID = Guid.NewGuid();
|
||||
|
@ -158,6 +160,24 @@ namespace Encompass
|
|||
this.trackingManager = trackingManager;
|
||||
}
|
||||
|
||||
internal void CheckMessageRead<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
if (!receiveTypes.Contains(typeof(TMessage)))
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
||||
}
|
||||
}
|
||||
|
||||
private bool EntityCreatedThisFrame(int entityID)
|
||||
{
|
||||
return _newlyCreatedEntities.Contains(entityID);
|
||||
}
|
||||
|
||||
internal void ClearNewlyCreatedEntities()
|
||||
{
|
||||
_newlyCreatedEntities.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs once per World update with the calculated delta-time.
|
||||
/// </summary>
|
||||
|
@ -169,7 +189,9 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected Entity CreateEntity()
|
||||
{
|
||||
return entityManager.CreateEntity();
|
||||
var entity = entityManager.CreateEntity();
|
||||
_newlyCreatedEntities.Add(entity.ID);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -180,6 +202,14 @@ namespace Encompass
|
|||
return entityManager.EntityExists(entity.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if an Entity with the specified ID exists.
|
||||
/// </summary>
|
||||
protected bool EntityExists(int entityID)
|
||||
{
|
||||
return entityManager.EntityExists(entityID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an Entity containing the specified Component type.
|
||||
/// </summary>
|
||||
|
@ -448,6 +478,37 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An alternative to SetComponent that can be used for new Entities and does not require setting write priority.
|
||||
/// </summary>
|
||||
/// <exception cref="Encompass.Exceptions.IllegalWriteException">
|
||||
/// Thrown when the Engine does not declare that it Writes the given Component Type.
|
||||
/// </exception>
|
||||
protected void AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
if (!EntityCreatedThisFrame(entity.ID))
|
||||
{
|
||||
throw new IllegalWriteException("AddComponent used on Entity that was not created in this context. Use SetComponent instead.");
|
||||
}
|
||||
|
||||
if (writeImmediateTypes.Contains(typeof(TComponent)))
|
||||
{
|
||||
componentManager.AddImmediateComponent(entity.ID, component);
|
||||
trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent));
|
||||
}
|
||||
else
|
||||
{
|
||||
componentManager.AddComponent(entity.ID, component);
|
||||
}
|
||||
|
||||
trackingManager.RegisterAddition(entity.ID, typeof(TComponent));
|
||||
|
||||
if (component is IDrawableComponent drawableComponent)
|
||||
{
|
||||
componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a Message.
|
||||
/// </summary>
|
||||
|
@ -490,11 +551,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
if (!receiveTypes.Contains(typeof(TMessage)))
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
||||
}
|
||||
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.GetMessagesByType<TMessage>();
|
||||
}
|
||||
|
||||
|
@ -506,6 +563,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.First<TMessage>();
|
||||
}
|
||||
|
||||
|
@ -517,11 +575,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
if (!receiveTypes.Contains(typeof(TMessage)))
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||
}
|
||||
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.Any<TMessage>();
|
||||
}
|
||||
|
||||
|
@ -648,16 +702,36 @@ namespace Encompass
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Efficiently reads Messages of a given type that all reference the same Entity.
|
||||
/// Efficiently reads Messages of a given type that all reference the given Entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessage">The Message subtype.</typeparam>
|
||||
/// <param name="entity">The entity that all messages in the IEnumerable refer to.</param>
|
||||
/// <returns></returns>
|
||||
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.WithEntity<TMessage>(entity.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Efficiently reads a single Message of a given type that references a given Entity.
|
||||
/// It is recommended to use this method in conjunction with SomeMessageWithEntity to prevent errors.
|
||||
/// </summary>
|
||||
protected TMessage ReadMessageWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.WithEntitySingular<TMessage>(entity.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Efficiently checks if any Message of a given type referencing a given Entity exists.
|
||||
/// </summary>
|
||||
protected bool SomeMessageWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
CheckMessageRead<TMessage>();
|
||||
return messageManager.SomeWithEntity<TMessage>(entity.ID);
|
||||
}
|
||||
|
||||
internal void CheckAndUpdateTracking(int entityID)
|
||||
{
|
||||
if (_trackedEntities.Contains(entityID) && !entityQuery.CheckEntity(entityID, componentManager.ExistingBits))
|
||||
|
|
|
@ -76,5 +76,17 @@ namespace Encompass
|
|||
|
||||
entitiesMarkedForDestroy.Clear();
|
||||
}
|
||||
|
||||
// NOTE: this is very suboptimal
|
||||
public void PruneEmptyEntities()
|
||||
{
|
||||
foreach (var id in EntityIDs)
|
||||
{
|
||||
if (componentManager.UpToDateEntityIsEmpty(id))
|
||||
{
|
||||
MarkForDestroy(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,5 +56,17 @@ namespace Encompass
|
|||
{
|
||||
return messageStore.WithEntity<TMessage>(entityID);
|
||||
}
|
||||
|
||||
internal TMessage WithEntitySingular<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
var enumerator = messageStore.WithEntity<TMessage>(entityID).GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
return enumerator.Current;
|
||||
}
|
||||
|
||||
internal bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
|
||||
{
|
||||
return messageStore.SomeWithEntity<TMessage>(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,9 +54,12 @@ namespace Encompass
|
|||
{
|
||||
engine.Update(dt);
|
||||
}
|
||||
|
||||
engine.ClearNewlyCreatedEntities();
|
||||
}
|
||||
|
||||
messageManager.ClearMessages();
|
||||
entityManager.PruneEmptyEntities();
|
||||
entityManager.DestroyMarkedEntities(enginesInOrder);
|
||||
|
||||
componentManager.RemoveMarkedComponents();
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Encompass
|
|||
|
||||
private readonly HashSet<Engine> senders = new HashSet<Engine>();
|
||||
|
||||
private readonly HashSet<Type> componentTypesToRegister = new HashSet<Type>();
|
||||
private readonly HashSet<Type> componentTypesToPreload = new HashSet<Type>();
|
||||
|
||||
private readonly HashSet<Type> messageTypes = new HashSet<Type>();
|
||||
|
||||
|
@ -87,8 +87,6 @@ namespace Encompass
|
|||
public void SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
RegisterComponentType<TComponent>();
|
||||
componentTypesToRegister.Add(typeof(TComponent));
|
||||
|
||||
startingExistingComponentStore.Set(entity.ID, component);
|
||||
startingUpToDateComponentStore.Set(entity.ID, component);
|
||||
|
||||
|
@ -104,6 +102,7 @@ namespace Encompass
|
|||
if (!typeToIndex.ContainsKey(typeof(TComponent)))
|
||||
{
|
||||
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
||||
componentTypesToPreload.Add(typeof(TComponent));
|
||||
componentManager.RegisterComponentType<TComponent>();
|
||||
startingExistingComponentStore.RegisterComponentType<TComponent>();
|
||||
startingUpToDateComponentStore.RegisterComponentType<TComponent>();
|
||||
|
@ -115,11 +114,6 @@ namespace Encompass
|
|||
messageTypes.UnionWith(types);
|
||||
}
|
||||
|
||||
internal void AddComponentTypeToRegister(Type componentType)
|
||||
{
|
||||
componentTypesToRegister.Add(componentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified Engine to the World.
|
||||
/// </summary>
|
||||
|
@ -164,11 +158,6 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readImmediateTypes))
|
||||
{
|
||||
AddComponentTypeToRegister(componentType);
|
||||
}
|
||||
|
||||
foreach (var receiveType in engine.receiveTypes.Union(engine.readImmediateTypes))
|
||||
{
|
||||
if (!typeToReaders.ContainsKey(receiveType))
|
||||
|
@ -196,6 +185,7 @@ namespace Encompass
|
|||
/// </summary>
|
||||
public OrderedRenderer<TComponent> AddOrderedRenderer<TComponent>(OrderedRenderer<TComponent> renderer) where TComponent : struct, IComponent, IDrawableComponent
|
||||
{
|
||||
RegisterComponentType<TComponent>();
|
||||
renderer.AssignEntityManager(entityManager);
|
||||
renderer.AssignComponentManager(componentManager);
|
||||
renderManager.RegisterOrderedRenderer<TComponent>(renderer.InternalRender);
|
||||
|
@ -364,16 +354,23 @@ namespace Encompass
|
|||
throw new EngineWriteConflictException(errorString);
|
||||
}
|
||||
|
||||
var engineOrder = new List<Engine>();
|
||||
|
||||
foreach (var registeredComponentType in componentTypesToRegister)
|
||||
// doing reflection to grab all component types, because not all writes need to be declared
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var generic = method.MakeGenericMethod(registeredComponentType);
|
||||
generic.Invoke(this, null);
|
||||
foreach (var componentType in assembly.GetTypes())
|
||||
{
|
||||
if (typeof(IComponent).IsAssignableFrom(componentType) && componentType.IsValueType && !componentType.IsEnum && !componentType.IsPrimitive)
|
||||
{
|
||||
var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var generic = method.MakeGenericMethod(componentType);
|
||||
generic.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PreloadJIT(componentTypesToRegister, messageTypes);
|
||||
PreloadJIT(componentTypesToPreload, messageTypes);
|
||||
|
||||
var engineOrder = new List<Engine>();
|
||||
|
||||
foreach (var engine in engineGraph.TopologicalSort())
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Encompass</RootNamespace>
|
||||
<PackageId>EncompassECS.Framework</PackageId>
|
||||
<Version>0.19.0</Version>
|
||||
<Version>0.20.0</Version>
|
||||
<Authors>Evan Hemsley</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Company>Moonside Games</Company>
|
||||
|
|
|
@ -497,6 +497,58 @@ namespace Tests
|
|||
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)
|
||||
|
@ -1240,6 +1292,132 @@ namespace Tests
|
|||
undilatedDeltaTime.Should().Be(0.5);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var (component, entity) = ReadComponentIncludingEntity<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));
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
var (component, entity) = ReadComponentIncludingEntity<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));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public class QueryTests
|
||||
{
|
||||
struct MockComponentB : IComponent { }
|
||||
|
|
Loading…
Reference in New Issue