Solved AsyncPlayerChatEvent firing sync..?

Discussion in 'Spigot Plugin Development' started by Eth, Aug 6, 2021.

  1. Eth

    Eth

    Hello, I'm having an odd issue with this code:
    Code (Text):
    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onPlayerChat(AsyncPlayerChatEvent event) {
       PlayerChatChannelEvent chatEvent = new PlayerChatChannelEvent(event.getPlayer(), getCurrentChannel(event.getPlayer().getUniqueId()), event.getFormat(), event.getMessage());
       Bukkit.getPluginManager().callEvent(chatEvent);
       // ...
    }
    Giving: java.lang.IllegalStateException: PlayerChatChannelEvent cannot be triggered asynchronously from inside synchronized code. on the line where the event is called.
    Few things to note:
    • PlayerChatChannelEvent is set to run as an async event in its constructor. This makes PlayerChatChannelEvent#isAsynchronous return true.
    • This IllegalStateException is only fired when I simulate the player chatting using Player#chat. If the player sends a normal message in chat, it works as intended.
    • The issue is that calling a new PlayerChatChannelEvent inside an AsyncPlayerChatEvent should be fine, because AsyncPlayerChatEvent runs on an async thread, and PlayerChatChannelEvent requires an async thread. However, it still throws an exception, as if AsyncPlayerChatEvent is firing synchronously..?
    • I cannot modify the code shown above! Saying that I should create a new async task for calling the event isn't helpful, I'm trying to figure out why this happens, not a workaround. I am able to modifythe Player#chat line. I have tried running player.chat on a new async thread, a new sync scheduled delayed thread, nothing changes this error.
    If someone with knowledge on how the bukkit event system works (specifically for async ones) can explain why this happens, that would be great

    EDIT:
    I did some more testing, and printed event.isAsynchronous() as well as Bukkit.isPrimaryThread() in the event listener for PlayerAsyncChatEvent. They both returned false: so the async chat event isn't async, meaning it is synchronous, but at the same time we aren't on the main bukkit thread (so synchronous).
    I'm really confused, it doesn't seem like this should be a possible state.
     
    #1 Eth, Aug 6, 2021
    Last edited: Aug 6, 2021
  2. most of the Bukkit and Minecraft Stuff runs in a single Thread Excpect the Chat. This is why you can spam "lag" at a serverlag in the chat ^^
    The AsyncPlayerChatEvent is called in the thread from The Chat.
    To get access to the BukkitThread use
    Bukkit.getScheduler().runTask(()->{/*will be executed in Bukkit Thread*/})
    so you need to do sth like this:
    Bukkit.getScheduler().runTask(()->{Bukkit.getPluginManager().callEvent(chatEvent)})

    Player#chat uses the Player object wich is in the Bukkit Thread. But internally the method makes access to the chat and writes a message into it.
     
    #2 Player_Schark, Aug 6, 2021
    Last edited: Aug 6, 2021
  3. Have you tried calling Player#chat within runTaskAsynchronousy? You may get an error complaining that you're accessing Bukkit API methods async though.
     
  4. he did

     
    • Like Like x 1
  5. Eth

    Eth

    I know how Bukkit threading works (btw there are several other things that are handled asynchronously, especially if you are using paper spigot, the most common Bukkit branch).
    Your solution doesn't make much sense, because I mentioned that the PlayerChatChannelEvent is marked as an async event in its constructor (can only be called asynchronously, similar to AsyncPlayerChatEvent). The error that I am getting says that PlayerChatChannelEvent must be fired async, and the error says that I am firing it on a synchronous thread... So why would scheduling a synchronous task for calling the event help?

    Regardless, I mentioned that I can't modify the code calling the PlayerChatChannelEvent, it isn't mine. That code works perfectly fine as intended if the player types an actual message in chat, but when using player.chat(), something changes. What seems to happen is that AsyncPlayerChatEvent is firing syncronously, because that is what Bukkit is complaining about.
    I assumed that running player.chat() on an async thread would help, but it didn't change anything.
     
  6. Eth

    Eth

    Updated original post with extra testing info.
     
  7. The JavaDocs for the AsyncPlayerChatEvent read

    So what you experienced is expected behavior.
     
  8. Eth

    Eth

    Thanks! This is what I was missing.
    Marking as solved.