Insanely fast ECS (Entity Component System) for Java

Overview

|) () |\/| | |\| | () |\|

Java CI with Maven CodeQL

Dominion is an Entity Component System library for Java.

Entity Component System architecture promotes data-oriented programming. It’s all about data (components) and first-class functions (systems) that operate on data.

This means that, unlike OOP, data and operations are not encapsulated together in objects, which are called entities in ECS.

Entities model the business objects of the user application, and the entity promotes "composition over inheritance" by grouping a dynamic list of components to define its specific features.

Systems usually operate on components sequentially and can be very fast if data are stored in cache-friendly ways. Systems are decoupled from each other and each system knows only about the data it operates on. This strongly promotes high concurrency, running systems in parallel whenever they can independently operate on the data.

ECS architecture is particularly suitable (but not limited to) if you have to manage many objects in your application. In addition, application code tends to be more reusable and easier to extend with new functionality thanks to the components' composition and subsequent addition of new systems.

Dominion Features

  • 🚀 FAST > Dominion is not only an insanely fast ECS implemented in Java, it can also be in the same league as ECS for C, C++, and Rust - see benchmarks .
  • 🤏 TINY > Just a high-performance and high-concurrency Java library with a minimal footprint and no dependencies. So you can easily integrate the Dominion core library into your game engine or framework or use it directly for your game or application without warring about the dependency hell.
  • ☕️ SIMPLE > Dominion promotes a clean, minimal and self-explanatory API that is simple by design. A few readme pages will provide complete usage documentation.
  • 💪 with SUPPORT > Join the Discord! The server will support users and announce the availability of the new version.

Quick Start

In your local environment you must have already installed a Java 17 (or newer) and Maven.

Add the following dependency declaration in your project pom.xml:

<project>
    <!-- ... -->

    <dependencies>
        <dependency>
            <groupId>dev.dominion.ecs</groupId>
            <artifactId>dominion-ecs-engine</artifactId>
            <version>0.6.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>central-snapshot</id>
            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

Check out the Dominion API documentation as a reference to get started implementing your first app.

About Performance

Designing a high-performance and high-concurrency Java library is a piece of cake quite a challenge as the execution speed of Java code could be affected in many ways. Dominion mitigates Java's performance pitfalls by taking a few actions:

  • not just using the standard library: the Java standard library implements data structures and algorithms designed without making any assumption about the data as they are general purpose. Dominion implements some custom data structures and algorithms to increase performances and fill the gap with ECS frameworks written in system languages.
  • reducing garbage collection activities: GC could affect overall performances as its activities run concurrently with user code and without direct control. To reduce GC activities significantly, Dominion implements a very efficient pooling system to reuse objects living in a heap and creates off-heap data structures whenever possible.
  • mastering concurrency: an ECS library must be not only fast but able to scale running on a multicore CPU. Otherwise, it makes little sense today. Writing a highly concurrent library in Java requires non-blocking concurrency as much as possible and leveraging the best available lock implementation as the fast StampedLock.
  • using Java 17: only by upgrading to the Java 17 you will get a performance boost for free: Java 17 is about 8-9% faster than Java 11.
  • adding a blazing-fast logging layer: by implementing a thin logging layer over the standard System.Logger (Platform Logging API and Service - JEP 264), Dominion achieves a half nanosecond logging level check with next to no performance impact and does not require a specific dependency on the logging implementation of your choice.

Ok, enough blah blah blah..

Here is an example:

public class HelloDominion {

    public static void main(String[] args) {
        // creates your world
        Dominion hello = Dominion.create();

        // creates an entity with components
        hello.createEntity(
                "my-entity",
                new Position(0, 0),
                new Velocity(1, 1)
        );

        // creates a system
        Runnable system = () -> {
            //finds entities
            hello.findEntitiesWith(Position.class, Velocity.class)
                    // stream the results
                    .stream().forEach(result -> {
                        Position position = result.comp1();
                        Velocity velocity = result.comp2();
                        position.x += velocity.x;
                        position.y += velocity.y;
                        System.out.printf("Entity %s moved with %s to %s\n",
                                result.entity().getName(), velocity, position);
                    });
        };

        // creates a scheduler
        Scheduler scheduler = hello.createScheduler();
        // schedules the system
        scheduler.schedule(system);
        // starts 3 ticks per second
        scheduler.tickAtFixedRate(3);
    }

    // component types can be both classes and records

    static class Position {
        double x, y;

        public Position(double x, double y) {/*...*/}

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

    record Velocity(double x, double y) {
    }
}

Dominion Examples Page

Dominion comes with some documented sample apps to help adopt the solution, like the HelloDominion sample above.

The DarkEntities sample app has also been added, it could inspire a turn-based rogue-like game running on a terminal window:

Here the Dominion Examples page with all the documented code.

Dominion Release Cycle

Phase Description Distribution Git tag
Preview Features are under heavy development and often have changing requirements and scope. github-zip only none
Early Access (EA) Features are documented and ready for testing with a wider audience. maven SNAPSHOT release-EA-#
Release Candidate (RC) Features have been tested through one or more early access cycles with no known showstopper-class bugs. maven RC release-RC#
Stable Release Features have passed all verifications / tests. Stable releases are ready for production use maven RELEASE release

Dominion is officially in Early Access.

Join the Discord for further updates!

Support Dominion

If you want to support Dominion project, consider giving it a Star ⭐️

Comments
  • about thread safe

    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?

    opened by endison1986 14
  • NullPointerException and ArrayIndexOutOfBoundsException

    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)
    
    opened by endison1986 7
  • 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`

    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 https://github.com/dominion-dev/dominion-ecs-java/issues/117#issuecomment-1362534115

    opened by endison1986 3
  • NullPointerException occurs

    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)
     
    
    opened by cnwillz 3
  • how to get component from entity

    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);
    
    opened by endison1986 2
  • QUESTION: Is it possible to work with entities with more than 6 components?

    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?

    opened by langurmonkey 2
  • `ClassIndex` does not handle duplicate identity hash codes

    `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.

    opened by TheMode 2
  • QUESTION: referencing another entities and direct component access

    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?

    opened by demkom58 1
Owner
Dominion
ECS - Entity Component System
Dominion
Sceneform React Native AR Component using ARCore and Google Filament as 3D engine. This the Sceneform Maintained Component for React Native

Discord Server Join us on Discord if you need a hand or just want to talk about Sceneform and AR. Features Remote and local assets Augmented Faces Clo

SceneView Open Community 42 Dec 17, 2022
JavaReactKamp 7.gün 3.ödev gerçekleştirildi. Ödev kapsamının dışına (entity ilişkileri hariç) çıkılmadı. Entitiy ilişkileri kod kısmında ayarlandı.

JavaReactKamp-7-hrmsDemo3 -> JavaReactKamp 7.gün 3.ödev gerçekleştirildi. -> Ödev kapsamının dışına (entity ilişkileri hariç) çıkılmadı. -> Ödev kapsa

null 14 Oct 4, 2021
Get or Throw Spring boot Starter will help you to hide handling if entity not found.

Get or Throw Spring boot Starter Get or Throw Spring boot Starter will help you to hide handling if entity not found. 1. Setup 2. Usage Library adds c

null 3 Feb 2, 2022
Tons of HUD tweaks including player stats, block/entity info, etc.

Tons of HUD tweaks including player stats, block/entity info, etc. Created because I've been driven mad by the annoying process of downloading that many mods to achieve the same goal.

Intelligent Creations 9 Dec 23, 2022
A mod for OneConfig that allows you to customize the hit color of any living entity to your liking.

HitColor A mod for OneConfig that allows you to customize the hit color of any living entity to your liking. Features An option to toggle Armor being

Nox 4 Nov 5, 2022
A React Native project starter with Typescript, a theme provider with hook to easy styling component, a folder architecture ready and some configs to keep a codebase clean.

React Native Boilerplate Folder structure : src ├── assets │   ├── audios │   ├── fonts │   ├── icons │   └── images ├── components │   ├── Layout.tsx

LazyRabbit 23 Sep 1, 2022
A straight table component designed for performance

@qlik-oss/react-native-simple-grid A straight table component designed for performance Installation npm install @qlik-oss/react-native-simple-grid Usa

Qlik - Open Source Software 2 Apr 23, 2022
MiniMessage Component-based Placeholders for PaperMC and Velocity platforms

MiniMessage Component-based Placeholders for PaperMC and Velocity platforms

null 10 Dec 28, 2022
NPM Package - A react native component that let you to add a wavy background UI.

react-native-wavy-background A react native component that let you to add a wavy background UI. Installation npm install react-native-wavy-background

Shevon Soyza 10 Oct 19, 2022
GalaxyCDC is a core component of PolarDB-X which is responsible for global binary log generation, publication and subscription.

中文文档 What is ApsaraDB GalaxyCDC ? GalaxyCDC is a core component of PolarDB-X which is responsible for global binary log generation, publication and su

null 56 Dec 19, 2022
An awesome native wheel picker component for React Native.

⛏️ react-native-picky An awesome native wheel picker component for react-native. Features Supports multiple columns ✅ Supports looping ✅ Native Androi

null 28 Dec 4, 2022
Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based system

FRC 2022 Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based s

null 4 Oct 4, 2022
Flash Sale System AKA. seckill system

FlashSaleSystem Project highlights Distributed system scheme From a single machine to a cluster, it is easy to scale horizontally simply by adding ser

wsbleek 12 Sep 13, 2022
💡极致性能的企业级Java服务器框架,RPC,游戏服务器框架,web应用服务器框架。(Extreme fast enterprise Java server framework, can be RPC, game server framework, web server framework.)

?? 为性能而生的万能服务器框架 ?? Ⅰ. zfoo简介 ?? 性能炸裂,天生异步,Actor设计思想,无锁化设计,基于Spring的MVC式用法的万能RPC框架 极致序列化,原生集成的目前二进制序列化和反序列化速度最快的 zfoo protocol 作为网络通讯协议 高可拓展性,单台服务器部署,

null 1k Jan 1, 2023
A fast and reliable Java micro-library which chooses the sorting algorithm that best fits your needs and sorts the parameter.

A fast and reliable Java micro-library which chooses the sorting algorithm that best fits your needs and sorts the parameter.

Simone Nicol 2 Feb 19, 2022
A distributed lock that supports the use of Redis and Zookeeper, out of the box, fast and easy to use

lock-spring-boot-starter A distributed lock that supports the use of Redis and Zookeeper, out of the box, fast and easy to use 一款基于 Redis 和 Zookeeper

Pear Stack 9 Oct 15, 2022
Fast Android Development. Easy maintainance.

Fast Android Development. Easy maintenance. AndroidAnnotations is an Open Source framework that speeds up Android development. It takes care of the pl

null 11.1k Dec 31, 2022
Text to Speech Project for Spring Boot and Kotlin, Auth Server, Python with Fast API (gTTS)

TTS-App Text to Speech Project for Spring Boot Module (etc Resource, Auth Server, Python with Fast API (gTTS)) Python의 gTTS lib를 활용하여 텍스트를 음성으로 변환하는 서

Seokhyun 7 Dec 21, 2021
A fast, lightweight and more productive microservices framework

A fast, lightweight and cloud-native microservices framework. Stack Overflow | Google Group | Gitter Chat | Subreddit | Youtube Channel | Documentatio

null 3.5k Jan 5, 2023