Custom Importer
Model Engine reads model files through a ModelParser. By default only Blockbench .bbmodel files are supported, but
you can register your own parser to import models stored in any other format. A parser is responsible for taking a File
and producing a ModelBlueprint (transformation and animation data) paired with a ModelAssets (textures and item
models) for that model.
Creating a parser class
A parser must implement the ModelParser interface, which has two methods. During import, Model Engine offers every
file to each registered parser; the first parser whose validateFile returns true is asked to generate the model.
public class CustomParser implements ModelParser {
@Override
public boolean validateFile(File file) {
// Return true if this parser can handle the file (e.g. by extension)
return TFile.isExtension(file.getName(), "mymodel");
}
@Override
public Pair<ModelBlueprint, ModelAssets> generate(File file, ErrorCollector collector) throws Exception {
var name = TFile.removeExtension(file.getName()).toLowerCase(Locale.ENGLISH);
// Read your own format and populate the blueprint
var blueprint = new ModelBlueprint();
blueprint.setName(name);
// blueprint.getBones().put(...) for each BlueprintBone
blueprint.constructFlatBoneMap(collector);
blueprint.cacheBoneBehaviors(collector);
// Populate the assets (textures and item models)
var assets = new ModelAssets();
assets.setName(name);
// assets.getTextures().add(...) and assets.getModels().put(...)
return Pair.of(blueprint, assets);
}
}
Pair here is it.unimi.dsi.fastutil.Pair, the same type returned by the built-in BlockbenchParser.
validateFile
This is a cheap check that decides whether the file is yours to handle. It is called for every parser on every file, so keep it lightweight - matching on the file extension is the typical approach.
generate
This does the actual work. Build a ModelBlueprint from your format's bone hierarchy and animations, and a
ModelAssets from its textures and models, then return them as a Pair. Any problem encountered during parsing should
be reported through the supplied ErrorCollector rather than thrown silently; returning null causes the model to be
skipped. After populating bones you should call constructFlatBoneMap and cacheBoneBehaviors (or finalizeModel) on
the blueprint so its internal lookups and bone behaviors are prepared.
Registering the parser
Parsers are registered by listening for RegisterParserEvent and calling register with your parser instance. This is
a normal Bukkit event, so register it the same way as any other listener.
public class ParserListener implements Listener {
@EventHandler
public void onRegisterParser(RegisterParserEvent event) {
event.register(new CustomParser());
}
}
// On plugin start-up
getServer().getPluginManager().registerEvents(new ParserListener(), this);
The built-in BlockbenchParser is always registered first, so your parser only receives files that it claims through
validateFile.