diff --git a/bukkit/src/main/java/org/zhdev/varioutil/config/BukkitYamlConfig.java b/bukkit/src/main/java/org/zhdev/varioutil/config/BukkitYamlConfig.java new file mode 100644 index 0000000..323102e --- /dev/null +++ b/bukkit/src/main/java/org/zhdev/varioutil/config/BukkitYamlConfig.java @@ -0,0 +1,45 @@ +package org.zhdev.varioutil.config; + +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.yaml.snakeyaml.nodes.Node; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class BukkitYamlConfig extends YamlConfig { + public BukkitYamlConfig(String key) { + super(key); + } + + public BukkitYamlConfig() { + super(); + } + + @Override + protected Object constructHandle(MapConfigSection section, Node keyNode, Node valueNode, String key, Object value) { + if (value instanceof Map) { + Map raw = (Map) value; + if (raw.containsKey(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) { + Map map = new LinkedHashMap<>(raw.size()); + for (Map.Entry entry : raw.entrySet()) { + map.put(String.valueOf(entry.getKey()), entry.getValue()); + } + return ConfigurationSerialization.deserializeObject(map); + } + } + return super.constructHandle(section, keyNode, valueNode, key, value); + } + + @Override + protected Node representHandle(String key, Object value) { + if (value instanceof ConfigurationSerializable) { + ConfigurationSerializable serializable = (ConfigurationSerializable) value; + Map values = new LinkedHashMap<>(); + values.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, ConfigurationSerialization.getAlias(serializable.getClass())); + values.putAll(serializable.serialize()); + return REPRESENTER.represent(values); + } + return super.representHandle(key, value); + } +} diff --git a/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitReflectionUtils.java b/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitReflectionUtils.java new file mode 100644 index 0000000..31dfba8 --- /dev/null +++ b/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitReflectionUtils.java @@ -0,0 +1,51 @@ +package org.zhdev.varioutil.util; + +import com.mojang.authlib.GameProfile; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.inventory.meta.SkullMeta; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; + +import static org.zhdev.varioutil.util.ReflectionUtils.*; + +class BukkitReflectionUtils { + private static final String VERSION = Bukkit.getServer().getClass().getName().split("\\.")[3]; + + private static final Class __CraftServer__CLASS = searchType("org.bukkit.craftbukkit." + VERSION + ".CraftServer"); + + private static final Method __setProfile__CraftMetaSkull__METHOD = ReflectionUtils.methodSearcher() + .typeOf("org.bukkit.craftbukkit." + VERSION + ".inventory.CraftMetaSkull") + .methodOf("setProfile") + .parameters(GameProfile.class) + .returns(void.class) + .search(); + + private static final Field __commandMap__CraftServer__FIELD = fieldSearcher() + .fieldOf("commandMap") + .type(__CraftServer__CLASS) + .fieldType(CommandMap.class) + .search(); + private static final Field __knownCommands__SimpleCommandMap__FIELD = fieldSearcher() + .fieldOf("knownCommands") + .type(SimpleCommandMap.class) + .fieldType(Map.class) + .search(); + + static CommandMap getCommandMap() { + return (CommandMap) getFieldValue(__commandMap__CraftServer__FIELD, Bukkit.getServer()); + } + + @SuppressWarnings("unchecked") + static Map getKnownCommands() { + return (Map) getFieldValue(__knownCommands__SimpleCommandMap__FIELD, getCommandMap()); + } + + static void setProfile(SkullMeta meta, GameProfile profile) { + ReflectionUtils.invokeMethod(meta, __setProfile__CraftMetaSkull__METHOD, profile); + } +} diff --git a/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitUtils.java b/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitUtils.java new file mode 100644 index 0000000..b163f0c --- /dev/null +++ b/bukkit/src/main/java/org/zhdev/varioutil/util/BukkitUtils.java @@ -0,0 +1,88 @@ +package org.zhdev.varioutil.util; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.bukkit.util.io.BukkitObjectOutputStream; +import org.zhdev.varioutil.Version; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; + +public class BukkitUtils { + public static final Version VERSION; + + private static final CommandMap COMMAND_MAP = BukkitReflectionUtils.getCommandMap(); + private static final Map KNOWN_COMMANDS = BukkitReflectionUtils.getKnownCommands(); + + private static final Map PROFILE_CACHE = new HashMap<>(); + + public static Command getCommand(String label) { + return KNOWN_COMMANDS.get(label); + } + + public static void registerCommand(String fallbackPrefix, String label, Command command) { + COMMAND_MAP.register(label, fallbackPrefix, command); + } + + public static void unregisterCommand(String label) { + KNOWN_COMMANDS.remove(label); + } + + public static void unregisterCommandIf(Predicate predicate) { + KNOWN_COMMANDS.values().removeIf(predicate); + } + + public static void setSkullTexture(SkullMeta meta, String base64) { + GameProfile profile = PROFILE_CACHE.get(base64); + if (profile == null) { + profile = new GameProfile(UUID.randomUUID(), base64); + profile.getProperties().put("textures", new Property("textures", base64)); + PROFILE_CACHE.put(base64, profile); + } + BukkitReflectionUtils.setProfile(meta, profile); + } + + public static String stacksToString(ItemStack[] contents) { + try (ByteArrayOutputStream str = new ByteArrayOutputStream(); + BukkitObjectOutputStream data = new BukkitObjectOutputStream(str)) { + data.writeInt(contents.length); + for (ItemStack stack : contents) { + data.writeObject(stack); + } + return Base64.getEncoder().encodeToString(str.toByteArray()); + } catch (IOException e) { + throw new IllegalStateException("Unable to convert items to string", e); + } + } + + public static ItemStack[] stringToStacks(String inventoryData) { + try (ByteArrayInputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(inventoryData)); + BukkitObjectInputStream data = new BukkitObjectInputStream(stream)) { + int length = data.readInt(); + ItemStack[] stacks = new ItemStack[length]; + for (int i = 0; i < length; i++) { + stacks[i] = (ItemStack) data.readObject(); + } + return stacks; + } catch (IOException | ClassNotFoundException e) { + throw new IllegalStateException("Unable to convert string to items", e); + } + } + + static { + String version = Bukkit.getServer().getVersion(); + VERSION = Version.fromString(version.substring(version.indexOf("(MC: ") + 5, version.length() - 1)); + } +}