private void DoAdd(RuntimeEntity added) { if (_triggerModified != null) { added.ModificationNotifier.Listener += ModificationNotifier_Listener; } }
/// <summary> /// Internal method to add an entity to the entity manager and register it with all /// associated systems. This executes the add immediately. /// </summary> /// <param name="toAdd">The entity to add.</param> private void InternalAddEntity(RuntimeEntity toAdd) { toAdd.GameEngine = this; // notify listeners that we both added and created the entity Log <GameEngine> .Info("Submitting internal EntityAddedEvent for " + toAdd); EventNotifier.Submit(EntityAddedEvent.Create(toAdd)); EventNotifier.Submit(ShowEntityEvent.Create(toAdd)); // add it to the entity index _entityIndex.AddEntity(toAdd); // register listeners toAdd.ModificationNotifier.Listener += OnEntityModified; toAdd.DataStateChangeNotifier.Listener += OnEntityDataStateChanged; // notify ourselves of data state changes so that it the entity is pushed to systems toAdd.DataStateChangeNotifier.Notify(); // ensure it contains metadata for our keys toAdd.Metadata.UnorderedListMetadata[_entityUnorderedListMetadataKey] = new UnorderedListMetadata(); // add it our list of entities _entities.Add(toAdd, GetEntitiesListFromMetadata(toAdd)); }
/// <summary> /// Ensures that an Entity is not in the cache. /// </summary> /// <returns>True if the entity was previously in the cache and was removed, false if it /// was not in the cache and was therefore not removed.</returns> public bool Remove(RuntimeEntity entity) { if (CachedEntities.Remove(entity, GetMetadata(entity))) { return(true); } return(false); }
public static RuntimeEntity CreateRuntimeEntity() { RuntimeEntity entity = new RuntimeEntity(); entity.Initialize(new ContentEntitySerializationFormat() { Data = new List<ContentEntity.DataInstance>(), PrettyName = "", UniqueId = _idGenerator.Next() }, new EventNotifier()); return entity; }
/// <summary> /// Called when an entity that is contained within the cache has been modified. /// </summary> /// <remarks> /// This function is only called if we have a modification trigger to invoke. /// </remarks> private void ModificationNotifier_Listener(RuntimeEntity entity) { // Notice that we cannot check to see if the entity passes the modification filter here, // because this callback is just informing us that the entity has been modified; it does // not mean that the entity is done being modified. // // In other words, the entity may fail the modification filter check now, but at a later // point in time the check may succeed. _notifiedModifiedEntities.Add(entity); }
public IEntity Instantiate() { int id = _gameEngine.EntityIdGenerator.Next(); EventNotifier eventNotifier = _gameEngine.EventNotifier; RuntimeEntity entity = new RuntimeEntity(id, this, eventNotifier); _gameEngine.AddEntity(entity); return(entity); }
public void Restore(RuntimeEntity entity) { // if we don't have an entity cache then we have nothing to restore if (_entityCache == null) { return; } if (_entityCache.UpdateCache(entity) == EntityCache.CacheChangeResult.Added) { DoAdd(entity); } }
/// <summary> /// Returns the CachedEntities metadata for the given entity. /// </summary> private UnorderedListMetadata GetMetadata(RuntimeEntity entity) { // get our unordered list metadata or create it UnorderedListMetadata metadata; if (entity.Metadata.UnorderedListMetadata.TryGetValue(_metadataKey, out metadata) == false) { metadata = new UnorderedListMetadata(); entity.Metadata.UnorderedListMetadata[_metadataKey] = metadata; } return(metadata); }
private void DoRemove(RuntimeEntity removed) { // if we removed an entity from the cache, then we don't want to hear of any more // modification events if (_triggerModified != null) { removed.ModificationNotifier.Listener -= ModificationNotifier_Listener; // We have to remove the entity from our list of entities to dispatch, as during the // frame when OnRemoved is called OnModified (and also OnUpdate) will not be // invoked. _dispatchModified.Remove(removed); } }
/// <summary> /// Returns an entity instance for the given entity UniqueId. If an instance for the given /// id already exists, then it is returned. Otherwise, either a RuntimeEntity or /// ContentEntity is created. /// </summary> /// <param name="entityId">The id of the entity to get an instance for.</param> /// <param name="context">The GameEngineContext, used to determine if we should create a /// ContentTemplate or RuntimeTemplate instance.</param> public IEntity GetEntityInstance(int entityId, GameEngineContext context) { if (CreatedEntities.ContainsKey(entityId)) { return CreatedEntities[entityId]; } IEntity entity; if (context.GameEngine.IsEmpty) { entity = new ContentEntity(); } else { entity = new RuntimeEntity(); } CreatedEntities[entityId] = entity; return entity; }
/// <summary> /// Updates the status of the entity inside of the cache; ie, if the entity is now /// passing the filter but was not before, then it will be added to the cache. /// </summary> /// <returns>The change in cache status for the entity</returns> public CacheChangeResult UpdateCache(RuntimeEntity entity) { UnorderedListMetadata metadata = GetMetadata(entity); bool passed = _filter.Check(entity); bool contains = CachedEntities.Contains(entity, metadata); // The entity is not in the cache it now passes the filter, so add it to the cache if (contains == false && passed) { CachedEntities.Add(entity, metadata); return(CacheChangeResult.Added); } // The entity is in the cache but it no longer passes the filter, so remove it if (contains && passed == false) { CachedEntities.Remove(entity, metadata); return(CacheChangeResult.Removed); } // no change to the cache return(CacheChangeResult.NoChange); }
/// <summary> /// Returns the CachedEntities metadata for the given entity. /// </summary> private UnorderedListMetadata GetMetadata(RuntimeEntity entity) { // get our unordered list metadata or create it UnorderedListMetadata metadata; if (entity.Metadata.UnorderedListMetadata.TryGetValue(_metadataKey, out metadata) == false) { metadata = new UnorderedListMetadata(); entity.Metadata.UnorderedListMetadata[_metadataKey] = metadata; } return metadata; }
/// <summary> /// Ensures that an Entity is not in the cache. /// </summary> /// <returns>True if the entity was previously in the cache and was removed, false if it /// was not in the cache and was therefore not removed.</returns> public bool Remove(RuntimeEntity entity) { if (CachedEntities.Remove(entity, GetMetadata(entity))) { return true; } return false; }
/// <summary> /// Called when an entity has data state changes /// </summary> private void OnEntityDataStateChanged(RuntimeEntity sender) { _notifiedStateChangeEntities.Add(sender); }
public void Restore(RuntimeEntity entity) { // if we don't have an entity cache then we have nothing to restore if (_entityCache == null) { return; } if (_entityCache.UpdateCache(entity) == EntityCache.CacheChangeResult.Added) { DoAdd(entity); } }
public IEntity Instantiate() { int id = _gameEngine.EntityIdGenerator.Next(); EventNotifier eventNotifier = _gameEngine.EventNotifier; RuntimeEntity entity = new RuntimeEntity(id, this, eventNotifier); _gameEngine.AddEntity(entity); return entity; }
/// <summary> /// Called when an entity has data state changes /// </summary> private void OnEntityDataStateChanged(RuntimeEntity sender) { _notifiedStateChangeEntities.Add(sender); }
/// <summary> /// Called when an Entity has been modified. /// </summary> private void OnEntityModified(RuntimeEntity sender) { _notifiedModifiedEntities.Add(sender); }
/// <summary> /// Helper method that returns the _entities unordered list metadata. /// </summary> private UnorderedListMetadata GetEntitiesListFromMetadata(RuntimeEntity entity) { return(entity.Metadata.UnorderedListMetadata[_entityUnorderedListMetadataKey]); }
/// <summary> /// Removes the given entity from the world. /// </summary> /// <param name="instance">The entity instance to remove</param> internal void RemoveEntity(RuntimeEntity instance) { _notifiedRemovedEntities.Add(instance); EventNotifier.Submit(HideEntityEvent.Create(instance)); }
private void UpdateEntitiesWithStateChanges() { // update our list of added and removed entities _addedEntities.Clear(); _removedEntities.Clear(); _notifiedAddingEntities.IterateAndClear(entity => _addedEntities.Add(entity)); _notifiedRemovedEntities.IterateAndClear(entity => _removedEntities.Add(entity)); ++UpdateNumber; // Add entities for (int i = 0; i < _addedEntities.Count; ++i) { RuntimeEntity toAdd = _addedEntities[i]; InternalAddEntity(toAdd); // apply initialization changes toAdd.ApplyModifications(); } // can't clear b/c it is shared // copy our state change entities notice that we do this after adding entities, because // adding entities triggers the data state change notifier _notifiedStateChangeEntities.IterateAndClear(entity => _stateChangeEntities.Add(entity)); // Remove entities for (int i = 0; i < _removedEntities.Count; ++i) { RuntimeEntity toRemove = _removedEntities[i]; // remove listeners toRemove.ModificationNotifier.Listener -= OnEntityModified; toRemove.DataStateChangeNotifier.Listener -= OnEntityDataStateChanged; // remove all data from the entity and then push said changes out foreach (DataAccessor accessor in toRemove.SelectData()) { toRemove.RemoveData(accessor); } toRemove.DataStateChangeUpdate(); // remove the entity from the list of entities _entities.Remove(toRemove, GetEntitiesListFromMetadata(toRemove)); EventNotifier.Submit(DestroyedEntityEvent.Create(toRemove)); // notify listeners we removed an event EventNotifier.Submit(EntityRemovedEvent.Create(toRemove)); // remove it from the index _entityIndex.RemoveEntity(toRemove); } // can't clear b/c it is shared // Do a data state change on the given items. { int i = 0; while (i < _stateChangeEntities.Count) { if (_stateChangeEntities[i].NeedsMoreDataStateChangeUpdates() == false) { // reset the notifier so it can be added to the _stateChangeEntities again _stateChangeEntities[i].DataStateChangeNotifier.Reset(); _stateChangeEntities.RemoveAt(i); } else { _stateChangeEntities[i].DataStateChangeUpdate(); ++i; } } } // apply the modifications to the modified entities this data is not shared, so we can // clear it _notifiedModifiedEntities.IterateAndClear(modified => { modified.ApplyModifications(); }); // update the global entity _globalEntity.ApplyModifications(); _globalEntity.DataStateChangeUpdate(); }
/// <summary> /// Called when an Entity has been modified. /// </summary> private void OnEntityModified(RuntimeEntity sender) { _notifiedModifiedEntities.Add(sender); }
/// <summary> /// Helper method that returns the _entities unordered list metadata. /// </summary> private UnorderedListMetadata GetEntitiesListFromMetadata(RuntimeEntity entity) { return entity.Metadata.UnorderedListMetadata[_entityUnorderedListMetadataKey]; }
/// <summary> /// Internal method to add an entity to the entity manager and register it with all /// associated systems. This executes the add immediately. /// </summary> /// <param name="toAdd">The entity to add.</param> private void InternalAddEntity(RuntimeEntity toAdd) { toAdd.GameEngine = this; // notify listeners that we both added and created the entity Log<GameEngine>.Info("Submitting internal EntityAddedEvent for " + toAdd); EventNotifier.Submit(EntityAddedEvent.Create(toAdd)); EventNotifier.Submit(ShowEntityEvent.Create(toAdd)); // add it to the entity index _entityIndex.AddEntity(toAdd); // register listeners toAdd.ModificationNotifier.Listener += OnEntityModified; toAdd.DataStateChangeNotifier.Listener += OnEntityDataStateChanged; // notify ourselves of data state changes so that it the entity is pushed to systems toAdd.DataStateChangeNotifier.Notify(); // ensure it contains metadata for our keys toAdd.Metadata.UnorderedListMetadata[_entityUnorderedListMetadataKey] = new UnorderedListMetadata(); // add it our list of entities _entities.Add(toAdd, GetEntitiesListFromMetadata(toAdd)); }
/// <summary> /// Runs bookkeeping on the system. All systems concurrently run this function. This /// function makes an *extremely* important guarantee that there will be no external API /// calls made that can modify the state of other systems that are currently executing. /// </summary> public void BookkeepingBeforeRunningSystems() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); try { // if we don't have entity cache (for example, the system could just have a // GlobalInput trigger), then we don't need to do any bookkeeping if (_entityCache == null) { return; } // copy our modified entities into our dispatch modified list we do this before // state changes so that we only have to remove from _dispatchModified and not // _notifiedModifiedEntities if (_triggerModified != null) { _dispatchModified.Clear(); _notifiedModifiedEntities.IterateAndClear(entity => _dispatchModified.Add(entity)); } // process entities that were added to the system for (int i = 0; i < _shared.AddedEntities.Count; ++i) { RuntimeEntity added = _shared.AddedEntities[i]; if (_entityCache.UpdateCache(added) == EntityCache.CacheChangeResult.Added) { DoAdd(added); _dispatchAdded.Add(added); } } PerformanceData.AddedTicks = stopwatch.ElapsedTicks; // process state changes for (int i = 0; i < _shared.StateChangedEntities.Count; ++i) // immutable { RuntimeEntity stateChanged = _shared.StateChangedEntities[i]; switch (_entityCache.UpdateCache(stateChanged)) { case EntityCache.CacheChangeResult.Added: DoAdd(stateChanged); _dispatchAdded.Add(stateChanged); break; case EntityCache.CacheChangeResult.Removed: DoRemove(stateChanged); _dispatchRemoved.Add(stateChanged); break; } } PerformanceData.StateChangeTicks = stopwatch.ElapsedTicks - PerformanceData.AddedTicks; // process entities that were removed from the system for (int i = 0; i < _shared.RemovedEntities.Count; ++i) { RuntimeEntity removed = _shared.RemovedEntities[i]; if (_entityCache.Remove(removed)) { DoRemove(removed); _dispatchRemoved.Add(removed); } } PerformanceData.RemovedTicks = stopwatch.ElapsedTicks - PerformanceData.AddedTicks - PerformanceData.StateChangeTicks; } catch (Exception e) { _shared.Exceptions.Add(e); } finally { PerformanceData.BookkeepingTicks = stopwatch.ElapsedTicks; } }
private void DoRemove(RuntimeEntity removed) { // if we removed an entity from the cache, then we don't want to hear of any more // modification events if (_triggerModified != null) { removed.ModificationNotifier.Listener -= ModificationNotifier_Listener; // We have to remove the entity from our list of entities to dispatch, as during the // frame when OnRemoved is called OnModified (and also OnUpdate) will not be // invoked. _dispatchModified.Remove(removed); } }
/// <summary> /// Removes the given entity from the world. /// </summary> /// <param name="instance">The entity instance to remove</param> internal void RemoveEntity(RuntimeEntity instance) { _notifiedRemovedEntities.Add(instance); EventNotifier.Submit(HideEntityEvent.Create(instance)); }
/// <summary> /// Updates the status of the entity inside of the cache; ie, if the entity is now /// passing the filter but was not before, then it will be added to the cache. /// </summary> /// <returns>The change in cache status for the entity</returns> public CacheChangeResult UpdateCache(RuntimeEntity entity) { UnorderedListMetadata metadata = GetMetadata(entity); bool passed = _filter.Check(entity); bool contains = CachedEntities.Contains(entity, metadata); // The entity is not in the cache it now passes the filter, so add it to the cache if (contains == false && passed) { CachedEntities.Add(entity, metadata); return CacheChangeResult.Added; } // The entity is in the cache but it no longer passes the filter, so remove it if (contains && passed == false) { CachedEntities.Remove(entity, metadata); return CacheChangeResult.Removed; } // no change to the cache return CacheChangeResult.NoChange; }
/// <summary> /// Called when an entity that is contained within the cache has been modified. /// </summary> /// <remarks> /// This function is only called if we have a modification trigger to invoke. /// </remarks> private void ModificationNotifier_Listener(RuntimeEntity entity) { // Notice that we cannot check to see if the entity passes the modification filter here, // because this callback is just informing us that the entity has been modified; it does // not mean that the entity is done being modified. // // In other words, the entity may fail the modification filter check now, but at a later // point in time the check may succeed. _notifiedModifiedEntities.Add(entity); }
public GameEngine(string snapshotJson, string templateJson) { _templateJson = templateJson; // Create our own little island of references with its own set of templates GameSnapshotRestorer restorer = GameSnapshotRestorer.Restore( snapshotJson, templateJson, Maybe.Just(this)); GameSnapshot snapshot = restorer.GameSnapshot; EntityIdGenerator = snapshot.EntityIdGenerator; _systems = snapshot.Systems; _entityIndex = new EntityIndex(); // TODO: ensure that when correctly restore UpdateNumber //UpdateNumber = updateNumber; _globalEntity = (RuntimeEntity)snapshot.GlobalEntity; EventNotifier.Submit(EntityAddedEvent.Create(_globalEntity)); foreach (var entity in snapshot.AddedEntities) { AddEntity((RuntimeEntity)entity); } foreach (var entity in snapshot.ActiveEntities) { RuntimeEntity runtimeEntity = (RuntimeEntity)entity; // add the entity InternalAddEntity(runtimeEntity); // TODO: verify that if the modification notifier is already triggered, we can // ignore this //if (((ContentEntity)entity).HasModification) { // runtimeEntity.ModificationNotifier.Notify(); //} // done via InternalAddEntity //if (deserializedEntity.HasStateChange) { // deserializedEntity.Entity.DataStateChangeNotifier.Notify(); //} } foreach (var entity in snapshot.RemovedEntities) { RuntimeEntity runtimeEntity = (RuntimeEntity)entity; // add the entity InternalAddEntity(runtimeEntity); // TODO: verify that if the modification notifier is already triggered, we can // ignore this //if (((ContentEntity)entity).HasModification) { // runtimeEntity.ModificationNotifier.Notify(); //} // done via InternalAddEntity //if (deserializedEntity.HasStateChange) { // deserializedEntity.Entity.DataStateChangeNotifier.Notify(); //} RemoveEntity(runtimeEntity); } TemplateIndex templateIndex = new TemplateIndex(restorer.Templates.Templates); _executionGroups = new List <ExecutionGroup>(); var executionGroups = SystemExecutionGroup.GetExecutionGroups(snapshot.Systems); foreach (var executionGroup in executionGroups) { List <MultithreadedSystem> multithreadedSystems = new List <MultithreadedSystem>(); foreach (var system in executionGroup.Systems) { MultithreadedSystem multithreaded = CreateMultithreadedSystem(system, templateIndex); multithreadedSystems.Add(multithreaded); } _executionGroups.Add(new ExecutionGroup(multithreadedSystems)); } _nextState = GameEngineNextState.SynchronizeState; SynchronizeState().Wait(); // call of the engine loaded systems foreach (var group in _executionGroups) { foreach (var system in group.Systems) { var onLoaded = system.System as Trigger.OnEngineLoaded; if (onLoaded != null) { onLoaded.OnEngineLoaded(EventNotifier); // TODO: verify that OnEngineLoaded didn't change any state (via hashing) } } } }
private void DoAdd(RuntimeEntity added) { if (_triggerModified != null) { added.ModificationNotifier.Listener += ModificationNotifier_Listener; } }
public GameEngine(string snapshotJson, string templateJson) { _templateJson = templateJson; // Create our own little island of references with its own set of templates GameSnapshotRestorer restorer = GameSnapshotRestorer.Restore( snapshotJson, templateJson, Maybe.Just(this)); GameSnapshot snapshot = restorer.GameSnapshot; EntityIdGenerator = snapshot.EntityIdGenerator; _systems = snapshot.Systems; _entityIndex = new EntityIndex(); // TODO: ensure that when correctly restore UpdateNumber //UpdateNumber = updateNumber; _globalEntity = (RuntimeEntity)snapshot.GlobalEntity; EventNotifier.Submit(EntityAddedEvent.Create(_globalEntity)); foreach (var entity in snapshot.AddedEntities) { AddEntity((RuntimeEntity)entity); } foreach (var entity in snapshot.ActiveEntities) { RuntimeEntity runtimeEntity = (RuntimeEntity)entity; // add the entity InternalAddEntity(runtimeEntity); // TODO: verify that if the modification notifier is already triggered, we can // ignore this //if (((ContentEntity)entity).HasModification) { // runtimeEntity.ModificationNotifier.Notify(); //} // done via InternalAddEntity //if (deserializedEntity.HasStateChange) { // deserializedEntity.Entity.DataStateChangeNotifier.Notify(); //} } foreach (var entity in snapshot.RemovedEntities) { RuntimeEntity runtimeEntity = (RuntimeEntity)entity; // add the entity InternalAddEntity(runtimeEntity); // TODO: verify that if the modification notifier is already triggered, we can // ignore this //if (((ContentEntity)entity).HasModification) { // runtimeEntity.ModificationNotifier.Notify(); //} // done via InternalAddEntity //if (deserializedEntity.HasStateChange) { // deserializedEntity.Entity.DataStateChangeNotifier.Notify(); //} RemoveEntity(runtimeEntity); } TemplateIndex templateIndex = new TemplateIndex(restorer.Templates.Templates); _executionGroups = new List<ExecutionGroup>(); var executionGroups = SystemExecutionGroup.GetExecutionGroups(snapshot.Systems); foreach (var executionGroup in executionGroups) { List<MultithreadedSystem> multithreadedSystems = new List<MultithreadedSystem>(); foreach (var system in executionGroup.Systems) { MultithreadedSystem multithreaded = CreateMultithreadedSystem(system, templateIndex); multithreadedSystems.Add(multithreaded); } _executionGroups.Add(new ExecutionGroup(multithreadedSystems)); } _nextState = GameEngineNextState.SynchronizeState; SynchronizeState().Wait(); // call of the engine loaded systems foreach (var group in _executionGroups) { foreach (var system in group.Systems) { var onLoaded = system.System as Trigger.OnEngineLoaded; if (onLoaded != null) { onLoaded.OnEngineLoaded(EventNotifier); // TODO: verify that OnEngineLoaded didn't change any state (via hashing) } } } }