Conversation
# Conflicts: # src/main/java/dev/twme/debugstickpro/listeners/BlockBreakEventListener.java # src/main/java/dev/twme/debugstickpro/listeners/FreezeBlockIsolationListener.java # src/main/java/dev/twme/debugstickpro/mode/freeze/FreezeBlockManager.java # src/main/java/dev/twme/debugstickpro/mode/freeze/FreezeRightClick.java # src/main/java/dev/twme/debugstickpro/utils/SendFakeBarrier.java
There was a problem hiding this comment.
Pull request overview
This PR replaces the BlocketAPI-based fake barrier approach in freeze mode with physically placing BARRIER blocks on the server. It adds a FreezePacketLayer (using PacketEvents) to handle BLOCK_CHANGE packet interception for dependent neighbor blocks (like levers/rails attached to frozen blocks), and introduces FreezeBlockIsolationListener to prevent game events (explosions, physics, pistons, etc.) from affecting frozen or protected blocks. It also improves the right-click targeting logic in freeze mode to better handle FaceAttachable blocks.
Changes:
- Replaced BlocketAPI fake-barrier mechanism with physical BARRIER block placement and a new packet interception layer (
FreezePacketLayer) for protecting dependent neighbor blocks - Added
FreezeBlockIsolationListenerto cancel a comprehensive set of block events for frozen/protected locations (physics, explosions, piston, growth, decay, etc.) - Improved
FreezeRightClickblock targeting to properly detect and unfreeze frozen support blocks when clicking onFaceAttachableblocks (levers, buttons) attached to them
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
FreezePacketLayer.java |
New file: intercepts BLOCK_CHANGE and MULTI_BLOCK_CHANGE packets to restore protected dependent block states |
FreezeBlockManager.java |
Major refactor: physically sets blocks to BARRIER on freeze, restores with BlockState, adds dependent neighbor snapshot/protection logic, removes BlocketAPI usage |
FreezeBlockData.java |
Added originalState (BlockState) field and getter for more reliable block restoration |
FreezeRightClick.java |
New resolveTargetBlock logic with FaceAttachable/Directional support; added null check for player |
FreezeBlockIsolationListener.java |
New file: comprehensive Bukkit event listener cancelling all block-changing events for frozen/protected locations |
PlayerDataManager.java |
playerRightClick signature updated to accept Action, Block, and BlockFace for contextual targeting |
RightClickListener.java |
Passes click context (action, clickedBlock, blockFace) to PlayerDataManager.playerRightClick |
LeftClickListener.java |
Removed unused imports (SendFakeBarrier, FreezeBlockManager, etc.) |
BlockBreakEventListener.java |
Clears protectedDependentBlocks entry when a non-frozen block is broken |
DebugStickPro.java |
Initializes/shuts down FreezePacketLayer; registers FreezeBlockIsolationListener; removes BlocketAPI init |
SendFakeBarrier.java |
Deleted: entire class removed, replaced by physical BARRIER + packet layer approach |
pom.xml |
Removed blocket-api dependency |
You can also share your feedback on Copilot code review. Take the survey.
| private static String getExpectedData(World world, int x, int y, int z) { | ||
| Location location = new Location(world, x, y, z); | ||
| return FreezeBlockManager.getProtectedDependentData(location); | ||
| } |
There was a problem hiding this comment.
The FreezePacketLayer listener intercepts BLOCK_CHANGE packets to protect dependent neighbor blocks (tracked in protectedDependentBlocks), but it does not intercept packets for the frozen blocks themselves. Frozen blocks are physically replaced with BARRIER on the server (line 58 in FreezeBlockManager), so if any plugin or server mechanism sends a BLOCK_CHANGE packet for a frozen location (e.g., during chunk re-sending, world restoration, or inter-plugin interaction), that packet will slip through and clients will see the wrong block state at the frozen location. Consider also intercepting BLOCK_CHANGE packets for locations that are in freezeBlockLocations by redirecting them to the BARRIER block state.
| @EventHandler(ignoreCancelled = true) | ||
| public void onBlockPhysics(BlockPhysicsEvent event) { | ||
| boolean protectedTarget = FreezeBlockManager.maintainProtectedDependent(event.getBlock()); | ||
| boolean protectedSource = FreezeBlockManager.maintainProtectedDependent(event.getSourceBlock()); |
There was a problem hiding this comment.
In onBlockPhysics, maintainProtectedDependent is called for both event.getBlock() and event.getSourceBlock() even when protectedTarget is already true. This means both blocks may have setBlockData(...) called on them during a single physics event unnecessarily. The maintainProtectedDependent(event.getSourceBlock()) call at line 28 can be skipped entirely if protectedTarget is already true since the event will be cancelled regardless. Consider short-circuit evaluation to avoid the redundant block modification.
| boolean protectedSource = FreezeBlockManager.maintainProtectedDependent(event.getSourceBlock()); | |
| boolean protectedSource = !protectedTarget && FreezeBlockManager.maintainProtectedDependent(event.getSourceBlock()); |
| private static void registerProtectedDependentSnapshot(Map<FreezeLocation, String> snapshot) { | ||
| protectedDependentBlocks.putAll(snapshot); |
There was a problem hiding this comment.
Entries added to protectedDependentBlocks via registerProtectedDependentSnapshot (after unfreezing a block) are never automatically removed once the temporary protection is no longer needed. They persist until the block is explicitly broken or replaced by a player. This causes a long-term stale protection issue: after a block is unfrozen, its former dependent neighbors (e.g., a lever, button, or rail) become permanently protected from physics events. For example, if a player later removes the support block for that lever legitimately, the onBlockPhysics event will still cancel the lever's fall because it remains in protectedDependentBlocks. Consider removing the snapshot entries from protectedDependentBlocks after the delayed restoration tasks (1-2 ticks) complete, keeping only the entries for blocks that are still in an inconsistent state after verification.
No description provided.