2019-08-01 22:06:19 +00:00
using System ;
using System.Collections.Generic ;
2019-08-01 23:24:57 +00:00
using System.Linq ;
2019-08-11 00:34:00 +00:00
using Encompass.Exceptions ;
2019-08-02 00:34:54 +00:00
2019-08-01 22:06:19 +00:00
namespace Encompass
{
class ComponentMessageManager
{
2019-12-05 04:50:08 +00:00
private readonly ComponentStore componentIDToComponent = new ComponentStore ( ) ;
2019-08-20 00:30:31 +00:00
private readonly Dictionary < Guid , Type > componentIDToType = new Dictionary < Guid , Type > ( ) ;
2019-08-01 22:06:19 +00:00
2019-08-20 00:30:31 +00:00
private readonly Dictionary < Guid , Guid > componentIDToEntityID = new Dictionary < Guid , Guid > ( ) ;
2019-10-24 19:48:36 +00:00
2019-08-01 23:24:57 +00:00
private readonly Dictionary < Type , HashSet < Guid > > componentMessageTypeToExistingComponentIDs = new Dictionary < Type , HashSet < Guid > > ( ) ;
private readonly Dictionary < Type , HashSet < Guid > > componentMessageTypeToPendingComponentIDs = new Dictionary < Type , HashSet < Guid > > ( ) ;
private readonly Dictionary < Type , HashSet < Guid > > componentMessageTypeToComponentIDs = new Dictionary < Type , HashSet < Guid > > ( ) ;
2019-08-01 22:06:19 +00:00
2019-12-05 04:50:08 +00:00
private readonly Dictionary < Type , Dictionary < Entity , Guid > > typeToEntityToExistingComponentID = new Dictionary < Type , Dictionary < Entity , Guid > > ( ) ;
private readonly Dictionary < Type , Dictionary < Entity , Guid > > typeToEntityToPendingComponentID = new Dictionary < Type , Dictionary < Entity , Guid > > ( ) ;
private readonly Dictionary < Type , Dictionary < Entity , Guid > > typeToEntityToComponentID = new Dictionary < Type , Dictionary < Entity , Guid > > ( ) ;
2019-08-01 23:24:57 +00:00
2019-12-05 04:50:08 +00:00
private readonly Dictionary < Type , Dictionary < Entity , int > > typeToEntityToPendingComponentPriority = new Dictionary < Type , Dictionary < Entity , int > > ( ) ;
2019-08-02 06:09:41 +00:00
2019-08-01 23:24:57 +00:00
internal void ClearMessages ( )
{
2019-12-05 04:50:08 +00:00
componentIDToComponent . ClearAll ( ) ;
2019-08-20 00:30:31 +00:00
componentIDToType . Clear ( ) ;
componentIDToEntityID . Clear ( ) ;
2019-08-01 23:24:57 +00:00
foreach ( var set in componentMessageTypeToExistingComponentIDs . Values )
{
set . Clear ( ) ;
}
foreach ( var set in componentMessageTypeToPendingComponentIDs . Values )
{
set . Clear ( ) ;
}
foreach ( var set in componentMessageTypeToComponentIDs . Values )
{
set . Clear ( ) ;
}
2019-12-05 04:50:08 +00:00
foreach ( var dictionary in typeToEntityToExistingComponentID . Values )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
dictionary . Clear ( ) ;
2019-08-01 23:24:57 +00:00
}
2019-12-05 04:50:08 +00:00
foreach ( var dictionary in typeToEntityToPendingComponentID . Values )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
dictionary . Clear ( ) ;
2019-08-01 23:24:57 +00:00
}
2019-12-05 04:50:08 +00:00
foreach ( var dictionary in typeToEntityToComponentID . Values )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
dictionary . Clear ( ) ;
2019-08-01 23:24:57 +00:00
}
2019-08-21 02:25:59 +00:00
2019-12-05 04:50:08 +00:00
foreach ( var dictionary in typeToEntityToPendingComponentPriority . Values )
2019-08-21 02:25:59 +00:00
{
dictionary . Clear ( ) ;
}
2019-08-01 23:24:57 +00:00
}
internal void AddExistingComponentMessage < TComponent > ( ComponentMessage < TComponent > componentMessage ) where TComponent : struct , IComponent
{
2019-08-02 00:05:36 +00:00
RegisterExistingOrPendingComponentMessage ( componentMessage . entity , componentMessage . componentID , componentMessage . component ) ;
2019-08-01 23:24:57 +00:00
if ( ! componentMessageTypeToExistingComponentIDs . ContainsKey ( typeof ( TComponent ) ) )
{
componentMessageTypeToExistingComponentIDs . Add ( typeof ( TComponent ) , new HashSet < Guid > ( ) ) ;
}
componentMessageTypeToExistingComponentIDs [ typeof ( TComponent ) ] . Add ( componentMessage . componentID ) ;
2019-12-05 04:50:08 +00:00
if ( ! typeToEntityToExistingComponentID . ContainsKey ( typeof ( TComponent ) ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
typeToEntityToExistingComponentID . Add ( typeof ( TComponent ) , new Dictionary < Entity , Guid > ( ) ) ;
}
if ( ! typeToEntityToExistingComponentID [ typeof ( TComponent ) ] . ContainsKey ( componentMessage . entity ) )
{
typeToEntityToExistingComponentID [ typeof ( TComponent ) ] . Add ( componentMessage . entity , componentMessage . componentID ) ;
2019-08-11 00:34:00 +00:00
}
else
{
throw new MultipleComponentOfSameTypeException ( "Entity {0} cannot have multiple components of type {1}" , componentMessage . entity . ID , typeof ( TComponent ) . Name ) ;
2019-08-01 23:24:57 +00:00
}
}
internal void AddPendingComponentMessage < TComponent > ( PendingComponentMessage < TComponent > pendingComponentMessage ) where TComponent : struct , IComponent
{
2019-08-02 00:05:36 +00:00
RegisterExistingOrPendingComponentMessage ( pendingComponentMessage . entity , pendingComponentMessage . componentID , pendingComponentMessage . component ) ;
2019-08-01 23:24:57 +00:00
if ( ! componentMessageTypeToPendingComponentIDs . ContainsKey ( typeof ( TComponent ) ) )
{
componentMessageTypeToPendingComponentIDs . Add ( typeof ( TComponent ) , new HashSet < Guid > ( ) ) ;
}
2019-12-05 04:50:08 +00:00
if ( ! typeToEntityToPendingComponentID . ContainsKey ( typeof ( TComponent ) ) )
{
typeToEntityToPendingComponentID . Add ( typeof ( TComponent ) , new Dictionary < Entity , Guid > ( ) ) ;
typeToEntityToPendingComponentPriority . Add ( typeof ( TComponent ) , new Dictionary < Entity , int > ( ) ) ;
}
if ( ! typeToEntityToPendingComponentID [ typeof ( TComponent ) ] . ContainsKey ( pendingComponentMessage . entity ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
typeToEntityToPendingComponentID [ typeof ( TComponent ) ] . Add ( pendingComponentMessage . entity , pendingComponentMessage . componentID ) ;
typeToEntityToPendingComponentPriority [ typeof ( TComponent ) ] . Add ( pendingComponentMessage . entity , pendingComponentMessage . priority ) ;
2019-08-21 02:25:59 +00:00
componentMessageTypeToPendingComponentIDs [ typeof ( TComponent ) ] . Add ( pendingComponentMessage . componentID ) ;
2019-08-11 00:34:00 +00:00
}
else
{
2019-12-05 04:50:08 +00:00
if ( pendingComponentMessage . priority < typeToEntityToPendingComponentPriority [ typeof ( TComponent ) ] [ pendingComponentMessage . entity ] )
2019-08-21 02:25:59 +00:00
{
2019-12-05 04:50:08 +00:00
componentMessageTypeToPendingComponentIDs [ typeof ( TComponent ) ] . Remove ( typeToEntityToPendingComponentID [ typeof ( TComponent ) ] [ pendingComponentMessage . entity ] ) ;
typeToEntityToPendingComponentID [ typeof ( TComponent ) ] [ pendingComponentMessage . entity ] = pendingComponentMessage . componentID ;
typeToEntityToPendingComponentPriority [ typeof ( TComponent ) ] [ pendingComponentMessage . entity ] = pendingComponentMessage . priority ;
2019-08-21 02:25:59 +00:00
componentMessageTypeToPendingComponentIDs [ typeof ( TComponent ) ] . Add ( pendingComponentMessage . componentID ) ;
}
2019-08-01 23:24:57 +00:00
}
}
2019-10-24 19:48:36 +00:00
private void RegisterExistingOrPendingComponentMessage < TComponent > ( Entity entity , Guid componentID , TComponent component ) where TComponent : struct , IComponent
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
componentIDToComponent . Set ( componentID , component ) ;
2019-08-20 00:30:31 +00:00
componentIDToEntityID [ componentID ] = entity . ID ;
componentIDToType [ componentID ] = typeof ( TComponent ) ;
2019-10-24 19:48:36 +00:00
2019-08-01 23:24:57 +00:00
if ( ! componentMessageTypeToComponentIDs . ContainsKey ( typeof ( TComponent ) ) )
{
componentMessageTypeToComponentIDs . Add ( typeof ( TComponent ) , new HashSet < Guid > ( ) ) ;
}
componentMessageTypeToComponentIDs [ typeof ( TComponent ) ] . Add ( componentID ) ;
2019-08-02 00:05:36 +00:00
2019-12-05 04:50:08 +00:00
if ( ! typeToEntityToComponentID . ContainsKey ( typeof ( TComponent ) ) )
{
typeToEntityToComponentID . Add ( typeof ( TComponent ) , new Dictionary < Entity , Guid > ( ) ) ;
}
typeToEntityToComponentID [ typeof ( TComponent ) ] [ entity ] = componentID ;
2019-08-01 23:24:57 +00:00
}
// general component reads by type
internal IEnumerable < ( Guid , TComponent ) > ReadExistingAndPendingComponentsByType < TComponent > ( ) where TComponent : struct , IComponent
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
return idSet . Select ( id = > ( id , componentIDToComponent . Get < TComponent > ( id ) ) ) ;
2019-08-01 23:24:57 +00:00
}
return Enumerable . Empty < ( Guid , TComponent ) > ( ) ;
}
2019-10-24 19:48:36 +00:00
internal IEnumerable < ( Guid , TComponent ) > ReadExistingComponentsByType < TComponent > ( ) where TComponent : struct , IComponent
2019-08-01 23:24:57 +00:00
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToExistingComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
return idSet . Select ( id = > ( id , componentIDToComponent . Get < TComponent > ( id ) ) ) ;
2019-08-01 23:24:57 +00:00
}
return Enumerable . Empty < ( Guid , TComponent ) > ( ) ;
}
internal IEnumerable < ( Guid , TComponent ) > ReadPendingComponentsByType < TComponent > ( ) where TComponent : struct , IComponent
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToPendingComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
return idSet . Select ( id = > ( id , componentIDToComponent . Get < TComponent > ( id ) ) ) ;
2019-08-01 23:24:57 +00:00
}
return Enumerable . Empty < ( Guid , TComponent ) > ( ) ;
}
// singular component reads by type
internal ( Guid , TComponent ) ReadFirstExistingOrPendingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
2019-10-24 19:48:36 +00:00
if ( ! SomeExistingOrPendingComponent < TComponent > ( ) ) { throw new Exceptions . NoComponentOfTypeException ( $"No Component with type {typeof(TComponent)} exists" ) ; }
2019-08-01 23:24:57 +00:00
return ReadExistingAndPendingComponentsByType < TComponent > ( ) . First ( ) ;
}
internal ( Guid , TComponent ) ReadFirstExistingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
2019-10-24 19:48:36 +00:00
if ( ! SomeExistingComponent < TComponent > ( ) ) { throw new Exceptions . NoComponentOfTypeException ( $"No Component with type {typeof(TComponent)} exists" ) ; }
2019-08-01 23:24:57 +00:00
return ReadExistingComponentsByType < TComponent > ( ) . First ( ) ;
}
internal ( Guid , TComponent ) ReadFirstPendingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
2019-10-24 19:48:36 +00:00
if ( ! SomeExistingComponent < TComponent > ( ) ) { throw new Exceptions . NoComponentOfTypeException ( $"No Component with type {typeof(TComponent)} exists" ) ; }
2019-08-01 23:24:57 +00:00
return ReadPendingComponentsByType < TComponent > ( ) . First ( ) ;
}
// check if some component of type exists in the world
internal bool SomeExistingOrPendingComponent < TComponent > ( ) where TComponent : struct , IComponent
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
return idSet . Count > 0 ;
}
return false ;
}
internal bool SomeExistingComponent < TComponent > ( ) where TComponent : struct , IComponent
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToExistingComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
return idSet . Count > 0 ;
}
return false ;
}
internal bool SomePendingComponent < TComponent > ( ) where TComponent : struct , IComponent
{
2019-08-10 02:29:08 +00:00
if ( componentMessageTypeToPendingComponentIDs . TryGetValue ( typeof ( TComponent ) , out HashSet < Guid > idSet ) )
2019-08-01 23:24:57 +00:00
{
return idSet . Count > 0 ;
}
return false ;
}
// read components by entity and type
2019-08-11 00:34:00 +00:00
internal ( Guid , TComponent ) ReadExistingComponentByEntityAndType < TComponent > ( Entity entity ) where TComponent : struct , IComponent
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
if ( typeToEntityToExistingComponentID . ContainsKey ( typeof ( TComponent ) ) & & typeToEntityToExistingComponentID [ typeof ( TComponent ) ] . TryGetValue ( entity , out Guid id ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
return ( id , componentIDToComponent . Get < TComponent > ( id ) ) ;
2019-08-01 23:24:57 +00:00
}
2019-08-11 00:34:00 +00:00
else
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
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
}
}
2019-08-11 00:34:00 +00:00
internal ( Guid , TComponent ) ReadPendingComponentByEntityAndType < TComponent > ( Entity entity ) where TComponent : struct , IComponent
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
if ( typeToEntityToPendingComponentID . ContainsKey ( typeof ( TComponent ) ) & & typeToEntityToPendingComponentID [ typeof ( TComponent ) ] . TryGetValue ( entity , out Guid id ) )
2019-08-01 23:24:57 +00:00
{
2019-12-05 04:50:08 +00:00
return ( id , componentIDToComponent . Get < TComponent > ( id ) ) ;
2019-08-11 00:34:00 +00:00
}
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
}
}
// check if entity has component of type
internal bool HasExistingOrPendingComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-12-05 04:50:08 +00:00
return typeToEntityToComponentID . ContainsKey ( typeof ( TComponent ) ) & & typeToEntityToComponentID [ typeof ( TComponent ) ] . ContainsKey ( entity ) ;
2019-08-01 23:24:57 +00:00
}
2019-11-13 21:15:43 +00:00
internal bool HasExistingOrPendingComponent ( Entity entity , Type type )
{
2019-12-05 04:50:08 +00:00
return typeToEntityToComponentID . ContainsKey ( type ) & & typeToEntityToComponentID [ type ] . ContainsKey ( entity ) ;
2019-11-13 21:15:43 +00:00
}
2019-08-01 23:24:57 +00:00
internal bool HasExistingComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-12-05 04:50:08 +00:00
return typeToEntityToExistingComponentID . ContainsKey ( typeof ( TComponent ) ) & & typeToEntityToExistingComponentID [ typeof ( TComponent ) ] . ContainsKey ( entity ) ;
2019-08-01 23:24:57 +00:00
}
2019-11-13 21:15:43 +00:00
internal bool HasExistingComponent ( Entity entity , Type type )
{
2019-12-05 04:50:08 +00:00
return typeToEntityToExistingComponentID . ContainsKey ( type ) & & typeToEntityToExistingComponentID [ type ] . ContainsKey ( entity ) ;
2019-11-13 21:15:43 +00:00
}
2019-08-01 23:24:57 +00:00
internal bool HasPendingComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-12-05 04:50:08 +00:00
return typeToEntityToPendingComponentID . ContainsKey ( typeof ( TComponent ) ) & & typeToEntityToPendingComponentID [ typeof ( TComponent ) ] . ContainsKey ( entity ) ;
2019-08-01 23:24:57 +00:00
}
2019-08-20 00:30:31 +00:00
2019-11-13 21:15:43 +00:00
internal bool HasPendingComponent ( Entity entity , Type type )
{
2019-12-05 04:50:08 +00:00
return typeToEntityToPendingComponentID . ContainsKey ( type ) & & typeToEntityToPendingComponentID [ type ] . ContainsKey ( entity ) ;
2019-11-13 21:15:43 +00:00
}
2019-12-05 04:50:08 +00:00
internal TComponent GetComponentByID < TComponent > ( Guid componentID ) where TComponent : struct , IComponent
2019-08-20 00:30:31 +00:00
{
2019-12-05 04:50:08 +00:00
if ( componentIDToComponent . Has < TComponent > ( componentID ) )
2019-08-22 22:20:10 +00:00
{
2019-12-05 04:50:08 +00:00
return componentIDToComponent . Get < TComponent > ( componentID ) ;
2019-08-22 22:20:10 +00:00
}
else
{
throw new ComponentNotFoundException ( "Component with ID {0} does not exist." , componentID ) ;
}
2019-08-20 00:30:31 +00:00
}
internal Type GetComponentTypeByID ( Guid componentID )
{
2019-08-22 22:20:10 +00:00
if ( componentIDToType . ContainsKey ( componentID ) )
{
return componentIDToType [ componentID ] ;
}
else
{
throw new ComponentNotFoundException ( "Component with ID {0} does not exist." , componentID ) ;
}
2019-08-20 00:30:31 +00:00
}
internal Guid GetEntityIDByComponentID ( Guid componentID )
{
2019-08-22 22:20:10 +00:00
if ( componentIDToEntityID . ContainsKey ( componentID ) )
{
return componentIDToEntityID [ componentID ] ;
}
else
{
throw new ComponentNotFoundException ( "Component with ID {0} does not exist." , componentID ) ;
}
2019-08-20 00:30:31 +00:00
}
2019-08-01 22:06:19 +00:00
}
}