Anzeigen: Beitritt/Verlassen als Text und Signalton, Discord-Status, TS-Thema, Sprecher in der Actionbar (abschaltbar)
This commit is contained in:
1 parent
3c0e3ed17a
commit
b335933678
19 files changed
+583
-37
No files matched your search
@@ -0,0 +1,49 @@
|
||||
package eu.mhsl.voicebridge.plugin;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** {@code /crosstalk actionbar}: die Sprecher-Anzeige für sich selbst aus- und einschalten. */
|
||||
final class ActionbarCommand implements TabExecutor {
|
||||
private static NamespacedKey key;
|
||||
|
||||
static void init(Plugin plugin) {
|
||||
key = new NamespacedKey(plugin, "actionbar_off");
|
||||
}
|
||||
|
||||
/** Main-Thread: ob der Spieler die Actionbar sehen will (Standard: ja). */
|
||||
static boolean enabled(Player player) {
|
||||
return !player.getPersistentDataContainer().has(key, PersistentDataType.BYTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage("Nur für Spieler.");
|
||||
return true;
|
||||
}
|
||||
if (args.length != 1 || !args[0].equalsIgnoreCase("actionbar")) return false;
|
||||
|
||||
boolean nowEnabled = !enabled(player);
|
||||
if (nowEnabled) player.getPersistentDataContainer().remove(key);
|
||||
else player.getPersistentDataContainer().set(key, PersistentDataType.BYTE, (byte) 1);
|
||||
player.sendMessage(Component.text("Anzeige, wer aus Discord/TeamSpeak spricht: "
|
||||
+ (nowEnabled ? "an" : "aus"), NamedTextColor.GRAY));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) {
|
||||
return args.length == 1 ? List.of("actionbar") : List.of();
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
@@ -43,7 +44,7 @@ final class BridgeLink {
|
||||
return System.currentTimeMillis() - lastReply < ALIVE_MILLIS;
|
||||
}
|
||||
|
||||
void sendHello(Map<String, Integer> members) {
|
||||
void sendHello(Map<String, List<Message.Member>> members) {
|
||||
boolean alive = isBridgeAlive();
|
||||
if (wasAlive && !alive) logger.warning("Bridge antwortet nicht mehr.");
|
||||
wasAlive = alive;
|
||||
|
||||
@@ -101,7 +101,9 @@ final class BridgeVoicechat implements VoicechatPlugin {
|
||||
if (api == null || link == null) return;
|
||||
|
||||
Map<UUID, List<VoicechatConnection>> byGroup = new HashMap<>();
|
||||
Map<UUID, String> names = new HashMap<>();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
names.put(player.getUniqueId(), player.getName());
|
||||
VoicechatConnection connection = api.getConnectionOf(player.getUniqueId());
|
||||
if (connection == null || !connection.isConnected() || connection.isDisabled()) continue;
|
||||
Group group = connection.getGroup();
|
||||
@@ -109,14 +111,17 @@ final class BridgeVoicechat implements VoicechatPlugin {
|
||||
byGroup.computeIfAbsent(group.getId(), k -> new ArrayList<>()).add(connection);
|
||||
}
|
||||
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
Map<String, List<Message.Member>> roster = new HashMap<>();
|
||||
for (CrosstalkRoom room : rooms.values()) {
|
||||
List<VoicechatConnection> members = byGroup.getOrDefault(room.groupId(), List.of());
|
||||
room.setMembers(members);
|
||||
room.dropIdleSpeakers();
|
||||
counts.put(room.key(), members.size());
|
||||
roster.put(room.key(), members.stream().map(c -> {
|
||||
UUID id = c.getPlayer().getUuid();
|
||||
return new Message.Member(id, names.getOrDefault(id, id.toString()));
|
||||
}).toList());
|
||||
}
|
||||
link.sendHello(counts);
|
||||
link.sendHello(roster);
|
||||
}
|
||||
|
||||
/** Netzwerk-Thread der Bridge-Verbindung. */
|
||||
@@ -127,6 +132,20 @@ final class BridgeVoicechat implements VoicechatPlugin {
|
||||
CrosstalkRoom room = rooms.get(audio.room());
|
||||
if (room != null) room.play(audio.source(), audio.opus());
|
||||
}
|
||||
case Message.Notice notice -> Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
CrosstalkRoom room = rooms.get(notice.room());
|
||||
if (room == null) return;
|
||||
Component text = Component.text("[" + room.name() + "] ", NamedTextColor.GOLD)
|
||||
.append(Component.text(notice.text(), NamedTextColor.GRAY));
|
||||
room.memberPlayers().forEach(player -> player.sendMessage(text));
|
||||
});
|
||||
case Message.Speakers speakers -> Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
CrosstalkRoom room = rooms.get(speakers.room());
|
||||
if (room == null || speakers.names().isEmpty() || !plugin.getConfig().getBoolean("actionbar", true)) return;
|
||||
Component text = Component.text("Spricht: ", NamedTextColor.GRAY)
|
||||
.append(Component.text(String.join(", ", speakers.names()), NamedTextColor.GOLD));
|
||||
room.memberPlayers().stream().filter(ActionbarCommand::enabled).forEach(player -> player.sendActionBar(text));
|
||||
});
|
||||
case Message.Hello ignored -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,13 @@ import de.maxhenkel.voicechat.api.VoicechatServerApi;
|
||||
import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel;
|
||||
import eu.mhsl.voicebridge.protocol.Message;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@@ -46,6 +50,11 @@ final class CrosstalkRoom {
|
||||
return current != null && current.active();
|
||||
}
|
||||
|
||||
/** Main-Thread: die Spieler in der Gruppe. */
|
||||
synchronized List<Player> memberPlayers() {
|
||||
return members.stream().map(c -> Bukkit.getPlayer(c.getPlayer().getUuid())).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
synchronized void setMembers(List<VoicechatConnection> members) {
|
||||
if (sameMembers(this.members, members)) return;
|
||||
this.members = List.copyOf(members);
|
||||
|
||||
@@ -22,6 +22,9 @@ public final class VoiceBridgePlugin extends JavaPlugin {
|
||||
InetSocketAddress bridge = new InetSocketAddress(
|
||||
getConfig().getString("bridge.host", "127.0.0.1"),
|
||||
getConfig().getInt("bridge.port", 24470));
|
||||
ActionbarCommand.init(this);
|
||||
var command = getCommand("crosstalk");
|
||||
if (command != null) command.setExecutor(new ActionbarCommand());
|
||||
voicechat = new BridgeVoicechat(this, bridge);
|
||||
service.registerPlugin(voicechat);
|
||||
}
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
bridge:
|
||||
host: 127.0.0.1
|
||||
port: 24470
|
||||
|
||||
# Actionbar "Spricht: …" mit den gerade sprechenden Leuten aus Discord/TeamSpeak.
|
||||
# Jeder Spieler kann sie zusätzlich mit /crosstalk actionbar für sich aus- und einschalten.
|
||||
actionbar: true
|
||||
@@ -6,3 +6,12 @@ depend: [ voicechat ]
|
||||
authors: [ MineTec ]
|
||||
description: Verbindet Simple-Voice-Chat-Gruppen mit Discord und TeamSpeak
|
||||
website: mhsl.eu
|
||||
commands:
|
||||
crosstalk:
|
||||
description: Einstellungen für die Crosstalk-Gruppen
|
||||
usage: "/crosstalk actionbar"
|
||||
permission: voicebridge.crosstalk
|
||||
permissions:
|
||||
voicebridge.crosstalk:
|
||||
description: /crosstalk benutzen
|
||||
default: true
|
||||
Reference in new issue
Block a user