Solved Getting a players message

Discussion in 'Spigot Plugin Development' started by CodingCyClone, Apr 18, 2021.

  1. What is the best way to get a players message? I have heard that I could use an AsyncPlayerChatEvent or conversation api but I am not exactly sure how to go about using it. I made a custom item name tag for my custom enchantment plugin but I need to get a players message when they apply that item name tag to an item. So what I am trying to do is be able to get what the player types in chat next and then save that message as a string and then remove that message from the actual game chat. I will also have to ask the player to confirm what they wrote but I assume that process will be the same getting their initial message.

    I made a separate class to try and mess around with the conversation api but I could not figure out how to exactly get it to work because I dont really need to do anything besides retrive a players message when a specific method is called.
    Code (Text):
    public void startConversationPrefix(Player p) {
            ConversationFactory factory = new ConversationFactory(ClonesEnchants.getInstance());

            Conversation conversation = factory.buildConversation(p);
            conversation.begin();

        }
     
  2. Yeah, you will want to use AsyncPlayerChatEvent. I'm not sure about the Conversation API but event handlers should work. Here's a fairly robust solution you could use:

    Code (Java):

    public class ChatHandler implements Listener {
        private Map<Player, BiConsumer<Player, String>> handlers = new HashMap<>();

        public void registerHandler(Player player, BiConsumer<Player, String> consumer) {
            handlers.put(player, consumer);
        }

        @EventHandler
        public void onChat(AsyncPlayerChatEvent event) {
            Player p = event.getPlayer();
            if(handlers.containsKey(p)) {
                handlers.get(p).accept(p, event.getMessage());
                handlers.removeKey(p);
                event.setCancelled(true);
            }
        }
    }
     
    Then you can simply do this whenever you want to get the next message a player types:

    Code (Java):

        chatHandler.registerHandler(player, (p, msg) -> {
            p.sendMessage("You entered " + msg); // TODO: handle the message however you want
        });
     
    Obviously you'll also have to register the ChatHandler class listener, etc.
     
  3. Thank you! Also for some reason the chatHandler call to the registerHandler method is not working correctly because nothing happens when a type into the chat. Also yes I did register it
    Code (Text):
     chatHandler.registerHandler(player, (p, msg) -> {
                p.sendMessage("Is this correct? " + msg);
            });
     
  4. I meant to register the actual event listener, i.e. in your plugin's onEnable, do getServer().getPluginManager().registerEvents(new ChatHandler(), this);
     
  5. Or you can do it with
    Bukkit.getPluginManager().registerEvents(new Listener(), this);
     
  6. Yes I have done that I know how to register events I just dont know how to use the Async chat event.
     
  7. Are you looking to get a Specific Message? or...
     
  8. I am trying to get the first message the player sends. I am calling this
    Code (Text):
    chatHandler.registerHandler(player, (p, msg) -> {
                p.sendMessage("Is this correct? " + msg);
            });
     
  9. Idk what you did wrong, in less than a minute I got this to work...
    Code (Java):

    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.AsyncPlayerChatEvent;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.plugin.java.JavaPlugin;

    import java.util.HashMap;
    import java.util.Map;
    import java.util.function.BiConsumer;

    public final class Test extends JavaPlugin implements Listener
    {
        @Override
        public void onEnable()
        {
            Bukkit.getPluginManager().registerEvents(this, this);
        }

        @EventHandler
        public void onJoin(PlayerJoinEvent e)
        {
            registerHandler(e.getPlayer(), (p, msg) -> {
               p.sendMessage("Is this correct? " + msg);
            });
        }

        private final Map<Player, BiConsumer<Player, String>> HANDLERS = new HashMap<>();

        public void registerHandler(Player player, BiConsumer<Player, String> consumer) {
            HANDLERS.put(player, consumer);
        }

        @EventHandler
        public void onChat(AsyncPlayerChatEvent event) {
            Player p = event.getPlayer();
            if(HANDLERS.containsKey(p)) {
                HANDLERS.get(p).accept(p, event.getMessage());
                HANDLERS.remove(p);
                event.setCancelled(true);
            }
        }
    }
     
  10. via AsyncPlayerChatEvent the best way
     
  11. To bug test I sent the map to the player just to make sure that part is working and it does return the correct player name. What I need to do is set a string equal to the players response so I can then use if statements to evaluate their response. What would be the best way to go about this? Also the lambda function must be somewhat working since it does register the players name but it just does not message the player so something must not be right.
    Code (Text):
    ChatHandler chatHandler = new ChatHandler();

    public boolean addNewName(ItemStack currentItem, Player player) {
            ItemMeta meta = currentItem.getItemMeta();
            player.sendMessage(ChatColor.LIGHT_PURPLE + "What would you like to name your item?");

            chatHandler.registerHandler(player, (p, msg) -> {
                p.sendMessage("Is this correct? " + msg);
            });
            player.sendMessage(chatHandler.getMessage());
    Code (Text):
    public class ChatHandler implements Listener {
        private final Map<Player, BiConsumer<Player, String>> handlers = new HashMap<>();

        public void registerHandler(Player player, BiConsumer<Player, String> consumer) {
            handlers.put(player, consumer);
        }

        @EventHandler
        public void onChat(AsyncPlayerChatEvent event) {
            Player p = event.getPlayer();
            if(handlers.containsKey(p)) {
                handlers.get(p).accept(p, event.getMessage());
                handlers.remove(p);
                event.setCancelled(true);
            }
        }

        public String getMessage() {
            return handlers.toString();
        }

    }
     
  12. Why are you creating an instance of ChatHandler? Do you know what you’re doing? Did you not see my code??
     
  13. What are you even talking about the code is basically the same. Also you can see that I am calling the object of the ChatHandler class right before my lambda function. Anyways I fixed the issue I forgot to make the hashmap static -_-
     
  14. I seriously doubt that you understand how this system works... you don’t need to access the hashmap and it shouldn’t be static... and no the code is completely different, you use the chathandler class when you shouldn’t... all you need is inside the lambda registerHandler
     
  15. The only difference is that you are calling yours all within the same class while mine is called from a separate class. In java we cant just call registerHandler since its in a different class. Also you cant access a hashmap from a separate class with getter methods if it is not static.
     
  16. The ChatHandler object should just be a singleton class, this way you wouldn't need a static field for the Map.
     
    • Agree Agree x 1
  17. You don’t need to access the hashmap, that’s my point... everyone should be done inside the registerHandler lambda. Even if mine is in one class, where do you see me access the hashmap inside my onJoin method? Never, it’s only the lambda