diff --git a/api/src/main/java/net/azisaba/loreeditor/api/item/ItemStack.java b/api/src/main/java/net/azisaba/loreeditor/api/item/ItemStack.java index 0a2af32..bec8a7e 100644 --- a/api/src/main/java/net/azisaba/loreeditor/api/item/ItemStack.java +++ b/api/src/main/java/net/azisaba/loreeditor/api/item/ItemStack.java @@ -38,4 +38,7 @@ public interface ItemStack { * @return the amount */ int getCount(); + + @NotNull + ItemStack copy(); } diff --git a/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java b/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java index cbc094e..e032e74 100644 --- a/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java +++ b/api/src/main/java/net/azisaba/loreeditor/api/util/ReflectionUtil.java @@ -25,6 +25,10 @@ public static boolean isModernNMS() { case "1.20.1-R0.1-SNAPSHOT": case "1.20.2-R0.1-SNAPSHOT": return "v1_20"; + case "1.21.1-R0.1-SNAPSHOT": + case "1.21.2-R0.1-SNAPSHOT": + case "1.21.3-R0.1-SNAPSHOT": + return "v1_21_1"; } return Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; } diff --git a/build.gradle.kts b/build.gradle.kts index 6601057..8991296 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,18 +2,19 @@ plugins { java `java-library` `maven-publish` - id("com.github.johnrengelman.shadow") version "7.1.2" + id("com.gradleup.shadow") version "8.3.3" + id("io.papermc.paperweight.userdev") version "1.7.4" apply false } allprojects { group = "net.azisaba.loreeditor" - version = "1.1.0-SNAPSHOT" + version = "1.2.0" apply { plugin("java") plugin("java-library") plugin("maven-publish") - plugin("com.github.johnrengelman.shadow") + plugin("com.gradleup.shadow") } java { @@ -47,6 +48,11 @@ allprojects { repositories { mavenCentral() maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/public/") } + maven("https://repo.papermc.io/repository/maven-public/") { + content { + includeGroup("io.papermc.paper") + } + } maven { url = uri("https://repo.azisaba.net/repository/maven-public/") } maven { url = uri("https://libraries.minecraft.net/") } if (properties["azisabaNmsUsername"] != null && properties["azisabaNmsPassword"] != null) { diff --git a/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java b/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java index 191cff4..3d8b0ca 100644 --- a/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java +++ b/common/src/main/java/net/azisaba/loreeditor/common/network/PacketPreHandler.java @@ -53,9 +53,11 @@ public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) if (msg.getClass().getSimpleName().contains("SetCreativeSlot")) { ServerboundSetCreativeSlot packet = ServerboundSetCreativeSlot.getInstance(msg); reverseProcessItemStack(packet.getItem()); + System.out.println("Reverse processed item (creative slot): " + packet.getItem()); } else if (msg.getClass().getSimpleName().contains("WindowClick")) { ServerboundClickContainerSlot packet = ServerboundClickContainerSlot.getInstance(msg); reverseProcessItemStack(packet.getItem()); + System.out.println("Reverse processed item (window click): " + packet.getItem()); } else if (msg.getClass().getSimpleName().contains("CloseWindow")) { if (player.getOpenInventory().getType() == InventoryType.MERCHANT) { // re-add lore after trading @@ -72,7 +74,7 @@ public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { // server -> client try { - if (msg.getClass().getSimpleName().contains("WindowItems")) { + if (msg.getClass().getSimpleName().contains("WindowItems") || msg.getClass().getSimpleName().contains("ContainerSetContent")) { if (player.getOpenInventory().getType() != InventoryType.MERCHANT) { ClientboundWindowItems packet = ClientboundWindowItems.getInstance(msg); packet.getItems().forEach(i -> { @@ -89,7 +91,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) ClientboundSetSlot packet = ClientboundSetSlot.getInstance(msg); PROCESS_ITEM_PERF_COUNTER.recordStart(); try { - processItemStack(packet.getItem()); +// processItemStack(packet.getItem()); } finally { PROCESS_ITEM_PERF_COUNTER.recordEnd(); } @@ -108,6 +110,7 @@ public void processItemStack(@Nullable ItemStack item) { if (tag == null) { tag = CompoundTag.getInstance(null).constructor(); } + System.out.println("Processing item: " + item + " with tag: " + tag); if (tag.hasKeyOfType("lore_editor", 10)) { return; } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661..1e2fbf0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index d8df81e..053e65d 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -4,6 +4,7 @@ dependencies { api(project(":v1_16_R3")) api(project(":v1_19_R3")) api(project(":v1_20")) + api(project(":v1_21_1")) } tasks { diff --git a/settings.gradle.kts b/settings.gradle.kts index ec2f846..dda5597 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,3 +6,4 @@ include("v1_15_R1") include("v1_16_R3") include("v1_19_R3") include("v1_20") +include("v1_21_1") diff --git a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/item/ItemStackImpl.java b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/item/ItemStackImpl.java index 8bbf941..fff2c1d 100644 --- a/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/item/ItemStackImpl.java +++ b/v1_15_R1/src/main/java/net/azisaba/loreeditor/v1_15_R1/item/ItemStackImpl.java @@ -49,4 +49,9 @@ public void setTag(@Nullable CompoundTag tag) { public int getCount() { return handle.getCount(); } + + @Override + public @NotNull ItemStack copy() { + return new ItemStackImpl(handle.cloneItemStack()); + } } diff --git a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/item/ItemStackImpl.java b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/item/ItemStackImpl.java index d05a3da..2df84c6 100644 --- a/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/item/ItemStackImpl.java +++ b/v1_16_R3/src/main/java/net/azisaba/loreeditor/v1_16_R3/item/ItemStackImpl.java @@ -49,4 +49,9 @@ public void setTag(@Nullable CompoundTag tag) { public int getCount() { return handle.getCount(); } + + @Override + public @NotNull ItemStack copy() { + return new ItemStackImpl(handle.cloneItemStack()); + } } diff --git a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/item/ItemStackImpl.java b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/item/ItemStackImpl.java index 76b1516..605a6a0 100644 --- a/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/item/ItemStackImpl.java +++ b/v1_19_R3/src/main/java/net/azisaba/loreeditor/v1_19_R3/item/ItemStackImpl.java @@ -49,4 +49,9 @@ public void setTag(@Nullable CompoundTag tag) { public int getCount() { return handle.K(); // getCount (probably) } + + @Override + public @NotNull ItemStack copy() { + return new ItemStackImpl(handle.o()); + } } diff --git a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/item/ItemStackImpl.java b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/item/ItemStackImpl.java index cd9b20d..f16881c 100644 --- a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/item/ItemStackImpl.java +++ b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/item/ItemStackImpl.java @@ -48,4 +48,9 @@ public void setTag(@Nullable CompoundTag tag) { public int getCount() { return handle.K(); // getCount (probably) } + + @Override + public @NotNull ItemStack copy() { + return new ItemStackImpl(handle.p()); + } } diff --git a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/ServerCommonPacketListenerImpl.java b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/ServerCommonPacketListenerImpl.java index a91191b..bb25080 100644 --- a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/ServerCommonPacketListenerImpl.java +++ b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/network/ServerCommonPacketListenerImpl.java @@ -2,8 +2,6 @@ import net.azisaba.loreeditor.api.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; -import xyz.acrylicstyle.util.reflector.CastTo; -import xyz.acrylicstyle.util.reflector.FieldGetter; import xyz.acrylicstyle.util.reflector.Reflector; import xyz.acrylicstyle.util.reflector.ReflectorHandler; diff --git a/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/util/ChatUtilImpl.java b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/util/ChatUtilImpl.java new file mode 100644 index 0000000..9cf4d9d --- /dev/null +++ b/v1_20/src/main/java/net/azisaba/loreeditor/v1_20/util/ChatUtilImpl.java @@ -0,0 +1,17 @@ +package net.azisaba.loreeditor.v1_20.util; + +import net.azisaba.loreeditor.common.util.ChatUtil; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.jetbrains.annotations.NotNull; + +public class ChatUtilImpl implements ChatUtil { + @Override + public @NotNull TextComponent createComponentWithHoverWithSuggestCommand(@NotNull String message, @NotNull String hoverText, @NotNull String suggestCommand) { + TextComponent component = new TextComponent(message); + component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hoverText))); + component.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestCommand)); + return component; + } +} diff --git a/v1_21_1/build.gradle.kts b/v1_21_1/build.gradle.kts new file mode 100644 index 0000000..3549db8 --- /dev/null +++ b/v1_21_1/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +repositories { + mavenLocal() +} + +java.toolchain.languageVersion.set(JavaLanguageVersion.of(21)) + +dependencies { + compileOnly(project(":common")) + compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT") +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ChatModifierImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ChatModifierImpl.java new file mode 100644 index 0000000..7abf2b9 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ChatModifierImpl.java @@ -0,0 +1,31 @@ +package net.azisaba.loreeditor.v1_21_1.chat; + +import net.azisaba.loreeditor.common.chat.ChatModifier; +import net.azisaba.loreeditor.common.util.Reflected; +import net.minecraft.network.chat.Style; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public record ChatModifierImpl(Style handle) implements ChatModifier { + public ChatModifierImpl { + Objects.requireNonNull(handle, "handle"); + } + + @Contract(value = "_ -> new", pure = true) + @Reflected + public static @NotNull ChatModifierImpl getInstance(@NotNull Object handle) { + return new ChatModifierImpl((Style) handle); + } + + @Override + public @NotNull Style handle() { + return handle; + } + + @Override + public @NotNull ChatModifier setItalic(boolean italic) { + return getInstance(handle.withItalic(italic)); // setItalic + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java new file mode 100644 index 0000000..62e88d1 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/chat/ComponentImpl.java @@ -0,0 +1,72 @@ +package net.azisaba.loreeditor.v1_21_1.chat; + +import net.azisaba.loreeditor.common.chat.ChatModifier; +import net.azisaba.loreeditor.common.chat.Component; +import net.azisaba.loreeditor.common.util.Reflected; +import net.minecraft.core.RegistryAccess; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; +import java.util.function.UnaryOperator; + +@Reflected +public record ComponentImpl(MutableComponent handle) implements Component { + public ComponentImpl(@Nullable net.minecraft.network.chat.Component handle) { + this(handle == null ? null : handle.copy()); + } + + @Contract(value = "_ -> new", pure = true) + @Reflected + public static @NotNull ComponentImpl getInstance(@Nullable Object component) { + return new ComponentImpl((net.minecraft.network.chat.Component) component); + } + + @Override + public @NotNull MutableComponent handle() { + return Objects.requireNonNull(handle, "cannot reference handle in static context"); + } + + public static MutableComponent deserializeFromJson(@NotNull String input) { + RegistryAccess registries = ((CraftServer) Bukkit.getServer()).getServer().registryAccess(); + return net.minecraft.network.chat.Component.Serializer.fromJson(input, registries); + } + + public static String serializeToJson(@NotNull MutableComponent component) { + RegistryAccess registries = ((CraftServer) Bukkit.getServer()).getServer().registryAccess(); + return net.minecraft.network.chat.Component.Serializer.toJson(component, registries); + } + + @Override + public @Nullable Component deserialize(@NotNull String input) { + return getInstance(deserializeFromJson(input)); + } + + @Override + public @NotNull String serialize(@NotNull Component component) { + return serializeToJson(((ComponentImpl) component).handle()); + } + + @Override + public @NotNull List getSiblings() { + return handle().getSiblings(); + } + + @Override + public void addSiblingText(@NotNull String text) { + handle().append(deserializeFromJson(text)); + } + + @Override + public @NotNull Component modifyStyle(@NotNull UnaryOperator action) { + ChatModifier cm = new ChatModifierImpl(handle().getStyle()); + Style newChatModifier = ((ChatModifierImpl) action.apply(cm)).handle(); + return getInstance(handle().setStyle(newChatModifier)); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/CraftPlayer.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/CraftPlayer.java new file mode 100644 index 0000000..0a3a29a --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/CraftPlayer.java @@ -0,0 +1,21 @@ +package net.azisaba.loreeditor.v1_21_1.entity; + +import net.azisaba.loreeditor.api.util.ReflectionUtil; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import xyz.acrylicstyle.util.reflector.CastTo; +import xyz.acrylicstyle.util.reflector.Reflector; +import xyz.acrylicstyle.util.reflector.ReflectorHandler; + +import java.util.Objects; + +public interface CraftPlayer { + static @NotNull CraftPlayer getInstance(@NotNull Player player) { + return Reflector.newReflector(null, CraftPlayer.class, + new ReflectorHandler(ReflectionUtil.getOBCClass("entity.CraftPlayer"), Objects.requireNonNull(player, "player"))); + } + + @NotNull + @CastTo(EntityPlayer.class) + EntityPlayer getHandle(); +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/EntityPlayer.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/EntityPlayer.java new file mode 100644 index 0000000..de0ff5d --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/entity/EntityPlayer.java @@ -0,0 +1,22 @@ +package net.azisaba.loreeditor.v1_21_1.entity; + +import net.azisaba.loreeditor.api.util.ReflectionUtil; +import net.azisaba.loreeditor.v1_21_1.network.ServerCommonPacketListenerImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.acrylicstyle.util.reflector.CastTo; +import xyz.acrylicstyle.util.reflector.FieldGetter; +import xyz.acrylicstyle.util.reflector.Reflector; +import xyz.acrylicstyle.util.reflector.ReflectorHandler; + +public interface EntityPlayer { + static @NotNull EntityPlayer getInstance(@Nullable Object o) { + return Reflector.newReflector(null, EntityPlayer.class, + new ReflectorHandler(ReflectionUtil.getNMSClass("net.minecraft.server.level.EntityPlayer"), o)); + } + + @NotNull + @CastTo(value = ServerCommonPacketListenerImpl.class, createInstance = true) + @FieldGetter("connection") + ServerCommonPacketListenerImpl getPlayerConnection(); +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/CraftItemStackImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/CraftItemStackImpl.java new file mode 100644 index 0000000..1dfb662 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/CraftItemStackImpl.java @@ -0,0 +1,27 @@ +package net.azisaba.loreeditor.v1_21_1.item; + +import net.azisaba.loreeditor.api.item.CraftItemStack; +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.common.util.Reflected; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CraftItemStackImpl implements CraftItemStack { + @Contract(value = "_ -> new", pure = true) + @Reflected + public static @NotNull CraftItemStackImpl getInstance(@Nullable Object item) { + return new CraftItemStackImpl(); + } + + @Override + public @Nullable ItemStack asNMSCopy(org.bukkit.inventory.@Nullable ItemStack item) { + return new ItemStackImpl(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item)); + } + + @NotNull + @Override + public org.bukkit.inventory.ItemStack asCraftMirror(@NotNull ItemStack item) { + return org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(((ItemStackImpl) item).handle()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java new file mode 100644 index 0000000..2764a90 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/ItemStackImpl.java @@ -0,0 +1,91 @@ +package net.azisaba.loreeditor.v1_21_1.item; + +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.api.item.tag.CompoundTag; +import net.azisaba.loreeditor.api.item.tag.ListTag; +import net.azisaba.loreeditor.common.util.Reflected; +import net.azisaba.loreeditor.v1_21_1.chat.ComponentImpl; +import net.azisaba.loreeditor.v1_21_1.item.tag.CompoundTagImpl; +import net.azisaba.loreeditor.v1_21_1.item.tag.ListTagImpl; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ItemLore; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public record ItemStackImpl(net.minecraft.world.item.ItemStack handle) implements ItemStack { + public ItemStackImpl(net.minecraft.world.item.ItemStack handle) { + this.handle = Objects.requireNonNull(handle, "handle"); + } + + @Override + public @NotNull net.minecraft.world.item.ItemStack handle() { + return handle; + } + + @Contract("_ -> new") + @Reflected + public static @NotNull ItemStackImpl getInstance(@NotNull Object item) { + Objects.requireNonNull(item, "item"); + return new ItemStackImpl((net.minecraft.world.item.ItemStack) item); + } + + @SuppressWarnings("deprecation") + @Override + public @NotNull CompoundTag getOrCreateTag() { + CustomData customData = handle.get(DataComponents.CUSTOM_DATA); + if (customData == null) { + customData = CustomData.of(new net.minecraft.nbt.CompoundTag()); + handle.set(DataComponents.CUSTOM_DATA, customData); + } + return new CompoundTagImpl(customData.getUnsafe()); + } + + @SuppressWarnings("deprecation") + @Override + public @Nullable CompoundTag getTag() { + CustomData customData = handle.get(DataComponents.CUSTOM_DATA); + if (customData == null) { + return null; + } + return new CompoundTagImpl(customData.getUnsafe()); + } + + @Override + public void setTag(@Nullable CompoundTag tag) { + handle.set(DataComponents.CUSTOM_DATA, tag == null ? null : CustomData.of(((CompoundTagImpl) tag).getHandle())); + if (tag != null) { + if (!tag.hasKeyOfType("display", 10)) { + return; + } + CompoundTag displayTag = tag.getCompound("display"); + ListTag listTag = displayTag.getList("Lore", 8); + if (listTag.size() > 0) { + List lore = + ((ListTagImpl) listTag).getHandle() + .stream() + .map(Tag::getAsString) + .map(ComponentImpl::deserializeFromJson) + .collect(Collectors.toUnmodifiableList()); + handle.set(DataComponents.LORE, new ItemLore(lore)); + } + } + } + + @Override + public int getCount() { + return handle.getCount(); + } + + @Override + public @NotNull ItemStack copy() { + return new ItemStackImpl(handle.copy()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/CompoundTagImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/CompoundTagImpl.java new file mode 100644 index 0000000..c7d5a42 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/CompoundTagImpl.java @@ -0,0 +1,94 @@ +package net.azisaba.loreeditor.v1_21_1.item.tag; + +import net.azisaba.loreeditor.api.item.tag.CompoundTag; +import net.azisaba.loreeditor.api.item.tag.ListTag; +import net.azisaba.loreeditor.api.item.tag.Tag; +import net.azisaba.loreeditor.common.util.Reflected; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CompoundTagImpl extends TagImpl implements CompoundTag { + public CompoundTagImpl(@NotNull net.minecraft.nbt.CompoundTag handle) { + super(handle); + } + + @Contract("_ -> new") + @Reflected + public static @NotNull CompoundTagImpl getInstance(@Nullable Object tag) { + if (tag == null) { + return new CompoundTagImpl(new net.minecraft.nbt.CompoundTag()); + } + return new CompoundTagImpl((net.minecraft.nbt.CompoundTag) tag); + } + + @Override + public @NotNull CompoundTag constructor() { + return new CompoundTagImpl(new net.minecraft.nbt.CompoundTag()); + } + + @Override + public int size() { + return getHandle().size(); + } + + @Override + public boolean hasKeyOfType(@NotNull String key, int type) { + return getHandle().contains(key, type); + } + + @Override + public void remove(@NotNull String key) { + getHandle().remove(key); + } + + @Override + public boolean getBoolean(@NotNull String key) { + return getHandle().getBoolean(key); + } + + @Override + public int getInt(@NotNull String key) { + return getHandle().getInt(key); + } + + @Override + public @NotNull String getString(@NotNull String key) { + return getHandle().getString(key); + } + + @Override + public @NotNull CompoundTag getCompound(@NotNull String key) { + return new CompoundTagImpl(getHandle().getCompound(key)); + } + + @Override + public @NotNull ListTag getList(@NotNull String key, int type) { + return new ListTagImpl(getHandle().getList(key, type)); + } + + @Override + public void setString(@NotNull String key, @NotNull String value) { + getHandle().putString(key, value); + } + + @Override + public void setBoolean(@NotNull String key, boolean value) { + getHandle().putBoolean(key, value); + } + + @Override + public void setInt(@NotNull String key, int value) { + getHandle().putInt(key, value); + } + + @Override + public void set(@NotNull String key, @NotNull Tag value) { + getHandle().put(key, ((TagImpl) value).getHandle()); + } + + @Override + public @Nullable Tag get(@NotNull String key) { + return TagImpl.toTag(getHandle().get(key)); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/ListTagImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/ListTagImpl.java new file mode 100644 index 0000000..7d8de03 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/ListTagImpl.java @@ -0,0 +1,43 @@ +package net.azisaba.loreeditor.v1_21_1.item.tag; + +import net.azisaba.loreeditor.api.item.tag.ListTag; +import net.azisaba.loreeditor.api.item.tag.Tag; +import net.azisaba.loreeditor.common.util.Reflected; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ListTagImpl extends TagImpl implements ListTag { + public ListTagImpl(net.minecraft.nbt.ListTag handle) { + super(handle); + } + + @Contract("_ -> new") + @Reflected + public static @NotNull ListTagImpl getInstance(@Nullable Object tag) { + if (tag == null) { + return new ListTagImpl(new net.minecraft.nbt.ListTag()); + } + return new ListTagImpl((net.minecraft.nbt.ListTag) tag); + } + + @Override + public @NotNull ListTag constructor() { + return new ListTagImpl(new net.minecraft.nbt.ListTag()); + } + + @Override + public int size() { + return getHandle().size(); + } + + @Override + public @NotNull Tag removeAt(int index) { + return TagImpl.toTag(getHandle().remove(index)); + } + + @Override + public void add(int index, @NotNull Tag tag) { + getHandle().add(index, ((TagImpl) tag).getHandle()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/StringTagImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/StringTagImpl.java new file mode 100644 index 0000000..62d53c3 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/StringTagImpl.java @@ -0,0 +1,25 @@ +package net.azisaba.loreeditor.v1_21_1.item.tag; + +import net.azisaba.loreeditor.api.item.tag.StringTag; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class StringTagImpl extends TagImpl implements StringTag { + public StringTagImpl(@NotNull net.minecraft.nbt.StringTag handle) { + super(handle); + } + + @Contract("_ -> new") + public static @NotNull StringTagImpl getInstance(@Nullable Object handle) { + if (handle == null) { + return new StringTagImpl(net.minecraft.nbt.StringTag.valueOf("")); + } + return new StringTagImpl((net.minecraft.nbt.StringTag) handle); + } + + @Override + public @NotNull StringTag valueOf(@NotNull String text) { + return getInstance(net.minecraft.nbt.StringTag.valueOf(text)); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/TagImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/TagImpl.java new file mode 100644 index 0000000..8edb971 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/item/tag/TagImpl.java @@ -0,0 +1,61 @@ +package net.azisaba.loreeditor.v1_21_1.item.tag; + +import net.azisaba.loreeditor.api.item.tag.Tag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class TagImpl implements Tag { + private final T handle; + + public TagImpl(@NotNull T handle) { + this.handle = Objects.requireNonNull(handle, "handle"); + } + + public @NotNull T getHandle() { + return Objects.requireNonNull(handle); + } + + @Contract("null -> null; !null -> !null") + public static Tag toTag(@Nullable net.minecraft.nbt.Tag handle) { + return switch (handle) { + case null -> null; + case CompoundTag compoundTag -> new CompoundTagImpl(compoundTag); + case ListTag tags -> new ListTagImpl(tags); + case StringTag stringTag -> new StringTagImpl(stringTag); + default -> new TagImpl<>(handle); + }; + } + + @Override + public @NotNull String asString() { + return handle.getAsString(); // asString + } + + @Override + public String toString() { + return handle.toString(); + } + + @Override + public int hashCode() { + return handle.hashCode(); + } + + @Contract(value = "null -> false", pure = true) + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Tag) && !(obj instanceof net.minecraft.nbt.Tag)) { + return false; + } + if (obj instanceof Tag) { + obj = ((TagImpl) obj).getHandle(); + } + return handle.equals(obj); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/IServerCommonPacketListenerImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/IServerCommonPacketListenerImpl.java new file mode 100644 index 0000000..62073de --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/IServerCommonPacketListenerImpl.java @@ -0,0 +1,12 @@ +package net.azisaba.loreeditor.v1_21_1.network; + +import org.jetbrains.annotations.NotNull; +import xyz.acrylicstyle.util.reflector.CastTo; +import xyz.acrylicstyle.util.reflector.FieldGetter; + +public interface IServerCommonPacketListenerImpl { + @NotNull + @CastTo(NetworkManager.class) + @FieldGetter("connection") + NetworkManager getNetworkManager(); +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/NetworkManager.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/NetworkManager.java new file mode 100644 index 0000000..a26854d --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/NetworkManager.java @@ -0,0 +1,11 @@ +package net.azisaba.loreeditor.v1_21_1.network; + +import io.netty.channel.Channel; +import org.jetbrains.annotations.NotNull; +import xyz.acrylicstyle.util.reflector.FieldGetter; + +public interface NetworkManager { + @NotNull + @FieldGetter("channel") + Channel getChannel(); +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/ServerCommonPacketListenerImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/ServerCommonPacketListenerImpl.java new file mode 100644 index 0000000..4920c82 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/ServerCommonPacketListenerImpl.java @@ -0,0 +1,19 @@ +package net.azisaba.loreeditor.v1_21_1.network; + +import net.azisaba.loreeditor.api.util.ReflectionUtil; +import org.jetbrains.annotations.NotNull; +import xyz.acrylicstyle.util.reflector.Reflector; +import xyz.acrylicstyle.util.reflector.ReflectorHandler; + +public class ServerCommonPacketListenerImpl { + private final IServerCommonPacketListenerImpl reflector; + + public ServerCommonPacketListenerImpl(Object o) { + this.reflector = Reflector.newReflector(null, IServerCommonPacketListenerImpl.class, + new ReflectorHandler(ReflectionUtil.getNMSClass("net.minecraft.server.network.ServerCommonPacketListenerImpl"), o)); + } + + public @NotNull NetworkManager getNetworkManager() { + return reflector.getNetworkManager(); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java new file mode 100644 index 0000000..02f58b2 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundSetSlotImpl.java @@ -0,0 +1,31 @@ +package net.azisaba.loreeditor.v1_21_1.network.packet; + +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.common.network.packet.ClientboundSetSlot; +import net.azisaba.loreeditor.v1_21_1.item.ItemStackImpl; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ClientboundSetSlotImpl implements ClientboundSetSlot { + private final ClientboundContainerSetSlotPacket handle; + + public ClientboundSetSlotImpl(ClientboundContainerSetSlotPacket handle) { + this.handle = handle; + } + + @Contract(value = "_ -> new", pure = true) + public static @NotNull ClientboundSetSlotImpl getInstance(@NotNull Object handle) { + return new ClientboundSetSlotImpl((ClientboundContainerSetSlotPacket) handle); + } + + public @NotNull ClientboundContainerSetSlotPacket getHandle() { + return handle; + } + + @Override + public @Nullable ItemStack getItem() { + return ItemStackImpl.getInstance(handle.getItem()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java new file mode 100644 index 0000000..4036b80 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ClientboundWindowItemsImpl.java @@ -0,0 +1,37 @@ +package net.azisaba.loreeditor.v1_21_1.network.packet; + +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.common.network.packet.ClientboundWindowItems; +import net.azisaba.loreeditor.v1_21_1.item.ItemStackImpl; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class ClientboundWindowItemsImpl implements ClientboundWindowItems { + private final ClientboundContainerSetContentPacket handle; + + public ClientboundWindowItemsImpl(@NotNull ClientboundContainerSetContentPacket handle) { + this.handle = handle; + } + + @Contract(value = "_ -> new", pure = true) + public static @NotNull ClientboundWindowItemsImpl getInstance(Object handle) { + return new ClientboundWindowItemsImpl((ClientboundContainerSetContentPacket) handle); + } + + public @NotNull ClientboundContainerSetContentPacket getHandle() { + return handle; + } + + @Override + public @NotNull List getItems() { + List items = new ArrayList<>(); + for (var o : handle.getItems()) { + items.add(ItemStackImpl.getInstance(o)); + } + return items; + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundClickContainerSlotImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundClickContainerSlotImpl.java new file mode 100644 index 0000000..8178acd --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundClickContainerSlotImpl.java @@ -0,0 +1,29 @@ +package net.azisaba.loreeditor.v1_21_1.network.packet; + +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.common.network.packet.ServerboundClickContainerSlot; +import net.azisaba.loreeditor.v1_21_1.item.ItemStackImpl; +import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class ServerboundClickContainerSlotImpl implements ServerboundClickContainerSlot { + private final ServerboundContainerClickPacket handle; + + public ServerboundClickContainerSlotImpl(@NotNull ServerboundContainerClickPacket handle) { + this.handle = Objects.requireNonNull(handle, "handle"); + } + + @Contract(value = "_ -> new", pure = true) + public static @NotNull ServerboundClickContainerSlotImpl getInstance(@NotNull Object handle) { + return new ServerboundClickContainerSlotImpl((ServerboundContainerClickPacket) handle); + } + + @Override + public @Nullable ItemStack getItem() { + return ItemStackImpl.getInstance(handle.getCarriedItem()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundSetCreativeSlotImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundSetCreativeSlotImpl.java new file mode 100644 index 0000000..e37d4a5 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/network/packet/ServerboundSetCreativeSlotImpl.java @@ -0,0 +1,27 @@ +package net.azisaba.loreeditor.v1_21_1.network.packet; + +import net.azisaba.loreeditor.api.item.ItemStack; +import net.azisaba.loreeditor.common.network.packet.ServerboundSetCreativeSlot; +import net.azisaba.loreeditor.v1_21_1.item.ItemStackImpl; +import net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ServerboundSetCreativeSlotImpl implements ServerboundSetCreativeSlot { + private final ServerboundSetCreativeModeSlotPacket handle; + + public ServerboundSetCreativeSlotImpl(ServerboundSetCreativeModeSlotPacket handle) { + this.handle = handle; + } + + @Contract(value = "_ -> new", pure = true) + public static @NotNull ServerboundSetCreativeSlotImpl getInstance(Object handle) { + return new ServerboundSetCreativeSlotImpl((ServerboundSetCreativeModeSlotPacket) handle); + } + + @Override + public @Nullable ItemStack getItem() { + return ItemStackImpl.getInstance(handle.itemStack()); + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChannelUtilImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChannelUtilImpl.java new file mode 100644 index 0000000..28c9773 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChannelUtilImpl.java @@ -0,0 +1,57 @@ +package net.azisaba.loreeditor.v1_21_1.util; + +import io.netty.channel.ChannelPipeline; +import net.azisaba.loreeditor.common.network.PacketPreHandler; +import net.azisaba.loreeditor.common.util.ChannelUtil; +import net.azisaba.loreeditor.v1_21_1.entity.CraftPlayer; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.NoSuchElementException; + +public class ChannelUtilImpl implements ChannelUtil { + @Override + public void inject(@NotNull Plugin plugin, @NotNull Player player) { + try { + CraftPlayer.getInstance(player) + .getHandle() + .getPlayerConnection() + .getNetworkManager() + .getChannel() + .pipeline() + .addBefore("packet_handler", "loreeditor", new PacketPreHandler(plugin, player)); + plugin.getLogger().info("Injected packet handler for " + player.getName()); + } catch (NoSuchElementException e) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!player.isOnline()) return; + try { + CraftPlayer.getInstance(player) + .getHandle() + .getPlayerConnection() + .getNetworkManager() + .getChannel() + .pipeline() + .addBefore("packet_handler", "loreeditor", new PacketPreHandler(plugin, player)); + plugin.getLogger().info("Injected packet handler for " + player.getName()); + } catch (NoSuchElementException ignore) { + plugin.getLogger().warning("Failed to inject packet handler to " + player.getName()); + } + }, 10); + } + } + + @Override + public void eject(@NotNull Player player) { + try { + ChannelPipeline pipeline = CraftPlayer.getInstance(player) + .getHandle() + .getPlayerConnection() + .getNetworkManager() + .getChannel() + .pipeline(); + if (pipeline.get("loreeditor") != null) pipeline.remove("loreeditor"); + } catch (RuntimeException ignore) {} + } +} diff --git a/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChatUtilImpl.java b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChatUtilImpl.java new file mode 100644 index 0000000..e71f0f6 --- /dev/null +++ b/v1_21_1/src/main/java/net/azisaba/loreeditor/v1_21_1/util/ChatUtilImpl.java @@ -0,0 +1,17 @@ +package net.azisaba.loreeditor.v1_21_1.util; + +import net.azisaba.loreeditor.common.util.ChatUtil; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.jetbrains.annotations.NotNull; + +public class ChatUtilImpl implements ChatUtil { + @Override + public @NotNull TextComponent createComponentWithHoverWithSuggestCommand(@NotNull String message, @NotNull String hoverText, @NotNull String suggestCommand) { + TextComponent component = new TextComponent(message); + component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hoverText))); + component.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestCommand)); + return component; + } +}