Skip to content

Model Loaders

PulseLib model loading is extensible through PModelLoader. Loaded raw models are baked into PBakedModel by PModelCache.

Built-in glTF loader

PGltfModelLoader is registered by default.

Supported roots and extensions:

assets/<modid>/glmodels/**/*.glb
assets/<modid>/glmodels/**/*.gltf

Default path:

new DefaultEntityModelData.DefaultEntityModelDataBuilder(id)

resolves to:

assets/<namespace>/glmodels/entity/<path>.glb

The parser is PGltfModelParser.

Gecko loader

PGeckoModelLoader supports:

assets/<modid>/geckolib/models/**/*.geo.json
assets/<modid>/geckolib/models/**/*.json
assets/<modid>/geckolib/animations/**/*.animation.json
assets/<modid>/geckolib/animations/**/*.json

Register it:

PModelCache.registerModelLoader(PGeckoModelLoader.INSTANCE);

Use it in model data:

PModelData data = new DefaultEntityModelData.DefaultEntityModelDataBuilder(
        Identifier.fromNamespaceAndPath("examplemod", "robot"),
        PGeckoModelLoader.INSTANCE.id())
        .build();

The parser is PGeckoModelParser.

Custom loader

public final class MyModelLoader implements PModelLoader {
    public static final MyModelLoader INSTANCE = new MyModelLoader();
    private static final Identifier ID =
            Identifier.fromNamespaceAndPath("examplemod", "my_format");

    @Override
    public Identifier id() {
        return ID;
    }

    @Override
    public boolean supports(Identifier modelPath) {
        return modelPath.getPath().startsWith("mymodels/")
                && modelPath.getPath().endsWith(".json");
    }

    @Override
    public Identifier defaultModelLocation(Identifier modelLocation, String modelType) {
        return modelLocation.withPrefix("mymodels/" + modelType + "/").withSuffix(".json");
    }

    @Override
    public Identifier textureLocation(Identifier modelPath, String textureName) {
        return modelPath.withPath("entity/" + textureName);
    }

    @Override
    public CompletableFuture<?> loadModels(Executor backgroundExecutor,
                                           ResourceManager resourceManager,
                                           BiConsumer<Identifier, PModel> elementConsumer) {
        return CompletableFuture.runAsync(() -> {
            // Parse resources and call elementConsumer.accept(modelLocation, model).
        }, backgroundExecutor);
    }
}

Register before client resource reload:

PModelCache.registerModelLoader(MyModelLoader.INSTANCE);

PModel contains raw bones, meshes, bone-to-mesh mapping, and animations. PModelCache owns baking, vertex buffer creation, atlas UV conversion, emissive metadata, and cache cleanup.