junkdog / artemis-odb

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

add support for generic component classes #629

Open InfectedBytes opened 3 years ago

InfectedBytes commented 3 years ago

This PR adds support for components inheriting from generic base classes. The most simple (and probably most important) use case are components with just a single value. In this case you often end up with several components that only differ in the type of the embedded value. With this PR we can now use generic types:

abstract class SingleValueComponent<T> {
  public T value;
  public void set(T value) { this.value = value; }
}

// no more boilerplate code for simple components!
class TextureMeta extends SingleValueComponent<String> { } // used to only store the path to the asset
@Transient class TextureRef extends SingleValueComponent<Texture> { } // stores the actual asset

This works especially well with the artemis-odb-contrib AssetManager (and LibGDX):

class SimpleAssetManager<A extends SingleValueComponent<String>, B extends SingleValueComponent<B>> extends AssetManager<A, B> {
    private final com.badlogic.gdx.assets.AssetManager assets;
    private final Class<B> refClass;

    public Manager(com.badlogic.gdx.assets.AssetManager assets, Class<A> classA, Class<B> classB) {
        super(classA, classB);
        this.assets = assets;
        refClass = classB;
    }

    @Override
    protected void setup(final int entity, final A a, final B b) {
        b.value = assets.get(a.value, refClass);
    }

    public static <A extends SingleValueComponent<String>, B extends SingleValueComponent<B>> Manager<A, B> create(com.badlogic.gdx.assets.AssetManager assets, Class<A> classA, Class<B> classB) {
        return new Manager<>(assets, classA, classB);
    }
}

// adding a new asset manager is now as simple as:
final WorldConfiguration cfg = new WorldConfigurationBuilder()
    .with(SimpleAssetManager.create(assets, TextureMeta.class, Texture.class))
    .with(SimpleAssetManager.create(assets, FontMeta.class, Font.class))
    // ...
    .build();

This also works with more complicated scenarios with various (generic) classes in between, although this might be an unusual use case, see the newly added tests.

DaanVanYperen commented 3 years ago

Scope is limited to logic for generating classes so I'm for merging, assuming it doesn't cause issues for GWT. @junkdog?