Skip to content

Instantly share code, notes, and snippets.

@misterT2525
Last active August 6, 2022 05:32
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save misterT2525/56671488127d6a5e8cc7 to your computer and use it in GitHub Desktop.
Save misterT2525/56671488127d6a5e8cc7 to your computer and use it in GitHub Desktop.

ItemCooldownUtil

License

アイテムのクールダウンを扱うユーティリティークラスです。

Minecraft 1.9にて、エンダーパールなどのアイテムに対してクールダウンが実装されました。 そのクールダウンを任意のアイテムに対して設定したり、 アイテムがクールダウン中か確認することが出来るメソッドが実装されています。

動作環境

確認はしてないけれども、動くはずの環境です。

  • Java 6以降
  • CraftBukkit 1.9以降(Spigot等のCraftBukkitフォークを含む)
  • Minecraft Client 1.9以降

動作確認環境

  • Java 8(1.8.0_77)
  • Spigot 1.9.2(git-Spigot-5a40365-b70058a)
  • Minecraft Client 1.9.2 (with OptiFine)

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.plugin.java.JavaPlugin;

/**
 * @author misterT2525
 */
public class TestPlugin extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        Bukkit.getPluginManager().registerEvents(this, this);
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if (!(sender instanceof Player)) {
            sender.sendMessage(ChatColor.RED + "This command is only executable from Player.");
            return false;
        }
        if (args.length != 1) {
            sender.sendMessage(ChatColor.RED + "Usage: /" + command.getName() + " <ticks>");
            return false;
        }
        int ticks;
        try {
            ticks = Integer.valueOf(args[0]);
        } catch (NumberFormatException e) {
            sender.sendMessage(ChatColor.RED + "Invalid number.");
            return false;
        }
        Player player = ((Player) sender);
        ItemCooldownUtil.setCooldown(player, player.getInventory().getItemInMainHand().getType(), ticks);
        return true;
    }

    @EventHandler
    @SuppressWarnings("unused")
    public void onInteract(PlayerInteractEvent event) {
        if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) {
            return;
        }
        if (!event.hasItem()) {
            return;
        }

        Player player = event.getPlayer();

        if (ItemCooldownUtil.inCooldown(player, event.getItem().getType())) {
            player.sendMessage(ChatColor.RED + "クールダウン中です。");
        }
    }
}

Example

Stone Items

発生する例外について

NullPointerException

このクラスの全てのメソッドは、引数にnullを渡されないことを想定しています。 その為、引数にnullが渡された場合にNullPointerExceptionが発生します。

IllegalArgumentException

引数にアイテムではないMaterialを渡した場合にIllegalArgumentExceptionが発生します。

RuntimeException

上記2つではないRuntimeExceptionは、主にこのユーティリティーが動作しない環境で呼ばれた場合に発生します。 もしも、1.9以降の環境で発生した場合には、不具合の可能性があるので連絡してくれると助かります。

連絡先

作者Twitter(@misterT2525)まで

/*
* The MIT License (MIT)
*
* Copyright (c) 2016 misterT2525
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.mistert2525.itemcooldownutil;// You can move to your package.
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
/**
* Utility class for item cool-down
* <p>
* https://gist.github.com/misterT2525/56671488127d6a5e8cc7
*
* @author misterT2525
*/
public final class ItemCooldownUtil {
public static void setCooldown(Player player, Material item, int ticks) throws NullPointerException, IllegalArgumentException {
if (player == null) throw new NullPointerException("player");
if (item == null) throw new NullPointerException("item");
Object internalItem = convertItem(item);
if (internalItem == null) throw new IllegalArgumentException("item");
invokeMethod(getSetCooldownMethod(), getItemCooldown(player), internalItem, ticks);
}
public static boolean inCooldown(Player player, Material item) throws NullPointerException, IllegalArgumentException {
if (player == null) throw new NullPointerException("player");
if (item == null) throw new NullPointerException("item");
Object internalItem = convertItem(item);
if (internalItem == null) throw new IllegalArgumentException("item");
return (Boolean) invokeMethod(getInCooldownMethod(), getItemCooldown(player), internalItem);
}
/*========== Internal ==========*/
private static Method GET_HANDLE;
private static Method GET_ITEM_COOLDOWN;
private static Method CONVERT_ITEM;
private static Object getItemCooldown(Player player) {
if (GET_HANDLE == null)
GET_HANDLE = getMethodByName(getCraftBukkitClass("entity.CraftPlayer"), "getHandle");
Object handle = invokeMethod(GET_HANDLE, player);
if (GET_ITEM_COOLDOWN == null)
GET_ITEM_COOLDOWN = getMethodByTypes(getMinecraftClass("EntityHuman"), "getItemCooldown", getItemCooldownClass());
return invokeMethod(GET_ITEM_COOLDOWN, handle);
}
private static Object convertItem(Material item) {
if (CONVERT_ITEM == null)
CONVERT_ITEM = getMethodByName(getCraftBukkitClass("util.CraftMagicNumbers"), "getItem", Material.class);
return invokeMethod(CONVERT_ITEM, null, item);
}
private static Method SET_COOLDOWN;
private static Method IN_COOLDOWN;
private static Class<?> ITEM_COOLDOWN_CLASS;
private static Class<?> ITEM_CLASS;
private static Method getSetCooldownMethod() {
if (SET_COOLDOWN == null)
SET_COOLDOWN = getMethodByTypes(getItemCooldownClass(), "setCooldown", void.class, getItemClass(), int.class);
return SET_COOLDOWN;
}
private static Method getInCooldownMethod() {
if (IN_COOLDOWN == null)
IN_COOLDOWN = getMethodByTypes(getItemCooldownClass(), "inCooldown", boolean.class, getItemClass());
return IN_COOLDOWN;
}
private static Class<?> getItemCooldownClass() {
if (ITEM_COOLDOWN_CLASS == null)
ITEM_COOLDOWN_CLASS = getMinecraftClass("ItemCooldown");
return ITEM_COOLDOWN_CLASS;
}
private static Class<?> getItemClass() {
if (ITEM_CLASS == null)
ITEM_CLASS = getMinecraftClass("Item");
return ITEM_CLASS;
}
/*========== Reflection ==========*/
private static String OBC_PACKAGE;
private static String NMS_PACKAGE;
private static Class<?> getCraftBukkitClass(String name) {
if (OBC_PACKAGE == null)
OBC_PACKAGE = Bukkit.getServer().getClass().getPackage().getName() + ".";
return getClass(OBC_PACKAGE + name);
}
private static Class<?> getMinecraftClass(String name) {
if (OBC_PACKAGE == null)
OBC_PACKAGE = Bukkit.getServer().getClass().getPackage().getName() + ".";
if (NMS_PACKAGE == null)
NMS_PACKAGE = OBC_PACKAGE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
return getClass(NMS_PACKAGE + name);
}
private static Class<?> getClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find " + name, e);
}
}
private static Method getMethodByName(Class<?> clazz, String name, Class<?>... parameterTypes) {
try {
return clazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to find " + buildMethodString(clazz, name, null, parameterTypes));
}
}
private static Method getMethodByTypes(Class<?> clazz, String name, Class<?> returnType, Class<?>... parameterTypes) {
for (Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isPublic(method.getModifiers())) {
continue;
}
if (method.getReturnType().equals(returnType) && Arrays.equals(method.getParameterTypes(), parameterTypes)) {
return method;
}
}
throw new RuntimeException("Unable to find " + buildMethodString(clazz, name, returnType, parameterTypes));
}
private static Object invokeMethod(Method method, Object object, Object... args) {
try {
return method.invoke(object, args);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static String buildMethodString(Class<?> clazz, String name, Class<?> returnType, Class<?>... parameterTypes) {
StringBuilder sb = new StringBuilder(clazz.getSimpleName()).append('#').append(name).append('(');
boolean firstParameter = true;
for (Class<?> parameterType : parameterTypes) {
if (firstParameter) {
firstParameter = false;
} else {
sb.append(", ");
}
sb.append(parameterType.getSimpleName());
}
sb.append(')');
if (returnType != null) {
sb.append(": ").append(returnType.getSimpleName());
}
return sb.toString();
}
private ItemCooldownUtil() {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment