Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
EntityProcessor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using SiliconStudio.Core.Diagnostics;
7 using SiliconStudio.Core.Extensions;
8 using SiliconStudio.Paradox.Games;
9 using System.Threading.Tasks;
10 using SiliconStudio.Core;
11 
12 namespace SiliconStudio.Paradox.EntityModel
13 {
14  /// <summary>Entity processor, triggered on various <see cref="EntitySystem"/> events such as Entity and Component additions and removals.</summary>
15  public abstract class EntityProcessor
16  {
17  private bool enabled = true;
18 
19  internal ProfilingKey UpdateProfilingKey;
20  internal ProfilingKey DrawProfilingKey;
21 
22  public bool Enabled
23  {
24  get { return enabled; }
25  set { enabled = value; }
26  }
27 
28  public EntitySystem EntitySystem { get; internal set; }
29 
30  public IServiceRegistry Services { get; internal set; }
31 
32  protected EntityProcessor()
33  {
34  UpdateProfilingKey = new ProfilingKey(GameProfilingKeys.GameUpdate, this.GetType().Name);
35  DrawProfilingKey = new ProfilingKey(GameProfilingKeys.GameDraw, this.GetType().Name);
36  }
37 
38  /// <summary>
39  /// Performs work related to this processor.
40  /// </summary>
41  /// <param name="time"></param>
42  public virtual void Update(GameTime time)
43  {
44  }
45 
46  /// <summary>
47  /// Performs work related to this processor.
48  /// </summary>
49  /// <param name="time"></param>
50  public virtual void Draw(GameTime time)
51  {
52  }
53 
54  /// <summary>
55  /// Run when this <see cref="EntityProcessor" /> is added to an <see cref="EntitySystem" />.
56  /// </summary>
57  protected internal abstract void OnSystemAdd();
58 
59  /// <summary>
60  /// Run when this <see cref="EntityProcessor" /> is removed from an <see cref="EntitySystem" />.
61  /// </summary>
62  protected internal abstract void OnSystemRemove();
63 
64  /// <summary>
65  /// Specifies weither an entity is enabled or not.
66  /// </summary>
67  /// <param name="entity">The entity.</param>
68  protected internal abstract void SetEnabled(Entity entity, bool enabled);
69 
70  protected virtual void OnEnabledChanged(Entity entity, bool enabled)
71  {
72 
73  }
74 
75  /// <summary>
76  /// Checks if <see cref="Entity"/> needs to be either added or removed.
77  /// </summary>
78  /// <param name="entity">The entity.</param>
79  /// <param name="forceRemove">if set to <c>true</c> [force remove].</param>
80  protected internal abstract void EntityCheck(Entity entity, List<EntityProcessor> processors, bool forceRemove = false);
81 
82  /// <summary>
83  /// Adds the entity to the internal list of the <see cref="EntitySystem"/>.
84  /// Exposed for inheriting class that has no access to EntitySystem as internal.
85  /// </summary>
86  /// <param name="entity">The entity.</param>
87  protected internal void InternalAddEntity(Entity entity)
88  {
89  EntitySystem.InternalAddEntity(entity);
90  }
91 
92  /// <summary>
93  /// Removes the entity to the internal list of the <see cref="EntitySystem"/>.
94  /// Exposed for inheriting class that has no access to EntitySystem as internal.
95  /// </summary>
96  /// <param name="entity">The entity.</param>
97  /// <param name="removeParent">Indicate if entity should be removed from its parent</param>
98  protected internal void InternalRemoveEntity(Entity entity, bool removeParent)
99  {
100  EntitySystem.InternalRemoveEntity(entity, removeParent);
101  }
102  }
103 
104  /// <summary>Helper class for <see cref="EntityProcessor"/>, that will keep track of <see cref="Entity"/> matching certain <see cref="EntityComponent"/> requirements.</summary>
105  /// Additional precomputed data will be stored alongside the <see cref="Entity"/> to offer faster accesses and iterations.
106  /// <typeparam name="T">Generic type parameter.</typeparam>
107  public abstract class EntityProcessor<T> : EntityProcessor
108  {
109  protected Dictionary<Entity, T> enabledEntities = new Dictionary<Entity, T>();
110  protected Dictionary<Entity, T> matchingEntities = new Dictionary<Entity, T>();
111  protected HashSet<Entity> reentrancyCheck = new HashSet<Entity>();
113 
114  protected EntityProcessor(PropertyKey[] requiredKeys)
115  {
116  this.requiredKeys = requiredKeys;
117  }
118 
119  /// <summary>Gets the required components for an entity to be added to this entity processor.</summary>
120  /// <value>The required keys.</value>
121  protected virtual PropertyKey[] RequiredKeys
122  {
123  get { return requiredKeys; }
124  }
125 
126  /// <inheritdoc/>
127  protected internal override void OnSystemAdd()
128  {
129  }
130 
131  /// <inheritdoc/>
132  protected internal override void OnSystemRemove()
133  {
134  }
135 
136  /// <inheritdoc/>
137  protected internal override void SetEnabled(Entity entity, bool enabled)
138  {
139  if (enabled)
140  {
141  T entityData;
142  if (!matchingEntities.TryGetValue(entity, out entityData))
143  throw new InvalidOperationException("EntityProcessor: Tried to enable an unknown entity.");
144 
145  enabledEntities.Add(entity, matchingEntities[entity]);
146  }
147  else
148  {
149  if (!enabledEntities.Remove(entity))
150  throw new InvalidOperationException("Invalid Entity Enabled state");
151  }
152 
153  OnEnabledChanged(entity, enabled);
154  }
155 
156  /// <inheritdoc/>
157  protected internal override void EntityCheck(Entity entity, List<EntityProcessor> processors, bool forceRemove)
158  {
159  // If forceRemove is true, no need to check if entity matches.
160  bool entityMatch = !forceRemove && EntityMatch(entity);
161  T entityData;
162  bool entityAdded = matchingEntities.TryGetValue(entity, out entityData);
163 
164  if (entityMatch && !entityAdded)
165  {
166  // Adding entity is not reentrant, so let's skip if already being called for current entity
167  // (could happen if either GenerateAssociatedData, OnEntityPrepare or OnEntityAdd changes
168  // any Entity components
169  lock (reentrancyCheck)
170  {
171  if (!reentrancyCheck.Add(entity))
172  return;
173  }
174 
175  // Need to add entity
176  entityData = GenerateAssociatedData(entity);
177 
178  processors.Add(this);
179  OnEntityAdding(entity, entityData);
180  matchingEntities.Add(entity, entityData);
181 
182  // If entity was enabled, add it to enabled entity list
183  if (EntitySystem.IsEnabled(entity))
184  enabledEntities.Add(entity, entityData);
185 
186  lock (reentrancyCheck)
187  {
188  reentrancyCheck.Remove(entity);
189  }
190  }
191  else if (entityAdded && !entityMatch)
192  {
193  // Need to be removed
194  OnEntityRemoved(entity, entityData);
195  processors.SwapRemove(this);
196 
197  // Remove from enabled and matching entities
198  enabledEntities.Remove(entity);
199  matchingEntities.Remove(entity);
200  }
201  }
202 
203  /// <summary>Generates associated data to the given entity.</summary>
204  /// Called right before <see cref="OnEntityAdding"/>.
205  /// <param name="entity">The entity.</param>
206  /// <returns>The associated data.</returns>
207  protected abstract T GenerateAssociatedData(Entity entity);
208 
209  protected virtual bool EntityMatch(Entity entity)
210  {
211  return RequiredKeys.All(x => entity.Tags.Get(x) != null);
212  }
213 
214  protected virtual void EntityReadd(Entity entity)
215  {
216  T data;
217  if (matchingEntities.TryGetValue(entity, out data))
218  {
219  try
220  {
221  OnEntityRemoved(entity, data);
222  OnEntityAdding(entity, data);
223  }
224  catch (Exception)
225  {
226  enabledEntities.Remove(entity);
227  matchingEntities.Remove(entity);
228  throw new Exception("Error during entity readd.");
229  }
230  }
231  }
232 
233  /// <summary>Run when a matching entity is added to this entity processor.</summary>
234  /// <param name="entity">The entity.</param>
235  /// <param name="data"> The associated data.</param>
236  protected virtual void OnEntityAdding(Entity entity, T data)
237  {
238  }
239 
240  /// <summary>Run when a matching entity is removed from this entity processor.</summary>
241  /// <param name="entity">The entity.</param>
242  /// <param name="data"> The associated data.</param>
243  protected virtual void OnEntityRemoved(Entity entity, T data)
244  {
245  }
246  }
247 }
virtual void Draw(GameTime time)
Performs work related to this processor.
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
A key to identify a specific profile.
Definition: ProfilingKey.cs:11
virtual void Update(GameTime time)
Performs work related to this processor.
static readonly ProfilingKey GameUpdate
Profiling Update() method of a GameBase. This profiling is only used through markers published every ...
A service registry is a IServiceProvider that provides methods to register and unregister services...
Keys used for profiling the game class.
Entity processor, triggered on various EntitySystem events such as Entity and Component additions and...
Current timing used for variable-step (real time) or fixed-step (game time) games.
Definition: GameTime.cs:31
Manage a collection of entities.
Definition: EntitySystem.cs:22
virtual void OnEntityRemoved(Entity entity, T data)
Run when a matching entity is removed from this entity processor.
virtual void OnEnabledChanged(Entity entity, bool enabled)
virtual void OnEntityAdding(Entity entity, T data)
Run when a matching entity is added to this entity processor.
static readonly ProfilingKey GameDraw
Profiling Draw() method of a GameBase. This profiling is only used through markers published every se...
A class that represents a tag propety.
Definition: PropertyKey.cs:17