junkdog / artemis-odb

A continuation of the popular Artemis ECS framework
BSD 2-Clause "Simplified" License
779 stars 112 forks source link

NullPointerException when using PooledComponent #205

Closed chrisapril closed 10 years ago

chrisapril commented 10 years ago

Hi,

i have switched with my project from gdx-artemis to artemis-odb, but now i get this error:

Exception in thread "LWJGL Application" java.lang.NullPointerException at com.artemis.ComponentPool.free(ComponentPool.java:27) at com.artemis.ComponentManager.removeComponents(ComponentManager.java:146) at com.artemis.ComponentManager.clean(ComponentManager.java:335) at com.artemis.World.process(World.java:554)

I have deleted an entity. The exception is thrown when i call world.process() after the removal with entity.edit().deleteEntity();.

junkdog commented 10 years ago

Hi,

Which version are you using, 0.7.1?

chrisapril commented 10 years ago

I got the NullPointerException in both versions:

0.7.0: Exception in thread "LWJGL Application" java.lang.NullPointerException at com.artemis.ComponentPool.free(ComponentPool.java:27) at com.artemis.ComponentManager.removeComponentsOfEntity(ComponentManager.java:146) at com.artemis.ComponentManager.clean(ComponentManager.java:338) at com.artemis.World.process(World.java:554)

0.7.1: Exception in thread "LWJGL Application" java.lang.NullPointerException at com.artemis.ComponentPool.free(ComponentPool.java:27) at com.artemis.ComponentManager.removeComponents(ComponentManager.java:146) at com.artemis.ComponentManager.clean(ComponentManager.java:335) at com.artemis.World.process(World.java:554)

chrisapril commented 10 years ago

Here is a test to reproduce the bug (version 0.7.1):

public class Issue205SystemTest {
    /**
     * @param args
     */
    public static void main(String[] args) {

        World world = new World();
        world.initialize();

        world.setSystem((new Issue205SystemTest()).new TestSystemA("A"));
        world.setSystem((new Issue205SystemTest()).new TestSystemAB("AB"));
        world.initialize();

        Entity e = world.createEntity();
        e.edit().create(TestComponentA.class);
        e.edit().create(TestComponentB.class);

        int d = 0;

        world.setDelta(d++);
        world.process();
        System.out.println(d + "=------------------------------------------");

        System.out.println(d + "= deleting "+e);
        e.deleteFromWorld();
        System.out.println(d + "= removing components from "+e);
        e.edit().remove(TestComponentB.class);
        e.edit().remove(TestComponentA.class);

        world.setDelta(d++);
        world.process();
        System.out.println(d + "=------------------------------------------");

    }

    public static class TestComponentA extends PooledComponent {

        @Override
        protected void reset() {
        }

    }

    public static class TestComponentB extends PooledComponent {

        @Override
        protected void reset() {
        }

    }

    class TestSystemA extends EntityProcessingSystem {

        private String name;

        @SuppressWarnings("unchecked")
        public TestSystemA(String name) {
            super(Aspect.getAspectForAll(TestComponentA.class));
            this.name = name;
        }

        @Override
        protected void process(Entity e) {
            System.out.println("System [" + name + "] processed: " + e);
        }

    }

    class TestSystemAB extends EntityProcessingSystem {

        private String name;

        @SuppressWarnings("unchecked")
        public TestSystemAB(String name) {
            super(Aspect.getAspectForAll(TestComponentA.class,
                    TestComponentB.class));
            this.name = name;
        }

    @Override
        protected void process(Entity e) {
            System.out.println("System [" + name + "] processed: " + e);
        }

    }

}

Log:

System [A] processed: Entity[0] System [AB] processed: Entity[0] 1=------------------------------------------ 1= deleting Entity[0] 1= removing components from Entity[0] Exception in thread "main" java.lang.NullPointerException at com.artemis.ComponentPool.free(ComponentPool.java:27) at com.artemis.ComponentManager.removeComponents(ComponentManager.java:146) at com.artemis.ComponentManager.clean(ComponentManager.java:335) at com.artemis.World.process(World.java:554) at com.krautfactory.tests.artemis.Issue205SystemTest.main(Issue205SystemTest.java:48)

junkdog commented 10 years ago

The error comes from deleting and manually removing the components; entity deletion implies that all of its components are removed too. I've created an issue for it; hopefully the next version can handle it better.

For all intents and purposes, a deleted entity is left in an undefined state.

chrisapril commented 10 years ago

Is there a possibility to recognize a deleted Entity so that i can omit the removal of components?

junkdog commented 10 years ago

Not at the moment; deleted entities are expunged from the world right before the next system starts processing (+ at the start of World#process).