Skip to content

Geckolib Items (Geckolib3)

Tslat edited this page Jul 6, 2023 · 11 revisions

Pre-word

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.

Steps

Creating a GeckoLib item requires the following steps:

  1. Creating your Blockbench Model
  2. Creating your Geo Model
  3. Creating your item display json
  4. Creating your item class
  5. 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

Full Video Guides

The Item Class

Quick Summary
  1. Implement IAnimatable
  2. Implement ISyncable
  3. Override getFactory and registerControllers
  4. Instantiate a new AnimationFactory via GeckoLibUtil.createFactory(this) at the top of your entity class and return it in getFactory
  5. 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.

Syncable Animatables

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.

Example Item Class

    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);
			}
		}
	}
    }

The Item Renderer

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.

Creating the class

To make the renderer itself, just make a class that extends GeoItemRenderer, passing in the GeoModel instance to the constructor

Example Renderer Class

    public class ExampleItemRenderer extends GeoItemRenderer<ExampleItem> {
    	public ExampleItemRenderer() {
    		super(new ExampleItemModel());
    	}
    }

Registering the Renderer

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

Using IItemRenderProperties (After 1.16)

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;
			}
		});
	}

Using setISTER (1.16.5 and below)

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());
    }

Table of Contents

Geckolib 3
Geckolib 4

Hosted By: Cloudsmith

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.

Clone this wiki locally