first commit
Build AsminVoicechat / prepare-release (push) Successful in 14s
Build AsminVoicechat / build-and-test (17) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (18) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (19) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (20) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (21) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (22) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (23) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (24) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (25) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (26) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (27-ea) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (16) (push) Canceled after 38s

This commit is contained in:
asminme committed 2026-10-24 15:18:03 +02:00
commit bbccd4a815
454 files changed
+45050

No files matched your search

+177
View File
@@ -0,0 +1,177 @@
name: Build AsminVoicechat
run-name: Build AsminVoicechat
on:
push:
branches:
- main
- master
workflow_dispatch:
concurrency:
group: asmin-voicechat-release
cancel-in-progress: false
jobs:
prepare-release:
runs-on: docker-builder
outputs:
version: ${{ steps.version.outputs.version }}
tag: ${{ steps.version.outputs.tag }}
release_id: ${{ steps.release.outputs.release_id }}
steps:
- name: Checkout repository and tags
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Calculate next version
id: version
shell: bash
run: |
latest="$(git tag --list 'v[0-9]*' --sort=-version:refname | head -n 1)"
if [[ -z "$latest" ]]; then
version="1.0.0"
else
current="${latest#v}"
IFS='.' read -r major minor patch <<< "$current"
if (( patch >= 9 )); then
version="$major.$((minor + 1)).0"
else
version="$major.$minor.$((patch + 1))"
fi
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "tag=v$version" >> "$GITHUB_OUTPUT"
- name: Create Gitea release
id: release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_SERVER_URL: ${{ gitea.server_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
VERSION: ${{ steps.version.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
shell: bash
run: |
set -euo pipefail
if [[ -z "$GITEA_TOKEN" ]]; then
echo "Add a repository write token as the GITEA_TOKEN secret."
exit 1
fi
api="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY"
release="$(curl --fail-with-body -sS -X POST "$api/releases" \
-H "Authorization: token $GITEA_TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"tag_name\":\"$TAG\",\"name\":\"AsminVoiceChat $VERSION\",\"body\":\"Dual-protocol Simple Voice Chat server release.\",\"draft\":false,\"prerelease\":false}")"
release_id="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<< "$release")"
echo "release_id=$release_id" >> "$GITHUB_OUTPUT"
build-and-test:
needs: prepare-release
runs-on: docker-builder
strategy:
fail-fast: false
matrix:
java:
- '16'
- '17'
- '18'
- '19'
- '20'
- '21'
- '22'
- '23'
- '24'
- '25'
- '26'
- '27-ea'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Java ${{ matrix.java }}
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.java }}
- name: Download 2.6.25 base and compile dependencies
shell: bash
run: |
set -euo pipefail
mkdir -p build/deps build/classes build/test-classes
hangar="https://hangarcdn.papermc.io/plugins/henkelmax/SimpleVoiceChat/versions/bukkit-2.6.25/PAPER/voicechat-bukkit-2.6.25.jar"
curl --fail --location --silent --show-error "$hangar" -o build/deps/voicechat-bukkit-2.6.25.jar
repo="https://repo.papermc.io/repository/maven-public"
curl --fail --location --silent --show-error "$repo/io/papermc/paper/paper-api/1.17.1-R0.1-SNAPSHOT/paper-api-1.17.1-R0.1-20220414.034903-311.jar" -o build/deps/paper-api.jar
curl --fail --location --silent --show-error "$repo/net/md-5/bungeecord-chat/1.16-R0.4/bungeecord-chat-1.16-R0.4.jar" -o build/deps/bungeecord-chat.jar
curl --fail --location --silent --show-error "$repo/net/kyori/adventure-api/4.9.3/adventure-api-4.9.3.jar" -o build/deps/adventure-api.jar
curl --fail --location --silent --show-error "$repo/net/kyori/adventure-key/4.9.3/adventure-key-4.9.3.jar" -o build/deps/adventure-key.jar
curl --fail --location --silent --show-error "$repo/net/kyori/examination-api/1.3.0/examination-api-1.3.0.jar" -o build/deps/examination-api.jar
curl --fail --location --silent --show-error "$repo/net/kyori/examination-string/1.3.0/examination-string-1.3.0.jar" -o build/deps/examination-string.jar
curl --fail --location --silent --show-error "$repo/org/jetbrains/annotations/22.0.0/annotations-22.0.0.jar" -o build/deps/annotations.jar
curl --fail --location --silent --show-error "$repo/io/netty/netty-buffer/4.1.63.Final/netty-buffer-4.1.63.Final.jar" -o build/deps/netty-buffer.jar
curl --fail --location --silent --show-error "$repo/io/netty/netty-common/4.1.63.Final/netty-common-4.1.63.Final.jar" -o build/deps/netty-common.jar
- name: Compile Java 8-compatible patch classes
env:
VERSION: ${{ needs.prepare-release.outputs.version }}
shell: bash
run: |
set -euo pipefail
cp="build/deps/voicechat-bukkit-2.6.25.jar:$(printf '%s:' build/deps/*.jar)"
javac --release 8 -cp "$cp" -d build/classes \
source/patch/de/maxhenkel/voicechat/voice/common/Secret.java \
source/patch/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.java
sed "s/^version:.*/version: '$VERSION'/" plugin.yml > build/plugin.yml
python3 - <<'PY'
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
base = Path("build/deps/voicechat-bukkit-2.6.25.jar")
target = Path("build/AsminVoiceChat-${{ needs.prepare-release.outputs.version }}.jar")
replacements = {
"de/maxhenkel/voicechat/voice/common/Secret.class": Path("build/classes/de/maxhenkel/voicechat/voice/common/Secret.class"),
"de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.class": Path("build/classes/de/maxhenkel/voicechat/voice/server/ServerVoiceEvents.class"),
"plugin.yml": Path("build/plugin.yml"),
}
with ZipFile(base) as source, ZipFile(target, "w", ZIP_DEFLATED) as output:
for item in source.infolist():
replacement = replacements.get(item.filename)
output.writestr(item, replacement.read_bytes() if replacement else source.read(item.filename))
print(f"Built {target}")
PY
- name: Run CBC/GCM interoperability test
shell: bash
run: |
set -euo pipefail
cp="build/AsminVoiceChat-${{ needs.prepare-release.outputs.version }}.jar:build/deps/netty-buffer.jar:build/deps/netty-common.jar"
javac --release 8 -cp "$cp" -d build/test-classes tests/ProtocolCryptoSelfTest.java
java -cp "build/test-classes:$cp" ProtocolCryptoSelfTest
- name: Upload JVM-specific build to release
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_SERVER_URL: ${{ gitea.server_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
RELEASE_ID: ${{ needs.prepare-release.outputs.release_id }}
VERSION: ${{ needs.prepare-release.outputs.version }}
JAVA_VERSION: ${{ matrix.java }}
shell: bash
run: |
set -euo pipefail
api="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY"
file="build/AsminVoiceChat-${VERSION}.jar"
asset="AsminVoiceChat-${VERSION}-Java${JAVA_VERSION}.jar"
curl --fail-with-body -sS -X POST "$api/releases/$RELEASE_ID/assets?name=$asset" \
-H "Authorization: token $GITEA_TOKEN" \
-F "attachment=@$file;filename=$asset"
if [[ "$JAVA_VERSION" == "21" ]]; then
curl --fail-with-body -sS -X POST "$api/releases/$RELEASE_ID/assets?name=AsminVoiceChat-${VERSION}.jar" \
-H "Authorization: token $GITEA_TOKEN" \
-F "attachment=@$file;filename=AsminVoiceChat-${VERSION}.jar"
fi
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
# AsminVoicechat
Simple Voice Chat server fork based on 2.6.25. It accepts protocol compatibility
18 (2.5.x clients) and 20 (2.6.x clients) at the same time. Clients remain
unmodified; each player still needs a mod release for their Minecraft version.
## Architecture
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
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
per-client cipher selection and compatibility-version acceptance.
The full source is in `source/decompiled/`. The two changed classes are also
available separately in `source/patch/`.
## Goxy
AsminVoicechat's integration with Goxy 1.15.0 has been checked. The original
Simple Voice Chat 2.5 server plugin did not integrate correctly with Goxy;
AsminVoicechat exposes the `voicechat` provider alias and supports Goxy's UUID
shim on Paper.
Goxy is a revolutionary anti-bot/anti-DDoS proxy for Minecraft servers
([goxy.io](https://goxy.io/)). I use it every day and recommend it. This is my
own recommendation, and I am not paid to promote it.
## Credits
Simple Voice Chat was originally created by Max Henkel and Matthew Wells.
AsminVoicechat is an independent community fork, not an official release.
I think this fork is a good contribution to the community, and I hope the
original author respects the work. If you have concerns, please contact
[hello@asmin.me](mailto:hello@asmin.me) so we can talk about them before any
DMCA is filed. If you feel strongly about the fork, no offense intended, get in
touch and we can try to work it out. Formal abuse reports can be sent to
[abuse@asmin.me](mailto:abuse@asmin.me).
Copyright (c) 2026 Asmin Studios (asmin.me) for the AsminVoicechat changes.
All rights reserved for those changes. Upstream and bundled third-party rights
and notices remain with their respective owners.
+28
View File
@@ -0,0 +1,28 @@
name: AsminVoicechat
version: 1.0.0
main: de.maxhenkel.voicechat.Voicechat
api-version: '1.13'
prefix: AsminVoicechat
authors:
- Asmin Studios (asmin.me)
- Max Henkel
- Matthew Wells
description: Simple Voice Chat server fork with support for 2.5 and 2.6 clients
website: https://git.asmin.me/asminme/AsminVoicechat
load: STARTUP
provides: [voicechat]
folia-supported: true
commands:
voicechat:
description: Manage voice chat
usage: Invalid command syntax
permissions:
voicechat.listen:
description: Allows to listen to voice chat
voicechat.speak:
description: Allows to speak in voice chat
voicechat.groups:
description: Allows to join groups
voicechat.admin:
description: Allows to test voice chat connections
softdepend: [PlaceholderAPI, ViaVersion]
@@ -0,0 +1,24 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat;
public class BuildConstants {
public static final int COMPATIBILITY_VERSION;
public static final String PLUGIN_NAME = "Simple Voice Chat";
public static final String TARGET_BUKKIT_VERSION = "1.8.8-R0.1-SNAPSHOT";
public static final String MOD_COMPATIBLE_VERSION = "2.6.x";
static {
int compatibilityVersion;
String compatibilityVersionString = "20";
try {
compatibilityVersion = Integer.parseInt(compatibilityVersionString);
}
catch (NumberFormatException e) {
compatibilityVersion = -1;
}
COMPATIBILITY_VERSION = compatibilityVersion;
}
}
@@ -0,0 +1,77 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat;
import de.maxhenkel.voicechat.Version;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
public class BukkitVersion
extends Version {
public static final Pattern BUKKIT_VERSION_REGEX = Pattern.compile("^(?<major>\\d+)\\.(?<minor>\\d+)(?:\\.(?<patch>\\d+))?-R(?<revision>[\\d.-]+)(?:-SNAPSHOT)?$");
protected final String revision;
public BukkitVersion(int major, int minor, int patch, String revision) {
super(major, minor, patch);
this.revision = revision;
}
private static BukkitVersion fromRegex(Matcher matcher) {
String major = matcher.group("major");
String minor = matcher.group("minor");
String patch = matcher.group("patch");
String revision = matcher.group("revision");
if (patch == null || patch.isEmpty()) {
patch = "0";
}
return new BukkitVersion(Integer.parseInt(major), Integer.parseInt(minor), Integer.parseInt(patch), revision);
}
@Nullable
public static BukkitVersion parseBukkitVersion(String bukkitVersion) {
Matcher targetMatcher = BUKKIT_VERSION_REGEX.matcher(bukkitVersion);
if (!targetMatcher.matches()) {
return null;
}
return BukkitVersion.fromRegex(targetMatcher);
}
@Nullable
public static BukkitVersion getTargetVersion() {
return BukkitVersion.parseBukkitVersion("1.8.8-R0.1-SNAPSHOT");
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof BukkitVersion)) {
return false;
}
BukkitVersion that = (BukkitVersion)o;
if (this.major != that.major) {
return false;
}
if (this.minor != that.minor) {
return false;
}
if (this.patch != that.patch) {
return false;
}
return this.revision.equals(that.revision);
}
public String toString() {
if (this.patch <= 0) {
return this.major + "." + this.minor + "-R" + this.revision;
}
return this.major + "." + this.minor + "." + this.patch + "-R" + this.revision;
}
}
@@ -0,0 +1,246 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class FallbackTranslations {
public static final Map<String, String> FALLBACK_TRANSLATIONS;
static {
HashMap<String, String> translations = new HashMap<String, String>();
translations.put("key.category.voicechat.voicechat", "Voice Chat");
translations.put("key.push_to_talk", "Push to Talk");
translations.put("key.whisper", "Whisper");
translations.put("key.mute_microphone", "Mute Microphone");
translations.put("key.disable_voice_chat", "Disable Voice Chat");
translations.put("key.hide_icons", "Hide Voice Chat Icons");
translations.put("key.voice_chat_settings", "Voice Chat Settings");
translations.put("key.voice_chat", "Voice Chat Menu");
translations.put("key.voice_chat_group", "Group Management");
translations.put("key.voice_chat_toggle_recording", "Toggle Recording");
translations.put("key.voice_chat_adjust_volumes", "Adjust Volumes");
translations.put("gui.voicechat.voice_chat.title", "Voice Chat");
translations.put("gui.voicechat.voice_chat_settings.title", "Voice Chat Settings");
translations.put("gui.voicechat.adjust_volume.title", "Adjust Volumes");
translations.put("gui.voicechat.select_microphone.title", "Select Microphone");
translations.put("gui.voicechat.select_speaker.title", "Select Speaker");
translations.put("gui.voicechat.group.title", "Group Management");
translations.put("gui.voicechat.join_create_group.title", "Join or Create Group");
translations.put("gui.voicechat.create_group.title", "Create Group");
translations.put("gui.voicechat.enter_password.title", "Enter Group Password");
translations.put("message.voicechat.settings", "Settings");
translations.put("message.voicechat.group", "Group");
translations.put("message.voicechat.voice_chat_volume", "Voice Chat Volume: %s");
translations.put("message.voicechat.gain", "Gain: %s");
translations.put("message.voicechat.gain.auto", "Auto");
translations.put("message.voicechat.gain.manual", "Manual");
translations.put("message.voicechat.gain.manual.warning", "Please keep automatic microphone gain adjustment enabled to ensure consistent volume levels for everyone hearing you.");
translations.put("message.voicechat.microphone_gain", "Microphone Gain: %s dB");
translations.put("message.voicechat.microphone_gain.warning", "Exceeding %s dB amplification may produce audio distortion and other issues!");
translations.put("message.voicechat.mic_test_unavailable", "Microphone testing unavailable!");
translations.put("message.voicechat.mic_test.disabled", "Press to enable microphone testing.");
translations.put("message.voicechat.mic_test.enabled", "Press to disable microphone testing.");
translations.put("message.voicechat.voice_chat_unavailable", "Voice chat unavailable");
translations.put("message.voicechat.voice_chat_not_connected", "Voice chat not connected");
translations.put("message.voicechat.activation_type", "Activation Method: %s");
translations.put("message.voicechat.activation_type.ptt", "Push to Talk");
translations.put("message.voicechat.activation_type.voice", "Voice");
translations.put("message.voicechat.voice_activation_detection", "Voice Activation: %s");
translations.put("message.voicechat.voice_activation_detection.auto", "Auto");
translations.put("message.voicechat.voice_activation_detection.manual", "Manual");
translations.put("message.voicechat.voice_activation", "Voice Activation Threshold: %s dB");
translations.put("message.voicechat.voice_activation.disabled", "0 dB deactivates the microphone!");
translations.put("message.voicechat.adjust_volumes", "Adjust Volumes");
translations.put("message.voicechat.volume_amplification", "Amplification: %s");
translations.put("message.voicechat.muted", "Muted");
translations.put("message.voicechat.no_microphone", "No microphones available");
translations.put("message.voicechat.default_microphone", "System Default");
translations.put("message.voicechat.no_speaker", "No speakers available");
translations.put("message.voicechat.default_speaker", "System Default");
translations.put("message.voicechat.test_speaker", "Press to play a test sound.");
translations.put("message.voicechat.select_microphone", "Select Microphone");
translations.put("message.voicechat.select_speaker", "Select Speaker");
translations.put("message.voicechat.back", "Back");
translations.put("message.voicechat.client_not_connected", "Client not connected");
translations.put("message.voicechat.failed_to_send_ping", "Failed to send ping: %s");
translations.put("message.voicechat.sending_ping", "Sending ping...");
translations.put("message.voicechat.ping_sent_waiting", "Ping sent. Waiting for response...");
translations.put("message.voicechat.ping_received", "Got a response in %s ms");
translations.put("message.voicechat.ping_received_attempt", "Got a response in %s ms after %s attempts");
translations.put("message.voicechat.ping_retry", "No response. Retrying...");
translations.put("message.voicechat.ping_timed_out", "Request timed out after %s attempts");
translations.put("message.voicechat.icons_hidden", "Voice chat icons hidden");
translations.put("message.voicechat.icons_visible", "Voice chat icons visible");
translations.put("message.voicechat.incompatible_version", "Your voice chat client version is not compatible with the server-side version.\nPlease install version %s of %s.");
translations.put("message.voicechat.incompatible", "Your voice chat client version is not compatible with the server-side version.");
translations.put("message.voicechat.group_members", "Group members:");
translations.put("message.voicechat.no_group_members", "Empty group");
translations.put("message.voicechat.join_create_group", "Join or Create Group");
translations.put("message.voicechat.group_name", "Group Name");
translations.put("message.voicechat.leave_group", "Press to leave the group.");
translations.put("message.voicechat.not_in_group", "You are not in a group");
translations.put("message.voicechat.invite", "%s invited you to the group %s. %s");
translations.put("message.voicechat.accept_invite", "ACCEPT");
translations.put("message.voicechat.accept_invite.hover", "Click to accept the invitation");
translations.put("message.voicechat.join_successful", "Successfully joined the group %s");
translations.put("message.voicechat.leave_successful", "Successfully left the group");
translations.put("message.voicechat.groups_disabled", "Groups are disabled on this server");
translations.put("message.voicechat.recording_disabled", "Recording is disabled on this server");
translations.put("message.voicechat.invite_successful", "Successfully invited %s");
translations.put("message.voicechat.processing_recording_session", "Processing recording session...");
translations.put("message.voicechat.processing_progress", "Processing %s%%");
translations.put("message.voicechat.save_session", "Saved session to %s");
translations.put("message.voicechat.save_session_failed", "Failed to save recording session: %s");
translations.put("message.voicechat.recording_started", "Started Recording");
translations.put("message.voicechat.recording_stopped", "Stopped Recording");
translations.put("message.voicechat.open_folder", "Open folder");
translations.put("message.voicechat.storage_size", "Estimated disk space usage: %s.");
translations.put("message.voicechat.microphone_unavailable", "Microphone unavailable");
translations.put("message.voicechat.speaker_unavailable", "Speaker unavailable");
translations.put("message.voicechat.playback_unavailable", "Playback unavailable");
translations.put("message.voicechat.denoiser", "Noise Suppression: %s");
translations.put("message.voicechat.denoiser.on", "ON");
translations.put("message.voicechat.denoiser.off", "OFF");
translations.put("message.voicechat.group_type_title", "%s (%s)");
translations.put("message.voicechat.group_title", "%s");
translations.put("message.voicechat.group_does_not_exist", "Such a group does not exist");
translations.put("message.voicechat.group_name_not_unique", "Group name is ambiguous");
translations.put("message.voicechat.create", "Create");
translations.put("message.voicechat.create_group", "Create Group");
translations.put("message.voicechat.create_group_button", "Create Group");
translations.put("message.voicechat.optional_password", "Password (Optional)");
translations.put("message.voicechat.group_type", "Group Type");
translations.put("message.voicechat.group_type.normal", "Normal");
translations.put("message.voicechat.group_type.normal.description", "Players who are not in your group can't hear you, but you can hear them.");
translations.put("message.voicechat.group_type.open", "Open");
translations.put("message.voicechat.group_type.open.description", "Players who are not in your group can hear you, and you can hear them too.");
translations.put("message.voicechat.group_type.isolated", "Isolated");
translations.put("message.voicechat.group_type.isolated.description", "Players who are not in your group can't hear you, and you can't hear them either.");
translations.put("message.voicechat.join_group", "Join Group");
translations.put("message.voicechat.enter_group_password", "Enter Group Password");
translations.put("message.voicechat.password", "Password");
translations.put("message.voicechat.wrong_password", "Incorrect Password");
translations.put("message.voicechat.server_port", "Voice chat server hosted on port %s");
translations.put("message.voicechat.macos_no_mic_permission", "No permission to access your microphone. Please open System Settings > Privacy & Security and check the access options there");
translations.put("message.voicechat.macos_unsupported_launcher", "Your launcher does not support macOS microphone permissions");
translations.put("message.voicechat.player_no_voicechat", "%s does not have %s installed");
translations.put("message.voicechat.mute.enabled", "Press to unmute your microphone.");
translations.put("message.voicechat.mute.disabled", "Press to mute your microphone.");
translations.put("message.voicechat.mute.disabled_ptt", "You can't mute your microphone when using push to talk.");
translations.put("message.voicechat.disable.enabled", "Press to enable all voice chat sounds.");
translations.put("message.voicechat.disable.disabled", "Press to disable all voice chat sounds.");
translations.put("message.voicechat.disable.speaker_unavailable", "Speaker unavailable.");
translations.put("message.voicechat.hide_icons.enabled", "Press to show all voice chat icons.");
translations.put("message.voicechat.hide_icons.disabled", "Press to hide all voice chat icons.");
translations.put("message.voicechat.show_group_hud.enabled", "Press to hide the group chat HUD.");
translations.put("message.voicechat.show_group_hud.disabled", "Press to show the group chat HUD.");
translations.put("message.voicechat.recording.disabled", "Press to start recording.");
translations.put("message.voicechat.recording.enabled", "Press to stop recording.");
translations.put("message.voicechat.no_speak_permission", "You do not have permission to speak");
translations.put("message.voicechat.no_listen_permission", "You do not have permission to hear the voice chat");
translations.put("message.voicechat.no_group_permission", "You do not have permission to join groups");
translations.put("message.voicechat.search_hint", "Search...");
translations.put("message.voicechat.search_empty", "Couldn't find any players with that name");
translations.put("message.voicechat.other_volume", "Other");
translations.put("message.voicechat.other_volume.description", "The volume of any sound not listed below.");
translations.put("message.voicechat.more_members", "and %s more...");
translations.put("message.voicechat.no_groups", "No existing groups");
translations.put("message.voicechat.audio_type", "3D Audio: %s");
translations.put("message.voicechat.audio_type.normal", "Normal");
translations.put("message.voicechat.audio_type.reduced", "Reduced");
translations.put("message.voicechat.audio_type.off", "OFF");
translations.put("message.voicechat.invite_player", "Press to invite %s to your group.");
translations.put("message.voicechat.press_to_reassign_key", "Press to assign a key.");
translations.put("message.voicechat.native_error", "Some modules failed to load - Your Operating System might not be supported.");
translations.put("message.voicechat.set_up", "Press %s to set up");
translations.put("message.voicechat.onboarding.reset", "Onboarding status has been reset");
translations.put("message.voicechat.onboarding.next", "Next");
translations.put("message.voicechat.onboarding.confirm", "Confirm");
translations.put("message.voicechat.onboarding.back", "Back");
translations.put("message.voicechat.onboarding.cancel", "Cancel");
translations.put("message.voicechat.onboarding.introduction.title", "Set Up %s");
translations.put("message.voicechat.onboarding.introduction.description", "This setup guide will help you configure your voice chat.\n\nYou can skip it if you know what you are doing.");
translations.put("message.voicechat.onboarding.introduction.skip", "I Know What I Am Doing - Skip");
translations.put("message.voicechat.onboarding.skip.title", "Skip Setup");
translations.put("message.voicechat.onboarding.skip.description", "Are you sure you want to skip this setup guide?\n\nIf you skip it, you will have to adjust all the settings manually!");
translations.put("message.voicechat.onboarding.microphone", "Select Microphone");
translations.put("message.voicechat.onboarding.speaker", "Select Speaker");
translations.put("message.voicechat.onboarding.activation.title", "Select Activation Method");
translations.put("message.voicechat.onboarding.activation", "Please choose the method to activate your microphone.");
translations.put("message.voicechat.onboarding.activation.ptt", "When selecting %s, you need to press and hold a button to speak.");
translations.put("message.voicechat.onboarding.activation.ptt.name", "Push to Talk");
translations.put("message.voicechat.onboarding.activation.voice", "%s automatically activates your microphone when you speak.");
translations.put("message.voicechat.onboarding.activation.voice.name", "Voice Activation");
translations.put("message.voicechat.onboarding.ptt.title", "Choose Push to Talk Keybind");
translations.put("message.voicechat.onboarding.ptt.description", "Please choose the key that should be used to activate your microphone.");
translations.put("message.voicechat.onboarding.ptt.button_description", "Press to assign");
translations.put("message.voicechat.onboarding.voice.title", "Adjust Voice Activation");
translations.put("message.voicechat.onboarding.voice.description", "Enable microphone testing and make sure you can hear your voice when speaking. If this doesn't work, use manual voice activation and adjust the voice activation threshold.");
translations.put("message.voicechat.onboarding.final", "Finish Setup");
translations.put("message.voicechat.onboarding.final.description.success", "You have successfully configured your voice chat!\n\nOpen the voice chat menu with %s.");
translations.put("message.voicechat.onboarding.final.description.ptt", "Hold %s while speaking to use the voice chat.");
translations.put("message.voicechat.onboarding.final.description.voice", "You will be muted after exiting this screen. Press %s to unmute.");
translations.put("message.voicechat.onboarding.final.description.configuration", "You can always change all the settings in the voice chat menu.\nKeybinds, however, can be changed just like any other keybind in the game.");
translations.put("message.voicechat.onboarding.final.finish_setup", "Finish Setup");
translations.put("resourcepack.voicechat.classic_icons", "Classic Icons");
translations.put("resourcepack.voicechat.classic_icons.description", "Classic voice chat icons");
translations.put("resourcepack.voicechat.white_icons", "White Icons");
translations.put("resourcepack.voicechat.white_icons.description", "White voice chat icons");
translations.put("resourcepack.voicechat.black_icons", "Black Icons");
translations.put("resourcepack.voicechat.black_icons.description", "Black voice chat icons");
translations.put("cloth_config.voicechat.settings", "Voice Chat Settings");
translations.put("cloth_config.voicechat.category.general", "General");
translations.put("cloth_config.voicechat.category.audio", "Audio");
translations.put("cloth_config.voicechat.category.hud_icons", "HUD Icons");
translations.put("cloth_config.voicechat.category.group_chat_icons", "Group Chat Icons");
translations.put("cloth_config.voicechat.category.ingame_menu", "In-Game Menu");
translations.put("cloth_config.voicechat.config.recording_destination", "Recording destination");
translations.put("cloth_config.voicechat.config.recording_destination.description", "The location where recordings should be saved.\nLeave blank to use the default location.");
translations.put("cloth_config.voicechat.config.run_local_server", "Run in singleplayer or LAN worlds");
translations.put("cloth_config.voicechat.config.run_local_server.description", "If the voice chat should work in singleplayer or in worlds shared over LAN.");
translations.put("cloth_config.voicechat.config.offline_player_volume_adjustment", "Offline player volume adjustment");
translations.put("cloth_config.voicechat.config.offline_player_volume_adjustment.description", "If the volume adjustment interface should also display offline players.");
translations.put("cloth_config.voicechat.config.freecam_mode", "Freecam mode");
translations.put("cloth_config.voicechat.config.freecam_mode.description", "How listening to other players should work when using freecam mods.\nCAMERA: You will hear the voice chat around your camera. Whether you will still be able to hear the voice chat when the camera is far away from your character depends on the voice chat broadcast range of the server.\nPLAYER: You will hear the voice chat around your character no matter where your camera is.");
translations.put("cloth_config.voicechat.config.freecam_mode.camera", "Camera");
translations.put("cloth_config.voicechat.config.freecam_mode.player", "Player");
translations.put("cloth_config.voicechat.config.mute_on_join", "Mute on join");
translations.put("cloth_config.voicechat.config.mute_on_join.description", "If enabled, you will be automatically muted when joining a world.");
translations.put("cloth_config.voicechat.config.audio_packet_threshold", "Audio packet threshold");
translations.put("cloth_config.voicechat.config.audio_packet_threshold.description", "The maximum number of audio packets that should be held back if a packet arrives out of order or is dropped.\nThis prevents audio packets that are only slightly out of order from being discarded.\nSet this to 0 to disable.");
translations.put("cloth_config.voicechat.config.voice_deactivation_delay", "Microphone deactivation delay");
translations.put("cloth_config.voicechat.config.voice_deactivation_delay.description", "The time it takes for the microphone to deactivate when using voice activation.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on.");
translations.put("cloth_config.voicechat.config.ptt_deactivation_delay", "Push to talk deactivation delay");
translations.put("cloth_config.voicechat.config.ptt_deactivation_delay.description", "The time it takes for the microphone to deactivate when using push to talk.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on.");
translations.put("cloth_config.voicechat.config.output_buffer_size", "Output buffer size");
translations.put("cloth_config.voicechat.config.output_buffer_size.description", "The size of the audio output buffer (in packets).\nHigher values mean a higher latency but less crackling.\nIncrease this value if you have an unstable internet connection.");
translations.put("cloth_config.voicechat.config.show_nametag_icons", "Show voice chat name tag icons");
translations.put("cloth_config.voicechat.config.show_nametag_icons.description", "If the voice chat icons next to player names should be visible");
translations.put("cloth_config.voicechat.config.show_hud_icons", "Show voice chat HUD icons");
translations.put("cloth_config.voicechat.config.show_hud_icons.description", "If the voice chat icons on the HUD should be visible");
translations.put("cloth_config.voicechat.config.hud_icon_scale", "Voice chat HUD icon scale");
translations.put("cloth_config.voicechat.config.hud_icon_scale.description", "The scale of the icons in the voice chat HUD, such as microphone or connection status.");
translations.put("cloth_config.voicechat.config.hud_icon_pos_x", "Voice chat HUD icon X position");
translations.put("cloth_config.voicechat.config.hud_icon_pos_x.description", "The X position of the icons in the voice chat HUD.\nNegative values mean anchoring to the right instead.");
translations.put("cloth_config.voicechat.config.hud_icon_pos_y", "Voice chat HUD icon Y position");
translations.put("cloth_config.voicechat.config.hud_icon_pos_y.description", "The Y position of the icons in the voice chat HUD.\nNegative values mean anchoring to the bottom instead.");
translations.put("cloth_config.voicechat.config.group_player_icon_orientation", "Group chat HUD icon orientation");
translations.put("cloth_config.voicechat.config.group_player_icon_orientation.description", "The orientation of the player icons in the group chat HUD.");
translations.put("cloth_config.voicechat.config.group_player_icon_orientation.vertical", "Vertical");
translations.put("cloth_config.voicechat.config.group_player_icon_orientation.horizontal", "Horizontal");
translations.put("cloth_config.voicechat.config.group_hud_icon_scale", "Group chat HUD icon scale");
translations.put("cloth_config.voicechat.config.group_hud_icon_scale.description", "The scale of the player icons in the group chat HUD.");
translations.put("cloth_config.voicechat.config.group_player_icon_pos_x", "Group chat HUD icon X position");
translations.put("cloth_config.voicechat.config.group_player_icon_pos_x.description", "The X position of the player icons in the group chat HUD.\nNegative values mean anchoring to the right instead.");
translations.put("cloth_config.voicechat.config.group_player_icon_pos_y", "Group chat HUD icon Y position");
translations.put("cloth_config.voicechat.config.group_player_icon_pos_y.description", "The Y position of the player icons in the group chat HUD.\nNegative values mean anchoring to the bottom instead.");
translations.put("cloth_config.voicechat.config.show_own_group_icon", "Show yourself in the group chat HUD");
translations.put("cloth_config.voicechat.config.show_own_group_icon.description", "If your own player icon should be displayed in the group chat HUD when you are in a group.");
FALLBACK_TRANSLATIONS = Collections.unmodifiableMap(translations);
}
}
@@ -0,0 +1,59 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat;
import de.maxhenkel.voicechat.Version;
import de.maxhenkel.voicechat.compatibility.ReflectionUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
public class PaperVersion
extends Version {
public static final Pattern PAPER_VERSION_REGEX = Pattern.compile("^(?<major>\\d+)\\.(?<minor>\\d+)(?:\\.(?<patch>\\d+))?\\.(?<build>.*)$");
private final String build;
public PaperVersion(int major, int minor, int patch, String build) {
super(major, minor, patch);
this.build = build;
}
private static PaperVersion fromRegex(Matcher matcher) {
String major = matcher.group("major");
String minor = matcher.group("minor");
String patch = matcher.group("patch");
String build = matcher.group("build");
if (patch == null || patch.isEmpty()) {
patch = "0";
}
return new PaperVersion(Integer.parseInt(major), Integer.parseInt(minor), Integer.parseInt(patch), build);
}
public static boolean isPaper() {
return ReflectionUtils.doesClassExist("io.papermc.paper.ServerBuildInfo");
}
@Nullable
public static PaperVersion parsePaperVersion(String version) {
if (!PaperVersion.isPaper()) {
return null;
}
Matcher targetMatcher = PAPER_VERSION_REGEX.matcher(version);
if (!targetMatcher.matches()) {
return null;
}
return PaperVersion.fromRegex(targetMatcher);
}
public String toString() {
if (this.patch <= 0) {
return this.major + "." + this.minor + "." + this.build;
}
return this.major + "." + this.minor + "." + this.patch + "." + this.build;
}
}
@@ -0,0 +1,76 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
* org.bukkit.Bukkit
*/
package de.maxhenkel.voicechat;
import de.maxhenkel.voicechat.BukkitVersion;
import de.maxhenkel.voicechat.PaperVersion;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
public class Version {
protected final int major;
protected final int minor;
protected final int patch;
public Version(int major, int minor, int patch) {
this.major = major;
this.minor = minor;
this.patch = patch;
}
@Nullable
public static Version parse(String version) {
Version v = BukkitVersion.parseBukkitVersion(version);
if (v == null) {
v = PaperVersion.parsePaperVersion(version);
}
return v;
}
@Nullable
public static Version getVersion() {
return Version.parse(Bukkit.getBukkitVersion());
}
public int getMajor() {
return this.major;
}
public int getMinor() {
return this.minor;
}
public int getPatch() {
return this.patch;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
Version that = (Version)o;
if (this.major != that.major) {
return false;
}
if (this.minor != that.minor) {
return false;
}
return this.patch == that.patch;
}
public int hashCode() {
int result = this.major;
result = 31 * result + this.minor;
result = 31 * result + this.patch;
return result;
}
}
@@ -0,0 +1,167 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.bukkit.Bukkit
* org.bukkit.command.CommandExecutor
* org.bukkit.command.PluginCommand
* org.bukkit.command.TabCompleter
* org.bukkit.event.Listener
* org.bukkit.plugin.Plugin
* org.bukkit.plugin.ServicePriority
* org.bukkit.plugin.java.JavaPlugin
*/
package de.maxhenkel.voicechat;
import de.maxhenkel.voicechat.BuildConstants;
import de.maxhenkel.voicechat.api.BukkitVoicechatService;
import de.maxhenkel.voicechat.command.VoiceChatCommands;
import de.maxhenkel.voicechat.commodore.Commodore;
import de.maxhenkel.voicechat.commodore.CommodoreProvider;
import de.maxhenkel.voicechat.compatibility.BukkitCompatibilityManager;
import de.maxhenkel.voicechat.compatibility.Compatibility;
import de.maxhenkel.voicechat.config.ServerConfig;
import de.maxhenkel.voicechat.config.Translations;
import de.maxhenkel.voicechat.configbuilder.ConfigBuilder;
import de.maxhenkel.voicechat.integration.commodore.CommodoreCommands;
import de.maxhenkel.voicechat.integration.commodore.MissingArgumentTypeException;
import de.maxhenkel.voicechat.integration.placeholderapi.VoicechatExpansion;
import de.maxhenkel.voicechat.integration.viaversion.ViaVersionCompatibility;
import de.maxhenkel.voicechat.logging.JavaLoggingLogger;
import de.maxhenkel.voicechat.logging.VoicechatLogger;
import de.maxhenkel.voicechat.net.NetManager;
import de.maxhenkel.voicechat.plugins.PluginManager;
import de.maxhenkel.voicechat.plugins.impl.BukkitVoicechatServiceImpl;
import de.maxhenkel.voicechat.voice.server.ServerPlayerManager;
import de.maxhenkel.voicechat.voice.server.ServerVoiceEvents;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
public final class Voicechat
extends JavaPlugin {
public static Voicechat INSTANCE;
public static final String MODID = "voicechat";
public static VoicechatLogger LOGGER;
public static int COMPATIBILITY_VERSION;
public static ServerConfig SERVER_CONFIG;
public static Translations TRANSLATIONS;
public static ServerVoiceEvents SERVER;
public static BukkitVoicechatServiceImpl apiService;
public static NetManager netManager;
public static Compatibility compatibility;
public static final int MAX_GROUP_NAME_LENGTH = 24;
public static final Pattern GROUP_REGEX;
public void onEnable() {
block17: {
INSTANCE = this;
LOGGER = new JavaLoggingLogger(this.getLogger());
if (Voicechat.debugMode()) {
LOGGER.warn("Running in debug mode - Don't leave this enabled in production!", new Object[0]);
}
try {
compatibility = BukkitCompatibilityManager.loadCompatibility();
if (compatibility == null) {
this.disablePlugin();
return;
}
}
catch (Throwable t) {
LOGGER.fatal("An unexpected error occurred while loading compatibility", t);
this.disablePlugin();
return;
}
LOGGER.info("Compatibility version {}", COMPATIBILITY_VERSION);
SERVER_CONFIG = ConfigBuilder.builder(ServerConfig::new).path(this.getDataFolder().toPath().resolve("voicechat-server.properties")).build();
TRANSLATIONS = ConfigBuilder.builder(Translations::new).path(this.getDataFolder().toPath().resolve("translations.properties")).build();
netManager = new NetManager();
netManager.onEnable();
apiService = new BukkitVoicechatServiceImpl();
this.getServer().getServicesManager().register(BukkitVoicechatService.class, (Object)apiService, (Plugin)this, ServicePriority.Normal);
PluginCommand voicechatCommand = this.getCommand(MODID);
if (voicechatCommand != null) {
VoiceChatCommands voiceChatCommands = new VoiceChatCommands();
voicechatCommand.setExecutor((CommandExecutor)voiceChatCommands);
voicechatCommand.setTabCompleter((TabCompleter)voiceChatCommands);
try {
if (CommodoreProvider.isSupported()) {
Commodore commodore = CommodoreProvider.getCommodore((Plugin)this);
CommodoreCommands.registerCompletions(commodore);
LOGGER.info("Successfully initialized commodore command completion", new Object[0]);
break block17;
}
LOGGER.warn("Commodore command completion is not supported", new Object[0]);
}
catch (MissingArgumentTypeException t) {
LOGGER.warn("Failed to initialize commodore command completion: {}", t.getMessage());
}
catch (Throwable t) {
LOGGER.warn("Failed to initialize commodore command completion", t);
}
} else {
LOGGER.error("Failed to register commands", new Object[0]);
}
}
try {
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new VoicechatExpansion().register();
LOGGER.info("Successfully registered PlaceholderAPI expansion", new Object[0]);
}
}
catch (Throwable t) {
LOGGER.error("Failed to register PlaceholderAPI expansion", t);
}
try {
if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) {
ViaVersionCompatibility.register();
LOGGER.info("Successfully added ViaVersion mappings", new Object[0]);
}
}
catch (Throwable t) {
LOGGER.error("Failed to add ViaVersion mappings", t);
}
if (System.getProperty("VOICECHAT_RELOADED") != null) {
LOGGER.error("{} does not support reloads! Expect that things will break!", "Simple Voice Chat");
}
System.setProperty("VOICECHAT_RELOADED", "true");
compatibility.runTask(() -> {
SERVER = new ServerVoiceEvents();
PluginManager.instance().init();
SERVER.init();
Bukkit.getPluginManager().registerEvents((Listener)SERVER, (Plugin)this);
ServerPlayerManager.init((Plugin)this);
});
}
private void disablePlugin() {
LOGGER.fatal("Disabling {}", "Simple Voice Chat");
Bukkit.getPluginManager().disablePlugin((Plugin)this);
}
public void onDisable() {
if (netManager != null) {
netManager.onDisable();
}
this.getServer().getServicesManager().unregister((Object)apiService);
if (SERVER != null) {
SERVER.getServer().close();
}
}
public static boolean debugMode() {
return System.getProperty("voicechat.debug") != null;
}
static {
COMPATIBILITY_VERSION = BuildConstants.COMPATIBILITY_VERSION;
GROUP_REGEX = Pattern.compile("^[^\\p{C}\\s][^\\p{C}]{0,23}$");
}
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.VoicechatPlugin;
public interface BukkitVoicechatService {
public void registerPlugin(VoicechatPlugin var1);
}
@@ -0,0 +1,20 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.RawUdpPacket;
import java.net.SocketAddress;
public interface ClientVoicechatSocket {
public void open() throws Exception;
public RawUdpPacket read() throws Exception;
public void send(byte[] var1, SocketAddress var2) throws Exception;
public void close();
public boolean isClosed();
}
@@ -0,0 +1,16 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Position;
import java.util.UUID;
public interface Entity {
public UUID getUuid();
public Object getEntity();
public Position getPosition();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(value=RetentionPolicy.RUNTIME)
public @interface ForgeVoicechatPlugin {
}
@@ -0,0 +1,47 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import java.util.UUID;
import javax.annotation.Nullable;
public interface Group {
public String getName();
public boolean hasPassword();
public UUID getId();
public boolean isPersistent();
public boolean isHidden();
public Type getType();
public static interface Builder {
public Builder setId(@Nullable UUID var1);
public Builder setName(String var1);
public Builder setPassword(@Nullable String var1);
public Builder setPersistent(boolean var1);
public Builder setHidden(boolean var1);
public Builder setType(Type var1);
public Group build();
}
public static interface Type {
public static final Type NORMAL = new Type(){};
public static final Type OPEN = new Type(){};
public static final Type ISOLATED = new Type(){};
}
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Entity;
public interface Player
extends Entity {
public Object getPlayer();
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
public interface Position {
public double getX();
public double getY();
public double getZ();
}
@@ -0,0 +1,15 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import java.net.SocketAddress;
public interface RawUdpPacket {
public byte[] getData();
public long getTimestamp();
public SocketAddress getSocketAddress();
}
@@ -0,0 +1,9 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
public interface ServerLevel {
public Object getServerLevel();
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Player;
import de.maxhenkel.voicechat.api.ServerLevel;
public interface ServerPlayer
extends Player {
public ServerLevel getServerLevel();
}
@@ -0,0 +1,52 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Entity;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.ServerLevel;
import de.maxhenkel.voicechat.api.ServerPlayer;
import de.maxhenkel.voicechat.api.VolumeCategory;
import de.maxhenkel.voicechat.api.audio.AudioConverter;
import de.maxhenkel.voicechat.api.mp3.Mp3Decoder;
import de.maxhenkel.voicechat.api.mp3.Mp3Encoder;
import de.maxhenkel.voicechat.api.opus.OpusDecoder;
import de.maxhenkel.voicechat.api.opus.OpusEncoder;
import de.maxhenkel.voicechat.api.opus.OpusEncoderMode;
import java.io.InputStream;
import java.io.OutputStream;
import javax.annotation.Nullable;
import javax.sound.sampled.AudioFormat;
public interface VoicechatApi {
public OpusEncoder createEncoder();
public OpusEncoder createEncoder(OpusEncoderMode var1);
public OpusDecoder createDecoder();
@Nullable
public Mp3Encoder createMp3Encoder(AudioFormat var1, int var2, int var3, OutputStream var4);
@Nullable
public Mp3Decoder createMp3Decoder(InputStream var1);
public AudioConverter getAudioConverter();
public Entity fromEntity(Object var1);
public ServerLevel fromServerLevel(Object var1);
public ServerPlayer fromServerPlayer(Object var1);
public Position createPosition(double var1, double var3, double var5);
public VolumeCategory.Builder volumeCategoryBuilder();
public double getVoiceChatDistance();
}
@@ -0,0 +1,78 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Entity;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.VoicechatApi;
import de.maxhenkel.voicechat.api.VolumeCategory;
import de.maxhenkel.voicechat.api.audiochannel.ClientEntityAudioChannel;
import de.maxhenkel.voicechat.api.audiochannel.ClientLocationalAudioChannel;
import de.maxhenkel.voicechat.api.audiochannel.ClientStaticAudioChannel;
import de.maxhenkel.voicechat.api.config.ConfigAccessor;
import de.maxhenkel.voicechat.api.config.VolumeConfigAccessor;
import java.util.UUID;
import javax.annotation.Nullable;
public interface VoicechatClientApi
extends VoicechatApi {
public boolean isMuted();
default public boolean isDisabled() {
return this.isDisabled(null);
}
public boolean isDisabled(@Nullable UUID var1);
default public boolean isDisconnected() {
return this.isDisconnected(null);
}
public boolean isDisconnected(@Nullable UUID var1);
default public boolean isTalking() {
return this.isTalking(null);
}
public boolean isTalking(@Nullable UUID var1);
default public boolean isWhispering() {
return this.isWhispering(null);
}
public boolean isWhispering(@Nullable UUID var1);
public boolean isPushToTalkKeyPressed();
public boolean isWhisperKeyPressed();
@Nullable
public Group getGroup();
@Deprecated
public ClientEntityAudioChannel createEntityAudioChannel(UUID var1);
public ClientEntityAudioChannel createEntityAudioChannel(UUID var1, Entity var2);
public ClientLocationalAudioChannel createLocationalAudioChannel(UUID var1, Position var2);
public ClientStaticAudioChannel createStaticAudioChannel(UUID var1);
public void registerClientVolumeCategory(VolumeCategory var1);
default public void unregisterClientVolumeCategory(VolumeCategory category) {
this.unregisterClientVolumeCategory(category.getId());
}
public void unregisterClientVolumeCategory(String var1);
public ConfigAccessor getClientConfig();
public VolumeConfigAccessor getVolumeConfig();
}
@@ -0,0 +1,33 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.ServerPlayer;
import javax.annotation.Nullable;
public interface VoicechatConnection {
@Nullable
public Group getGroup();
public boolean isInGroup();
public void setGroup(@Nullable Group var1);
public boolean isConnected();
public void setConnected(boolean var1);
public boolean isDisabled();
public void setDisabled(boolean var1);
public boolean isInstalled();
public ServerPlayer getPlayer();
}
@@ -0,0 +1,18 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.VoicechatApi;
import de.maxhenkel.voicechat.api.events.EventRegistration;
public interface VoicechatPlugin {
public String getPluginId();
default public void initialize(VoicechatApi api) {
}
default public void registerEvents(EventRegistration registration) {
}
}
@@ -0,0 +1,125 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.Entity;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.ServerLevel;
import de.maxhenkel.voicechat.api.ServerPlayer;
import de.maxhenkel.voicechat.api.VoicechatApi;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.VolumeCategory;
import de.maxhenkel.voicechat.api.audiochannel.AudioChannel;
import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer;
import de.maxhenkel.voicechat.api.audiochannel.EntityAudioChannel;
import de.maxhenkel.voicechat.api.audiochannel.LocationalAudioChannel;
import de.maxhenkel.voicechat.api.audiochannel.StaticAudioChannel;
import de.maxhenkel.voicechat.api.audiolistener.AudioListener;
import de.maxhenkel.voicechat.api.audiolistener.PlayerAudioListener;
import de.maxhenkel.voicechat.api.audiosender.AudioSender;
import de.maxhenkel.voicechat.api.config.ConfigAccessor;
import de.maxhenkel.voicechat.api.opus.OpusEncoder;
import de.maxhenkel.voicechat.api.packets.ConvertablePacket;
import de.maxhenkel.voicechat.api.packets.EntitySoundPacket;
import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket;
import de.maxhenkel.voicechat.api.packets.StaticSoundPacket;
import java.util.Collection;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nullable;
public interface VoicechatServerApi
extends VoicechatApi {
public void sendEntitySoundPacketTo(VoicechatConnection var1, EntitySoundPacket var2);
public void sendLocationalSoundPacketTo(VoicechatConnection var1, LocationalSoundPacket var2);
public void sendStaticSoundPacketTo(VoicechatConnection var1, StaticSoundPacket var2);
public ConvertablePacket createPacket();
@Nullable
public EntityAudioChannel createEntityAudioChannel(UUID var1, Entity var2);
@Nullable
public LocationalAudioChannel createLocationalAudioChannel(UUID var1, ServerLevel var2, Position var3);
@Deprecated
@Nullable
public StaticAudioChannel createStaticAudioChannel(UUID var1, ServerLevel var2, VoicechatConnection var3);
@Nullable
public StaticAudioChannel createStaticAudioChannel(UUID var1);
public AudioPlayer createAudioPlayer(AudioChannel var1, OpusEncoder var2, Supplier<short[]> var3);
public AudioPlayer createAudioPlayer(AudioChannel var1, OpusEncoder var2, short[] var3);
public AudioSender createAudioSender(VoicechatConnection var1);
public boolean registerAudioSender(AudioSender var1);
public boolean unregisterAudioSender(AudioSender var1);
public PlayerAudioListener.Builder playerAudioListenerBuilder();
public boolean registerAudioListener(AudioListener var1);
public boolean unregisterAudioListener(AudioListener var1);
public boolean unregisterAudioListener(UUID var1);
@Nullable
public VoicechatConnection getConnectionOf(UUID var1);
@Nullable
default public VoicechatConnection getConnectionOf(ServerPlayer player) {
return this.getConnectionOf(player.getUuid());
}
@Deprecated
public Group createGroup(String var1, @Nullable String var2);
@Deprecated
public Group createGroup(String var1, @Nullable String var2, boolean var3);
public Group.Builder groupBuilder();
public boolean removeGroup(UUID var1);
@Nullable
public Group getGroup(UUID var1);
public Collection<Group> getGroups();
@Nullable
@Deprecated
public UUID getSecret(UUID var1);
public Collection<ServerPlayer> getPlayersInRange(ServerLevel var1, Position var2, double var3, Predicate<ServerPlayer> var5);
public double getBroadcastRange();
default public Collection<ServerPlayer> getPlayersInRange(ServerLevel level, Position pos, double range) {
return this.getPlayersInRange(level, pos, range, null);
}
public void registerVolumeCategory(VolumeCategory var1);
default public void unregisterVolumeCategory(VolumeCategory category) {
this.unregisterVolumeCategory(category.getId());
}
public void unregisterVolumeCategory(String var1);
public Collection<VolumeCategory> getVolumeCategories();
public ConfigAccessor getServerConfig();
}
@@ -0,0 +1,22 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api;
import de.maxhenkel.voicechat.api.RawUdpPacket;
import java.net.SocketAddress;
public interface VoicechatSocket {
public void open(int var1, String var2) throws Exception;
public RawUdpPacket read() throws Exception;
public void send(byte[] var1, SocketAddress var2) throws Exception;
public int getLocalPort();
public void close();
public boolean isClosed();
}
@@ -0,0 +1,44 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api;
import javax.annotation.Nullable;
public interface VolumeCategory {
public String getId();
public String getName();
@Nullable
public String getNameTranslationKey();
@Nullable
public String getDescription();
@Nullable
public String getDescriptionTranslationKey();
@Nullable
public int[][] getIcon();
public static interface Builder {
public Builder setId(String var1);
public Builder setName(String var1);
public Builder setNameTranslationKey(@Nullable String var1);
public Builder setDescription(@Nullable String var1);
public Builder setDescriptionTranslationKey(@Nullable String var1);
public Builder setIcon(@Nullable int[][] var1);
public VolumeCategory build();
}
}
@@ -0,0 +1,19 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audio;
public interface AudioConverter {
public short[] bytesToShorts(byte[] var1);
public byte[] shortsToBytes(short[] var1);
public short[] floatsToShorts(float[] var1);
public float[] shortsToFloats(short[] var1);
public byte[] floatsToBytes(float[] var1);
public float[] bytesToFloats(byte[] var1);
}
@@ -0,0 +1,33 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.ServerPlayer;
import de.maxhenkel.voicechat.api.packets.MicrophonePacket;
import java.util.UUID;
import java.util.function.Predicate;
import javax.annotation.Nullable;
public interface AudioChannel {
public void send(byte[] var1);
public void send(MicrophonePacket var1);
public void setFilter(Predicate<ServerPlayer> var1);
public void flush();
public boolean isClosed();
public UUID getId();
@Nullable
public String getCategory();
public void setCategory(@Nullable String var1);
}
@@ -0,0 +1,19 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
public interface AudioPlayer {
public void startPlaying();
public void stopPlaying();
public boolean isStarted();
public boolean isPlaying();
public boolean isStopped();
public void setOnStopped(Runnable var1);
}
@@ -0,0 +1,22 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.audiochannel;
import java.util.UUID;
import javax.annotation.Nullable;
public interface ClientAudioChannel {
public UUID getId();
public void play(short[] var1);
@Nullable
public String getCategory();
public void setCategory(@Nullable String var1);
}
@@ -0,0 +1,21 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel;
import java.util.UUID;
public interface ClientEntityAudioChannel
extends ClientAudioChannel {
public UUID getEntityId();
public void setWhispering(boolean var1);
public boolean isWhispering();
public float getDistance();
public void setDistance(float var1);
}
@@ -0,0 +1,19 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel;
public interface ClientLocationalAudioChannel
extends ClientAudioChannel {
public Position getLocation();
public void setLocation(Position var1);
public float getDistance();
public void setDistance(float var1);
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.audiochannel.ClientAudioChannel;
public interface ClientStaticAudioChannel
extends ClientAudioChannel {
}
@@ -0,0 +1,23 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.Entity;
import de.maxhenkel.voicechat.api.audiochannel.AudioChannel;
public interface EntityAudioChannel
extends AudioChannel {
public boolean isWhispering();
public void setWhispering(boolean var1);
public void updateEntity(Entity var1);
public Entity getEntity();
public float getDistance();
public void setDistance(float var1);
}
@@ -0,0 +1,19 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.audiochannel.AudioChannel;
public interface LocationalAudioChannel
extends AudioChannel {
public void updateLocation(Position var1);
public Position getLocation();
public float getDistance();
public void setDistance(float var1);
}
@@ -0,0 +1,21 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiochannel;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.audiochannel.AudioChannel;
public interface StaticAudioChannel
extends AudioChannel {
public void setBypassGroupIsolation(boolean var1);
public boolean bypassesGroupIsolation();
public void addTarget(VoicechatConnection var1);
public void removeTarget(VoicechatConnection var1);
public void clearTargets();
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiolistener;
import java.util.UUID;
public interface AudioListener {
public UUID getListenerId();
}
@@ -0,0 +1,26 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiolistener;
import de.maxhenkel.voicechat.api.ServerPlayer;
import de.maxhenkel.voicechat.api.audiolistener.AudioListener;
import de.maxhenkel.voicechat.api.packets.SoundPacket;
import java.util.UUID;
import java.util.function.Consumer;
public interface PlayerAudioListener
extends AudioListener {
public UUID getPlayerUuid();
public static interface Builder {
public Builder setPlayer(ServerPlayer var1);
public Builder setPlayer(UUID var1);
public Builder setPacketListener(Consumer<SoundPacket> var1);
public PlayerAudioListener build();
}
}
@@ -0,0 +1,19 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.audiosender;
public interface AudioSender {
public AudioSender whispering(boolean var1);
public boolean isWhispering();
public AudioSender sequenceNumber(long var1);
public boolean canSend();
public boolean send(byte[] var1);
public boolean reset();
}
@@ -0,0 +1,49 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.config;
import javax.annotation.Nullable;
public interface ConfigAccessor {
public boolean hasKey(String var1);
@Nullable
public String getValue(String var1);
default public String getString(String key, String def) {
String value = this.getValue(key);
if (value == null) {
return def;
}
return value;
}
default public boolean getBoolean(String key, boolean def) {
String value = this.getValue(key);
if (value == null) {
return def;
}
return Boolean.parseBoolean(value);
}
default public int getInt(String key, int def) {
String value = this.getValue(key);
if (value == null) {
return def;
}
return Integer.parseInt(value);
}
default public double getDouble(String key, double def) {
String value = this.getValue(key);
if (value == null) {
return def;
}
return Double.parseDouble(value);
}
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.config;
import java.util.UUID;
public interface VolumeConfigAccessor {
public double getVolume(UUID var1);
public double getCategoryVolume(String var1);
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatClientApi;
import de.maxhenkel.voicechat.api.events.Event;
public interface ClientEvent
extends Event {
public VoicechatClientApi getVoicechat();
}
@@ -0,0 +1,42 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.events.ClientEvent;
import java.util.UUID;
import javax.annotation.Nullable;
public interface ClientReceiveSoundEvent
extends ClientEvent {
public UUID getId();
public short[] getRawAudio();
public void setRawAudio(@Nullable short[] var1);
public static interface StaticSound
extends ClientReceiveSoundEvent {
}
public static interface LocationalSound
extends ClientReceiveSoundEvent {
public Position getPosition();
public float getDistance();
}
public static interface EntitySound
extends ClientReceiveSoundEvent {
public UUID getEntityId();
public boolean isWhispering();
public float getDistance();
}
}
@@ -0,0 +1,16 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface ClientSoundEvent
extends ClientEvent {
public short[] getRawAudio();
public void setRawAudio(short[] var1);
public boolean isWhispering();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface ClientVoicechatConnectionEvent
extends ClientEvent {
public boolean isConnected();
}
@@ -0,0 +1,20 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.ClientVoicechatSocket;
import de.maxhenkel.voicechat.api.events.ClientEvent;
import javax.annotation.Nullable;
public interface ClientVoicechatInitializationEvent
extends ClientEvent {
public void setSocketImplementation(ClientVoicechatSocket var1);
@Nullable
public ClientVoicechatSocket getSocketImplementation();
}
@@ -0,0 +1,23 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.GroupEvent;
import javax.annotation.Nullable;
public interface CreateGroupEvent
extends GroupEvent {
@Override
public Group getGroup();
@Override
@Nullable
public VoicechatConnection getConnection();
}
@@ -0,0 +1,14 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface CreateOpenALContextEvent
extends ClientEvent {
public long getContext();
public long getDevice();
}
@@ -0,0 +1,14 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface DestroyOpenALContextEvent
extends ClientEvent {
public long getContext();
public long getDevice();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.SoundPacketEvent;
import de.maxhenkel.voicechat.api.packets.EntitySoundPacket;
public interface EntitySoundPacketEvent
extends SoundPacketEvent<EntitySoundPacket> {
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
public interface Event {
public boolean isCancellable();
public boolean cancel();
public boolean isCancelled();
}
@@ -0,0 +1,16 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.Event;
import java.util.function.Consumer;
public interface EventRegistration {
public <T extends Event> void registerEvent(Class<T> var1, Consumer<T> var2, int var3);
default public <T extends Event> void registerEvent(Class<T> eventClass, Consumer<T> onPacket) {
this.registerEvent(eventClass, onPacket, 0);
}
}
@@ -0,0 +1,22 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import javax.annotation.Nullable;
public interface GroupEvent
extends ServerEvent {
@Nullable
public Group getGroup();
@Nullable
public VoicechatConnection getConnection();
}
@@ -0,0 +1,18 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.GroupEvent;
public interface JoinGroupEvent
extends GroupEvent {
@Override
public Group getGroup();
@Override
public VoicechatConnection getConnection();
}
@@ -0,0 +1,23 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.GroupEvent;
import javax.annotation.Nullable;
public interface LeaveGroupEvent
extends GroupEvent {
@Override
@Nullable
public Group getGroup();
@Override
public VoicechatConnection getConnection();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.SoundPacketEvent;
import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket;
public interface LocationalSoundPacketEvent
extends SoundPacketEvent<LocationalSoundPacket> {
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface MergeClientSoundEvent
extends ClientEvent {
public void mergeAudio(short[] var1);
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface MicrophoneMuteEvent
extends ClientEvent {
public boolean isDisabled();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.PacketEvent;
import de.maxhenkel.voicechat.api.packets.MicrophonePacket;
public interface MicrophonePacketEvent
extends PacketEvent<MicrophonePacket> {
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
import java.util.UUID;
public interface NameTagIconRenderEvent
extends ClientEvent {
public UUID getEntityId();
}
@@ -0,0 +1,35 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.events.ClientEvent;
import java.util.UUID;
import javax.annotation.Nullable;
public interface OpenALSoundEvent
extends ClientEvent {
@Nullable
public Position getPosition();
@Nullable
public UUID getChannelId();
public int getSource();
@Nullable
public String getCategory();
public static interface Post
extends OpenALSoundEvent {
}
public static interface Pre
extends OpenALSoundEvent {
}
}
@@ -0,0 +1,24 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import de.maxhenkel.voicechat.api.packets.Packet;
import javax.annotation.Nullable;
public interface PacketEvent<T extends Packet>
extends ServerEvent {
public T getPacket();
@Nullable
public VoicechatConnection getReceiverConnection();
@Nullable
public VoicechatConnection getSenderConnection();
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.ServerEvent;
public interface PlayerConnectedEvent
extends ServerEvent {
public VoicechatConnection getConnection();
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import java.util.UUID;
public interface PlayerDisconnectedEvent
extends ServerEvent {
public UUID getPlayerUuid();
}
@@ -0,0 +1,25 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import java.util.UUID;
import javax.annotation.Nullable;
public interface PlayerStateChangedEvent
extends ServerEvent {
public boolean isDisabled();
public boolean isDisconnected();
public UUID getPlayerUuid();
@Nullable
public VoicechatConnection getConnection();
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.VolumeCategoryEvent;
public interface RegisterVolumeCategoryEvent
extends VolumeCategoryEvent {
}
@@ -0,0 +1,24 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.Group;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.GroupEvent;
import javax.annotation.Nullable;
public interface RemoveGroupEvent
extends GroupEvent {
@Override
public Group getGroup();
@Override
@Nullable
@Deprecated
public VoicechatConnection getConnection();
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatServerApi;
import de.maxhenkel.voicechat.api.events.Event;
public interface ServerEvent
extends Event {
public VoicechatServerApi getVoicechat();
}
@@ -0,0 +1,18 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.PacketEvent;
import de.maxhenkel.voicechat.api.packets.Packet;
public interface SoundPacketEvent<T extends Packet>
extends PacketEvent<T> {
public static final String SOURCE_GROUP = "group";
public static final String SOURCE_PROXIMITY = "proximity";
public static final String SOURCE_SPECTATOR = "spectator";
public static final String SOURCE_PLUGIN = "plugin";
public String getSource();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.SoundPacketEvent;
import de.maxhenkel.voicechat.api.packets.StaticSoundPacket;
public interface StaticSoundPacketEvent
extends SoundPacketEvent<StaticSoundPacket> {
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.VolumeCategoryEvent;
public interface UnregisterVolumeCategoryEvent
extends VolumeCategoryEvent {
}
@@ -0,0 +1,20 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatConnection;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import de.maxhenkel.voicechat.api.packets.MicrophonePacket;
public interface VoiceDistanceEvent
extends ServerEvent {
public MicrophonePacket getPacket();
public VoicechatConnection getSenderConnection();
public float getDistance();
public void setDistance(float var1);
}
@@ -0,0 +1,17 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.ServerPlayer;
import de.maxhenkel.voicechat.api.events.ServerEvent;
public interface VoiceHostEvent
extends ServerEvent {
public String getVoiceHost();
public void setVoiceHost(String var1);
public ServerPlayer getPlayer();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ClientEvent;
public interface VoicechatDisableEvent
extends ClientEvent {
public boolean isDisabled();
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ServerEvent;
public interface VoicechatServerStartedEvent
extends ServerEvent {
}
@@ -0,0 +1,20 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VoicechatSocket;
import de.maxhenkel.voicechat.api.events.ServerEvent;
import javax.annotation.Nullable;
public interface VoicechatServerStartingEvent
extends ServerEvent {
public void setSocketImplementation(VoicechatSocket var1);
@Nullable
public VoicechatSocket getSocketImplementation();
}
@@ -0,0 +1,11 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.events.ServerEvent;
public interface VoicechatServerStoppedEvent
extends ServerEvent {
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.events;
import de.maxhenkel.voicechat.api.VolumeCategory;
import de.maxhenkel.voicechat.api.events.ServerEvent;
public interface VolumeCategoryEvent
extends ServerEvent {
public VolumeCategory getVolumeCategory();
}
@@ -0,0 +1,16 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.mp3;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
public interface Mp3Decoder {
public short[] decode() throws IOException;
public AudioFormat getAudioFormat() throws IOException;
public int getBitrate() throws IOException;
}
@@ -0,0 +1,13 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.mp3;
import java.io.IOException;
public interface Mp3Encoder {
public void encode(short[] var1) throws IOException;
public void close() throws IOException;
}
@@ -0,0 +1,22 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.opus;
import javax.annotation.Nullable;
public interface OpusDecoder {
public short[] decode(@Nullable byte[] var1);
public short[][] decode(byte[] var1, int var2);
public void resetState();
public boolean isClosed();
public void close();
}
@@ -0,0 +1,15 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.opus;
public interface OpusEncoder {
public byte[] encode(short[] var1);
public void resetState();
public boolean isClosed();
public void close();
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.opus;
public enum OpusEncoderMode {
VOIP,
AUDIO,
RESTRICTED_LOWDELAY;
}
@@ -0,0 +1,28 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.packets.EntitySoundPacket;
import de.maxhenkel.voicechat.api.packets.LocationalSoundPacket;
import de.maxhenkel.voicechat.api.packets.StaticSoundPacket;
import java.util.UUID;
public interface ConvertablePacket {
public EntitySoundPacket.Builder<?> entitySoundPacketBuilder();
public LocationalSoundPacket.Builder<?> locationalSoundPacketBuilder();
public StaticSoundPacket.Builder<?> staticSoundPacketBuilder();
@Deprecated
public EntitySoundPacket toEntitySoundPacket(UUID var1, boolean var2);
@Deprecated
public LocationalSoundPacket toLocationalSoundPacket(Position var1);
@Deprecated
public StaticSoundPacket toStaticSoundPacket();
}
@@ -0,0 +1,26 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.packets.SoundPacket;
import java.util.UUID;
public interface EntitySoundPacket
extends SoundPacket {
public UUID getEntityUuid();
public boolean isWhispering();
public float getDistance();
public static interface Builder<T extends Builder<T>>
extends SoundPacket.Builder<T, EntitySoundPacket> {
public T entityUuid(UUID var1);
public T whispering(boolean var1);
public T distance(float var1);
}
}
@@ -0,0 +1,22 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.Position;
import de.maxhenkel.voicechat.api.packets.SoundPacket;
public interface LocationalSoundPacket
extends SoundPacket {
public Position getPosition();
public float getDistance();
public static interface Builder<T extends Builder<T>>
extends SoundPacket.Builder<T, LocationalSoundPacket> {
public T position(Position var1);
public T distance(float var1);
}
}
@@ -0,0 +1,18 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.packets.ConvertablePacket;
import de.maxhenkel.voicechat.api.packets.Packet;
public interface MicrophonePacket
extends Packet,
ConvertablePacket {
public boolean isWhispering();
public byte[] getOpusEncodedData();
public void setOpusEncodedData(byte[] var1);
}
@@ -0,0 +1,8 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
public interface Packet {
}
@@ -0,0 +1,42 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.packets.ConvertablePacket;
import de.maxhenkel.voicechat.api.packets.Packet;
import java.util.UUID;
import javax.annotation.Nullable;
public interface SoundPacket
extends Packet,
ConvertablePacket {
public UUID getChannelId();
public UUID getSender();
public byte[] getOpusEncodedData();
public long getSequenceNumber();
@Nullable
public String getCategory();
public static interface Builder<T extends Builder<T, P>, P extends SoundPacket> {
public T channelId(UUID var1);
public T sender(UUID var1);
public T opusEncodedData(byte[] var1);
public T sequenceNumber(long var1);
public T category(@Nullable String var1);
public P build();
}
}
@@ -0,0 +1,15 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.api.packets;
import de.maxhenkel.voicechat.api.packets.SoundPacket;
public interface StaticSoundPacket
extends SoundPacket {
public static interface Builder<T extends Builder<T>>
extends SoundPacket.Builder<T, StaticSoundPacket> {
}
}
@@ -0,0 +1,308 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* javax.annotation.Nullable
* org.bukkit.command.Command
* org.bukkit.command.CommandExecutor
* org.bukkit.command.CommandSender
* org.bukkit.command.TabCompleter
* org.bukkit.entity.Player
*/
package de.maxhenkel.voicechat.command;
import de.maxhenkel.voicechat.Voicechat;
import de.maxhenkel.voicechat.net.NetManager;
import de.maxhenkel.voicechat.permission.PermissionManager;
import de.maxhenkel.voicechat.voice.common.PlayerState;
import de.maxhenkel.voicechat.voice.server.ClientConnection;
import de.maxhenkel.voicechat.voice.server.Group;
import de.maxhenkel.voicechat.voice.server.PingManager;
import de.maxhenkel.voicechat.voice.server.Server;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
public class VoiceChatCommands
implements CommandExecutor,
TabCompleter {
public static final String VOICECHAT_COMMAND = "voicechat";
public boolean onCommand(CommandSender commandSender, Command command, String label, String[] args) {
if (VoiceChatCommands.checkNoVoicechat(commandSender)) {
return true;
}
if (!(commandSender instanceof Player)) {
return true;
}
Player sender = (Player)commandSender;
if (args.length >= 1) {
if (args[0].equalsIgnoreCase("help")) {
return this.helpCommand(sender, command, label, args);
}
if (args[0].equalsIgnoreCase("test")) {
if (commandSender.hasPermission(PermissionManager.ADMIN_PERMISSION)) {
return this.testCommand(sender, command, label, args);
}
return true;
}
if (args[0].equalsIgnoreCase("invite")) {
return this.inviteCommand(sender, command, label, args);
}
if (args[0].equalsIgnoreCase("join")) {
return this.joinCommand(sender, command, label, args);
}
if (args[0].equalsIgnoreCase("leave")) {
return this.leaveCommand(sender, command, label, args);
}
}
return this.helpCommand(sender, command, label, args);
}
@Nullable
public List<String> onTabComplete(CommandSender commandSender, Command command, String label, String[] args) {
String arg;
if (args.length == 1) {
return this.tabCompleteList(args[0], Arrays.asList("help", "test", "invite", "join", "leave"));
}
if (args.length == 2) {
arg = args[0];
if (arg.equals("test") || arg.equals("invite")) {
return null;
}
if (arg.startsWith("join")) {
return Collections.emptyList();
}
}
if (args.length == 3 && (arg = args[0]).startsWith("join")) {
return Collections.emptyList();
}
return Collections.emptyList();
}
private List<String> tabCompleteList(String arg, List<String> list) {
return list.stream().filter(s -> s.startsWith(arg)).collect(Collectors.toList());
}
private boolean helpCommand(Player commandSender, Command command, String label, String[] args) {
commandSender.sendMessage("/voicechat [help]");
commandSender.sendMessage("/voicechat [test] <target>");
commandSender.sendMessage("/voicechat [invite] <target>");
commandSender.sendMessage("/voicechat [join] <group> [<password>]");
commandSender.sendMessage("/voicechat [leave]");
return true;
}
private boolean testCommand(final Player commandSender, Command command, String label, String[] args) {
if (args.length < 2) {
return false;
}
Player player = VoiceChatCommands.parsePlayer((CommandSender)commandSender, args[1]);
if (player == null) {
NetManager.sendMessage(commandSender, "argument.entity.notfound.player", new String[0]);
return true;
}
if (!Voicechat.SERVER.isCompatible(player)) {
NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), "Simple Voice Chat");
return true;
}
ClientConnection clientConnection = Voicechat.SERVER.getServer().getConnections().get(player.getUniqueId());
if (clientConnection == null) {
NetManager.sendMessage(commandSender, "message.voicechat.client_not_connected", new String[0]);
return true;
}
try {
NetManager.sendMessage(commandSender, "message.voicechat.sending_ping", new String[0]);
Voicechat.SERVER.getServer().getPingManager().sendPing(clientConnection, 500L, 10, new PingManager.PingListener(){
final /* synthetic */ VoiceChatCommands this$0;
{
this.this$0 = this$0;
}
@Override
public void onPong(int attempts, long pingMilliseconds) {
if (attempts <= 1) {
NetManager.sendMessage(commandSender, "message.voicechat.ping_received", String.valueOf(pingMilliseconds));
} else {
NetManager.sendMessage(commandSender, "message.voicechat.ping_received_attempt", String.valueOf(pingMilliseconds), String.valueOf(attempts));
}
}
@Override
public void onFailedAttempt(int attempts) {
NetManager.sendMessage(commandSender, "message.voicechat.ping_retry", new String[0]);
}
@Override
public void onTimeout(int attempts) {
NetManager.sendMessage(commandSender, "message.voicechat.ping_timed_out", String.valueOf(attempts));
}
});
NetManager.sendMessage(commandSender, "message.voicechat.ping_sent_waiting", new String[0]);
}
catch (Exception e) {
NetManager.sendMessage(commandSender, "message.voicechat.failed_to_send_ping", e.getMessage());
Voicechat.LOGGER.warn("Failed to send ping", e);
}
return true;
}
private boolean inviteCommand(Player commandSender, Command command, String label, String[] args) {
if (args.length < 2) {
return false;
}
Player player = VoiceChatCommands.parsePlayer((CommandSender)commandSender, args[1]);
if (player == null || !Voicechat.compatibility.canSee(commandSender, player)) {
NetManager.sendMessage(commandSender, "argument.entity.notfound.player", new String[0]);
return true;
}
PlayerState state = Voicechat.SERVER.getServer().getPlayerStateManager().getState(commandSender.getUniqueId());
if (state == null || !state.hasGroup()) {
NetManager.sendMessage(commandSender, "message.voicechat.not_in_group", new String[0]);
return true;
}
Group group = Voicechat.SERVER.getServer().getGroupManager().getGroup(state.getGroup());
if (group == null) {
return true;
}
if (!Voicechat.SERVER.isCompatible(player)) {
NetManager.sendMessage(commandSender, "message.voicechat.player_no_voicechat", player.getDisplayName(), "Simple Voice Chat");
return true;
}
String passwordSuffix = group.getPassword() == null ? "" : " \"" + group.getPassword() + "\"";
String cmd = "/voicechat join " + group.getId().toString() + passwordSuffix;
Voicechat.compatibility.sendInviteMessage(player, commandSender, group.getName(), cmd);
NetManager.sendMessage(commandSender, "message.voicechat.invite_successful", player.getName());
return true;
}
private boolean joinCommand(Player commandSender, Command command, String label, String[] args) {
UUID groupUUID;
int argIndex;
if (args.length < 2) {
return false;
}
try {
groupUUID = UUID.fromString(args[argIndex]);
}
catch (Exception e) {
String groupName;
if (args[argIndex].startsWith("\"")) {
String[] split;
StringBuilder sb = new StringBuilder();
for (argIndex = 1; argIndex < args.length; ++argIndex) {
sb.append(args[argIndex]).append(" ");
if (args[argIndex].endsWith("\"") && !args[argIndex].endsWith("\\\"")) break;
}
if ((split = (groupName = sb.toString().trim()).split("\"")).length > 1) {
groupName = split[1];
}
} else {
groupName = args[argIndex];
}
groupUUID = this.getGroupUUID(commandSender, Voicechat.SERVER.getServer(), groupName);
}
if (groupUUID == null) {
return true;
}
String password = null;
if (args.length >= ++argIndex + 1) {
String[] split;
StringBuilder sb = new StringBuilder();
while (argIndex < args.length) {
sb.append(args[argIndex]).append(" ");
++argIndex;
}
password = sb.toString().trim();
if (password.startsWith("\"") && (split = password.split("\"")).length > 1) {
password = split[1];
}
}
VoiceChatCommands.joinGroup(commandSender, groupUUID, password);
return true;
}
private UUID getGroupUUID(Player commandSender, Server server, String groupName) {
List groups = server.getGroupManager().getGroups().values().stream().filter(group -> group.getName().equals(groupName)).collect(Collectors.toList());
if (groups.isEmpty()) {
NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist", new String[0]);
return null;
}
if (groups.size() > 1) {
NetManager.sendMessage(commandSender, "message.voicechat.group_name_not_unique", new String[0]);
return null;
}
return ((Group)groups.get(0)).getId();
}
private static void joinGroup(Player commandSender, UUID groupID, @Nullable String password) {
if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) {
NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled", new String[0]);
return;
}
Server server = Voicechat.SERVER.getServer();
if (!commandSender.hasPermission(PermissionManager.GROUPS_PERMISSION)) {
NetManager.sendMessage(commandSender, "message.voicechat.no_group_permission", new String[0]);
return;
}
Group group = server.getGroupManager().getGroup(groupID);
if (group == null) {
NetManager.sendMessage(commandSender, "message.voicechat.group_does_not_exist", new String[0]);
return;
}
server.getGroupManager().joinGroup(group, commandSender, password);
NetManager.sendMessage(commandSender, "message.voicechat.join_successful", group.getName());
}
private boolean leaveCommand(Player commandSender, Command command, String label, String[] args) {
if (!Voicechat.SERVER_CONFIG.groupsEnabled.get().booleanValue()) {
NetManager.sendMessage(commandSender, "message.voicechat.groups_disabled", new String[0]);
return true;
}
Server server = Voicechat.SERVER.getServer();
PlayerState state = server.getPlayerStateManager().getState(commandSender.getUniqueId());
if (state == null || !state.hasGroup()) {
NetManager.sendMessage(commandSender, "message.voicechat.not_in_group", new String[0]);
return true;
}
server.getGroupManager().leaveGroup(commandSender);
NetManager.sendMessage(commandSender, "message.voicechat.leave_successful", new String[0]);
return true;
}
private static boolean checkNoVoicechat(CommandSender commandSender) {
if (commandSender instanceof Player) {
if (Voicechat.SERVER.isCompatible((Player)commandSender)) {
return false;
}
commandSender.sendMessage(String.format(Voicechat.TRANSLATIONS.voicechatNeededForCommandMessage.get(), "Simple Voice Chat"));
} else {
commandSender.sendMessage(Voicechat.TRANSLATIONS.playerCommandMessage.get());
}
return true;
}
@Nullable
public static Player parsePlayer(CommandSender commandSender, String playerArg) {
Player player = commandSender.getServer().getPlayer(playerArg);
if (player != null) {
return player;
}
try {
UUID uuid = UUID.fromString(playerArg);
return commandSender.getServer().getPlayer(uuid);
}
catch (IllegalArgumentException e) {
return null;
}
}
}
@@ -0,0 +1,120 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.brigadier.Command
* com.mojang.brigadier.suggestion.SuggestionProvider
* com.mojang.brigadier.tree.ArgumentCommandNode
* com.mojang.brigadier.tree.CommandNode
* com.mojang.brigadier.tree.LiteralCommandNode
* com.mojang.brigadier.tree.RootCommandNode
* org.bukkit.command.Command
* org.bukkit.command.PluginCommand
*/
package de.maxhenkel.voicechat.commodore;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import de.maxhenkel.voicechat.commodore.Commodore;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.bukkit.command.PluginCommand;
abstract class AbstractCommodore
implements Commodore {
protected static final Field CUSTOM_SUGGESTIONS_FIELD;
protected static final Field COMMAND_EXECUTE_FUNCTION_FIELD;
protected static final Field CHILDREN_FIELD;
protected static final Field LITERALS_FIELD;
protected static final Field ARGUMENTS_FIELD;
protected static final Field[] CHILDREN_FIELDS;
protected static final Command<?> DUMMY_COMMAND;
protected static final SuggestionProvider<?> DUMMY_SUGGESTION_PROVIDER;
AbstractCommodore() {
}
protected static void removeChild(RootCommandNode root, String name) {
try {
for (Field field : CHILDREN_FIELDS) {
Map children = (Map)field.get(root);
children.remove(name);
}
}
catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
protected static void setRequiredHackyFieldsRecursively(CommandNode<?> node, SuggestionProvider<?> suggestionProvider) {
try {
COMMAND_EXECUTE_FUNCTION_FIELD.set(node, DUMMY_COMMAND);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
if (suggestionProvider != null && node instanceof ArgumentCommandNode) {
ArgumentCommandNode argumentNode = (ArgumentCommandNode)node;
try {
CUSTOM_SUGGESTIONS_FIELD.set(argumentNode, suggestionProvider);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
}
for (CommandNode child : node.getChildren()) {
AbstractCommodore.setRequiredHackyFieldsRecursively(child, suggestionProvider);
}
}
protected static <S> LiteralCommandNode<S> renameLiteralNode(LiteralCommandNode<S> node, String newLiteral) {
LiteralCommandNode clone = new LiteralCommandNode(newLiteral, node.getCommand(), node.getRequirement(), node.getRedirect(), node.getRedirectModifier(), node.isFork());
for (CommandNode child : node.getChildren()) {
clone.addChild(child);
}
return clone;
}
protected static Collection<String> getAliases(org.bukkit.command.Command command) {
Objects.requireNonNull(command, "command");
Stream<String> aliasesStream = Stream.concat(Stream.of(command.getLabel()), command.getAliases().stream());
if (command instanceof PluginCommand) {
String fallbackPrefix = ((PluginCommand)command).getPlugin().getName().toLowerCase().trim();
aliasesStream = aliasesStream.flatMap(alias -> Stream.of(alias, fallbackPrefix + ":" + alias));
}
return aliasesStream.distinct().collect(Collectors.toList());
}
static {
try {
CUSTOM_SUGGESTIONS_FIELD = ArgumentCommandNode.class.getDeclaredField("customSuggestions");
CUSTOM_SUGGESTIONS_FIELD.setAccessible(true);
COMMAND_EXECUTE_FUNCTION_FIELD = CommandNode.class.getDeclaredField("command");
COMMAND_EXECUTE_FUNCTION_FIELD.setAccessible(true);
CHILDREN_FIELD = CommandNode.class.getDeclaredField("children");
LITERALS_FIELD = CommandNode.class.getDeclaredField("literals");
ARGUMENTS_FIELD = CommandNode.class.getDeclaredField("arguments");
for (Field field : CHILDREN_FIELDS = new Field[]{CHILDREN_FIELD, LITERALS_FIELD, ARGUMENTS_FIELD}) {
field.setAccessible(true);
}
DUMMY_COMMAND = ctx -> {
throw new UnsupportedOperationException();
};
DUMMY_SUGGESTION_PROVIDER = (context, builder) -> {
throw new UnsupportedOperationException();
};
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
}
@@ -0,0 +1,12 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.commodore;
public final class BrigadierUnsupportedException
extends UnsupportedOperationException {
BrigadierUnsupportedException(String message) {
super(message);
}
}
@@ -0,0 +1,48 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.brigadier.builder.LiteralArgumentBuilder
* com.mojang.brigadier.tree.LiteralCommandNode
* org.bukkit.command.Command
* org.bukkit.entity.Player
*/
package de.maxhenkel.voicechat.commodore;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import java.util.Objects;
import java.util.function.Predicate;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
public interface Commodore {
public void register(Command var1, LiteralCommandNode<?> var2, Predicate<? super Player> var3);
default public void register(Command command, LiteralArgumentBuilder<?> argumentBuilder, Predicate<? super Player> permissionTest) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(argumentBuilder, "argumentBuilder");
Objects.requireNonNull(permissionTest, "permissionTest");
this.register(command, argumentBuilder.build(), permissionTest);
}
default public void register(Command command, LiteralCommandNode<?> node) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(node, "node");
this.register(command, node, arg_0 -> ((Command)command).testPermissionSilent(arg_0));
}
default public void register(Command command, LiteralArgumentBuilder<?> argumentBuilder) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(argumentBuilder, "argumentBuilder");
this.register(command, argumentBuilder.build());
}
public void register(LiteralCommandNode<?> var1);
default public void register(LiteralArgumentBuilder<?> argumentBuilder) {
Objects.requireNonNull(argumentBuilder, "argumentBuilder");
this.register(argumentBuilder.build());
}
}
@@ -0,0 +1,68 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.bukkit.plugin.Plugin
*/
package de.maxhenkel.voicechat.commodore;
import de.maxhenkel.voicechat.commodore.BrigadierUnsupportedException;
import de.maxhenkel.voicechat.commodore.Commodore;
import de.maxhenkel.voicechat.commodore.PaperCommodore;
import de.maxhenkel.voicechat.commodore.ReflectionCommodore;
import java.util.Objects;
import java.util.function.Function;
import org.bukkit.plugin.Plugin;
public final class CommodoreProvider {
private static final Function<Plugin, Commodore> PROVIDER = CommodoreProvider.checkSupported();
private CommodoreProvider() {
throw new AssertionError();
}
private static Function<Plugin, Commodore> checkSupported() {
try {
Class.forName("com.mojang.brigadier.CommandDispatcher");
}
catch (Throwable e) {
CommodoreProvider.printDebugInfo(e);
return null;
}
try {
PaperCommodore.ensureSetup();
return PaperCommodore::new;
}
catch (Throwable e) {
CommodoreProvider.printDebugInfo(e);
try {
ReflectionCommodore.ensureSetup();
return ReflectionCommodore::new;
}
catch (Throwable e2) {
CommodoreProvider.printDebugInfo(e2);
return null;
}
}
}
private static void printDebugInfo(Throwable e) {
if (System.getProperty("commodore.debug") != null) {
System.err.println("Exception while initialising commodore:");
e.printStackTrace(System.err);
}
}
public static boolean isSupported() {
return PROVIDER != null;
}
public static Commodore getCommodore(Plugin plugin) throws BrigadierUnsupportedException {
Objects.requireNonNull(plugin, "plugin");
if (PROVIDER == null) {
throw new BrigadierUnsupportedException("Brigadier is not supported by the server. Set -Dcommodore.debug=true for debug info.");
}
return PROVIDER.apply(plugin);
}
}
@@ -0,0 +1,114 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent
* com.mojang.brigadier.builder.LiteralArgumentBuilder
* com.mojang.brigadier.tree.LiteralCommandNode
* com.mojang.brigadier.tree.RootCommandNode
* org.bukkit.command.Command
* org.bukkit.entity.Player
* org.bukkit.event.EventHandler
* org.bukkit.event.Listener
* org.bukkit.plugin.Plugin
*/
package de.maxhenkel.voicechat.commodore;
import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import de.maxhenkel.voicechat.commodore.AbstractCommodore;
import de.maxhenkel.voicechat.commodore.Commodore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
final class PaperCommodore
extends AbstractCommodore
implements Commodore,
Listener {
private final List<CommodoreCommand> commands = new ArrayList<CommodoreCommand>();
PaperCommodore(Plugin plugin) {
plugin.getServer().getPluginManager().registerEvents((Listener)this, plugin);
}
@Override
public void register(LiteralCommandNode<?> node) {
Objects.requireNonNull(node, "node");
this.commands.add(new CommodoreCommand(node, null));
}
@Override
public void register(Command command, LiteralCommandNode<?> node, Predicate<? super Player> permissionTest) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(node, "node");
Objects.requireNonNull(permissionTest, "permissionTest");
try {
PaperCommodore.setRequiredHackyFieldsRecursively(node, DUMMY_SUGGESTION_PROVIDER);
}
catch (Throwable e) {
e.printStackTrace();
}
Collection<String> aliases = PaperCommodore.getAliases(command);
if (!aliases.contains(node.getLiteral())) {
node = PaperCommodore.renameLiteralNode(node, command.getName());
}
for (String alias : aliases) {
if (node.getLiteral().equals(alias)) {
this.commands.add(new CommodoreCommand(node, permissionTest));
continue;
}
LiteralCommandNode redirectNode = ((LiteralArgumentBuilder)LiteralArgumentBuilder.literal((String)alias).redirect(node)).build();
this.commands.add(new CommodoreCommand(redirectNode, permissionTest));
}
}
@EventHandler
public void onPlayerSendCommandsEvent(AsyncPlayerSendCommandsEvent<?> event) {
if (event.isAsynchronous() || !event.hasFiredAsync()) {
for (CommodoreCommand command : this.commands) {
command.apply(event.getPlayer(), event.getCommandNode());
}
}
}
static void ensureSetup() {
}
static {
try {
Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent");
}
catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Not running on modern Paper!", e);
}
}
private static final class CommodoreCommand {
private final LiteralCommandNode<?> node;
private final Predicate<? super Player> permissionTest;
private CommodoreCommand(LiteralCommandNode<?> node, Predicate<? super Player> permissionTest) {
this.node = node;
this.permissionTest = permissionTest;
}
public void apply(Player player, RootCommandNode<?> root) {
if (this.permissionTest != null && !this.permissionTest.test((Player)player)) {
return;
}
AbstractCommodore.removeChild(root, this.node.getName());
root.addChild(this.node);
}
}
}
@@ -0,0 +1,186 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.brigadier.CommandDispatcher
* com.mojang.brigadier.builder.LiteralArgumentBuilder
* com.mojang.brigadier.suggestion.SuggestionProvider
* com.mojang.brigadier.tree.CommandNode
* com.mojang.brigadier.tree.LiteralCommandNode
* com.mojang.brigadier.tree.RootCommandNode
* org.bukkit.Bukkit
* org.bukkit.command.Command
* org.bukkit.entity.Player
* org.bukkit.event.EventHandler
* org.bukkit.event.Listener
* org.bukkit.event.player.PlayerCommandSendEvent
* org.bukkit.event.server.ServerLoadEvent
* org.bukkit.plugin.Plugin
*/
package de.maxhenkel.voicechat.commodore;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import de.maxhenkel.voicechat.commodore.AbstractCommodore;
import de.maxhenkel.voicechat.commodore.Commodore;
import de.maxhenkel.voicechat.commodore.ReflectionUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandSendEvent;
import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.plugin.Plugin;
final class ReflectionCommodore
extends AbstractCommodore
implements Commodore {
private static final Field CONSOLE_FIELD;
private static final Method GET_COMMAND_DISPATCHER_METHOD;
private static final Method GET_BRIGADIER_DISPATCHER_METHOD;
private static final Constructor<?> COMMAND_WRAPPER_CONSTRUCTOR;
private final Plugin plugin;
private final List<LiteralCommandNode<?>> registeredNodes = new ArrayList();
ReflectionCommodore(Plugin plugin) {
this.plugin = plugin;
this.plugin.getServer().getPluginManager().registerEvents((Listener)new ServerReloadListener(this), this.plugin);
}
private CommandDispatcher<?> getDispatcher() {
try {
Object mcServerObject = CONSOLE_FIELD.get(Bukkit.getServer());
Object commandDispatcherObject = GET_COMMAND_DISPATCHER_METHOD.invoke(mcServerObject, new Object[0]);
return (CommandDispatcher)GET_BRIGADIER_DISPATCHER_METHOD.invoke(commandDispatcherObject, new Object[0]);
}
catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
@Override
public void register(LiteralCommandNode<?> node) {
Objects.requireNonNull(node, "node");
CommandDispatcher<?> dispatcher = this.getDispatcher();
RootCommandNode root = dispatcher.getRoot();
ReflectionCommodore.removeChild(root, node.getName());
root.addChild(node);
this.registeredNodes.add(node);
}
@Override
public void register(Command command, LiteralCommandNode<?> node, Predicate<? super Player> permissionTest) {
Objects.requireNonNull(command, "command");
Objects.requireNonNull(node, "node");
Objects.requireNonNull(permissionTest, "permissionTest");
try {
SuggestionProvider wrapper = (SuggestionProvider)COMMAND_WRAPPER_CONSTRUCTOR.newInstance(this.plugin.getServer(), command);
ReflectionCommodore.setRequiredHackyFieldsRecursively(node, wrapper);
}
catch (Throwable e) {
e.printStackTrace();
}
Collection<String> aliases = ReflectionCommodore.getAliases(command);
if (!aliases.contains(node.getLiteral())) {
node = ReflectionCommodore.renameLiteralNode(node, command.getName());
}
for (String alias : aliases) {
if (node.getLiteral().equals(alias)) {
this.register(node);
continue;
}
this.register(((LiteralArgumentBuilder)LiteralArgumentBuilder.literal((String)alias).redirect(node)).build());
}
this.plugin.getServer().getPluginManager().registerEvents((Listener)new CommandDataSendListener(command, permissionTest), this.plugin);
}
static void ensureSetup() {
}
static {
try {
Class<?> commandDispatcher;
Class<?> minecraftServer;
if (ReflectionUtil.minecraftVersion() >= 19) {
throw new UnsupportedOperationException("ReflectionCommodore is not supported on MC 1.19 or above. Switch to Paper :)");
}
if (ReflectionUtil.minecraftVersion() > 16) {
minecraftServer = ReflectionUtil.mcClass("server.MinecraftServer");
commandDispatcher = ReflectionUtil.mcClass("commands.CommandDispatcher");
} else {
minecraftServer = ReflectionUtil.nmsClass("MinecraftServer");
commandDispatcher = ReflectionUtil.nmsClass("CommandDispatcher");
}
Class<?> craftServer = ReflectionUtil.obcClass("CraftServer");
CONSOLE_FIELD = craftServer.getDeclaredField("console");
CONSOLE_FIELD.setAccessible(true);
GET_COMMAND_DISPATCHER_METHOD = Arrays.stream(minecraftServer.getDeclaredMethods()).filter(method -> method.getParameterCount() == 0).filter(method -> commandDispatcher.isAssignableFrom(method.getReturnType())).findFirst().orElseThrow(NoSuchMethodException::new);
GET_COMMAND_DISPATCHER_METHOD.setAccessible(true);
GET_BRIGADIER_DISPATCHER_METHOD = Arrays.stream(commandDispatcher.getDeclaredMethods()).filter(method -> method.getParameterCount() == 0).filter(method -> CommandDispatcher.class.isAssignableFrom(method.getReturnType())).findFirst().orElseThrow(NoSuchMethodException::new);
GET_BRIGADIER_DISPATCHER_METHOD.setAccessible(true);
Class<?> commandWrapperClass = ReflectionUtil.obcClass("command.BukkitCommandWrapper");
COMMAND_WRAPPER_CONSTRUCTOR = commandWrapperClass.getConstructor(craftServer, Command.class);
}
catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private static final class ServerReloadListener
implements Listener {
private final ReflectionCommodore commodore;
private ServerReloadListener(ReflectionCommodore commodore) {
this.commodore = commodore;
}
@EventHandler
public void onLoad(ServerLoadEvent e) {
CommandDispatcher dispatcher = this.commodore.getDispatcher();
RootCommandNode root = dispatcher.getRoot();
for (LiteralCommandNode node : this.commodore.registeredNodes) {
AbstractCommodore.removeChild(root, node.getName());
root.addChild((CommandNode)node);
}
}
}
private static final class CommandDataSendListener
implements Listener {
private final Set<String> aliases;
private final Set<String> minecraftPrefixedAliases;
private final Predicate<? super Player> permissionTest;
CommandDataSendListener(Command pluginCommand, Predicate<? super Player> permissionTest) {
this.aliases = new HashSet<String>(AbstractCommodore.getAliases(pluginCommand));
this.minecraftPrefixedAliases = this.aliases.stream().map(alias -> "minecraft:" + alias).collect(Collectors.toSet());
this.permissionTest = permissionTest;
}
@EventHandler
public void onCommandSend(PlayerCommandSendEvent e) {
e.getCommands().removeAll(this.minecraftPrefixedAliases);
if (!this.permissionTest.test((Player)e.getPlayer())) {
e.getCommands().removeAll(this.aliases);
}
}
}
}
@@ -0,0 +1,68 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* org.bukkit.Bukkit
*/
package de.maxhenkel.voicechat.commodore;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
final class ReflectionUtil {
private static final String SERVER_VERSION = ReflectionUtil.getServerVersion();
private static String getServerVersion() {
Class<?> server = Bukkit.getServer().getClass();
if (!server.getSimpleName().equals("CraftServer")) {
return ".";
}
if (server.getName().equals("org.bukkit.craftbukkit.CraftServer")) {
return ".";
}
String version = server.getName().substring("org.bukkit.craftbukkit".length());
return version.substring(0, version.length() - "CraftServer".length());
}
public static String mc(String name) {
return "net.minecraft." + name;
}
public static String nms(String className) {
return "net.minecraft.server" + SERVER_VERSION + className;
}
public static Class<?> mcClass(String className) throws ClassNotFoundException {
return Class.forName(ReflectionUtil.mc(className));
}
public static Class<?> nmsClass(String className) throws ClassNotFoundException {
return Class.forName(ReflectionUtil.nms(className));
}
public static String obc(String className) {
return "org.bukkit.craftbukkit" + SERVER_VERSION + className;
}
public static Class<?> obcClass(String className) throws ClassNotFoundException {
return Class.forName(ReflectionUtil.obc(className));
}
public static int minecraftVersion() {
try {
Matcher matcher = Pattern.compile("\\(MC: (\\d)\\.(\\d+)\\.?(\\d+?)?( .*)?\\)").matcher(Bukkit.getVersion());
if (matcher.find()) {
return Integer.parseInt(matcher.toMatchResult().group(2), 10);
}
throw new IllegalArgumentException(String.format("No match found in '%s'", Bukkit.getVersion()));
}
catch (IllegalArgumentException ex) {
throw new RuntimeException("Failed to determine Minecraft version", ex);
}
}
private ReflectionUtil() {
}
}
@@ -0,0 +1,81 @@
/*
* Decompiled with CFR 0.152.
*/
package de.maxhenkel.voicechat.commodore.file;
import java.util.Iterator;
import java.util.NoSuchElementException;
abstract class AbstractIterator<T>
implements Iterator<T> {
private State state = State.NOT_READY;
private T next;
protected AbstractIterator() {
}
protected abstract T computeNext() throws Exception;
protected final T endOfData() {
this.state = State.DONE;
return null;
}
@Override
public final boolean hasNext() {
if (this.state == State.FAILED) {
throw new IllegalStateException();
}
switch (this.state) {
case DONE: {
return false;
}
case READY: {
return true;
}
}
return this.tryToComputeNext();
}
private boolean tryToComputeNext() {
this.state = State.FAILED;
try {
this.next = this.computeNext();
}
catch (Exception e) {
throw new RuntimeException("Exception whilst computing next value", e);
}
if (this.state != State.DONE) {
this.state = State.READY;
return true;
}
return false;
}
@Override
public final T next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
this.state = State.NOT_READY;
T result = this.next;
this.next = null;
return result;
}
public final T peek() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
return this.next;
}
private static enum State {
READY,
NOT_READY,
DONE,
FAILED;
}
}
Loaded 100 of 454 files, more files were not shown because too many files have changed in this diff. Show more