mirror of
https://github.com/songoda/SongodaCore.git
synced 2024-10-22 12:20:26 +02:00
add utils
This commit is contained in:
parent
0f2cd764c3
commit
44138bb257
21
pom.xml
21
pom.xml
@ -21,23 +21,18 @@
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>private</id>
|
||||
<url>https://repo.songoda.com/artifactory/private/</url>
|
||||
<url>http://68.183.129.248/artifactory/private/</url>
|
||||
</repository>
|
||||
<!-- sk89q-repo and spigot-repo are required for worldguard -->
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sk89q-repo</id>
|
||||
<url>https://maven.sk89q.com/repo/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.14.4</version>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.gmail.filoghost.holographicdisplays</groupId>
|
||||
@ -62,8 +57,14 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.milkbowl</groupId>
|
||||
<artifactId>vault</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.7.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.json-simple</groupId>
|
||||
<artifactId>json-simple</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
851
src/main/java/com/songoda/core/utils/BlockUtils.java
Normal file
851
src/main/java/com/songoda/core/utils/BlockUtils.java
Normal file
@ -0,0 +1,851 @@
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
|
||||
public class BlockUtils {
|
||||
|
||||
protected static final Set<Material> DOORS;
|
||||
protected static final Set<Material> PRESSURE_PLATES;
|
||||
protected static final Set<Material> FENCE_GATES;
|
||||
protected static final Set<Material> TRAP_DOORS;
|
||||
protected static final boolean useLegacy = Material.getMaterial("OAK_LOG") == null;
|
||||
protected static Method legacySetBlockData = null;
|
||||
protected static Method legacyUpdateBlockData = null;
|
||||
|
||||
static {
|
||||
DOORS = EnumSet.noneOf(Material.class);
|
||||
PRESSURE_PLATES = EnumSet.noneOf(Material.class);
|
||||
FENCE_GATES = EnumSet.noneOf(Material.class);
|
||||
TRAP_DOORS = EnumSet.noneOf(Material.class);
|
||||
|
||||
for (Material material : Material.values()) {
|
||||
String name = material.name();
|
||||
if (name.contains("DOOR") && !name.contains("ITEM")) {
|
||||
if (name.contains("TRAP")) {
|
||||
TRAP_DOORS.add(material);
|
||||
} else {
|
||||
DOORS.add(material);
|
||||
}
|
||||
} else if (name.contains("GATE") && !name.contains("END")) {
|
||||
FENCE_GATES.add(material);
|
||||
} else if (name.contains("_PLATE")) {
|
||||
PRESSURE_PLATES.add(material);
|
||||
}
|
||||
}
|
||||
|
||||
if (useLegacy) {
|
||||
try {
|
||||
//legacyUpdateBlockData = Block.class.getDeclaredMethod("update");
|
||||
legacySetBlockData = Block.class.getDeclaredMethod("setData", byte.class);
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with this block to either update redstone or open doors
|
||||
*
|
||||
* @param b block to update
|
||||
* @return if this block's state was updated
|
||||
*/
|
||||
public static boolean tryInteract(Block b) {
|
||||
final Material bType = b.getType();
|
||||
if (isOpenable(bType)) {
|
||||
toggleDoorStates(true, b);
|
||||
return true;
|
||||
} else if(bType == Material.LEVER) {
|
||||
toggleLever(b);
|
||||
return true;
|
||||
} else if(bType.name().endsWith("_BUTTON")) {
|
||||
pressButton(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a pressure plate's redstone state
|
||||
* @param plate plate to update
|
||||
* @param power power to set to 0-15 (wood plates are active if greater than 0)
|
||||
*/
|
||||
public static void updatePressurePlate(Block plate, int power) {
|
||||
if (useLegacy && legacySetBlockData != null) {
|
||||
_updatePressurePlateLegacy(plate, power);
|
||||
} else {
|
||||
BlockUtilsModern._updatePressurePlateModern(plate, power);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _updatePressurePlateLegacy(Block plate, int power) {
|
||||
final Material m = plate.getType();
|
||||
try {
|
||||
if (m.name().equals("GOLD_PLATE") || m.name().equals("IRON_PLATE")) {
|
||||
legacySetBlockData.invoke(plate, (byte) (power & 0x15));
|
||||
} else if (m.name().endsWith("_PLATE")) {
|
||||
legacySetBlockData.invoke(plate, (byte) (power == 0 ? 0 : 1));
|
||||
}
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void pressButton(Block button) {
|
||||
if (useLegacy && legacySetBlockData != null) {
|
||||
_pressButtonLegacy(button);
|
||||
} else {
|
||||
BlockUtilsModern._pressButtonModern(button);
|
||||
}
|
||||
}
|
||||
|
||||
public static void releaseButton(Block button) {
|
||||
if (useLegacy && legacySetBlockData != null) {
|
||||
_releaseButtonLegacy(button);
|
||||
} else {
|
||||
BlockUtilsModern._releaseButtonModern(button);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _pressButtonLegacy(Block button) {
|
||||
final Material m = button.getType();
|
||||
if(!m.name().endsWith("_BUTTON")) return;
|
||||
try {
|
||||
legacySetBlockData.invoke(button, (byte) (button.getData() | (31 & 0x8)));
|
||||
button.getState().update();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _releaseButtonLegacy(Block button) {
|
||||
final Material m = button.getType();
|
||||
if(!m.name().endsWith("_BUTTON")) return;
|
||||
try {
|
||||
legacySetBlockData.invoke(button, (byte) (button.getData() & ~0x8));
|
||||
button.getState().update();
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void toggleLever(Block lever) {
|
||||
if (useLegacy && legacySetBlockData != null) {
|
||||
_toggleLeverLegacy(lever);
|
||||
} else {
|
||||
BlockUtilsModern._toggleLeverModern(lever);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _toggleLeverLegacy(Block lever) {
|
||||
final Material m = lever.getType();
|
||||
if(m != Material.LEVER) return;
|
||||
try {
|
||||
legacySetBlockData.invoke(lever, (byte) (lever.getData() ^ 0x8));
|
||||
lever.getState().update();
|
||||
//lever.getWorld().playEffect(lever.getLocation(), Effect.CLICK1, 0);
|
||||
// now we need to update the redstone around it..
|
||||
// int data = lever.getData() & ~0x8;
|
||||
// Block attached;
|
||||
// switch(data) {
|
||||
// case 0:
|
||||
// attached = lever.getRelative(BlockFace.UP);
|
||||
// break;
|
||||
// case 1:
|
||||
// attached = lever.getRelative(BlockFace.WEST);
|
||||
// break;
|
||||
// case 2:
|
||||
// attached = lever.getRelative(BlockFace.EAST);
|
||||
// break;
|
||||
// case 3:
|
||||
// attached = lever.getRelative(BlockFace.NORTH);
|
||||
// break;
|
||||
// case 4:
|
||||
// attached = lever.getRelative(BlockFace.SOUTH);
|
||||
// break;
|
||||
// case 5:
|
||||
// attached = lever.getRelative(BlockFace.DOWN);
|
||||
// break;
|
||||
// default:
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Change all of the given door states to be inverse; that is, if a door is
|
||||
* open, it will be closed afterwards. If the door is closed, it will become
|
||||
* open.
|
||||
* <p/>
|
||||
* Note that the blocks given must be the bottom block of the door.
|
||||
*
|
||||
* @param allowDoorToOpen If FALSE, and the door is currently CLOSED, it
|
||||
* will NOT be opened!
|
||||
* @param doors Blocks given must be the bottom block of the door
|
||||
*/
|
||||
public static void toggleDoorStates(boolean allowDoorToOpen, Block... doors) {
|
||||
if (useLegacy && legacySetBlockData != null) {
|
||||
_toggleDoorStatesLegacy(allowDoorToOpen, doors);
|
||||
} else {
|
||||
BlockUtilsModern._toggleDoorStatesModern(allowDoorToOpen, doors);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _toggleDoorStatesLegacy(boolean allowDoorToOpen, Block... doors) {
|
||||
try {
|
||||
for (Block door : doors) {
|
||||
if (door == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean isTop = (door.getData() & 0x8) != 0;
|
||||
if (isTop) {
|
||||
// The lower half of the door contains the direction & open/close state
|
||||
door = door.getRelative(BlockFace.DOWN);
|
||||
}
|
||||
|
||||
// If we aren't allowing the door to open, check if it's already closed
|
||||
if (!allowDoorToOpen && (door.getData() & 0x4) == 0) {
|
||||
// The door is already closed and we don't want to open it
|
||||
// the bit 0x4 is set when the door is open
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now xor both data values with 0x4, the flag that states if the door is open
|
||||
legacySetBlockData.invoke(door, (byte) (door.getData() ^ 0x4));
|
||||
|
||||
// Play the door open/close sound
|
||||
door.getWorld().playEffect(door.getLocation(), Effect.DOOR_TOGGLE, 0);
|
||||
}
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
||||
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the double door for the given block
|
||||
*
|
||||
* @param block
|
||||
* @return
|
||||
*/
|
||||
public static Block getDoubleDoor(Block block) {
|
||||
// TODO? if legacy, just search N/S/E/W to see if there's another door nearby
|
||||
if (!isOpenable(block.getType())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return BlockUtilsModern._getDoubleDoorModern(block);
|
||||
}
|
||||
|
||||
public static boolean isOpenable(Material m) {
|
||||
return DOORS.contains(m)
|
||||
|| FENCE_GATES.contains(m)
|
||||
|| TRAP_DOORS.contains(m);
|
||||
}
|
||||
|
||||
public static BlockFace getDoorClosedDirection(Block door) {
|
||||
return useLegacy ? _getDoorClosedDirectionLegacy(door) : BlockUtilsModern._getDoorClosedDirectionModern(door);
|
||||
}
|
||||
|
||||
private static BlockFace _getDoorClosedDirectionLegacy(Block door) {
|
||||
final Material type = door.getType();
|
||||
if (DOORS.contains(type)) {
|
||||
boolean isTop = (door.getData() & 0x8) != 0;
|
||||
if (isTop) {
|
||||
// The lower half of the door contains the direction & open/close state
|
||||
door = door.getRelative(BlockFace.DOWN);
|
||||
if (door.getType() != type) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
boolean isOpen = (door.getData() & 0x4) != 0;
|
||||
//int facing = (door.getData() & 0x3);
|
||||
// [east, south, west, north]
|
||||
boolean facingNS = (door.getData() & 0x1) != 0;
|
||||
if (facingNS) {
|
||||
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
} else {
|
||||
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
||||
}
|
||||
} else if (FENCE_GATES.contains(door.getType())) {
|
||||
boolean isOpen = (door.getData() & 0x4) != 0;
|
||||
//int facing = (door.getData() & 0x3);
|
||||
// so fence gate orientations are [south, west, north, east]
|
||||
boolean facingNS = (door.getData() & 0x1) == 0;
|
||||
if (facingNS) {
|
||||
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
} else {
|
||||
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
||||
}
|
||||
} else if (TRAP_DOORS.contains(door.getType())) {
|
||||
boolean isOpen = (door.getData() & 0x4) != 0;
|
||||
// [south, north, east, west]
|
||||
boolean facingNS = (door.getData() & 0x3) <= 1;
|
||||
if (facingNS) {
|
||||
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
} else {
|
||||
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Class<?> clazzCraftWorld, clazzCraftBlock, clazzBlockPosition;
|
||||
private static Method getHandle, updateAdjacentComparators, getNMSBlock;
|
||||
|
||||
/**
|
||||
* Manually trigger the updateAdjacentComparators method for containers
|
||||
* @param containerLocation location of the container
|
||||
*/
|
||||
public static void updateAdjacentComparators(Location containerLocation) {
|
||||
try {
|
||||
// Cache reflection.
|
||||
if (clazzCraftWorld == null) {
|
||||
String ver = Bukkit.getServer().getClass().getPackage().getName().substring(23);
|
||||
clazzCraftWorld = Class.forName("org.bukkit.craftbukkit." + ver + ".CraftWorld");
|
||||
clazzCraftBlock = Class.forName("org.bukkit.craftbukkit." + ver + ".block.CraftBlock");
|
||||
clazzBlockPosition = Class.forName("net.minecraft.server." + ver + ".BlockPosition");
|
||||
Class<?> clazzWorld = Class.forName("net.minecraft.server." + ver + ".World");
|
||||
Class<?> clazzBlock = Class.forName("net.minecraft.server." + ver + ".Block");
|
||||
|
||||
getHandle = clazzCraftWorld.getMethod("getHandle");
|
||||
updateAdjacentComparators = clazzWorld.getMethod("updateAdjacentComparators", clazzBlockPosition, clazzBlock);
|
||||
getNMSBlock = clazzCraftBlock.getDeclaredMethod("getNMSBlock");
|
||||
getNMSBlock.setAccessible(true);
|
||||
}
|
||||
|
||||
// invoke and cast objects.
|
||||
Object craftWorld = clazzCraftWorld.cast(containerLocation.getWorld());
|
||||
Object world = getHandle.invoke(craftWorld);
|
||||
Object craftBlock = clazzCraftBlock.cast(containerLocation.getBlock());
|
||||
|
||||
// Invoke final method.
|
||||
updateAdjacentComparators
|
||||
.invoke(world, clazzBlockPosition.getConstructor(double.class, double.class, double.class)
|
||||
.newInstance(containerLocation.getX(), containerLocation.getY(), containerLocation.getZ()),
|
||||
getNMSBlock.invoke(craftBlock));
|
||||
|
||||
} catch (ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canPassThrough(Material m) {
|
||||
|
||||
switch (m.name()) {
|
||||
case "ACACIA_BUTTON":
|
||||
case "ACACIA_PRESSURE_PLATE":
|
||||
case "ACACIA_SAPLING":
|
||||
case "ACACIA_SIGN":
|
||||
case "ACACIA_WALL_SIGN":
|
||||
case "ACTIVATOR_RAIL":
|
||||
case "AIR":
|
||||
case "ATTACHED_MELON_STEM":
|
||||
case "ATTACHED_PUMPKIN_STEM":
|
||||
case "AZURE_BLUET":
|
||||
//case "BAMBOO_SAPLING":
|
||||
//case "BARRIER": // could let robots pass through barriers
|
||||
case "BEETROOTS":
|
||||
case "BIRCH_BUTTON":
|
||||
case "BIRCH_PRESSURE_PLATE":
|
||||
case "BIRCH_SAPLING":
|
||||
case "BIRCH_SIGN":
|
||||
case "BIRCH_WALL_SIGN":
|
||||
case "BLACK_WALL_BANNER":
|
||||
case "BLUE_BANNER":
|
||||
case "BLUE_ORCHID":
|
||||
case "BLUE_WALL_BANNER":
|
||||
case "BRAIN_CORAL_FAN":
|
||||
case "BRAIN_CORAL_WALL_FAN":
|
||||
case "BROWN_BANNER":
|
||||
case "BROWN_MUSHROOM":
|
||||
case "BROWN_WALL_BANNER":
|
||||
case "BUBBLE_CORAL_FAN":
|
||||
case "BUBBLE_CORAL_WALL_FAN":
|
||||
case "CARROTS":
|
||||
case "CAVE_AIR":
|
||||
case "COBWEB":
|
||||
case "CORNFLOWER":
|
||||
case "CYAN_BANNER":
|
||||
case "CYAN_WALL_BANNER":
|
||||
case "DANDELION":
|
||||
case "DARK_OAK_BUTTON":
|
||||
case "DARK_OAK_PRESSURE_PLATE":
|
||||
case "DARK_OAK_SAPLING":
|
||||
case "DARK_OAK_SIGN":
|
||||
case "DARK_OAK_WALL_SIGN":
|
||||
case "DEAD_BRAIN_CORAL_FAN":
|
||||
case "DEAD_BRAIN_CORAL_WALL_FAN":
|
||||
case "DEAD_BUBBLE_CORAL_FAN":
|
||||
case "DEAD_BUBBLE_CORAL_WALL_FAN":
|
||||
case "DEAD_BUSH":
|
||||
case "DEAD_FIRE_CORAL_FAN":
|
||||
case "DEAD_FIRE_CORAL_WALL_FAN":
|
||||
case "DEAD_HORN_CORAL_FAN":
|
||||
case "DEAD_HORN_CORAL_WALL_FAN":
|
||||
case "DEAD_TUBE_CORAL_FAN":
|
||||
case "DEAD_TUBE_CORAL_WALL_FAN":
|
||||
case "DETECTOR_RAIL":
|
||||
case "END_PORTAL":
|
||||
case "FERN":
|
||||
case "FIRE": // probably should take damage
|
||||
case "FIRE_CORAL_FAN":
|
||||
case "FIRE_CORAL_WALL_FAN":
|
||||
case "GRASS":
|
||||
case "GRAY_BANNER":
|
||||
case "GRAY_WALL_BANNER":
|
||||
case "GREEN_BANNER":
|
||||
case "GREEN_WALL_BANNER":
|
||||
case "HEAVY_WEIGHTED_PRESSURE_PLATE":
|
||||
case "HORN_CORAL_FAN":
|
||||
case "HORN_CORAL_WALL_FAN":
|
||||
case "JUNGLE_BUTTON":
|
||||
case "JUNGLE_PRESSURE_PLATE":
|
||||
case "JUNGLE_SAPLING":
|
||||
case "JUNGLE_SIGN":
|
||||
case "JUNGLE_WALL_SIGN":
|
||||
case "KELP":
|
||||
case "LADDER":
|
||||
case "LARGE_FERN":
|
||||
case "LAVA":
|
||||
case "LEVER":
|
||||
case "LIGHT_BLUE_BANNER":
|
||||
case "LIGHT_BLUE_WALL_BANNER":
|
||||
case "LIGHT_GRAY_BANNER":
|
||||
case "LIGHT_GRAY_WALL_BANNER":
|
||||
case "LIGHT_WEIGHTED_PRESSURE_PLATE":
|
||||
case "LILAC":
|
||||
case "LILY_OF_THE_VALLEY":
|
||||
case "LIME_BANNER":
|
||||
case "MAGENTA_BANNER":
|
||||
case "MAGENTA_WALL_BANNER":
|
||||
case "MELON_STEM":
|
||||
case "NETHER_PORTAL":
|
||||
case "NETHER_WART":
|
||||
case "OAK_BUTTON":
|
||||
case "OAK_PRESSURE_PLATE":
|
||||
case "OAK_SAPLING":
|
||||
case "OAK_SIGN":
|
||||
case "OAK_WALL_SIGN":
|
||||
case "ORANGE_BANNER":
|
||||
case "ORANGE_TULIP":
|
||||
case "ORANGE_WALL_BANNER":
|
||||
case "OXEYE_DAISY":
|
||||
case "PEONY":
|
||||
case "PINK_BANNER":
|
||||
case "PINK_TULIP":
|
||||
case "PINK_WALL_BANNER":
|
||||
case "POTATOES":
|
||||
case "POWERED_RAIL":
|
||||
case "PUMPKIN_STEM":
|
||||
case "PURPLE_BANNER":
|
||||
case "PURPLE_WALL_BANNER":
|
||||
case "RAIL":
|
||||
case "REDSTONE_TORCH":
|
||||
case "REDSTONE_WALL_TORCH":
|
||||
case "REDSTONE_WIRE":
|
||||
case "RED_BANNER":
|
||||
case "RED_MUSHROOM":
|
||||
case "RED_TULIP":
|
||||
case "RED_WALL_BANNER":
|
||||
case "ROSE_BUSH":
|
||||
case "SCAFFOLDING":
|
||||
case "SEAGRASS":
|
||||
case "SPRUCE_BUTTON":
|
||||
case "SPRUCE_PRESSURE_PLATE":
|
||||
case "SPRUCE_SAPLING":
|
||||
case "SPRUCE_SIGN":
|
||||
case "SPRUCE_WALL_SIGN":
|
||||
case "STONE_BUTTON":
|
||||
case "STONE_PRESSURE_PLATE":
|
||||
case "STRUCTURE_VOID":
|
||||
case "SUGAR_CANE":
|
||||
case "SUNFLOWER":
|
||||
case "SWEET_BERRY_BUSH":
|
||||
case "TALL_GRASS":
|
||||
case "TALL_SEAGRASS":
|
||||
case "TORCH":
|
||||
case "TRIPWIRE":
|
||||
case "TRIPWIRE_HOOK":
|
||||
case "TUBE_CORAL_FAN":
|
||||
case "TUBE_CORAL_WALL_FAN":
|
||||
case "VINE":
|
||||
case "VOID_AIR":
|
||||
case "WALL_TORCH":
|
||||
case "WATER":
|
||||
case "WHEAT":
|
||||
case "WHITE_BANNER":
|
||||
case "WHITE_TULIP":
|
||||
case "WHITE_WALL_BANNER":
|
||||
case "WITHER_ROSE":
|
||||
case "YELLOW_BANNER":
|
||||
case "YELLOW_WALL_BANNER":
|
||||
// Legacy values:
|
||||
case "WEB":
|
||||
case "LONG_GRASS":
|
||||
case "YELLOW_FLOWER":
|
||||
case "RED_ROSE":
|
||||
case "CROPS":
|
||||
case "SIGN_POST":
|
||||
case "RAILS":
|
||||
case "WALL_SIGN":
|
||||
case "STONE_PLATE":
|
||||
case "WOOD_PLATE":
|
||||
case "REDSTONE_TORCH_OFF":
|
||||
case "REDSTONE_TORCH_ON":
|
||||
case "SUGAR_CANE_BLOCK":
|
||||
case "PORTAL":
|
||||
case "ENDER_PORTAL":
|
||||
case "CARROT":
|
||||
case "POTATO":
|
||||
case "WOOD_BUTTON":
|
||||
case "GOLD_PLATE":
|
||||
case "IRON_PLATE":
|
||||
case "DOUBLE_PLANT":
|
||||
case "STANDING_BANNER":
|
||||
case "WALL_BANNER":
|
||||
case "BEETROOT_BLOCK":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean canWalkTo(Material m) {
|
||||
switch (m.name()) {
|
||||
case "ACACIA_BUTTON":
|
||||
case "ACACIA_PRESSURE_PLATE":
|
||||
case "ACACIA_SAPLING":
|
||||
case "ACACIA_SIGN":
|
||||
case "ACACIA_SLAB":
|
||||
case "ACACIA_STAIRS":
|
||||
case "ACACIA_TRAPDOOR":
|
||||
case "ACACIA_WALL_SIGN":
|
||||
case "ACTIVATOR_RAIL":
|
||||
case "AIR":
|
||||
case "ANDESITE_SLAB":
|
||||
case "ANDESITE_STAIRS":
|
||||
case "ATTACHED_MELON_STEM":
|
||||
case "ATTACHED_PUMPKIN_STEM":
|
||||
case "AZURE_BLUET":
|
||||
//case "BAMBOO_SAPLING":
|
||||
//case "BARRIER": // could let robots pass through barriers
|
||||
case "BEETROOTS":
|
||||
case "BIRCH_BUTTON":
|
||||
case "BIRCH_DOOR":
|
||||
case "BIRCH_FENCE_GATE":
|
||||
case "BIRCH_PRESSURE_PLATE":
|
||||
case "BIRCH_SAPLING":
|
||||
case "BIRCH_SIGN":
|
||||
case "BIRCH_SLAB":
|
||||
case "BIRCH_STAIRS":
|
||||
case "BIRCH_TRAPDOOR":
|
||||
case "BIRCH_WALL_SIGN":
|
||||
case "BLACK_CARPET":
|
||||
case "BLACK_WALL_BANNER":
|
||||
case "BLUE_BANNER":
|
||||
case "BLUE_CARPET":
|
||||
case "BLUE_ORCHID":
|
||||
case "BLUE_WALL_BANNER":
|
||||
case "BRAIN_CORAL_FAN":
|
||||
case "BRAIN_CORAL_WALL_FAN":
|
||||
case "BRICK_SLAB":
|
||||
case "BRICK_STAIRS":
|
||||
case "BROWN_BANNER":
|
||||
case "BROWN_CARPET":
|
||||
case "BROWN_MUSHROOM":
|
||||
case "BROWN_WALL_BANNER":
|
||||
case "BUBBLE_CORAL_FAN":
|
||||
case "BUBBLE_CORAL_WALL_FAN":
|
||||
case "CAKE":
|
||||
case "CAMPFIRE": // could take damage from walking over?
|
||||
case "CARROTS":
|
||||
case "CAVE_AIR":
|
||||
case "COBBLESTONE_SLAB":
|
||||
case "COBBLESTONE_STAIRS":
|
||||
case "COBWEB":
|
||||
case "COMPARATOR":
|
||||
case "CORNFLOWER":
|
||||
case "CUT_RED_SANDSTONE_SLAB":
|
||||
case "CUT_SANDSTONE_SLAB":
|
||||
case "CYAN_BANNER":
|
||||
case "CYAN_CARPET":
|
||||
case "CYAN_WALL_BANNER":
|
||||
case "DANDELION":
|
||||
case "DARK_OAK_BUTTON":
|
||||
case "DARK_OAK_DOOR":
|
||||
case "DARK_OAK_FENCE_GATE":
|
||||
case "DARK_OAK_PRESSURE_PLATE":
|
||||
case "DARK_OAK_SAPLING":
|
||||
case "DARK_OAK_SIGN":
|
||||
case "DARK_OAK_SLAB":
|
||||
case "DARK_OAK_STAIRS":
|
||||
case "DARK_OAK_TRAPDOOR":
|
||||
case "DARK_OAK_WALL_SIGN":
|
||||
case "DARK_PRISMARINE_SLAB":
|
||||
case "DARK_PRISMARINE_STAIRS":
|
||||
case "DAYLIGHT_DETECTOR":
|
||||
case "DEAD_BRAIN_CORAL_FAN":
|
||||
case "DEAD_BRAIN_CORAL_WALL_FAN":
|
||||
case "DEAD_BUBBLE_CORAL_FAN":
|
||||
case "DEAD_BUBBLE_CORAL_WALL_FAN":
|
||||
case "DEAD_BUSH":
|
||||
case "DEAD_FIRE_CORAL_FAN":
|
||||
case "DEAD_FIRE_CORAL_WALL_FAN":
|
||||
case "DEAD_HORN_CORAL_FAN":
|
||||
case "DEAD_HORN_CORAL_WALL_FAN":
|
||||
case "DEAD_TUBE_CORAL_FAN":
|
||||
case "DEAD_TUBE_CORAL_WALL_FAN":
|
||||
case "DETECTOR_RAIL":
|
||||
case "DIORITE_SLAB":
|
||||
case "DIORITE_STAIRS":
|
||||
case "END_PORTAL":
|
||||
case "END_STONE_BRICK_SLAB":
|
||||
case "END_STONE_BRICK_STAIRS":
|
||||
case "FERN":
|
||||
case "FIRE": // probably should take damage
|
||||
case "FIRE_CORAL_FAN":
|
||||
case "FIRE_CORAL_WALL_FAN":
|
||||
case "FLOWER_POT":
|
||||
case "GRANITE_SLAB":
|
||||
case "GRANITE_STAIRS":
|
||||
case "GRASS":
|
||||
case "GRAY_BANNER":
|
||||
case "GRAY_CARPET":
|
||||
case "GRAY_WALL_BANNER":
|
||||
case "GREEN_BANNER":
|
||||
case "GREEN_WALL_BANNER":
|
||||
case "HEAVY_WEIGHTED_PRESSURE_PLATE":
|
||||
case "HORN_CORAL_FAN":
|
||||
case "HORN_CORAL_WALL_FAN":
|
||||
case "IRON_DOOR":
|
||||
case "JUNGLE_BUTTON":
|
||||
case "JUNGLE_DOOR":
|
||||
case "JUNGLE_FENCE_GATE":
|
||||
case "JUNGLE_PRESSURE_PLATE":
|
||||
case "JUNGLE_SAPLING":
|
||||
case "JUNGLE_SIGN":
|
||||
case "JUNGLE_SLAB":
|
||||
case "JUNGLE_STAIRS":
|
||||
case "JUNGLE_TRAPDOOR":
|
||||
case "JUNGLE_WALL_SIGN":
|
||||
case "KELP":
|
||||
case "LADDER":
|
||||
case "LARGE_FERN":
|
||||
case "LAVA":
|
||||
case "LEVER":
|
||||
case "LIGHT_BLUE_BANNER":
|
||||
case "LIGHT_BLUE_CARPET":
|
||||
case "LIGHT_BLUE_WALL_BANNER":
|
||||
case "LIGHT_GRAY_BANNER":
|
||||
case "LIGHT_GRAY_CARPET":
|
||||
case "LIGHT_GRAY_WALL_BANNER":
|
||||
case "LIGHT_WEIGHTED_PRESSURE_PLATE":
|
||||
case "LILAC":
|
||||
case "LILY_OF_THE_VALLEY":
|
||||
case "LILY_PAD":
|
||||
case "LIME_BANNER":
|
||||
case "LIME_CARPET":
|
||||
case "MAGENTA_BANNER":
|
||||
case "MAGENTA_CARPET":
|
||||
case "MAGENTA_WALL_BANNER":
|
||||
case "MELON_STEM":
|
||||
case "MOSSY_COBBLESTONE_SLAB":
|
||||
case "MOSSY_COBBLESTONE_STAIRS":
|
||||
case "MOSSY_STONE_BRICK_SLAB":
|
||||
case "MOSSY_STONE_BRICK_STAIRS":
|
||||
case "NETHER_BRICK_SLAB":
|
||||
case "NETHER_BRICK_STAIRS":
|
||||
case "NETHER_PORTAL":
|
||||
case "NETHER_WART":
|
||||
case "OAK_BUTTON":
|
||||
case "OAK_DOOR":
|
||||
case "OAK_FENCE_GATE":
|
||||
case "OAK_PRESSURE_PLATE":
|
||||
case "OAK_SAPLING":
|
||||
case "OAK_SIGN":
|
||||
case "OAK_SLAB":
|
||||
case "OAK_STAIRS":
|
||||
case "OAK_TRAPDOOR":
|
||||
case "OAK_WALL_SIGN":
|
||||
case "ORANGE_BANNER":
|
||||
case "ORANGE_CARPET":
|
||||
case "ORANGE_TULIP":
|
||||
case "ORANGE_WALL_BANNER":
|
||||
case "OXEYE_DAISY":
|
||||
case "PEONY":
|
||||
case "PETRIFIED_OAK_SLAB":
|
||||
case "PINK_BANNER":
|
||||
case "PINK_CARPET":
|
||||
case "PINK_TULIP":
|
||||
case "PINK_WALL_BANNER":
|
||||
case "POLISHED_ANDESITE_SLAB":
|
||||
case "POLISHED_ANDESITE_STAIRS":
|
||||
case "POLISHED_DIORITE_SLAB":
|
||||
case "POLISHED_DIORITE_STAIRS":
|
||||
case "POLISHED_GRANITE_SLAB":
|
||||
case "POLISHED_GRANITE_STAIRS":
|
||||
case "POTATOES":
|
||||
case "POTTED_ACACIA_SAPLING":
|
||||
case "POTTED_ALLIUM":
|
||||
case "POTTED_AZURE_BLUET":
|
||||
case "POTTED_BAMBOO":
|
||||
case "POTTED_BIRCH_SAPLING":
|
||||
case "POTTED_BLUE_ORCHID":
|
||||
case "POTTED_BROWN_MUSHROOM":
|
||||
case "POTTED_CACTUS":
|
||||
case "POTTED_CORNFLOWER":
|
||||
case "POTTED_DANDELION":
|
||||
case "POTTED_DARK_OAK_SAPLING":
|
||||
case "POTTED_DEAD_BUSH":
|
||||
case "POTTED_FERN":
|
||||
case "POTTED_JUNGLE_SAPLING":
|
||||
case "POTTED_LILY_OF_THE_VALLEY":
|
||||
case "POTTED_OAK_SAPLING":
|
||||
case "POTTED_ORANGE_TULIP":
|
||||
case "POTTED_OXEYE_DAISY":
|
||||
case "POTTED_PINK_TULIP":
|
||||
case "POTTED_POPPY":
|
||||
case "POTTED_RED_MUSHROOM":
|
||||
case "POTTED_RED_TULIP":
|
||||
case "POTTED_SPRUCE_SAPLING":
|
||||
case "POTTED_WHITE_TULIP":
|
||||
case "POTTED_WITHER_ROSE":
|
||||
case "POWERED_RAIL":
|
||||
case "PRISMARINE_BRICK_SLAB":
|
||||
case "PRISMARINE_BRICK_STAIRS":
|
||||
case "PRISMARINE_SLAB":
|
||||
case "PRISMARINE_STAIRS":
|
||||
case "PUMPKIN_STEM":
|
||||
case "PURPLE_BANNER":
|
||||
case "PURPLE_CARPET":
|
||||
case "PURPLE_WALL_BANNER":
|
||||
case "PURPUR_SLAB":
|
||||
case "PURPUR_STAIRS":
|
||||
case "RAIL":
|
||||
case "REDSTONE_TORCH":
|
||||
case "REDSTONE_WALL_TORCH":
|
||||
case "REDSTONE_WIRE":
|
||||
case "RED_BANNER":
|
||||
case "RED_CARPET":
|
||||
case "RED_MUSHROOM":
|
||||
case "RED_SANDSTONE_SLAB":
|
||||
case "RED_SANDSTONE_STAIRS":
|
||||
case "RED_TULIP":
|
||||
case "RED_WALL_BANNER":
|
||||
case "REPEATER":
|
||||
case "ROSE_BUSH":
|
||||
case "SANDSTONE_SLAB":
|
||||
case "SANDSTONE_STAIRS":
|
||||
case "SCAFFOLDING":
|
||||
case "SEAGRASS":
|
||||
case "SMOOTH_QUARTZ_SLAB":
|
||||
case "SMOOTH_QUARTZ_STAIRS":
|
||||
case "SMOOTH_RED_SANDSTONE_SLAB":
|
||||
case "SMOOTH_RED_SANDSTONE_STAIRS":
|
||||
case "SMOOTH_SANDSTONE_SLAB":
|
||||
case "SMOOTH_SANDSTONE_STAIRS":
|
||||
case "SMOOTH_STONE_SLAB":
|
||||
case "SPRUCE_BUTTON":
|
||||
case "SPRUCE_DOOR":
|
||||
case "SPRUCE_FENCE_GATE":
|
||||
case "SPRUCE_PRESSURE_PLATE":
|
||||
case "SPRUCE_SAPLING":
|
||||
case "SPRUCE_SIGN":
|
||||
case "SPRUCE_SLAB":
|
||||
case "SPRUCE_STAIRS":
|
||||
case "SPRUCE_TRAPDOOR":
|
||||
case "SPRUCE_WALL_SIGN":
|
||||
case "STONECUTTER": // technically can step on, so sure
|
||||
case "STONE_BRICK_SLAB":
|
||||
case "STONE_BRICK_STAIRS":
|
||||
case "STONE_BUTTON":
|
||||
case "STONE_PRESSURE_PLATE":
|
||||
case "STONE_SLAB":
|
||||
case "STONE_STAIRS":
|
||||
case "STRUCTURE_VOID":
|
||||
case "SUGAR_CANE":
|
||||
case "SUNFLOWER":
|
||||
case "SWEET_BERRY_BUSH":
|
||||
case "TALL_GRASS":
|
||||
case "TALL_SEAGRASS":
|
||||
case "TORCH":
|
||||
case "TRIPWIRE":
|
||||
case "TRIPWIRE_HOOK":
|
||||
case "TUBE_CORAL_FAN":
|
||||
case "TUBE_CORAL_WALL_FAN":
|
||||
case "VINE":
|
||||
case "VOID_AIR":
|
||||
case "WALL_TORCH":
|
||||
case "WATER":
|
||||
case "WHEAT":
|
||||
case "WHITE_BANNER":
|
||||
case "WHITE_CARPET":
|
||||
case "WHITE_TULIP":
|
||||
case "WHITE_WALL_BANNER":
|
||||
case "WITHER_ROSE":
|
||||
case "YELLOW_BANNER":
|
||||
case "YELLOW_CARPET":
|
||||
case "YELLOW_WALL_BANNER":
|
||||
// Legacy values:
|
||||
case "WEB":
|
||||
case "LONG_GRASS":
|
||||
case "YELLOW_FLOWER":
|
||||
case "RED_ROSE":
|
||||
case "STEP":
|
||||
case "WOOD_STAIRS":
|
||||
case "CROPS":
|
||||
case "SIGN_POST":
|
||||
case "RAILS":
|
||||
case "WOODEN_DOOR":
|
||||
case "WALL_SIGN":
|
||||
case "STONE_PLATE":
|
||||
case "IRON_DOOR_BLOCK":
|
||||
case "WOOD_PLATE":
|
||||
case "REDSTONE_TORCH_OFF":
|
||||
case "REDSTONE_TORCH_ON":
|
||||
case "SNOW":
|
||||
case "SUGAR_CANE_BLOCK":
|
||||
case "PORTAL":
|
||||
case "CAKE_BLOCK":
|
||||
case "DIODE_BLOCK_OFF":
|
||||
case "DIODE_BLOCK_ON":
|
||||
case "TRAP_DOOR":
|
||||
case "FENCE_GATE":
|
||||
case "SMOOTH_STAIRS":
|
||||
case "ENDER_PORTAL":
|
||||
case "WOOD_STEP":
|
||||
case "SPRUCE_WOOD_STAIRS":
|
||||
case "BIRCH_WOOD_STAIRS":
|
||||
case "JUNGLE_WOOD_STAIRS":
|
||||
case "CARROT":
|
||||
case "POTATO":
|
||||
case "WOOD_BUTTON":
|
||||
case "GOLD_PLATE":
|
||||
case "IRON_PLATE":
|
||||
case "REDSTONE_COMPARATOR_OFF":
|
||||
case "REDSTONE_COMPARATOR_ON":
|
||||
case "QUARTZ_STAIRS":
|
||||
case "DOUBLE_PLANT":
|
||||
case "STANDING_BANNER":
|
||||
case "WALL_BANNER":
|
||||
case "DAYLIGHT_DETECTOR_INVERTED":
|
||||
case "DOUBLE_STONE_SLAB2":
|
||||
case "STONE_SLAB2":
|
||||
case "BEETROOT_BLOCK":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
161
src/main/java/com/songoda/core/utils/BlockUtilsModern.java
Normal file
161
src/main/java/com/songoda/core/utils/BlockUtilsModern.java
Normal file
@ -0,0 +1,161 @@
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.AnaloguePowerable;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.block.data.type.Gate;
|
||||
import org.bukkit.block.data.type.Switch;
|
||||
import org.bukkit.block.data.type.TrapDoor;
|
||||
|
||||
public class BlockUtilsModern {
|
||||
|
||||
protected static void _updatePressurePlateModern(Block plate, int power) {
|
||||
BlockData blockData = plate.getBlockData();
|
||||
if (blockData instanceof AnaloguePowerable) {
|
||||
AnaloguePowerable a = (AnaloguePowerable) blockData;
|
||||
a.setPower(Math.max(a.getMaximumPower(), power));
|
||||
plate.setBlockData(a);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void _toggleLeverModern(Block lever) {
|
||||
BlockData blockData = lever.getBlockData();
|
||||
if (blockData instanceof Switch) {
|
||||
Switch s = (Switch) blockData;
|
||||
s.setPowered(!s.isPowered());
|
||||
lever.setBlockData(s);
|
||||
//lever.getWorld().playEffect(lever.getLocation(), Effect.CLICK1, 0);
|
||||
lever.getState().update();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void _pressButtonModern(Block button) {
|
||||
BlockData blockData = button.getBlockData();
|
||||
if (blockData instanceof Switch) {
|
||||
Switch s = (Switch) blockData;
|
||||
s.setPowered(true);
|
||||
button.setBlockData(s);
|
||||
//lever.getWorld().playEffect(lever.getLocation(), Effect.CLICK1, 0);
|
||||
button.getState().update();
|
||||
}
|
||||
}
|
||||
|
||||
static void _releaseButtonModern(Block button) {
|
||||
BlockData blockData = button.getBlockData();
|
||||
if (blockData instanceof Switch) {
|
||||
Switch s = (Switch) blockData;
|
||||
s.setPowered(false);
|
||||
button.setBlockData(s);
|
||||
//lever.getWorld().playEffect(lever.getLocation(), Effect.CLICK1, 0);
|
||||
button.getState().update();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void _toggleDoorStatesModern(boolean allowDoorToOpen, Block... doors) {
|
||||
for (Block door : doors) {
|
||||
BlockData blockData;
|
||||
if (door == null || !((blockData = door.getBlockData()) instanceof Door)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Door data = (Door) blockData;
|
||||
if (!allowDoorToOpen && !data.isOpen()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The lower half of the door contains the open/close state
|
||||
if (data.getHalf() == Bisected.Half.TOP) {
|
||||
Block lowerHalf = door.getRelative(BlockFace.DOWN);
|
||||
if (lowerHalf.getBlockData() instanceof Door) {
|
||||
Door lowerData = (Door) lowerHalf.getBlockData();
|
||||
lowerData.setOpen(!data.isOpen());
|
||||
lowerHalf.setBlockData(lowerData);
|
||||
}
|
||||
} else {
|
||||
data.setOpen(!data.isOpen());
|
||||
door.setBlockData(data);
|
||||
}
|
||||
|
||||
// Play the door open/close sound
|
||||
door.getWorld().playEffect(door.getLocation(), Effect.DOOR_TOGGLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected static Block _getDoubleDoorModern(Block block) {
|
||||
BlockData bd = block.getBlockData();
|
||||
Block door = null;
|
||||
if (bd instanceof Door) {
|
||||
final Door d = (Door) bd;
|
||||
final BlockFace face = d.getFacing();
|
||||
if (face.getModX() == 0) {
|
||||
if (d.getHinge() == Door.Hinge.RIGHT) {
|
||||
door = block.getRelative(face.getModZ(), 0, 0);
|
||||
} else {
|
||||
door = block.getRelative(-face.getModZ(), 0, 0);
|
||||
}
|
||||
} else {
|
||||
if (d.getHinge() == Door.Hinge.RIGHT) {
|
||||
door = block.getRelative(0, 0, -face.getModX());
|
||||
} else {
|
||||
door = block.getRelative(0, 0, face.getModX());
|
||||
}
|
||||
}
|
||||
}
|
||||
return door != null && door.getBlockData() instanceof Door
|
||||
&& ((Door) door.getBlockData()).getHinge() != ((Door) bd).getHinge() ? door : null;
|
||||
}
|
||||
|
||||
protected static BlockFace _getDoorClosedDirectionModern(Block door) {
|
||||
if (BlockUtils.DOORS.contains(door.getType())) {
|
||||
BlockData bd = door.getBlockData();
|
||||
if (bd instanceof Door) {
|
||||
Door d = (Door) bd;
|
||||
|
||||
// The lower half of the door contains the open/close state
|
||||
if (d.getHalf() == Bisected.Half.TOP) {
|
||||
door = door.getRelative(BlockFace.DOWN);
|
||||
if (door.getBlockData() instanceof Door) {
|
||||
d = (Door) door.getBlockData();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final BlockFace face = d.getFacing();
|
||||
// now we /could/ also correct for the hinge (top block), it's not needed information
|
||||
if (face.getModX() == 0) {
|
||||
return d.isOpen() ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
} else {
|
||||
return d.isOpen() ? BlockFace.SOUTH : BlockFace.EAST;
|
||||
}
|
||||
}
|
||||
} else if (BlockUtils.FENCE_GATES.contains(door.getType())) {
|
||||
BlockData bd = door.getBlockData();
|
||||
if (bd instanceof Gate) {
|
||||
Gate g = (Gate) bd;
|
||||
final BlockFace face = g.getFacing();
|
||||
if (face.getModX() == 0) {
|
||||
return g.isOpen() ? BlockFace.EAST : BlockFace.SOUTH;
|
||||
} else {
|
||||
return g.isOpen() ? BlockFace.SOUTH : BlockFace.EAST;
|
||||
}
|
||||
}
|
||||
} else if (BlockUtils.TRAP_DOORS.contains(door.getType())) {
|
||||
BlockData bd = door.getBlockData();
|
||||
if (bd instanceof TrapDoor) {
|
||||
TrapDoor t = (TrapDoor) bd;
|
||||
if (!t.isOpen()) {
|
||||
return BlockFace.UP;
|
||||
} else {
|
||||
return t.getFacing();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
747
src/main/java/com/songoda/core/utils/ItemUtils.java
Normal file
747
src/main/java/com/songoda/core/utils/ItemUtils.java
Normal file
@ -0,0 +1,747 @@
|
||||
/**
|
||||
* This class uses some Minecraft code and also Paper API
|
||||
*/
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.songoda.core.compatibility.LegacyMaterials;
|
||||
import com.songoda.core.compatibility.ServerVersion;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
public class ItemUtils {
|
||||
|
||||
static boolean check_compatibility = false;
|
||||
static boolean can_getI18NDisplayName = true;
|
||||
|
||||
static void init() {
|
||||
check_compatibility = true;
|
||||
try {
|
||||
ItemStack.class.getMethod("getI18NDisplayName");
|
||||
} catch (NoSuchMethodException | SecurityException ex) {
|
||||
can_getI18NDisplayName = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack getAsCopy(ItemStack item, int qty) {
|
||||
// org.bukkit.inventory.ItemStack.asQuantity is a paper-only function
|
||||
ItemStack clone = item.clone();
|
||||
clone.setAmount(qty);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public static String getItemName(ItemStack it) {
|
||||
if (!check_compatibility) {
|
||||
init();
|
||||
}
|
||||
if (it == null) {
|
||||
return null;
|
||||
} else if (can_getI18NDisplayName) {
|
||||
return it.getI18NDisplayName();
|
||||
} else {
|
||||
return itemName(it.getType());
|
||||
}
|
||||
}
|
||||
|
||||
static String itemName(Material mat) {
|
||||
String matName = mat.name().replace("_", " ");
|
||||
StringBuilder titleCase = new StringBuilder(matName.length());
|
||||
|
||||
Stream.of(matName.split(" ")).forEach(s -> {
|
||||
s = s.toLowerCase();
|
||||
if (s.equals("of")) {
|
||||
titleCase.append(s).append(" ");
|
||||
} else {
|
||||
char[] str = s.toCharArray();
|
||||
str[0] = Character.toUpperCase(str[0]);
|
||||
titleCase.append(new String(str)).append(" ");
|
||||
}
|
||||
});
|
||||
|
||||
return titleCase.toString().trim();
|
||||
}
|
||||
|
||||
public static ItemStack getPlayerSkull(OfflinePlayer player) {
|
||||
ItemStack head = LegacyMaterials.PLAYER_HEAD.getItem();
|
||||
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_8)) {
|
||||
return head;
|
||||
}
|
||||
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
|
||||
meta.setOwningPlayer(player);
|
||||
} else {
|
||||
meta.setOwner(player.getName());
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
public static void setHeadOwner(ItemStack head, OfflinePlayer player) {
|
||||
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_8) || head == null || !LegacyMaterials.PLAYER_HEAD.matches(head)) {
|
||||
return;
|
||||
}
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
|
||||
meta.setOwningPlayer(player);
|
||||
} else {
|
||||
meta.setOwner(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack getCustomHead(String texture) {
|
||||
ItemStack skullItem = LegacyMaterials.PLAYER_HEAD.getItem();
|
||||
if (ServerVersion.isServerVersionBelow(ServerVersion.V1_8)) {
|
||||
return skullItem;
|
||||
}
|
||||
SkullMeta sm = (SkullMeta) skullItem.getItemMeta();
|
||||
GameProfile gm;
|
||||
if (texture.endsWith("=")) {
|
||||
gm = new GameProfile(UUID.nameUUIDFromBytes(texture.getBytes()), "CustomHead");
|
||||
gm.getProperties().put("textures", new Property("texture", texture.replaceAll("=", "")));
|
||||
} else {
|
||||
gm = new GameProfile(UUID.nameUUIDFromBytes(texture.getBytes()), "CustomHead");
|
||||
byte[] encodedData = Base64.getEncoder().encode(String.format("{textures:{SKIN:{url:\"http://textures.minecraft.net/texture/%s\"}}}", texture).getBytes());
|
||||
gm.getProperties().put("textures", new Property("textures", new String(encodedData)));
|
||||
}
|
||||
|
||||
try {
|
||||
Field profileField;
|
||||
profileField = sm.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(sm, gm);
|
||||
skullItem.setItemMeta(sm);
|
||||
return skullItem;
|
||||
} catch (NoSuchFieldException | IllegalAccessException | SecurityException ex) {
|
||||
throw new RuntimeException("Reflection error while setting head texture", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSimilarMaterial(ItemStack is1, ItemStack is2) {
|
||||
LegacyMaterials mat1 = LegacyMaterials.getMaterial(is1);
|
||||
return mat1 != null && mat1 == LegacyMaterials.getMaterial(is2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this item can be moved into a single slot in this
|
||||
* inventory. <br>
|
||||
* This returns true if there is a free slot or a slot with a matching item
|
||||
* where adding this item's amount to that item's amount will not violate
|
||||
* the maximum stack size for that item.
|
||||
*
|
||||
* @param inventory inventory to check
|
||||
* @param item item to check against
|
||||
* @return true if a free slot or single receiver slot is available
|
||||
*/
|
||||
public static boolean canMove(Inventory inventory, ItemStack item) {
|
||||
if (inventory.firstEmpty() != -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final ItemMeta itemMeta = item.getItemMeta();
|
||||
for (ItemStack stack : inventory) {
|
||||
final ItemMeta stackMeta;
|
||||
if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
|
||||
&& ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
|
||||
&& (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this item can be moved into a single slot in this
|
||||
* inventory. <br>
|
||||
* This returns true if there is a free slot or a slot with a matching item
|
||||
* where adding this item's amount to that item's amount will not violate
|
||||
* the maximum stack size for that item.
|
||||
*
|
||||
* @param contents inventory to check
|
||||
* @param item item to check against
|
||||
* @return true if a free slot or single receiver slot is available
|
||||
*/
|
||||
public static boolean canMove(ItemStack[] contents, ItemStack item) {
|
||||
final ItemMeta itemMeta = item.getItemMeta();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
final ItemStack stack = contents[i];
|
||||
if (stack == null || stack.getAmount() == 0) {
|
||||
return true;
|
||||
}
|
||||
final ItemMeta stackMeta;
|
||||
if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
|
||||
&& ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
|
||||
&& (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this item can be moved into a single slot in this
|
||||
* inventory while also reserving one of the slots.<br>
|
||||
* This returns true if there is a free slot or a slot with a matching item
|
||||
* where adding this item's amount to that item's amount will not violate
|
||||
* the maximum stack size for that item.
|
||||
*
|
||||
* @param inventory inventory to check
|
||||
* @param item item to check against
|
||||
* @param reserved which slot should be reserved
|
||||
* @return true if a free slot or single receiver slot is available
|
||||
*/
|
||||
public static boolean canMoveReserved(Inventory inventory, ItemStack item, int reserved) {
|
||||
final ItemMeta itemMeta = item.getItemMeta();
|
||||
final ItemStack[] contents = inventory.getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
if (i == reserved) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack stack = contents[i];
|
||||
final ItemMeta stackMeta;
|
||||
if (stack == null || stack.getAmount() == 0
|
||||
|| (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
|
||||
&& ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
|
||||
&& (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this item can be moved into a single slot in this
|
||||
* inventory while also reserving one of the slots.<br>
|
||||
* This returns true if there is a free slot or a slot with a matching item
|
||||
* where adding this item's amount to that item's amount will not violate
|
||||
* the maximum stack size for that item.
|
||||
*
|
||||
* @param contents inventory to check
|
||||
* @param item item to check against
|
||||
* @param reserved which slot should be reserved
|
||||
* @return true if a free slot or single receiver slot is available
|
||||
*/
|
||||
public static boolean canMoveReserved(ItemStack[] contents, ItemStack item, int reserved) {
|
||||
final ItemMeta itemMeta = item.getItemMeta();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
if (i == reserved) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack stack = contents[i];
|
||||
if (stack == null || stack.getAmount() == 0) {
|
||||
return true;
|
||||
}
|
||||
final ItemMeta stackMeta;
|
||||
if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
|
||||
&& ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
|
||||
&& (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add up to a number of items to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amountToAdd how many of this item to attempt to add
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param maxSize maximum number of different items this container can hold
|
||||
* @return how many items were added
|
||||
*/
|
||||
public static int addAny(ItemStack item, int amountToAdd, List<ItemStack> inventory, int maxSize) {
|
||||
return addAny(item, amountToAdd, inventory, maxSize, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add up to a number of items to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amountToAdd how many of this item to attempt to add
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param maxSize maximum number of different items this container can hold
|
||||
* @param reserved slot to reserve - will not fill this slot
|
||||
* @return how many items were added
|
||||
*/
|
||||
public static int addAny(ItemStack item, int amountToAdd, List<ItemStack> inventory, int maxSize, int reserved) {
|
||||
int totalAdded = 0;
|
||||
if (inventory != null && item != null && amountToAdd > 0) {
|
||||
final int maxStack = item.getMaxStackSize();
|
||||
for (int i = 0; amountToAdd > 0 && i < maxSize; i++) {
|
||||
if (i == reserved) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack cacheItem = i >= inventory.size() ? null : inventory.get(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
int toAdd = Math.min(maxStack, amountToAdd);
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(toAdd);
|
||||
if (i >= inventory.size()) {
|
||||
inventory.add(item2);
|
||||
} else {
|
||||
inventory.set(i, item2);
|
||||
}
|
||||
totalAdded += toAdd;
|
||||
amountToAdd -= toAdd;
|
||||
} else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
|
||||
// free space!
|
||||
int toAdd = Math.min(maxStack - cacheItem.getAmount(), amountToAdd);
|
||||
inventory.get(i).setAmount(toAdd + cacheItem.getAmount());
|
||||
totalAdded += toAdd;
|
||||
amountToAdd -= toAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to this inventory, but only if it can be added completely.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param containerSize maximum number of different items this container can
|
||||
* hold
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, List<ItemStack> inventory, int containerSize) {
|
||||
if (inventory == null || item == null || item.getAmount() <= 0 || containerSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
return addItem(item, item.getAmount(), inventory, containerSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to this inventory, but only if it can be added completely.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param containerSize maximum number of different items this container can
|
||||
* hold
|
||||
* @param reserved slot to reserve - will not fill this slot
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, List<ItemStack> inventory, int containerSize, int reserved) {
|
||||
if (inventory == null || item == null || item.getAmount() <= 0 || containerSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
return addItem(item, item.getAmount(), inventory, containerSize, reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add an item to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amount how many of this item should be added
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param containerSize maximum number of different items this container can
|
||||
* @param reserved slot to reserve - will not fill this slot hold
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, int amount, List<ItemStack> inventory, int containerSize, int reserved) {
|
||||
return addItem(item, amount, inventory, containerSize, reserved, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add an item to this inventory, but only if it can be added completely.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amount how many of this item should be added
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param containerSize maximum number of different items this container can
|
||||
* hold
|
||||
* @param reserved slot to reserve - will not fill this slot
|
||||
* @param inventorySource Material of the container
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, int amount, List<ItemStack> inventory, int containerSize, int reserved, Material inventorySource) {
|
||||
if (inventory == null || item == null || amount <= 0 || inventorySource == null) {
|
||||
return false;
|
||||
}
|
||||
boolean[] check = null;
|
||||
|
||||
if (inventorySource != null && inventorySource != Material.AIR) {
|
||||
// Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
|
||||
if (inventorySource.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// some destination containers have special conditions
|
||||
switch (inventorySource.name()) {
|
||||
case "BREWING_STAND": {
|
||||
|
||||
// first compile a list of what slots to check
|
||||
check = new boolean[5];
|
||||
String typeStr = item.getType().name().toUpperCase();
|
||||
if (typeStr.contains("POTION") || typeStr.contains("BOTTLE")) {
|
||||
// potion bottles are the first three slots
|
||||
check[0] = check[1] = check[2] = true;
|
||||
}
|
||||
// fuel in 5th position, input in 4th
|
||||
if (item.getType() == Material.BLAZE_POWDER) {
|
||||
check[4] = true;
|
||||
} else {
|
||||
check[3] = true;
|
||||
}
|
||||
|
||||
}
|
||||
case "SMOKER":
|
||||
case "BLAST_FURNACE":
|
||||
case "BURNING_FURNACE":
|
||||
case "FURNACE": {
|
||||
|
||||
check = new boolean[3];
|
||||
|
||||
boolean isFuel = !item.getType().name().contains("LOG") && LegacyMaterials.getMaterial(item.getType()).isFuel();
|
||||
// fuel is 2nd slot, input is first
|
||||
if (isFuel) {
|
||||
|
||||
check[1] = true;
|
||||
} else {
|
||||
check[0] = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// grab the amount to move and the max item stack size
|
||||
int toAdd = item.getAmount();
|
||||
final int maxStack = item.getMaxStackSize();
|
||||
|
||||
// we can reduce calls to ItemStack.isSimilar() by caching what cells to look at
|
||||
if (check == null) {
|
||||
check = new boolean[containerSize];
|
||||
for (int i = 0; toAdd > 0 && i < check.length; i++) {
|
||||
check[i] = true;
|
||||
}
|
||||
}
|
||||
if (reserved >= 0 && check.length < reserved) {
|
||||
check[reserved] = false;
|
||||
}
|
||||
|
||||
// first verify that we can add this item
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (check[i]) {
|
||||
final ItemStack cacheItem = i >= inventory.size() ? null : inventory.get(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
toAdd -= Math.min(maxStack, toAdd);
|
||||
check[i] = true;
|
||||
} else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
|
||||
// free space!
|
||||
toAdd -= Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
check[i] = true;
|
||||
} else {
|
||||
check[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toAdd <= 0) {
|
||||
// all good to add!
|
||||
toAdd = item.getAmount();
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (!check[i]) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack cacheItem = i >= inventory.size() ? null : inventory.get(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
int adding = Math.min(maxStack, toAdd);
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(adding);
|
||||
if (i >= inventory.size()) {
|
||||
inventory.add(item2);
|
||||
} else {
|
||||
inventory.set(i, item2);
|
||||
}
|
||||
toAdd -= adding;
|
||||
} else if (maxStack > cacheItem.getAmount()) {
|
||||
// free space!
|
||||
// (no need to check item.isSimilar(cacheItem), since we have that cached in check[])
|
||||
int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
inventory.get(i).setAmount(adding + cacheItem.getAmount());
|
||||
toAdd -= adding;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add up to a number of items to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amountToAdd how many of this item to attempt to add
|
||||
* @param inventory a list that represents the inventory
|
||||
* @return how many items were added
|
||||
*/
|
||||
public static int addAny(ItemStack item, int amountToAdd, Inventory inventory) {
|
||||
int totalAdded = 0;
|
||||
if (inventory != null && item != null && amountToAdd > 0) {
|
||||
final int containerSize = inventory.getSize();
|
||||
final int maxStack = item.getMaxStackSize();
|
||||
for (int i = 0; amountToAdd > 0 && i < containerSize; i++) {
|
||||
final ItemStack cacheItem = inventory.getItem(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
int toAdd = Math.min(maxStack, amountToAdd);
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(toAdd);
|
||||
inventory.setItem(i, item2);
|
||||
totalAdded += toAdd;
|
||||
amountToAdd -= toAdd;
|
||||
} else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
|
||||
// free space!
|
||||
int toAdd = Math.min(maxStack - cacheItem.getAmount(), amountToAdd);
|
||||
cacheItem.setAmount(toAdd + cacheItem.getAmount());
|
||||
totalAdded += toAdd;
|
||||
amountToAdd -= toAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to this inventory, but only if it can be added completely.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param inventory a list that represents the inventory hold
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, Inventory inventory) {
|
||||
if (inventory == null || item == null || item.getAmount() <= 0) {
|
||||
return false;
|
||||
}
|
||||
return addItem(item, item.getAmount(), inventory, -1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add an item to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amount how many of this item should be added
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param reserved slot to reserve - will not fill this slot
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, int amount, Inventory inventory, int reserved) {
|
||||
return addItem(item, amount, inventory, reserved, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add an item to this inventory, but only if it can be added completely.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amount how many of this item should be added
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param reserved slot to reserve - will not fill this slot
|
||||
* @param inventorySource Material of the container
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, int amount, Inventory inventory, int reserved, Material inventorySource) {
|
||||
if (inventory == null || item == null || amount <= 0 || inventorySource == null) {
|
||||
return false;
|
||||
}
|
||||
boolean[] check = null;
|
||||
|
||||
if (inventorySource != null && inventorySource != Material.AIR) {
|
||||
|
||||
// Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
|
||||
if (inventorySource.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// some destination containers have special conditions
|
||||
switch (inventorySource.name()) {
|
||||
case "BREWING_STAND": {
|
||||
|
||||
// first compile a list of what slots to check
|
||||
check = new boolean[5];
|
||||
String typeStr = item.getType().name().toUpperCase();
|
||||
if (typeStr.contains("POTION") || typeStr.contains("BOTTLE")) {
|
||||
// potion bottles are the first three slots
|
||||
check[0] = check[1] = check[2] = true;
|
||||
}
|
||||
// fuel in 5th position, input in 4th
|
||||
if (item.getType() == Material.BLAZE_POWDER) {
|
||||
check[4] = true;
|
||||
} else {
|
||||
check[3] = true;
|
||||
}
|
||||
|
||||
}
|
||||
case "SMOKER":
|
||||
case "BLAST_FURNACE":
|
||||
case "BURNING_FURNACE":
|
||||
case "FURNACE": {
|
||||
|
||||
check = new boolean[3];
|
||||
|
||||
boolean isFuel = !item.getType().name().contains("LOG") && LegacyMaterials.getMaterial(item.getType()).isFuel();
|
||||
// fuel is 2nd slot, input is first
|
||||
if (isFuel) {
|
||||
|
||||
check[1] = true;
|
||||
} else {
|
||||
check[0] = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// grab the amount to move and the max item stack size
|
||||
int toAdd = item.getAmount();
|
||||
final int maxStack = item.getMaxStackSize();
|
||||
final int containerSize = inventory.getSize();
|
||||
|
||||
// we can reduce calls to ItemStack.isSimilar() by caching what cells to look at
|
||||
if (check == null) {
|
||||
check = new boolean[containerSize];
|
||||
for (int i = 0; toAdd > 0 && i < check.length; i++) {
|
||||
check[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// first verify that we can add this item
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (check[i]) {
|
||||
final ItemStack cacheItem = inventory.getItem(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
toAdd -= Math.min(maxStack, toAdd);
|
||||
check[i] = true;
|
||||
} else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
|
||||
// free space!
|
||||
toAdd -= Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
check[i] = true;
|
||||
} else {
|
||||
check[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toAdd <= 0) {
|
||||
// all good to add!
|
||||
toAdd = item.getAmount();
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (!check[i]) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack cacheItem = inventory.getItem(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
int adding = Math.min(maxStack, toAdd);
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(adding);
|
||||
inventory.setItem(i, item2);
|
||||
toAdd -= adding;
|
||||
} else if (maxStack > cacheItem.getAmount()) {
|
||||
// free space!
|
||||
// (no need to check item.isSimilar(cacheItem), since we have that cached in check[])
|
||||
int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
cacheItem.setAmount(adding + cacheItem.getAmount());
|
||||
toAdd -= adding;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add an item to this inventory.
|
||||
*
|
||||
* @param item item to add
|
||||
* @param amount how many of this item should be added
|
||||
* @param inventory a list that represents the inventory
|
||||
* @param containerSize maximum number of different items this container can
|
||||
* hold
|
||||
* @return true if the item was added
|
||||
*/
|
||||
public static boolean addItem(ItemStack item, int amount, List<ItemStack> inventory, int containerSize) {
|
||||
if (inventory == null || item == null || amount <= 0 || containerSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// grab the amount to move and the max item stack size
|
||||
int toAdd = amount;
|
||||
final int maxStack = item.getMaxStackSize();
|
||||
boolean[] check = null;
|
||||
|
||||
// we can reduce calls to ItemStack.isSimilar() by caching what cells to look at
|
||||
if (check == null) {
|
||||
check = new boolean[containerSize];
|
||||
for (int i = 0; toAdd > 0 && i < check.length; i++) {
|
||||
check[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// first verify that we can add this item
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (check[i]) {
|
||||
final ItemStack cacheItem = i >= inventory.size() ? null : inventory.get(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
toAdd -= Math.min(maxStack, toAdd);
|
||||
check[i] = true;
|
||||
} else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
|
||||
// free space!
|
||||
toAdd -= Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
check[i] = true;
|
||||
} else {
|
||||
check[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toAdd <= 0) {
|
||||
// all good to add!
|
||||
toAdd = item.getAmount();
|
||||
for (int i = 0; toAdd > 0 && i < containerSize; i++) {
|
||||
if (!check[i]) {
|
||||
continue;
|
||||
}
|
||||
final ItemStack cacheItem = i >= inventory.size() ? null : inventory.get(i);
|
||||
if (cacheItem == null || cacheItem.getAmount() == 0) {
|
||||
// free slot!
|
||||
int adding = Math.min(maxStack, toAdd);
|
||||
ItemStack item2 = item.clone();
|
||||
item2.setAmount(adding);
|
||||
if (i >= inventory.size()) {
|
||||
inventory.add(item2);
|
||||
} else {
|
||||
inventory.set(i, item2);
|
||||
}
|
||||
toAdd -= adding;
|
||||
} else if (maxStack > cacheItem.getAmount()) {
|
||||
// free space!
|
||||
// (no need to check item.isSimilar(cacheItem), since we have that cached in check[])
|
||||
int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd);
|
||||
inventory.get(i).setAmount(adding + cacheItem.getAmount());
|
||||
toAdd -= adding;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -32,6 +32,25 @@ public class PlayerUtils {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all of the players that this player can "see"
|
||||
*
|
||||
* @param sender user to check against, or null for all players
|
||||
* @param startingWith optional query to test: only players whose game names
|
||||
* start with this
|
||||
* @return list of player names that are "visible" to the player
|
||||
*/
|
||||
public static List<String> getVisiblePlayerDisplayNames(CommandSender sender, String startingWith) {
|
||||
Player player = sender instanceof Player ? (Player) sender : null;
|
||||
final String startsWith = startingWith == null || startingWith.isEmpty() ? null : startingWith.replaceAll("[^a-zA-Z]", "").toLowerCase();
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.filter(p -> p != player)
|
||||
.filter(p -> startsWith == null || p.getDisplayName().replaceAll("[^a-zA-Z]", "").toLowerCase().startsWith(startsWith))
|
||||
.filter(p -> player == null || (player.canSee(p) && p.getMetadata("vanished").isEmpty()))
|
||||
.map(Player::getDisplayName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all of the players that this player can "see"
|
||||
*
|
||||
@ -51,9 +70,39 @@ public class PlayerUtils {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all online player names that start with a string.
|
||||
*
|
||||
* @param us Ourselves / who is requesting the list. Will not return this player.
|
||||
* @param startsWith All names returned must start with this input string
|
||||
* @return List of matching player IGN
|
||||
*/
|
||||
public static List<String> getAllPlayers(CommandSender us, String startsWith) {
|
||||
final String arg = startsWith.toLowerCase();
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.filter(p -> us != p && p.getName().startsWith(arg))
|
||||
.map(Player::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all online player names that start with a string.
|
||||
*
|
||||
* @param us Ourselves / who is requesting the list. Will not return this player.
|
||||
* @param startsWith All names returned must start with this input string
|
||||
* @return List of matching player display names
|
||||
*/
|
||||
public static List<String> getAllPlayersDisplay(CommandSender us, String startsWith) {
|
||||
final String arg = startsWith.replaceAll("[^a-zA-Z]", "").toLowerCase();
|
||||
return Bukkit.getOnlinePlayers().stream()
|
||||
.filter(p -> us != p && p.getDisplayName().replaceAll("[^a-zA-Z]", "").startsWith(arg))
|
||||
.map(Player::getDisplayName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for and grab the closest match for a provided player name. <br />
|
||||
* Uses player display names if there is not an exact match.
|
||||
* Also checks player display names if there is not an exact match.
|
||||
*
|
||||
* @param player player to search for
|
||||
* @return Player that closest matches the input name, or null if none found
|
||||
@ -61,12 +110,21 @@ public class PlayerUtils {
|
||||
public static Player findPlayer(String player) {
|
||||
Player found = Bukkit.getServer().getPlayer(player);
|
||||
if (found == null) {
|
||||
final String searchName = player.replaceAll("[^a-zA-Z]", "").toLowerCase();
|
||||
final String searchName = player.toLowerCase();
|
||||
final String searchDisplayName = player.replaceAll("[^a-zA-Z]", "").toLowerCase();
|
||||
int d = 999;
|
||||
for (Player p2 : Bukkit.getOnlinePlayers()) {
|
||||
final String test = p2.getDisplayName().replaceAll("[^a-zA-Z]", "");
|
||||
if (test.toLowerCase().startsWith(searchName)) {
|
||||
int d2 = test.length() - searchName.length();
|
||||
final String test;
|
||||
if (p2.getName().toLowerCase().startsWith(searchName)) {
|
||||
int d2 = p2.getName().length() - searchName.length();
|
||||
if (d2 < d) {
|
||||
found = p2;
|
||||
d = d2;
|
||||
} else if (d2 == d) {
|
||||
found = null;
|
||||
}
|
||||
} else if ((test = p2.getDisplayName().replaceAll("[^a-zA-Z]", "")).toLowerCase().startsWith(searchDisplayName)) {
|
||||
int d2 = test.length() - searchDisplayName.length();
|
||||
if (d2 < d) {
|
||||
found = p2;
|
||||
d = d2;
|
||||
|
327
src/main/java/com/songoda/core/utils/ReflectionUtils.java
Normal file
327
src/main/java/com/songoda/core/utils/ReflectionUtils.java
Normal file
@ -0,0 +1,327 @@
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.CodeSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
public final static double JAVA_VERSION = getVersion();
|
||||
private static String system_os = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
private static double getVersion() {
|
||||
String version = System.getProperty("java.version");
|
||||
int i = version.indexOf('.');
|
||||
if (i != -1 && (i = version.indexOf('.', i + 1)) != -1) {
|
||||
return Double.parseDouble(version.substring(0, i));
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
public static File getJarFile(Class jarClass) {
|
||||
return new File(jarClass.getProtectionDomain().getCodeSource().getLocation().getPath().
|
||||
replace("%20", " ").replace("%25", "%"));
|
||||
}
|
||||
|
||||
public static void setPrivateField(Class<?> c, Object handle, String fieldName, Object value) throws Exception {
|
||||
Field f = c.getDeclaredField(fieldName);
|
||||
f.setAccessible(true);
|
||||
f.set(handle, value);
|
||||
}
|
||||
|
||||
public static Object getPrivateField(Class<?> c, Object handle, String fieldName) throws Exception {
|
||||
Field field = c.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(handle);
|
||||
}
|
||||
|
||||
public static Object invokePrivateMethod(Class<?> c, String methodName, Object handle, Class[] types, Object[] parameters) throws Exception {
|
||||
Method m = c.getDeclaredMethod(methodName, types);
|
||||
m.setAccessible(true);
|
||||
return m.invoke(handle, parameters);
|
||||
}
|
||||
|
||||
// does not work in JRE 8+
|
||||
private static Method getStackTraceElementMethod;
|
||||
private static Method getStackTraceDepthMethod;
|
||||
|
||||
static {
|
||||
try {
|
||||
getStackTraceElementMethod = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class);
|
||||
getStackTraceElementMethod.setAccessible(true);
|
||||
getStackTraceDepthMethod = Throwable.class.getDeclaredMethod("getStackTraceDepth");
|
||||
getStackTraceDepthMethod.setAccessible(true);
|
||||
} catch (Exception ex) {
|
||||
getStackTraceElementMethod = getStackTraceDepthMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If you only need one stack trace element this is faster than
|
||||
* Throwable.getStackTrace()[element], it doesn't generate the full stack
|
||||
* trace.
|
||||
*/
|
||||
public static StackTraceElement getStackTraceElement(int index) {
|
||||
try {
|
||||
Throwable dummy = new Throwable();
|
||||
|
||||
if (JAVA_VERSION >= 8 && JAVA_VERSION < 9) {
|
||||
return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(dummy, index);
|
||||
// } else if (JAVA_VERSION >= 9) {
|
||||
// return StackWalker.getInstance(Collections.emptySet(), index + 1)
|
||||
// .walk(s -> s.skip(index).findFirst())
|
||||
// .orElse(null);
|
||||
} else if (getStackTraceElementMethod == null) {
|
||||
// better than nothing, right? :/
|
||||
return (new Throwable()).getStackTrace()[index];
|
||||
} else {
|
||||
if (index < (Integer) getStackTraceDepthMethod.invoke(dummy)) {
|
||||
return (StackTraceElement) getStackTraceElementMethod.invoke(new Throwable(), index);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> Map<Class<?>, T> getClassesInClassPackageByAnnotation(Class<?> clazz, Class<T> annotation) throws IOException {
|
||||
final Map<Class<?>, T> foundClasses = new HashMap<>();
|
||||
for (Class<?> c : getAllClassesInClassPackage(clazz, false)) {
|
||||
T t = c.getAnnotation(annotation);
|
||||
if (t != null) {
|
||||
foundClasses.put(c, t);
|
||||
}
|
||||
}
|
||||
return foundClasses;
|
||||
}
|
||||
|
||||
public static List<Class<?>> getAllClassesInClassPackage(Class<?> clazz, boolean recursive) throws IOException {
|
||||
final List<Class<?>> packageClasses = new ArrayList<>();
|
||||
|
||||
final String clazzPackageName = clazz.getPackage().getName();
|
||||
URL dot = clazz.getResource(".");
|
||||
if (dot == null) {
|
||||
// jar file
|
||||
String packagePath = clazzPackageName.replace('.', '/');
|
||||
CodeSource src = clazz.getProtectionDomain().getCodeSource();
|
||||
if (src != null) {
|
||||
URL jar = src.getLocation();
|
||||
ZipInputStream zip = new ZipInputStream(jar.openStream());
|
||||
ZipEntry e;
|
||||
while ((e = zip.getNextEntry()) != null) {
|
||||
String name = e.getName();
|
||||
if (!name.endsWith("/") && name.startsWith(packagePath + "/")) {
|
||||
if (recursive || name.indexOf('/', packagePath.length() + 1) == -1) {
|
||||
try {
|
||||
Class<?> loadedClazz = Class.forName(name.substring(0, name.lastIndexOf('.')).replace('/', '.'));
|
||||
packageClasses.add(loadedClazz);
|
||||
} catch (ClassNotFoundException e1) {
|
||||
System.err.println("class not found: " + e1.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String clazzPath = clazz.getResource(".").getPath();
|
||||
if (clazzPath.startsWith("/") && system_os.contains("win")) {
|
||||
clazzPath = clazzPath.substring(1);
|
||||
}
|
||||
Path packagePath = Paths.get(clazzPath);
|
||||
|
||||
Files.walkFileTree(packagePath, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
String filename = file.getName(file.getNameCount() - 1).toString();
|
||||
|
||||
if (filename.endsWith(".class")) {
|
||||
String className = filename.replace(".class", "");
|
||||
|
||||
try {
|
||||
Class<?> loadedClazz = Class.forName(
|
||||
clazzPackageName + "." + className);
|
||||
|
||||
packageClasses.add(loadedClazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("class not found: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return packageClasses;
|
||||
}
|
||||
|
||||
public static enum ITERATION {
|
||||
|
||||
NONE, CLASS, PACKAGE, FULL
|
||||
}
|
||||
|
||||
public static List<String> getClassNamesFromPackage(Class classInPackage) throws IOException, URISyntaxException, ClassNotFoundException {
|
||||
String classPath = classInPackage.getName();
|
||||
int packageDelim = classPath.lastIndexOf('.');
|
||||
return getClassNamesFromPackage(getJarFile(classInPackage), classPath.substring(0, packageDelim), ITERATION.NONE);
|
||||
}
|
||||
|
||||
public static List<String> getClassNamesFromPackage(String packageName) throws IOException, URISyntaxException, ClassNotFoundException {
|
||||
return getClassNamesFromPackage(packageName, ITERATION.NONE);
|
||||
}
|
||||
|
||||
public static List<String> getClassNamesFromPackage(String packageName, ITERATION iterate) throws IOException, URISyntaxException, ClassNotFoundException {
|
||||
return getClassNamesFromPackage(null, packageName, iterate);
|
||||
}
|
||||
|
||||
public static List<String> getClassNamesFromPackage(File sourceJar, String packageName, ITERATION iterate) throws IOException, URISyntaxException, ClassNotFoundException {
|
||||
// http://stackoverflow.com/questions/1456930/how-do-i-read-all-classes-from-a-java-package-in-the-classpath
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
URL packageURL;
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
|
||||
if (packageName.contains("/")) {
|
||||
// load as a file
|
||||
packageURL = classLoader.getResource(packageName);
|
||||
|
||||
// todo - if there is an error, step backwards to find the first avaliable package
|
||||
if (packageURL == null && packageName.contains("/")) {
|
||||
// added - check to see if maybe trying to load a file?
|
||||
final int i = packageName.lastIndexOf('/');
|
||||
packageName = packageName.substring(0, i) + "." + packageName.substring(i + 1);
|
||||
packageURL = classLoader.getResource(packageName);
|
||||
}
|
||||
} else {
|
||||
packageName = packageName.replace(".", "/");
|
||||
packageURL = classLoader.getResource(packageName);
|
||||
|
||||
if (sourceJar == null && packageURL == null) {
|
||||
throw new IOException("Cannot open resource '" + packageName + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sourceJar == null && packageURL == null) {
|
||||
throw new IOException("Cannot open resource '" + packageName + "'");
|
||||
//} else if (packageURL.getProtocol().equals("file") || ) {
|
||||
// cannot do this..
|
||||
} else if (sourceJar != null || packageURL.getProtocol().equals("jar")) {
|
||||
// this can also be used to load jar from resources
|
||||
String jarFileName;
|
||||
JarFile jf;
|
||||
Enumeration<JarEntry> jarEntries;
|
||||
String entryName;
|
||||
|
||||
// build jar file name, then loop through zipped entries
|
||||
jarFileName = sourceJar != null ? sourceJar.getAbsolutePath() : URLDecoder.decode(packageURL.getFile(), "UTF-8");
|
||||
// changed - support for resource jar files, too
|
||||
if (jarFileName.startsWith("file:/")) {
|
||||
jarFileName = jarFileName.substring(system_os.contains("win") ? 5 : 4);
|
||||
}
|
||||
if (jarFileName.startsWith("/") && system_os.contains("win")) {
|
||||
jarFileName = jarFileName.substring(1);
|
||||
}
|
||||
if (jarFileName.contains("!")) {
|
||||
jarFileName = jarFileName.substring(0, jarFileName.indexOf("!"));
|
||||
}
|
||||
|
||||
jf = new JarFile(jarFileName);
|
||||
jarEntries = jf.entries();
|
||||
// in case of multiple sub-classes, keep track of what classes have been searched
|
||||
ArrayList<String> loaded = new ArrayList<String>();
|
||||
while (jarEntries.hasMoreElements()) {
|
||||
entryName = jarEntries.nextElement().getName();
|
||||
if (entryName.startsWith(packageName) && entryName.length() > packageName.length() && entryName.toLowerCase().endsWith(".class")) {
|
||||
if (entryName.contains(".")) {
|
||||
entryName = entryName.substring(packageName.length() + 1, entryName.lastIndexOf('.'));
|
||||
}
|
||||
// iteration test
|
||||
if (!entryName.contains("/") || (iterate == ITERATION.PACKAGE || iterate == ITERATION.FULL)) {
|
||||
|
||||
if (entryName.contains("$")) { // added - sub-package test
|
||||
// added - iteration
|
||||
if (iterate == ITERATION.CLASS || iterate == ITERATION.FULL) {
|
||||
entryName = entryName.substring(0, entryName.indexOf('$')).replace('/', '.');
|
||||
if (!loaded.contains(entryName)) {
|
||||
loaded.add(entryName);
|
||||
try {
|
||||
Class c = Class.forName(packageName.replace('/', '.') + "." + entryName);
|
||||
for (Class c2 : c.getDeclaredClasses()) {
|
||||
names.add(entryName + "." + c2.getSimpleName());
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
names.add(entryName.replace('/', '.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// hits here if running in IDE
|
||||
|
||||
// loop through files in classpath
|
||||
URI uri = new URI(packageURL.toString());
|
||||
File folder = new File(uri.getPath());
|
||||
// won't work with path which contains blank (%20)
|
||||
// File folder = new File(packageURL.getFile());
|
||||
File[] contenuti = folder.listFiles();
|
||||
// in case of multiple sub-classes, keep track of what classes have been searched
|
||||
ArrayList<String> loaded = new ArrayList<String>();
|
||||
String entryName;
|
||||
for (File actual : contenuti) {
|
||||
entryName = actual.getName();
|
||||
if (entryName.contains(".")) { // added - folder check
|
||||
entryName = entryName.substring(0, entryName.lastIndexOf('.'));
|
||||
if (entryName.contains("$")) { // added - sub-package test
|
||||
// added - iteration
|
||||
if (iterate == ITERATION.CLASS || iterate == ITERATION.FULL) {
|
||||
entryName = entryName.substring(0, entryName.indexOf('$'));
|
||||
if (!loaded.contains(entryName)) {
|
||||
loaded.add(entryName);
|
||||
Class c = Class.forName(packageName.replace('/', '.') + "." + entryName);
|
||||
for (Class c2 : c.getDeclaredClasses()) {
|
||||
names.add(entryName + "." + c2.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
names.add(entryName);
|
||||
}
|
||||
} else if (iterate == ITERATION.PACKAGE || iterate == ITERATION.FULL) {
|
||||
// added - iteration
|
||||
for (String sub : getClassNamesFromPackage(packageName + "/" + entryName, iterate)) {
|
||||
names.add(entryName + "." + sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
40
src/main/java/com/songoda/core/utils/RotationUtils.java
Normal file
40
src/main/java/com/songoda/core/utils/RotationUtils.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.songoda.core.utils;
|
||||
|
||||
import org.bukkit.block.BlockFace;
|
||||
|
||||
public class RotationUtils {
|
||||
|
||||
public static float faceToYaw(BlockFace face) {
|
||||
switch (face) {
|
||||
case NORTH:
|
||||
return 180F;
|
||||
case SOUTH:
|
||||
return 0F;
|
||||
case EAST:
|
||||
return -90F;
|
||||
case WEST:
|
||||
return 90F;
|
||||
}
|
||||
return 0F;
|
||||
}
|
||||
|
||||
public static BlockFace yawToFace(float face) {
|
||||
switch ((int) Math.round((face + 360) / 90) * 90) {
|
||||
case 0:
|
||||
case 360:
|
||||
return BlockFace.SOUTH;
|
||||
case 180:
|
||||
case 540:
|
||||
return BlockFace.NORTH;
|
||||
case 270:
|
||||
case 630:
|
||||
return BlockFace.EAST;
|
||||
case 90:
|
||||
case 450:
|
||||
return BlockFace.WEST;
|
||||
}
|
||||
// idk
|
||||
return BlockFace.SOUTH;
|
||||
}
|
||||
|
||||
}
|
@ -2,16 +2,16 @@ package com.songoda.core.utils;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class Methods {
|
||||
public class TextUtils {
|
||||
|
||||
public static String formatText(String text) {
|
||||
return formatText(text, false);
|
||||
}
|
||||
|
||||
public static String formatText(String text, boolean cap) {
|
||||
public static String formatText(String text, boolean capitalize) {
|
||||
if (text == null || text.equals(""))
|
||||
return "";
|
||||
if (cap)
|
||||
if (capitalize)
|
||||
text = text.substring(0, 1).toUpperCase() + text.substring(1);
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
Loading…
Reference in New Issue
Block a user