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
{
public abstract class Engine
{
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-06-15 07:39:08 +00:00
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-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-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 ;
}
var activatesAttribute = GetType ( ) . GetCustomAttribute < Activates > ( false ) ;
if ( activatesAttribute ! = null )
{
sendTypes . UnionWith ( activatesAttribute . activateTypes ) ;
}
2019-07-20 00:50:13 +00:00
var updatesAttribute = GetType ( ) . GetCustomAttribute < Updates > ( false ) ;
if ( updatesAttribute ! = null )
{
sendTypes . UnionWith ( updatesAttribute . updateTypes ) ;
}
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-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-06-24 19:14:37 +00:00
public abstract void Update ( double dt ) ;
2019-06-15 00:51:06 +00:00
2019-06-16 01:05:56 +00:00
protected Entity CreateEntity ( )
{
2019-06-20 03:37:46 +00:00
return entityManager . CreateEntity ( ) ;
}
2019-07-13 00:37:31 +00:00
protected bool EntityExists ( Guid entityID )
{
return entityManager . EntityExists ( entityID ) ;
}
2019-06-20 03:37:46 +00:00
protected Entity GetEntity ( Guid entityID )
{
return entityManager . GetEntity ( entityID ) ;
}
2019-06-22 00:50:01 +00:00
protected Guid GetEntityIDByComponentID ( Guid componentID )
2019-06-20 03:37:46 +00:00
{
2019-08-20 00:30:31 +00:00
return componentMessageManager . GetEntityIDByComponentID ( componentID ) ;
2019-06-15 00:51:06 +00:00
}
2019-06-22 00:50:01 +00:00
protected Entity GetEntityByComponentID ( Guid componentID )
2019-06-22 00:44:07 +00:00
{
2019-06-22 00:50:01 +00:00
return GetEntity ( GetEntityIDByComponentID ( componentID ) ) ;
2019-06-22 00:44:07 +00:00
}
protected TComponent GetComponentByID < TComponent > ( Guid componentID ) where TComponent : struct , IComponent
{
2019-08-20 00:30:31 +00:00
if ( componentMessageManager . GetComponentTypeByID ( componentID ) ! = typeof ( TComponent ) )
2019-06-22 00:44:07 +00:00
{
2019-08-20 00:30:31 +00:00
throw new ComponentTypeMismatchException ( "Expected Component to be of type {0} but was actually of type {1}" , typeof ( TComponent ) . Name , componentMessageManager . GetComponentTypeByID ( componentID ) . Name ) ;
2019-06-22 00:44:07 +00:00
}
2019-07-16 18:17:07 +00:00
2019-08-20 00:30:31 +00:00
return ( TComponent ) componentMessageManager . GetComponentByID ( componentID ) ;
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-08-01 23:44:29 +00:00
internal IEnumerable < ( Guid , 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-08-20 00:30:31 +00:00
internal Entity ReadEntityFromWorld ( Guid componentID )
{
return GetEntity ( componentManager . GetEntityIDByComponentID ( componentID ) ) ;
}
2019-07-17 18:24:21 +00:00
protected Guid AddComponent < TComponent > ( Entity entity , TComponent component ) where TComponent : struct , IComponent
{
2019-08-11 00:34:00 +00:00
var componentID = componentManager . MarkComponentForAdd ( entity , component ) ;
2019-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
if ( sendTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) )
{
2019-08-01 23:24:57 +00:00
PendingComponentMessage < TComponent > newComponentMessage ;
newComponentMessage . entity = entity ;
newComponentMessage . componentID = componentID ;
newComponentMessage . component = component ;
SendMessage ( newComponentMessage ) ;
SendPendingComponentMessage ( newComponentMessage ) ;
2019-07-23 05:52:51 +00:00
}
2019-07-18 21:02:57 +00:00
return componentID ;
2019-07-17 18:24:21 +00:00
}
protected Guid AddDrawComponent < TComponent > ( Entity entity , TComponent component , int layer = 0 ) where TComponent : struct , IComponent
{
2019-08-11 00:34:00 +00:00
var componentID = componentManager . MarkDrawComponentForAdd ( entity , component , layer ) ;
2019-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
if ( sendTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) )
{
PendingComponentMessage < TComponent > newComponentMessage ;
newComponentMessage . entity = entity ;
newComponentMessage . componentID = componentID ;
newComponentMessage . component = component ;
SendMessage ( newComponentMessage ) ;
2019-08-01 23:24:57 +00:00
SendPendingComponentMessage ( newComponentMessage ) ;
2019-07-23 05:52:51 +00:00
}
2019-07-18 21:02:57 +00:00
return componentID ;
2019-07-17 18:24:21 +00:00
}
2019-08-01 23:24:57 +00:00
protected IEnumerable < ValueTuple < Guid , TComponent > > ReadComponents < 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-07-20 21:10:06 +00:00
protected ValueTuple < Guid , TComponent > ReadComponent < TComponent > ( ) 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 ( 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-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-07-17 18:24:21 +00:00
protected ValueTuple < Guid , TComponent > GetComponent < 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 ( 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
}
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-06-17 18:33:38 +00:00
internal void UpdateComponentInWorld < TComponent > ( Guid componentID , TComponent newComponent ) where TComponent : struct , IComponent
2019-06-16 01:05:56 +00:00
{
2019-07-18 01:53:31 +00:00
componentManager . AddUpdateComponentOperation ( componentID , newComponent ) ;
2019-06-15 18:40:42 +00:00
}
2019-06-17 18:33:38 +00:00
protected void UpdateComponent < TComponent > ( Guid componentID , TComponent newComponentValue ) where TComponent : struct , IComponent
2019-06-16 01:05:56 +00:00
{
2019-07-20 00:50:13 +00:00
if ( ! sendTypes . Contains ( typeof ( ComponentUpdateMessage < TComponent > ) ) )
{
throw new IllegalUpdateException ( "Engine {0} tried to update undeclared Component {1}" , GetType ( ) . Name , typeof ( TComponent ) . Name ) ;
}
ComponentUpdateMessage < TComponent > componentUpdateMessage ;
componentUpdateMessage . componentID = componentID ;
componentUpdateMessage . component = newComponentValue ;
SendMessage ( componentUpdateMessage ) ;
2019-06-15 07:39:08 +00:00
}
2019-06-16 01:55:35 +00:00
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-08-20 02:05:18 +00:00
protected void SendMessageDelayed < TMessage > ( TMessage message , double time ) where TMessage : struct , IMessage
{
messageManager . AddMessageDelayed ( 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-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-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-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
protected void Destroy ( Guid entityID )
{
entityManager . MarkForDestroy ( entityID ) ;
}
2019-07-17 18:24:21 +00:00
protected void RemoveComponent ( Guid componentID )
{
2019-07-18 01:12:29 +00:00
componentManager . MarkForRemoval ( componentID ) ;
2019-07-17 18:24:21 +00:00
}
2019-06-15 00:51:06 +00:00
}
}