(In BlockBench / In Minecraft)
BetterModel is a plugin-based engine that provides runtime BlockBench model rendering & animating for Minecraft Java Edition.
It implements fully server-side 3D models by using an item display entity packet.
- Importing Generic BlockBench model
.bbmodel - Auto-generating resource pack
- Playing animation
- Syncing with base entity
- Custom hit box
- 12-limb player animation
BetterModel aims to be a reliable engine that provides stable, high-quality animations for Paper-based high-traffic servers.
- Stability First: We take a conservative approach to feature expansion. By avoiding the implementation of features that are difficult to maintain or have limited use cases, we focus on providing a stable API and ensuring overall operational safety.
- Performance Optimized: Our goal is to minimize runtime computation, memory footprint, and network overhead. Through asynchronous design and optimized packet handling, we ensure the engine runs efficiently even under heavy server loads.
- Tailored for Large-scale Servers: We provide essential features specifically designed for high-population servers and MMORPG content creation.
- Per-player Animation: Individual animation control tailored to each player's perspective.
- Player Model Animation: Support for sophisticated 12-limb animations based on player models.
./gradlew build: Builds all jars
./gradlew shadowJar: Builds plugin jar
./gradlew javadocJar: Builds javadoc jar
./gradlew runServer: Runs Paper test server with test plugin
- Kotlin stdlib: modern functional programming
- semver4j: semver parser
- cloud: command
- adventure: component
- stable player display: player animation
- caffeine: concurrent map cache
- DynamicUV: player model
- ArmorModel: armor in player model
- molang-compiler: compiling and evaluating molang expression
- libby: runtime library downloader
Note
For more detailed API specifications, please refer to our GitHub Wiki.
Gradle (Kotlin)
repositories {
mavenCentral()
}
dependencies {
compileOnly("io.github.toxicity188:bettermodel:VERSION")
}repositories {
maven("https://maven.pkg.github.com/toxicity188/BetterModel") {
credentials {
username = YOUR_GITHUB_USERNAME
password = YOUR_GITHUB_TOKEN
}
}
}
dependencies {
compileOnly("io.github.toxicity188:bettermodel:VERSION-SNAPSHOT")
}Gradle (Groovy)
repositories {
mavenCentral()
}
dependencies {
compileOnly 'io.github.toxicity188:bettermodel:VERSION'
}repositories {
maven {
url "https://maven.pkg.github.com/toxicity188/BetterModel"
credentials {
username = YOUR_GITHUB_USERNAME
password = YOUR_GITHUB_TOKEN
}
}
}
dependencies {
compileOnly 'io.github.toxicity188:bettermodel:VERSION-SNAPSHOT'
}Maven
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.github.toxicity188</groupId>
<artifactId>bettermodel</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
</dependencies><repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/toxicity188/BetterModel</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.github.toxicity188</groupId>
<artifactId>bettermodel</artifactId>
<version>VERSION-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>Example code
BetterModel.model("demon_knight"); //A model file in BetterModel/models (for general model with saving)
BetterModel.limb("steve"); //A model file in BetterModel/players (for player model with no saveing)
BetterModel.modelOrNull("demon_knight"); //general model or null
BetterModel.limbOrNull("steve"); //player model or nullEntityTracker tracker = BetterModel.model("demon_knight")
.map(r -> r.getOrCreate(entity)) //Gets or creates entity tracker by this renderer to some entity.
.orElse(null);EntityTracker tracker = BetterModel.model("demon_knight")
.map(r -> r.create(entity, TrackerModifier.DEFAULT, t -> t.update(TrackerUpdateAction.tint(0x0026FF)))) //Creates entity tracker with pre-spawn task.
.orElse(null);DummyTracker tracker = BetterModel.model("demon_knight")
.map(r -> r.create(location)) //Creates some dummy tracker to this location.
.orElse(null);DummyTracker tracker = BetterModel.limb("steve")
.map(r -> r.create(location, ModelProfile.of(player))) //Creates some dummy tracker to this location and player's skin profile.
.orElse(null);BetterModel.model("demon_knight")
.map(r -> r.create(entity, TrackerModifier.DEFAULT, t -> {
t.update(TrackerUpdateAction.tint(rgb)); //Tint
t.update(TrackerUpdateAction.enchant(true), bone -> true); //Enchant with predicate
}))
.ifPresent(tracker -> tracker.update(TrackerUpdateAction.composite( //Composite
TrackerUpdateAction.brightness(15, 15) //Brightness
TrackerUpdateAction.billboard(Display.Billboard.CENTER) //Billboard
)));
}






