Skip to content

Creating a Tweaker Add On

Meredith Espinosa edited this page Feb 10, 2020 · 5 revisions

Tweakers are designed to be extensible, so other mods can add support for their own recipes and systems. Starting with LibCD 2.0, tweakers are added inside the initTweakers block of a LibCDInitializer set as a libcd entrypoint in Fabric. The initTweakers block is passed an instance of the TweakerManager which is used for registration of tweakers, assistants, and stack factories.

Naming

All tweakers and assistants are given string names using package notation, e.g. LibCD's built-in "libcd.recipe.RecipeTweaker". If you need to register multiple copies of the same tweaker, such as with Artis tables, you should specify a standard package notation name, then append an @ symbol and the discriminating ID for the instance of the assistant. Using Artis as an example, a tweaker for a table named artis:test_table would be named "artis.ArtisTweaker@artis:test_table".

Tweaker Manager

The tweaker manager contains the following methods for extending tweakers:

  • public void addTweaker(String name, Tweaker tweaker) - Registers a tweaker instance to the given name. The name should have package notation (see above).
  • public void addAssistant(String name, Object assistant) - Registers an assistant class to the given name. The name should have package notation (see above).
  • public void addAssistantFactory(String name, Function<ScriptBridge, Object> factory) - Registers a factory for an assistant class to the given name. The name should have package notation (see above).
  • public void addStackFactory(Identifier id, TweakerStackFactory factory) - Registers a factory for getting specific stacks based on an identifier. Accessed from a script as factory:id->factory:stack.

Tweakers

The Tweaker interface defines a class which can be used to perform transformations to game data in a more auditable and structured way than just using assistants. The interface contains five methods:

  • void prepareReload(ResourceManager manager) - Run before any tweaker scripts are run. Used to prepare the tweaker so it can be used on the current resource reload. Passed the resource manager being used to reload data packs.
  • void applyReload(ResourceManager manager, Executor executor) - Run after all tweaker scripts are run. Used to apply any changes made by tweakers during tweaker execution. Passed the resource manager and executor being used to reload data packs.
  • String getApplyMessage() - Used to print what changes tweakers have applied to the server console. Should have a number of things applied, similar to vanilla's count of recipes loaded.
  • void prepareFor(ScriptBridge bridge) - Used to prepare the tweaker for each individual script being run. Can be used to set namespaces for content added, or similar behavior. Defaulted to no-op.
  • JsonObject getDebugInfo() - Used to append debug information, such as the IDs of registered recipes or modified loot tables, to the debug file when /libcd debug export is run.

There should only ever be one instance of a given tweaker registered at a time.

Assistants

Assistants can be any object used to make writing scripts easier. There are two ways to register assistants: as a simple object or as a factory for objects. Factories are passed a ScriptBridge, which contains metadata about the script requesting the assistant.

Adding support for your recipes

LibCD already contains and registers a tweaker class for adding recipes. Because of that, you don't need to register your own tweaker class if you just want to support adding recipes. All you need is an assistant class which can construct recipes and pass them to the RecipeTweaker.INSTANCE.addRecipe(Recipe<?> recipe) method.

Tweaker scripts don't have full access to Mojang classes due to game obfuscation, so recipe-adding methods should only use strings, collections, primitives, and Objects as parameters. LibCD provides methods to construct both vanilla Ingredients and ItemStacks from Objects, so they should be used for parsing inputs and outputs. As all recipes need unique identifiers, LibCD provides a method for generating the ID of the recipe based on the currently-running script, how many recipes have already been created, and the output stack of the recipe. It should be called as such.

RecipeParser also contains utilities for processing 2D arrays and key/value dictionaries for shaped crafting recipes. Be aware that due to the use of Objects, the method signatures for 2D arrays and key/value dictionaries may overload each other from a scripting environment, so they should have different names, like the built-in RecipeTweaker#addShaped and RecipeTweaker#addDictShaped methods.

Stack factories

There are some items, like potions, that work off a separate system for available items. Because of that, specifying that a minecraft:potion item in a recipe means that someone can use any potion in it, not just a bottle of water. Because of that, the tweaker system adds a system for creating ingredients (or output stacks) of special stacks called TweakerStackFactorys. New getters are registered through the TweakerManager#addStackFactory method mentioned earlier, passing an Identifier for the getter and a lambda taking in another Identifier for the entry to return. To call the factoru, a user will use a string [getter id]->[entry id]. To see an example of this, check LibCD's call of the method for registering a getter for potions. If a factory can't find an entry, it should return ItemStack.EMPTY.