Skip to content

Developers Plugin Lifecycle

Yanny edited this page Oct 3, 2026 · 5 revisions

Plugin Lifecycle

Applies to both mods. The examples name ALI's types; Advanced Worldgen Info's IPlugin, ICommonRegistry, IClientRegistry and IServerRegistry live in com.yanny.awi.api and follow the same three phases — see Worldgen Info → Overview. AWI's ICommonRegistry has only registerTranslationKey; registerEntityVariants is ALI-only.

A plugin has three registration methods. Each runs on a different side, at a different time, against a different registry.

Method Side When Registry
registerCommon both once, while the mod starts ICommonRegistry
registerClient client only once, on client start IClientRegistry
registerServer server (also the integrated one) per server level, and again on every reload IServerRegistry

registerCommon

Runs on both sides, so whatever you register here must exist on both. Used for data that has to match between client and server:

  • registry.registerTranslationKey(String key) — declares a tooltip translation key. Keys registered here are sent over the network as a compact index instead of the full string.
  • registry.registerEntityVariants(EntityType<T>, Function<Level, List<Entity>>) — supplies the entity instances used to render a variant (as vanilla sheep are rendered per color). Attributing a variant's loot table to its entity type does not need this; an unregistered variant simply falls back to any instance of its type.
  • NumberFunctions.register(NumberFunction) — a static call, not a registry method, but it belongs here: the client evaluates number expressions too, so a number function of your own has to be known on both sides.

With your keys in an enum implementing com.yanny.aci.language.ITooltipKey:

@Override
public void registerCommon(ICommonRegistry registry) {
    for (MyLang lang : MyLang.values()) {
        registry.registerTranslationKey(lang.singular());
        registry.registerTranslationKey(lang.plural());
    }
}

Register every translation key you use in a tooltip here, so that it is known on both sides. An unregistered key still works — it is sent as the full string — but a key registered on one side only breaks the index lookup and is shown as a wrong or not-implemented label on the client.

registerClient

Client-only. Used to register the rendering half of any custom node type:

@Override
public void registerClient(IClientRegistry registry) {
    registry.registerWidget(MyNode.ID, MyWidget::new);
    registry.registerDataNode(MyNode.ID, MyNode::new);
}

Both are keyed by the same ID as the node itself — see Nodes and Widgets. If you do not add a custom node type, this method stays empty.

registerServer

Where nearly all of ALI's plugin work happens: it maps your classes to the code that describes them. It runs once per server level and again after every reload, on a registry whose previous data was cleared first — so it must be idempotent: register the same things every time, and do not accumulate state between calls.

@Override
public void registerServer(IServerRegistry registry) {
    registry.registerConditionTooltip(MyCondition.class, MyTooltips::getMyConditionTooltip);
    registry.registerFunctionTooltip(MyFunction.class, MyTooltips::getMyFunctionTooltip);
}

The full list of registration methods is in the Registration Reference, or, for AWI, in its own Registration Reference.

Caches for data collection

Data collection runs on the server right after registerServer, and a plugin may cache whatever it computes repeatedly during it — a lookup per page, a parsed pattern, a reflective copy. Such a cache is needed only while the data is being collected, so register how to empty it:

private static final Map<Identifier, MyResult> CACHE = new HashMap<>();

@Override
public void registerServer(IServerRegistry registry) {
    registry.registerCacheCleaner(CACHE::clear);
}

1.20.1–1.21.1: the map key is a ResourceLocation.

Every registered cleaner runs once data collection has finished, also when it failed. Cleaners are dropped with the rest of the registrations, so register them again in each registerServer call, like everything else. The method is the same for ALI and AWI.

Failure handling

Each plugin's registration call is wrapped: a thrown exception is logged with your mod ID and the rest of the plugins still register. A broken plugin degrades to "your types render as auto-detected JSON" rather than breaking the game — but check the log, because nothing else will tell you.

The same holds during the scan. A registered loot entry, tooltip or trade listing that throws is shown as if it were not registered — auto-detected, and a trade listing first tries its rolled offer — and the log names the class once per scan (showing it as unsupported). The rest of the loot table or trader is still shown.

Useful log output

At startup and after data collection, ALI logs:

  • registration info — how many types of each category are registered against the corresponding vanilla registry (registered/total), so you can see what is still uncovered;
  • runtime info — every class that was looked up and had no registration, i.e. everything that ended up as Auto-detected.

That second list is the quickest way to find out what your own mod still needs to register.

Clone this wiki locally