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-02 01:53:44 +00:00
using Collections.Pooled ;
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-08-01 23:24:57 +00:00
private readonly Dictionary < Guid , IComponent > componentIDToComponent = new Dictionary < Guid , IComponent > ( ) ;
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-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-08-11 00:34:00 +00:00
private readonly Dictionary < Entity , PooledDictionary < Type , Guid > > entityToTypeToExistingComponentID = new Dictionary < Entity , PooledDictionary < Type , Guid > > ( ) ;
private readonly Dictionary < Entity , PooledDictionary < Type , Guid > > entityToTypeToPendingComponentID = new Dictionary < Entity , PooledDictionary < Type , Guid > > ( ) ;
private readonly Dictionary < Entity , PooledDictionary < Type , Guid > > entityToTypeToComponentID = new Dictionary < Entity , PooledDictionary < Type , Guid > > ( ) ;
2019-08-01 23:24:57 +00:00
2019-08-02 06:09:41 +00:00
internal void RegisterEntity ( Entity entity )
{
2019-08-11 00:34:00 +00:00
entityToTypeToComponentID [ entity ] = new PooledDictionary < Type , Guid > ( ) ;
entityToTypeToPendingComponentID [ entity ] = new PooledDictionary < Type , Guid > ( ) ;
entityToTypeToExistingComponentID [ entity ] = new PooledDictionary < Type , Guid > ( ) ;
2019-08-02 06:09:41 +00:00
}
internal void RegisterDestroyedEntity ( Entity entity )
{
2019-08-11 00:34:00 +00:00
entityToTypeToComponentID [ entity ] . Dispose ( ) ;
entityToTypeToComponentID . Remove ( entity ) ;
2019-08-02 06:09:41 +00:00
2019-08-11 00:34:00 +00:00
entityToTypeToPendingComponentID [ entity ] . Dispose ( ) ;
entityToTypeToPendingComponentID . Remove ( entity ) ;
2019-08-02 06:09:41 +00:00
2019-08-11 00:34:00 +00:00
entityToTypeToExistingComponentID [ entity ] . Dispose ( ) ;
entityToTypeToExistingComponentID . Remove ( entity ) ;
2019-08-02 06:09:41 +00:00
}
2019-08-01 23:24:57 +00:00
internal void ClearMessages ( )
{
componentIDToComponent . Clear ( ) ;
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-08-11 00:34:00 +00:00
foreach ( var dictionary in entityToTypeToExistingComponentID . 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-11 00:34:00 +00:00
foreach ( var dictionary in entityToTypeToPendingComponentID . 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-11 00:34:00 +00:00
foreach ( var dictionary in entityToTypeToComponentID . 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
}
}
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-08-11 00:34:00 +00:00
if ( ! entityToTypeToExistingComponentID [ componentMessage . entity ] . ContainsKey ( typeof ( TComponent ) ) )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
entityToTypeToExistingComponentID [ componentMessage . entity ] . Add ( typeof ( TComponent ) , componentMessage . componentID ) ;
}
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 > ( ) ) ;
}
componentMessageTypeToPendingComponentIDs [ typeof ( TComponent ) ] . Add ( pendingComponentMessage . componentID ) ;
2019-08-11 00:34:00 +00:00
if ( ! entityToTypeToPendingComponentID [ pendingComponentMessage . entity ] . ContainsKey ( typeof ( TComponent ) ) )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
entityToTypeToPendingComponentID [ pendingComponentMessage . entity ] . Add ( typeof ( TComponent ) , pendingComponentMessage . componentID ) ;
}
else
{
throw new MultipleComponentOfSameTypeException ( "Entity {0} cannot have multiple components of type {1}" , pendingComponentMessage . entity . ID , typeof ( TComponent ) . Name ) ;
2019-08-01 23:24:57 +00:00
}
}
2019-08-02 00:05: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
{
componentIDToComponent [ componentID ] = component ;
2019-08-20 00:30:31 +00:00
componentIDToEntityID [ componentID ] = entity . ID ;
componentIDToType [ componentID ] = typeof ( TComponent ) ;
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-08-11 18:26:31 +00:00
entityToTypeToComponentID [ entity ] [ typeof ( TComponent ) ] = 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
{
return idSet . Select ( id = > ( id , ( TComponent ) componentIDToComponent [ id ] ) ) ;
}
return Enumerable . Empty < ( Guid , TComponent ) > ( ) ;
}
internal IEnumerable < ( Guid , TComponent ) > ReadExistingComponentsByType < 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 . Select ( id = > ( id , ( TComponent ) componentIDToComponent [ id ] ) ) ;
}
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
{
return idSet . Select ( id = > ( id , ( TComponent ) componentIDToComponent [ id ] ) ) ;
}
return Enumerable . Empty < ( Guid , TComponent ) > ( ) ;
}
// singular component reads by type
internal ( Guid , TComponent ) ReadFirstExistingOrPendingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadExistingAndPendingComponentsByType < TComponent > ( ) . First ( ) ;
}
internal ( Guid , TComponent ) ReadFirstExistingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
return ReadExistingComponentsByType < TComponent > ( ) . First ( ) ;
}
internal ( Guid , TComponent ) ReadFirstPendingComponentByType < TComponent > ( ) where TComponent : struct , IComponent
{
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-08-11 00:34:00 +00:00
if ( entityToTypeToExistingComponentID . ContainsKey ( entity ) & & entityToTypeToExistingComponentID [ entity ] . TryGetValue ( typeof ( TComponent ) , out Guid id ) )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
return ( id , ( TComponent ) componentIDToComponent [ 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-08-11 00:34:00 +00:00
if ( entityToTypeToPendingComponentID . ContainsKey ( entity ) & & entityToTypeToPendingComponentID [ entity ] . TryGetValue ( typeof ( TComponent ) , out Guid id ) )
2019-08-01 23:24:57 +00:00
{
2019-08-11 00:34:00 +00:00
return ( id , ( TComponent ) componentIDToComponent [ id ] ) ;
}
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-08-11 00:34:00 +00:00
return entityToTypeToComponentID . ContainsKey ( entity ) & & entityToTypeToComponentID [ entity ] . ContainsKey ( typeof ( TComponent ) ) ;
2019-08-01 23:24:57 +00:00
}
internal bool HasExistingComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-08-11 00:34:00 +00:00
return entityToTypeToExistingComponentID . ContainsKey ( entity ) & & entityToTypeToExistingComponentID [ entity ] . ContainsKey ( typeof ( TComponent ) ) ;
2019-08-01 23:24:57 +00:00
}
internal bool HasPendingComponent < TComponent > ( Entity entity ) where TComponent : struct , IComponent
{
2019-08-11 00:34:00 +00:00
return entityToTypeToPendingComponentID . ContainsKey ( entity ) & & entityToTypeToPendingComponentID [ entity ] . ContainsKey ( typeof ( TComponent ) ) ;
2019-08-01 23:24:57 +00:00
}
2019-08-20 00:30:31 +00:00
internal IComponent GetComponentByID ( Guid componentID )
{
return componentIDToComponent [ componentID ] ;
}
internal Type GetComponentTypeByID ( Guid componentID )
{
return componentIDToType [ componentID ] ;
}
internal Guid GetEntityIDByComponentID ( Guid componentID )
{
return componentIDToEntityID [ componentID ] ;
}
2019-08-01 22:06:19 +00:00
}
}