Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5429ee4c6 |
No files matched your search
@@ -33,7 +33,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
latest="$(git tag --list 'v[0-9]*' --sort=-version:refname | head -n 1)"
|
latest="$(git tag --list 'v[0-9]*' --sort=-version:refname | head -n 1)"
|
||||||
if [[ -z "$latest" ]]; then
|
if [[ -z "$latest" ]]; then
|
||||||
version="1.0.1"
|
version="1.0.3"
|
||||||
else
|
else
|
||||||
current="${latest#v}"
|
current="${latest#v}"
|
||||||
IFS='.' read -r major minor patch <<< "$current"
|
IFS='.' read -r major minor patch <<< "$current"
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ build/
|
|||||||
*.class
|
*.class
|
||||||
*.log
|
*.log
|
||||||
/LOCAL_AI_NOTES.md
|
/LOCAL_AI_NOTES.md
|
||||||
|
AsminVoiceChat-*.jar
|
||||||
Binary file not shown.
@@ -10,8 +10,12 @@ The plugin is compiled to Java 8 bytecode and runs on newer JVMs.
|
|||||||
The server negotiates the protocol generation during the existing voice-chat
|
The server negotiates the protocol generation during the existing voice-chat
|
||||||
handshake and stores it with that player's 16-byte secret. The UDP path then
|
handshake and stores it with that player's 16-byte secret. The UDP path then
|
||||||
uses AES-CBC for 2.5 clients and AES-GCM for 2.6 clients. Shared packet layouts
|
uses AES-CBC for 2.5 clients and AES-GCM for 2.6 clients. Shared packet layouts
|
||||||
are passed through the existing 2.6 voice routing. The fork changes only the
|
are passed through the existing 2.6 voice routing. State messages are sent on
|
||||||
per-client cipher selection and compatibility-version acceptance.
|
the channel names expected by each client generation, so 2.5 clients receive
|
||||||
|
their player and group-member updates as well. For compatibility 18 the server
|
||||||
|
maps `voicechat:state` and `voicechat:states` to the older
|
||||||
|
`voicechat:player_state` and `voicechat:player_states` channels. When a player
|
||||||
|
leaves, it sends the disconnected state because 2.5 has no remove-state packet.
|
||||||
|
|
||||||
The Bukkit plugin source and API source are in `source/bukkit/` and
|
The Bukkit plugin source and API source are in `source/bukkit/` and
|
||||||
`source/api/`. The cipher and compatibility changes are in the regular source
|
`source/api/`. The cipher and compatibility changes are in the regular source
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = 'de.maxhenkel.voicechat'
|
group = 'de.maxhenkel.voicechat'
|
||||||
version = findProperty('buildVersion') ?: '1.0.1'
|
version = findProperty('buildVersion') ?: '1.0.3'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
name: AsminVoicechat
|
name: AsminVoicechat
|
||||||
version: 1.0.1
|
version: 1.0.3
|
||||||
main: de.maxhenkel.voicechat.Voicechat
|
main: de.maxhenkel.voicechat.Voicechat
|
||||||
api-version: '1.13'
|
api-version: '1.13'
|
||||||
prefix: AsminVoicechat
|
prefix: AsminVoicechat
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ public class VoiceChatCommands implements CommandExecutor, TabCompleter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clientCompatibilityVersion = Voicechat.SERVER.getClientCompatibilityVersion(player.getUniqueId());
|
||||||
|
|
||||||
ClientConnection clientConnection = Voicechat.SERVER.getServer().getConnections().get(player.getUniqueId());
|
ClientConnection clientConnection = Voicechat.SERVER.getServer().getConnections().get(player.getUniqueId());
|
||||||
|
|
||||||
if (clientConnection == null) {
|
if (clientConnection == null) {
|
||||||
@@ -130,6 +132,8 @@ public class VoiceChatCommands implements CommandExecutor, TabCompleter {
|
|||||||
} else {
|
} else {
|
||||||
NetManager.sendMessage(commandSender, "message.voicechat.ping_received_attempt", String.valueOf(pingMilliseconds), String.valueOf(attempts));
|
NetManager.sendMessage(commandSender, "message.voicechat.ping_received_attempt", String.valueOf(pingMilliseconds), String.valueOf(attempts));
|
||||||
}
|
}
|
||||||
|
commandSender.sendMessage("Voice chat connection verified (client compatibility version "
|
||||||
|
+ clientCompatibilityVersion + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -326,4 +330,4 @@ public class VoiceChatCommands implements CommandExecutor, TabCompleter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,133 +27,97 @@ public class ServerConfig {
|
|||||||
public ConfigEntry<Boolean> threadedServerSupport;
|
public ConfigEntry<Boolean> threadedServerSupport;
|
||||||
|
|
||||||
public ServerConfig(ConfigBuilder builder) {
|
public ServerConfig(ConfigBuilder builder) {
|
||||||
builder.header(String.format("AsminVoiceChat (Simple Voice Chat) server config v%s", Voicechat.INSTANCE.getDescription().getVersion()));
|
builder.header("AsminVoiceChat (Simple Voice Chat) server config v1.0.2");
|
||||||
|
|
||||||
voiceChatPort = builder
|
voiceChatPort = builder
|
||||||
.integerEntry("port", 24454, -1, 65535,
|
.integerEntry("port", 24454, -1, 65535,
|
||||||
"EN: The port number to use for the voice chat communication.",
|
"The port number to use for the voice chat communication.",
|
||||||
"PL: Port używany do komunikacji czatu głosowego.",
|
"Audio packets are always transmitted via the UDP protocol on the port number",
|
||||||
"EN: Audio packets are always transmitted via the UDP protocol on the port number",
|
"specified here, independently of other networking used for the game server.",
|
||||||
"PL: Pakiety audio są zawsze przesyłane przez UDP na porcie wskazanym tutaj,",
|
"Set this to '-1' to use the same port number that is used by the Minecraft server.",
|
||||||
"EN: specified here, independently of other networking used for the game server.",
|
"However, it is strongly recommended NOT to use the same port number because UDP on",
|
||||||
"PL: niezależnie od pozostałej komunikacji sieciowej serwera gry.",
|
"it is also used by default for the server query. Doing so may crash the server!"
|
||||||
"EN: Set this to '-1' to use the same port number that is used by the Minecraft server.",
|
|
||||||
"PL: Ustaw '-1', aby użyć tego samego portu co serwer Minecraft.",
|
|
||||||
"EN: However, it is strongly recommended NOT to use the same port number because UDP on",
|
|
||||||
"PL: Zdecydowanie zaleca się użycie innego portu, ponieważ UDP na tym porcie jest domyślnie używane także przez zapytania serwera.",
|
|
||||||
"EN: it is also used by default for the server query. Doing so may crash the server!",
|
|
||||||
"PL: Użycie tego samego portu może spowodować awarię serwera!"
|
|
||||||
);
|
);
|
||||||
voiceChatBindAddress = builder
|
voiceChatBindAddress = builder
|
||||||
.stringEntry("bind_address", "",
|
.stringEntry("bind_address", "",
|
||||||
"EN: The server IP address to bind the voice chat to",
|
"The server IP address to bind the voice chat to",
|
||||||
"PL: Adres IP serwera, na którym ma nasłuchiwać czat głosowy.",
|
"Leave blank to use the 'server-ip' property from the 'server.properties' config file",
|
||||||
"EN: Leave blank to use the 'server-ip' property from the 'server.properties' config file",
|
"To bind to the wildcard IP address, use '*'"
|
||||||
"PL: Pozostaw puste, aby użyć wartości 'server-ip' z pliku 'server.properties'.",
|
|
||||||
"EN: To bind to the wildcard IP address, use '*'",
|
|
||||||
"PL: Aby nasłuchiwać na wszystkich interfejsach sieciowych, wpisz '*'."
|
|
||||||
);
|
);
|
||||||
voiceChatDistance = builder
|
voiceChatDistance = builder
|
||||||
.doubleEntry("max_voice_distance", 48D, 1D, 1_000_000D,
|
.doubleEntry("max_voice_distance", 48D, 1D, 1_000_000D,
|
||||||
"EN: The distance to which the voice can be heard",
|
"The distance to which the voice can be heard"
|
||||||
"PL: Maksymalna odległość, z której słychać głos."
|
|
||||||
);
|
);
|
||||||
whisperDistance = builder
|
whisperDistance = builder
|
||||||
.doubleEntry("whisper_distance", 24D, 1D, 1_000_000D,
|
.doubleEntry("whisper_distance", 24D, 1D, 1_000_000D,
|
||||||
"EN: The distance to which the voice can be heard when whispering",
|
"The distance to which the voice can be heard when whispering"
|
||||||
"PL: Maksymalna odległość, z której słychać szept."
|
|
||||||
);
|
);
|
||||||
voiceChatCodec = builder
|
voiceChatCodec = builder
|
||||||
.enumEntry("codec", Codec.VOIP,
|
.enumEntry("codec", Codec.VOIP,
|
||||||
"EN: The Opus codec",
|
"The Opus codec",
|
||||||
"PL: Używany kodek Opus.",
|
"Valid values are 'VOIP', 'AUDIO', and 'RESTRICTED_LOWDELAY'"
|
||||||
"EN: Valid values are 'VOIP', 'AUDIO', and 'RESTRICTED_LOWDELAY'",
|
|
||||||
"PL: Dozwolone wartości: 'VOIP', 'AUDIO' oraz 'RESTRICTED_LOWDELAY'."
|
|
||||||
);
|
);
|
||||||
voiceChatMtuSize = builder
|
voiceChatMtuSize = builder
|
||||||
.integerEntry("mtu_size", AudioUtils.MAX_OPUS_PAYLOAD_SIZE, 512, 2048,
|
.integerEntry("mtu_size", AudioUtils.MAX_OPUS_PAYLOAD_SIZE, 512, 2048,
|
||||||
"EN: The maximum size that audio packets are allowed to have (in bytes)",
|
"The maximum size that audio packets are allowed to have (in bytes)",
|
||||||
"PL: Maksymalny rozmiar pakietu audio w bajtach.",
|
"Setting this to lower values might cause issues"
|
||||||
"EN: Setting this to lower values might cause issues",
|
|
||||||
"PL: Ustawienie mniejszej wartości może powodować problemy."
|
|
||||||
);
|
);
|
||||||
tcpRateLimit = builder
|
tcpRateLimit = builder
|
||||||
.integerEntry("tcp_rate_limit", 16, -1, 1024,
|
.integerEntry("tcp_rate_limit", 16, -1, 1024,
|
||||||
"EN: The maximum number of packets a player can send per second",
|
"The maximum number of packets a player can send per second",
|
||||||
"PL: Maksymalna liczba pakietów, które gracz może wysłać w ciągu sekundy.",
|
"Set this to -1 to disable the rate limit - This must be greater than 0 in all other cases",
|
||||||
"EN: Set this to -1 to disable the rate limit - This must be greater than 0 in all other cases",
|
"This only applies to voice chat packets that are sent through Minecrafts networking",
|
||||||
"PL: Ustaw '-1', aby wyłączyć limit. W pozostałych przypadkach wartość musi być większa od 0.",
|
"This affects actions like opening/joining/leaving voice chat groups or general state changes like disabling/enabling the voice chat"
|
||||||
"EN: This only applies to voice chat packets that are sent through Minecrafts networking",
|
|
||||||
"PL: Limit dotyczy tylko pakietów voice chatu przesyłanych przez sieć Minecrafta.",
|
|
||||||
"EN: This affects actions like opening/joining/leaving voice chat groups or general state changes like disabling/enabling the voice chat",
|
|
||||||
"PL: Obejmuje m.in. otwieranie, dołączanie i opuszczanie grup oraz włączanie lub wyłączanie voice chatu."
|
|
||||||
);
|
);
|
||||||
keepAlive = builder
|
keepAlive = builder
|
||||||
.integerEntry("keep_alive", 1000, 1000, Integer.MAX_VALUE,
|
.integerEntry("keep_alive", 1000, 1000, Integer.MAX_VALUE,
|
||||||
"EN: The frequency at which keep-alive packets are sent (in milliseconds)",
|
"The frequency at which keep-alive packets are sent (in milliseconds)",
|
||||||
"PL: Częstotliwość wysyłania pakietów keep-alive w milisekundach.",
|
"Setting this to a higher value may result in timeouts"
|
||||||
"EN: Setting this to a higher value may result in timeouts",
|
|
||||||
"PL: Ustawienie większej wartości może powodować przekroczenia czasu połączenia."
|
|
||||||
);
|
);
|
||||||
groupsEnabled = builder
|
groupsEnabled = builder
|
||||||
.booleanEntry("enable_groups", true,
|
.booleanEntry("enable_groups", true,
|
||||||
"EN: If group chats are allowed",
|
"If group chats are allowed"
|
||||||
"PL: Czy rozmowy grupowe są dozwolone."
|
|
||||||
);
|
);
|
||||||
voiceHost = builder
|
voiceHost = builder
|
||||||
.stringEntry("voice_host", "",
|
.stringEntry("voice_host", "",
|
||||||
"EN: The hostname that clients should use to connect to the voice chat",
|
"The hostname that clients should use to connect to the voice chat",
|
||||||
"PL: Nazwa hosta, której klienci używają do łączenia się z voice chatem.",
|
"This may also include a port, e.g. 'example.com:24454'",
|
||||||
"EN: This may also include a port, e.g. 'example.com:24454'",
|
"Do NOT change this value if you don't know what you're doing"
|
||||||
"PL: Możesz podać również port, np. 'example.com:24454'.",
|
|
||||||
"EN: Do NOT change this value if you don't know what you're doing",
|
|
||||||
"PL: Nie zmieniaj tej wartości, jeśli nie wiesz, do czego służy."
|
|
||||||
);
|
);
|
||||||
allowRecording = builder
|
allowRecording = builder
|
||||||
.booleanEntry("allow_recording", true,
|
.booleanEntry("allow_recording", true,
|
||||||
"EN: If players are allowed to record the voice chat audio",
|
"If players are allowed to record the voice chat audio"
|
||||||
"PL: Czy gracze mogą nagrywać dźwięk z voice chatu."
|
|
||||||
);
|
);
|
||||||
spectatorInteraction = builder
|
spectatorInteraction = builder
|
||||||
.booleanEntry("spectator_interaction", false,
|
.booleanEntry("spectator_interaction", false,
|
||||||
"EN: If spectators are allowed to talk to other players",
|
"If spectators are allowed to talk to other players"
|
||||||
"PL: Czy widzowie mogą rozmawiać z innymi graczami."
|
|
||||||
);
|
);
|
||||||
spectatorPlayerPossession = builder
|
spectatorPlayerPossession = builder
|
||||||
.booleanEntry("spectator_player_possession", false,
|
.booleanEntry("spectator_player_possession", false,
|
||||||
"EN: If spectators can talk to players they are spectating",
|
"If spectators can talk to players they are spectating"
|
||||||
"PL: Czy widz może rozmawiać z graczem, którego obserwuje."
|
|
||||||
);
|
);
|
||||||
forceVoiceChat = builder
|
forceVoiceChat = builder
|
||||||
.booleanEntry("force_voice_chat", false,
|
.booleanEntry("force_voice_chat", false,
|
||||||
"EN: If players without the voice chat mod should be kicked from the server",
|
"If players without the voice chat mod should be kicked from the server"
|
||||||
"PL: Czy gracze bez moda voice chatu mają być wyrzucani z serwera."
|
|
||||||
);
|
);
|
||||||
loginTimeout = builder
|
loginTimeout = builder
|
||||||
.integerEntry("login_timeout", 10_000, 100, Integer.MAX_VALUE,
|
.integerEntry("login_timeout", 10_000, 100, Integer.MAX_VALUE,
|
||||||
"EN: The amount of time the server should wait to check if a player has the mod installed (in milliseconds)",
|
"The amount of time the server should wait to check if a player has the mod installed (in milliseconds)",
|
||||||
"PL: Czas oczekiwania na sprawdzenie, czy gracz ma zainstalowany mod, w milisekundach.",
|
"Only relevant when 'force_voice_chat' is set to 'true'"
|
||||||
"EN: Only relevant when 'force_voice_chat' is set to 'true'",
|
|
||||||
"PL: Używane tylko wtedy, gdy 'force_voice_chat' ma wartość 'true'."
|
|
||||||
);
|
);
|
||||||
broadcastRange = builder
|
broadcastRange = builder
|
||||||
.doubleEntry("broadcast_range", -1D, -1D, Double.MAX_VALUE,
|
.doubleEntry("broadcast_range", -1D, -1D, Double.MAX_VALUE,
|
||||||
"EN: The range in which the voice chat should broadcast audio",
|
"The range in which the voice chat should broadcast audio",
|
||||||
"PL: Zasięg, w którym voice chat rozsyła dźwięk.",
|
"A value less than 0 means 'max_voice_distance'"
|
||||||
"EN: A value less than 0 means 'max_voice_distance'",
|
|
||||||
"PL: Wartość mniejsza od 0 oznacza użycie 'max_voice_distance'."
|
|
||||||
);
|
);
|
||||||
allowPings = builder
|
allowPings = builder
|
||||||
.booleanEntry("allow_pings", true,
|
.booleanEntry("allow_pings", true,
|
||||||
"EN: If the voice chat server should reply to external pings",
|
"If the voice chat server should reply to external pings"
|
||||||
"PL: Czy serwer voice chatu ma odpowiadać na zewnętrzne pingi."
|
|
||||||
);
|
);
|
||||||
threadedServerSupport = builder
|
threadedServerSupport = builder
|
||||||
.booleanEntry("threaded_server_support", true,
|
.booleanEntry("threaded_server_support", true,
|
||||||
"EN: If the voice chat should support servers that run multiple threads, like Folia",
|
"If the voice chat should support servers that run multiple threads, like Folia",
|
||||||
"PL: Czy voice chat ma obsługiwać serwery wielowątkowe, takie jak Folia.",
|
"Disabling this may slightly improve performance, but can cause issues on servers that don't run everything on a single thread"
|
||||||
"EN: Disabling this may slightly improve performance, but can cause issues on servers that don't run everything on a single thread",
|
|
||||||
"PL: Wyłączenie może nieznacznie poprawić wydajność, ale powodować problemy na serwerach, które nie wykonują wszystkiego na jednym wątku."
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ public class NetManager implements Listener {
|
|||||||
registerOutgoingPacket(JoinedGroupPacket.class);
|
registerOutgoingPacket(JoinedGroupPacket.class);
|
||||||
registerOutgoingPacket(AddCategoryPacket.class);
|
registerOutgoingPacket(AddCategoryPacket.class);
|
||||||
registerOutgoingPacket(RemoveCategoryPacket.class);
|
registerOutgoingPacket(RemoveCategoryPacket.class);
|
||||||
|
|
||||||
|
registerOutgoingChannel(ProtocolChannelCompatibility.LEGACY_PLAYER_STATE);
|
||||||
|
registerOutgoingChannel(ProtocolChannelCompatibility.LEGACY_PLAYER_STATES);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException("Failed to register voice chat packets", e);
|
throw new IllegalStateException("Failed to register voice chat packets", e);
|
||||||
}
|
}
|
||||||
@@ -100,6 +103,10 @@ public class NetManager implements Listener {
|
|||||||
|
|
||||||
private <T extends Packet<?>> void registerOutgoingPacket(Class<T> packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
private <T extends Packet<?>> void registerOutgoingPacket(Class<T> packetClass) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
||||||
String id = packetClass.getDeclaredConstructor().newInstance().getID().toString();
|
String id = packetClass.getDeclaredConstructor().newInstance().getID().toString();
|
||||||
|
registerOutgoingChannel(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerOutgoingChannel(String id) {
|
||||||
packets.add(id);
|
packets.add(id);
|
||||||
Bukkit.getMessenger().registerOutgoingPluginChannel(Voicechat.INSTANCE, id);
|
Bukkit.getMessenger().registerOutgoingPluginChannel(Voicechat.INSTANCE, id);
|
||||||
}
|
}
|
||||||
@@ -114,7 +121,11 @@ public class NetManager implements Listener {
|
|||||||
p.toBytes(buf);
|
p.toBytes(buf);
|
||||||
byte[] bytes = new byte[buf.readableBytes()];
|
byte[] bytes = new byte[buf.readableBytes()];
|
||||||
buf.readBytes(bytes);
|
buf.readBytes(bytes);
|
||||||
player.sendPluginMessage(Voicechat.INSTANCE, p.getID().toString(), bytes);
|
int compatibilityVersion = Voicechat.SERVER.getClientCompatibilityVersion(player.getUniqueId());
|
||||||
|
String channel = ProtocolChannelCompatibility.outgoingChannel(p.getID().toString(), compatibilityVersion);
|
||||||
|
if (channel != null) {
|
||||||
|
player.sendPluginMessage(Voicechat.INSTANCE, channel, bytes);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Voicechat.LOGGER.error("Failed to send packet to '{}'", player.getName(), e);
|
Voicechat.LOGGER.error("Failed to send packet to '{}'", player.getName(), e);
|
||||||
}
|
}
|
||||||
@@ -129,4 +140,4 @@ public class NetManager implements Listener {
|
|||||||
Voicechat.compatibility.sendStatusMessage(player, key, args);
|
Voicechat.compatibility.sendStatusMessage(player, key, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package de.maxhenkel.voicechat.net;
|
||||||
|
|
||||||
|
public final class ProtocolChannelCompatibility {
|
||||||
|
public static final int LEGACY_COMPATIBILITY_VERSION = 18;
|
||||||
|
|
||||||
|
public static final String LEGACY_PLAYER_STATE = "voicechat:player_state";
|
||||||
|
public static final String LEGACY_PLAYER_STATES = "voicechat:player_states";
|
||||||
|
|
||||||
|
private ProtocolChannelCompatibility() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String outgoingChannel(String channel, int compatibilityVersion) {
|
||||||
|
if (compatibilityVersion != LEGACY_COMPATIBILITY_VERSION) {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
switch (channel) {
|
||||||
|
case "voicechat:state":
|
||||||
|
return LEGACY_PLAYER_STATE;
|
||||||
|
case "voicechat:states":
|
||||||
|
return LEGACY_PLAYER_STATES;
|
||||||
|
case "voicechat:remove_state":
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-4
@@ -56,8 +56,7 @@ public class PlayerStateManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onPlayerHide(PlayerHideEvent event) {
|
public void onPlayerHide(PlayerHideEvent event) {
|
||||||
RemovePlayerStatePacket packet = new RemovePlayerStatePacket(event.getHiddenPlayer().getUniqueId());
|
sendRemoveState(event.getObserver(), event.getHiddenPlayer());
|
||||||
NetManager.sendToClient(event.getObserver(), packet);
|
|
||||||
Voicechat.LOGGER.debug("Removing state of {} for {}", event.getHiddenPlayer().getName(), event.getObserver().getName());
|
Voicechat.LOGGER.debug("Removing state of {} for {}", event.getHiddenPlayer().getName(), event.getObserver().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +82,22 @@ public class PlayerStateManager implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void broadcastRemoveState(Player stateOwner) {
|
public void broadcastRemoveState(Player stateOwner) {
|
||||||
RemovePlayerStatePacket packet = new RemovePlayerStatePacket(stateOwner.getUniqueId());
|
|
||||||
for (Player receiver : Voicechat.INSTANCE.getServer().getOnlinePlayers()) {
|
for (Player receiver : Voicechat.INSTANCE.getServer().getOnlinePlayers()) {
|
||||||
NetManager.sendToClient(receiver, packet);
|
sendRemoveState(receiver, stateOwner);
|
||||||
}
|
}
|
||||||
// Send the default disconnected state to the API when disconnecting
|
// Send the default disconnected state to the API when disconnecting
|
||||||
PluginManager.instance().onPlayerStateChanged(defaultDisconnectedState(stateOwner));
|
PluginManager.instance().onPlayerStateChanged(defaultDisconnectedState(stateOwner));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendRemoveState(Player receiver, Player stateOwner) {
|
||||||
|
if (Voicechat.SERVER.getClientCompatibilityVersion(receiver.getUniqueId())
|
||||||
|
== de.maxhenkel.voicechat.net.ProtocolChannelCompatibility.LEGACY_COMPATIBILITY_VERSION) {
|
||||||
|
NetManager.sendToClient(receiver, new PlayerStatePacket(defaultDisconnectedState(stateOwner)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NetManager.sendToClient(receiver, new RemovePlayerStatePacket(stateOwner.getUniqueId()));
|
||||||
|
}
|
||||||
|
|
||||||
public void onPlayerCompatibilityCheckSucceeded(Player player) {
|
public void onPlayerCompatibilityCheckSucceeded(Player player) {
|
||||||
List<PlayerState> stateList = new ArrayList<>(states.size());
|
List<PlayerState> stateList = new ArrayList<>(states.size());
|
||||||
for (PlayerState state : states.values()) {
|
for (PlayerState state : states.values()) {
|
||||||
|
|||||||
@@ -83,6 +83,10 @@ public class ServerVoiceEvents implements Listener {
|
|||||||
return isSupportedCompatibilityVersion(clientCompatibilities.getOrDefault(playerUuid, -1));
|
return isSupportedCompatibilityVersion(clientCompatibilities.getOrDefault(playerUuid, -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getClientCompatibilityVersion(UUID playerUuid) {
|
||||||
|
return clientCompatibilities.getOrDefault(playerUuid, -1);
|
||||||
|
}
|
||||||
|
|
||||||
public static void sendIncompatibleMessage(Player player, int clientCompatibilityVersion) {
|
public static void sendIncompatibleMessage(Player player, int clientCompatibilityVersion) {
|
||||||
if (clientCompatibilityVersion <= 6) {
|
if (clientCompatibilityVersion <= 6) {
|
||||||
player.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNotCompatibleMessage.get(),
|
player.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNotCompatibleMessage.get(),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import de.maxhenkel.voicechat.voice.common.Secret;
|
import de.maxhenkel.voicechat.voice.common.Secret;
|
||||||
|
import de.maxhenkel.voicechat.net.ProtocolChannelCompatibility;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -9,6 +10,8 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
|
|
||||||
public class ProtocolCryptoSelfTest {
|
public class ProtocolCryptoSelfTest {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
testStateChannelCompatibility();
|
||||||
|
|
||||||
byte[] key = new byte[16];
|
byte[] key = new byte[16];
|
||||||
for (int i = 0; i < key.length; i++) key[i] = (byte) (i * 13 + 7);
|
for (int i = 0; i < key.length; i++) key[i] = (byte) (i * 13 + 7);
|
||||||
UUID legacyKey = uuidFromBytes(key);
|
UUID legacyKey = uuidFromBytes(key);
|
||||||
@@ -34,7 +37,23 @@ public class ProtocolCryptoSelfTest {
|
|||||||
throw new AssertionError("Hybrid server AES-GCM round-trip failed");
|
throw new AssertionError("Hybrid server AES-GCM round-trip failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.out.println("PASS: 100 CBC client/server interop cycles and 100 GCM round-trips");
|
System.out.println("PASS: legacy state-channel mapping, 100 CBC interop cycles and 100 GCM round-trips");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testStateChannelCompatibility() {
|
||||||
|
check("voicechat:player_state", ProtocolChannelCompatibility.outgoingChannel("voicechat:state", 18));
|
||||||
|
check("voicechat:player_states", ProtocolChannelCompatibility.outgoingChannel("voicechat:states", 18));
|
||||||
|
if (ProtocolChannelCompatibility.outgoingChannel("voicechat:remove_state", 18) != null) {
|
||||||
|
throw new AssertionError("The 2.5 client has no remove-state packet");
|
||||||
|
}
|
||||||
|
check("voicechat:state", ProtocolChannelCompatibility.outgoingChannel("voicechat:state", 20));
|
||||||
|
check("voicechat:states", ProtocolChannelCompatibility.outgoingChannel("voicechat:states", 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void check(String expected, String actual) {
|
||||||
|
if (!expected.equals(actual)) {
|
||||||
|
throw new AssertionError("Expected channel " + expected + ", got " + actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UUID uuidFromBytes(byte[] bytes) {
|
private static UUID uuidFromBytes(byte[] bytes) {
|
||||||
|
|||||||
Reference in new issue
Block a user