commit
72a7f8bfbf
|
@ -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 all components of a type without destroying Entities
|
||||||
- method to remove a component of a type without destroying entity
|
- 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
|
- look at test coverage
|
||||||
- docs
|
- docs
|
||||||
|
|
|
@ -33,7 +33,6 @@ namespace Encompass
|
||||||
|
|
||||||
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
//RegisterComponentType<TComponent>();
|
|
||||||
return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>;
|
return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,11 @@ namespace Encompass
|
||||||
return Lookup<TMessage>().WithEntity(entityID);
|
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)
|
public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta)
|
||||||
{
|
{
|
||||||
foreach (var store in Stores.Values)
|
foreach (var store in Stores.Values)
|
||||||
|
|
|
@ -93,6 +93,11 @@ namespace Encompass
|
||||||
return entityToMessage.ContainsKey(entityID) ? entityToMessage[entityID] : System.Linq.Enumerable.Empty<TMessage>();
|
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()
|
public override void Clear()
|
||||||
{
|
{
|
||||||
store.Clear();
|
store.Clear();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using MoonTools.FastCollections;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
|
@ -73,7 +74,14 @@ namespace Encompass
|
||||||
return false;
|
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);
|
var result = upToDateComponentStore.Set(entityID, component, priority);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -83,6 +91,12 @@ namespace Encompass
|
||||||
return result;
|
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
|
// existing or immediate reads
|
||||||
|
|
||||||
internal IEnumerable<(TComponent, int)> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct, IComponent
|
internal IEnumerable<(TComponent, int)> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -249,5 +263,10 @@ namespace Encompass
|
||||||
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID);
|
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()
|
protected Engine()
|
||||||
{
|
{
|
||||||
ID = Guid.NewGuid();
|
ID = Guid.NewGuid();
|
||||||
|
@ -158,6 +160,24 @@ namespace Encompass
|
||||||
this.trackingManager = trackingManager;
|
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>
|
/// <summary>
|
||||||
/// Runs once per World update with the calculated delta-time.
|
/// Runs once per World update with the calculated delta-time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -169,7 +189,9 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Entity CreateEntity()
|
protected Entity CreateEntity()
|
||||||
{
|
{
|
||||||
return entityManager.CreateEntity();
|
var entity = entityManager.CreateEntity();
|
||||||
|
_newlyCreatedEntities.Add(entity.ID);
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -180,6 +202,14 @@ namespace Encompass
|
||||||
return entityManager.EntityExists(entity.ID);
|
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>
|
/// <summary>
|
||||||
/// Returns an Entity containing the specified Component type.
|
/// Returns an Entity containing the specified Component type.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Sends a Message.
|
/// Sends a Message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -490,11 +551,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
|
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!receiveTypes.Contains(typeof(TMessage)))
|
CheckMessageRead<TMessage>();
|
||||||
{
|
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return messageManager.GetMessagesByType<TMessage>();
|
return messageManager.GetMessagesByType<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,6 +563,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
|
CheckMessageRead<TMessage>();
|
||||||
return messageManager.First<TMessage>();
|
return messageManager.First<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,11 +575,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
|
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!receiveTypes.Contains(typeof(TMessage)))
|
CheckMessageRead<TMessage>();
|
||||||
{
|
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return messageManager.Any<TMessage>();
|
return messageManager.Any<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,16 +702,36 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <typeparam name="TMessage">The Message subtype.</typeparam>
|
/// <typeparam name="TMessage">The Message subtype.</typeparam>
|
||||||
/// <param name="entity">The entity that all messages in the IEnumerable refer to.</param>
|
/// <param name="entity">The entity that all messages in the IEnumerable refer to.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity
|
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity
|
||||||
{
|
{
|
||||||
|
CheckMessageRead<TMessage>();
|
||||||
return messageManager.WithEntity<TMessage>(entity.ID);
|
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)
|
internal void CheckAndUpdateTracking(int entityID)
|
||||||
{
|
{
|
||||||
if (_trackedEntities.Contains(entityID) && !entityQuery.CheckEntity(entityID, componentManager.ExistingBits))
|
if (_trackedEntities.Contains(entityID) && !entityQuery.CheckEntity(entityID, componentManager.ExistingBits))
|
||||||
|
|
|
@ -76,5 +76,17 @@ namespace Encompass
|
||||||
|
|
||||||
entitiesMarkedForDestroy.Clear();
|
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);
|
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.Update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine.ClearNewlyCreatedEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
messageManager.ClearMessages();
|
messageManager.ClearMessages();
|
||||||
|
entityManager.PruneEmptyEntities();
|
||||||
entityManager.DestroyMarkedEntities(enginesInOrder);
|
entityManager.DestroyMarkedEntities(enginesInOrder);
|
||||||
|
|
||||||
componentManager.RemoveMarkedComponents();
|
componentManager.RemoveMarkedComponents();
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Encompass
|
||||||
|
|
||||||
private readonly HashSet<Engine> senders = new HashSet<Engine>();
|
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>();
|
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
|
public void SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
RegisterComponentType<TComponent>();
|
RegisterComponentType<TComponent>();
|
||||||
componentTypesToRegister.Add(typeof(TComponent));
|
|
||||||
|
|
||||||
startingExistingComponentStore.Set(entity.ID, component);
|
startingExistingComponentStore.Set(entity.ID, component);
|
||||||
startingUpToDateComponentStore.Set(entity.ID, component);
|
startingUpToDateComponentStore.Set(entity.ID, component);
|
||||||
|
|
||||||
|
@ -104,6 +102,7 @@ namespace Encompass
|
||||||
if (!typeToIndex.ContainsKey(typeof(TComponent)))
|
if (!typeToIndex.ContainsKey(typeof(TComponent)))
|
||||||
{
|
{
|
||||||
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
||||||
|
componentTypesToPreload.Add(typeof(TComponent));
|
||||||
componentManager.RegisterComponentType<TComponent>();
|
componentManager.RegisterComponentType<TComponent>();
|
||||||
startingExistingComponentStore.RegisterComponentType<TComponent>();
|
startingExistingComponentStore.RegisterComponentType<TComponent>();
|
||||||
startingUpToDateComponentStore.RegisterComponentType<TComponent>();
|
startingUpToDateComponentStore.RegisterComponentType<TComponent>();
|
||||||
|
@ -115,11 +114,6 @@ namespace Encompass
|
||||||
messageTypes.UnionWith(types);
|
messageTypes.UnionWith(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddComponentTypeToRegister(Type componentType)
|
|
||||||
{
|
|
||||||
componentTypesToRegister.Add(componentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the specified Engine to the World.
|
/// Adds the specified Engine to the World.
|
||||||
/// </summary>
|
/// </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))
|
foreach (var receiveType in engine.receiveTypes.Union(engine.readImmediateTypes))
|
||||||
{
|
{
|
||||||
if (!typeToReaders.ContainsKey(receiveType))
|
if (!typeToReaders.ContainsKey(receiveType))
|
||||||
|
@ -196,6 +185,7 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public OrderedRenderer<TComponent> AddOrderedRenderer<TComponent>(OrderedRenderer<TComponent> renderer) where TComponent : struct, IComponent, IDrawableComponent
|
public OrderedRenderer<TComponent> AddOrderedRenderer<TComponent>(OrderedRenderer<TComponent> renderer) where TComponent : struct, IComponent, IDrawableComponent
|
||||||
{
|
{
|
||||||
|
RegisterComponentType<TComponent>();
|
||||||
renderer.AssignEntityManager(entityManager);
|
renderer.AssignEntityManager(entityManager);
|
||||||
renderer.AssignComponentManager(componentManager);
|
renderer.AssignComponentManager(componentManager);
|
||||||
renderManager.RegisterOrderedRenderer<TComponent>(renderer.InternalRender);
|
renderManager.RegisterOrderedRenderer<TComponent>(renderer.InternalRender);
|
||||||
|
@ -364,16 +354,23 @@ namespace Encompass
|
||||||
throw new EngineWriteConflictException(errorString);
|
throw new EngineWriteConflictException(errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var engineOrder = new List<Engine>();
|
// doing reflection to grab all component types, because not all writes need to be declared
|
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
foreach (var registeredComponentType in componentTypesToRegister)
|
|
||||||
{
|
{
|
||||||
var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance);
|
foreach (var componentType in assembly.GetTypes())
|
||||||
var generic = method.MakeGenericMethod(registeredComponentType);
|
{
|
||||||
generic.Invoke(this, null);
|
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())
|
foreach (var engine in engineGraph.TopologicalSort())
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<RootNamespace>Encompass</RootNamespace>
|
<RootNamespace>Encompass</RootNamespace>
|
||||||
<PackageId>EncompassECS.Framework</PackageId>
|
<PackageId>EncompassECS.Framework</PackageId>
|
||||||
<Version>0.19.0</Version>
|
<Version>0.20.0</Version>
|
||||||
<Authors>Evan Hemsley</Authors>
|
<Authors>Evan Hemsley</Authors>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<Company>Moonside Games</Company>
|
<Company>Moonside Games</Company>
|
||||||
|
|
|
@ -497,6 +497,58 @@ namespace Tests
|
||||||
entityMessageResults.Should().BeEmpty();
|
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
|
class SomeComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -1240,6 +1292,132 @@ namespace Tests
|
||||||
undilatedDeltaTime.Should().Be(0.5);
|
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
|
public class QueryTests
|
||||||
{
|
{
|
||||||
struct MockComponentB : IComponent { }
|
struct MockComponentB : IComponent { }
|
||||||
|
|
Loading…
Reference in New Issue