Skip to main content

BlockPart

Trait BlockPart 

pub trait BlockPart:
    Send
    + Sync
    + 'static {
Show 42 methods // Provided methods fn neighbor_changed( &self, level: &mut dyn LevelTicksHost, event: &mut NeighborChangedEvent, ) { ... } fn random_tick( &self, level: &mut dyn LevelWriteHost, event: &mut RandomTickEvent, ) -> Flow { ... } fn tick_block( &self, level: &mut dyn LevelWriteHost, event: &mut TickBlockEvent, ) -> Flow { ... } fn update_shape( &self, level: &mut dyn LevelTicksHost, event: &mut UpdateShapeEvent, ) -> Option<BlockState> { ... } fn block_signal(&self, level: &dyn LevelHost, event: &mut BlockSignalEvent) { ... } fn is_signal_source( &self, level: &dyn LevelHost, event: &mut IsSignalSourceEvent, ) { ... } fn has_analog_output( &self, level: &dyn LevelHost, event: &mut HasAnalogOutputEvent, ) { ... } fn analog_output( &self, level: &dyn LevelHost, event: &mut AnalogOutputEvent, ) { ... } fn can_survive( &self, level: &dyn LevelHost, event: &mut CanSurviveEvent, ) -> Option<bool> { ... } fn may_place_on( &self, level: &dyn LevelHost, event: &mut MayPlaceOnEvent, ) -> Option<bool> { ... } fn is_valid_bonemeal_target( &self, level: LevelSide<'_>, event: &mut IsValidBonemealTargetEvent, ) -> Option<bool> { ... } fn is_bonemeal_success( &self, level: &mut dyn LevelRandomHost, event: &mut IsBonemealSuccessEvent, ) { ... } fn perform_bonemeal( &self, level: &mut dyn LevelWriteHost, event: &mut PerformBonemealEvent, ) { ... } fn state_for_placement( &self, level: &dyn LevelHost, event: &mut StateForPlacementEvent<'_>, ) -> Option<Option<BlockState>> { ... } fn fire_odds( &self, level: &dyn LevelHost, event: &mut FireOddsEvent, ) -> Option<(i32, i32)> { ... } fn smoke_source( &self, level: &dyn LevelHost, event: &mut SmokeSourceEvent, ) -> Option<bool> { ... } fn affect_neighbors_after_removal( &self, level: &dyn LevelHost, event: &mut AffectNeighborsAfterRemovalEvent<'_>, ) { ... } fn block_jump_factor( &self, context: &dyn LoopContext, event: &mut BlockJumpFactorEvent, ) { ... } fn block_speed_factor( &self, context: &dyn LoopContext, event: &mut BlockSpeedFactorEvent, ) { ... } fn fall_on( &self, level: &mut dyn LevelRandomHost, event: &mut FallOnEvent<'_>, ) { ... } fn bounce_on( &self, level: &mut dyn LevelRandomHost, event: &mut BounceOnEvent<'_>, ) { ... } fn block_render_visibility( &self, host: &dyn ClientHost, event: &mut BlockRenderVisibilityEvent, ) { ... } fn use_item_on( &self, host: &mut dyn ServerHost, event: &mut UseItemOnEvent<'_>, ) -> Option<InteractionResult> { ... } fn use_without_item( &self, host: &mut dyn ServerHost, event: &mut UseWithoutItemEvent<'_>, ) -> Option<InteractionResult> { ... } fn can_harvest_block( &self, host: HostSide<'_>, event: &mut CanHarvestBlockEvent, ) { ... } fn can_sustain_plant( &self, level: &dyn LevelHost, event: &mut CanSustainPlantEvent, ) -> Option<bool> { ... } fn clone_item_stack( &self, host: &dyn Host, event: &mut CloneItemStackEvent<'_>, ) -> Option<ItemStack> { ... } fn connects_to(&self, level: &dyn LevelHost, event: &mut ConnectsToEvent) { ... } fn contents_changed( &self, host: &mut dyn ServerHost, event: &mut ContentsChangedEvent, ) { ... } fn dispense_method( &self, host: &mut dyn ServerHost, event: &mut DispenseMethodEvent<'_>, ) -> Option<(Option<ItemStack>, i32)> { ... } fn entity_inside( &self, host: &mut dyn ServerHost, event: &mut EntityInsideEvent, ) { ... } fn exp_drop( &self, level: &dyn LevelHost, event: &mut ExpDropEvent<'_>, ) -> Option<i32> { ... } fn is_ladder(&self, context: &dyn LoopContext, event: &mut IsLadderEvent) { ... } fn is_pathfindable(&self, host: &dyn Host, event: &mut IsPathfindableEvent) { ... } fn item_after_vertical_collision( &self, host: HostSide<'_>, event: &mut ItemAfterVerticalCollisionEvent<'_>, ) -> Flow { ... } fn minecart_pass( &self, host: &mut dyn ServerHost, event: &mut MinecartPassEvent, ) { ... } fn on_block_exploded( &self, host: &mut dyn ServerHost, event: &mut OnBlockExplodedEvent<'_>, ) { ... } fn on_neighbor_change( &self, level: &dyn LevelHost, event: &mut OnNeighborChangeEvent, ) { ... } fn remove_block( &self, level: &dyn LevelHost, event: &mut RemoveBlockEvent, ) -> Option<BlockState> { ... } fn should_check_weak_power( &self, level: &dyn LevelHost, event: &mut ShouldCheckWeakPowerEvent, ) { ... } fn should_redstone_wire_connect_to( &self, level: &dyn LevelHost, event: &mut ShouldRedstoneWireConnectToEvent, ) { ... } fn weak_changes(&self, level: &dyn LevelHost, event: &mut WeakChangesEvent) { ... }
}
Expand description

A block’s part: code attached through Registrar to one block, a mod’s own or vanilla’s. Its methods are the scoped hooks’, asked only for the blocks it is attached to: a scoped hook has no Hooks method. They may run on the window’s thread or the server thread. Annotate each part trait implementation with horizon_part to derive its subscriptions.

Provided Methods§

fn neighbor_changed( &self, level: &mut dyn LevelTicksHost, event: &mut NeighborChangedEvent, )

An authoritative server is about to deliver neighborChanged. State and block IDs are valid in this level’s registries for this call. The host is the level with its ticks, as vanilla’s neighborChanged gets the level: a part may read its inputs (signal, has_neighbor_signal) and schedule its tick here, as a diode does (DiodeBlock.checkTickOnNeighbor). Side: server.

fn random_tick( &self, level: &mut dyn LevelWriteHost, event: &mut RandomTickEvent, ) -> Flow

An authoritative server’s ServerLevel.tickChunk is about to random-tick the block state at pos (BlockState.randomTick): only blocks that tick randomly, a mod’s as its vanilla template block does. Bone meal’s random ticks (StemBlock.performBonemeal) don’t fire it. Change the block with native_set_block_property and set handled to skip the block’s own random tick (a mod crop growing its own way); a block changed without handled takes its own random tick as it is now, if it still ticks randomly. Lava’s fluid random tick runs either way. Side: server.

Return Flow::Cancel to take it: this sets handled, and later parts are skipped.

fn tick_block( &self, level: &mut dyn LevelWriteHost, event: &mut TickBlockEvent, ) -> Flow

An authoritative server’s ServerLevel.tickBlock is about to run a due scheduled tick of the block state at pos (BlockState.tick): the block is still the one the tick was scheduled for. Change the block with native_set_block_property and set handled to skip the block’s own tick; a block changed without handled takes its own tick as it is now, if it is still the tick’s block. Side: server.

Return Flow::Cancel to take it: this sets handled, and later parts are skipped.

fn update_shape( &self, level: &mut dyn LevelTicksHost, event: &mut UpdateShapeEvent, ) -> Option<BlockState>

An authoritative server is about to compute the state the block state at pos takes now that its neighbour in direction is neighbour (BlockBehaviour.updateShape). state may not be in the world yet (a piston landing it): decide from state, not from the block at pos. Answer only for your own blocks: put the new state in new (state keeps the block as it is; air breaks it, with its drops, on a neighbour update) and the block’s own updateShape doesn’t run, nor the ticks it would schedule. The level is read-only, as vanilla’s LevelReader; ticks go through native_schedule_block_tick and native_schedule_fluid_tick with ticks (ScheduledTickAccess). It runs often, at least six times per setBlock that updates shapes (more for redstone wire’s diagonals and knock-on updates): keep it short. Side: server.

Return Some to set new; the first part returning Some wins.

fn block_signal(&self, level: &dyn LevelHost, event: &mut BlockSignalEvent)

The redstone signal the block state at pos gives on its face, the side that touches the block reading it: BlockState.getDirectSignal when direct (what passes through a block it touches, as a lever’s does), else getSignal. signal holds vanilla’s answer: change it when the block is yours (0 to 15; anything else is clamped). Asked very often, from inside the level’s update, so answer from your own state: check the block first, and don’t read or change the world here. When the answer changes, and once the block is placed, call level.update_neighbors(host, pos, state, NeighbourUpdate::Neighbours). Authoritative servers only. Side: server.

fn is_signal_source( &self, level: &dyn LevelHost, event: &mut IsSignalSourceEvent, )

BlockState.isSignalSource: set source for a block of yours that gives a signal, so redstone wire beside it connects to it. Authoritative servers only. Side: server.

fn has_analog_output( &self, level: &dyn LevelHost, event: &mut HasAnalogOutputEvent, )

BlockState.hasAnalogOutputSignal: set output for a block of yours that comparators read (how full or far along it is, as a composter’s level), so they ask native_analog_output. Asked from inside the level’s update: answer from state alone. Authoritative servers only. Side: server.

Every part gets event.output in order and may add, change or remove output.

fn analog_output(&self, level: &dyn LevelHost, event: &mut AnalogOutputEvent)

BlockState.getAnalogOutputSignal: the signal a comparator reads from the block state at pos, face the side that touches the comparator (or the conductor in front of it). output holds vanilla’s answer: change it when the block is yours (0 to 15; anything else is clamped). Asked only for blocks native_has_analog_output answered for, from inside the level’s update: don’t change the world here. When the answer changes without the block’s state changing, call level.update_neighbors(host, pos, state, NeighbourUpdate::OutputSignal); a change of state through native_set_block or native_set_block_property (neighbour updates on) tells the comparators itself, as vanilla’s Level.setBlock does. Authoritative servers only. Side: server.

Every part gets event.output in order and may add, change or remove output.

fn can_survive( &self, level: &dyn LevelHost, event: &mut CanSurviveEvent, ) -> Option<bool>

On an authoritative server, BlockState.canSurvive for state at pos (BlockBehaviour.canSurvive), before the block answers it: as it is placed (BlockItem.canPlace), from a shape update of a block whose template checks it (a plant, a torch, a sign: false breaks the block with its drops), and wherever else vanilla asks. state may not be in the world yet, so decide from state. Answer only for your own blocks: Some(false) refuses the spot, Some(true) allows it, and the block’s own rule doesn’t run. The level is read-only. Asked on every shape update of such a block: keep it short. Side: server.

Return Some to set survives; the first part returning Some wins.

fn may_place_on( &self, level: &dyn LevelHost, event: &mut MayPlaceOnEvent, ) -> Option<bool>

On an authoritative server, VegetationBlock.mayPlaceOn for the plant state on ground at ground_pos, before the plant answers it: the blocks a mod plant (one whose template is a vanilla plant, such as a crop) can stand on. Its template’s canSurvive asks it, so the plant is refused there and pops off when its ground changes to one it can’t stand on. Answer only for your own blocks. The level is read-only. Side: server.

Return Some to set may; the first part returning Some wins.

fn is_valid_bonemeal_target( &self, level: LevelSide<'_>, event: &mut IsValidBonemealTargetEvent, ) -> Option<bool>

A block nothing in Horizon knows a BonemealableBlock for is about to take bone meal: vanilla’s BonemealableBlock.isValidBonemealTarget, state the block’s own state at pos. Answer valid for your own blocks: the meal is used up on one as vanilla uses it up (the growth particles and the sound follow, whether or not the roll below grows it), from a player’s BoneMealItem.useOn, from a dispenser and, on a crop (a villager bonemeals only a CropBlock), from a villager. Asked on both sides, as vanilla asks it on both, so a client predicts the use with your answer: say no where you can only grow on a server (match LevelSide). Some(false) refuses the meal, even on a block whose template takes it (vanilla’s growCrop then keeps the meal); left None, the block keeps the BonemealableBlock its template gives it, or takes no bone meal. Side: both.

Return Some to set valid; the first part returning Some wins.

fn is_bonemeal_success( &self, level: &mut dyn LevelRandomHost, event: &mut IsBonemealSuccessEvent, )

BonemealableBlock.isBonemealSuccess for a block that answered native_is_valid_bonemeal_target, after it did: set success to grow it this time. Vanilla draws the level’s random here (isBonemealSuccess(Level, RandomSource, BlockPos, BlockState)), so draw from native_level_random to keep vanilla’s order. Authoritative servers only. Side: server.

Every part gets event.success in order and may add, change or remove success.

fn perform_bonemeal( &self, level: &mut dyn LevelWriteHost, event: &mut PerformBonemealEvent, )

BonemealableBlock.performBonemeal for a block that answered native_is_valid_bonemeal_target and whose native_is_bonemeal_success said yes: grow it here, state its state at pos. The meal is used up either way. Change the block with the level’s native_set_block_property, and schedule with native_schedule_block_tick (ticks is the hook’s). Authoritative servers only. Side: server.

fn state_for_placement( &self, level: &dyn LevelHost, event: &mut StateForPlacementEvent<'_>, ) -> Option<Option<BlockState>>

A block is about to take the state it is placed in (Block.getStateForPlacement(BlockPlaceContext)), state the block’s own default state. Answer only for your blocks: put the state you want in answer as Some(Some(state)) — a state of that block, as vanilla sets properties on its own defaultBlockState (another block’s is ignored) — or refuse the placement with Some(None): the block goes nowhere and the stack is kept, as vanilla’s null. Left empty, the block’s own placement runs. context is vanilla’s BlockPlaceContext (the clicked face, the placer’s rotation, the clicked position, whether the clicked block is being replaced, the item in hand) and fluid the fluid in the position the block would go in, which a waterlogged block reads. Build the state from state with native_state_with_property, and know whether state is yours with native_state_block. It is asked for every placer that goes through vanilla’s placement (a player’s BlockItem.place, a dispenser’s DirectionalPlaceContext), and the answer still takes its survival and entity obstruction checks. A trait mod returns Some(Some(state)) to choose a state, Some(None) to refuse, or None to leave the answer to the next mod or vanilla. Changes to the event’s fluid copy are mod-provided data forwarded to later Parts, never consumed by the engine. Authoritative servers only. Side: server.

Return Some to set answer; the first part returning Some wins.

fn fire_odds( &self, level: &dyn LevelHost, event: &mut FireOddsEvent, ) -> Option<(i32, i32)>

On an authoritative server, how fire treats the block state (FireBlock.setFlammable(block, igniteOdds, burnOdds)): put (ignite, burn) in odds for your own blocks, and vanilla’s table isn’t read. Ignite odds above zero let fire stand beside the block and spread into the air around it (planks 5, wool 30, leaves 30); burn odds are how fast fire destroys it (planks 20, wool 60, leaves 60). (0, 0) never burns; keep both within vanilla’s 0 to 100. A waterlogged state never burns and isn’t asked. Answer only for your own blocks and leave odds empty otherwise; the level is read-only. Asked hundreds of times per fire tick: keep it short. Side: server.

Return Some to set odds; the first part returning Some wins.

fn smoke_source( &self, level: &dyn LevelHost, event: &mut SmokeSourceEvent, ) -> Option<bool>

On an authoritative server, CampfireBlock.isSmokeSource for the block state under a campfire, as the campfire is placed or the block under it changes: Some(true) for your own blocks makes the campfire a signal fire whose smoke rises higher, as over a hay bale. The level is read-only. Side: server.

Return Some to set smoke; the first part returning Some wins.

fn affect_neighbors_after_removal( &self, level: &dyn LevelHost, event: &mut AffectNeighborsAfterRemovalEvent<'_>, )

Block.affectNeighborsAfterRemoval for a mod’s block: an authoritative server removed the block state from pos (moved: a piston pushed it) and has run its template class’s own updates. Push onto updates the neighbour updates it wants, in order: OutputSignal (updateNeighbourForOutputSignal), Neighbours (updateNeighborsAt) and NeighboursExcept(direction) (updateNeighborsAtExceptFromFacing); the level runs each at once, as the block’s own override would. Answered from inside the level’s write: it reads, and cannot write blocks or spawn entities. Side: server.

Every part gets event.updates in order and may add, change or remove updates.

fn block_jump_factor( &self, context: &dyn LoopContext, event: &mut BlockJumpFactorEvent, )

The jump factor of a block state this part is attached to (Block.getJumpFactor, which Entity.getBlockJumpFactor reads for the player, the cube, the panda, the rabbit and every other living jumper) is being read; vanilla’s values are 0.5 for honey and 1.0 for the rest. A part may change factor (event.factor). The entity reads the block at its feet and, when that gives 1.0, the block below it, so a changed factor takes part in that choice exactly as the block’s own would. It runs for each read, on both sides and on the client’s replayed ticks, so register the mod on both and keep the listener a pure function of its inputs. It is given the loop context of the side that ticks the entity, and takes no Host. NeoForge’s counterpart Block.getJumpFactor() is a method of the block, with no bus event, so this is a part method only; a mod reacting to its own blocks uses this part. Diverges from upstream: new hook. Side: both.

fn block_speed_factor( &self, context: &dyn LoopContext, event: &mut BlockSpeedFactorEvent, )

The speed factor of a block state this part is attached to (Block.getSpeedFactor, which Entity.getBlockSpeedFactor reads for the player, mobs, boats and minecarts where vanilla reads it) is being read; vanilla’s values are 0.4 for honey and soul sand and 1.0 for the rest. A part may change factor (event.factor). The entity reads the block at its feet and, when that is not water or a bubble column and gives 1.0, the block below it, so a changed factor takes part in that choice exactly as the block’s own would. It runs for each read, on both sides and on the client’s replayed ticks, so register the mod on both and keep the listener a pure function of its inputs. It is given the loop context of the side that ticks the entity, and takes no Host. NeoForge’s counterpart Block.getSpeedFactor() is a method of the block, with no bus event, so this is a part method only; a mod reacting to its own blocks uses this part. Diverges from upstream: new hook. Side: both.

fn fall_on(&self, level: &mut dyn LevelRandomHost, event: &mut FallOnEvent<'_>)

An entity landed on a block state this part is attached to (Block.fallOn), after falling event.distance blocks. event.damage is the fall damage the entity calculated, before hurt handling and the fall sounds: change it, and zero prevents both. An entity that cannot be hurt by the fall (creative, fall immune) is told with zero damage and keeps its immunity, and a cancelled fall still lands. It runs inside the entity’s move, on the level random host: it reads blocks and draws the level’s random in vanilla’s order, and cannot write. A write the override makes (farmland turning to dirt, a turtle egg breaking) is asked with event.request(LandingWrite::SetBlock(state)) or LandingWrite::DestroyBlock { drop } and lands at the block the entity landed on once the entity’s batch has ticked, in the order asked, if the block is still the state it landed on. SetBlock takes an API BlockState. The complete requested batch is checked before queuing: an invalid key or ordinal refuses all writes and sibling outputs from that callback, including damage. The original landed-state guard is checked once per batch, not between its ordered writes. Players, mobs and dropped items land here (an item as an EntityRef of kind minecraft:item, with zero damage: items take none); projectiles and the other entities do not yet. Side: server.

Every part gets event.damage in order and may add, change or remove damage.

fn bounce_on( &self, level: &mut dyn LevelRandomHost, event: &mut BounceOnEvent<'_>, )

An entity bounced off a block state this part is attached to (Block.bounceOn), after falling event.fall_distance blocks. It fires only when the entity bounced, just before vanilla sets its movement. event.movement is the movement the bounce leaves it (x, y, z): change it to change what the entity keeps. It runs inside the entity’s move, on the level random host: it reads blocks and draws the level’s random in vanilla’s order, but writes nothing. Players and mobs bounce here; dropped items and the other entities do not yet. Side: server.

Every part gets event.movement in order and may add, change or remove movement.

fn block_render_visibility( &self, host: &dyn ClientHost, event: &mut BlockRenderVisibilityEvent, )

Hides a block state from the mesher: set event.hidden and the state draws nothing, as if its blocks were air. Its neighbours’ faces toward it show, it no longer hides what is behind it, and its fluid layer and block entity are not drawn; light, collision and the server are untouched. The answer depends on the state alone and is resolved at mesh time, never per frame: the game asks once for every state when the client joins a world, and again for every state each time a mod calls ClientHost::refresh_render_visibility (a toggle, an ore scanner). Attach the part to vanilla blocks with block_part_tag. With no mod answering, the mesher pays nothing. Side: client.

Every part gets event.hidden in order and may add, change or remove hidden.

fn use_item_on( &self, host: &mut dyn ServerHost, event: &mut UseItemOnEvent<'_>, ) -> Option<InteractionResult>

BlockBehaviour.useItemOn: the block’s own behaviour, with the held item, on the server for each player. An answer replaces the template’s behaviour; TryWithEmptyHand tries useWithoutItem on the main hand, and Pass goes on to the item’s useOn. Side: server.

Return Some to set answer; the first part returning Some wins.

fn use_without_item( &self, host: &mut dyn ServerHost, event: &mut UseWithoutItemEvent<'_>, ) -> Option<InteractionResult>

BlockBehaviour.useWithoutItem: the captured state’s empty-hand method, after useItemOn asks for it, on the server and main hand only. Side: server.

Return Some to set answer; the first part returning Some wins.

fn can_harvest_block( &self, host: HostSide<'_>, event: &mut CanHarvestBlockEvent, )

Whether the player player’s tool harvests the block state at pos (IBlockExtension.canHarvestBlock, what Player.hasCorrectToolForDrops asks of the block). can_harvest starts with vanilla’s answer: false for a block that needs a tool the player’s held item is not, true otherwise. Set it for your own block; false breaks the block and drops nothing, and the dig is slowed as vanilla slows a wrong tool. The part answers first and the global player_harvest_check hears the result, so a mod reacting to every block still has the last word. Asked wherever the harvest rule is: the dig’s progress (both sides, so a client predicts it), the break and a door’s break. Side: both.

Every part gets event.can_harvest in order and may add, change or remove can_harvest.

fn can_sustain_plant( &self, level: &dyn LevelHost, event: &mut CanSustainPlantEvent, ) -> Option<bool>

On an authoritative server, IBlockExtension.canSustainPlant for the soil ground at ground_pos and the plant state above it, asked before the plant answers its own mayPlaceOn (may_place_on) wherever vanilla’s plant rule reads its ground: when the plant is placed, from its shape update and wherever else vanilla asks. Some(true) lets the plant stand there, Some(false) refuses it (a planted one pops off when its ground changes to this block), and left None the plant’s own may_place_on answers, as vanilla’s does. Answer only for your own soil. The level is read-only. Runs on every shape update of a plant over a part’s block: keep it short. Side: server.

Return Some to set sustains; the first part returning Some wins.

fn clone_item_stack( &self, host: &dyn Host, event: &mut CloneItemStackEvent<'_>, ) -> Option<ItemStack>

BlockBehaviour.getCloneItemStack, asked by ServerGamePacketListenerImpl.handlePickItemFromBlock. include_data is true for a creative player picking with Ctrl. Leave stack unset to keep the game’s item. Creative breaking, such as a beehive’s playerWillDestroy, does not ask this query. Server-side. Side: server.

Return Some to set stack; the first part returning Some wins.

fn connects_to(&self, level: &dyn LevelHost, event: &mut ConnectsToEvent)

Whether a fence, wall, or iron bars or pane of yours connects a side: set connected to say whether the block state at pos connects toward neighbour, the state beside it, direction pointing from the block to that neighbour and face_solid whether the neighbour’s face toward the block is sturdy. kind names vanilla’s rule, and connected holds its answer: ConnectionKind::Fence is FenceBlock.connectsTo (a solid face, a fence of the same kind or a gate across the arm), Wall is WallBlock.connectsTo (a wall, a solid face, iron bars or a pane, or a gate across the side; a connected side is still low or tall from the block above) and Bars is IronBarsBlock.attachsTo for iron bars and glass panes (a solid face, bars or a pane, or a wall; vanilla’s rule ignores direction). Change it, to false as well as to true, when the block is your own. Asked whenever the block settles its shape toward a side or is placed, inside the level’s update: answer from the arguments without touching the world. Only the block’s own part is asked, so vanilla blocks cost nothing. Authoritative servers only. Contract version 2: version 1 was fence_connects_to, for fences alone and without kind. Diverges from upstream: new hook. Side: server.

Every part gets event.connected in order and may add, change or remove connected.

fn contents_changed( &self, host: &mut dyn ServerHost, event: &mut ContentsChangedEvent, )

A server-only, non-cancellable backing-block storage notice at Container.setChanged / BlockEntity.setChanged, after the write and before existing dirty/comparator updates. The event carries LevelRef, BlockPos and BlockState. Native After::Changed transactions notify each backing block once at the root commit, never on abort or simulation; explicit set_changed invalidates even equal contents. Nested writes to the block whose notice is active still apply but do not re-enter its notice; writes to another block notify normally. Double containers notify each backing component, not the other half merely refreshed for comparators. Vehicle/menu placeholder coordinates are excluded. Replaces the Create port positional contents_changed mixin for depot, package and schematic storage; there is no matching NeoForge bus event. Side: server.

fn dispense_method( &self, host: &mut dyn ServerHost, event: &mut DispenseMethodEvent<'_>, ) -> Option<(Option<ItemStack>, i32)>

DispenserBlock.getDispenseMethod, before the item’s dispense_item: the block the dispenser faces chooses what the dispense does, for any item, including vanilla items, on the authoritative server (not droppers). state is the block at pos moved by facing (air included), and the part is asked only for that block. An answer wins: no item part is asked and vanilla’s behaviour doesn’t run. The answer is dispense_item’s: a remainder of None empties the slot, Some(stack) replaces it (the hook owns consumption: no extra item is removed afterwards), and event is the level event played with the smoke: 1000 the click, 1001 the fail sound, or 0 for nothing at all. Leave answer None and dispense_item decides, as it did before. Side: server.

Return Some to set answer; the first part returning Some wins.

fn entity_inside( &self, host: &mut dyn ServerHost, event: &mut EntityInsideEvent, )

An entity is inside a block state this part is attached to (Block.entityInside). event.precise is Entity.checkInsideBlocks’ flag: the entity moved nearly a block, or its box at the target touches the block. Fires for mobs, projectiles, dropped items and players on the server, once per entity and block per move, after the entity-kind batch (or the player’s turn) has ticked, not mid-sweep; a contact whose entity is gone or whose block changed is dropped. Vanilla’s InsideBlockEffectApplier is not exposed. Side: server.

fn exp_drop( &self, level: &dyn LevelHost, event: &mut ExpDropEvent<'_>, ) -> Option<i32>

Experience before enchantments (IBlockExtension.getExpDrop). First answer replaces vanilla sampling; the global break_block event may override it. Answers are clamped to 0..=32767. A panic unwinds before the answer is applied. Side: server.

Return Some to set experience; the first part returning Some wins.

fn is_ladder(&self, context: &dyn LoopContext, event: &mut IsLadderEvent)

Whether a living entity climbs the block state this part is attached to (IBlockExtension.isLadder, which LivingEntity.onClimbable asks of the block the entity stands in). entity is the climber’s id and pos the block it stands in; state is that block’s state. ladder starts with vanilla’s answer, whether the block is in #minecraft:climbable, and a part may set either value: true makes the block climbable as a ladder is, false refuses it though the tag lists it. A gliding entity (isFallFlying) in a #minecraft:can_glide_through block, a spectator and a player who is flying are never asked, as vanilla never climbs for them, and an open trapdoor over a ladder climbs as before. Read for the player, the mobs, and the climbing a mod reads through LivingRef::is_climbing. It fires on both sides and on the client’s replayed ticks, so register the mod on both and keep the listener a pure function of its inputs. It is given the loop context of the side that ticks the entity, and takes no Host. With no part attached to the state, the owning game checks the hook subscription and prepared API block key before any event conversion, so the cost is one table lookup. Armor stands never ask it. Diverges from upstream: new hook. Side: both.

fn is_pathfindable(&self, host: &dyn Host, event: &mut IsPathfindableEvent)

Changes whether a path of a PathComputationType (Land, Water or Air) may go through a block state. event.pathfindable starts with the block’s own answer. The answer depends on the state and the type alone: the game asks once per state and type when parts resolve, at world load and on every /reload, so path finding and spawning read the stored answer and a part cannot answer from a position, level or time. Side: server.

Every part gets event.pathfindable in order and may add, change or remove pathfindable.

fn item_after_vertical_collision( &self, host: HostSide<'_>, event: &mut ItemAfterVerticalCollisionEvent<'_>, ) -> Flow

native_item_after_vertical_collision lends a dropped item’s active stack after vertical collision response, before block effects, merging and pickup. The block is the one selected by the legacy on-position query. client identifies prediction. Set discard (trait Flow::Cancel) or set the stack to None to consume the item without loot or pickup. A movement skipped by the normal item tick sends no notification. Bundles need “hooks”: @API:item_after_vertical_collision@. Side: both.

Return Flow::Cancel to take it: this sets discard, and later parts are skipped.

fn minecart_pass( &self, host: &mut dyn ServerHost, event: &mut MinecartPassEvent, )

A minecart passed over a rail block state this part is attached to (the moment AbstractMinecart calls activateMinecart on an activator rail, for every rail; Forge’s IBaseRailExtension.onMinecartPass, which NeoForge 26.3 no longer has, so this hook has no counterpart). event.entity is the cart, event.pos the rail. With the old minecart physics it fires once per tick the cart is on a rail; with minecart_improvements once per track iteration, so a fast cart can pass several times in a tick. It fires after the cart’s batch has ticked, not mid-move, so a write the part makes (a velocity change through the cart handle) lands on the stored cart, and a pass whose cart is gone or whose rail changed is dropped. Only a rail state a part listens for is recorded; with no such part nothing is kept. Diverges from upstream: new hook. Side: server.

fn on_block_exploded( &self, host: &mut dyn ServerHost, event: &mut OnBlockExplodedEvent<'_>, )

An explosion destroys this block, before removal and while its live block entity is readable. Writes are allowed; the engine still replaces the cell with air afterwards, including a replacement written by the part. Side: server.

fn on_neighbor_change( &self, level: &dyn LevelHost, event: &mut OnNeighborChangeEvent, )

A neighbouring block entity changed, was created or removed. Vanilla comparator processing runs first. Side: server.

fn remove_block( &self, level: &dyn LevelHost, event: &mut RemoveBlockEvent, ) -> Option<BlockState>

Choose the state left by removing your block. Return a state in answer to replace vanilla’s fluid block (air when dry), or leave it unanswered. Only the removed block’s Part is asked, on the authoritative server. The replacement must be a registered block state; an invalid answer is refused with a diagnostic and vanilla’s replacement is written instead. The normal setBlock effects and flags 3 (+64 when moved by a piston) apply to the written state. The level is read-only during this call. Side: server.

Return Some to set answer; the first part returning Some wins.

fn should_check_weak_power( &self, level: &dyn LevelHost, event: &mut ShouldCheckWeakPowerEvent, )

IBlockExtension.shouldCheckWeakPower: set check to decide whether indirect power is read through this block. check starts with vanilla’s conductor answer. direction is the input side of the block being powered, opposite the queried block’s output side. Authoritative servers only. Side: server.

Every part gets event.check in order and may add, change or remove check.

fn should_redstone_wire_connect_to( &self, level: &dyn LevelHost, event: &mut ShouldRedstoneWireConnectToEvent, )

BlockBehaviour.shouldRedstoneWireConnectTo: set connected to say whether redstone wire connects to the block state at pos. direction points from the wire toward the neighbouring block, or is None when the wire asks about the block above or below. connected holds vanilla’s answer: change it when the block is yours. Asked whenever wire settles its shape: answer from state and pos without touching the world. When the answer changes, and once the wire is placed, update its neighbours (level.update_neighbors). Authoritative servers only. Side: server.

Every part gets event.connected in order and may add, change or remove connected.

fn weak_changes(&self, level: &dyn LevelHost, event: &mut WeakChangesEvent)

Whether this block receives block entity changes through an adjacent conductor. Starts false. Side: server.

Every part gets event.receive in order and may add, change or remove receive.

Trait Implementations§

§

impl Wire for Box<dyn BlockPart>

§

const MIN: usize = 8

Minimum encoded size, used to reject impossible collection lengths.
§

fn put(&self, out: &mut Writer)

Encodes this value, recording failures on the writer.
§

fn put_owned(self, out: &mut Writer)

Consumes owned data when a resource’s ownership must cross the boundary.
§

fn take(input: &mut Reader<'_>) -> Result<Box<dyn BlockPart>, WireError>

Decodes one value, leaving any following bytes for the caller.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§