Discord/TS-Teilnehmer als Mitglieder in der Voicechat-Gruppenanzeige (mit Sprech-Symbol), Actionbar entfernt
This commit is contained in:
1 parent
d5c181a224
commit
e2546ad982
17 files changed
+250
-150
No files matched your search
@@ -37,8 +37,6 @@ public final class Bridge {
|
||||
private final ScheduledExecutorService ticker = Executors.newSingleThreadScheduledExecutor(
|
||||
Thread.ofPlatform().name("bridge-tick").factory());
|
||||
private final Announcer announcer;
|
||||
/** Wie lange nach dem letzten Paket jemand noch als "spricht" gilt. */
|
||||
private static final long SPEAKING_MILLIS = 400;
|
||||
|
||||
private volatile List<Message.RoomInfo> roomInfos = List.of();
|
||||
|
||||
@@ -63,14 +61,6 @@ public final class Bridge {
|
||||
this.teamspeak = config.teamspeak().enabled()
|
||||
? new TeamspeakSide(config.teamspeak(), config.dataDir(), List.copyOf(rooms.values()), updater)
|
||||
: null;
|
||||
for (Room room : rooms.values()) {
|
||||
DiscordRoomBot bot = discordBots.get(room.key());
|
||||
room.setNameResolver((side, id) -> switch (side) {
|
||||
case TEAMSPEAK -> teamspeak != null ? teamspeak.nickname(Integer.parseInt(id)) : id;
|
||||
case DISCORD -> bot != null ? bot.name(Long.parseLong(id)) : id;
|
||||
case MINECRAFT -> id;
|
||||
});
|
||||
}
|
||||
this.announcer = new Announcer(plugin, teamspeak, ticker);
|
||||
roomInfos = buildInfos();
|
||||
}
|
||||
@@ -82,7 +72,7 @@ public final class Bridge {
|
||||
if (teamspeak != null) teamspeak.start();
|
||||
discordBots.values().forEach(DiscordRoomBot::start);
|
||||
ticker.scheduleAtFixedRate(this::safeTick, 1, 1, TimeUnit.SECONDS);
|
||||
ticker.scheduleAtFixedRate(this::sendSpeakers, 500, 500, TimeUnit.MILLISECONDS);
|
||||
ticker.scheduleAtFixedRate(this::sendParticipants, 2, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void safeTick() {
|
||||
@@ -154,16 +144,27 @@ public final class Bridge {
|
||||
return roster;
|
||||
}
|
||||
|
||||
/** Actionbar im Spiel: wer aus Discord/TeamSpeak gerade spricht. */
|
||||
private void sendSpeakers() {
|
||||
/**
|
||||
* Wer aus Discord/TeamSpeak im Raum ist, ans Plugin: Es trägt sie in die Gruppenanzeige des Voicechats ein.
|
||||
* Alle 2 s komplett, damit ein verlorenes UDP-Paket nichts ausmacht.
|
||||
*/
|
||||
private void sendParticipants() {
|
||||
try {
|
||||
for (Room room : rooms.values()) {
|
||||
if (!room.active()) continue;
|
||||
List<String> speakers = room.externalSpeakers(SPEAKING_MILLIS);
|
||||
if (!speakers.isEmpty()) plugin.sendSpeakers(room.key(), speakers);
|
||||
DiscordRoomBot bot = discordBots.get(room.key());
|
||||
List<Message.Member> members = new ArrayList<>();
|
||||
if (teamspeak != null && teamspeak.ready()) {
|
||||
teamspeak.participants(room).forEach((id, name) ->
|
||||
members.add(new Message.Member(room.sourceUuid("ts:" + id), name + " [TeamSpeak]")));
|
||||
}
|
||||
if (bot != null && bot.ready()) {
|
||||
bot.participants().forEach((id, name) ->
|
||||
members.add(new Message.Member(room.sourceUuid("dc:" + id), name + " [Discord]")));
|
||||
}
|
||||
plugin.sendParticipants(room.key(), members);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
LOG.warn("Sprecher-Anzeige fehlgeschlagen", e);
|
||||
LOG.warn("Teilnehmer-Abgleich fehlgeschlagen", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@ final class PluginLink {
|
||||
if (target != null && alive()) send(new Message.Notice(room, text), target);
|
||||
}
|
||||
|
||||
void sendSpeakers(String room, List<String> names) {
|
||||
void sendParticipants(String room, List<Message.Member> members) {
|
||||
SocketAddress target = plugin;
|
||||
if (target != null && alive()) send(new Message.Speakers(room, names), target);
|
||||
if (target != null && alive()) send(new Message.Participants(room, members), target);
|
||||
}
|
||||
|
||||
void sendAudio(String room, UUID source, byte[] opus) {
|
||||
@@ -121,7 +121,7 @@ final class PluginLink {
|
||||
}
|
||||
case Message.Rooms ignored -> {}
|
||||
case Message.Notice ignored -> {}
|
||||
case Message.Speakers ignored -> {}
|
||||
case Message.Participants ignored -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@@ -36,9 +35,6 @@ public final class Room {
|
||||
private final Mixer toDiscord = new Mixer();
|
||||
private final Map<String, Source> sources = new ConcurrentHashMap<>();
|
||||
|
||||
/** Anzeigename eines Sprechers (Seite, ID ohne Präfix), für die Actionbar. */
|
||||
private volatile BiFunction<Side, String, String> names = (side, id) -> id;
|
||||
|
||||
/** Wohin Frames für Minecraft gehen (Plugin-Verbindung). */
|
||||
private volatile MinecraftSink minecraft = (room, source, opus) -> {};
|
||||
|
||||
@@ -59,13 +55,12 @@ public final class Room {
|
||||
final FrameSplitter splitter = new FrameSplitter();
|
||||
OpusEncoder minecraftEncoder;
|
||||
volatile long lastSeen;
|
||||
volatile String name;
|
||||
int lastSequence = -1;
|
||||
|
||||
Source(Side side, String key) {
|
||||
this.side = side;
|
||||
this.key = key;
|
||||
this.uuid = UUID.nameUUIDFromBytes(("voicebridge:" + config.key() + ":" + key).getBytes(StandardCharsets.UTF_8));
|
||||
this.uuid = sourceUuid(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,15 +78,13 @@ public final class Room {
|
||||
public Mixer toDiscord() { return toDiscord; }
|
||||
|
||||
public void setMinecraftSink(MinecraftSink sink) { this.minecraft = sink; }
|
||||
public void setNameResolver(BiFunction<Side, String, String> names) { this.names = names; }
|
||||
|
||||
/** Wer aus Discord/TeamSpeak in den letzten {@code millis} Audio geschickt hat, als "Name|Kürzel". */
|
||||
public List<String> externalSpeakers(long millis) {
|
||||
long since = System.currentTimeMillis() - millis;
|
||||
return sources.values().stream()
|
||||
.filter(s -> s.side != Side.MINECRAFT && s.lastSeen >= since)
|
||||
.map(s -> s.name + "|" + (s.side == Side.DISCORD ? "DC" : "TS"))
|
||||
.sorted().toList();
|
||||
/**
|
||||
* Feste UUID eines Sprechers, z. B. {@code ts:5} oder {@code dc:1234}. Unter ihr läuft sein Audio im Spiel,
|
||||
* und unter ihr erscheint er auch in der Gruppenanzeige des Voicechats.
|
||||
*/
|
||||
public UUID sourceUuid(String key) {
|
||||
return UUID.nameUUIDFromBytes(("voicebridge:" + config.key() + ":" + key).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static String label(Side side) {
|
||||
@@ -132,7 +125,6 @@ public final class Room {
|
||||
if (!active || opus.length == 0) return;
|
||||
Source source = sources.computeIfAbsent(key, k -> new Source(side, k));
|
||||
source.lastSeen = System.currentTimeMillis();
|
||||
if (source.name == null) source.name = names.apply(side, key.substring(3));
|
||||
|
||||
List<short[]> frames = new ArrayList<>(2);
|
||||
try {
|
||||
|
||||
@@ -152,13 +152,6 @@ public final class DiscordRoomBot implements AudioSendHandler, AudioReceiveHandl
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Anzeigename eines Users, für die Sprecher-Anzeige. */
|
||||
public String name(long userId) {
|
||||
Guild guild = this.guild;
|
||||
Member member = guild == null ? null : guild.getMemberById(userId);
|
||||
return member == null ? "?" : member.getEffectiveName();
|
||||
}
|
||||
|
||||
/** Ob der Bot eingeloggt ist und seinen Channel kennt. */
|
||||
public boolean ready() {
|
||||
return guild != null && channelId != 0;
|
||||
|
||||
@@ -89,12 +89,6 @@ public final class TeamspeakSide {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Nickname eines Clients, für die Sprecher-Anzeige. */
|
||||
public String nickname(int clientId) {
|
||||
TsClient client = clients.get(clientId);
|
||||
return client == null ? "?" : client.name();
|
||||
}
|
||||
|
||||
/** Ob der Raum-Client gerade im Channel ist. */
|
||||
public boolean roomConnected(Room room) {
|
||||
TeamspeakRoomClient client = roomClients.get(room.key());
|
||||
|
||||
Reference in new issue
Block a user