add utils

This commit is contained in:
jascotty2 2019-08-26 08:29:50 -05:00
parent 0f2cd764c3
commit 44138bb257
35 changed files with 2203 additions and 18 deletions

21
pom.xml
View File

@ -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>

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -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;

View 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;
}
}

View 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;
}
}

View File

@ -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);
}