-
-
Notifications
You must be signed in to change notification settings - Fork 128
Geckolib Items (Geckolib3)
Because Minecraft only ever keeps one instance of any given Item, GeckoLib animations for items need to be handled slightly differently. Where objects like Entities and BlockEntities can have their animations handled directly, Items need to make sure it's matching up with its respective synced equivalent.
Ensure you're thoroughly reading the examples and descriptions on this page to determine the required differences.
Creating a GeckoLib item requires the following steps:
- Creating your Blockbench Model
- Creating your Geo Model
- Creating your item display json
- Creating your item class
- Creating and registering your renderer
Steps #1 and #2 will not be covered on this page, instead visit their respective links for info. This page will focus on steps #3, #4, and #5
Quick Summary
- Implement
IAnimatable
- Implement
ISyncable
- Override
getFactory
andregisterControllers
- Instantiate a new
AnimationFactory
viaGeckoLibUtil.createFactory(this)
at the top of your entity class and return it ingetFactory
- Add any controllers you want for animations in
registerControllers
There are a few things needed to set up a GeckoLib item class.
The first is to implement IAnimatable
on your item class, and override the two methods your IDE will tell you to override.
This interface is the base of all animatable objects in GeckoLib, and lets the various other features of the mod pick up your item as an animatable item.
Next, we'll create an instance of an AnimationFactory
for our item. This stores our animatable instance so that it can be retrieved by the renderer and other outside areas.
To do this, we'll instantiate a new factory via GeckoLibUtil.createFactory(this)
at the top of your item class, caching it in a final variable.
Next, we'll override getFactory
in our item class if it hasn't been done already, and return the factory instance we just created.
And finally, override registerControllers
in your item class. This method is called when your item is first being used for animations, and is where you define your actual animation handling.
This finalises the base setup for an animatable Item. However because of the nature of items, with these steps alone you'll only be able to do animations based on the client-side state of the itemstack, which often isn't very useful.
To rectify this, we need to do a couple extra things.
To rectify the issue of not being able to handle animations from server-side functionality, we need to handle a few things specifically.
First we'll implement ISyncable
. This interface allows GeckoLib to identify this animatable object as needing special handling for animations. This is used here because Items are singleton objects and require an assigned id to properly animate.
Then we'll add GeckoLibNetwork.registerSyncable(this);
to the constructor of our item. This is to set up the item instance for animation syncing.
This allows us to override onAnimationSync
, which the method that is called on the client side when an animation call has been made from the server.
Then, when we want to sync an animation from the server, we ensure we assign an ID to the itemstack via GeckoLibUtil.guaranteeIDForStack
, then use that ID in GeckoLibNetwork.syncAnimation
This will cause a call to onAnimationSync
, which we can then use to handle a synced animation on the client side.
public class ExampleItem extends Item implements IAnimatable, ISyncable {
private static final int ACTIVATE_ANIM_STATE = 0;
private static final AnimationBuilder ACTIVATE_ANIM = new AnimationBuilder().addAnimation("misc.activate", false)
public final AnimationFactory factory = GeckoLibUtil.createFactory(this);
public ExampleItem(Properties properties) {
super(properties);
GeckoLibNetwork.registerSyncable(this);
}
@Override
public void registerControllers(final AnimationData data) {
data.addAnimationController(new AnimationController(this, "Activation", 20, event -> PlayState.CONTINUE));
}
@Override
public AnimationFactory getFactory() {
return this.factory;
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
ItemStack stack = player.getItemInHand(hand);
if (!world.isClientSide) {
final int id = GeckoLibUtil.guaranteeIDForStack(stack , (ServerLevel)level);
// Assign an ID for animations to this stack, then use it to sync an animation to the client
GeckoLibNetwork.syncAnimation(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), this, id, ACTIVATE_ANIM_STATE);
}
return InteractionResultHolder.consume(stack);
}
@Override
public void onAnimationSync(int id, int state) {
if (state == ACTIVATE_ANIM_STATE) {
// Always use GeckoLibUtil to get AnimationControllers when you don't have
// access to an AnimationEvent
final AnimationController controller = GeckoLibUtil.getControllerForID(this.factory, id, "Activation");
if (controller.getAnimationState() == AnimationState.Stopped) {
final Player player = MyClientUtils.getPlayer();
if (player != null)
player.sendMessage(new TextComponent("Activating my item!"));
// If you don't do this, the popup animation will only play once because the
// animation will be cached.
controller.markNeedsReload();
// Set the animation to open the JackInTheBoxItem which will start playing music
// and
// eventually do the actual animation. Also sets it to not loop
controller.setAnimation(ACTIVATE_ANIM);
}
}
}
}
To then get the item rendering, we'll need to make a renderer then register it. Due to the nature of items, this requires a little more work than is usual to register.
To make the renderer itself, just make a class that extends GeoItemRenderer
, passing in the GeoModel
instance to the constructor
public class ExampleItemRenderer extends GeoItemRenderer<ExampleItem> {
public ExampleItemRenderer() {
super(new ExampleItemModel());
}
}
Item renderers get registered a little differently to other renderers, and GeckoLib utilises the same system, so we need to be aware of the correct method of registration. This also differs significantly between Forge and other loaders, so for convenience the below section is split into two.
Forge Registration
On more modern versions of Forge, Forge provides a client-interfacing handler for item-specific functionalities. GeckoLib utilises this to render, so we'll need to implement this in our item class.
See below for an example implementation of this:
@Override
public void initializeClient(Consumer<IItemRenderProperties> consumer) {
consumer.accept(new IItemRenderProperties() {
private ExampleItemRenderer renderer = null;
// Don't instantiate until ready. This prevents race conditions breaking things
@Override public BlockEntityWithoutLevelRenderer getItemStackRenderer() {
if (this.renderer == null)
this.renderer = new ExampleItemRenderer();
return renderer;
}
});
}
To register your item renderer for GeckoLib, you need to call setISTER
in your Item Properties
when instantiating it.
See below for example implementation:
public ExampleItem() {
super(new Properties().setISTER(() -> new Callable() {
private final ExampleItemRenderer renderer = new ExampleItemRenderer();
@Override public ExampleItemRenderer call() throws Exception {
return this.renderer;
}
});
}
Fabric Registration
To register your item renderer on Fabric, call GeoItemRenderer.registerItemRenderer
in your mod's client entrypoint (ClientInitializer)
See below for an example:
@Override
public void onInitializeClient() {
GeoItemRenderer.registerItemRenderer(MyItems.EXAMPLE_ITEM, new ExampleItemRenderer());
}
Geckolib 3
Geckolib 4
- Installation
- Getting Started
- Upgrading from GeckoLib 3.1.x to 4.0
- Updating to GeckoLib 4.5
- Basic
- Advanced
- Miscellaneous
Package repository hosting is graciously provided by Cloudsmith.
Cloudsmith is the only fully hosted, cloud-native, universal package management solution that enables your organization to create, store and share packages in any format, to any place, with total confidence.