This guide describes the public API in the current source version 0.6.4. Use the dependency guidance below and check that the mod is loaded when integrating conditionally.

FFItemWeight — Modding API

Guide for other mods (and AI agents) integrating with FFItemWeight (ffitemweight).

Minecraft1.21.1
LoaderNeoForge 21.1.x
Mod IDffitemweight
API packagecom.fyxe.ffitemweight.api
Client helperscom.fyxe.ffitemweight.api.client

Optional dependency:

[[dependencies.yourmod]]
    modId="ffitemweight"
    type="optional"
    versionRange="[0,)"
    ordering="NONE"
    side="BOTH"

Use ModList.get().isLoaded("ffitemweight") or a compile-only / optional dependency before calling API classes.


Core concepts


Dependency check

import net.neoforged.fml.ModList;

if (!ModList.get().isLoaded("ffitemweight")) {
    return;
}

Reading item weights

import com.fyxe.ffitemweight.api.ItemWeightAPI;
import com.fyxe.ffitemweight.api.WeightCategory;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;

double unit = ItemWeightAPI.getUnitWeight(item);
double stack = ItemWeightAPI.getWeight(stack); // includes nested if enabled

WeightCategory cat = ItemWeightAPI.getItemWeightCategory(stack);
String name = cat.name();
int rgb = cat.rgb();
double bandMax = cat.maxWeight();

List<WeightCategory> allItemBands = ItemWeightAPI.getItemWeightCategories();
MethodNotes
getUnitWeight(Item)One item; default weight if unknown
getWeight(ItemStack)Count + nested contents
getItemWeightCategory(double/stack)Band from client weightCategories
getItemWeightCategories()Ordered immutable list

Empty stacks return 0.0. Null item uses the configured default unit weight.


Player totals and encumbrance

import net.minecraft.world.entity.player.Player;
import com.fyxe.ffitemweight.api.EncumbranceLevel;

boolean tracking = ItemWeightAPI.isPlayerWeightTrackingEnabled();

double total = ItemWeightAPI.getPlayerTotalWeight(player);
EncumbranceLevel enc = ItemWeightAPI.getPlayerEncumbrance(player);
int level = ItemWeightAPI.getPlayerEncumbranceLevel(player);

boolean heavyOrWorse = ItemWeightAPI.isPlayerEncumbranceAtLeast(player, 3);
boolean pastMedium = ItemWeightAPI.isPlayerOverLevel(player, 2);

EncumbranceLevel band = ItemWeightAPI.getEncumbranceCategory(total, player);
List<EncumbranceLevel> loads = ItemWeightAPI.getEncumbranceLevels();
MethodNotes
getPlayerTotalWeight(Player)Cached ~5 ticks; respects creative / slot toggles
getPlayerEncumbrance(Player)Current EncumbranceLevel after capacity scaling
getPlayerEncumbranceLevel(Player)Integer level from the datapack band
isPlayerEncumbranceAtLeast(p, level)Current level >= given level
isPlayerOverLevel(p, level)Total weight above that band's scaled capacity
getEncumbranceLevels()Base bands (capacities before scaling)

Creative players return 0 total (and no HUD) unless applyInventoryWeightsInCreative is true.


Capacity

boolean capOn = ItemWeightAPI.isCapacityScalingEnabled();
double mult = ItemWeightAPI.getPlayerCapacityMultiplier(player); // level formula
double flat = ItemWeightAPI.getPlayerCapacityFlatBonus(player);  // armour / accessories / enchants

double effectiveMax = ItemWeightAPI.scaleThreshold(2000.0, player); // Heavy Load example

double pieceBonus = ItemWeightAPI.getEquipmentCapacityBonus(chestStack);
boolean isGear = ItemWeightAPI.isCapacityEquipment(chestStack);

Formula used internally: threshold' = base * levelMultiplier + flatBonus.

Enchantment keys (datapack):


Effects toggles (read-only)

boolean potions = ItemWeightAPI.areEncumbranceEffectsEnabled();
boolean attrs = ItemWeightAPI.areEncumbranceAttributesEnabled();

Actual potion / attribute application is internal (EncumbranceEffects). Query toggles only; do not depend on internal applicator classes.


Cache and readiness

// After you mutate inventory in a way this mod does not already listen for
ItemWeightAPI.invalidatePlayerCache(player);
ItemWeightAPI.invalidatePlayerCache(null); // all players

boolean ready = ItemWeightAPI.isWeightTableReady(); // server computed / client synced
Set<Item> stillDefault = ItemWeightAPI.getFallbackItems(); // server audit helper

Built-in invalidation already covers: equipment change, item pickup, container close, item destroy, logout.


Client-only helpers

import com.fyxe.ffitemweight.api.client.ClientItemWeightAPI;

double localTotal = ClientItemWeightAPI.getLocalPlayerTotalWeight();
EncumbranceLevel localEnc = ClientItemWeightAPI.getLocalPlayerEncumbrance();
boolean overloaded = ClientItemWeightAPI.isLocalPlayerEncumbranceAtLeast(4);

Use for HUD / UI only. Gameplay rules belong on the server with ItemWeightAPI and a real Player / ServerPlayer.


Datapack weights (for content packs)

Path: data/<namespace>/item_weights/<name>.json

{
  "weights": [
    { "id": "mymod:widget", "weight": 2.5 },
    { "id": "mymod:.*_ore", "weight": 6.0, "regex": true },
    { "id": "mymod:boss_core", "weight": 50.0, "force": true }
  ]
}
FieldMeaning
idItem id, or regex when regex is true
weightUnit weight
regexTreat id as a full-id Java regex
forceLock base; recipes cannot overwrite

Prefer exact ids for anchors; leave craftable tools out of JSON so recipe derivation can fill them.

Datapack encumbrance

Path: data/<namespace>/ffitemweight/encumbrance/<id>.json

Override a built-in by shipping the same path (for example ffitemweight/encumbrance/heavy_load.json).

{
  "level": 3,
  "display_name": "Heavy Load",
  "color": "#FFAA00",
  "capacity": 2000,
  "icon": "ffitemweight:textures/gui/encumbrance/heavy_load.png",
  "shake": 1.5,
  "effects": [{ "id": "minecraft:slowness", "amplifier": 0 }],
  "attributes": [{ "id": "minecraft:generic.movement_speed", "operation": "multiply_total", "amount": -0.20 }]
}

Compare level in code. Treat display_name as a label only.


Events (NeoForge event bus)

Register on NeoForge.EVENT_BUS (common / server).

EncumbranceChangedEvent (after level change, not cancellable)

Fired when the player's integer encumbrance level changes (for example 2 to 3). Checked about every 10 ticks with potion/attribute application. First observation after join does not fire (avoids login spam).

import com.fyxe.ffitemweight.api.EncumbranceChangedEvent;
import net.neoforged.bus.api.SubscribeEvent;

@SubscribeEvent
public void onEncumbranceChanged(EncumbranceChangedEvent event) {
    if (event.isIncrease()) {
        // moved to a heavier band
    }
    int from = event.getOldLevel();
    int to = event.getNewLevel();
    double total = event.getTotalWeight();
    EncumbranceLevel band = event.getNewBand();
}
GetterMeaning
getPlayer()ServerPlayer
getOldLevel() / getNewLevel()Previous / new integer bands (Integer.MIN_VALUE when tracking is off)
getTotalWeight()Carried weight at transition
getOldBand() / getNewBand()EncumbranceLevel snapshots (old may be null)
isIncrease() / isDecrease()Direction along integer levels

Note: There is no pre-change cancellable event — weight is inventory-derived. Cancel gameplay side-effects in your own handlers instead.

Soft compatibility (do not hard-depend)

ModRole
EMITooltip weights via vanilla tooltip path
Accessories / CuriosSlot weight + capacity (Accessories preferred if both present)
CreateConfig recipe modifiers / filters / nested handlers

Integrate through ItemWeightAPI, not compat.* packages.


Stability

SurfaceStatus
com.fyxe.ffitemweight.api.*Public API
EncumbranceChangedEventPublic API
com.fyxe.ffitemweight.api.client.*Public API (client)
WeightManager / CapacityHelper public methodsStable but prefer ItemWeightAPI
Config fields / TOML keysUser-facing; do not hard-code as API
EncumbranceEffects, compat.*, network internalsInternal

Minimal integration example

@EventBusSubscriber(modid = "yourmod")
public class YourWeightHooks {
    @SubscribeEvent
    public static void onSpellCast(YourSpellEvent event) {
        if (!(event.getEntity() instanceof ServerPlayer player)) return;
        if (!ModList.get().isLoaded("ffitemweight")) return;

        if (ItemWeightAPI.isPlayerEncumbranceAtLeast(player, 4)) {
            event.setCanceled(true);
            player.displayClientMessage(
                    Component.literal("Too encumbered to cast."), true);
            return;
        }

        // Optional: react to carried mass
        double mass = ItemWeightAPI.getPlayerTotalWeight(player);
        if (mass > 3000.0) {
            // apply your own mild penalty...
        }
    }
}

Datapack item weight references (0.6.4)

In data/<namespace>/item_weights/<name>.json, use an exact weight_from reference instead of a numeric weight:

{
  "weights": [
    { "id": "minecraft:oxidized_copper", "weight_from": "minecraft:copper_block" }
  ]
}

The item always uses the source item's final unit weight, including recipe calculation, clamps, and fallback. References are locked regardless of force and take precedence over numeric regex bases. Do not combine weight_from with weight or regex: true. Chains are supported. Missing items and cycles, including self-references and dependent chains, log warnings and retain normal regex/recipe/fallback calculation. Recipe ingredients follow the source's current weight. Final weights sync to clients; nested contents are still counted separately.

Default data maps all 63 oxidation and wax variants of the nine copper shapes to their unwaxed, unoxidized equivalents. Replace the same resource path to override these defaults. Later loaded exact numeric/reference entries replace earlier ones. Reload with /reload; Java API signatures are unchanged.