MarkusBordihn / BOs-Easy-NPC

Create easily NPC for your world or for your mod.
Other
20 stars 8 forks source link

[Bug] Client disconnect with open trading screen on dialog button action #286

Closed Yoshun closed 3 months ago

Yoshun commented 3 months ago

Minecraft and Mod version 🐞 Minecraft 1.20.1, Fabric 0.5.11, EasyNPC 5.5.1

Describe the bug 🐞 I have an NPC to trade items. I set a "Yes/No" dialog to display text explaining the items the NPC is trading. The "No" button closes the dialog without opening the trade interface, no problem there. The problem is that clicking the "Yes" button disconnects the player with the error below in the server console.

To Reproduce ⚙️

  1. Create an NPC and define some trades
  2. Create a "Yes/No" dialog
  3. On "Yes" action, set "OPEN_TRADING_SCREEN"
  4. Click on "Yes" button after interact with the NPC

Debugging 🛠️ Here is the error :

[10:13:07] [Netty Epoll Server IO #0/ERROR]: Encountered exception while handling in channel with name "easy_npc:dialog_button_action"
java.lang.NullPointerException: Cannot invoke "net.minecraft.class_1916.isEmpty()" because "$$4" is null
        at net.minecraft.class_1915.method_17449(class_1915.java:44) ~[server-intermediary.jar:?]
        at de.markusbordihn.easynpc.entity.easynpc.data.TradingData.openTradingScreen(TradingData.java:501) ~[easy_npc-fabric-1.20.1-5.5.1.jar:?]
        at de.markusbordihn.easynpc.entity.easynpc.handlers.ActionHandler.executeAction(ActionHandler.java:337) ~[easy_npc-fabric-1.20.1-5.5.1.jar:?]
        at de.markusbordihn.easynpc.entity.easynpc.handlers.ActionHandler.executeActions(ActionHandler.java:289) ~[easy_npc-fabric-1.20.1-5.5.1.jar:?]
        at de.markusbordihn.easynpc.network.message.server.ExecuteDialogButtonActionMessage.handleServer(ExecuteDialogButtonActionMessage.java:125) ~[easy_npc-fabric-1.20.1-5.5.1.jar:?]
        at de.markusbordihn.easynpc.network.NetworkHandler.lambda$registerServerNetworkMessageHandler$1(NetworkHandler.java:93) ~[easy_npc-fabric-1.20.1-5.5.1.jar:?]
        at net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon.receive(ServerPlayNetworkAddon.java:85) ~[fabric-networking-api-v1-1.3.11+1802ada577-cf20906c7ecece00.jar:?]
        at net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon.receive(ServerPlayNetworkAddon.java:39) ~[fabric-networking-api-v1-1.3.11+1802ada577-cf20906c7ecece00.jar:?]
        at net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon.handle(AbstractChanneledNetworkAddon.java:101) ~[fabric-networking-api-v1-1.3.11+1802ada577-cf20906c7ecece00.jar:?]
        at net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon.handle(ServerPlayNetworkAddon.java:80) ~[fabric-networking-api-v1-1.3.11+1802ada577-cf20906c7ecece00.jar:?]
        at net.minecraft.class_3244.handler$zoi000$fabric-networking-api-v1$handleCustomPayloadReceivedAsync(class_3244.java:2000) ~[server-intermediary.jar:?]
        at net.minecraft.class_3244.method_12075(class_3244.java) ~[server-intermediary.jar:?]
        at net.minecraft.class_2817.method_12199(class_2817.java:38) ~[server-intermediary.jar:?]
        at net.minecraft.class_2817.method_11054(class_2817.java:7) ~[server-intermediary.jar:?]
        at net.minecraft.class_2535.method_10759(class_2535.java:175) ~[server-intermediary.jar:?]
        at net.minecraft.class_2535.method_10770(class_2535.java:160) ~[server-intermediary.jar:?]
        at net.minecraft.class_2535.channelRead0(class_2535.java:52) ~[server-intermediary.jar:?]
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:336) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:308) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:336) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:308) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:336) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:308) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286) ~[netty-handler-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.82.Final.jar:?]
        at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) ~[netty-transport-classes-epoll-4.1.82.Final.jar:?]
        at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:499) ~[netty-transport-classes-epoll-4.1.82.Final.jar:?]
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:397) ~[netty-transport-classes-epoll-4.1.82.Final.jar:?]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.82.Final.jar:?]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.82.Final.jar:?]
        at java.lang.Thread.run(Thread.java:840) ~[?:?]
[10:13:07] [Server thread/INFO]: Yoshun lost connection: Internal Exception: java.lang.NullPointerException: Cannot invoke "net.minecraft.class_1916.isEmpty()" because "$$4" is null

Thanks !

MarkusBordihn commented 3 months ago

Thank you for your report. In version 5.5.1, the trading data were adjusted as noted in the changelog: "Note: Due to changes and fixes in the trading data, some trading data will be reset. Please edit the trades again, and they will be saved in the new format."

To ensure your trades are stored correctly in the latest version, please make a minor adjustment—such as moving an item out and then back in.

I will also implement a check to disable the "Open Trading Screen" option when invalid trading data is detected.

Yoshun commented 3 months ago

Hi, Thanks for the response! I read the changelogs and saw this information. I had updated the trades by removing all the items and putting them all back to make sure it was up to date in the new format before posting this issue.

MarkusBordihn commented 3 months ago

Please examine the affected NPC and press "F3 + i" to copy the entity data to your clipboard. Share this data in the bug report so that I can investigate the issue and the crash in more detail.

I attempted to reproduce the issue with a new NPC but was unable to do so. It might be an isolated problem with the existing NPCs.

Yoshun commented 3 months ago

Entity data : /summon easy_npc:humanoid -425.50 66.00 -495.50 {ActionData: {ActionEventSet: {}, ActionPermissionLevel: 4}, DeathTime: 0s, LeftHanded: 0b, OnGround: 1b, AbsorptionAmount: 0.0f, SkinData: {Skin: "", SkinUUID: [I; 1379223705, 2080193635, -2060185035, -1442307105], SkinURL: "https://pokemine.fr/images/skins/brandon.png", SkinType: "INSECURE_REMOTE_URL"}, Attributes: [{Name: "minecraft:generic.attack_damage", Base: 1.0d}, {Name: "minecraft:generic.knockback_resistance", Base: 0.0d}, {Name: "minecraft:generic.follow_range", Modifiers: [{Amount: 0.008406636896658354d, UUID: [I; 568897395, -1114488355, -1580054262, 1501830831], Name: "Random spawn bonus", Operation: 1}], Base: 32.0d}, {Name: "minecraft:generic.movement_speed", Base: 0.6000000238418579d}, {Name: "minecraft:generic.attack_knockback", Base: 0.0d}], Invulnerable: 1b, Brain: {memories: {}}, RenderData: {}, Navigation: {Home: {Y: 66, Z: -496, X: -426}}, Owner: [I; 1428444344, -1768468530, -1795086739, -1767964366], "puzzleslib:spawn_type": "SPAWN_EGG", Rotation: [133.46571f, 1.0133115f], HurtByTimestamp: 0, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], HandDropChances: [0.085f, 0.085f], EntityAttribute: {CanCloseDoor: 0b, Freefall: 0b, IsAttackable: 0b, CanUseNetherPortal: 0b, CanPassDoor: 0b, PushEntities: 0b, CanFloat: 0b, CanBeLeashed: 0b, IsPushable: 0b, LightLevel: 7, CanOpenDoor: 0b}, ObjectiveData: {HasObjectives: 1b, ObjectiveDataSet: [{Type: "LOOK_AT_PLAYER", Prio: 9}, {Type: "LOOK_AT_MOB", Prio: 10}, {Type: "LOOK_AT_RESET", Prio: 9}]}, CustomName: '{"color":"#FFFF00","text":"Brandon"}', SoundData: {SoundDataSet: [{Type: "DEATH", Name: "minecraft:entity.player.death"}, {Type: "EAT", Name: "minecraft:entity.generic.eat"}, {Type: "HURT", Name: "minecraft:entity.player.hurt"}, {Type: "TRADE", Name: "minecraft:entity.villager.trade"}, {Type: "TRADE_YES", Name: "minecraft:entity.villager.yes"}, {Type: "TRADE_NO", Name: "minecraft:entity.villager.no"}]}, DialogData: {Type: "YES_NO", Default: "question", DialogDataSet: [{Buttons: [{Type: "DEFAULT", Name: "Montre moi ça !", Actions: [{Type: "OPEN_TRADING_SCREEN"}], Label: "yes_button"}, {Type: "DEFAULT", Name: "Non merci.", Actions: [{Type: "CLOSE_DIALOG"}], Label: "no_button"}], Texts: [{Text: "Bonjour @initiator ! Je t'échange tes Pièces de combat contre des médicaments spéciaux. Chaque médicament augmente l'IV correspondant d'un point. Parfait pour parfaire tes Pokémons !"}], Name: "Question Dialog", Label: "question"}]}, AngerTime: 0, ArmorItems: [{}, {}, {}, {}], EasyNPCVersion: 2, HandItems: [{}, {}], Air: 300s, Offers: {Inventory: {}, Recipes: {Recipes: [{xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:hp_up_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:protein_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:iron_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:calcium_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:zinc_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "pokeminemod:battlecoin", Count: 6b}, sell: {id: "pokeminemod:carbos_plus", Count: 1b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}, {xp: 0, buy: {id: "minecraft:air", Count: 0b}, sell: {id: "minecraft:air", Count: 0b}, uses: 0, priceMultiplier: 1.0f, maxUses: 64, rewardExp: 1b, demand: 0, specialPrice: 0, buyB: {id: "minecraft:air", Count: 0b}}]}}, Profession: "NONE", TradingData: {TradingDataSet: {Type: "BASIC", RewardedXP: 0, LastReset: 1723549710640L, ResetsEveryMin: 64, MaxUses: 64}}, FallDistance: 0.0f, Variant: "STEVE", Motion: [0.0d, 0.0d, 0.0d], PersistenceRequired: 0b, FallFlying: 0b, CanPickUpLoot: 0b, ModelData: {DefaultPose: "STANDING", Pose: "DEFAULT", Visible: {}, Position: {}, Rotation: {}, SmartAnimations: 1b}, HurtTime: 0s, Health: 20.0f, Fire: -1s, PortalCooldown: 0}

When I created the NPC there was no problem. However, the problem occurred after the server automatically restarted at 5am. And after changing an item to force the registration of the NPC, the bug disappeared... It's quite strange. I'll wait to see if the bug starts again tomorrow after the automatic reboot to see if it's related to that or not.

MarkusBordihn commented 3 months ago

Thanks for providing the details. One thing you could try is "respawning" the NPC, which is similar to performing a server restart.

If the issue persists after doing this, it might indicate that there’s a problem with the save data. If that’s the case, I should be able to address it relatively easily. Let me know how it goes!