Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hbmmods/hbm-s-nuclear-tech-git/llms.txt

Use this file to discover all available pages before exploring further.

NTM’s hazard system is one of the mod’s most distinctive features: every item in a player’s inventory is scanned each tick by HazardSystem, which resolves a list of HazardEntry objects for that item and applies their effects — radiation exposure, heat, chemical toxicity, hydroactive detonation, and more — to the carrier. The system is designed to be extended by addon mods. HazardSystem.register() lets you attach hazard data to any Item, ItemStack, Block, or OreDict key, and HazardModifier subclasses let that data scale dynamically with NBT values (fuel burnup, temperature, etc.). On the entity side, IRadiationImmune grants complete immunity, IResistanceProvider allows partial mitigation per-source, and IRadarDetectableNT makes custom projectiles and vehicles visible on NTM radar screens.

HazardRegistry — Radiation Constants

com.hbm.hazard.HazardRegistry is a large static class that registers hazard data for every NTM item. It also exposes a comprehensive set of float constants representing the radiation output (in RADs/s) of real and fictional isotopes, which addon mods can reuse when registering their own items:
// Simplified half-life groups (for RadioactiveCraft compat)
public static final float gen_S    = 10_000F; // seconds range
public static final float gen_H    = 2_000F;  // hours range
public static final float gen_10D  = 100F;    // ~10 days
public static final float gen_100D = 80F;
public static final float gen_1Y   = 50F;
public static final float gen_10Y  = 30F;
public static final float gen_100Y = 10F;
public static final float gen_1K   = 7.5F;
public static final float gen_10K  = 6.25F;
public static final float gen_100K = 5F;
public static final float gen_1M   = 2.5F;
public static final float gen_10M  = 1.5F;
public static final float gen_100M = 1F;
public static final float gen_1B   = 0.5F;
public static final float gen_10B  = 0.1F;

// Specific isotope constants (RADs/s per item in inventory)
public static final float co60  = 30.0F;    // Cobalt-60      (5a,  β−)
public static final float sr90  = 15.0F;    // Strontium-90   (29a, β−)
public static final float tc99  = 2.75F;    // Technetium-99  (211Ka, β−)
public static final float i131  = 150.0F;   // Iodine-131     (192h, β−)
public static final float xe135 = 1250.0F;  // Xenon-135      (9h,  β−)
public static final float cs137 = 20.0F;    // Caesium-137    (30a, β−)
public static final float au198 = 500.0F;   // Gold-198       (64h, β−)
public static final float pb209 = 10000.0F; // Lead-209       (3h,  β−)
public static final float at209 = 7500.0F;  // Astatine-209   (5h,  β+)
public static final float po210 = 75.0F;    // Polonium-210   (138d, α)
public static final float ra226 = 7.5F;     // Radium-226     (1600a, α)
public static final float ac227 = 30.0F;    // Actinium-227   (22a, β−)
public static final float th232 = 0.1F;     // Thorium-232    (14Ga, α)
public static final float u233  = 5.0F;     // Uranium-233    (160Ka, α)
public static final float u235  = 1.0F;     // Uranium-235    (700Ma, α)
public static final float u238  = 0.25F;    // Uranium-238    (4.5Ga, α)
public static final float np237 = 2.5F;     // Neptunium-237  (2.1Ma, α)
public static final float pu238 = 10.0F;    // Plutonium-238  (88a,  α)
public static final float pu239 = 5.0F;     // Plutonium-239  (24Ka, α)
public static final float pu240 = 7.5F;     // Plutonium-240  (6600a, α)
public static final float pu241 = 25.0F;    // Plutonium-241  (14a,  β−)
public static final float am241 = 8.5F;     // Americium-241  (432a, α)
public static final float am242 = 9.5F;     // Americium-242  (141a, β−)
public static final float bf    = 300_000F; // Balefire (fictional)

Registering Item Hazards

All registration goes through HazardSystem.register(Object key, HazardData data). The key may be an Item, Block, ItemStack, ComparableStack, or an OreDict String. HazardData is a builder that chains addEntry() calls to attach one or more HazardEntry objects (each holding a HazardTypeBase and a base level):
import com.hbm.hazard.HazardData;
import com.hbm.hazard.HazardRegistry;
import com.hbm.hazard.HazardSystem;

// Register a simple radioactive item using HazardRegistry type singletons
HazardSystem.register(
    MyItems.myUraniumFuel,               // the Item to register
    new HazardData()
        .addEntry(HazardRegistry.RADIATION, HazardRegistry.u235)
);

// Register by OreDict key — applies to any item in that OreDict group
HazardSystem.register(
    "ingotUranium235",
    new HazardData()
        .addEntry(HazardRegistry.RADIATION, HazardRegistry.u235)
);

// Register a specific ItemStack (item + meta match, no NBT)
HazardSystem.register(
    new ItemStack(MyItems.myHotFuelRod, 1, 0),
    new HazardData()
        .addEntry(HazardRegistry.RADIATION, HazardRegistry.pu239)
        .addEntry(HazardRegistry.HOT, 1.0F)
);
OreDict registrations are evaluated before item and stack registrations. If the same item matches multiple OreDict keys that have conflicting data, the mutex system (HazardData.setMutex(int bits)) can prevent duplicate application. Bit -1 is reserved internally for the "ingotX" OreDict pattern.

HazardData Builder API

public class HazardData {

    /**
     * Add a hazard of the given type at the given base level.
     * If override = true, all previously fetched entries for this stack
     * (including OreDict entries) are cleared before this one is added.
     */
    public HazardData addEntry(HazardTypeBase hazard, float level) { ... }
    public HazardData addEntry(HazardTypeBase hazard, float level, boolean override) { ... }
    public HazardData addEntry(HazardEntry entry) { ... }

    /**
     * Mutex bitmask. If two HazardData objects share a bit, only the first
     * one (by resolution order) is applied — the second yields.
     */
    public HazardData setMutex(int mutex) { ... }
}

Hazard Types

Each HazardTypeBase subclass defines what happens when a hazard fires. NTM ships the following concrete types:
ClassEffect
HazardTypeRadiationApplies RAD/s radiation exposure to the holder
HazardTypeAsbestosApplies asbestos dust inhalation (fibrosis) effects
HazardTypeCoalApplies coal dust inhalation (pneumoconiosis)
HazardTypeHotBurns the holder and nearby entities/blocks
HazardTypeExplosiveDetonates dropped item entities
HazardTypeHydroactiveExplodes on contact with water (dropped items)
HazardTypeBlindingApplies blindness effects
HazardTypeDigammaApplies Digamma radiation (fictional, extreme)
All types extend HazardTypeBase:
public abstract class HazardTypeBase {

    /** Apply effects to `target` at the computed `level`. */
    public abstract void onUpdate(EntityLivingBase target, float level, ItemStack stack);

    /** Apply effects to a dropped EntityItem (e.g. explode if hydroactive). */
    public abstract void updateEntity(EntityItem item, float level);

    /** Add tooltip lines to the item. Client-side only. */
    @SideOnly(Side.CLIENT)
    public abstract void addHazardInformation(EntityPlayer player, List list,
                                              float level, ItemStack stack,
                                              List<HazardModifier> modifiers);
}

HazardModifier — Dynamic Level Scaling

HazardModifier lets you scale a hazard’s base level at runtime, for example based on NBT data (fuel burnup, temperature). Chain modifiers onto a HazardEntry:
import com.hbm.hazard.HazardEntry;
import com.hbm.hazard.HazardRegistry;
import com.hbm.hazard.modifier.HazardModifier;

HazardEntry entry = new HazardEntry(HazardRegistry.RADIATION, HazardRegistry.pu239)
    .addMod(new HazardModifier() {
        @Override
        public float modify(ItemStack stack, EntityLivingBase holder, float level) {
            // Scale radiation by burnup stored in NBT (0.0 – 1.0)
            if (stack.hasTagCompound()) {
                float burnup = stack.getTagCompound().getFloat("burnup");
                return level * (1F + burnup * 4F); // up to 5× base at full burnup
            }
            return level;
        }
    });

HazardSystem.register(MyItems.myFuelRod,
    new HazardData().addEntry(entry));
NTM ships four built-in modifier implementations:
ModifierBehaviour
HazardModifierFuelRadiationScales radiation by fuel-rod burn state
HazardModifierRBMKRadiationScales radiation by RBMK rod parameters
HazardModifierRBMKHotScales heat output by RBMK rod temperature
HazardModifierRTGRadiationScales radiation by RTG depletion level

HazardTransformer — Pre/Post Entry Manipulation

HazardTransformerBase subclasses are registered in HazardSystem.trafos and called before (transformPre) and after (transformPost) the hazard entry list is assembled from the maps. NTM uses transformers to inject dynamic entries (e.g. ME storage cells containing radioactive items, NBT-tagged radiation containers):
public abstract class HazardTransformerBase {

    /** Called before the item/oredict maps are queried. Add synthetic entries here. */
    public abstract void transformPre(ItemStack stack, List<HazardEntry> entries);

    /** Called after all map lookups. Filter or modify entries here. */
    public abstract void transformPost(ItemStack stack, List<HazardEntry> entries);
}

Entity Radiation Interfaces

IRadiationImmune — Full Immunity

package api.hbm.entity;

public interface IRadiationImmune { }
IRadiationImmune is a pure marker interface with no methods. Implement it on any Entity or EntityLivingBase subclass to make that entity completely immune to NTM radiation damage. This is also checked for armor pieces — if worn armor implements IRadiationImmune, the radiation system can treat the wearer as protected.
// Example: a radiation-immune entity
public class EntityRadiationGolem extends EntityMob implements IRadiationImmune {
    // no additional methods required
}

IResistanceProvider — Partial / Custom Resistance

package api.hbm.entity;

import net.minecraft.util.DamageSource;

/**
 * Allows custom entities to specify threshold and resistance values
 * based on incoming damage type, amount, and piercing values.
 * Only applies to entities that explicitly implement this interface.
 */
public interface IResistanceProvider {

    /**
     * Returns a float[] of {damageThreshold, damageResistance} for this hit.
     * @param damage    The incoming DamageSource
     * @param amount    Raw damage amount
     * @param pierceDT  How much the attack pierces damage threshold
     * @param pierce    How much the attack pierces damage resistance (0–1)
     */
    public float[] getCurrentDTDR(DamageSource damage, float amount,
                                  float pierceDT, float pierce);

    /** Called after damage is resolved — use for reactive behaviour (e.g. cracking armour). */
    public void onDamageDealt(DamageSource damage, float amount);
}
IResistanceProvider is checked by NTM’s custom damage resolution pipeline for entities that implement it. Standard Minecraft mobs and players are instead governed by DamageResistanceHandlerIResistanceProvider is the more powerful, entity-specific alternative available to addon mod authors.

Radar Detection Interfaces

IRadarDetectableNT (Current)

package api.hbm.entity;

public interface IRadarDetectableNT {

    // Blip level constants (map to RadarEntry.blipLevel)
    public static final int TIER0    = 0;   // micro missiles
    public static final int TIER1    = 1;   // tier-1 missiles
    public static final int TIER2    = 2;
    public static final int TIER3    = 3;
    public static final int TIER4    = 4;   // nuclear / thermo / doomsday
    public static final int TIER10   = 5;   // size-10 custom missile
    public static final int TIER10_15= 6;
    public static final int TIER15   = 7;
    public static final int TIER15_20= 8;
    public static final int TIER20   = 9;
    public static final int TIER_AB  = 10;  // anti-ballistic missile
    public static final int PLAYER   = 11;
    public static final int ARTY     = 12;  // artillery shell
    /** Purple blip — use when no other tier applies. */
    public static final int SPECIAL  = 13;

    /** Localization key for the radar display name. */
    public String getUnlocalizedName();

    /** Blip icon / redstone output tier. */
    public int getBlipLevel();

    /** Whether this entity can be detected by the given radar block. */
    public boolean canBeSeenBy(Object radar);

    /** Whether radar scan parameters (missile/shell/player filters) allow this blip. */
    public boolean paramsApplicable(RadarScanParams params);

    /** Whether this blip contributes to the radar's redstone output. */
    public boolean suppliesRedstone(RadarScanParams params);

    public static class RadarScanParams {
        public boolean scanMissiles = true;
        public boolean scanShells   = true;
        public boolean scanPlayers  = true;
        public boolean smartMode    = true;

        public RadarScanParams(boolean m, boolean s, boolean p, boolean smart) { ... }
    }
}

IRadarDetectable (Deprecated)

@Deprecated // Use IRadarDetectableNT instead — old interface still works
public interface IRadarDetectable {

    public enum RadarTargetType {
        MISSILE_TIER0("Micro Missile"),
        MISSILE_TIER1("Tier 1 Missile"),
        MISSILE_TIER2("Tier 2 Missile"),
        MISSILE_TIER3("Tier 3 Missile"),
        MISSILE_TIER4("Tier 4 Missile"),  // nuclear, thermo, doomsday
        MISSILE_10("Size 10 Custom Missile"),
        MISSILE_10_15("Size 10/15 Custom Missile"),
        MISSILE_15("Size 15 Custom Missile"),
        MISSILE_15_20("Size 15/20 Custom Missile"),
        MISSILE_20("Size 20 Custom Missile"),
        MISSILE_AB("Anti-Ballistic Missile"),
        PLAYER("Player"),
        ARTILLERY("Artillery Shell");

        public String name;
    }

    public RadarTargetType getTargetType();
}

RadarEntry — Data Packet

RadarEntry is the object sent from server to client when a radar scan fires. You do not typically construct these yourself; NTM builds them from your entity’s IRadarDetectableNT implementation:
public class RadarEntry {

    public String unlocalizedName; // display name key
    public int blipLevel;          // IRadarDetectableNT tier constant
    public int posX, posY, posZ;   // block position of the entity
    public int dim;                // dimension ID
    public int entityID;           // for targeting / rendering
    public boolean redstone;       // whether this blip drives redstone output

    // Convenience constructor from a live entity
    public RadarEntry(IRadarDetectableNT detectable, Entity entity, boolean redstone) { ... }

    // ByteBuf serialization (used by NTM's packet system)
    public void toBytes(ByteBuf buf) { ... }
    public void fromBytes(ByteBuf buf) { ... }
}

IRecipeRegisterListener — Recipe Injection

api.hbm.recipe.IRecipeRegisterListener is the correct way for addon mods to add recipes to NTM machines. It is called once per SerializableRecipe type during SerializableRecipe.initialize(), after NTM’s defaults are loaded but before the recipe template is written to disk.
package api.hbm.recipe;

public interface IRecipeRegisterListener {

    /**
     * Called once for every SerializableRecipe class that initialises.
     * recipeClassName is the simple class name of the recipe type
     * (e.g. "RecipeMachineBlastFurnace"). Use it to register only the
     * recipes relevant to that machine.
     *
     * Note: SerializableRecipe instances hold only static state — do not
     * store references to the instances themselves.
     */
    public void onRecipeLoad(String recipeClassName);
}

Registering the Listener

// In your mod's FMLInitializationEvent (or PreInit, before recipes load):
import com.hbm.recipes.machines.SerializableRecipe;
import api.hbm.recipe.IRecipeRegisterListener;

public class MyMod {

    @Mod.EventHandler
    public void init(FMLInitializationEvent event) {
        SerializableRecipe.registerListener(new IRecipeRegisterListener() {
            @Override
            public void onRecipeLoad(String recipeClassName) {
                if ("RecipeMachineBlastFurnace".equals(recipeClassName)) {
                    // Register your blast furnace recipes here
                }
            }
        });
    }
}
Recipe registration via the older IMCHandler system is deprecated and explicitly noted by NTM’s maintainers as broken on recipe reload. Always use IRecipeRegisterListener for new addon mods.

Complete Example: Registering a Radioactive Item

The following example registers a custom fuel rod item with radiation that scales with burnup, using a HazardModifier:
package com.example.mymod.hazard;

import com.hbm.hazard.HazardData;
import com.hbm.hazard.HazardEntry;
import com.hbm.hazard.HazardRegistry;
import com.hbm.hazard.HazardSystem;
import com.hbm.hazard.modifier.HazardModifier;
import com.example.mymod.items.MyItems;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;

public class MyFuelRodHazards {

    public static void register() {

        // Base radiation entry with burnup scaling modifier
        // HazardRegistry.RADIATION is the canonical HazardTypeBase singleton for radiation
        HazardEntry radEntry = new HazardEntry(
                HazardRegistry.RADIATION,
                HazardRegistry.pu239)          // 5.0 RADs/s at fresh
            .addMod(new HazardModifier() {
                @Override
                public float modify(ItemStack stack, EntityLivingBase holder, float level) {
                    if (stack.hasTagCompound()) {
                        // "burnup" goes 0.0 (fresh) → 1.0 (depleted)
                        float burnup = stack.getTagCompound().getFloat("burnup");
                        // Fresh: 5 RAD/s. Partially burned: up to ~20 RAD/s. Depleted: ~1 RAD/s.
                        return level * Math.max(0.2F, 1F + (1F - burnup) * 3F);
                    }
                    return level;
                }
            });

        // Heat entry — always present, not burnup-dependent
        HazardEntry hotEntry = new HazardEntry(HazardRegistry.HOT, 1.5F);

        HazardSystem.register(
            MyItems.myFuelRod,
            new HazardData()
                .addEntry(radEntry)
                .addEntry(hotEntry)
        );

        // Also register by OreDict so other mods' variants are covered
        HazardSystem.register(
            "fuelRodMyMod",
            new HazardData()
                .addEntry(HazardRegistry.RADIATION, HazardRegistry.pu239)
        );
    }
}

Build docs developers (and LLMs) love