Skip to content

Commit

Permalink
fix: InventoryView exception & closes #928
Browse files Browse the repository at this point in the history
  • Loading branch information
StarWishsama committed Aug 1, 2024
1 parent cb6bb12 commit f51bf7e
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.logging.Level;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.bukkit.ExplosionResult;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.Inventory;

@UtilityClass
public class VersionedEvent {
private Constructor<BlockExplodeEvent> blockExplodeConstructor;
private Constructor<BlockExplodeEvent> BLOCK_EXPLODE_EVENT_CONSTRUCTOR;

private Method GET_TOP_INVENTORY;

public void init() {
if (Slimefun.getMinecraftVersion().isBefore(MinecraftVersion.MINECRAFT_1_21)) {
try {
blockExplodeConstructor = BlockExplodeEvent.class.getConstructor(Block.class, List.class, float.class);
} catch (NoSuchMethodException e) {
BLOCK_EXPLODE_EVENT_CONSTRUCTOR =
BlockExplodeEvent.class.getConstructor(Block.class, List.class, float.class);

GET_TOP_INVENTORY =
Class.forName("org.bukkit.inventory.InventoryView").getMethod("getTopInventory");
GET_TOP_INVENTORY.setAccessible(true);
} catch (NoSuchMethodException | ClassNotFoundException e) {
Slimefun.logger().log(Level.WARNING, "无法初始化事件版本兼容模块, 部分功能可能无法正常使用", e);
}
}
Expand All @@ -30,10 +40,26 @@ public BlockExplodeEvent newBlockExplodeEvent(Block block, List<Block> affectedB
if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_21)) {
return new BlockExplodeEvent(block, block.getState(), affectedBlock, yield, ExplosionResult.DESTROY);
} else {
if (blockExplodeConstructor == null) {
if (BLOCK_EXPLODE_EVENT_CONSTRUCTOR == null) {
throw new IllegalStateException("Unable to create BlockExplodeEvent: missing constructor");
}
return blockExplodeConstructor.newInstance(block, affectedBlock, yield);
return BLOCK_EXPLODE_EVENT_CONSTRUCTOR.newInstance(block, affectedBlock, yield);
}
}

/**
* See https://www.spigotmc.org/threads/inventoryview-changed-to-interface-backwards-compatibility.651754/
*/
@SneakyThrows
public Inventory getTopInventory(InventoryEvent event) {
if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_21)) {
return event.getView().getTopInventory();
} else {
if (GET_TOP_INVENTORY == null) {
throw new IllegalStateException("Unable to get top inventory: missing method");
}

return (Inventory) GET_TOP_INVENTORY.invoke(event.getView());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public ToolUseHandler getItemHandler() {
SoundEffect.EXPLOSIVE_TOOL_EXPLODE_SOUND.playAt(b);

List<Block> blocks = findBlocks(b);

if (!StorageCacheUtils.hasBlock(b.getLocation())) {
blocks.add(b);
}

breakBlocks(e, p, tool, b, blocks, drops);
}
};
Expand Down Expand Up @@ -172,79 +177,81 @@ private void breakBlock(BlockBreakEvent event, Player player, ItemStack item, Bl
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, material);
Location blockLocation = block.getLocation();

Optional<SlimefunItem> optionalBlockSfItem = Optional.ofNullable(StorageCacheUtils.getSfItem(blockLocation));
Optional<SlimefunItem> blockItem = Optional.ofNullable(StorageCacheUtils.getSfItem(blockLocation));

/*
* 修复: https://github.com/SlimefunGuguProject/Slimefun4/issues/853
*
* 该问题源于 ExoticGarden MagicalEssence/ExoticGardenFruit useVanillaBlockBreaking 为 true,
* 将调用 breakNaturally 方法而非将其作为 SlimefunItem 进行处理。
*
* 此前将 blocks 进行排序,以确保头颅为最先处理的对象,检查头颅的 Y - 1 方块是否为叶子,
* 若为叶子则尝试获取该处的 SlimefunItem,若能获取得到则此处应为异域花园植物,将叶子处直接设置为 AIR 并移除该处 Slimefun 方块数据。
*/
AtomicBoolean isUseVanillaBlockBreaking = new AtomicBoolean(true);

if (Bukkit.getPluginManager().isPluginEnabled("ExoticGarden")
&& block.getType().equals(Material.PLAYER_HEAD)) {
Location leavesLocation = blockLocation.clone();
leavesLocation.setY(leavesLocation.getY() - 1);

Block leaveBlock = leavesLocation.getBlock();
Material leaveBlockType = leaveBlock.getType();

if (Tag.LEAVES.isTagged(leaveBlockType)) {
Optional<SlimefunItem> optionalLeavesBlockSfItem =
Optional.ofNullable(StorageCacheUtils.getSfItem(leavesLocation));

optionalBlockSfItem.ifPresent(blockSfItem -> optionalLeavesBlockSfItem.ifPresent(leavesSfItem -> {
Collection<ItemStack> sfItemDrops = blockSfItem.getDrops();
Collection<ItemStack> leavesSfItemDrops = leavesSfItem.getDrops();

if (Arrays.equals(sfItemDrops.toArray(), leavesSfItemDrops.toArray())) {
leaveBlock.setType(Material.AIR);
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(leavesLocation);

isUseVanillaBlockBreaking.set(false);
blockItem.ifPresentOrElse(
sfItem -> {
/*
* 修复: https://github.com/SlimefunGuguProject/Slimefun4/issues/853
*
* 该问题源于 ExoticGarden MagicalEssence/ExoticGardenFruit useVanillaBlockBreaking 为 true,
* 将调用 breakNaturally 方法而非将其作为 SlimefunItem 进行处理。
*
* 此前将 blocks 进行排序,以确保头颅为最先处理的对象,检查头颅的 Y - 1 方块是否为叶子,
* 若为叶子则尝试获取该处的 SlimefunItem,若能获取得到则此处应为异域花园植物,将叶子处直接设置为 AIR 并移除该处 Slimefun 方块数据。
*/
if (Bukkit.getPluginManager().isPluginEnabled("ExoticGarden")
&& block.getType().equals(Material.PLAYER_HEAD)) {
Location leavesLocation = blockLocation.clone();
leavesLocation.setY(leavesLocation.getY() - 1);

Block leaveBlock = leavesLocation.getBlock();
Material leaveBlockType = leaveBlock.getType();

if (Tag.LEAVES.isTagged(leaveBlockType)) {
Optional<SlimefunItem> optionalLeavesBlockSfItem =
Optional.ofNullable(StorageCacheUtils.getSfItem(leavesLocation));

optionalLeavesBlockSfItem.ifPresent(leavesSfItem -> {
Collection<ItemStack> sfItemDrops = sfItem.getDrops();
Collection<ItemStack> leavesSfItemDrops = leavesSfItem.getDrops();

if (Arrays.equals(sfItemDrops.toArray(), leavesSfItemDrops.toArray())) {
leaveBlock.setType(Material.AIR);
Slimefun.getDatabaseManager()
.getBlockDataController()
.removeBlock(leavesLocation);

isUseVanillaBlockBreaking.set(false);
}
});
}
}
}));
}
}

optionalBlockSfItem.ifPresent(sfItem -> {
if (isUseVanillaBlockBreaking.get()) {
isUseVanillaBlockBreaking.set(sfItem.useVanillaBlockBreaking());
}

if (isUseVanillaBlockBreaking.get()) {
block.breakNaturally(item);
} else {
/*
* Fixes #2989
* We create a dummy here to pass onto the BlockBreakHandler.
* This will set the correct block context.
*/
BlockBreakEvent dummyEvent = new BlockBreakEvent(block, event.getPlayer());

/*
* Fixes #3036 and handling in general.
* Call the BlockBreakHandler if the block has one to allow for proper handling.
*/
sfItem.callItemHandler(
BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));

// Make sure the event wasn't cancelled by the BlockBreakHandler.
if (!dummyEvent.isCancelled()) {
drops.addAll(sfItem.getDrops(player));
block.setType(Material.AIR);
Slimefun.getDatabaseManager().getBlockDataController().removeBlock(blockLocation);
}
}
});
if (isUseVanillaBlockBreaking.get()) {
isUseVanillaBlockBreaking.set(sfItem.useVanillaBlockBreaking());
}

if (optionalBlockSfItem.isEmpty()) {
block.breakNaturally(item);
}
if (isUseVanillaBlockBreaking.get()) {
block.breakNaturally(item);
} else {
/*
* Fixes #2989
* We create a dummy here to pass onto the BlockBreakHandler.
* This will set the correct block context.
*/
BlockBreakEvent dummyEvent = new BlockBreakEvent(block, event.getPlayer());

/*
* Fixes #3036 and handling in general.
* Call the BlockBreakHandler if the block has one to allow for proper handling.
*/
sfItem.callItemHandler(
BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));

// Make sure the event wasn't cancelled by the BlockBreakHandler.
if (!dummyEvent.isCancelled()) {
drops.addAll(sfItem.getDrops(player));
block.setType(Material.AIR);
Slimefun.getDatabaseManager()
.getBlockDataController()
.removeBlock(blockLocation);
}
}
},
() -> block.breakNaturally(item));

damageItem(player, item);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting;

import city.norain.slimefun4.compatibillty.VersionedEvent;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -32,7 +33,7 @@ public BrewingStandListener(@Nonnull Slimefun plugin) {
@EventHandler(ignoreCancelled = true)
public void onPreBrew(InventoryClickEvent e) {
Inventory clickedInventory = e.getClickedInventory();
Inventory topInventory = e.getView().getTopInventory();
Inventory topInventory = VersionedEvent.getTopInventory(e);

if (clickedInventory != null
&& topInventory.getType() == InventoryType.BREWING
Expand Down

0 comments on commit f51bf7e

Please sign in to comment.