Conversation
There was a problem hiding this comment.
Pull request overview
This PR bundles several urgent fixes around item comparison, explosion/Wither interactions, database safety, and spawn-protection interactions, addressing issues #1126, #1177, #1178, #1186, #1187 and a spawn protection dupe. The main themes are stricter Slimefun ID–based item matching, more robust explosion/Wither-proof handling (including new WitherProof API hooks), and making storage updates safer when data is pending removal.
Changes:
- Refines
SlimefunUtils.isItemSimilarto compare Slimefun IDs even when the second item is not anItemStackWrapper, fixing incorrect stacking behavior (#1178) and removes cargo-specific debug logging. - Extends
WitherProofwithonAttackEventandisExplosionProof, wires these intoExplosionsListenerandBlockPhysicsListener, and adds a configurable Wither-proof toggle toHardenedGlass, with its registration updated accordingly (#1126, #1187). - Adjusts explosion handling so blocks without
BlockBreakHandlerare now actually destroyed by explosions, and machines drop themselves first on explosion, plus changesSlimefunBlockData.setDatato silently ignore writes to pending-removed blocks to avoid DB foreign-key errors (#1177, #1186). - Adds
e.canBuild()checks to block-place listeners to respect external protections (e.g., spawn protection) and prevent ghost/dupe scenarios.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java |
Tightens isItemSimilar to always consider Slimefun IDs (and DistinctiveItem) when both sides have Slimefun metadata, even if the second item is not an ItemStackWrapper, addressing stacking inconsistencies (#1178). |
src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java |
Registers HardenedGlass with the new constructor, setting witherProof to false so it remains explosion-proof but still breakable by direct Wither attacks, matching its intended behavior. |
src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java |
Reworks explosion handling: introduces WitherProof.isExplosionProof checks, fixes the logic so blocks without BlockBreakHandler are destroyed instead of ignored, ensures machine drops are included on explosion, and now updates nearby networks for each destroyed energy/cargo node. |
src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java |
Simplifies EntityChangeBlockEvent handling: treats WitherSkull as non-emitting, routes Wither interactions on Slimefun blocks through WitherProof.onAttackEvent when applicable, and then removes the block data and drops items; also leaves ENDERMAN behavior unchanged. |
src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java |
Adds e.canBuild() guards to both block-place handlers so Slimefun placement logic respects external protections and avoids ghost blocks or dupes in protected regions (e.g., spawn protection). |
src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HardenedGlass.java |
Introduces a witherProof flag and overrides onAttackEvent so HardenedGlass can opt out of Wither-proof behavior while still using the shared WitherProofBlock implementation. |
src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/WitherProof.java |
Adds onAttackEvent(EntityChangeBlockEvent) and isExplosionProof() default methods, formalizing the contract for Wither attack and explosion behavior and documenting interaction with ExplosionsListener. |
src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunBlockData.java |
Changes setData so that when a block is pending removal, writes are ignored instead of throwing, preventing the SQL foreign-key exceptions seen when addons write to invalidated data (#1177/#1186). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| case WITHER -> { | ||
| // fix issue 1126 | ||
| // the wither break is handled in the WitherListener, then the data is removed there, so it will | ||
| // conflict with this listener | ||
| var block = e.getBlock(); | ||
| var item = SlimefunItem.getById(blockData.getSfId()); | ||
|
|
||
| var controller = Slimefun.getDatabaseManager().getBlockDataController(); | ||
| if (item != null | ||
| && !(item instanceof WitherProof) | ||
| && !item.callItemHandler(BlockBreakHandler.class, handler -> { | ||
| if (blockData.isDataLoaded()) { | ||
| callHandler(handler, block); | ||
| } else { | ||
| blockData.setPendingRemove(true); | ||
| controller.loadDataAsync(blockData, new IAsyncReadCallback<>() { | ||
| @Override | ||
| public boolean runOnMainThread() { | ||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public void onResult(ASlimefunDataContainer result) { | ||
| callHandler(handler, block); | ||
| blockData.setPendingRemove(false); | ||
| } | ||
| }); | ||
| } | ||
| })) { | ||
| if (item != null) { | ||
| if (item instanceof WitherProof witherProof) { | ||
| witherProof.onAttackEvent(e); | ||
| if (!e.isCancelled()) { | ||
| return; | ||
| } | ||
| } | ||
| controller.removeBlock(block.getLocation()); | ||
| block.setType(Material.AIR); | ||
| for (var drop : item.getDrops()) { | ||
| if (drop != null && !drop.getType().isAir()) { | ||
| block.getWorld().dropItemNaturally(block.getLocation(), drop); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Here WitherProof blocks are still being removed even when their onAttackEvent implementation cancels the EntityChangeBlockEvent. For WitherProof items, onAttackEvent sets the event as cancelled, so e.isCancelled() becomes true and the code falls through to controller.removeBlock(...) and block.setType(Material.AIR), effectively making Wither-proof blocks breakable by Withers and contradicting the WitherProof contract and the existing WitherListener behavior. You likely want to skip the removal/drop logic when onAttackEvent cancels the event (e.g. by returning early when e.isCancelled() is true), instead of removing the block in that case.
src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/WitherProof.java
Show resolved
Hide resolved
| SlimefunItem item, ASlimefunDataContainer blockData, Block block, AtomicBoolean updateRef) { | ||
| return !item.callItemHandler(BlockBreakHandler.class, handler -> { | ||
| private void callBreakHandler( | ||
| SlimefunItem item, ASlimefunDataContainer blockData, Block block, Runnable destroyCcb) { |
There was a problem hiding this comment.
逗我吗
很明显这是很多种情况都要运行的, 集中写比较好
听起来很合理
| * | ||
| * @return whether this is explosion proof | ||
| */ | ||
| default boolean isExplosionProof() { |
There was a problem hiding this comment.
你要有防爆就拆到另一个 attr 里,我记得 sf 这个 WitherProof 原来的设计就是免疫凋零爆炸破坏
| } | ||
|
|
||
| private void updateNearbyNetwork(SlimefunItem item, Location loc) { | ||
| // fix: |
| new ItemStack(Material.GLASS) | ||
| }, | ||
| new SlimefunItemStack(SlimefunItems.HARDENED_GLASS, 16)) | ||
| new SlimefunItemStack(SlimefunItems.HARDENED_GLASS, 16), |
|
|
||
| @ParametersAreNonnullByDefault | ||
| private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, AtomicBoolean ref) { | ||
| private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, Runnable destroyCcb) { |
There was a problem hiding this comment.
| private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, Runnable destroyCcb) { | |
| private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, Runnable explosionCb) { |
| if (!item.callItemHandler(BlockBreakHandler.class, handler -> { | ||
| if (blockData.isDataLoaded()) { | ||
| handleExplosion(handler, block, item, updateRef); | ||
| handleExplosion(handler, block, item, destroyCcb); |
There was a problem hiding this comment.
| handleExplosion(handler, block, item, destroyCcb); | |
| handleExplosion(handler, block, item, explosionCb); |
| @Override | ||
| public void onResult(ASlimefunDataContainer result) { | ||
| handleExplosion(handler, block, item, updateRef); | ||
| handleExplosion(handler, block, item, destroyCcb); |
There was a problem hiding this comment.
| handleExplosion(handler, block, item, destroyCcb); | |
| handleExplosion(handler, block, item, explosionCb); |
| } | ||
| }); | ||
| })) { | ||
| destroyCcb.run(); |
There was a problem hiding this comment.
| destroyCcb.run(); | |
| explosionCb.run(); |
| block.setType(Material.AIR); | ||
|
|
||
| List<ItemStack> drops = new ArrayList<>(); | ||
| // fix : 1187, machine should drop themselves first, in explosion |
There was a problem hiding this comment.
这里之前反复修过几次,看看有没有其他地方监听了导致刷物的情况
There was a problem hiding this comment.
应该没有 正常onBlockBreak也是需要从getDrops开始的, 而且目前就是不掉机器本体
| } | ||
|
|
||
| updateNearbyNetwork(item, block.getLocation(), ref); | ||
| destroyCcb.run(); |
There was a problem hiding this comment.
| destroyCcb.run(); | |
| explosionCb.run(); |
简介
相关的 Issues (没有可不填)
修复
#1126
#1177
#1178
#1186
#1187
修复
出生点保护导致的刷物