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

FF Nutrition — Modding API

This document describes the public API other mods (and agents) can use to interact with FF Nutrition on Minecraft 1.21.1 / NeoForge.

Primary entry point: com.fyxeinc.ffnutrition.api.FFNutritionAPI

Events live under com.fyxeinc.ffnutrition.api.event.


Dependency

Optional (recommended):

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

Always prefer the API over writing the nutrition_data attachment or attribute base value directly. The API keeps events, the max-health modifier, and the Metabolic Gauge client sync consistent.


Max-health compatibility

FF Nutrition no longer calls AttributeInstance#setBaseValue on Attributes.MAX_HEALTH.

It applies a permanent AttributeModifier with a stable id:

ffnutrition:nutrition_max_health

Exposed as FFNutritionMod.NUTRITION_MAX_HEALTH_MODIFIER_ID and FFNutritionAPI.getMaxHealthModifierId().

Behaviour:

  1. Remove any previous instance of our modifier.
  2. Measure the attribute value without us.
  3. Add an ADD_VALUE modifier so the final value equals the nutrition target (same absolute result as the old base-value overwrite).
  4. Clamp current health downward if it exceeds the new max.

Other mods can:


Queries (safe on both sides when the attachment exists)

MethodReturns
getNutritionData(LivingEntity)Attachment instance (creates defaults if needed)
getNutritionScore(Player)Score in [0.0, 1.0]
getCategoryValue(Player, String)Category fill in [0.0, 100.0]
getCategoryValues(Player)Unmodifiable category map
getCategories()Ordered datapack category names
hasCategory(String)Whether the category is currently loaded
getItemNutritionValues(Item)Raw datapack vector (unscaled)
hasItemNutrition(Item)Whether a datapack entry exists
getDefaultTargetMaxHealth(Player)Built-in formula target (before events)
getMaxHealthModifierId()ResourceLocation of our permanent modifier
getMaxHealthModifierAmount(Player)Optional<Double> of current modifier amount

Mutations (server only; no-ops on client)

All mutation helpers:

  1. Post a cancellable NutritionChangeEvent.
  2. Apply the change (with clamping).
  3. Refresh the max-health modifier (fires ComputeMaxHealthEvent + MaxHealthAppliedEvent).
  4. Sync Metabolic Gauge state to the owning client.
  5. Post NutritionChangedEvent.
MethodPurpose
addToCategory(Player, String, double)Add delta to one category
addToCategory(..., Cause)Same with explicit cause
setCategory(Player, String, double)Absolute set (clamped)
setCategory(..., Cause)Same with explicit cause
setAllCategories(Player, double)Set every category to the same value (clamped)
setAllCategories(..., Cause)Same with explicit cause
addNutritionVector(Player, double[], Cause)Ordered vector add (food-style)
applyFoodNutrition(ServerPlayer, Item, double[], usedFallback, fromPlacedBlock)Food path + FoodNutritionAppliedEvent
applyMaxHealth(Player)Force modifier refresh only

Cause values: FOOD, DECAY, COMMAND, API, DEATH_CLONE, OTHER.


Events (NeoForge bus, server-side)

EventCancellableWhen
NutritionChangeEventYesBefore a category mutation
NutritionChangedEventNoAfter a successful mutation
ComputeMaxHealthEventNo (adjust target instead)Before the max-health modifier is written
MaxHealthAppliedEventNoAfter the modifier is applied
FoodNutritionAppliedEventNoAfter food (item or placed block) contributed values

Example — override max health from another mod

@SubscribeEvent
public static void onComputeMaxHealth(ComputeMaxHealthEvent event) {
    // e.g. give a bonus heart while a custom effect is active
    if (event.getPlayer().hasEffect(YOUR_EFFECT)) {
        event.setTargetMaxHealth(event.getTargetMaxHealth() + 2.0);
    }
}

Example — block nutrition gain from a specific food

@SubscribeEvent
public static void onNutritionChange(NutritionChangeEvent event) {
    if (event.getCause() == NutritionChangeEvent.Cause.FOOD
            && event.getOperation() == NutritionChangeEvent.Operation.ADD_VECTOR) {
        // cancel or mutate event.getVector()
        event.setCanceled(true);
    }
}

Example — react after score changes

@SubscribeEvent
public static void onNutritionChanged(NutritionChangedEvent event) {
    if (event.getNewScore() >= 0.9) {
        // grant achievement, particle, etc.
    }
}

Notes for agents / integrators


Package layout

com.fyxeinc.ffnutrition.api
├── FFNutritionAPI.java
└── event
    ├── NutritionChangeEvent.java
    ├── NutritionChangedEvent.java
    ├── ComputeMaxHealthEvent.java
    ├── MaxHealthAppliedEvent.java
    └── FoodNutritionAppliedEvent.java