• Es freut uns dass du in unser Minecraft Forum gefunden hast. Hier kannst du mit über 130.000 Minecraft Fans über Minecraft diskutieren, Fragen stellen und anderen helfen. In diesem Minecraft Forum kannst du auch nach Teammitgliedern, Administratoren, Moderatoren , Supporter oder Sponsoren suchen. Gerne kannst du im Offtopic Bereich unseres Minecraft Forums auch über nicht Minecraft spezifische Themen reden. Wir hoffen dir gefällt es in unserem Minecraft Forum!

NullPointerException bei Command

K

Kleeraphie

Guest
Hi,
ich versuche grade ein Plugin zu programmieren, bei dem der Chat in mehrere "Channels" aufgeteilt wird. Immer wenn ich in ein Channel joinen möchte, tritt folgender Fehler auf:
Code:
[Server thread/ERROR]: null
org.bukkit.command.CommandException: Unhandled exception executing command 'cc' in plugin ChannelChat v1.0
    at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) ~[spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at org.bukkit.craftbukkit.v1_8_R3.CraftServer.dispatchCommand(CraftServer.java:641) ~[spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.PlayerConnection.handleCommand(PlayerConnection.java:1162) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:997) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:45) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:1) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_25]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_25]
    at net.minecraft.server.v1_8_R3.SystemUtils.a(SourceFile:44) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:715) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [spigot_server.jar:git-Spigot-db6de12-18fbb24]
    at java.lang.Thread.run(Thread.java:745) [?:1.8.0_25]
Caused by: java.lang.NullPointerException
    at de.kleeraphie.channelchat.Commands.CMD_CC.onCommand(CMD_CC.java:38) ~[?:?]
    at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[spigot_server.jar:git-Spigot-db6de12-18fbb24]
    ... 15 more

Meine Klasse für den Command:
Code:
package de.kleeraphie.channelchat.Commands;

import java.util.HashMap;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import de.kleeraphie.channelchat.Main.Main;

public class CMD_CC implements CommandExecutor {
  
  
    public static HashMap<Player, String> Channels = new HashMap<>();
    String Channelnummer = null;

    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        Player p = (Player) sender;

        if(args.length==1 | args.length==2){
            if(args[0].equalsIgnoreCase("help")){
                p.sendMessage("§e=====================§6ChannelChat§e====================");
                p.sendMessage("§eGeschrieben von: §6 " + Bukkit.getPluginManager().getPlugin("ChannelChat").getDescription().getAuthors());
                p.sendMessage("§eVersion: §6 " + Bukkit.getPluginManager().getPlugin("ChannelChat").getDescription().getVersion());
                p.sendMessage("§e-----------------§6ChannelChat-Befehle§e----------------");
                p.sendMessage("§6/cc join [Channelname] §e: Um in einen Channel zu joinen");
                p.sendMessage("§6/cc leave §e: Um einen Channel zu verlassen");
                p.sendMessage("§e===================================================");
                return true;
              
            } else if(args[0].equalsIgnoreCase("join")){
              
                if(p.hasPermission("cc.join")){
                if(args.length==2){
                    if(Channels.get(p).equalsIgnoreCase(Main.cfg.getString("Channelname"))) {
                    Channels.replace(p, Channels.get(p), args[1]);
                    Channelnummer = Channels.get(p);
                    Main.setPermission("cc." + args[1], true, p);
                    p.sendMessage(Main.prefix + "§eDu wurdest in §6Channel " + args[1] + " §2verschoben.");
                    for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                      
                        if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p))){
                            Channelplayer.sendMessage("§a[§e" + Channelnummer + "§a] " + "§6 " + p.getName() + "§ehat den Channel §2betreten.");
                        }
                    }
                    Channelnummer = null;
                    return true;
                  
                    }    else{
                        p.sendMessage(Main.prefix + "§cDu musst §4Channel " + Channels.get(p) + "§c erst verlassen, bevor du in §4Channel " + args[1] + "kannst.");
                    }
                } else if(args.length>=3){
                    p.sendMessage(Main.prefix + "§cBenutze §4/cc join [Channel-Nummer]."); // noch ändern, dass er das auch ausgibt wenn ich z.B. /cc join 6 5 eingebe
                    return true;
                }
            } else{
                p.sendMessage(Main.noperm);
                return true;
            }
              
            } else if(args[0].equalsIgnoreCase("leave")){
              
              
                if(args.length==1){
                    if(Channels.get(p).equalsIgnoreCase(Main.cfg.getString("Channelname"))) {
                      
                    Main.setPermission(Channels.get(p), false, p);
                    Channelnummer = Channels.get(p);
                    Channels.replace(p, Channels.get(p), Main.cfg.getString("Channelname"));
                    p.sendMessage(Main.prefix + "§eDu hast den Channel §6" + args[1] + " §cverlassen.");
                    for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                      
                        if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p))){
                            Channelplayer.sendMessage("§a[§e" + Channelnummer + "§a] " + p.getName() + "§6 " + p.getName() + "§ehat den Channel §cverlassen.");
                        }
                    }
                    p.sendMessage(Main.prefix + "§eDu bist nun im §6Standard-Channel.");
                    Channelnummer = null;
                    return true;

                    } else{
                        p.sendMessage(Main.prefix + "§cDu kannst den §4Standardchannel §cnicht verlassen.");
                    }
                } else {
                    p.sendMessage(Main.prefix + "§cBenutze §4/cc leave.");
                    return true;
                }
            }
            return true;
          
            } else {
            p.sendMessage(Main.prefix + "§eFür Hilfe benutze §6/cc help§e.");
            return true;
        }
    }
}
 

moinless

Schafhirte
Registriert
4 Oktober 2013
Beiträge
103
Diamanten
302
Du versuchst hier ein Player Objekt aus der HashMap zu holen, ohne zu überprüfen, ob es überhaupt drin ist.
Code:
 if(Channels.get(p).equalsIgnoreCase(Main.cfg.getString("Channelname"))) {

Richtig wäre:
Code:
if (Channels.containsKey(p){ ... }
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Das Speichern von Spielerobjekten in einer Map ist eine schlechte Idee. Hierdurch werden Referenzen auf einen ganzen Haufen anderer Objekte gehalten, so dass ein Speicherleck entsteht. Besser ist es die UUID der Spieler als Schlüssel zu verwenden.
 

UnityGaming

Workaholic
Registriert
25 Oktober 2015
Beiträge
527
Alter
26
Diamanten
312
Minecraft
FastFelix771
Das Speichern von Spielerobjekten in einer Map ist eine schlechte Idee. Hierdurch werden Referenzen auf einen ganzen Haufen anderer Objekte gehalten, so dass ein Speicherleck entsteht. Besser ist es die UUID der Spieler als Schlüssel zu verwenden.
Ich denke eine WeakHashMap sollte dieses Problem beheben, aber dennoch, die UUID als Key ist weitaus umsichtiger und auch flexibler, da man nicht an die WeakHashMap (oder irgendeine andere Map Implementierung mit weak-Keys) gebunden ist.

Du versuchst hier ein Player Objekt aus der HashMap zu holen, ohne zu überprüfen, ob es überhaupt drin ist.
+1
Das dürfte die Fehlerquelle sein.

Eine Anmerkung hätte ich noch zu machen:
Du speicherst im CommandHandler ein nicht-statisches Feld "Channelnummer" und veränderst diese jedes Mal, wenn ein Spieler den Command ausführt und willst das für mehrere Spieler anwenden.
Das halte ich für eine prinzipiell schlechte Idee, obwohl das im Fall von Minecraft sogar problemlos klappen *könnte*, da beim CommandHandling keine Race Conditions auftreten dürften... die werden soweit ich weiß ebenfalls der Reihe im Mainthread abgearbeitet.

Würdest du sowas im Chat Event anwenden, hättest du vermutlich ein Problem, da dieses an asynchrones Event ist und mehrmals zur selben Zeit auftreten kann. Das würde dann wahrscheinlich falsche Werte rausgeben, da die Handler sich sozusagen alle "ins Wort fallen".
Ich glaube nämlich nicht, dass für jeden Event- und CommandExecutor Aufruf ein neuer Executor konstruiert wird, sondern die beim Start übergebene Instanz wiederverwendet wird. Wäre aus rein logischer Sicht auch bescheuert, wenn das anders wäre...

Eventuell solltest du das Channel Handling auch in eine eigene Klasse setzen um das dort abgekapselt und in aller Sorgfalt handhaben zu können. So ist es momentan, salopp gesagt, quer in den Code gekotzt.
 
K

Kleeraphie

Guest
Du versuchst hier ein Player Objekt aus der HashMap zu holen, ohne zu überprüfen, ob es überhaupt drin ist.

In einer anderen Klasse, die ich nicht gepostet habe, wird der Spieler beim Joinen zur Hashmap hinzugefügt.

Besser ist es die UUID der Spieler als Schlüssel zu verwenden.

Das habe ich gemacht, der Fehler tritt jetzt nicht mehr auf, allerdings ein anderer der durch die Benutzung einer WeakHashMap behoben wurde.

Jetzt habe ich nur noch ein Problem, nämlich bekommt jeder die Nachrichten, die jemand schreibt. Dafür ist der Code:
Code:
    @EventHandler
    public void onWrite(AsyncPlayerChatEvent e){
        Player p = e.getPlayer();
        String message = e.getMessage();
       
        for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
           
            if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                e.setCancelled(true);
                Channelplayer.sendMessage("§a[§e" + CMD_CC.Channels.get(p.getUniqueId()) + "§a] " + p.getName() + "§7 " + message);
            }
        }
       
    }
 
Zuletzt bearbeitet:

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Also da die auf diese Map von mehrere Threads zugreifst und WeakHashMap nicht synchronisiert ist, könntest du beim Erzeugen der Map Collections.synchronizedMap() verwenden. Ich denke aber, dass du Programm sowieso noch mehrfach komplett umwerfen wirst, wenn andere Spieler die Lücken in deinem Plugin finden. :)

Bei deinem aktuellen Problem scheinen dann tatsächlich alle Spieler über diese Permission zu verfügen. Vielleicht ist es hier tatsächlich besser, eine andere Datenstruktur zu verwenden. Also z.B. eine Abbildung des Channels auf eine Liste der Spieler, die diesen Channel verwenden:
Code:
private Map<String, Set<UUID>> channelPlayers = new ConcurrentHashMap<>();

public void addChannel(String channel) {
    channelPlayers.put(channel, Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>()));
}
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
z.B. so:
Code:
public void sendMessageToChannel(String channel, String message) {
    Set<UUID> players = channelPlayers.get(channel);
    if (players == null) {
        return;
    }
    players.stream().map(Bukkit::getPlayer).filter(Objects::nonNull).forEach(player -> player.sendMessage(message));
}
 
K

Kleeraphie

Guest
Ich habe jetzt meinen Code durch deinen ersetzt, trotzdem kriegen immer noch alle Spieler die Nachricht.

Die Klasse für den Command:
Code:
package de.kleeraphie.channelchat.Commands;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import de.kleeraphie.channelchat.Main.Main;


public class CMD_CC implements CommandExecutor {
   
   
    public static WeakHashMap<UUID, String> Channels = new WeakHashMap<>();
    public static Map<String, Set<UUID>> channelPlayers = new ConcurrentHashMap<>();
    //public static List<String> ChannelListe = new ArrayList<>();
   
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        Player p = (Player) sender;

        if(args.length==1 | args.length==2){
            if(args[0].equalsIgnoreCase("help")){
                p.sendMessage("§e=====================§6ChannelChat§e====================");
                p.sendMessage("§eGeschrieben von: §6 " + Bukkit.getPluginManager().getPlugin("ChannelChat").getDescription().getAuthors());
                p.sendMessage("§eVersion: §6 " + Bukkit.getPluginManager().getPlugin("ChannelChat").getDescription().getVersion());
                p.sendMessage("§e-----------------§6ChannelChat-Befehle§e----------------");
                p.sendMessage("§6/cc join [Channelname] §e: Um in einen Channel zu joinen.");
                p.sendMessage("§6/cc leave §e: Um einen Channel zu verlassen.");
                p.sendMessage("§e===================================================");
                return true;
               
            } else if(args[0].equalsIgnoreCase("join")){
               
                if(p.hasPermission("cc.join")){
                if(args.length==2){
                    if(Channels.containsKey(p.getUniqueId())){
                    if(Channels.get(p.getUniqueId()).equalsIgnoreCase(Main.cfg.getString("Channelname"))) {
                       
                    Channels.replace(p.getUniqueId(), Channels.get(p.getUniqueId()), args[1]);
                    addChannel(args[1]);
                    Main.setPermission("cc." + args[1], true, p);
                    p.sendMessage(Main.prefix + "§eDu wurdest in §6Channel " + args[1] + " §2verschoben§e.");
                    for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                       
                        if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                            Channelplayer.sendMessage("§a[§e" + Channels.get(p.getUniqueId()) + "§a] " + "§6 " + p.getName() + "§e hat den Channel §2betreten§e.");
                        }
                    }
                    return true;
                   
                    }    else if(args[1]== Channels.get(p.getUniqueId())){
                        p.sendMessage(Main.prefix + "§cDu bist bereits in §4Channel " + Channels.get(p.getUniqueId() + "§c."));
                    } else{
                        p.sendMessage(Main.prefix + "§cDu musst §4Channel " + Channels.get(p.getUniqueId()) + "§c erst verlassen, bevor du in ");
                        p.sendMessage("§4Channel " + args[1] + "§c kannst.");
                    }
                    } else{
                        Channels.put(p.getUniqueId(), args[1]);
                        addChannel(args[1]);
                        Main.setPermission("cc." + args[1], true, p);
                        p.sendMessage(Main.prefix + "§eDu wurdest in §6Channel " + args[1] + " §2verschoben§e.");
                        for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                           
                            if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                                Channelplayer.sendMessage("§a[§e" + Channels.get(p.getUniqueId()) + "§a] " + "§6 " + p.getName() + "§e hat den Channel §2betreten§e.");
                            }
                        }
                        return true;
                    }
                } else if(args.length>=3){
                    p.sendMessage(Main.prefix + "§cBenutze §4/cc join [Channel-Nummer]."); // noch ändern, dass er das auch ausgibt wenn ich z.B. /cc join 6 5 eingebe
                    return true;
                }
            } else{
                p.sendMessage(Main.noperm);
                return true;
            }
               
            } else if(args[0].equalsIgnoreCase("leave")){
               
               
                if(args.length==1){
                    if(Channels.containsKey(p.getUniqueId())){
                    if(!(Channels.get(p.getUniqueId()).equalsIgnoreCase(Main.cfg.getString("Channelname")))) {
                       
                        Main.setPermission("cc." + Channels.get(p.getUniqueId()), false, p);
                        for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                           
                            if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                                Channelplayer.sendMessage("§a[§e" + Channels.get(p.getUniqueId()) + "§a]§6 " + p.getName() + "§e hat den Channel §cverlassen§e.");
                            }
                        }
                        p.sendMessage(Main.prefix + "§eDu hast den Channel §6" + Channels.get(p.getUniqueId()) + " §cverlassen.");
                        p.sendMessage(Main.prefix + "§eDu bist nun im §6Standard-Channel§e.");
                        Channels.replace(p.getUniqueId(), Channels.get(p.getUniqueId()), Main.cfg.getString("Channelname"));
                       
                       
                        for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                           
                            if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                                Channelplayer.sendMessage("§a[§e" + Channels.get(p.getUniqueId()) + "§a]§6 " + p.getName() + "§e hat den Channel §2betreten§e.");
                            }
                        }
                        Main.setPermission("cc." + Main.cfg.getString("Channelname"), true, p);
                    return true;

                    } else{
                        p.sendMessage(Main.prefix + "§cDu kannst den §4Standardchannel §cnicht verlassen.");
                    }
                    } else{
                        Channels.put(p.getUniqueId(), Main.cfg.getString("Channelname"));
                        p.sendMessage(Main.prefix + "§eDu bist nun im §6Standard-Channel§e.");
                        for(Player Channelplayer : Bukkit.getOnlinePlayers()) {
                           
                            if(Channelplayer.hasPermission("cc." + CMD_CC.Channels.get(p.getUniqueId()))){
                                Channelplayer.sendMessage("§a[§e" + Channels.get(p.getUniqueId()) + "§a]§6 " + p.getName() + "§e hat den Channel §cverlassen§e.");
                            }
                        }
                        Main.setPermission("cc." + Main.cfg.getString("Channelname"), true, p);
                    }
                } else {
                    p.sendMessage(Main.prefix + "§cBenutze §4/cc leave."); // noch ändern, dass er das auch ausgibt wenn ich z.B. /cc join 6 5 eingebe
                    return true;
                }
            } else {
            p.sendMessage(Main.prefix + "§eFür Hilfe benutze §6/cc help§e.");
            return true;
        }
        }
        return true;
        }
    public void addChannel(String channel) {
    channelPlayers.put(channel, Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>()));
}
}

Die Klasse, damit nur bestimmte Spieler die Nachricht kriegen:
Code:
package de.kleeraphie.channelchat.Events;

import java.util.Objects;
import java.util.Set;
import java.util.UUID;

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 de.kleeraphie.channelchat.Commands.CMD_CC;

public class PlayerWrite implements Listener {

    @EventHandler
    public void onWrite(AsyncPlayerChatEvent e){
        Player p = e.getPlayer();
        String message = e.getMessage();
       
        sendMessageToChannel(CMD_CC.Channels.get(p.getUniqueId()), message);
       
    }

    public void sendMessageToChannel(String channel, String message) {
        Set<UUID> players = CMD_CC.channelPlayers.get(channel);
        if (players == null) {
            return;
        }
        players.stream().map(Bukkit::getPlayer).filter(Objects::nonNull).forEach(player -> player.sendMessage(message));
    }
}
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Ich frage mich, was du überhaupt genau erreichen möchtest. Unter welchen Voraussetzungen soll ein Spieler einen Channel betreten, wann verlassen und darf ein Spieler nur in einem oder in mehreren Channeln gleichzeitig sein? Was ist der Standard-Channel?

Um es übersichtlicher zu machen, bietet es sich an, die Felder Channels und channelPlayers in eine extra Klasse zu verschieben, dort auf private zu setzen und public static Methoden in der Klasse für den Zugriff zu implementieren.
 
K

Kleeraphie

Guest
Ich frage mich, was du überhaupt genau erreichen möchtest. Unter welchen Voraussetzungen soll ein Spieler einen Channel betreten, wann verlassen und darf ein Spieler nur in einem oder in mehreren Channeln gleichzeitig sein? Was ist der Standard-Channel?
Der Spieler soll einen Channel betreten können, wenn er die Permission "cc.join" hat. Verlassen darf er einen Channel eigentlich immer. Ein Spieler kann immer nur in einen Channel sein und der Standard-Channel kann in der Config festgelegt werden.
Gestern ist mir aufgefallen, dass der Code, damit nur bestimmte Spieler die Nachricht kriegen, doch funktioniert, ich habe bloß vergessen mich als Operator. Jetzt gibt es nur noch ein Problem, nämlich wird die Nachricht von einem Nicht-Operator normal ausgegeben, sodass sie jeder kriegt. Ich denke es hängt mit Permission*** zusammen, also das man per Plugin einem Spieler keine Permissions geben kann.
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Wenn ein Spieler den Channel verlässt, dann ist er also wieder im Standardchannel. Ein spieler kann also jeden beliebigen Channel erstellen oder nur aus einer Auswahl von definierten Channeln?

Also ich hoffe, du hast du Channelverwaltung in eine eigene Klasse ausgelagert, bei der alle Datenfelder privat sind und du public Methoden definierst für bestimmte Aktionen.

Falls ein Spieler jeden beliebigen Channel erstellen kann, wäre eine Map<UUID, String> eine geeignete Datenspeicherung. channelPlayers wirst du nicht benötigen und keine Permission neben "cc.join".

In deiner Klasse zur Channelverwaltung kannst du dir dann z.B. solche Methoden anlegen:
public static String getStandardChannel()
public static String getPlayerChannel(UUID uuid)
public static void setPlayerChannel(UUID uuid, String channel)
public static void sendMessageToChannel(String channel, String message)

Wenn du deine Map channels nennst könntest du letztere Methode dann z.B. so definieren:
Code:
    public void sendMessageToChannel(String channel, String message) {
        channels.entrySet().stream().filter(entry -> entry.getValue().equals(channel))
                .map(entry -> Buckit.getPlayer(entry.getKey())).filter(Objects::nonNull)
                .forEach(player -> player.sendMessage(message));
    }
 
Oben