2019-06-15 07:39:08 +00:00
using System ;
using System.Reflection ;
2019-06-15 00:51:06 +00:00
using System.Collections.Generic ;
2019-06-17 01:11:35 +00:00
using System.Linq ;
2019-06-24 19:14:37 +00:00
using Encompass.Exceptions ;
2019-06-15 00:51:06 +00:00
2019-06-16 01:05:56 +00:00
namespace Encompass
{
2019-10-24 19:48:36 +00:00
/// <summary>
/// Engines are the Encompass notion of an ECS System.
/// They are responsible for reading the World state, reading messages, emitting messages, and creating or mutating Entities and Components.
/// Engines run once per World Update.
/// </summary>
2019-10-24 20:13:43 +00:00
public abstract class Engine : IEquatable < Engine >
2019-06-16 01:05:56 +00:00
{
2019-11-21 03:01:29 +00:00
internal Guid ID ;
2019-10-24 20:13:43 +00:00
2019-07-19 01:20:38 +00:00
internal readonly HashSet < Type > sendTypes = new HashSet < Type > ( ) ;
2019-07-19 19:47:17 +00:00
internal readonly HashSet < Type > receiveTypes = new HashSet < Type > ( ) ;
2019-08-21 02:25:59 +00:00
internal readonly Dictionary < Type , int > writePriorities = new Dictionary < Type , int > ( ) ;
2019-06-15 07:39:08 +00:00
2019-11-21 21:53:33 +00:00
/// <summary>
2019-12-05 20:10:33 +00:00
/// If false, the Engine will ignore time dilation.
2019-11-21 21:53:33 +00:00
/// </summary>
internal bool usesTimeDilation = true ;
public bool TimeDilationActive { get = > usesTimeDilation & & timeManager . TimeDilationActive ; }
/// <summary>
/// Used when activating time dilation. Lower priority overrides higher priority.
/// </summary>
2019-06-15 00:51:06 +00:00
private EntityManager entityManager ;
2019-06-16 01:55:35 +00:00
private MessageManager messageManager ;
2019-08-20 00:30:31 +00:00
private ComponentManager componentManager ;
2019-08-01 23:24:57 +00:00
private ComponentMessageManager componentMessageManager ;
2019-11-21 21:53:33 +00:00
private TimeManager timeManager ;
2019-06-15 00:51:06 +00:00
2019-06-20 17:46:15 +00:00
protected Engine ( )
2019-06-16 01:05:56 +00:00
{
2019-10-24 20:13:43 +00:00
ID = Guid . NewGuid ( ) ;
2019-07-19 19:47:17 +00:00
var sendsAttribute = GetType ( ) . GetCustomAttribute < Sends > ( false ) ;
if ( sendsAttribute ! = null )
2019-06-16 01:55:35 +00:00
{
2019-07-19 19:47:17 +00:00
sendTypes = sendsAttribute . sendTypes ;
}
2019-08-21 02:25:59 +00:00
var activatesAttribute = GetType ( ) . GetCustomAttribute < WritesPending > ( false ) ;
2019-07-19 19:47:17 +00:00
if ( activatesAttribute ! = null )
{
2019-08-21 02:25:59 +00:00
sendTypes . UnionWith ( activatesAttribute . writePendingTypes ) ;
2019-07-19 19:47:17 +00:00
}
2019-08-22 02:21:55 +00:00
var writesAttributes = GetType ( ) . GetCustomAttributes < Writes > ( false ) ;
foreach ( var writesAttribute in writesAttributes )
2019-07-20 00:50:13 +00:00
{
2019-08-21 02:25:59 +00:00
sendTypes . UnionWith ( writesAttribute . writeTypes ) ;
2019-08-22 02:21:55 +00:00
writePriorities = new Dictionary < Type , int > [ 2 ] { writePriorities , writesAttribute . priorities } . SelectMany ( dict = > dict ) . ToDictionary ( pair = > pair . Key , pair = > pair . Value ) ;
2019-07-20 00:50:13 +00:00
}
2019-07-19 19:47:17 +00:00
var receivesAttribute = GetType ( ) . GetCustomAttribute < Receives > ( false ) ;
if ( receivesAttribute ! = null )
{
receiveTypes = receivesAttribute . receiveTypes ;
2019-06-16 01:55:35 +00:00
}
2019-06-20 03:37:46 +00:00
var readsAttribute = GetType ( ) . GetCustomAttribute < Reads > ( false ) ;
2019-06-16 01:55:35 +00:00
if ( readsAttribute ! = null )
{
2019-07-19 19:47:17 +00:00
receiveTypes . UnionWith ( readsAttribute . readTypes ) ;
2019-06-16 01:55:35 +00:00
}
2019-07-23 17:17:53 +00:00
var readsPendingAttribute = GetType ( ) . GetCustomAttribute < ReadsPending > ( false ) ;
if ( readsPendingAttribute ! = null )
{
receiveTypes . UnionWith ( readsPendingAttribute . readPendingTypes ) ;
}
2019-06-15 07:39:08 +00:00
}
2019-10-24 20:13:43 +00:00
public override bool Equals ( object obj )
{
if ( obj is Engine )
{
return this . Equals ( ( Engine ) obj ) ;
}
return false ;
}
public bool Equals ( Engine other )
{
return other . ID = = ID ;
}
public override int GetHashCode ( )
{
return ID . GetHashCode ( ) ;
}
2019-06-16 01:05:56 +00:00
internal void AssignEntityManager ( EntityManager entityManager )
{
2019-06-15 00:51:06 +00:00
this . entityManager = entityManager ;
}
2019-06-16 01:05:56 +00:00
internal void AssignComponentManager ( ComponentManager componentManager )
{
2019-06-15 00:51:06 +00:00
this . componentManager = componentManager ;
}
2019-06-16 01:55:35 +00:00
internal void AssignMessageManager ( MessageManager messageManager )
{
this . messageManager = messageManager ;
}
2019-08-01 23:24:57 +00:00
internal void AssignComponentMessageManager ( ComponentMessageManager componentMessageManager )
{
this . componentMessageManager = componentMessageManager ;
}
2019-11-21 21:53:33 +00:00
internal void AssignTimeManager ( TimeManager timeManager )
{
this . timeManager = timeManager ;
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Runs once per World update with the calculated delta-time.
/// </summary>
/// <param name="dt">The time in seconds that has elapsed since the previous frame.</param>
2019-06-24 19:14:37 +00:00
public abstract void Update ( double dt ) ;
2019-06-15 00:51:06 +00:00
2019-10-24 19:48:36 +00:00
/// <summary>
/// Creates and returns a new empty Entity.
/// </summary>
2019-06-16 01:05:56 +00:00
protected Entity CreateEntity ( )
{
2019-06-20 03:37:46 +00:00
return entityManager . CreateEntity ( ) ;
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Returns true if an Entity with the specified ID exists.
/// </summary>
2019-11-22 21:14:36 +00:00
protected bool EntityExists ( Entity entity )
2019-07-13 00:37:31 +00:00
{
2019-11-22 21:14:36 +00:00
return entityManager . EntityExists ( entity . ID ) ;
2019-07-13 00:37:31 +00:00
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Returns the Entity with the specified ID.
/// </summary>
/// <exception cref="Encompass.Exceptions.EntityNotFoundException">
/// Thrown when an Entity with the given ID does not exist.
/// </exception>
2019-11-21 03:01:29 +00:00
internal Entity GetEntity ( Guid entityID )
2019-06-20 03:37:46 +00:00
{
return entityManager . GetEntity ( entityID ) ;
}
2019-10-24 19:48:36 +00:00
/// <summary>
2019-11-17 18:48:39 +00:00
/// Returns an Entity containing the specified Component type.
2019-10-24 19:48:36 +00:00
/// </summary>
protected Entity ReadEntity < TComponent > ( ) where TComponent : struct , IComponent
{
2019-12-05 20:10:33 +00:00
return ReadComponentHelper < TComponent > ( ) . Item1 ;
2019-10-24 19:48:36 +00:00
}
/// <summary>
2019-11-17 18:48:39 +00:00
/// Returns all Entities containing the specified Component type.
2019-10-24 19:48:36 +00:00
/// </summary>
protected IEnumerable < Entity > ReadEntities < TComponent > ( ) where TComponent : struct , IComponent
{
2019-12-05 20:10:33 +00:00
return ReadComponentsHelper < TComponent > ( ) . Select ( pair = > pair . Item1 ) ;
2019-06-22 00:44:07 +00:00
}
2019-08-20 01:11:15 +00:00
// these next two are for the ComponentMessageEmitter only
2019-08-20 02:05:18 +00:00
2019-12-05 20:10:33 +00:00
internal IEnumerable < TComponent > ReadComponentsFromWorld < TComponent > ( ) where TComponent : struct , IComponent
2019-06-16 01:05:56 +00:00
{
2019-08-01 23:44:29 +00:00
return componentManager . GetComponentsByType < TComponent > ( ) ;
2019-06-15 00:51:06 +00:00
}
2019-06-15 07:39:08 +00:00
2019-12-05 20:10:33 +00:00
private IEnumerable < ( Entity , TComponent ) > ReadComponentsHelper < TComponent > ( ) where TComponent : struct , IComponent
2019-07-20 21:10:06 +00:00
{
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( existingRead & & pendingRead )
{
2019-08-01 23:24:57 +00:00
return componentMessageManager . ReadExistingAndPendingComponentsByType < TComponent > ( ) ;
2019-07-20 21:10:06 +00:00
}
2019-07-23 17:17:53 +00:00
else if ( existingRead )
{
2019-08-01 23:24:57 +00:00
return componentMessageManager . ReadExistingComponentsByType < TComponent > ( ) ;
2019-07-23 17:17:53 +00:00
}
else if ( pendingRead )
{
2019-08-01 23:24:57 +00:00
return componentMessageManager . ReadPendingComponentsByType < TComponent > ( ) ;
2019-07-23 17:17:53 +00:00
}
2019-07-20 21:10:06 +00:00
else
2019-07-18 21:02:57 +00:00
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
2019-07-20 21:10:06 +00:00
}
2019-07-18 21:02:57 +00:00
2019-10-24 19:48:36 +00:00
/// <summary>
2019-11-21 03:01:29 +00:00
/// Returns all of the Components with the specified Component Type.
2019-11-14 04:08:11 +00:00
/// </summary>
2019-11-21 03:01:29 +00:00
protected IEnumerable < TComponent > ReadComponents < TComponent > ( ) where TComponent : struct , IComponent
2019-11-14 04:08:11 +00:00
{
2019-11-21 03:01:29 +00:00
return ReadComponentsHelper < TComponent > ( ) . Select ( tuple = > tuple . Item2 ) ;
2019-11-14 04:08:11 +00:00
}
/// <summary>
2019-11-21 03:01:29 +00:00
/// Returns all of the components of the specified type including an Entity reference for each Component.
2019-10-24 19:48:36 +00:00
/// </summary>
2019-11-21 03:01:29 +00:00
protected IEnumerable < ( TComponent , Entity ) > ReadComponentsIncludingEntity < TComponent > ( ) where TComponent : struct , IComponent
{
2019-12-05 20:10:33 +00:00
return ReadComponentsHelper < TComponent > ( ) . Select ( ( tuple ) = > ( tuple . Item2 , tuple . Item1 ) ) ;
2019-11-21 03:01:29 +00:00
}
2019-12-05 22:59:55 +00:00
internal IEnumerable < ( TComponent , Entity ) > InternalRead < TComponent > ( ) where TComponent : struct , IComponent
{
return componentManager . GetComponentsIncludingEntity < TComponent > ( ) ;
}
2019-12-05 20:10:33 +00:00
private ( Entity , TComponent ) ReadComponentHelper < TComponent > ( ) where TComponent : struct , IComponent
2019-07-20 21:10:06 +00:00
{
2019-08-01 23:24:57 +00:00
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( existingRead & & pendingRead )
{
return componentMessageManager . ReadFirstExistingOrPendingComponentByType < TComponent > ( ) ;
}
else if ( existingRead )
{
return componentMessageManager . ReadFirstExistingComponentByType < TComponent > ( ) ;
}
else if ( pendingRead )
{
return componentMessageManager . ReadFirstPendingComponentByType < TComponent > ( ) ;
}
else
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
2019-07-19 19:47:17 +00:00
}
2019-11-21 03:01:29 +00:00
/// <summary>
/// Returns a Component with the specified Component Type. If multiples exist, an arbitrary Component is returned.
/// </summary>
protected TComponent ReadComponent < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadComponentHelper < TComponent > ( ) . Item2 ;
}
2019-11-14 04:08:11 +00:00
/// <summary>
/// Returns a component of the specified type including its Entity reference. If multiples exist, an arbitrary Component is returned.
/// </summary>
2019-11-21 03:01:29 +00:00
protected ( TComponent , Entity ) ReadComponentIncludingEntity < TComponent > ( ) where TComponent : struct , IComponent
2019-11-14 04:08:11 +00:00
{
2019-12-05 20:10:33 +00:00
var ( entity , component ) = ReadComponentHelper < TComponent > ( ) ;
return ( component , entity ) ;
2019-11-14 04:08:11 +00:00
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Returns true if any Component with the specified Component Type exists.
/// </summary>
2019-07-20 21:10:06 +00:00
protected bool SomeComponent < TComponent > ( ) where TComponent : struct , IComponent
2019-07-19 19:47:17 +00:00
{
2019-08-01 23:24:57 +00:00
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( existingRead & & pendingRead )
{
return componentMessageManager . SomeExistingOrPendingComponent < TComponent > ( ) ;
}
else if ( existingRead )
{
return componentMessageManager . SomeExistingComponent < TComponent > ( ) ;
}
else if ( pendingRead )
{
return componentMessageManager . SomePendingComponent < TComponent > ( ) ;
}
else
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
2019-07-19 19:47:17 +00:00
}
2019-12-05 20:10:33 +00:00
private TComponent GetComponentHelper < TComponent > ( Entity entity ) where TComponent : struct , IComponent
2019-07-17 18:24:21 +00:00
{
2019-08-01 23:24:57 +00:00
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( existingRead & & pendingRead )
{
2019-08-11 01:17:52 +00:00
if ( componentMessageManager . HasPendingComponent < TComponent > ( entity ) )
{
return componentMessageManager . ReadPendingComponentByEntityAndType < TComponent > ( entity ) ;
}
else if ( componentMessageManager . HasExistingComponent < TComponent > ( entity ) )
{
return componentMessageManager . ReadExistingComponentByEntityAndType < TComponent > ( entity ) ;
}
else
{
throw new NoComponentOfTypeOnEntityException ( "No Component of type {0} exists on Entity {1}" , typeof ( TComponent ) . Name , entity . ID ) ;
}
2019-08-01 23:24:57 +00:00
}
else if ( existingRead )
{
2019-08-11 00:34:00 +00:00
return componentMessageManager . ReadExistingComponentByEntityAndType < TComponent > ( entity ) ;
2019-08-01 23:24:57 +00:00
}
else if ( pendingRead )
{
2019-08-11 00:34:00 +00:00
return componentMessageManager . ReadPendingComponentByEntityAndType < TComponent > ( entity ) ;
2019-08-01 23:24:57 +00:00
}
else
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
2019-07-17 18:24:21 +00:00
}
2019-11-13 21:24:20 +00:00
/// <summary>
/// Returns a Component with the specified Type that exists on the Entity.
/// </summary>
/// <exception cref="Encompass.Exceptions.NoComponentOfTypeOnEntityException">
/// Thrown when the Entity does not have a Component of the specified Type
/// </exception>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it reads the given Component Type.
/// </exception>
2019-11-21 03:01:29 +00:00
protected TComponent GetComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-12-05 20:10:33 +00:00
return GetComponentHelper < TComponent > ( entity ) ;
2019-11-21 03:01:29 +00:00
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Returns true if the Entity has a Component of the given Type.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that is Reads the given Component Type.
/// </exception>
2019-07-17 18:24:21 +00:00
protected bool HasComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-08-01 23:24:57 +00:00
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( pendingRead & & existingRead )
{
return componentMessageManager . HasExistingOrPendingComponent < TComponent > ( entity ) ;
}
else if ( existingRead )
{
return componentMessageManager . HasExistingComponent < TComponent > ( entity ) ;
}
else if ( pendingRead )
{
return componentMessageManager . HasPendingComponent < TComponent > ( entity ) ;
}
else
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
2019-07-17 18:24:21 +00:00
}
2019-11-13 21:15:43 +00:00
/// <summary>
/// Returns true if the Entity has a Component of the given Type.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that is Reads the given Component Type.
/// </exception>
protected bool HasComponent ( Entity entity , Type type )
{
var pending = typeof ( PendingComponentMessage < > ) . MakeGenericType ( type ) ;
var existing = typeof ( ComponentMessage < > ) . MakeGenericType ( type ) ;
var pendingRead = receiveTypes . Contains ( pending ) ;
var existingRead = receiveTypes . Contains ( existing ) ;
if ( pendingRead & & existingRead )
{
return componentMessageManager . HasExistingOrPendingComponent ( entity , type ) ;
}
else if ( existingRead )
{
return componentMessageManager . HasExistingComponent ( entity , type ) ;
}
else if ( pendingRead )
{
return componentMessageManager . HasPendingComponent ( entity , type ) ;
}
else
{
throw new IllegalReadException ( "Engine {0} tried to read undeclared Component {1}" , GetType ( ) . Name , type . Name ) ;
}
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Sets Component data for the specified Component Type on the specified Entity. If Component data for this Type already existed on the Entity, the component data is overwritten.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalWriteException">
/// Thrown when the Engine does not declare that it Writes the given Component Type.
/// </exception>
2019-11-21 03:01:29 +00:00
protected void SetComponent < TComponent > ( Entity entity , TComponent component ) where TComponent : struct , IComponent
2019-06-16 01:05:56 +00:00
{
2019-08-21 02:25:59 +00:00
var priority = writePriorities . ContainsKey ( typeof ( TComponent ) ) ? writePriorities [ typeof ( TComponent ) ] : 0 ;
if ( ! sendTypes . Contains ( typeof ( ComponentWriteMessage < TComponent > ) ) )
2019-07-20 00:50:13 +00:00
{
2019-08-21 02:25:59 +00:00
throw new IllegalWriteException ( "Engine {0} tried to update undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
2019-07-20 00:50:13 +00:00
}
2019-08-21 02:25:59 +00:00
if ( sendTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) )
{
PendingComponentMessage < TComponent > newComponentMessage ;
newComponentMessage . entity = entity ;
newComponentMessage . component = component ;
newComponentMessage . priority = priority ;
SendPendingComponentMessage ( newComponentMessage ) ;
}
2019-12-05 23:14:28 +00:00
else
{
componentMessageManager . UpdateComponent < TComponent > ( entity , component , priority ) ;
}
2019-08-21 02:25:59 +00:00
2019-11-21 03:16:44 +00:00
if ( component is IDrawableComponent drawableComponent )
2019-08-21 02:25:59 +00:00
{
2019-12-05 22:59:55 +00:00
componentManager . RegisterDrawableComponent < TComponent > ( entity , component , drawableComponent . Layer ) ;
2019-08-21 02:25:59 +00:00
}
2019-06-15 07:39:08 +00:00
}
2019-06-16 01:55:35 +00:00
2019-10-24 19:48:36 +00:00
/// <summary>
/// Sends a Message.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalSendException">
/// Thrown when the Engine does not declare that it Sends the Message Type.
/// </exception>
2019-07-19 03:31:31 +00:00
protected void SendMessage < TMessage > ( TMessage message ) where TMessage : struct , IMessage
2019-06-16 01:55:35 +00:00
{
2019-07-19 01:20:38 +00:00
if ( ! sendTypes . Contains ( typeof ( TMessage ) ) )
2019-06-16 01:55:35 +00:00
{
2019-07-20 00:50:13 +00:00
throw new IllegalSendException ( "Engine {0} tried to send undeclared Message {1}" , GetType ( ) . Name , typeof ( TMessage ) . Name ) ;
2019-06-16 01:55:35 +00:00
}
2019-07-16 18:17:07 +00:00
messageManager . AddMessage ( message ) ;
2019-06-16 01:55:35 +00:00
}
2019-10-24 19:48:36 +00:00
/// <summary>
2019-11-21 22:22:10 +00:00
/// Sends a message after the specified number of seconds, respecting time dilation.
2019-10-24 19:48:36 +00:00
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
2019-11-21 22:22:10 +00:00
protected void SendMessage < TMessage > ( TMessage message , double time ) where TMessage : struct , IMessage
2019-08-20 02:05:18 +00:00
{
messageManager . AddMessageDelayed ( message , time ) ;
}
2019-11-21 22:22:10 +00:00
/// <summary>
/// Sends a message after the specified number of seconds, ignoring time dilation.
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessageIgnoringTimeDilation < TMessage > ( TMessage message , double time ) where TMessage : struct , IMessage
{
messageManager . AddMessageDelayedIgnoringTimeDilation ( message , time ) ;
}
2019-07-29 05:25:34 +00:00
// unparameterized version to enable dynamic dispatch
protected void SendMessage ( IMessage message )
{
var type = message . GetType ( ) ;
if ( ! sendTypes . Contains ( type ) | | ! type . IsValueType )
{
throw new IllegalSendException ( "Engine {0} tried to send undeclared Message {1}" , GetType ( ) . Name , type . Name ) ;
}
messageManager . AddMessage ( message ) ;
}
2019-08-01 23:24:57 +00:00
internal void SendExistingComponentMessage < TComponent > ( ComponentMessage < TComponent > message ) where TComponent : struct , IComponent
{
componentMessageManager . AddExistingComponentMessage ( message ) ;
}
internal void SendPendingComponentMessage < TComponent > ( PendingComponentMessage < TComponent > message ) where TComponent : struct , IComponent
{
componentMessageManager . AddPendingComponentMessage ( message ) ;
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Reads all messages of the specified Type.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
2019-06-16 01:55:35 +00:00
protected IEnumerable < TMessage > ReadMessages < TMessage > ( ) where TMessage : struct , IMessage
{
2019-07-19 19:47:17 +00:00
if ( ! receiveTypes . Contains ( typeof ( TMessage ) ) )
2019-06-16 01:55:35 +00:00
{
2019-07-16 18:17:07 +00:00
throw new IllegalReadException ( "Engine {0} tried to read undeclared Message {1}" , this . GetType ( ) . Name , typeof ( TMessage ) . Name ) ;
2019-06-16 01:55:35 +00:00
}
2019-07-16 18:17:07 +00:00
return messageManager . GetMessagesByType < TMessage > ( ) ;
2019-06-16 01:55:35 +00:00
}
2019-06-17 01:11:35 +00:00
2019-10-24 19:48:36 +00:00
/// <summary>
/// Reads an arbitrary message of the specified Type.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
2019-07-18 21:02:57 +00:00
protected TMessage ReadMessage < TMessage > ( ) where TMessage : struct , IMessage
{
2019-08-20 22:44:01 +00:00
return ReadMessages < TMessage > ( ) . First ( ) ;
2019-07-18 21:02:57 +00:00
}
2019-10-24 19:48:36 +00:00
/// <summary>
/// Returns true if a Message of the specified Type has been sent this frame.
/// </summary>
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
2019-07-17 18:46:54 +00:00
protected bool SomeMessage < TMessage > ( ) where TMessage : struct , IMessage
2019-06-17 01:11:35 +00:00
{
2019-07-19 19:47:17 +00:00
if ( ! receiveTypes . Contains ( typeof ( TMessage ) ) )
2019-06-17 01:11:35 +00:00
{
2019-07-18 21:02:57 +00:00
throw new IllegalReadException ( "Engine {0} tried to read undeclared Message {1}" , GetType ( ) . Name , typeof ( TMessage ) . Name ) ;
2019-06-17 01:11:35 +00:00
}
2019-07-16 18:17:07 +00:00
2019-07-19 00:50:38 +00:00
return ReadMessages < TMessage > ( ) . Any ( ) ;
2019-06-17 01:11:35 +00:00
}
2019-06-20 03:37:46 +00:00
2019-10-24 19:48:36 +00:00
/// <summary>
/// Destroys the specified Entity. This also removes all of the Components associated with the Entity.
/// Entity destruction takes place after all the Engines have been processed by World Update.
/// </summary>
protected void Destroy ( Entity entity )
{
2019-12-05 22:59:55 +00:00
entityManager . MarkForDestroy ( entity ) ;
2019-10-24 19:48:36 +00:00
}
/// <summary>
/// Destroys an arbitrary Entity containing a Component of the specified Type.
/// Entity destruction takes place after all the Engines have been processed by World Update.
/// </summary>
protected void DestroyWith < TComponent > ( ) where TComponent : struct , IComponent
{
Destroy ( ReadEntity < TComponent > ( ) ) ;
}
/// <summary>
/// Destroys all Entities containing a Component of the specified Type.
/// Entity destruction takes place after all the Engines have been processed by World Update.
/// </summary>
protected void DestroyAllWith < TComponent > ( ) where TComponent : struct , IComponent
{
foreach ( var entity in ReadEntities < TComponent > ( ) )
{
Destroy ( entity ) ;
}
}
2019-11-17 18:48:39 +00:00
/// <summary>
/// Removes a Component with the specified type from the given Entity.
/// Note that the Engine must Read the Component type that is being removed.
2019-11-21 03:01:29 +00:00
/// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity.
2019-11-17 18:48:39 +00:00
/// </summary>
2019-11-21 03:01:29 +00:00
protected bool RemoveComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
2019-11-17 18:48:39 +00:00
{
2019-11-21 03:01:29 +00:00
if ( ! HasComponent < TComponent > ( entity ) ) { return false ; }
2019-12-05 20:10:33 +00:00
componentManager . Remove < TComponent > ( entity ) ;
2019-11-21 03:01:29 +00:00
return true ;
2019-11-17 18:48:39 +00:00
}
2019-11-21 22:22:10 +00:00
/// <summary>
/// Activates the Encompass time dilation system.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
2019-11-22 21:14:36 +00:00
/// If multiple time dilations are active they will be averaged.
2019-11-21 22:22:10 +00:00
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
2019-11-21 21:53:33 +00:00
public void ActivateTimeDilation ( double factor , double easeInTime , double activeTime , double easeOutTime )
{
2019-11-22 21:14:36 +00:00
timeManager . ActivateTimeDilation ( factor , easeInTime , activeTime , easeOutTime ) ;
2019-11-21 21:53:33 +00:00
}
2019-11-21 22:22:10 +00:00
/// <summary>
/// Activates the Encompass time dilation system.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
2019-11-22 21:14:36 +00:00
/// If multiple time dilations are active they will be averaged.
2019-11-21 22:22:10 +00:00
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="easeInFunction">An easing function for the easing in of time dilation.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
2019-11-21 21:53:33 +00:00
public void ActivateTimeDilation ( double factor , double easeInTime , System . Func < double , double , double , double , double > easeInFunction , double activeTime , double easeOutTime )
{
2019-11-22 21:14:36 +00:00
timeManager . ActivateTimeDilation ( factor , easeInTime , easeInFunction , activeTime , easeOutTime ) ;
2019-11-21 21:53:33 +00:00
}
2019-11-21 22:22:10 +00:00
/// <summary>
/// Activates the Encompass time dilation system.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
2019-11-22 21:14:36 +00:00
/// If multiple time dilations are active they will be averaged.
2019-11-21 22:22:10 +00:00
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
2019-11-21 21:53:33 +00:00
public void ActivateTimeDilation ( double factor , double easeInTime , double activeTime , double easeOutTime , System . Func < double , double , double , double , double > easeOutFunction )
{
2019-11-22 21:14:36 +00:00
timeManager . ActivateTimeDilation ( factor , easeInTime , activeTime , easeOutTime , easeOutFunction ) ;
2019-11-21 21:53:33 +00:00
}
2019-11-21 22:22:10 +00:00
/// <summary>
/// Activates the Encompass time dilation system.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
2019-11-22 21:14:36 +00:00
/// If multiple time dilations are active they will be averaged.
2019-11-21 22:22:10 +00:00
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="easeInFunction">An easing function for the easing in of time dilation.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
2019-11-21 21:53:33 +00:00
public void ActivateTimeDilation ( double factor , double easeInTime , System . Func < double , double , double , double , double > easeInFunction , double activeTime , double easeOutTime , System . Func < double , double , double , double , double > easeOutFunction )
{
2019-11-22 21:14:36 +00:00
timeManager . ActivateTimeDilation ( factor , easeInTime , easeInFunction , activeTime , easeOutTime , easeOutFunction ) ;
2019-11-21 21:53:33 +00:00
}
2019-06-15 00:51:06 +00:00
}
}