From 7822d002b8164defba1793fe810d980db5f4b5ec Mon Sep 17 00:00:00 2001 From: Moulberry Date: Tue, 29 Aug 2023 15:53:34 +0800 Subject: [PATCH] Update to support protocol version 4 (Axiom 1.1.0) --- .../java/com/moulberry/axiom/AxiomPaper.java | 185 +++++++++++++----- src/main/java/com/moulberry/axiom/View.java | 132 +++++++++++++ .../axiom/packet/AxiomBigPayloadHandler.java | 2 +- .../packet/SetBlockBufferPacketListener.java | 6 + .../axiom/packet/SetBlockPacketListener.java | 4 + .../axiom/persistence/UUIDDataType.java | 39 ++++ src/main/resources/plugin.yml | 5 + 7 files changed, 327 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/moulberry/axiom/View.java create mode 100644 src/main/java/com/moulberry/axiom/persistence/UUIDDataType.java diff --git a/src/main/java/com/moulberry/axiom/AxiomPaper.java b/src/main/java/com/moulberry/axiom/AxiomPaper.java index 0f7e853..eff5682 100644 --- a/src/main/java/com/moulberry/axiom/AxiomPaper.java +++ b/src/main/java/com/moulberry/axiom/AxiomPaper.java @@ -4,17 +4,14 @@ import com.moulberry.axiom.packet.AxiomBigPayloadHandler; import com.moulberry.axiom.packet.SetBlockBufferPacketListener; import com.moulberry.axiom.packet.SetBlockPacketListener; import com.moulberry.axiom.persistence.ItemStackDataType; -import io.netty.buffer.ByteBuf; +import com.moulberry.axiom.persistence.UUIDDataType; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.ByteToMessageDecoder; +import io.papermc.paper.event.player.PlayerFailMoveEvent; import io.papermc.paper.network.ChannelInitializeListener; import io.papermc.paper.network.ChannelInitializeListenerHolder; -import io.papermc.paper.network.ConnectionEvent; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.Connection; @@ -24,8 +21,6 @@ import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import org.bukkit.*; @@ -34,16 +29,16 @@ import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.java.JavaPlugin; import org.checkerframework.checker.nullness.qual.NonNull; -import org.jetbrains.annotations.NotNull; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.UUID; public class AxiomPaper extends JavaPlugin implements Listener { @@ -54,25 +49,110 @@ public class AxiomPaper extends JavaPlugin implements Listener { } } + private static final int API_VERSION = 4; + private static final NamespacedKey ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index"); + private static final NamespacedKey HOTBAR_DATA = new NamespacedKey("axiom", "hotbar_data"); + + private static final NamespacedKey ACTIVE_VIEW = new NamespacedKey("axiom", "active_view"); + private static final NamespacedKey VIEWS = new NamespacedKey("axiom", "views"); + @Override public void onEnable() { Bukkit.getPluginManager().registerEvents(this, this); Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:enable"); Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:initialize_hotbars"); + Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:set_editor_views"); + HashSet activeAxiomPlayers = new HashSet<>(); + + Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:hello", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + int apiVersion = friendlyByteBuf.readVarInt(); + friendlyByteBuf.readNbt(); // Discard + + if (apiVersion != API_VERSION) { + player.kick(Component.text("Unsupported Axiom API Version. Server supports " + API_VERSION + + ", while client is " + apiVersion)); + return; + } + + activeAxiomPlayers.add(player.getUniqueId()); + + // Enable + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeBoolean(true); + buf.writeByte(0); // todo: world properties + buf.writeInt(0x100000); // Max Buffer Size + buf.writeBoolean(false); // No source info + buf.writeBoolean(false); // No source settings + buf.writeVarInt(5); // Maximum Reach + buf.writeVarInt(16); // Max editor views + buf.writeBoolean(true); // Editable Views + player.sendPluginMessage(this, "axiom:enable", buf.accessByteBufWithCorrectSize()); + + // Initialize Hotbars + PersistentDataContainer container = player.getPersistentDataContainer(); + int activeHotbarIndex = container.getOrDefault(ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0); + PersistentDataContainer hotbarItems = container.get(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER); + if (hotbarItems != null) { + buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeByte((byte) activeHotbarIndex); + for (int i=0; i<9*9; i++) { + // Ignore selected hotbar + if (i / 9 == activeHotbarIndex) { + buf.writeItem(net.minecraft.world.item.ItemStack.EMPTY); + } else { + ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE); + buf.writeItem(CraftItemStack.asNMSCopy(stack)); + } + } + player.sendPluginMessage(this, "axiom:initialize_hotbars", buf.accessByteBufWithCorrectSize()); + } + + // Initialize Views + UUID activeView = container.get(ACTIVE_VIEW, UUIDDataType.INSTANCE); + if (activeView != null) { + buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeUUID(activeView); + + PersistentDataContainer[] views = container.get(VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY); + buf.writeVarInt(views.length); + for (PersistentDataContainer view : views) { + View.load(view).write(buf); + } + + player.sendPluginMessage(this, "axiom:set_editor_views", buf.accessByteBufWithCorrectSize()); + } + }); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_gamemode", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); GameType gameType = GameType.byId(friendlyByteBuf.readByte()); ((CraftPlayer)player).getHandle().setGameMode(gameType); }); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_fly_speed", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); float flySpeed = friendlyByteBuf.readFloat(); ((CraftPlayer)player).getHandle().getAbilities().setFlyingSpeed(flySpeed); }); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this)); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); int index = friendlyByteBuf.readByte(); if (index < 0 || index >= 9*9) return; @@ -85,6 +165,10 @@ public class AxiomPaper extends JavaPlugin implements Listener { container.set(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, hotbarItems); }); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); int oldHotbarIndex = friendlyByteBuf.readByte(); int activeHotbarIndex = friendlyByteBuf.readByte(); @@ -118,6 +202,10 @@ public class AxiomPaper extends JavaPlugin implements Listener { container.set(ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) activeHotbarIndex); }); Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:teleport", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); ResourceKey resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION); double x = friendlyByteBuf.readDouble(); @@ -132,6 +220,26 @@ public class AxiomPaper extends JavaPlugin implements Listener { player.teleport(new Location(world, x, y, z, yRot, xRot)); } }); + Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_editor_views", (channel, player, message) -> { + if (!player.hasPermission("axiom.*")) { + return; + } + + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); + UUID uuid = friendlyByteBuf.readUUID(); + List views = friendlyByteBuf.readList(View::read); + + PersistentDataContainer container = player.getPersistentDataContainer(); + container.set(ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid); + + PersistentDataContainer[] containerArray = new PersistentDataContainer[views.size()]; + for (int i = 0; i < views.size(); i++) { + PersistentDataContainer viewContainer = container.getAdapterContext().newPersistentDataContainer(); + views.get(i).save(viewContainer); + containerArray[i] = viewContainer; + } + container.set(VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY, containerArray); + }); SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this); @@ -147,7 +255,7 @@ public class AxiomPaper extends JavaPlugin implements Listener { } } if (payloadId < 0) { - throw new RuntimeException("Failed ot find ServerboundCustomPayloadPacket id"); + throw new RuntimeException("Failed to find ServerboundCustomPayloadPacket id"); } Connection connection = (Connection) channel.pipeline().get("packet_handler"); @@ -156,45 +264,32 @@ public class AxiomPaper extends JavaPlugin implements Listener { } }); - // Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_block_buffer", new SetBlockBufferPacketListener(this)); - } + Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> { + HashSet newActiveAxiomPlayers = new HashSet<>(); - private static final NamespacedKey ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index"); - private static final NamespacedKey HOTBAR_DATA = new NamespacedKey("axiom", "hotbar_data"); - - @EventHandler - public void onRegisterChannel(PlayerRegisterChannelEvent event) { - Player player = event.getPlayer(); - String channel = event.getChannel(); - - switch (channel) { - case "axiom:enable" -> { - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); - friendlyByteBuf.writeBoolean(true); - friendlyByteBuf.writeByte(0); // todo: world properties - player.sendPluginMessage(this, "axiom:enable", friendlyByteBuf.array()); - } - case "axiom:initialize_hotbars" -> { - PersistentDataContainer container = player.getPersistentDataContainer(); - int activeHotbarIndex = container.getOrDefault(ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0); - PersistentDataContainer hotbarItems = container.get(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER); - if (hotbarItems != null) { - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); - friendlyByteBuf.writeByte((byte) activeHotbarIndex); - for (int i=0; i<9*9; i++) { - // Ignore selected hotbar - if (i / 9 == activeHotbarIndex) continue; - - ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE); - friendlyByteBuf.writeItem(CraftItemStack.asNMSCopy(stack)); + for (Player player : Bukkit.getServer().getOnlinePlayers()) { + if (activeAxiomPlayers.contains(player.getUniqueId())) { + if (!player.hasPermission("axiom.*")) { + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); + buf.writeBoolean(false); + player.sendPluginMessage(this, "axiom:enable", buf.accessByteBufWithCorrectSize()); + } else { + newActiveAxiomPlayers.add(player.getUniqueId()); } - player.sendPluginMessage(this, "axiom:initialize_hotbars", friendlyByteBuf.array()); } } - default -> {} + + activeAxiomPlayers.clear(); + activeAxiomPlayers.addAll(newActiveAxiomPlayers); + }, 20, 20); + } + + @EventHandler + public void onFailMove(PlayerFailMoveEvent event) { + if (event.getPlayer().hasPermission("axiom.*") && + event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) { + event.setAllowed(true); } } - - } diff --git a/src/main/java/com/moulberry/axiom/View.java b/src/main/java/com/moulberry/axiom/View.java new file mode 100644 index 0000000..5dd2138 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/View.java @@ -0,0 +1,132 @@ +package com.moulberry.axiom; + +import com.moulberry.axiom.persistence.UUIDDataType; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.bukkit.NamespacedKey; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import java.util.UUID; + +public final class View { + + public String name; + public final UUID uuid; + public boolean pinLevel = false; + public boolean pinLocation = false; + private ResourceKey level = null; + private Vec3 position = null; + private float yaw; + private float pitch; + + public View(String name, UUID uuid) { + this.name = name; + this.uuid = uuid; + } + + public void write(FriendlyByteBuf byteBuf) { + byteBuf.writeUtf(this.name, 64); + byteBuf.writeUUID(this.uuid); + + byteBuf.writeBoolean(this.pinLevel); + if (this.pinLevel && this.level != null) { + byteBuf.writeBoolean(true); + byteBuf.writeResourceKey(this.level); + } else { + byteBuf.writeBoolean(false); + } + + byteBuf.writeBoolean(this.pinLocation); + if (this.position != null) { + byteBuf.writeBoolean(true); + byteBuf.writeDouble(this.position.x); + byteBuf.writeDouble(this.position.y); + byteBuf.writeDouble(this.position.z); + byteBuf.writeFloat(this.yaw); + byteBuf.writeFloat(this.pitch); + } else { + byteBuf.writeBoolean(false); + } + } + + public static View read(FriendlyByteBuf byteBuf) { + View view = new View(byteBuf.readUtf(64), byteBuf.readUUID()); + + view.pinLevel = byteBuf.readBoolean(); + if (byteBuf.readBoolean()) { + view.level = byteBuf.readResourceKey(Registries.DIMENSION); + } + + view.pinLocation = byteBuf.readBoolean(); + if (byteBuf.readBoolean()) { + view.position = new Vec3(byteBuf.readDouble(), byteBuf.readDouble(), byteBuf.readDouble()); + view.yaw = byteBuf.readFloat(); + view.pitch = byteBuf.readFloat(); + } + + return view; + } + + private static final NamespacedKey NAME_KEY = new NamespacedKey("axiom", "view_name"); + private static final NamespacedKey UUID_KEY = new NamespacedKey("axiom", "view_uuid"); + private static final NamespacedKey PIN_LEVEL_KEY = new NamespacedKey("axiom", "view_pin_level"); + private static final NamespacedKey LEVEL_KEY = new NamespacedKey("axiom", "view_level"); + private static final NamespacedKey PIN_LOCATION_KEY = new NamespacedKey("axiom", "view_pin_location"); + private static final NamespacedKey X_KEY = new NamespacedKey("axiom", "view_x"); + private static final NamespacedKey Y_KEY = new NamespacedKey("axiom", "view_y"); + private static final NamespacedKey Z_KEY = new NamespacedKey("axiom", "view_z"); + private static final NamespacedKey YAW_KEY = new NamespacedKey("axiom", "view_yaw"); + private static final NamespacedKey PITCH_KEY = new NamespacedKey("axiom", "view_pitch"); + + public void save(PersistentDataContainer container) { + container.set(NAME_KEY, PersistentDataType.STRING, this.name); + container.set(UUID_KEY, UUIDDataType.INSTANCE, this.uuid); + + container.set(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, this.pinLevel); + if (this.pinLevel && this.level != null) { + container.set(LEVEL_KEY, PersistentDataType.STRING, this.level.location().toString()); + } + + container.set(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, this.pinLocation); + if (this.position != null) { + container.set(X_KEY, PersistentDataType.DOUBLE, this.position.x); + container.set(Y_KEY, PersistentDataType.DOUBLE, this.position.y); + container.set(Z_KEY, PersistentDataType.DOUBLE, this.position.z); + container.set(YAW_KEY, PersistentDataType.FLOAT, this.yaw); + container.set(PITCH_KEY, PersistentDataType.FLOAT, this.pitch); + } + } + + public static View load(PersistentDataContainer tag) { + String name = tag.get(NAME_KEY, PersistentDataType.STRING); + UUID uuid = tag.get(UUID_KEY, UUIDDataType.INSTANCE); + + View view = new View(name, uuid); + + view.pinLevel = tag.getOrDefault(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, false); + if (tag.has(LEVEL_KEY)) { + String level = tag.get(LEVEL_KEY, PersistentDataType.STRING); + view.level = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(level)); + } + + view.pinLocation = tag.getOrDefault(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, false); + if (tag.has(X_KEY) && tag.has(Y_KEY) && tag.has(Z_KEY)) { + double x = tag.getOrDefault(X_KEY, PersistentDataType.DOUBLE, 0.0); + double y = tag.getOrDefault(Y_KEY, PersistentDataType.DOUBLE, 0.0); + double z = tag.getOrDefault(Z_KEY, PersistentDataType.DOUBLE, 0.0); + view.position = new Vec3(x, y, z); + view.yaw = tag.getOrDefault(YAW_KEY, PersistentDataType.FLOAT, 0.0f); + view.pitch = tag.getOrDefault(PITCH_KEY, PersistentDataType.FLOAT, 0.0f); + } + + return view; + } + +} diff --git a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java index 48682bb..0d85bbc 100644 --- a/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java +++ b/src/main/java/com/moulberry/axiom/packet/AxiomBigPayloadHandler.java @@ -37,7 +37,7 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder { ResourceLocation identifier = buf.readResourceLocation(); if (identifier.equals(SET_BUFFER)) { ServerPlayer player = connection.getPlayer(); - if (player != null) { + if (player != null && player.getBukkitEntity().hasPermission("axiom.*")) { listener.onReceive(player, buf); return; } diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java index 505c417..03c1aa2 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockBufferPacketListener.java @@ -64,6 +64,12 @@ public class SetBlockBufferPacketListener { if (server == null) return; ResourceKey worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION); + friendlyByteBuf.readUUID(); // Discard, we don't need to associate buffers + boolean continuation = friendlyByteBuf.readBoolean(); + + if (!continuation) { + friendlyByteBuf.readNbt(); // Discard sourceInfo + } byte type = friendlyByteBuf.readByte(); if (type == 0) { diff --git a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java index bfdaa08..44ae910 100644 --- a/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java +++ b/src/main/java/com/moulberry/axiom/packet/SetBlockPacketListener.java @@ -48,6 +48,10 @@ public class SetBlockPacketListener implements PluginMessageListener { @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) { + if (!bukkitPlayer.hasPermission("axiom.*")) { + return; + } + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); BlockPos blockPos = friendlyByteBuf.readBlockPos(); BlockState blockState = friendlyByteBuf.readById(Block.BLOCK_STATE_REGISTRY); diff --git a/src/main/java/com/moulberry/axiom/persistence/UUIDDataType.java b/src/main/java/com/moulberry/axiom/persistence/UUIDDataType.java new file mode 100644 index 0000000..12fca84 --- /dev/null +++ b/src/main/java/com/moulberry/axiom/persistence/UUIDDataType.java @@ -0,0 +1,39 @@ +package com.moulberry.axiom.persistence; + +import org.bukkit.persistence.PersistentDataAdapterContext; +import org.bukkit.persistence.PersistentDataType; + +import java.nio.ByteBuffer; +import java.util.UUID; + +public class UUIDDataType implements PersistentDataType { + public static UUIDDataType INSTANCE = new UUIDDataType(); + private UUIDDataType() { + } + + public Class getPrimitiveType() { + return byte[].class; + } + + @Override + public Class getComplexType() { + return UUID.class; + } + + @Override + public byte[] toPrimitive(UUID complex, PersistentDataAdapterContext context) { + ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + bb.putLong(complex.getMostSignificantBits()); + bb.putLong(complex.getLeastSignificantBits()); + return bb.array(); + } + + @Override + public UUID fromPrimitive(byte[] primitive, PersistentDataAdapterContext context) { + ByteBuffer bb = ByteBuffer.wrap(primitive); + long firstLong = bb.getLong(); + long secondLong = bb.getLong(); + return new UUID(firstLong, secondLong); + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c5d9a7e..67339da 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,3 +5,8 @@ description: $description authors: - Moulberry api-version: "$apiVersion" +permissions: + axiom.*: + description: Allows use of all Axiom features + default: op +