Giter VIP home page Giter VIP logo

dominion-ecs-java's People

Contributors

endison1986 avatar enricostara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dominion-ecs-java's Issues

When I create entities and add components in multiple threads, there are unforeseen concurrency issues

In my actual project, I create monster entities in a System. In order to take advantage of multi-core, I use parallelStream and create monster entities in it, and cache the Entity to Component, but I found that in the next System, the Entity in the Component obtained by the context.findEntitiesWith() method is different from the hashCode of ResultSet.entity()

example code like this.

public enum State {
    S1, S2, S3;
}

public static class C {
    private final Entity entity;

    public C(Entity entity) {
        this.entity = entity;
    }
}

public static class B {

}

public static class A {
    private C c;

    public A(Dominion dominion) {
        c = new C(dominion.createEntity(this));
        c.entity.setState(S1);
    }
}

public static void main(String[] args) {
    final Dominion dominion = Dominion.create();
    final var list = List.<Runnable>of(() -> {
        for (int i = 0; i < 200; i++) {
            final var a = new A(dominion);
            a.c.entity.add(new B());
        }
    }, () -> {
        for (int i = 0; i < 200; i++) {
            final var a = new A(dominion);
            a.c.entity.add(new B());
        }
    }, () -> {
        for (int i = 0; i < 200; i++) {
            final var a = new A(dominion);
            a.c.entity.add(new B());
        }
    });
    final var scheduler = dominion.createScheduler();
    scheduler.schedule(() -> list.parallelStream().forEach(Runnable::run));
    scheduler.schedule(() -> {
        dominion.findEntitiesWith(A.class).stream().forEach(rs->{
            if(rs.entity().hashCode() != rs.comp().c.entity.hashCode()) {
                System.out.println("1111111111111111111");
                System.exit(-1);
            }
        });
        System.exit(0);
    });
    scheduler.tickAtFixedRate(10);
}

If I remove a.c.entity.add(new B());, the program is fine.
If I change paralleStream() to stream(), this program is fine.

When I created entities in parallel, some errors occurred

this code is fine.

public static void main(String[] args) {
    final Dominion dominion = Dominion.create();
    final var list = List.<Runnable>of(() -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    });
    final var scheduler = dominion.createScheduler();
    scheduler.schedule(() -> list.parallelStream().forEach(Runnable::run));
    scheduler.tickAtFixedRate(10);
}

this code is also fine.

public static void main(String[] args) {
    final Dominion dominion = Dominion.create();
    final var list = List.<Runnable>of(() -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B()).add(new C());
        }
    });
    final var scheduler = dominion.createScheduler();
    scheduler.schedule(() -> list.stream().forEach(Runnable::run));
    scheduler.tickAtFixedRate(10);
}

but I get some error with this code

public static void main(String[] args) {
    final Dominion dominion = Dominion.create();
    final var list = List.<Runnable>of(() -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B());
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            dominion.createEntity(new A()).add(new B()).add(new C());
        }
    });
    final var scheduler = dominion.createScheduler();
    scheduler.schedule(() -> list.parallelStream().forEach(Runnable::run));

    scheduler.tickAtFixedRate(10);
}
  严重         dominion.SystemScheduler invoke 
java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=1, dataLength=1, capacity=4096, size=0, previous=null, next=null, of Tenant={id=1, dataLength=1, nextId=|0:1:0|, subject=root}}] retrieved by [4097]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=1, dataLength=1, capacity=4096, size=0, previous=null, next=null, of Tenant={id=1, dataLength=1, nextId=|0:1:0|, subject=root}}] retrieved by [4097]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:689)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:765)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.Test.lambda$main$3(Test.java:38)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=1, dataLength=1, capacity=4096, size=0, previous=null, next=null, of Tenant={id=1, dataLength=1, nextId=|0:1:0|, subject=root}}] retrieved by [4097]
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.collections.ChunkedPool$Tenant.freeId(ChunkedPool.java:273)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.collections.ChunkedPool$Tenant.freeId(ChunkedPool.java:263)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.CompositionRepository.modifyComponents(CompositionRepository.java:167)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.CompositionRepository.addComponent(CompositionRepository.java:185)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.IntEntity.add(IntEntity.java:91)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.Test.lambda$main$2(Test.java:34)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
	... 5 more

and this code

public static void main(String[] args) {
    final Dominion dominion = Dominion.create();
    final var list = List.<Runnable>of(() -> {
        for (int i = 0; i < 100; i++) {
            final var entity = dominion.createEntity(new A()).setState(S1);
            entity.add(new B());
            entity.setState(S2);
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            final var entity = dominion.createEntity(new A()).setState(S1);
            entity.add(new B());
            entity.setState(S2);
        }
    }, () -> {
        for (int i = 0; i < 100; i++) {
            final var entity = dominion.createEntity(new A()).setState(S1);
            entity.add(new B());
            entity.setState(S3);
        }
    });
    final var scheduler = dominion.createScheduler();
    scheduler.schedule(() -> list.parallelStream().forEach(Runnable::run));
    scheduler.tickAtFixedRate(10);
}
  严重         dominion.SystemScheduler invoke 
java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=2, dataLength=0, capacity=4096, size=1, previous=null, next=null, of Tenant={id=2, dataLength=0, nextId=|0:2:0|, subject=|1085:[4, 0]|}}] retrieved by [8194]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=2, dataLength=0, capacity=4096, size=1, previous=null, next=null, of Tenant={id=2, dataLength=0, nextId=|0:2:0|, subject=|1085:[4, 0]|}}] retrieved by [8194]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:562)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:689)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:765)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.FixBug.lambda$main$3(FixBug.java:51)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.IllegalArgumentException: Invalid chunkById [LinkedChunk={id=2, dataLength=0, capacity=4096, size=1, previous=null, next=null, of Tenant={id=2, dataLength=0, nextId=|0:2:0|, subject=|1085:[4, 0]|}}] retrieved by [8194]
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.collections.ChunkedPool$Tenant.freeId(ChunkedPool.java:273)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.collections.ChunkedPool$Tenant.freeStateId(ChunkedPool.java:267)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.IntEntity.setState(IntEntity.java:168)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.FixBug.lambda$main$0(FixBug.java:35)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:720)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:754)
	... 5 more

A concurrency issue

During development, I got an exception log that looked like it was looping to a null value. So I wrote a piece of test code to try to restore the error. Judging from the test code, this should be a concurrency issue.

Is this result expected?

dominion.SystemScheduler invoke 
java.lang.NullPointerException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:564)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:280)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:257)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "dev.dominion.ecs.engine.collections.ChunkedPool$Item.getChunk()" because "item" is null
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.collections.ChunkedPool$PoolDataIteratorWithState.next(ChunkedPool.java:754)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.DataComposition$IteratorWith1Next.next(DataComposition.java:306)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.DataComposition$IteratorWith1Next.next(DataComposition.java:294)
	at java.base/java.lang.Iterable.forEach(Iterable.java:74)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.Test.lambda$main$0(Test.java:34)
	at dev.dominion.ecs.engine/dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

Test code:

public class Test {
    public enum S {
        A, B
    }
    public record A(int id) {
    }
    public static void consume(Object c) {
        try {
            TimeUnit.MILLISECONDS.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) {
        EntityRepository entityRepository = (EntityRepository) new EntityRepository.Factory().create("test");
        final var list = new ArrayList<Entity>(1000);
        for (int i = 0; i < 1000; i++) {
            list.add(entityRepository.createEntity(new A(i)).setState(S.A));
        }
        Scheduler scheduler = entityRepository.createScheduler();

        scheduler.schedule(() -> entityRepository.findEntitiesWith(A.class).withState(S.A).forEach(Test::consume));


        new Thread(() -> {
            while (true) {
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                    for (int i = 0; i < 1000; i++) {
                        list.get(i).setState(S.B);
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();

        scheduler.tickAtFixedRate(20);
    }
}

QUESTION: referencing another entities and direct component access

I'm trying to implement a basic Transform component like in Godot or Unity.

The main idea is that the parent should affect the children, for that I need some way to reference them and then query the component.

I saw that there is an IntEntity with getId(), but this is not a public API and requests cannot be made using these identifiers. Also Entity doesn't have methods to access components.

Can we expect such functionality in the future or is there some other way to implement it?

Bug with Inheritance

Through my time of attempting to use this ecs I noticed one glaring problem. That problem being that this ecs does not play nicely with components that utilize inheritance. In the example below we create two entities where one uses the super class component and the other uses the subclass component.

public class Main {
    public static void main(String[] args) {
        Dominion dom = Dominion.create();
        dom.createEntity(new DemoA());
        dom.createEntity(new DemoB());
        Scheduler scheduler = dom.createScheduler();
        scheduler.schedule(() -> {
            System.out.println("ALL DEMOA COMPONENTS");
            dom.findCompositionsWith(DemoA.class)
            .stream().forEach(r -> r.onExec());
        });
        scheduler.schedule(() -> {
            System.out.println("ALL DEMOB COMPONENTS");
            dom.findCompositionsWith(DemoB.class)
            .stream().forEach(r -> r.onExec());
        });    
        scheduler.tick();
        scheduler.shutDown();
    }
    private static class DemoA {
        public void onExec() {
            System.out.println("A");
        }
    }
    private static class DemoB extends DemoA {
        @Override
        public void onExec() {
            System.out.println("B");
        }
    }
}

Now the expected result is that since DemoB inheriets from DemoA, when we query for compositions utalizing DemoA, the entitiy that has DemoB would be type casted into DemoA producing the result below:

ALL DEMOA COMPONENTS
A
B
ALL DEMOB COMPONENTS
B

However when the example is run it produces the following result:

ALL DEMOA COMPONENTS
A
ALL DEMOB COMPONENTS
B

Regardless of if this is a bug or the intended implementation by the author I believe that dominion needs to support inheritance as it is a must have in more complex systems that benefits from the ECS paradigm such as physics and graphics engines.

Cannot found entity after some and/remove operation

Hi @enricostara , this is my test code

var d = Dominion.create();
var entity = d.createEntity(new A());
var s = d.createScheduler();
s.schedule(() -> {
    d.findEntitiesWith(A.class, C.class).stream().forEach(rs -> {
        try {
            System.out.println("AAAA");
            if (!rs.entity().has(B.class)) {
                rs.entity().add(new B());
            }
        } finally {
            rs.entity().removeType(C.class);
        }
    });
});
s.schedule(() -> {
    d.findEntitiesWith(A.class, B.class).stream().forEach(rs -> {
        System.out.println("BBBBBB");
    });
});
/// always handle the A.class
s.schedule(() -> {
    System.out.println("Before CCCC");
    d.findEntitiesWith(A.class).stream().forEach(rs -> {
        System.out.println("CCCCCCCCCCCC");
    });
});
s.tickAtFixedRate(1);
TimeUnit.SECONDS.sleep(2);
entity.add(new C());

I have three component (A,B,C)and three system, always have a system to handle A.class. In the initial situation, the system operation is normal,but when I add C.class and add B.class then remove C.class, the system is not working

My version is 0.9.0-SNAPSHOT, you can run my test code and see the output.

Hi @enricostara I get a new error when I add a second component `B`

Hi @enricostara I get a new error when I add a second component B

public static void main(String[] args) {
    var d = Dominion.create();
    var s = d.createScheduler();
    s.schedule(() -> {
        d.findEntitiesWith(A.class, B.class).iterator();
    });

    for(var i = 0; i < 50; i++) {
        new Thread(()-> {
            for(var j = 0; j< 100; j++) {
                d.createEntity(new A(), new B());
            }
        }).start();
    }

    s.tickAtFixedRate(3);
}
Exception in thread "Thread-0" Exception in thread "Thread-9" Exception in thread "Thread-13" Exception in thread "Thread-2" Exception in thread "Thread-4" Exception in thread "Thread-10" Exception in thread "Thread-15" Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-12" Exception in thread "Thread-14" Exception in thread "Thread-7" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-8" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-5" Exception in thread "Thread-11" Exception in thread "Thread-6" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "Thread-3" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)
java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 4
	at dev.dominion.ecs.engine.system.ClassIndex.getIndexKey(ClassIndex.java:153)
	at dev.dominion.ecs.engine.CompositionRepository.getOrCreate(CompositionRepository.java:92)
	at dev.dominion.ecs.engine.EntityRepository.createEntity(EntityRepository.java:44)
	at dev.dominion.ecs.engine.TestClass.lambda$main$1(VirtualWorld.java:53)
	at java.base/java.lang.Thread.run(Thread.java:833)

Originally posted by @endison1986 in #117 (comment)

Add Ability to Retrieve All Entities

Description

Would it be possible to add an option to the API to retrieve all entities?

I am currently using a workaround where I add a dummy component to all entities and then just do:

dominion.findEntitiesWith(FillerComponent.class).iterator();

And then just iterate through it to get a list of all my entities, while it works, it would be nicer if I did not have to add a dummy component.

Use case

I wanted to fetch all entities for a debug menu so that I could implement a GUI where I can just click to select an entity from the list to add or remove a component from UI during testing. This is a lot faster than having to make all component changes programmatically.

A question about Item

Hi @enricostara ,I have a question, are the Item interface and LinkedChunk generics necessary? Why not use the IntEntity array directly, so that there is no performance loss of unpacking?

withState() doesn't seem to be working

This is an enum I'm using to categorize entities.

package components;

public enum EntityType {
    CUE, BALL, POCKET, WALL;
}

When I do

List<With1<EntityType>> cueResult = GameWorld.get().getDominion()
                .findEntitiesWith(EntityType.class)
                .stream().collect(Collectors.toList());

cueResult has size() 18 and contains With1[comp=CUE, entity=Entity={id=|0:5:0|-> [CUE, java.awt.Color[r=255,g=255,b=255], models.Transform2@3d75a2cf, colliders.ColliderComponent@788dcd3c, bodies.Body@55dc666e, components.TagCue@6ef8985a], stateId=|1:0:0|, enabled=true}]

When I do

List<With1<EntityType>> cueResult = GameWorld.get().getDominion()
                .findEntitiesWith(EntityType.class)
                .withState(EntityType.CUE)
                .stream().collect(Collectors.toList());

cueResult has size 0

Either I don't understand what withState() is intended to do or there is a bug.

In the meantime I've just used a tag class to accomplish the same goal

With1<TagCue> cueResult = GameWorld.get().getDominion().findEntitiesWith(TagCue.class).stream().findFirst().orElse(null);

about thread safe

I use dominion on the server side,so there are some question about thread safe.
I need createEntity, addComponent or removeComponent, above action must run in System?
If I want to do above action in network thread,will there be any thread safety issues?

QUESTION: Is it possible to work with entities with more than 6 components?

Right now, the Dominion.findEntitiesWith() method accepts up to 6 component types. The returned Results object maps the types for each component by position and allows for their retrieval. Is there a mechanism in place to enable finding and working with entities with more than 6 components? Is this something that will come at a later stage?

`ClassIndex` does not handle duplicate identity hash codes

I may be wrong, but ClassIndex does not seem to handle System.identityHashCode returning the same for two distinct classes, as collision detection is only implemented based on the even smaller hashBits field. Which is an unlikely scenario, but not impossible.

how to get component from entity

how to get component from entity?

Dominion dominion= Dominion.create();
dominion.createEntity(comp1, comp2);
/// ....

final var scheduler = dominion.createSchduler();
scheduler.schedule(()->{
  dominion.findEntitiesWith(Component1.class, Component2.class).stream().forEach(rs->{
    final var entity = rs.entity();
    ///...
    if(entity.has(Component3.class)) {
        final var comp3 = entity.get(Component3.class);
    } else {
        fianl var comp3 = new Component3();
        ///... to config comp3
        entity.add(comp3);
    }
  });
});

scheduler.tickAtFixedRate(3);

NullPointerException and ArrayIndexOutOfBoundsException

@enricostara I define three component, A,B,C

public static class A{}
public static class B{}
public static class C{}

This is my test code:

it's fine.

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A());
    s.tickAtFixedRate(60);
}

I get NullPointerException

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class, B.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A());
    s.tickAtFixedRate(60);
}
dominion.SystemScheduler invoke 
java.lang.NullPointerException
	at java.base/jdk.internal.reflect.GeneratedConstructorAccessor1.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:564)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot load from int array because "this.componentIndex" is null
	at dev.dominion.ecs.engine.DataComposition.fetchComponentIndex(DataComposition.java:69)
	at dev.dominion.ecs.engine.DataComposition.select(DataComposition.java:173)
	at dev.dominion.ecs.engine.ResultSet$With2.compositionIterator(ResultSet.java:208)
	at dev.dominion.ecs.engine.ResultSet.iterator(ResultSet.java:56)
	at dev.dominion.ecs.engine.ResultSet.stream(ResultSet.java:85)
	at com.yunzhi.ancientsecrets.server.common.VirtualWorld.lambda$main$1(VirtualWorld.java:37)
	at dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

it's fine

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class, B.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A(), new B());
    s.tickAtFixedRate(60);
}

I get ArrayIndexOutOfBoundsException

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class, B.class, C.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A(), new B());
    s.tickAtFixedRate(60);
}
dominion.SystemScheduler invoke 
java.lang.ArrayIndexOutOfBoundsException
	at java.base/jdk.internal.reflect.GeneratedConstructorAccessor1.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:564)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 2
	at dev.dominion.ecs.engine.collections.ChunkedPool$PoolMultiDataIterator.data(ChunkedPool.java:587)
	at dev.dominion.ecs.engine.DataComposition$IteratorWith3.next(DataComposition.java:356)
	at dev.dominion.ecs.engine.DataComposition$IteratorWith3.next(DataComposition.java:342)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at com.yunzhi.ancientsecrets.server.common.VirtualWorld.lambda$main$1(VirtualWorld.java:37)
	at dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

it's fine.

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class, B.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A(), new B(), new C());
    s.tickAtFixedRate(60);
}

I get ArrayIndexOutOfBoundsException

public static void main(String[] args) {
    var w = Dominion.create();
    var s = w.createScheduler();
    s.schedule(()-> w.findEntitiesWith(A.class, B.class).stream().forEach((rs)-> System.out.println(rs.entity())));
    w.createEntity(new A(), new C());
    s.tickAtFixedRate(60);
}
dominion.SystemScheduler invoke 
java.lang.ArrayIndexOutOfBoundsException
	at java.base/jdk.internal.reflect.GeneratedConstructorAccessor1.newInstance(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:564)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 2
	at dev.dominion.ecs.engine.collections.ChunkedPool$PoolMultiDataIterator.data(ChunkedPool.java:587)
	at dev.dominion.ecs.engine.DataComposition$IteratorWith2.next(DataComposition.java:321)
	at dev.dominion.ecs.engine.DataComposition$IteratorWith2.next(DataComposition.java:307)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at com.yunzhi.ancientsecrets.server.common.VirtualWorld.lambda$main$1(VirtualWorld.java:37)
	at dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

NullPointerException occurs

I'm tring to test a situation when i add entities and remove all after that, it occurs exception,
I fount when outer loop time less than 3 will not occurs, is this some kind of thread problem?

        // creates your world
        Dominion hello = Dominion.create();

        // creates a scheduler
        Scheduler scheduler = hello.createScheduler();

        // a system removes all entities with component Position
        Runnable s = () -> {
            hello.findEntitiesWith(Position.class).stream().forEach(e -> {
                hello.deleteEntity(e.entity());
            });
        };
        scheduler.schedule(s);

        for (int i = 0; i < 10; i++) {
            // add entities
            for (int j = 0; j < 1000; j++) {
                var e = hello.createEntity(
                        "my-entity",
                        new Position(0, 0),
                        new Velocity(1, 1)
                );
            }
            // tick to remove all entities
            scheduler.tick();
        }

Exception stacktrace:

dominion.SystemScheduler invoke 
java.lang.NullPointerException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:564)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:591)
	at java.base/java.util.concurrent.ForkJoinTask.joinForPoolInvoke(ForkJoinTask.java:1042)
	at java.base/java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:2639)
	at dev.dominion.ecs.engine.SystemScheduler.forkAndJoin(SystemScheduler.java:113)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:262)
	at dev.dominion.ecs.engine.SystemScheduler$Single.call(SystemScheduler.java:239)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "dev.dominion.ecs.engine.IntEntity$Data.composition()" because the return value of "dev.dominion.ecs.engine.IntEntity.getData()" is null
	at dev.dominion.ecs.engine.Composition$IteratorWith1.next(Composition.java:352)
	at dev.dominion.ecs.engine.Composition$IteratorWith1.next(Composition.java:340)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at com.example.demo1.Demo1Application.lambda$main$1(Demo1Application.java:24)
	at dev.dominion.ecs.engine.SystemScheduler$2.compute(SystemScheduler.java:116)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
 

Test Failures

When I run 'mvn package', some tests are failing;

[ERROR] SystemSchedulerTest.deltaTime:164 expected: <0.5> but was: <0.5152623>
[ERROR] SystemSchedulerTest.tickAtFixedRate:148 expected: <6> but was: <7>

I'm using Microsoft OpenJDK21.

Are there any logical loopholes in ClassIndex?

@enricostara hello friend, I have a question

This api ClassIndex.getIndexOrAddClasses(Class<?> klass) used for get or create index for component type. If hash codes for component types collide,Does it always return the index of the first component?

I have another question about IndexKey

@enricostara hi friend, I have another question about IndexKey
I read the source code of IndexKey,why the constructor IndexKey(int value) donot initialize the data field.
Will it cause it to obtain or overwrite the value of other IndexKey when it is used as the Key of the Map?

public final class IndexKey {
    private final int hashCode;
    private final byte[] data;

    public IndexKey(int value) {
        this.hashCode = value;
        data = null;
    }

    public IndexKey(int[] array) {...}

    public IndexKey(boolean[] checkArray, int min, int max, int length) {...}

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        return Arrays.equals(((IndexKey) o).data, data);
    }

    @Override
    public int hashCode() {
        return hashCode;
    }

    @Override
    public String toString() {...}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.