Class BlockPlacementManager

java.lang.Object
me.hackware.api.BlockPlacementManager

public class BlockPlacementManager extends Object
Centralized block-placement manager. Handles placement rate-limiting, per-block cooldowns, air-place, rotation, offhand swap tricks, and placement sounds.

Configuration is read through AntiCheatBridge.PlacementPolicy. Ported from Meteor's BlockPlacementManager, adapted to Hackware APIs and Mojang mappings.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
     
  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    beginPlacement(List<net.minecraft.core.BlockPos> positions, net.minecraft.world.item.Item item)
    Begins a placement transaction with a list of positions.
    boolean
    beginPlacement(net.minecraft.core.BlockPos position, net.minecraft.world.level.block.state.BlockState state, net.minecraft.world.item.Item item)
    Begins a placement transaction.
    static boolean
    canPlaceOver(net.minecraft.core.BlockPos pos)
    Returns true if a block can be placed at this position (either the block is replaceable, or it's an insta-breakable block that BPM will clear with a break packet before placing).
    boolean
    checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos)
     
    boolean
    checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state)
     
    boolean
    checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state, net.minecraft.world.level.block.state.BlockState desiredState)
     
    void
     
    void
    forceResetPlaceCooldown(net.minecraft.core.BlockPos blockPos)
     
    get()
     
    int
    Returns packets sent in the current rate-limit window (0 when idle/reset).
    static net.minecraft.core.Direction
    getPlaceOnDirection(net.minecraft.core.BlockPos pos)
     
    int
    Returns how many placement packets can still be sent in the current rate-limit window.
    long
    Returns the timestamp the current rate-limit window started, or -1 if idle.
    void
    Register event handlers.
    static boolean
    isInstaBreakAndShouldClear(net.minecraft.world.level.block.state.BlockState state, net.minecraft.core.BlockPos blockPos)
    Returns true if the given non-replaceable block can be insta-broken (zero hardness) and therefore should be cleared with a break packet immediately before placement.
    boolean
    isOnPlaceCooldown(net.minecraft.core.BlockPos blockPos)
    Returns true if the position is still on per-block retry cooldown.
    boolean
    placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos)
    Places a single block.
    boolean
    placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, boolean ignorePerBlockCooldown)
    Placement variant that can bypass the per-position retry cooldown (AntiCheatBridge.PlacementPolicy.perBlockCooldownMs()).
    boolean
    placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state)
     
    boolean
    placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state, boolean ignorePerBlockCooldown)
     
    List<net.minecraft.core.BlockPos>
    placeBlocksBatch(List<net.minecraft.core.BlockPos> blocks, net.minecraft.world.item.Item item)
    Batch placement — keeps the swap open and sends multiple placement packets.
    List<net.minecraft.core.BlockPos>
    placeBlocksBatch(List<net.minecraft.core.BlockPos> blocks, net.minecraft.world.item.Item item, boolean asymmetric)
    Batch placement variant.
    List<net.minecraft.core.BlockPos>
    placeBlocksBatchWithState(List<BlockPlacementManager.PlacementRequest> blocks, net.minecraft.world.item.Item item)
    Batch placement with desired block states (for oriented slabs, stairs, etc.).
    List<net.minecraft.core.BlockPos>
    placeBlocksBatchWithState(List<BlockPlacementManager.PlacementRequest> blocks, net.minecraft.world.item.Item item, boolean asymmetric)
    Batch placement with desired block states (for oriented slabs, stairs, etc.).
    void
    removePendingSound(net.minecraft.core.BlockPos pos)
    Remove a pending sound entry so the client-side sound is not played when the server confirms the block update (avoids double sounds).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • get

      public static BlockPlacementManager get()
    • init

      public void init()
      Register event handlers. Call once during mod init.
    • beginPlacement

      public boolean beginPlacement(net.minecraft.core.BlockPos position, net.minecraft.world.level.block.state.BlockState state, net.minecraft.world.item.Item item)
      Begins a placement transaction. Swaps the item into the main hand. Must be followed by placeBlock(net.minecraft.world.item.Item, net.minecraft.core.BlockPos) calls and then endPlacement().
    • beginPlacement

      public boolean beginPlacement(List<net.minecraft.core.BlockPos> positions, net.minecraft.world.item.Item item)
      Begins a placement transaction with a list of positions. Succeeds if at least one position is valid for placement.
    • placeBlock

      public boolean placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos)
      Places a single block. Must be called between beginPlacement(net.minecraft.core.BlockPos, net.minecraft.world.level.block.state.BlockState, net.minecraft.world.item.Item) and endPlacement(), or standalone (will use SwapManager internally).
    • placeBlock

      public boolean placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, boolean ignorePerBlockCooldown)
      Placement variant that can bypass the per-position retry cooldown (AntiCheatBridge.PlacementPolicy.perBlockCooldownMs()). Used by Surround so it isn't throttled re-placing the same slot; all other modules keep the retry delay.
    • placeBlock

      public boolean placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state)
    • placeBlock

      public boolean placeBlock(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state, boolean ignorePerBlockCooldown)
    • placeBlocksBatch

      public List<net.minecraft.core.BlockPos> placeBlocksBatch(List<net.minecraft.core.BlockPos> blocks, net.minecraft.world.item.Item item)
      Batch placement — keeps the swap open and sends multiple placement packets. Returns the positions that were actually placed.
    • placeBlocksBatch

      public List<net.minecraft.core.BlockPos> placeBlocksBatch(List<net.minecraft.core.BlockPos> blocks, net.minecraft.world.item.Item item, boolean asymmetric)
      Batch placement variant.
      Parameters:
      asymmetric - when true, a block item that has to be silent-swapped up from the deep inventory is left in the hotbar afterward instead of being swapped back (see SwapManager.beginSwap(Item, boolean, boolean)). Continuous builders (Scaffold, HighwayCleaner) set this so they promote the block into the hotbar once and reuse it, instead of paying a swap-back every tick.
    • placeBlocksBatchWithState

      public List<net.minecraft.core.BlockPos> placeBlocksBatchWithState(List<BlockPlacementManager.PlacementRequest> blocks, net.minecraft.world.item.Item item)
      Batch placement with desired block states (for oriented slabs, stairs, etc.).
    • placeBlocksBatchWithState

      public List<net.minecraft.core.BlockPos> placeBlocksBatchWithState(List<BlockPlacementManager.PlacementRequest> blocks, net.minecraft.world.item.Item item, boolean asymmetric)
      Batch placement with desired block states (for oriented slabs, stairs, etc.).
      Parameters:
      asymmetric - when true, an item that has to be silent-swapped up from the deep inventory is left in the hotbar afterward instead of being swapped back (see SwapManager.beginSwap(Item, boolean, boolean)).
    • endPlacement

      public void endPlacement()
    • forceResetPlaceCooldown

      public void forceResetPlaceCooldown(net.minecraft.core.BlockPos blockPos)
    • isOnPlaceCooldown

      public boolean isOnPlaceCooldown(net.minecraft.core.BlockPos blockPos)
      Returns true if the position is still on per-block retry cooldown.
    • getRemainingBudget

      public int getRemainingBudget()
      Returns how many placement packets can still be sent in the current rate-limit window.
    • getPacketsSent

      public int getPacketsSent()
      Returns packets sent in the current rate-limit window (0 when idle/reset).
    • getWindowStartTimestamp

      public long getWindowStartTimestamp()
      Returns the timestamp the current rate-limit window started, or -1 if idle.
    • checkPlacement

      public boolean checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos)
    • checkPlacement

      public boolean checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state)
    • isInstaBreakAndShouldClear

      public static boolean isInstaBreakAndShouldClear(net.minecraft.world.level.block.state.BlockState state, net.minecraft.core.BlockPos blockPos)
      Returns true if the given non-replaceable block can be insta-broken (zero hardness) and therefore should be cleared with a break packet immediately before placement. Used to allow placing onto things like tnt, scaffolding, torches, redstone, etc. without performing an extra inventory swap.
    • canPlaceOver

      public static boolean canPlaceOver(net.minecraft.core.BlockPos pos)
      Returns true if a block can be placed at this position (either the block is replaceable, or it's an insta-breakable block that BPM will clear with a break packet before placing). Use this from modules (Surround, AutoTrap, etc.) instead of a raw canBeReplaced() check so insta-breakable blocks like tnt/scaffolding/torches are not skipped.
    • checkPlacement

      public boolean checkPlacement(net.minecraft.world.item.Item item, net.minecraft.core.BlockPos blockPos, net.minecraft.world.level.block.state.BlockState state, net.minecraft.world.level.block.state.BlockState desiredState)
    • getPlaceOnDirection

      public static net.minecraft.core.Direction getPlaceOnDirection(net.minecraft.core.BlockPos pos)
    • removePendingSound

      public void removePendingSound(net.minecraft.core.BlockPos pos)
      Remove a pending sound entry so the client-side sound is not played when the server confirms the block update (avoids double sounds).