Core interfaces and classes
Upgradeable
Any machine block entity that accepts upgrades must implement theUpgradeable interface:
getUpgradeInventory() returns the ItemStackHandler representing the machine’s upgrade slots. The system checks for this interface before applying any upgrade; attempting to apply an upgrade to a non-upgradeable block throws an IllegalStateException.
UpgradeBase
UpgradeBase is the base class for all upgrade items. It extends BaseItem and holds:
- A
descriptionstring (shown in the item tooltip when the player holds Shift) - An
hasBeenAppliedflag tracking whether the upgrade is currently active functionalUpgrade(BaseEntityBlock<?>, BlockState)— called to apply the upgrade’s effect; validates that the target block implementsUpgradeableappendHoverText(...)— showsgui.gm.press_shiftuntil Shift is held, then shows the upgrade description
UpgradeBase. UpgradeEmpty (used by the Upgrade Base placeholder) overrides appendHoverText with an empty body.
UpgradeMap
UpgradeMap is a record that pairs a DeferredBlockEntityType with an immutable list of compatible upgrade entries:
upgrades is a Pair of an ItemDefinition<UpgradeBase> and an Integer representing the maximum number of that upgrade allowed in the machine. When no explicit maximum is provided during registration, it defaults to CoreUpgradeRegistry.MAX_UPGRADES (currently 8).
DeferredUpgradeMap
DeferredUpgradeMap wraps a DeferredHolder<UpgradeMap<?>, UpgradeMap<T>> to support deferred registration, which is required by NeoForge’s registry system. It also stores the target BasePoweredBlockEntity class for runtime validation.
Upgradeable at build time via a Preconditions.checkArgument guard.
Querying compatible upgrades
UseCoreUpgrades.getCompatibleUpgrades(Block) to retrieve the upgrade list for any registered machine block:
ResourceLocation, looks it up in CoreRegistries.UPGRADE_MAP_REGISTRY, and returns the associated upgrade pairs. Returns an empty ImmutableList if the block has no registered upgrades.
UpgradeFunctionBuilder and UpgradeFunction
Upgrades with active effects (as opposed to passive stat modifiers) use theUpgradeFunction interface:
create— called once when the upgrade is installed; receives the upgrade item instance and the attribute it targetswork— called each tick (or operation cycle) while the upgrade is active
UpgradeFunctionBuilder is a @FunctionalInterface that produces an UpgradeFunction:
CoreUpgrades.create(...) to register an active function alongside the upgrade item. If null is passed, the upgrade is treated as a passive card with no tick logic.
Example — Speed Upgrade implementation:
Effect stacking
Multiple copies of the same upgrade can be inserted up to the per-upgrade maximum defined in the machine’sUpgradeMap. The global cap per upgrade type per machine is CoreUpgradeRegistry.MAX_UPGRADES (8). Some upgrades set a lower maximum of 1 — for example, OVERCLOCK, AUTO_EJECTOR, SILENCING_COIL, REDSTONE_INTERFACE, and VOID_MOD on the Matter Fabricator. Inserting more copies than the registered maximum has no additional effect.
Installing an upgrade
Craft the upgrade card
Obtain the desired upgrade item. All upgrade cards appear in the General Mechanics creative tab.
Insert the upgrade card
Place the upgrade card into one of the machine’s upgrade slots. The upgrade takes effect immediately.
Verify compatibility
If the slot rejects the card, the upgrade is not compatible with that machine. Check the upgrade’s entry in the Upgrade Reference for supported machines.
Adding upgrade support to a machine
To register upgrade compatibility for a new machine:- Implement
Upgradeableon the machine’sBlockEntityclass and return a validItemStackHandlerfromgetUpgradeInventory(). - Add an entry to
CoreUpgradeRegistry.UpgradePairs(or build a customImmutableList) listing each compatible upgrade and its per-machine maximum. - Register a
DeferredUpgradeMapviaCoreUpgradeRegistry.build(...), passing the machine’sBlockDefinition, entity class,DeferredBlockEntityType, and upgrade list.
build method validates that MyBlockEntity implements Upgradeable and registers the map into CoreRegistries.UPGRADE_MAP_REGISTRY.