Exist something like an "onPlayerChatMessageRecive" event?

Discussion in 'Plugin Development' started by Pitazzo, Jul 30, 2013.

  1. Hello folks!
    I'm developing right now a RPG-Language-Plugin for my RPG-Plugin. More or less, what it would do is to change the format of the message that the player who doesn't have a permission node recived (having this node would be the same as knowing this language, and then to understand what the other player, who doesn't speak the same language says.
    In the practise, the plugin would get the recepienst of the message, check if they have the node, and if not, change themessage to something without sense.
    Do you think that it is possible?
    Regards, Pitazzo
     
  2. Offline

    Pawnguy7

  3. Pawnguy7 Not sure if this is what I'm looking for... I would need a class which has the method getRecivedMessage() or getSentMessage()
     
  4. It's possible, but you either need to do some ugly NMS hacking, or (far easier) use ProtocolLib and intercept incoming chat messages.
     
  5. I explain how you can achieve this with ProtocolLib in this thread - essentially, you intercept every Packet3Chat sent to each player, switching out its content with your "translated" text.

    Here's an example of just that, together with a compact orcish translator (download):
    Code:java
    1. private Language orcish = new OrcishLanguage();
    2.  
    3. @Override
    4. public void onEnable() {
    5. ProtocolLibrary.getProtocolManager().addPacketListener(
    6. new PacketAdapter(this, ConnectionSide.SERVER_SIDE, Packets.Server.CHAT) {
    7. private JSONParser parser = new JSONParser();
    8.  
    9. @SuppressWarnings("unchecked")
    10. public void onPacketSending(PacketEvent event) {
    11. try {
    12. PacketContainer packet = event.getPacket();
    13. String json = packet.getStrings().read(0);
    14.  
    15. JSONObject data = (JSONObject) parser.parse(json);
    16. String text = (String) data.get("text");
    17.  
    18. if (text != null) {
    19. data.put("text", orcish.translate(text));
    20.  
    21. // Write back the resulting JSON
    22. packet.getStrings().write(0, data.toJSONString());
    23. }
    24.  
    25. } catch (ParseException e) {
    26. throw new RuntimeException("Cannot parse JSON.", e);
    27. }
    28. }
    29. }
    30. );
    31. }
    32.  
    33. private static class Language {
    34. // Words sorted by lenght
    35. private String[][] words;
    36.  
    37. // Word matcher
    38. private Pattern wordPattern = Pattern.compile("(" + ChatColor.COLOR_CHAR + "\\w)*(\\w+)");
    39.  
    40. public Language(String... words) {
    41. @SuppressWarnings("unchecked")
    42. List<String>[] bins = (List<String>[]) new List[findLongest(words)];
    43.  
    44. // Place word into the correct bin
    45. for (String word : words) {
    46. int i = word.length() - 1;
    47.  
    48. if (bins[i] == null)
    49. bins[i] = new ArrayList<String>();
    50. bins[i].add(word);
    51. }
    52. this.words = generateLookup(bins);
    53. }
    54.  
    55. /**
    56.   * Translate the given text into the current language.
    57.   * @param text - the text.
    58.   * @return The resulting language.
    59.   */
    60. public String translate(String text) {
    61. Matcher matcher = wordPattern.matcher(text);
    62.  
    63. while (matcher.find()) {
    64. String translate = translateWord(matcher.group(2));
    65. matcher.appendReplacement(sb, "$1" + Matcher.quoteReplacement(translate));
    66. }
    67. matcher.appendTail(sb);
    68. return sb.toString();
    69. }
    70.  
    71. /**
    72.   * Translate a single word.
    73.   * @param currentWord - the word to translate.
    74.   * @return The translated word.
    75.   */
    76. protected String translateWord(String currentWord) {
    77. String[] group = words[Math.min(currentWord.length(), words.length) - 1];
    78. int index = Math.abs(currentWord.hashCode() % group.length);
    79.  
    80. return preserveCase(group[index], currentWord);
    81. }
    82.  
    83. protected static String preserveCase(String text, String caseFormat) {
    84. char[] modify = text.toCharArray();
    85. char[] template = caseFormat.toCharArray();
    86.  
    87. // Check every character
    88. for (int i = 0; i < modify.length; i++) {
    89. if (Character.isLetter(modify[i])) {
    90. modify[i] = Character.isUpperCase(template[i]) ?
    91. Character.toUpperCase(modify[i]) : Character.toLowerCase(modify[i]);
    92. }
    93. }
    94. return new String(modify);
    95. }
    96.  
    97. private static String[][] generateLookup(List<String>[] bins) {
    98. String[][] result = new String[bins.length][];
    99.  
    100. // Generate lookup
    101. for (int i = 0; i < bins.length; i++) {
    102. result[i] = bins[i].toArray(new String[bins[i].size()]);
    103. }
    104. return result;
    105. }
    106.  
    107. private static int findLongest(String[] words) {
    108. int length = 0;
    109.  
    110. for (String word : words)
    111. length = Math.max(length, word.length());
    112. return length;
    113. }
    114. }
    115.  
    116. private static class OrcishLanguage extends Language {
    117. public OrcishLanguage() {
    118. super(
    119. "A", "N", "G", "O", "L",
    120. "Ha", "Ko", "No", "Mu", "Ag", "Ka", "Gi", "Il",
    121. "Lok", "Tar", "Kaz", "Ruk", "Kek", "Mog", "Zug", "Gul", "Nuk", "Aaz", "Kil", "Ogg",
    122. "Rega", "Nogu", "Tago", "Uruk", "Kagg", "Zaga", "Grom", "Ogar", "Gesh", "Thok", "Dogg", "Maka", "Maza",
    123. "Regas", "Nogah", "Kazum", "Magan", "No'bu", "Golar", "Throm", "Zugas", "Re'ka", "No'ku", "Ro'th",
    124. "Thrakk", "Revash", "Nakazz", "Moguna", "No'gor", "Goth'a", "Raznos", "Ogerin", "Gezzno", "Thukad", "Makogg", "Aaz'no",
    125. "Lok'Tar", "Gul'rok", "Kazreth", "Tov'osh", "Zil'Nok", "Rath'is", "Kil'azi",
    126. "Throm'ka", "Osh'Kava", "Gul'nath", "Kog'zela", "Ragath'a", "Zuggossh", "Moth'aga",
    127. "Tov'nokaz", "Osh'kazil", "No'throma", "Gesh'nuka", "Lok'mogul", "Lok'bolar", "Ruk'ka'ha",
    128. "Regasnogah", "Kazum'nobu", "Throm'bola", "Gesh'zugas", "Maza'rotha", "Ogerin'naz",
    129. "Thrakk'reva", "Kaz'goth'no", "No'gor'goth", "Kil'azi'aga", "Zug-zug'ama", "Maza'thrakk",
    130. "Lokando'nash", "Ul'gammathar", "Golgonnashar", "Dalggo'mazah",
    131. "Khaz'rogg'ahn", "Moth'kazoroth");
    132. }
    133. }[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]

    Here's how this looks in the client itself:
    [​IMG]
     
    Pitazzo and xTrollxDudex like this.
  6. Comphenix
    That seems a bit overly complex, can't you just intercept AsyncPlayerChatEvent and change the message?
     
  7. If I understood Pitazzo correctly, he wanted a message to appear garbled if the player doesn't know the "language", otherwise it should be kept the same. Just like what happens when horde and alliance players try to talk to each other in WoW.

    This requires that the same message appear differently depending on the receiving player, which naturally got me (and desht) thinking of ProtocolLib. But in hindsight I suppose you could do this purely with Bukkit API, if you cancel all (or those without permission nodes) recipients in AsyncPlayerChatEvent and do sendMessage() yourself, preferably in ListenerPriority.HIGHEST.
     
  8. Comphenix
    PHP:
    1. @EventHandler(priority = EventPriority.HIGHEST)
    2. public void onPlayerChat(AsyncPlayerChatEvent pizza){
    3.  
    4. pizza.setCancelled(true);
    5.  
    6. for(Player p : Bukkit.getOnlinePlayers()){
    7. //determine random word -->here<--
    8. p.sendMessage(/*random word*/);
    9. }
    10. }
     
  9. I don't believe the loop would run after you cancel the event.
     
  10. fanaticmw2

    Incorrect, all actions performed on the Event object itself take effect in game after the listener's full method has been called.

    Using event.setCancelled() does not stop the method short (this is not possible in Java without return being used or, in some cases, an exception being thrown) :)
     
    fanaticmw2 likes this.
  11. That's not how cancelled works. It's just a method that sets an internal boolean flag to TRUE, which Bukkit checks after all the event listeners have been executed (including that method above).
     
    fanaticmw2 likes this.
  12. Cancelling the player chat event and then sending an alternative message will work fine if you only need to intercept players chatting. The ProtocolLib approach would also work for messages sent by plugins (i.e. via player.sendMessage()). Depends on your requirements, I guess.
     
  13. All right... So complex for me, but I'll speak about this with the leader of my Server-Dev-Team, who will exploit better than me this great answer. Thanks a lot to all the people who got involved in this post: Comphenix xTrollxDudex desht Pawnguy7 fanaticmw2 and Hoolean. We can tag this thread as solved.
     
    desht, Comphenix and xTrollxDudex like this.

Share This Page