WesJD / AnvilGUI

Capture user input in Minecraft through an anvil GUI in under 20 lines of code
MIT License
481 stars 114 forks source link

NoSuchMethodError on latest Spigot builds for Minecraft 1.21 #342

Closed 0dinD closed 2 months ago

0dinD commented 2 months ago

On the latest builds of Spigot for Minecraft 1.21, opening an anvil GUI doesn't work and causes a NoSuchMethodError to be thrown. The breakage has occurred due to CraftBukkit@9c3bd439054771ce89ed69b8f74f5eba2ff4fc51 which changes the return type of net.minecraft.world.inventory.ContainerAnvil#getBukkitInventory() from CraftInventoryView to CraftAnvilView and therefore breaks the ABI compatibility for AnvilGUI (even if the types would otherwise be compatible).

All builds of CraftBukkit, Spigot and derivatives are affected, the latest builds for Minecraft 1.21. Paper is not yet affected because they haven't pulled the latest Spigot patches yet, but I would assume that the problem will also arise on Paper once they do, probably pretty soon. This is not a bug or problem with CraftBukkit/Spigot, just something that broke because, ya know, NMS is not an API and may break at any point.

Here is a full stack trace which I get when opening an anvil GUI on the latest build of Spigot:

[18:14:39] [Server thread/ERROR]: Could not pass event InventoryClickEvent to UhcCore v1.20.11-SNAPSHOT-f3f716834d893cd5d191e22cf7f00882e2c8d6c4
org.bukkit.event.EventException: null
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:310) ~[spigot-api-1.21-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-api-1.21-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:601) ~[spigot-api-1.21-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:588) ~[spigot-api-1.21-R0.1-SNAPSHOT.jar:?]
        at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:2763) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.network.protocol.game.PacketPlayInWindowClick.a(SourceFile:71) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.network.protocol.game.PacketPlayInWindowClick.a(SourceFile:14) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.network.protocol.PlayerConnectionUtils.lambda$ensureRunningOnSameThread$0(PlayerConnectionUtils.java:35) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.TickTask.run(SourceFile:18) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.util.thread.IAsyncTaskHandler.d(SourceFile:162) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.d(SourceFile:23) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1270) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.d(MinecraftServer.java:203) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.util.thread.IAsyncTaskHandler.B(SourceFile:136) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.bv(MinecraftServer.java:1249) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.B(MinecraftServer.java:1242) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.util.thread.IAsyncTaskHandler.b(SourceFile:145) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1207) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.v_(MinecraftServer.java:1214) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.y(MinecraftServer.java:1078) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:318) ~[spigot-1.21-R0.1-SNAPSHOT.jar:4286-Spigot-fb8fb72-00fc9fb]
        at java.base/java.lang.Thread.run(Thread.java:1583) [?:?]
Caused by: java.lang.NoSuchMethodError: 'org.bukkit.craftbukkit.v1_21_R1.inventory.CraftInventoryView com.gmail.val59000mc.anvilgui.version.Wrapper1_21_R1$AnvilContainer.getBukkitView()'
        at com.gmail.val59000mc.anvilgui.version.Wrapper1_21_R1$AnvilContainer.getBukkitInventory(Wrapper1_21_R1.java:149) ~[?:?]
        at com.gmail.val59000mc.anvilgui.AnvilGUI.openInventory(AnvilGUI.java:212) ~[?:?]
        at com.gmail.val59000mc.anvilgui.AnvilGUI.access$1000(AnvilGUI.java:38) ~[?:?]
        at com.gmail.val59000mc.anvilgui.AnvilGUI$Builder.open(AnvilGUI.java:712) ~[?:?]
        at com.gmail.val59000mc.listeners.ItemsListener.openTeamRenameGUI(ItemsListener.java:401) ~[?:?]
        at com.gmail.val59000mc.listeners.ItemsListener.handleGameItemInteract(ItemsListener.java:301) ~[?:?]
        at com.gmail.val59000mc.listeners.ItemsListener.onClickInInventory(ItemsListener.java:138) ~[?:?]
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
        at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot-api-1.21-R0.1-SNAPSHOT.jar:?]
        ... 21 more

Fortunately, this looks pretty easy to work around for now, because we could compile against net.minecraft.world.inventory.Container#getBukkitInventory() instead, which hasn't had an ABI breakage. If we do this, AnvilGUI will still be compatible with all server versions, both before and after the problematic CraftBukkit commit.

0dinD commented 2 months ago

On a somewhat related note (but kind of unrelated to this issue), I had a look at the changes in the above mentioned CraftBukkit commit and it seems like while it doesn't really change anything for us right now, it's a good cleanup of the current API which seems to be in preparation for some more exciting additions that might land in the future. I haven't looked at it in detail, but it seems to me like CraftBukkit PR 1458 (you need stash access to view it) is the motivation for the API cleanup, and I think there's a possibility that it would allow us to implement AnvilGUI using just the Bukkit API. Maybe I shouldn't get my hopes too high just yet, but it would definitely be a welcome surprise if we could finally put an end to years of maintaining NMS wrappers! Fingers crossed :slightly_smiling_face:


After looking into it some more, this looks very promising! The author of these CraftBukkit patches made a post about the new InventoryView APIs on the Spigot forums, and has more or less confirmed that proper anvil menus are one of the goals of their contributions to CraftBukkit, judging by this message in the PaperMC Discord server. Also, I found an old post of theirs which goes into great detail about creating anvil GUIs specifically, using NMS. I am seeing many similarities between that code and the CraftBukkit contributions, so I'm sure that was the inspiration behind it all. Fingers crossed that the last parts needed for the complete Anvil API will be merged at some point in the future, and that AnvilGUI can make use of that effort in order to remove all or at least most of the version wrapper NMS code for future game versions!