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 ;
private ComponentManager componentManager ;
2019-06-16 01:55:35 +00:00
private MessageManager messageManager ;
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-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-06-22 00:50:01 +00:00
return componentManager . 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-07-16 18:17:07 +00:00
if ( componentManager . GetComponentTypeByID ( componentID ) ! = typeof ( TComponent ) )
2019-06-22 00:44:07 +00:00
{
throw new ComponentTypeMismatchException ( "Expected Component to be of type {0} but was actually of type {1}" , typeof ( TComponent ) . Name , componentManager . GetComponentTypeByID ( componentID ) . Name ) ;
}
2019-07-16 18:17:07 +00:00
return ( TComponent ) componentManager . GetComponentByID ( componentID ) ;
2019-06-22 00:44:07 +00:00
}
2019-07-18 21:02:57 +00:00
internal IEnumerable < ValueTuple < Entity , Guid , TComponent > > ReadComponentsFromWorld < TComponent > ( ) where TComponent : struct , IComponent
2019-06-16 01:05:56 +00:00
{
2019-07-18 21:02:57 +00:00
return componentManager . GetActiveComponentsByType < TComponent > ( ) . Select ( ( triple ) = > ( GetEntity ( triple . Item1 ) , triple . Item2 , triple . Item3 ) ) ;
2019-06-15 00:51:06 +00:00
}
2019-06-15 07:39:08 +00:00
2019-07-17 18:24:21 +00:00
protected Guid AddComponent < TComponent > ( Entity entity , TComponent component ) where TComponent : struct , IComponent
{
2019-07-23 05:52:51 +00:00
var componentID = componentManager . NextID ( ) ;
2019-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
componentManager . AddComponent ( entity , componentID , component ) ;
2019-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
if ( sendTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) )
{
PendingComponentMessage < TComponent > componentMessage ;
componentMessage . entity = entity ;
componentMessage . componentID = componentID ;
componentMessage . component = component ;
SendMessage ( componentMessage ) ;
}
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-07-23 05:52:51 +00:00
var componentID = componentManager . NextID ( ) ;
2019-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
componentManager . AddDrawComponent ( entity , componentID , component ) ;
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-07-18 21:02:57 +00:00
return componentID ;
2019-07-17 18:24:21 +00:00
}
2019-07-18 21:02:57 +00:00
protected void ActivateComponent < TComponent > ( Guid componentID ) where TComponent : struct , IComponent
2019-07-17 18:24:21 +00:00
{
2019-07-18 21:02:57 +00:00
var entity = GetEntity ( componentManager . GetEntityIDByComponentID ( componentID ) ) ;
var component = GetComponentByID < TComponent > ( componentID ) ;
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-07-18 21:02:57 +00:00
2019-07-23 05:52:51 +00:00
componentManager . Activate ( componentID ) ;
}
2019-07-17 18:24:21 +00:00
}
protected void DeactivateComponent ( Guid componentID )
{
2019-07-18 01:12:29 +00:00
componentManager . MarkForDeactivation ( componentID ) ;
2019-07-17 18:24:21 +00:00
}
2019-07-20 21:10:06 +00:00
private IEnumerable < ValueTuple < Entity , Guid , TComponent > > ExistingComponents < TComponent > ( ) where TComponent : struct , IComponent
2019-07-17 18:24:21 +00:00
{
2019-07-20 21:10:06 +00:00
return ReadMessages < ComponentMessage < TComponent > > ( ) . Select ( ( message ) = > ( message . entity , message . componentID , message . component ) ) ;
}
private IEnumerable < ValueTuple < Entity , Guid , TComponent > > PendingComponents < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadMessages < PendingComponentMessage < TComponent > > ( ) . Select ( ( message ) = > ( message . entity , message . componentID , message . component ) ) ;
}
private IEnumerable < ValueTuple < Entity , Guid , TComponent > > ReadComponentMessages < TComponent > ( ) where TComponent : struct , IComponent
{
var pendingRead = receiveTypes . Contains ( typeof ( PendingComponentMessage < TComponent > ) ) ;
var existingRead = receiveTypes . Contains ( typeof ( ComponentMessage < TComponent > ) ) ;
if ( existingRead & & pendingRead )
{
return ExistingComponents < TComponent > ( ) . Union ( PendingComponents < TComponent > ( ) ) ;
}
2019-07-23 17:17:53 +00:00
else if ( existingRead )
{
return ExistingComponents < TComponent > ( ) ;
}
else if ( pendingRead )
{
return PendingComponents < TComponent > ( ) ;
}
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
private IEnumerable < ValueTuple < Guid , TComponent > > ExistingComponentsOnEntity < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
return ReadComponentMessages < TComponent > ( ) . Where ( ( triple ) = > triple . Item1 = = entity ) . Select ( ( triple ) = > ( triple . Item2 , triple . Item3 ) ) ;
2019-07-17 18:24:21 +00:00
}
2019-07-19 23:15:48 +00:00
private IEnumerable < ValueTuple < Guid , TComponent > > PendingComponentsOnEntity < TComponent > ( Entity entity ) where TComponent : struct , IComponent
2019-07-19 19:47:17 +00:00
{
2019-07-20 21:10:06 +00:00
return ReadComponentMessages < TComponent > ( ) . Where ( ( triple ) = > triple . Item1 = = entity ) . Select ( ( triple ) = > ( triple . Item2 , triple . Item3 ) ) ;
}
protected IEnumerable < ValueTuple < Guid , TComponent > > ReadComponents < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadComponentMessages < TComponent > ( ) . Select ( ( triple ) = > ( triple . Item2 , triple . Item3 ) ) ;
}
2019-07-19 19:47:17 +00:00
2019-07-20 21:10:06 +00:00
protected ValueTuple < Guid , TComponent > ReadComponent < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadComponents < TComponent > ( ) . Single ( ) ;
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-07-20 21:10:06 +00:00
return ReadComponentMessages < TComponent > ( ) . Any ( ) ;
2019-07-19 19:47:17 +00:00
}
protected IEnumerable < ValueTuple < Guid , TComponent > > GetComponents < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
return ExistingComponentsOnEntity < TComponent > ( entity ) ;
}
2019-07-17 18:24:21 +00:00
protected ValueTuple < Guid , TComponent > GetComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
return GetComponents < TComponent > ( entity ) . First ( ) ;
}
protected bool HasComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-07-19 19:47:17 +00:00
return GetComponents < TComponent > ( entity ) . Any ( ) ;
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
}
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
{
return ReadMessages < TMessage > ( ) . Single ( ) ;
}
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
}
}