NeoForge extension methods and Horizon
This page compares the public methods of NeoForge 26.3's object-extension interfaces with what a Horizon mod can answer today. It is the reference the Parts lane starts from: before proposing a new block or item hook, check whether content data, a handle or an existing Part already answers the same question.
From the modding book of arismoko/horizonbfbda6a
On this page
Read from NeoForge 26.3.0.101 (neoforge-26.3.0.101-universal.jar, net.neoforged.neoforge.common.extensions) with javap -p, and from Horizon at commit 061a06c7b. Method lists and parameter names are factual citations; no NeoForge source or Javadoc is copied. Counts exclude each interface's private self() accessor.
How to read the verdicts
| Verdict | Meaning |
|---|---|
| Covered | A mod can answer the same question for its own object, at the same moment, through content data, a handle or a Part method. |
| Partial | The game lets a mod answer something close, but one of these differs: the object (a global hook instead of a per-block/item method), the moment, the arguments, or the answer (a factor or notice where NeoForge returns a decision). |
| Missing | Neither data, a handle nor a hook exposes the question. |
| n/a | The method has no Horizon equivalent because the architecture removes its reason to exist. |
A Part method is a generated method on BlockPart, ItemPart, BlockEntityPart, MenuPart or EntityPart, declared with scope in crates/horizon-mod-vocab/src/hooks/<area>.rs. A Part method runs only for the objects a mod attached its part to. An unscoped hook in the same files is global: every mod hears it and filters by the arguments itself. Data means a content declaration in crates/horizon-mod-package/src/content.rs, read into the game through crates/horizon-items/src/blocks.rs. Handle means a value or reference type in crates/horizon-mod-vocab/src/ (ItemStack, ItemResource, AttachmentStore).
EntityPart exists today but has two methods, register_goals and spawn_cluster_size (docs/modding/src/concepts/trait-mods/023-entity-parts-and-mob-goals.md). It does not answer IEntityExtension methods; those are covered only where a global hook or a handle does.
Counts
| Interface | Public methods | Covered | Partial | Missing | n/a |
|---|---|---|---|---|---|
IBlockExtension | 60 | 6 | 21 | 33 | 0 |
IBlockStateExtension | 57 | 5 | 20 | 32 | 0 |
IItemExtension | 46 | 9 | 15 | 22 | 0 |
IEntityExtension | 33 | 1 | 16 | 16 | 0 |
ILivingEntityExtension | 6 | 0 | 3 | 3 | 0 |
IBlockEntityExtension | 9 | 1 | 3 | 4 | 1 |
IFluidExtension | 9 | 0 | 6 | 3 | 0 |
IMenuTypeExtension | 2 | 0 | 2 | 0 | 0 |
Of the 60 block methods, 57 exist a second time with the state as receiver, so the state-extension counts are the block counts minus three; see IBlockStateExtension. The block follow-up is #1038 and the item follow-up is #1039. Their groups were written from the earlier audit and do not name every Missing row yet. Both predate hooks that have since landed, so some of their rows are narrower or already answered; the last section lists what changed.
The earlier audit's counts included self() and folded the four isInFluidType overloads into one; this page counts each declared public method, so the entity total is 33 rather than 30.
IBlockExtension
Data fields are static values from a block's content declaration, inherited from its template when unset. They answer the method for a mod block but cannot vary by level, position or entity. The engine's own copy of the same facts is StateFacts in crates/horizon-items/src/blocks.rs.
getFriction(state, level, pos, entity)- Verdict
- Partial
- Horizon
BlockProperties.friction→StateFacts.friction- Notes
- Static; the entity is not consulted.
hasDynamicLightEmission(state)- Verdict
- Missing
- Horizon
- —
- Notes
StateFacts.emissionis a fixed level, not a dynamic emission.
getLightEmission(state, level, pos)- Verdict
- Partial
- Horizon
BlockProperties.light→StateFacts.emission- Notes
- Static; no level or position.
ignitedByLava(state, level, pos, direction)- Verdict
- Partial
- Horizon
- template state flag (
StateFacts,state_)flags:: IGNITED_ BY_ LAVA - Notes
- Inherited from the template's prepared data; no content field or Part changes it.
isLadder(state, level, pos, entity)- Verdict
- Covered
- Horizon
BlockPart::(is_ ladder hooks/)is_ ladder.rs - Notes
- Asked of the block a living entity stands in, with the entity id, after the
#climbabletag: the part's answer replaces the tag's, either way. Players and mobs; armor stands never ask.
makesOpenTrapdoorAboveClimbable(state, level, pos, stateAbove)- Verdict
- Missing
- Horizon
- —
- Notes
- Engine rule in the climbing code; not exposed.
isBurning(state, level, pos)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-block burning query;
block_is fire removing a block.burn
canHarvestBlock(state, level, pos, player)- Verdict
- Covered
- Horizon
BlockPart::(can_ harvest_ block hooks/)can_ harvest_ block.rs - Notes
- Asked where
player_fires, before it: the global hook still hears and may change the part's answer.harvest_ check
onDestroyedByPlayer(state, level, pos, player, stack, willHarvest, fluid)- Verdict
- Partial
- Horizon
break_(block hooks/),base.rs block_(drops hooks/)block_ drops.rs - Notes
break_cancels the break or replaces the XP sample;block block_edits drops. Neither returns "the block was destroyed" for the caller. #1038.drops
onDestroyedByPushReaction(state, level, pos, direction, fluid)- Verdict
- Missing
- Horizon
- —
- Notes
- No hook at the piston/fluid destruction point.
getRespawnPosition(state, entityType, level, pos, angle)- Verdict
- Partial
- Horizon
player_(respawn_ position hooks/)base.rs - Notes
- The global
PlayerRespawnPositionEventmoves the player after vanilla found the bed or anchor; the per-block search is engine-owned.
getExplosionResistance(state, level, pos, explosion)- Verdict
- Partial
- Horizon
BlockProperties.explosion_→resistance StateFacts.explosion_resistance - Notes
- Static; the explosion is not consulted.
getCloneItemStack(level, pos, state, includeData, player)- Verdict
- Covered
- Horizon
BlockPart::(clone_ item_ stack hooks/)clone_ item_ stack.rs - Notes
include_and the player are passed; leaving the stack unset keeps the game's item.data
addLandingEffects(state, level, pos, stateBelow, entity, count)- Verdict
- Missing
- Horizon
- —
- Notes
fall_edits fall damage, not the landing particle/sound burst.on
addRunningEffects(state, level, pos, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- No hook for the running dust burst.
playFallSound(state, level, pos, entity)- Verdict
- Partial
- Horizon
BlockProperties.sounds- Notes
- Picks a vanilla sound type; no custom event, volume or pitch.
playStepSound(state, level, pos, entity, volume, pitch)- Verdict
- Partial
- Horizon
BlockProperties.sounds- Notes
- Same static sound type; step volume and pitch are not settable.
canSustainPlant(state, level, pos, direction, plantState)- Verdict
- Covered
- Horizon
BlockPart::(can_ sustain_ plant hooks/)can_ sustain_ plant.rs - Notes
- The soil's answer for the plant above it (allow, deny or none), asked before the plant's
may_, which still answers for your plant. The direction is always up.place_ on
onTreeGrow(state, level, posConsumer, random, pos, feature)- Verdict
- Missing
- Horizon
- —
- Notes
block_observes or edits the feature a sapling grows into; it does not let a block run its own tree growth.grow_ feature
isFertile(state, level, pos)- Verdict
- Missing
- Horizon
- —
- Notes
- No fertile-block query; bonemeal hooks fire later.
getExpDrop(state, level, pos, blockEntity, breaker, tool)- Verdict
- Partial
- Horizon
break_(block.exp_ to_ drop hooks/)base.rs - Notes
- Replaces the XP sample for a player break; global, not per-block, and the block entity/tool/breaker are not arguments. #1038.
rotate(state, level, pos, rotation)- Verdict
- Missing
- Horizon
- —
- Notes
- Structure rotation is engine behaviour; no callback.
getEnchantPowerBonus(state, level, pos)- Verdict
- Missing
- Horizon
- —
- Notes
- Bookshelf enchanting power is a hard-coded block rule.
onNeighborChange(state, level, pos, fromPos)- Verdict
- Missing
- Horizon
- —
- Notes
neighbor_ischanged Block.neighborChanged, a different callback. #1038.
shouldCheckWeakPower(state, level, pos, direction)- Verdict
- Covered
- Horizon
BlockPart::(should_ check_ weak_ power hooks/)should_ check_ weak_ power.rs - Notes
- The argument direction is the input side, as NeoForge's.
getWeakChanges(state, level, pos)- Verdict
- Missing
- Horizon
- —
- Notes
- No weak-change observer query. #1038.
getSoundType(state, level, pos, entity)- Verdict
- Partial
- Horizon
BlockProperties.sounds,host.block_states().sound(state) - Notes
- Static set of break/step/place/hit/fall sounds; no per-position or per-entity choice.
getBeaconColorMultiplier(state, level, pos, beaconPos)- Verdict
- Missing
- Horizon
- —
- Notes
- Beacon beam colour is engine-owned.
getStateAtViewpoint(state, level, pos, viewpoint)- Verdict
- Missing
- Horizon
- —
- Notes
- No viewpoint-state query.
getBlockPathType(state, level, pos, mob)- Verdict
- Partial
- Horizon
BlockPart::(is_ pathfindable hooks/)is_ pathfindable.rs - Notes
- Answers whether a
PathComputationTypemay pass, once per state and type; not aPathTypeper mob or position. #1038.
getAdjacentBlockPathType(state, level, pos, mob, pathType)- Verdict
- Missing
- Horizon
- —
- Notes
- No adjacent-path-type query.
isSlimeBlock(state)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-state slime query; the piston/fall logic is engine-owned. #1038.
isStickyBlock(state)- Verdict
- Missing
- Horizon
- —
- Notes
- Same. #1038.
canStickTo(state, otherState)- Verdict
- Missing
- Horizon
- —
- Notes
- Same. #1038.
isFlammable(state, level, pos, direction)- Verdict
- Partial
- Horizon
BlockPart::(fire_ odds hooks/)base.rs - Notes
- Sets ignite and burn odds (
0, 0= never burns), but there is no boolean flammable predicate. #1038.
getFireSpreadSpeed(state, level, pos, direction)- Verdict
- Partial
- Horizon
BlockPart::(fire_ odds hooks/)base.rs - Notes
- Ignite/spread odds (the first element of
fire_'sodds (ignite, burn)tuple) replace vanilla's table for the block. The answer is state-based, with no position or direction as in NeoForge's contextual override.
getFlammability(state, level, pos, direction)- Verdict
- Partial
- Horizon
BlockPart::(fire_ odds hooks/)base.rs - Notes
- Burn/destruction odds (the second element of
fire_'sodds (ignite, burn)tuple) replace vanilla's table for the block. The answer is state-based, with no position or direction as in NeoForge's contextual override.
onCaughtFire(state, level, pos, direction, igniter, stack)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-block caught-fire callback.
isFireSource(state, level, pos, direction)- Verdict
- Missing
- Horizon
- —
- Notes
- Fire-source rules are engine-owned.
canEntityDestroy(state, level, pos, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- Mob-grief checks are engine rules;
entity_is a global event at a different moment.mob_ griefing
canDropFromExplosion(state, level, pos, explosion)- Verdict
- Partial
- Horizon
explosion_(detonate hooks/)base.rs - Notes
- Removes positions from the blast before blocks are hit; no per-block keep/drop query.
onBlockExploded(state, level, pos, explosion)- Verdict
- Partial
- Horizon
explosion_(detonate hooks/)base.rs - Notes
- Same global pre-blast hook; no per-block callback after the block is removed. #1038.
collisionExtendsVertically(state, level, pos, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- Collision shapes are data; no per-entity extension query.
shouldDisplayFluidOverlay(state, level, pos, fluid)- Verdict
- Missing
- Horizon
- —
- Notes
- Overlay drawing is engine-owned.
getToolModifiedState(state, context, ability, simulate)- Verdict
- Partial
- Horizon
block_(tool_ modification hooks/)block_ tool_ modification.rs - Notes
- Global
BlockEvent.BlockToolModificationEventcancels or replaces the final state; not a Part method and nosimulateflag. #1038.
isScaffolding(state, level, pos, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- Scaffolding is identified by block class; no content field or Part.
hidesNeighborFace(level, pos, state, neighborState, direction)- Verdict
- Missing
- Horizon
- —
- Notes
block_hides a whole state from the mesher, not one face.render_ visibility
supportsExternalFaceHiding(state)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-face culling query.
onBlockStateChange(level, pos, oldState, newState)- Verdict
- Partial
- Horizon
block_(changed hooks/, a global server hook)base.rs - Notes
- Fires after the commit but before block side effects and neighbour updates, and only on an authoritative server. It may not modify the level.
canBeHydrated(state, level, pos, fluid)- Verdict
- Missing
- Horizon
- —
- Notes
- Farmland hydration is engine-owned; fluid
canHydrateis data.
getMapColor(state, level, pos, defaultColor)- Verdict
- Partial
- Horizon
BlockProperties.map_→color StateFacts.map_color - Notes
- Static; no position.
getAppearance(state, level, pos, direction, neighborState, neighborPos)- Verdict
- Missing
- Horizon
- —
- Notes
- No appearance query.
getPistonPushReaction(state)- Verdict
- Covered
- Horizon
BlockProperties.push_reaction - Notes
- Static;
PUSH_,PULL PUSH,POPPED,IMMOVEABLE,IGNORE_.ENTITY
isEmpty(state)- Verdict
- Missing
- Horizon
- —
- Notes
- Air/replaceable facts exist (
block_), but nostates().replaceable isEmptyanswer for a state.
getBubbleColumnDirection(state)- Verdict
- Missing
- Horizon
- —
- Notes
- Bubble-column rules are engine-owned.
shouldHideAdjacentFluidFace(state, direction, fluid)- Verdict
- Missing
- Horizon
- —
- Notes
- Fluid-face culling is engine-owned.
getBounceRestitution(level, pos, state, entity)- Verdict
- Partial
- Horizon
BlockPart::(bounce_ on hooks/)block_ landing.rs - Notes
- Edits the entity's movement after it bounced; the restitution factor is not exposed. #1038.
getRelocability(level, pos, state)- Verdict
- Missing
- Horizon
- —
- Notes
- No relocation query (pistons, structure blocks).
canBeConnectedTo(state, direction, neighborBlock)- Verdict
- Partial
- Horizon
BlockPart::(connects_ to hooks/)connects_ to.rs - Notes
- Asks the connecting fence, wall, bars or pane (your block), not the block being connected to: a modded target cannot answer for a vanilla fence, and only those shapes ask at all.
getModelData(state, level, pos)- Verdict
- Missing
- Horizon
- —
- Notes
- No
ModelData; block-entity drawing takes ablock_part with its own model path.entity_ submit
IBlockStateExtension
This interface repeats the block questions with the state as receiver instead of the first argument. All 57 methods are the same behaviours and take the same verdict as the IBlockExtension row of the same name, with the parameters shifted by one. Three block methods have no state-receiver form:
| Block-only method | Verdict there |
|---|---|
getPistonPushReaction(state) | Covered (content push_) |
getMapColor(state, level, pos, defaultColor) | Partial (content map_) |
makesOpenTrapdoorAboveClimbable(state, level, pos, stateAbove) | Missing |
Counts: 5 covered, 20 partial, 32 missing among the 57. The handful of signature differences (canStickTo takes the neighbour state; getCloneItemStack reorders its arguments; getEnchantPowerBonus takes a LevelReader) do not change any verdict.
IItemExtension
Item data is a 26.3 component patch over a vanilla template (crates/horizon-mod-package/src/content.rs), which is the same place NeoForge's item components live. Reads are on host (host/items.rs) or on the owned ItemStack / ItemResource values.
getDefaultAttributeModifiers(stack)- Verdict
- Partial
- Horizon
item_(attribute_ modifier hooks/)item_ attribute_ modifier.rs - Notes
- Global
ItemAttributeModifierEventedits the stack's modifiers; the stack filters it, but it is not a Part method.
onDroppedByPlayer(stack, player)- Verdict
- Partial
- Horizon
item_(toss hooks/)item_ toss.rs - Notes
- Global
ItemTossEvent, cancellable; the item is not a Part attachment.
getHighlightTip(stack, name)- Verdict
- Missing
- Horizon
- —
- Notes
- No highlight-name hook.
onItemUseFirst(stack, context)- Verdict
- Covered
- Horizon
ItemPart::(on_ item_ use_ first hooks/)on_ item_ use_ first.rs - Notes
- Runs after
use_let it through, before the block's own use.item_ on_ block
isPiglinCurrency(stack)- Verdict
- Missing
- Horizon
- —
- Notes
- Piglin barter currency is a hard-coded item tag.
makesPiglinsNeutral(stack, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- Piglin neutrality is a hard-coded item/tag rule.
isCombineRepairable(stack)- Verdict
- Partial
- Horizon
minecraft:repairablecomponent viaItemResource::repairable - Notes
- Data answers which material repairs it; the anvil combine predicate is not exposed.
getXpRepairRatio(stack)- Verdict
- Partial
- Horizon
mending_(repair hooks/, a global hook)base.rs - Notes
- Changes the repair amount for Mending; the per-item ratio is not a separate read, and the hook is not scoped to the item.
onStopUsing(stack, entity, timeLeft)- Verdict
- Partial
- Horizon
ItemPart::(release_ using hooks/)base.rs - Notes
- Runs on an early release only, after the vanilla item's release; finishing the use or switching to another item stops it without asking. Both sides.
onLeftClickEntity(stack, player, entity)- Verdict
- Covered
- Horizon
ItemPart::(on_ left_ click_ entity hooks/)item_ attack.rs - Notes
- Runs where
Player.attackstarts, afterattack_let the blow through; a cancel leaves the target unhurt, with noentity hurt_and no wear.enemy
getCraftingRemainder(instance)- Verdict
- Covered
- Horizon
ItemPart::, contentcrafting_ remainder crafting_remainder - Notes
- The per-stack Part override replaces the data remainder in crafting, fuel and quick moves.
getEntityLifespan(stack, level)- Verdict
- Partial
- Horizon
item_(expire hooks/)base.rs - Notes
- Adds extra ticks to a dropped item's life; no absolute lifespan and not per-item.
hasCustomEntity(stack)- Verdict
- Missing
- Horizon
- —
- Notes
- No custom dropped-entity selection.
createEntity(level, entity, stack)- Verdict
- Missing
- Horizon
- —
- Notes
- Same.
onEntityItemUpdate(stack, itemEntity)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-item dropped-entity tick. #1039.
doesSneakBypassUse(stack, level, pos, player)- Verdict
- Missing
- Horizon
- —
- Notes
- No sneak-bypass query.
canEquip(stack, slot, entity)- Verdict
- Partial
- Horizon
equippable.allowed_,entities entity_capability:: goes_ in_ slot - Notes
- Component data decides slot and allowed entities; no per-stack code predicate. #1039.
getEquipmentSlot(stack)- Verdict
- Covered
- Horizon
ItemResource::,equippable_ slot host.item_equippable_ slot - Notes
- Read from the effective
equippablecomponent.
onEntitySwing(stack, entity, hand)- Verdict
- Covered
- Horizon
ItemPart::(on_ entity_ swing hooks/)item_ attack.rs - Notes
- Runs where
LivingEntity.swingstarts, on both sides; a cancel starts no swing (no animation, no packet).
getDamage(stack)- Verdict
- Covered
- Horizon
ItemStack::damage - Notes
- The stack's numeric damage override.
getMaxDamage(stack)- Verdict
- Partial
- Horizon
minecraft:max_effective component,damage host.max_damage - Notes
- The stack's effective component includes a patch over the item default;
host.max_reads that default only.damage
isDamaged(stack)- Verdict
- Covered
- Horizon
ItemStack::,damage damage_component - Notes
- Distinguishes explicit zero from absent.
setDamage(stack, damage)- Verdict
- Partial
- Horizon
ItemStack::set_ damage - Notes
- Stores the requested value; the game checks it against the effective maximum when it accepts the write instead of clamping here.
canPerformAction(instance, ability)- Verdict
- Partial
- Horizon
ItemPart::(can_ perform_ action hooks/),can_ perform_ action.rs block_(tool_ modification hooks/)block_ tool_ modification.rs - Notes
- The part answers per stack and per namespaced ability id, starting from vanilla's answer, where vanilla checks the item kind:
minecraft:shield_(a raised item blocking attacks, its use time and animation),block minecraft:shears_(sheep, mooshroom, snow golem, bogged, bee nests, a dispenser's shears) andharvest minecraft:shears_(a pumpkin). The block side of a tool action (strip, wax, path, ...) iscarve block_; no tool ability (tool_ modification axe_...) is asked of the item yet. #1039.strip
getMaxStackSize(stack)- Verdict
- Partial
- Horizon
max_component,stack_ size host.max_stack_ size - Notes
- The stack's effective component includes a patch over the item default;
host.max_reads that default only, and invalid values are refused at the write.stack_ size
isPrimaryItemFor(stack, enchantment)- Verdict
- Partial
- Horizon
host.enchantment_supports - Notes
- Answers supported items; the narrower "primary item" distinction is not exposed.
supportsEnchantment(stack, enchantment)- Verdict
- Partial
- Horizon
host.enchantment_supports - Notes
- A client-side read of
Enchantment.isSupportedItemfor an item id; not per stack and without NeoForge's enchanted-book special case.
getEnchantmentLevel(instance, enchantment)- Verdict
- Covered
- Horizon
get_(enchantment_ level hooks/)get_ enchantment_ level.rs - Notes
- Edits the level gameplay sees.
getAllEnchantments(stack, lookup)- Verdict
- Covered
- Horizon
get_with no targetenchantment_ level - Notes
- The hook's
targetisNonefor every-enchantment reads.
shouldCauseReequipAnimation(stack, oldStack, equipped)- Verdict
- Missing
- Horizon
- —
- Notes
- Client animation rule; no hook.
shouldCauseBlockBreakReset(oldStack, newStack)- Verdict
- Missing
- Horizon
- —
- Notes
- Client mining-reset rule; no hook.
canContinueUsing(stack, otherStack)- Verdict
- Missing
- Horizon
- —
- Notes
- No continue-use query.
getCreatorModId(registries, stack)- Verdict
- Missing
- Horizon
- —
- Notes
- Diagnostic ownership string; Horizon keeps the item's namespace in its key.
onAnimalArmorTick(stack, level, mob)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-item animal-armour tick.
damageItem(stack, amount, entity, onBreak)- Verdict
- Covered
- Horizon
ItemPart::(damage_ item hooks/)damage_ item.rs - Notes
- Runs on the server for the parts of the worn item, after Unbreaking, on every wear path (a player's tools, armour and shield, a dispenser's tool, a mob's armour). The part gets the stack and the amount about to be lost, and changes it (0 or less leaves the item whole) or cancels the wear. It is not given the wearing entity (
host.players().acting_names the player on a player's paths) and has noplayer() onBreakconsumer: the break isplayer_.destroy_ item
onDestroyed(itemEntity, source)- Verdict
- Missing
- Horizon
- —
- Notes
item_is lifetime removal, not damage destruction.despawn
isGazeDisguise(stack, player, target)- Verdict
- Missing
- Horizon
- —
- Notes
- No gaze-disguise query.
canWalkOnPowderedSnow(stack, entity)- Verdict
- Missing
- Horizon
- —
- Notes
- Powder-snow walking is engine-owned.
isDamageable(stack)- Verdict
- Covered
- Horizon
ItemResource::damageable(host) - Notes
- Reads the effective components:
minecraft:max_anddamage minecraft:damagepresent,minecraft:unbreakableabsent.
getSweepHitBox(stack, player, target)- Verdict
- Missing
- Horizon
- —
- Notes
sweep_decides whether a sweep happens, not its box.attack
isNotReplaceableByPickAction(stack, player, slot)- Verdict
- Missing
- Horizon
- —
- Notes
- Pick-block replacement is engine-owned.
canGrindstoneRepair(stack)- Verdict
- Missing
- Horizon
- —
- Notes
grindstone_observes or edits the result; no per-item predicate.place
canBeHurtBy(stack, source)- Verdict
- Missing
- Horizon
- —
- Notes
- No item damage-immunity query.
applyEnchantments(stack, enchantments)- Verdict
- Missing
- Horizon
- —
- Notes
- No item-level enchantment application hook.
canFitInsideContainerItems(stack)- Verdict
- Partial
- Horizon
MenuPart::(menu_ slot_ rules hooks/)base.rs - Notes
- Slot rules implement container-item restrictions (a shulker box in a slot); no per-stack override.
onGlideDamage(stack, entity, slot)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-item glide-damage callback.
IEntityExtension
There is no per-entity Part method yet (EntityPart only registers goals), so entity coverage is data, handles and global hooks. On the server a mod can act on entities through EntityRef and AttachmentStore.
captureDrops()- Verdict
- Missing
- Horizon
- —
- Notes
living_edits a dying mob's drops; it does not capture an arbitrary entity's drops.drops
captureDrops(collection)- Verdict
- Missing
- Horizon
- —
- Notes
- Same.
getPersistentData()- Verdict
- Covered
- Horizon
AttachmentStore,AttachmentHolder::Entity - Notes
- Saved and synced attachments replace the writable compound; the data is typed, not raw NBT.
shouldRiderSit()- Verdict
- Missing
- Horizon
- —
- Notes
- Rider pose is engine-owned.
canRiderInteract()- Verdict
- Missing
- Horizon
- —
- Notes
- No rider-interaction query.
canBeRiddenUnderFluidType(type, rider)- Verdict
- Missing
- Horizon
- —
- Notes
entity_fires on mount/dismount, not on fluid riding.mount
canTrample(level, state, pos, distance)- Verdict
- Partial
- Horizon
farmland_(trample hooks/)farmland_ trample.rs - Notes
- Global
BlockEvent.FarmlandTrampleEvent; per-entity override is not exposed.
getClassification(includeVehicles)- Verdict
- Partial
- Horizon
host.entity_, content entity typeclassification - Notes
- A read of the template's category; a mod entity cannot set a different one per entity.
isAddedToLevel()- Verdict
- Partial
- Horizon
entity_/join_ level entity_,leave_ level host.entity_added_ to_ level - Notes
- State is tracked by the game; the handles tell a mod after the fact.
onAddedToLevel()- Verdict
- Partial
- Horizon
entity_(join_ level hooks/)base.rs - Notes
- Fires after the entity is in the level's lists; cancellable, unlike the method.
onRemovedFromLevel()- Verdict
- Partial
- Horizon
entity_(leave_ level hooks/)base.rs - Notes
- Fires after removal and only listens.
revive()- Verdict
- Missing
- Horizon
- —
- Notes
- No entity revive API.
isMultipartEntity()- Verdict
- Missing
- Horizon
- —
- Notes
- The dragon's parts are internal to the engine.
getParts()- Verdict
- Missing
- Horizon
- —
- Notes
- Same;
EntityRefnames dragon parts in some reads but does not expose the array.
getFluidTypeHeight(type)- Verdict
- Missing
- Horizon
- —
- Notes
- Fluid properties are per-fluid data; no per-entity height.
getMaxHeightFluidType()- Verdict
- Missing
- Horizon
- —
- Notes
- Same.
isInFluidType(state)- Verdict
- Partial
- Horizon
host.entity_,is_ in_ water entity_is_ in_ lava - Notes
- Only water and lava answered; no arbitrary fluid.
isInFluidType(type)- Verdict
- Partial
- Horizon
host.entity_,is_ in_ water entity_is_ in_ lava - Notes
- Same.
isInFluidType(predicate)- Verdict
- Partial
- Horizon
host.entity_,is_ in_ water entity_is_ in_ lava - Notes
- No predicate form.
isInFluidType()- Verdict
- Partial
- Horizon
host.entity_,is_ in_ water entity_is_ in_ lava - Notes
- "Any fluid" is water-or-lava only.
getFirstEyeInFluidType()- Verdict
- Missing
- Horizon
- —
- Notes
- Eye position per fluid is engine-owned.
isEyeInFluidType(type)- Verdict
- Missing
- Horizon
- —
- Notes
- Same.
canStartSwimming()- Verdict
- Missing
- Horizon
- —
- Notes
- Swimming start is engine-owned.
getFluidMotionScale(type)- Verdict
- Missing
- Horizon
- —
- Notes
- No per-entity fluid scale.
isPushedByFluid(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_push_ entity - Notes
- Per-fluid data, not a per-entity answer.
canSwimInFluidType(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_swim - Notes
- Per-fluid data.
canFluidExtinguish(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_extinguish - Notes
- Per-fluid data.
getFluidFallDistanceModifier(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.fall_distance_ modifier - Notes
- Per-fluid data.
canHydrateInFluidType(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_hydrate - Notes
- Per-fluid data.
getSoundFromFluidType(type, action)- Verdict
- Missing
- Horizon
- —
- Notes
- No fluid sound-action table.
sendPairingData(player, consumer)- Verdict
- Missing
- Horizon
- —
- Notes
- No pairing-payload API.
copyAttachmentsFrom(entity, wasDeath)- Verdict
- Partial
- Horizon
- attachments survive dimension change;
player_(clone hooks/)base.rs - Notes
- Copy rules are the attachment store's; there is no per-entity hook at the copy.
getBlockBounciness(pos, state)- Verdict
- Partial
- Horizon
BlockPart::(bounce_ on hooks/)block_ landing.rs - Notes
- Edits post-bounce movement instead of returning a bounciness factor.
ILivingEntityExtension
canSwimInFluidType(type)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_swim - Notes
- Per-fluid data, not per living entity.
jumpInFluid(type)- Verdict
- Missing
- Horizon
- —
- Notes
- Fluid jump behaviour is engine-owned.
sinkInFluid(type)- Verdict
- Missing
- Horizon
- —
- Notes
- Same.
canDrownInFluidType(type)- Verdict
- Partial
- Horizon
living_(drown hooks/),base.rs FluidTypeProperties.can_drown - Notes
- The global drown event can cancel or change damage; fluid data decides whether it applies.
moveInFluid(type, movement, fallDistance)- Verdict
- Missing
- Horizon
- —
- Notes
- Movement in fluid is engine-owned; no per-entity method.
onDamageTaken(container)- Verdict
- Partial
- Horizon
living_(damage_ post hooks/),living_ damage_ post.rs living_(incoming_ damage hooks/)base.rs - Notes
- Global server hooks: the incoming container before the hit, and a post-damage notice only once health dropped, not a per-entity callback for every hurt.
IBlockEntityExtension
Block entity parts are attached with r.block_entity_part; BlockEntityPart extends BlockPart and carries the block-entity hooks (crates/horizon-mod-vocab/src/hooks/ with scope = "block_entity"). Saved data and attachments are reachable through BlockEntityRef.
onDataPacket(connection, input)- Verdict
- Partial
- Horizon
BlockEntityPart::(block_ entity_ update_ tag hooks/)base.rs - Notes
- The server half (
getUpdateTag) is settable; the client's merge of the received tag is engine-side.
handleUpdateTag(input)- Verdict
- Partial
- Horizon
BlockEntityPart::(block_ entity_ update_ tag hooks/)base.rs - Notes
- Same: the data is covered, the client callback is not.
getPersistentData()- Verdict
- Covered
- Horizon
AttachmentStore,AttachmentHolder::BlockEntity - Notes
- Typed saved/synced attachments replace the writable compound.
onChunkUnloaded()- Verdict
- Missing
- Horizon
- —
- Notes
chunk_is the chunk event; there is no per-block-entity callback.unload
onLoad()- Verdict
- Partial
- Horizon
BlockEntityPart::(block_ entity hooks/)base.rs - Notes
- Initial saved data is set at creation, before the saved NBT is applied; no after-load notice.
requestModelDataUpdate()- Verdict
- Missing
- Horizon
- —
- Notes
- No model-data invalidation API.
getModelData()- Verdict
- Missing
- Horizon
- —
- Notes
- No
ModelData; drawing usesblock_and the model path.entity_ submit
invalidateCapabilities()- Verdict
- n/a
- Horizon
- capability providers are queried per lookup (
crates/)horizon-mod-vocab/ src/ parts/ block_ entities.rs - Notes
- There is no cached handler to invalidate.
applyStructureRotation(mirror, rotation)- Verdict
- Missing
- Horizon
- —
- Notes
- Structure rotation is engine-owned; no callback.
IFluidExtension
Fluid type facts are one record, FluidTypeProperties (crates/horizon-mod-vocab/src/block/fluid_states.rs), read with host.fluid_states().type_properties(key). They are static per fluid, not per position or block, and they are derived today: the record describes water's and lava's families and gives every other fluid inert values (crates/horizon-client/src/game/modding/native_block_states.rs). A mod's own fluid declares a sprite and tint, not its type properties, so "partial" below means the vanilla answer is readable but a mod fluid cannot set it.
getExplosionResistance(state, level, pos, explosion)- Verdict
- Missing
- Horizon
- —
- Notes
- No fluid explosion resistance.
getFluidType()- Verdict
- Partial
- Horizon
host.fluid_states().type_ properties - Notes
- Reads water's and lava's type record; a mod's own fluid cannot declare one and reads as inert.
canConvertToSource(state, level, pos)- Verdict
- Partial
- Horizon
create_(fluid_ source hooks/)create_ fluid_ source.rs - Notes
- Global
CreateFluidSourceEvent; not per-fluid and not a Part.
supportsBoating(state, boat)- Verdict
- Partial
- Horizon
FluidTypeProperties.supports_boating - Notes
- Static, and only a water-family fluid supports boating; a mod fluid cannot opt in.
getBlockPathType(state, level, pos, mob, canFloat)- Verdict
- Partial
- Horizon
BlockPart::(is_ pathfindable hooks/)is_ pathfindable.rs - Notes
- Block-level path computation type only; no fluid
PathType.
getAdjacentBlockPathType(state, level, pos, mob, pathType)- Verdict
- Missing
- Horizon
- —
- Notes
- No adjacent fluid path type.
canHydrate(state, level, pos, farmland)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_hydrate - Notes
- Static, and only a water-family fluid hydrates; a mod fluid cannot opt in.
canExtinguish(state, level, pos)- Verdict
- Partial
- Horizon
FluidTypeProperties.can_extinguish - Notes
- Static, and only a water-family fluid extinguishes; a mod fluid cannot opt in.
appendHoverText(stack, context, display, lines, flag)- Verdict
- Missing
- Horizon
- —
- Notes
FluidStackhas no tooltip hook.
IMenuTypeExtension
Menu types are content data (MenuType in crates/horizon-mod-package/src/content.rs, files under data/<id>/horizon/menu/), and the game's own menu engine opens them (menu::Kind::Mod). A MenuPart can answer slot rules, not construct a menu.
create(IContainerFactory)(static)- Verdict
- Partial
- Horizon
- content
MenuTypedeclaration - Notes
- Declares slot count, data slots and take-only slots, but cannot supply a factory that builds the client menu from server-sent data.
create(windowId, inventory, buffer)- Verdict
- Partial
- Horizon
- menu engine +
MenuPart::menu_ slot_ rules - Notes
- The engine builds the menu from the declaration; a mod cannot run code at construction.
What the follow-up issues cover
#1038 (blocks) and #1039 (items) were written from the earlier audit. Some of their rows have landed or become partial since and should be narrowed when they are filed:
- Changed on the block side:
shouldCheckWeakPowerandshould_redstone_wire_connect_to(the issue says reuse them) are Parts;getFlammability/getFireSpreadSpeedare nowfire_odds(state-based, without a position or direction);canSustainPlantiscan_sustain_plant(the soil) beforemay_place_on(the plant);canHarvestBlockiscan_harvest_blockbeforeplayer_harvest_check;isLadderisis_ladder;getToolModifiedStateis partlyblock_tool_modification. - Changed on the item side:
getEquipmentSlotisItemResource::equippable_slot;getCraftingRemainderhasItemPart::crafting_remainderplus content data andhost.item_crafting_remainder;canEquiphas theequippablecomponent;getXpRepairRatiohas a globalmending_repairthat changes the amount. - Block group rows that still need their own answer:
getExpDrop,onBlockExploded,getWeakChanges,onNeighborChange,getBounceRestitution,isSlimeBlock,isStickyBlock,canStickTo,onDestroyedByPlayer(all Partial or Missing above). - Item group rows that still need their own answer:
onEntityItemUpdate,canPerformAction(both Partial or Missing above). - Missing but not in either group: the remaining block, entity, block-entity and fluid rows marked Missing above; they have no follow-up issue yet. The largest are the entity fluid queries, block entity model data and fluid tooltips.
Edit this page on GitHub · Spotted something wrong? Open an issue .