fix crash when removing a specific component from an entity the same frame the entity is destroyed

pull/5/head
Evan Hemsley 2019-07-10 18:22:08 -07:00
parent caac238ff9
commit 751d36a844
4 changed files with 47 additions and 15 deletions

View File

@ -18,18 +18,18 @@ namespace Encompass
private readonly List<Guid> activeComponents = new List<Guid>(); private readonly List<Guid> activeComponents = new List<Guid>();
private readonly List<Guid> inactiveComponents = new List<Guid>(); private readonly List<Guid> inactiveComponents = new List<Guid>();
private readonly List<Guid> componentsToActivate = new List<Guid>(); private readonly HashSet<Guid> componentsToActivate = new HashSet<Guid>();
private readonly List<Guid> componentsToDeactivate = new List<Guid>(); private readonly HashSet<Guid> componentsToDeactivate = new HashSet<Guid>();
private readonly List<Guid> componentsToRemove = new List<Guid>(); private readonly HashSet<Guid> componentsToRemove = new HashSet<Guid>();
//shared references with EntityManager //shared references with EntityManager
private readonly List<Guid> entitiesWithAddedComponents; private readonly HashSet<Guid> entitiesWithAddedComponents;
private readonly List<Guid> entitiesWithRemovedComponents; private readonly HashSet<Guid> entitiesWithRemovedComponents;
public ComponentManager( public ComponentManager(
DrawLayerManager drawLayerManager, DrawLayerManager drawLayerManager,
List<Guid> entitiesWithAddedComponents, HashSet<Guid> entitiesWithAddedComponents,
List<Guid> entitiesWithRemovedComponents HashSet<Guid> entitiesWithRemovedComponents
) )
{ {
this.drawLayerManager = drawLayerManager; this.drawLayerManager = drawLayerManager;

View File

@ -12,15 +12,15 @@ namespace Encompass
private readonly Dictionary<Type, HashSet<IEntityTracker>> componentTypeToEntityTrackers = new Dictionary<Type, HashSet<IEntityTracker>>(); private readonly Dictionary<Type, HashSet<IEntityTracker>> componentTypeToEntityTrackers = new Dictionary<Type, HashSet<IEntityTracker>>();
private readonly Dictionary<Guid, HashSet<IEntityTracker>> entityToEntityTrackers = new Dictionary<Guid, HashSet<IEntityTracker>>(); private readonly Dictionary<Guid, HashSet<IEntityTracker>> entityToEntityTrackers = new Dictionary<Guid, HashSet<IEntityTracker>>();
private readonly List<Guid> entitiesWithAddedComponents; private readonly HashSet<Guid> entitiesWithAddedComponents;
private readonly List<Guid> entitiesWithRemovedComponents; private readonly HashSet<Guid> entitiesWithRemovedComponents;
private readonly ComponentManager componentManager; private readonly ComponentManager componentManager;
public EntityManager( public EntityManager(
ComponentManager componentManager, ComponentManager componentManager,
List<Guid> entitiesWithAddedComponents, HashSet<Guid> entitiesWithAddedComponents,
List<Guid> entitiesWithRemovedComponents HashSet<Guid> entitiesWithRemovedComponents
) )
{ {
this.componentManager = componentManager; this.componentManager = componentManager;

View File

@ -22,8 +22,8 @@ namespace Encompass
public WorldBuilder() public WorldBuilder()
{ {
var entitiesWithAddedComponents = new List<Guid>(); var entitiesWithAddedComponents = new HashSet<Guid>();
var entitiesWithRemovedComponents = new List<Guid>(); var entitiesWithRemovedComponents = new HashSet<Guid>();
drawLayerManager = new DrawLayerManager(); drawLayerManager = new DrawLayerManager();
componentManager = new ComponentManager(drawLayerManager, entitiesWithAddedComponents, entitiesWithRemovedComponents); componentManager = new ComponentManager(drawLayerManager, entitiesWithAddedComponents, entitiesWithRemovedComponents);
entityManager = new EntityManager(componentManager, entitiesWithAddedComponents, entitiesWithRemovedComponents); entityManager = new EntityManager(componentManager, entitiesWithAddedComponents, entitiesWithRemovedComponents);

View File

@ -435,8 +435,40 @@ namespace Tests
world.Update(0.01f); world.Update(0.01f);
Assert.That(results, Does.Not.Contain(new KeyValuePair<Guid, MockComponent>(componentID, mockComponent))); Assert.That(results, Does.Not.Contain((componentID, mockComponent)));
Assert.That(results, Does.Not.Contain(new KeyValuePair<Guid, MockComponent>(componentBID, mockComponent))); Assert.That(results, Does.Not.Contain((componentBID, mockComponent)));
}
class DestroyAndAddComponentEngine : Engine
{
public override void Update(double dt)
{
foreach (var componentPair in ReadComponents<DestroyerComponent>())
{
var componentID = componentPair.Item1;
var entity = GetEntityByComponentID(componentID);
var (id, _) = entity.GetComponent<MockComponent>();
entity.RemoveComponent(id);
Destroy(entity.id);
}
}
}
[Test]
public void DestroyEntityWhileRemovingComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new DestroyAndAddComponentEngine());
worldBuilder.AddEngine(new ReaderEngine());
var entity = worldBuilder.CreateEntity();
entity.AddComponent(new DestroyerComponent());
entity.AddComponent(new MockComponent());
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.01));
} }
static Entity entityFromComponentIDResult; static Entity entityFromComponentIDResult;