Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public void setData(String key, String val) {
checkData();

if (isPendingRemove()) {
throw new IllegalStateException("不能修改即将删除的方块数据");
// someone is modifying a removed blockData or a virtual blockData, DO NOT SAVE
return;
}

setCacheInternal(key, val, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import javax.annotation.Nonnull;
import org.bukkit.block.Block;
import org.bukkit.entity.Wither;
import org.bukkit.event.entity.EntityChangeBlockEvent;

/**
* This Interface, when attached to a class that inherits from {@link SlimefunItem}, marks
Expand All @@ -21,11 +22,26 @@ public interface WitherProof extends ItemAttribute {
/**
* This method is called when a {@link Wither} tried to attack the given {@link Block}.
* You can use this method to play particles or even damage the {@link Wither}.
* This method is only called from {@link WitherProof#onAttackEvent(EntityChangeBlockEvent)}
*
* @param block
* The {@link Block} which was attacked.
* @param wither
* The {@link Wither} who attacked.
*/
void onAttack(@Nonnull Block block, @Nonnull Wither wither);

/**
* This method is called when a {@link Wither} tried to attack the block.
* You can use this method to handle the {@link EntityChangeBlockEvent}.
*
* @param event
* The {@link EntityChangeBlockEvent} which was involved.
*/
default void onAttackEvent(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Wither wither) {
event.setCancelled(true);
onAttack(event.getBlock(), wither);
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

无需更改

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkull;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.inventory.ItemStack;

/**
Expand All @@ -20,7 +21,6 @@
*
*/
public class HardenedGlass extends WitherProofBlock {

@ParametersAreNonnullByDefault
public HardenedGlass(
ItemGroup itemGroup,
Expand All @@ -30,4 +30,9 @@ public HardenedGlass(
ItemStack recipeOutput) {
super(itemGroup, item, recipeType, recipe, recipeOutput);
}

@Override
public void onAttackEvent(EntityChangeBlockEvent event) {
// the Hardened Glass does not proof wither , so event shouldn't be cancelled
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public BlockListener(@Nonnull Slimefun plugin) {

@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockPlaceExisting(BlockPlaceEvent e) {
if (!e.canBuild()) {
return;
}
Block block = e.getBlock();
var loc = block.getLocation();

Expand Down Expand Up @@ -111,6 +114,9 @@ public void onExplosiveToolBlockBreak(ExplosiveToolBreakBlocksEvent e) {

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
if (!e.canBuild()) {
return;
}
ItemStack item = e.getItemInHand();
SlimefunItem sfItem = SlimefunItem.getByItem(item);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;

import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.ASlimefunDataContainer;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import io.papermc.lib.PaperLib;
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
import java.util.ArrayList;
import java.util.Objects;
import javax.annotation.Nonnull;
import org.bukkit.Location;
Expand Down Expand Up @@ -67,58 +63,35 @@ public void onBlockFall(EntityChangeBlockEvent e) {
}
}

case WITHER, WITHER_SKULL -> {
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);
}
}
}
Comment on lines +66 to 87
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
}

// fix: issue 1126 there is not such EntityChangeBlockEvent about WitherSkull
// Don't move my machine :|
case ENDERMAN -> e.setCancelled(true);
}
}

private void callHandler(BlockBreakHandler handler, Block b) {
if (handler.isExplosionAllowed(b)) {
b.setType(Material.AIR);

var drops = new ArrayList<ItemStack>();
handler.onExplode(b, drops);
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(b.getLocation());

for (var drop : drops) {
if (drop != null && !drop.getType().isAir()) {
b.getWorld().dropItemNaturally(b.getLocation(), drop);
}
}
}
}

@EventHandler(ignoreCancelled = true)
public void onPistonExtend(BlockPistonExtendEvent e) {
if (StorageCacheUtils.hasSlimefunBlock(e.getBlock().getLocation())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.ExplosionResult;
Expand Down Expand Up @@ -69,9 +68,6 @@ public void onBlockExplode(BlockExplodeEvent e) {
}

private void removeResistantBlocks(@Nonnull Iterator<Block> blocks) {
// For explosion handling, only update network once for a random affected block to improve performance.
AtomicBoolean networkUpdated = new AtomicBoolean(false);

while (blocks.hasNext()) {
Block block = blocks.next();
var loc = block.getLocation();
Expand All @@ -80,21 +76,28 @@ private void removeResistantBlocks(@Nonnull Iterator<Block> blocks) {

if (item != null) {
blocks.remove();

if (!(item instanceof WitherProof) && !callBreakHandler(item, blockData, block, networkUpdated)) {
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(loc);
block.setType(Material.AIR);
updateNearbyNetwork(item, loc, networkUpdated);
// add WitherProof api
if (item instanceof WitherProof) {
continue;
} else {
Runnable destroyTask = () -> {
block.setType(Material.AIR);
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(loc);
updateNearbyNetwork(item, loc);
};
// fix # 1187, the callBreakHandler returns true if there is no handler exist actually, so it
// shouldn't be added a !
callBreakHandler(item, blockData, block, destroyTask);
}
}
}
}

private boolean callBreakHandler(
SlimefunItem item, ASlimefunDataContainer blockData, Block block, AtomicBoolean updateRef) {
return !item.callItemHandler(BlockBreakHandler.class, handler -> {
private void callBreakHandler(
SlimefunItem item, ASlimefunDataContainer blockData, Block block, Runnable destroyBlockCb) {
if (!item.callItemHandler(BlockBreakHandler.class, handler -> {
if (blockData.isDataLoaded()) {
handleExplosion(handler, block, item, updateRef);
handleExplosion(handler, block, item, destroyBlockCb);
} else {
Slimefun.getDatabaseManager()
.getBlockDataController()
Expand All @@ -106,44 +109,37 @@ public boolean runOnMainThread() {

@Override
public void onResult(ASlimefunDataContainer result) {
handleExplosion(handler, block, item, updateRef);
handleExplosion(handler, block, item, destroyBlockCb);
}
});
}
});
})) {
destroyBlockCb.run();
}
}

@ParametersAreNonnullByDefault
private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, AtomicBoolean ref) {
private void handleExplosion(BlockBreakHandler handler, Block block, SlimefunItem item, Runnable destroyBlockCb) {
if (handler.isExplosionAllowed(block)) {
block.setType(Material.AIR);

List<ItemStack> drops = new ArrayList<>();
// fix : 1187, machine should drop themselves first, in explosion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里之前反复修过几次,看看有没有其他地方监听了导致刷物的情况

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该没有 正常onBlockBreak也是需要从getDrops开始的, 而且目前就是不掉机器本体

List<ItemStack> drops = new ArrayList<>(item.getDrops());
handler.onExplode(block, drops);
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(block.getLocation());

for (ItemStack drop : drops) {
if (drop != null && !drop.getType().isAir()) {
block.getWorld().dropItemNaturally(block.getLocation(), drop);
}
}

updateNearbyNetwork(item, block.getLocation(), ref);
destroyBlockCb.run();
}
}

@ParametersAreNonnullByDefault
private void updateNearbyNetwork(SlimefunItem item, Location loc, AtomicBoolean updated) {
if (updated.get()) {
return;
}

private void updateNearbyNetwork(SlimefunItem item, Location loc) {
if (!(item instanceof EnergyNetComponent) && !(item instanceof CargoNode)) {
return;
}

Slimefun.getNetworkManager().updateAllNetworks(loc);

updated.getAndSet(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ public static boolean isItemSimilar(
}
return false;
} else if (item.hasItemMeta()) {
Debug.log(TestCase.CARGO_INPUT_TESTING, "SlimefunUtils#isItemSimilar - item.hasItemMeta()");
ItemMeta itemMeta = item.getItemMeta();

if (sfitem instanceof SlimefunItemStack sfItemStack) {
Expand Down Expand Up @@ -350,61 +349,40 @@ public static boolean isItemSimilar(

ItemMetaSnapshot meta = ((SlimefunItemStack) sfitem).getItemMetaSnapshot();
return equalsItemMeta(itemMeta, meta, checkLore);
} else if (sfitem instanceof ItemStackWrapper && sfitem.hasItemMeta()) {
Debug.log(TestCase.CARGO_INPUT_TESTING, " is wrapper");
/*
* Cargo optimization (PR #3258)
*
* Slimefun items may be ItemStackWrapper's in the context of cargo
* so let's try to do an ID comparison before meta comparison
*/
Debug.log(TestCase.CARGO_INPUT_TESTING, " sfitem is ItemStackWrapper - possible SF Item: {}", sfitem);

ItemMeta possibleSfItemMeta = sfitem.getItemMeta();
String id = Slimefun.getItemDataService().getItemData(itemMeta).orElse(null);
String possibleItemId = Slimefun.getItemDataService()
.getItemData(possibleSfItemMeta)
.orElse(null);
// Prioritize SlimefunItem id comparison over ItemMeta comparison
if (id != null && possibleItemId != null) {
/*
* PR #3417
*
* Some items can't rely on just IDs matching and will implement Distinctive Item
* in which case we want to use the method provided to compare
*/
// to fix issue #976
var match = id.equals(possibleItemId);
if (match) {
Optional<DistinctiveItem> optionalDistinctive = getDistinctiveItem(id);
if (optionalDistinctive.isPresent()) {
return optionalDistinctive.get().canStack(possibleSfItemMeta, itemMeta);
} else {
// issue # 1178 should compare sfid even if the second one isn't a ItemStackWrapper
if (sfitem.hasItemMeta()) {
ItemMeta possibleSfItemMeta = sfitem.getItemMeta();
String id =
Slimefun.getItemDataService().getItemData(itemMeta).orElse(null);
String possibleItemId = Slimefun.getItemDataService()
.getItemData(possibleSfItemMeta)
.orElse(null);
// Prioritize SlimefunItem id comparison over ItemMeta comparison
if (id != null && possibleItemId != null) {
/*
* PR #3417
*
* Some items can't rely on just IDs matching and will implement Distinctive Item
* in which case we want to use the method provided to compare
*/
// to fix issue #976
var match = id.equals(possibleItemId);
if (match) {
Optional<DistinctiveItem> optionalDistinctive = getDistinctiveItem(id);
if (optionalDistinctive.isPresent()) {
return optionalDistinctive.get().canStack(possibleSfItemMeta, itemMeta);
}
}
return match;
} else {
return equalsItemMeta(itemMeta, possibleSfItemMeta, checkLore, checkCustomModelData);
}
Debug.log(TestCase.CARGO_INPUT_TESTING, " Use Item ID match: {}", match);
return match;
} else {
Debug.log(
TestCase.CARGO_INPUT_TESTING,
" one of item have no Slimefun ID, checking meta {} == {} (lore: {})",
itemMeta,
possibleSfItemMeta,
checkLore);

return equalsItemMeta(itemMeta, possibleSfItemMeta, checkLore, checkCustomModelData);
return false;
}
} else if (sfitem.hasItemMeta()) {
ItemMeta sfItemMeta = sfitem.getItemMeta();
Debug.log(
TestCase.CARGO_INPUT_TESTING,
" Comparing meta (vanilla items?) - {} == {} (lore: {})",
itemMeta,
sfItemMeta,
checkLore);
return equalsItemMeta(itemMeta, sfItemMeta, checkLore, checkCustomModelData);
} else {
return false;
}

} else {
return !sfitem.hasItemMeta();
}
Expand Down