Skip to content

Commit

Permalink
Move no-snapshot method out of API (#236)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jikoo authored Aug 7, 2024
1 parent 4198b7f commit 0f0bde3
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,17 @@

package com.lishid.openinv.internal;

import org.bukkit.block.Barrel;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.EnderChest;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Chest;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.util.BoundingBox;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Method;

import static com.lishid.openinv.util.InventoryAccess.getBlockState;

public interface IAnySilentContainer {

/**
Expand All @@ -61,62 +53,7 @@ public interface IAnySilentContainer {
* @param block the {@link Block} of the container
* @return true if the container is blocked
*/
default boolean isAnyContainerNeeded(@NotNull Block block) {
BlockState blockState = getBlockState(block);

// Barrels do not require AnyContainer.
if (blockState instanceof Barrel) {
return false;
}

// Enderchests require a non-occluding block on top to open.
if (blockState instanceof EnderChest) {
return block.getRelative(0, 1, 0).getType().isOccluding();
}

// Shulker boxes require half a block clear in the direction they open.
if (blockState instanceof ShulkerBox) {
return isShulkerBlocked(block);
}

if (!(blockState instanceof org.bukkit.block.Chest)) {
return false;
}

if (isChestBlocked(block)) {
return true;
}

BlockData blockData = block.getBlockData();
if (!(blockData instanceof Chest chest) || chest.getType() == Chest.Type.SINGLE) {
return false;
}

BlockFace relativeFace = switch (chest.getFacing()) {
case NORTH -> chest.getType() == Chest.Type.RIGHT ? BlockFace.WEST : BlockFace.EAST;
case EAST -> chest.getType() == Chest.Type.RIGHT ? BlockFace.NORTH : BlockFace.SOUTH;
case SOUTH -> chest.getType() == Chest.Type.RIGHT ? BlockFace.EAST : BlockFace.WEST;
case WEST -> chest.getType() == Chest.Type.RIGHT ? BlockFace.SOUTH : BlockFace.NORTH;
default -> BlockFace.SELF;
};
Block relative = block.getRelative(relativeFace);

if (relative.getType() != block.getType()) {
return false;
}

BlockData relativeData = relative.getBlockData();
if (!(relativeData instanceof Chest relativeChest)) {
return false;
}

if (relativeChest.getFacing() != chest.getFacing()
|| relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) {
return false;
}

return isChestBlocked(relative);
}
boolean isAnyContainerNeeded(@NotNull Block block);

/**
* Check if a shulker box block cannot be opened under ordinary circumstances.
Expand All @@ -127,9 +64,13 @@ default boolean isAnyContainerNeeded(@NotNull Block block) {
default boolean isShulkerBlocked(@NotNull Block shulkerBox) {
Directional directional = (Directional) shulkerBox.getBlockData();
BlockFace facing = directional.getFacing();
// Construct a new 1-block bounding box at the origin.
BoundingBox box = new BoundingBox(0, 0, 0, 1, 1, 1);
// Expand the box in the direction the shulker will open.
box.expand(facing, 0.5);
// Move the box away from the origin by a block so only the expansion intersects with a box around the origin.
box.shift(facing.getOppositeFace().getDirection());
// Check if the relative block's collision shape (which will be at the origin) intersects with the expanded box.
return shulkerBox.getRelative(facing).getCollisionShape().overlaps(box);
}

Expand All @@ -151,9 +92,7 @@ default boolean isChestBlocked(@NotNull Block chest) {
* @param block the potential container
* @return true if the type is a supported container
*/
default boolean isAnySilentContainer(@NotNull Block block) {
return isAnySilentContainer(getBlockState(block));
}
boolean isAnySilentContainer(@NotNull Block block);

/**
* Check if the given {@link BlockState} is a container which can be unblocked or silenced.
Expand Down
26 changes: 0 additions & 26 deletions api/src/main/java/com/lishid/openinv/util/InventoryAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,16 @@
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;

public final class InventoryAccess {

private static @Nullable BiFunction<Inventory, Class<? extends ISpecialInventory>, ISpecialInventory> provider;
private static Method blockGetStateNoSnapshotMethod;

static {
try {
blockGetStateNoSnapshotMethod = Block.class.getMethod("getState", boolean.class);
} catch (NoSuchMethodException e) {
blockGetStateNoSnapshotMethod = null;
}
}

public static BlockState getBlockState(Block block) {
// Try to get block state without snapshot (only available in paper currently)
if (blockGetStateNoSnapshotMethod != null) {
try {
return (BlockState) blockGetStateNoSnapshotMethod.invoke(block, false);
} catch (InvocationTargetException | IllegalAccessException e) {
return block.getState();
}
} else {
return block.getState();
}
}

public static boolean isUsable() {
return provider != null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.lishid.openinv.internal;

import org.bukkit.block.Barrel;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.EnderChest;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Chest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Method;

public abstract class AnySilentContainerBase implements IAnySilentContainer {

private static final @Nullable Method BLOCK_GET_STATE_BOOLEAN;

static {
@Nullable Method getState;
try {
//noinspection JavaReflectionMemberAccess
getState = Block.class.getMethod("getState", boolean.class);
} catch (NoSuchMethodException e) {
getState = null;
}
BLOCK_GET_STATE_BOOLEAN = getState;
}

private static BlockState getBlockState(Block block) {
// Paper: Get state without snapshotting.
if (BLOCK_GET_STATE_BOOLEAN != null) {
try {
return (BlockState) BLOCK_GET_STATE_BOOLEAN.invoke(block, false);
} catch (ReflectiveOperationException ignored) {
// If we encounter an issue, fall through to regular snapshotting method.
}
}
return block.getState();
}

@Override
public boolean isAnyContainerNeeded(@NotNull Block block) {
BlockState blockState = getBlockState(block);

// Barrels do not require AnyContainer.
if (blockState instanceof Barrel) {
return false;
}

// Enderchests require a non-occluding block on top to open.
if (blockState instanceof EnderChest) {
return block.getRelative(0, 1, 0).getType().isOccluding();
}

// Shulker boxes require half a block clear in the direction they open.
if (blockState instanceof ShulkerBox) {
return isShulkerBlocked(block);
}

if (!(blockState instanceof org.bukkit.block.Chest)) {
return false;
}

if (isChestBlocked(block)) {
return true;
}

BlockData blockData = block.getBlockData();
if (!(blockData instanceof Chest chest) || chest.getType() == Chest.Type.SINGLE) {
return false;
}

BlockFace relativeFace = switch (chest.getFacing()) {
case NORTH -> chest.getType() == Chest.Type.RIGHT ? BlockFace.WEST : BlockFace.EAST;
case EAST -> chest.getType() == Chest.Type.RIGHT ? BlockFace.NORTH : BlockFace.SOUTH;
case SOUTH -> chest.getType() == Chest.Type.RIGHT ? BlockFace.EAST : BlockFace.WEST;
case WEST -> chest.getType() == Chest.Type.RIGHT ? BlockFace.SOUTH : BlockFace.NORTH;
default -> BlockFace.SELF;
};
Block relative = block.getRelative(relativeFace);

if (relative.getType() != block.getType()) {
return false;
}

BlockData relativeData = relative.getBlockData();
if (!(relativeData instanceof Chest relativeChest)) {
return false;
}

if (relativeChest.getFacing() != chest.getFacing()
|| relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) {
return false;
}

return isChestBlocked(relative);
}

@Override
public boolean isAnySilentContainer(@NotNull Block block) {
return isAnySilentContainer(getBlockState(block));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.lishid.openinv.internal.v1_20_R3;

import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -48,7 +48,7 @@
import java.lang.reflect.Field;
import java.util.logging.Logger;

public class AnySilentContainer implements IAnySilentContainer {
public class AnySilentContainer extends AnySilentContainerBase {

private final @NotNull Logger logger;
private final @NotNull LanguageManager lang;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.lishid.openinv.internal.v1_20_R4;

import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -48,7 +48,7 @@
import java.lang.reflect.Field;
import java.util.logging.Logger;

public class AnySilentContainer implements IAnySilentContainer {
public class AnySilentContainer extends AnySilentContainerBase {

private final @NotNull Logger logger;
private final @NotNull LanguageManager lang;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.lishid.openinv.internal.v1_21_R1.container;

import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.internal.v1_21_R1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.v1_21_R1.player.PlayerManager;
import com.lishid.openinv.util.ReflectionHelper;
Expand Down Expand Up @@ -50,7 +50,7 @@
import java.lang.reflect.Field;
import java.util.logging.Logger;

public class AnySilentContainer implements IAnySilentContainer {
public class AnySilentContainer extends AnySilentContainerBase {

private final @NotNull Logger logger;
private final @NotNull LanguageManager lang;
Expand Down

0 comments on commit 0f0bde3

Please sign in to comment.