Compare commits
77 Commits
47f36e3ff9
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
babb22bf88
|
|||
|
468127996c
|
|||
|
|
b6b6b20fe9 | ||
|
|
f75b512837 | ||
|
|
7412aca81c | ||
|
|
02cf349075 | ||
|
|
67b988e6d2 | ||
|
|
d2c13c2a4c | ||
|
|
498a38cf74 | ||
|
|
13a1c93ea6 | ||
|
|
38a0a7ed27 | ||
|
|
70c3eabdb1 | ||
|
|
4cd3b68697 | ||
|
|
1140fc65ba | ||
|
|
5753548b44 | ||
|
|
806b386cdb | ||
|
|
d266059abe | ||
|
|
b1dd26fbc4 | ||
|
|
c8c27af7c3 | ||
|
|
ba01492790 | ||
|
|
94368d5021 | ||
|
|
ec793a9fdb | ||
|
|
37f622f226 | ||
|
|
87f74eaeda | ||
|
|
8406979e71 | ||
|
|
6e80f57739 | ||
|
|
1532fb360b | ||
|
|
180af8c844 | ||
|
|
311e2bc18d | ||
|
|
bfd15e1a81 | ||
|
|
d2d333a958 | ||
|
|
60a22ff330 | ||
|
|
946e5c47d4 | ||
|
|
5d450ab3c7 | ||
|
|
a509a878e9 | ||
|
|
49e2988e37 | ||
|
|
db8d16fd6e | ||
|
|
d47848cb93 | ||
| 873fca763d | |||
|
|
e99407132f | ||
| 67d63faeca | |||
| 871b053561 | |||
|
|
81deb1fff8 | ||
|
|
59560ebad1 | ||
|
|
67a6600c05 | ||
|
|
f3e30558e4 | ||
|
|
e46ab6ad7d | ||
|
|
b6fd48f282 | ||
| c2edc26d8e | |||
| 76417b13d4 | |||
| 91a61643bd | |||
| b6e05cb0b9 | |||
| 1507b91463 | |||
|
|
b06af3718c | ||
|
|
a20a896582 | ||
|
|
e1a3421212 | ||
|
|
19e51a2b12 | ||
|
|
b89a5c5ce9 | ||
|
|
65d3277319 | ||
|
|
a22bfa10f9 | ||
|
|
d9d1319a3a | ||
|
|
15ecbf4345 | ||
|
|
5e3bbcd427 | ||
|
|
a6c79db07b | ||
|
|
6e33bc6c17 | ||
|
|
01208bb359 | ||
|
|
fa88aaae52 | ||
|
|
2da400a267 | ||
|
|
8103135dfb | ||
|
|
cfabff7288 | ||
|
|
2f5a27a708 | ||
|
|
fdfe8bcc4b | ||
| a19fd8db74 | |||
| e63d71423d | |||
|
|
a7afe35fab | ||
|
|
56d6339313 | ||
|
|
2475572573 |
6
.github/workflows/gradle.yml
vendored
6
.github/workflows/gradle.yml
vendored
@@ -14,10 +14,10 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Gradle
|
- name: Set up Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v4
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 21
|
||||||
distribution: 'temurin'
|
distribution: 'zulu'
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ tasks {
|
|||||||
"https://jd.advntr.dev/api/${libs.adventure.bom.get().version}/",
|
"https://jd.advntr.dev/api/${libs.adventure.bom.get().version}/",
|
||||||
"https://jd.advntr.dev/text-minimessage/${libs.adventure.bom.get().version}/",
|
"https://jd.advntr.dev/text-minimessage/${libs.adventure.bom.get().version}/",
|
||||||
"https://jd.advntr.dev/key/${libs.adventure.bom.get().version}/",
|
"https://jd.advntr.dev/key/${libs.adventure.bom.get().version}/",
|
||||||
"https://javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/${libs.caffeine.get().version}/",
|
"https://www.javadocs.dev/com.github.ben-manes.caffeine/caffeine/${libs.caffeine.get().version}/",
|
||||||
)
|
)
|
||||||
|
|
||||||
o.tags(
|
o.tags(
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import com.velocitypowered.api.plugin.Plugin;
|
|||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.AbstractProcessor;
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
@@ -68,8 +67,8 @@ public class PluginAnnotationProcessor extends AbstractProcessor {
|
|||||||
|
|
||||||
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
Name qualifiedName = ((TypeElement) element).getQualifiedName();
|
||||||
|
|
||||||
if (Objects.equals(pluginClassFound, qualifiedName.toString())) {
|
if (pluginClassFound != null) {
|
||||||
if (!warnedAboutMultiplePlugins) {
|
if (!pluginClassFound.equals(qualifiedName.toString()) && !warnedAboutMultiplePlugins) {
|
||||||
environment.getMessager()
|
environment.getMessager()
|
||||||
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support "
|
.printMessage(Diagnostic.Kind.WARNING, "Velocity does not yet currently support "
|
||||||
+ "multiple plugins. We are using " + pluginClassFound
|
+ "multiple plugins. We are using " + pluginClassFound
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ public interface EventManager {
|
|||||||
*
|
*
|
||||||
* @param plugin the plugin to associate with the handler
|
* @param plugin the plugin to associate with the handler
|
||||||
* @param eventClass the class for the event handler to register
|
* @param eventClass the class for the event handler to register
|
||||||
* @param postOrder the relative order in which events should be posted to the handler
|
* @param postOrder the relative order in which events should be posted to the handler. The higher
|
||||||
|
* the priority, the earlier the event handler will be called
|
||||||
* @param handler the handler to register
|
* @param handler the handler to register
|
||||||
* @param <E> the event type to handle
|
* @param <E> the event type to handle
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* The Velocity API is licensed under the terms of the MIT License. For more details,
|
||||||
|
* reference the LICENSE file in the api top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.api.event.proxy;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.velocitypowered.api.event.annotation.AwaitingEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is fired by the proxy after it has stopped accepting new connections,
|
||||||
|
* but before players are disconnected.
|
||||||
|
* This is the last point at which you can interact with currently connected players,
|
||||||
|
* for example to transfer them to another proxy or perform other cleanup tasks.
|
||||||
|
*
|
||||||
|
* @implNote Velocity will wait for all event listeners to complete before disconnecting players,
|
||||||
|
* but note that the event will time out after the configured value of the
|
||||||
|
* <code>velocity.pre-shutdown-timeout</code> system property, default 10 seconds,
|
||||||
|
* in seconds to prevent shutdown from hanging indefinitely
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
@AwaitingEvent
|
||||||
|
public final class ProxyPreShutdownEvent {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ProxyPreShutdownEvent";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,9 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
|||||||
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"),
|
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"),
|
||||||
MINECRAFT_1_21_4(769, "1.21.4"),
|
MINECRAFT_1_21_4(769, "1.21.4"),
|
||||||
MINECRAFT_1_21_5(770, "1.21.5"),
|
MINECRAFT_1_21_5(770, "1.21.5"),
|
||||||
MINECRAFT_1_21_6(771, "1.21.6");
|
MINECRAFT_1_21_6(771, "1.21.6"),
|
||||||
|
MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"),
|
||||||
|
MINECRAFT_1_21_9(773, "1.21.9", "1.21.10");
|
||||||
|
|
||||||
private static final int SNAPSHOT_BIT = 30;
|
private static final int SNAPSHOT_BIT = 30;
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.util.Locale;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
import net.kyori.adventure.dialog.DialogLike;
|
||||||
import net.kyori.adventure.identity.Identified;
|
import net.kyori.adventure.identity.Identified;
|
||||||
import net.kyori.adventure.inventory.Book;
|
import net.kyori.adventure.inventory.Book;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
@@ -48,7 +49,7 @@ public interface Player extends
|
|||||||
/* Fundamental Velocity interfaces */
|
/* Fundamental Velocity interfaces */
|
||||||
CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink,
|
CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink,
|
||||||
/* Adventure-specific interfaces */
|
/* Adventure-specific interfaces */
|
||||||
Identified, HoverEventSource<HoverEvent.ShowEntity>, Keyed, KeyIdentifiable {
|
Identified, HoverEventSource<HoverEvent.ShowEntity>, Keyed, KeyIdentifiable, Sound.Emitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the player's current username.
|
* Returns the player's current username.
|
||||||
@@ -383,8 +384,12 @@ public interface Player extends
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <b>This method is not currently implemented in Velocity
|
*
|
||||||
|
* @apiNote <b>This method is not currently implemented in Velocity
|
||||||
* and will not perform any actions.</b>
|
* and will not perform any actions.</b>
|
||||||
|
* @see #playSound(Sound, Sound.Emitter)
|
||||||
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound) {
|
default void playSound(@NotNull Sound sound) {
|
||||||
@@ -393,8 +398,11 @@ public interface Player extends
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <b>This method is not currently implemented in Velocity
|
* @apiNote <b>This method is not currently implemented in Velocity
|
||||||
* and will not perform any actions.</b>
|
* and will not perform any actions.</b>
|
||||||
|
* @see #playSound(Sound, Sound.Emitter)
|
||||||
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound, double x, double y, double z) {
|
default void playSound(@NotNull Sound sound, double x, double y, double z) {
|
||||||
@@ -403,18 +411,28 @@ public interface Player extends
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <b>This method is not currently implemented in Velocity
|
* <p><b>Note</b>: Due to <a href="https://bugs.mojang.com/browse/MC/issues/MC-146721">MC-146721</a>, stereo sounds are always played globally in 1.14+.
|
||||||
* and will not perform any actions.</b>
|
*
|
||||||
|
* <p><b>Note</b>: Due to <a href="https://bugs.mojang.com/browse/MC/issues/MC-138832">MC-138832</a>, the volume and pitch are ignored when using this method in 1.14 to 1.16.5.
|
||||||
|
*
|
||||||
|
* @param sound the sound to play
|
||||||
|
* @param emitter the emitter of the sound; may be another player of this player's server
|
||||||
|
* @since 3.4.0
|
||||||
|
* @sinceMinecraft 1.19.3
|
||||||
|
* @apiNote This method is currently only implemented for players on 1.19.3+
|
||||||
|
* and requires a present {@link #getCurrentServer} for the emitting player as well as this player.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound, Sound.Emitter emitter) {
|
default void playSound(@NotNull Sound sound, @NotNull Sound.Emitter emitter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* <b>This method is not currently implemented in Velocity
|
* @param stop the sound and/or a sound source, to stop
|
||||||
* and will not perform any actions.</b>
|
* @since 3.4.0
|
||||||
|
* @sinceMinecraft 1.19.3
|
||||||
|
* @apiNote This method is currently only implemented for players on 1.19.3+.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void stopSound(@NotNull SoundStop stop) {
|
default void stopSound(@NotNull SoundStop stop) {
|
||||||
@@ -425,11 +443,40 @@ public interface Player extends
|
|||||||
*
|
*
|
||||||
* <b>This method is not currently implemented in Velocity
|
* <b>This method is not currently implemented in Velocity
|
||||||
* and will not perform any actions.</b>
|
* and will not perform any actions.</b>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void openBook(@NotNull Book book) {
|
default void openBook(@NotNull Book book) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <b>This method is not currently implemented in Velocity
|
||||||
|
* and will not perform any actions.</b>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
|
* Unsupported Adventure Operations</a>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
default void showDialog(@NotNull DialogLike dialog) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <b>This method is not currently implemented in Velocity
|
||||||
|
* and will not perform any actions.</b>
|
||||||
|
*
|
||||||
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
|
* Unsupported Adventure Operations</a>
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
default void closeDialog() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfers a Player to a host.
|
* Transfers a Player to a host.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a 1.7 and above server list ping response. This class is immutable.
|
* Represents a 1.7 and above server list ping response. This class is immutable.
|
||||||
@@ -28,9 +30,10 @@ public final class ServerPing {
|
|||||||
|
|
||||||
private final Version version;
|
private final Version version;
|
||||||
private final @Nullable Players players;
|
private final @Nullable Players players;
|
||||||
private final net.kyori.adventure.text.Component description;
|
private final @Nullable Component description;
|
||||||
private final @Nullable Favicon favicon;
|
private final @Nullable Favicon favicon;
|
||||||
private final @Nullable ModInfo modinfo;
|
private final @Nullable ModInfo modinfo;
|
||||||
|
private final boolean preventsChatReports = true;
|
||||||
|
|
||||||
public ServerPing(Version version, @Nullable Players players,
|
public ServerPing(Version version, @Nullable Players players,
|
||||||
net.kyori.adventure.text.Component description, @Nullable Favicon favicon) {
|
net.kyori.adventure.text.Component description, @Nullable Favicon favicon) {
|
||||||
@@ -47,7 +50,7 @@ public final class ServerPing {
|
|||||||
* @param modinfo the mods this server runs
|
* @param modinfo the mods this server runs
|
||||||
*/
|
*/
|
||||||
public ServerPing(Version version, @Nullable Players players,
|
public ServerPing(Version version, @Nullable Players players,
|
||||||
net.kyori.adventure.text.Component description, @Nullable Favicon favicon,
|
Component description, @Nullable Favicon favicon,
|
||||||
@Nullable ModInfo modinfo) {
|
@Nullable ModInfo modinfo) {
|
||||||
this.version = Preconditions.checkNotNull(version, "version");
|
this.version = Preconditions.checkNotNull(version, "version");
|
||||||
this.players = players;
|
this.players = players;
|
||||||
@@ -64,7 +67,8 @@ public final class ServerPing {
|
|||||||
return Optional.ofNullable(players);
|
return Optional.ofNullable(players);
|
||||||
}
|
}
|
||||||
|
|
||||||
public net.kyori.adventure.text.Component getDescriptionComponent() {
|
@Nullable
|
||||||
|
public Component getDescriptionComponent() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +155,7 @@ public final class ServerPing {
|
|||||||
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
|
private final List<SamplePlayer> samplePlayers = new ArrayList<>();
|
||||||
private String modType = "FML";
|
private String modType = "FML";
|
||||||
private final List<ModInfo.Mod> mods = new ArrayList<>();
|
private final List<ModInfo.Mod> mods = new ArrayList<>();
|
||||||
private net.kyori.adventure.text.Component description;
|
private Component description;
|
||||||
private @Nullable Favicon favicon;
|
private @Nullable Favicon favicon;
|
||||||
private boolean nullOutPlayers;
|
private boolean nullOutPlayers;
|
||||||
private boolean nullOutModinfo;
|
private boolean nullOutModinfo;
|
||||||
@@ -299,7 +303,7 @@ public final class ServerPing {
|
|||||||
* @param description Component to use as the description.
|
* @param description Component to use as the description.
|
||||||
* @return this builder, for chaining
|
* @return this builder, for chaining
|
||||||
*/
|
*/
|
||||||
public Builder description(net.kyori.adventure.text.Component description) {
|
public Builder description(Component description) {
|
||||||
this.description = Preconditions.checkNotNull(description, "description");
|
this.description = Preconditions.checkNotNull(description, "description");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -359,7 +363,7 @@ public final class ServerPing {
|
|||||||
return samplePlayers;
|
return samplePlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<net.kyori.adventure.text.Component> getDescriptionComponent() {
|
public Optional<Component> getDescriptionComponent() {
|
||||||
return Optional.ofNullable(description);
|
return Optional.ofNullable(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,15 @@ import org.gradle.jvm.tasks.Jar
|
|||||||
import org.gradle.kotlin.dsl.withType
|
import org.gradle.kotlin.dsl.withType
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
// This interface is needed as a workaround to get an instance of ExecOperations
|
||||||
|
interface Injected {
|
||||||
|
@get:Inject
|
||||||
|
val execOps: ExecOperations
|
||||||
|
}
|
||||||
|
|
||||||
val currentShortRevision = ByteArrayOutputStream().use {
|
val currentShortRevision = ByteArrayOutputStream().use {
|
||||||
exec {
|
val execOps = objects.newInstance<Injected>().execOps
|
||||||
|
execOps.exec {
|
||||||
executable = "git"
|
executable = "git"
|
||||||
args = listOf("rev-parse", "HEAD")
|
args = listOf("rev-parse", "HEAD")
|
||||||
standardOutput = it
|
standardOutput = it
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ extensions.configure<PublishingExtension> {
|
|||||||
maven {
|
maven {
|
||||||
credentials(PasswordCredentials::class.java)
|
credentials(PasswordCredentials::class.java)
|
||||||
|
|
||||||
name = "paper"
|
name = if (version.toString().endsWith("SNAPSHOT")) "paperSnapshots" else "paper" // "paper" is seemingly not defined
|
||||||
val base = "https://repo.papermc.io/repository/maven"
|
val base = "https://artifactory.papermc.io/artifactory"
|
||||||
val releasesRepoUrl = "$base-releases/"
|
val releasesRepoUrl = "$base/releases/"
|
||||||
val snapshotsRepoUrl = "$base-snapshots/"
|
val snapshotsRepoUrl = "$base/snapshots/"
|
||||||
setUrl(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
|
setUrl(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ subprojects {
|
|||||||
testImplementation(rootProject.libs.junit)
|
testImplementation(rootProject.libs.junit)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
testing.suites.named<JvmTestSuite>("test") {
|
||||||
test {
|
useJUnitJupiter()
|
||||||
useJUnitPlatform()
|
targets.all {
|
||||||
reports {
|
testTask.configure {
|
||||||
junitXml.required.set(true)
|
reports.junitXml.required = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,17 @@ configurate3 = "3.7.3"
|
|||||||
configurate4 = "4.1.2"
|
configurate4 = "4.1.2"
|
||||||
flare = "2.0.1"
|
flare = "2.0.1"
|
||||||
log4j = "2.24.3"
|
log4j = "2.24.3"
|
||||||
netty = "4.2.1.Final"
|
netty = "4.2.7.Final"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
fill = "io.papermc.fill.gradle:1.0.3"
|
||||||
indra-publishing = "net.kyori.indra.publishing:2.0.6"
|
indra-publishing = "net.kyori.indra.publishing:2.0.6"
|
||||||
shadow = "io.github.goooler.shadow:8.1.5"
|
shadow = "com.gradleup.shadow:8.3.6"
|
||||||
spotless = "com.diffplug.spotless:6.25.0"
|
spotless = "com.diffplug.spotless:6.25.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
adventure-bom = "net.kyori:adventure-bom:4.21.0"
|
adventure-bom = "net.kyori:adventure-bom:4.25.0"
|
||||||
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.21.0"
|
adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.25.0"
|
||||||
adventure-facet = "net.kyori:adventure-platform-facet:4.3.4"
|
adventure-facet = "net.kyori:adventure-platform-facet:4.3.4"
|
||||||
asm = "org.ow2.asm:asm:9.8"
|
asm = "org.ow2.asm:asm:9.8"
|
||||||
auto-service = "com.google.auto.service:auto-service:1.0.1"
|
auto-service = "com.google.auto.service:auto-service:1.0.1"
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
|
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
|
||||||
|
import io.papermc.fill.model.BuildChannel
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
application
|
application
|
||||||
id("velocity-init-manifest")
|
id("velocity-init-manifest")
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
|
alias(libs.plugins.fill)
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@@ -108,6 +110,24 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val projectVersion = version as String
|
||||||
|
fill {
|
||||||
|
project("velocity")
|
||||||
|
|
||||||
|
build {
|
||||||
|
channel = BuildChannel.STABLE
|
||||||
|
versionFamily("3.0.0")
|
||||||
|
version(projectVersion)
|
||||||
|
|
||||||
|
downloads {
|
||||||
|
register("server:default") {
|
||||||
|
file = tasks.shadowJar.flatMap { it.archiveFile }
|
||||||
|
nameResolver.set { project, _, version, build -> "$project-$version-$build.jar" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":velocity-api"))
|
implementation(project(":velocity-api"))
|
||||||
implementation(project(":velocity-native"))
|
implementation(project(":velocity-native"))
|
||||||
|
|||||||
@@ -47,11 +47,6 @@ public class Velocity {
|
|||||||
System.setProperty("io.netty.native.workdir", System.getProperty("velocity.natives-tmpdir"));
|
System.setProperty("io.netty.native.workdir", System.getProperty("velocity.natives-tmpdir"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore allocator used before Netty 4.2 due to oom issues with the adaptive allocator
|
|
||||||
if (System.getProperty("io.netty.allocator.type") == null) {
|
|
||||||
System.setProperty("io.netty.allocator.type", "pooled");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the resource leak detector by default as it reduces performance. Allow the user to
|
// Disable the resource leak detector by default as it reduces performance. Allow the user to
|
||||||
// override this if desired.
|
// override this if desired.
|
||||||
if (!VelocityProperties.hasProperty("io.netty.leakDetection.level")) {
|
if (!VelocityProperties.hasProperty("io.netty.leakDetection.level")) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.velocitypowered.api.command.BrigadierCommand;
|
import com.velocitypowered.api.command.BrigadierCommand;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyPreShutdownEvent;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
|
import com.velocitypowered.api.event.proxy.ProxyReloadEvent;
|
||||||
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
@@ -119,7 +120,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
*/
|
*/
|
||||||
public class VelocityServer implements ProxyServer, ForwardingAudience {
|
public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||||
|
|
||||||
public static final String VELOCITY_URL = "https://velocitypowered.com";
|
public static final String VELOCITY_URL = "https://papermc.io/software/velocity";
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(VelocityServer.class);
|
private static final Logger logger = LogManager.getLogger(VelocityServer.class);
|
||||||
public static final Gson GENERAL_GSON = new GsonBuilder()
|
public static final Gson GENERAL_GSON = new GsonBuilder()
|
||||||
@@ -150,6 +151,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
)
|
)
|
||||||
.registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE)
|
.registerTypeHierarchyAdapter(Favicon.class, FaviconSerializer.INSTANCE)
|
||||||
.create();
|
.create();
|
||||||
|
private static final int PRE_SHUTDOWN_TIMEOUT =
|
||||||
|
Integer.getInteger("velocity.pre-shutdown-timeout", 10);
|
||||||
|
|
||||||
private final ConnectionManager cm;
|
private final ConnectionManager cm;
|
||||||
private final ProxyOptions options;
|
private final ProxyOptions options;
|
||||||
@@ -216,7 +219,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
ProxyVersion version = getVersion();
|
ProxyVersion version = getVersion();
|
||||||
PluginDescription description = new VelocityPluginDescription(
|
PluginDescription description = new VelocityPluginDescription(
|
||||||
"velocity", version.getName(), version.getVersion(), "The Velocity proxy",
|
"velocity", version.getName(), version.getVersion(), "The Velocity proxy",
|
||||||
VELOCITY_URL, ImmutableList.of(version.getVendor()), Collections.emptyList(), null);
|
version.getName().equals("Velocity") ? VELOCITY_URL : null,
|
||||||
|
ImmutableList.of(version.getVendor()), Collections.emptyList(), null);
|
||||||
VelocityPluginContainer container = new VelocityPluginContainer(description);
|
VelocityPluginContainer container = new VelocityPluginContainer(description);
|
||||||
container.setInstance(VelocityVirtualPlugin.INSTANCE);
|
container.setInstance(VelocityVirtualPlugin.INSTANCE);
|
||||||
return container;
|
return container;
|
||||||
@@ -578,6 +582,20 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
// done first to refuse new connections
|
// done first to refuse new connections
|
||||||
cm.shutdown();
|
cm.shutdown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
eventManager.fire(new ProxyPreShutdownEvent())
|
||||||
|
.toCompletableFuture()
|
||||||
|
.get(PRE_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS);
|
||||||
|
} catch (TimeoutException ignored) {
|
||||||
|
logger.warn("Your plugins took over {} seconds during pre shutdown.",
|
||||||
|
PRE_SHUTDOWN_TIMEOUT);
|
||||||
|
} catch (ExecutionException ee) {
|
||||||
|
logger.error("Exception in ProxyPreShutdownEvent handler; continuing shutdown.", ee);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
logger.warn("Interrupted while waiting for ProxyPreShutdownEvent; continuing shutdown.");
|
||||||
|
}
|
||||||
|
|
||||||
ImmutableList<ConnectedPlayer> players = ImmutableList.copyOf(connectionsByUuid.values());
|
ImmutableList<ConnectedPlayer> players = ImmutableList.copyOf(connectionsByUuid.values());
|
||||||
for (ConnectedPlayer player : players) {
|
for (ConnectedPlayer player : players) {
|
||||||
player.disconnect(reason);
|
player.disconnect(reason);
|
||||||
|
|||||||
@@ -53,15 +53,23 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
viewer.getProtocolVersion(),
|
viewer.getProtocolVersion(),
|
||||||
viewer.translateMessage(this.bar.name())
|
viewer.translateMessage(this.bar.name())
|
||||||
);
|
);
|
||||||
viewer.getConnection().write(BossBarPacket.createAddPacket(this.id, this.bar, name));
|
viewer.getBossBarManager().writeUpdate(this, BossBarPacket.createAddPacket(this.id, this.bar, name));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void createDirect(final ConnectedPlayer viewer) {
|
||||||
|
final ComponentHolder name = new ComponentHolder(
|
||||||
|
viewer.getProtocolVersion(),
|
||||||
|
viewer.translateMessage(this.bar.name())
|
||||||
|
);
|
||||||
|
viewer.getConnection().write(BossBarPacket.createAddPacket(this.id, this.bar, name));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean viewerRemove(final ConnectedPlayer viewer) {
|
public boolean viewerRemove(final ConnectedPlayer viewer) {
|
||||||
if (this.viewers.remove(viewer)) {
|
if (this.viewers.remove(viewer)) {
|
||||||
viewer.getConnection().write(BossBarPacket.createRemovePacket(this.id, this.bar));
|
viewer.getBossBarManager().remove(this, BossBarPacket.createRemovePacket(this.id, this.bar));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -84,7 +92,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
this.bar,
|
this.bar,
|
||||||
new ComponentHolder(viewer.getProtocolVersion(), translated)
|
new ComponentHolder(viewer.getProtocolVersion(), translated)
|
||||||
);
|
);
|
||||||
viewer.getConnection().write(packet);
|
viewer.getBossBarManager().writeUpdate(this, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +104,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
) {
|
) {
|
||||||
final BossBarPacket packet = BossBarPacket.createUpdateProgressPacket(this.id, this.bar);
|
final BossBarPacket packet = BossBarPacket.createUpdateProgressPacket(this.id, this.bar);
|
||||||
for (final ConnectedPlayer viewer : this.viewers) {
|
for (final ConnectedPlayer viewer : this.viewers) {
|
||||||
viewer.getConnection().write(packet);
|
viewer.getBossBarManager().writeUpdate(this, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +116,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
) {
|
) {
|
||||||
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
|
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
|
||||||
for (final ConnectedPlayer viewer : this.viewers) {
|
for (final ConnectedPlayer viewer : this.viewers) {
|
||||||
viewer.getConnection().write(packet);
|
viewer.getBossBarManager().writeUpdate(this, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +128,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
) {
|
) {
|
||||||
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
|
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
|
||||||
for (final ConnectedPlayer viewer : this.viewers) {
|
for (final ConnectedPlayer viewer : this.viewers) {
|
||||||
viewer.getConnection().write(packet);
|
viewer.getBossBarManager().writeUpdate(this, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +140,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
|||||||
) {
|
) {
|
||||||
final BossBarPacket packet = BossBarPacket.createUpdatePropertiesPacket(this.id, this.bar);
|
final BossBarPacket packet = BossBarPacket.createUpdatePropertiesPacket(this.id, this.bar);
|
||||||
for (final ConnectedPlayer viewer : this.viewers) {
|
for (final ConnectedPlayer viewer : this.viewers) {
|
||||||
viewer.getConnection().write(packet);
|
viewer.getBossBarManager().writeUpdate(this, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.velocitypowered.api.command.CommandManager;
|
|||||||
import com.velocitypowered.api.command.CommandMeta;
|
import com.velocitypowered.api.command.CommandMeta;
|
||||||
import com.velocitypowered.api.command.CommandResult;
|
import com.velocitypowered.api.command.CommandResult;
|
||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
import com.velocitypowered.api.command.VelocityBrigadierMessage;
|
|
||||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.event.command.PostCommandInvocationEvent;
|
import com.velocitypowered.api.event.command.PostCommandInvocationEvent;
|
||||||
import com.velocitypowered.api.plugin.PluginManager;
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
@@ -59,6 +58,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentLike;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.checkerframework.checker.lock.qual.GuardedBy;
|
import org.checkerframework.checker.lock.qual.GuardedBy;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
@@ -242,8 +242,8 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand());
|
CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand());
|
||||||
if (isSyntaxError) {
|
if (isSyntaxError) {
|
||||||
final Message message = e.getRawMessage();
|
final Message message = e.getRawMessage();
|
||||||
if (message instanceof VelocityBrigadierMessage velocityMessage) {
|
if (message instanceof ComponentLike componentLike) {
|
||||||
source.sendMessage(velocityMessage.asComponent().applyFallbackStyle(NamedTextColor.RED));
|
source.sendMessage(componentLike.asComponent().applyFallbackStyle(NamedTextColor.RED));
|
||||||
} else {
|
} else {
|
||||||
source.sendMessage(Component.text(e.getMessage(), NamedTextColor.RED));
|
source.sendMessage(Component.text(e.getMessage(), NamedTextColor.RED));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,8 +176,7 @@ public final class VelocityCommand {
|
|||||||
.append(Component.text()
|
.append(Component.text()
|
||||||
.content("PaperMC")
|
.content("PaperMC")
|
||||||
.color(NamedTextColor.GREEN)
|
.color(NamedTextColor.GREEN)
|
||||||
.clickEvent(
|
.clickEvent(ClickEvent.openUrl(VelocityServer.VELOCITY_URL))
|
||||||
ClickEvent.openUrl("https://papermc.io/software/velocity"))
|
|
||||||
.build())
|
.build())
|
||||||
.append(Component.text(" - "))
|
.append(Component.text(" - "))
|
||||||
.append(Component.text()
|
.append(Component.text()
|
||||||
|
|||||||
@@ -103,13 +103,17 @@ abstract class InvocableCommandRegistrar<T extends InvocableCommand<I>,
|
|||||||
.requiresWithContext((context, reader) -> requirement.test(context))
|
.requiresWithContext((context, reader) -> requirement.test(context))
|
||||||
.executes(callback)
|
.executes(callback)
|
||||||
.suggests((context, builder) -> {
|
.suggests((context, builder) -> {
|
||||||
|
// Offset the suggestion to the last space seperated word
|
||||||
|
int lastSpace = builder.getRemaining().lastIndexOf(' ') + 1;
|
||||||
|
final var offsetBuilder = builder.createOffset(builder.getStart() + lastSpace);
|
||||||
|
|
||||||
final I invocation = invocationFactory.create(context);
|
final I invocation = invocationFactory.create(context);
|
||||||
return command.suggestAsync(invocation).thenApply(suggestions -> {
|
return command.suggestAsync(invocation).thenApply(suggestions -> {
|
||||||
for (String value : suggestions) {
|
for (String value : suggestions) {
|
||||||
Preconditions.checkNotNull(value, "suggestion");
|
Preconditions.checkNotNull(value, "suggestion");
|
||||||
builder.suggest(value);
|
offsetBuilder.suggest(value);
|
||||||
}
|
}
|
||||||
return builder.build();
|
return offsetBuilder.build();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
|
|
||||||
String forwardingSecretString = System.getenv().getOrDefault(
|
String forwardingSecretString = System.getenv().getOrDefault(
|
||||||
"VELOCITY_FORWARDING_SECRET", "");
|
"VELOCITY_FORWARDING_SECRET", "");
|
||||||
if (forwardingSecretString.isEmpty()) {
|
if (forwardingSecretString.isBlank()) {
|
||||||
final String forwardSecretFile = config.get("forwarding-secret-file");
|
final String forwardSecretFile = config.get("forwarding-secret-file");
|
||||||
final Path secretPath = forwardSecretFile == null
|
final Path secretPath = forwardSecretFile == null
|
||||||
? defaultForwardingSecretPath
|
? defaultForwardingSecretPath
|
||||||
@@ -528,7 +528,11 @@ public class VelocityConfiguration implements ProxyConfig {
|
|||||||
"The file " + forwardSecretFile + " is not a valid file or it is a directory.");
|
"The file " + forwardSecretFile + " is not a valid file or it is a directory.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("The forwarding-secret-file does not exist.");
|
Files.createFile(secretPath);
|
||||||
|
Files.writeString(secretPath, forwardingSecretString = generateRandomString(12),
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
logger.info("The forwarding-secret-file does not exist. A new file has been created at {}",
|
||||||
|
forwardSecretFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final byte[] forwardingSecret = forwardingSecretString.getBytes(StandardCharsets.UTF_8);
|
final byte[] forwardingSecret = forwardingSecretString.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.DialogClearPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.DialogShowPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.EncryptionRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.EncryptionRequestPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.EncryptionResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.EncryptionResponsePacket;
|
||||||
@@ -48,6 +52,7 @@ import com.velocitypowered.proxy.protocol.packet.ServerDataPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCustomClickActionPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.SetCompressionPacket;
|
import com.velocitypowered.proxy.protocol.packet.SetCompressionPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
|
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.StatusRequestPacket;
|
||||||
@@ -67,6 +72,8 @@ import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerComma
|
|||||||
import com.velocitypowered.proxy.protocol.packet.config.ActiveFeaturesPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ActiveFeaturesPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductAcceptPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
||||||
@@ -364,4 +371,32 @@ public interface MinecraftSessionHandler {
|
|||||||
default boolean handle(ClientboundServerLinksPacket packet) {
|
default boolean handle(ClientboundServerLinksPacket packet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean handle(DialogClearPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(DialogShowPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(ServerboundCustomClickActionPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(CodeOfConductPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(CodeOfConductAcceptPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(ClientboundSoundEntityPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean handle(ClientboundStopSoundPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import com.velocitypowered.api.event.player.ServerResourcePackSendEvent;
|
|||||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.command.CommandGraphInjector;
|
import com.velocitypowered.proxy.command.CommandGraphInjector;
|
||||||
@@ -177,11 +179,13 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(BossBarPacket packet) {
|
public boolean handle(BossBarPacket packet) {
|
||||||
|
if (serverConn.getPlayer().getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||||
if (packet.getAction() == BossBarPacket.ADD) {
|
if (packet.getAction() == BossBarPacket.ADD) {
|
||||||
playerSessionHandler.getServerBossBars().add(packet.getUuid());
|
playerSessionHandler.getServerBossBars().add(packet.getUuid());
|
||||||
} else if (packet.getAction() == BossBarPacket.REMOVE) {
|
} else if (packet.getAction() == BossBarPacket.REMOVE) {
|
||||||
playerSessionHandler.getServerBossBars().remove(packet.getUuid());
|
playerSessionHandler.getServerBossBars().remove(packet.getUuid());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false; // forward
|
return false; // forward
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,31 +294,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register and unregister packets are simply forwarded to the server as-is.
|
|
||||||
if (PluginMessageUtil.isRegister(packet) || PluginMessageUtil.isUnregister(packet)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PluginMessageUtil.isMcBrand(packet)) {
|
|
||||||
PluginMessagePacket rewritten = PluginMessageUtil
|
|
||||||
.rewriteMinecraftBrand(packet,
|
|
||||||
server.getVersion(), playerConnection.getProtocolVersion());
|
|
||||||
playerConnection.write(rewritten);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
||||||
// Handled.
|
// Handled.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, copy);
|
String channel = packet.getChannel();
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||||
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
||||||
PluginMessagePacket copied = new PluginMessagePacket(
|
PluginMessagePacket copied = new PluginMessagePacket(
|
||||||
@@ -359,8 +346,13 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
// Inject commands from the proxy.
|
// Inject commands from the proxy.
|
||||||
final CommandGraphInjector<CommandSource> injector = server.getCommandManager().getInjector();
|
final CommandGraphInjector<CommandSource> injector = server.getCommandManager().getInjector();
|
||||||
injector.inject(rootNode, serverConn.getPlayer());
|
injector.inject(rootNode, serverConn.getPlayer());
|
||||||
|
|
||||||
|
// In 1.21.6 a confirmation prompt was added when executing a command via `run_command` click
|
||||||
|
// action if the command is unknown. To prevent this prompt we have to send the command.
|
||||||
|
if (this.playerConnection.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_6)) {
|
||||||
rootNode.removeChildByName("velocity:callback");
|
rootNode.removeChildByName("velocity:callback");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
server.getEventManager().fire(
|
server.getEventManager().fire(
|
||||||
new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode))
|
new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode))
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import com.velocitypowered.proxy.protocol.packet.ResourcePackResponsePacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket;
|
import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket;
|
||||||
@@ -256,7 +257,13 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(DisconnectPacket packet) {
|
public boolean handle(DisconnectPacket packet) {
|
||||||
serverConn.disconnect();
|
serverConn.disconnect();
|
||||||
|
// If the player receives a DisconnectPacket without a connection to a server in progress,
|
||||||
|
// it means that the backend server has kicked the player during reconfiguration
|
||||||
|
if (serverConn.getPlayer().getConnectionInFlight() != null) {
|
||||||
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
|
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
|
||||||
|
} else {
|
||||||
|
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet, true);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +365,12 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(CodeOfConductPacket packet) {
|
||||||
|
this.serverConn.getPlayer().getConnection().write(packet.retain());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnected() {
|
public void disconnected() {
|
||||||
resultFuture.completeExceptionally(
|
resultFuture.completeExceptionally(
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
|
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
|
||||||
smc.setAutoReading(false);
|
smc.setAutoReading(false);
|
||||||
clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop());
|
clientPlaySessionHandler.doSwitch().thenRunAsync(() -> smc.setAutoReading(true), smc.eventLoop());
|
||||||
} else {
|
} else {
|
||||||
// Initial login - the player is already in configuration state.
|
// Initial login - the player is already in configuration state.
|
||||||
server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConn));
|
server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConn));
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
|||||||
private boolean gracefulDisconnect = false;
|
private boolean gracefulDisconnect = false;
|
||||||
private BackendConnectionPhase connectionPhase = BackendConnectionPhases.UNKNOWN;
|
private BackendConnectionPhase connectionPhase = BackendConnectionPhases.UNKNOWN;
|
||||||
private final Map<Long, Long> pendingPings = new HashMap<>();
|
private final Map<Long, Long> pendingPings = new HashMap<>();
|
||||||
|
private @MonotonicNonNull Integer entityId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new server connection.
|
* Initializes a new server connection.
|
||||||
@@ -324,6 +326,14 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
|||||||
return pendingPings;
|
return pendingPings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityId(Integer entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that this server connection remains "active": the connection is established and not
|
* Ensures that this server connection remains "active": the connection is established and not
|
||||||
* closed, the player is still connected to the server, and the player still remains online.
|
* closed, the player is still connected to the server, and the player still remains online.
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ import com.velocitypowered.proxy.protocol.packet.PingIdentifyPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
|
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponsePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCustomClickActionPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductAcceptPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
||||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||||
@@ -205,6 +207,26 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(ServerboundCustomClickActionPacket packet) {
|
||||||
|
if (player.getConnectionInFlight() != null) {
|
||||||
|
player.getConnectionInFlight().ensureConnected().write(packet.retain());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(CodeOfConductAcceptPacket packet) {
|
||||||
|
if (this.player.getConnectionInFlight() != null) {
|
||||||
|
this.player.getConnectionInFlight().ensureConnected().write(packet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleGeneric(MinecraftPacket packet) {
|
public void handleGeneric(MinecraftPacket packet) {
|
||||||
VelocityServerConnection serverConnection = player.getConnectedServer();
|
VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.construc
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.brigadier.suggestion.Suggestion;
|
import com.mojang.brigadier.suggestion.Suggestion;
|
||||||
import com.velocitypowered.api.command.VelocityBrigadierMessage;
|
|
||||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||||
import com.velocitypowered.api.event.player.CookieReceiveEvent;
|
import com.velocitypowered.api.event.player.CookieReceiveEvent;
|
||||||
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
|
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
|
||||||
@@ -30,6 +29,8 @@ import com.velocitypowered.api.event.player.TabCompleteEvent;
|
|||||||
import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent;
|
import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.connection.ConnectionTypes;
|
import com.velocitypowered.proxy.connection.ConnectionTypes;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
@@ -87,6 +88,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentLike;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@@ -339,26 +341,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!player.getPhase().handle(player, packet, serverConn)) {
|
if (!player.getPhase().handle(player, packet, serverConn)) {
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
// We don't have any plugins listening on this channel, process the packet now.
|
|
||||||
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
|
|
||||||
.consideredComplete()) {
|
|
||||||
// The client is trying to send messages too early. This is primarily caused by mods,
|
|
||||||
// but further aggravated by Velocity. To work around these issues, we will queue any
|
|
||||||
// non-FML handshake messages to be sent once the FML handshake has completed or the
|
|
||||||
// JoinGame packet has been received by the proxy, whichever comes first.
|
|
||||||
//
|
|
||||||
// We also need to make sure to retain these packets, so they can be flushed
|
|
||||||
// appropriately.
|
|
||||||
loginPluginMessages.add(packet.retain());
|
|
||||||
} else {
|
|
||||||
// The connection is ready, send the packet now.
|
|
||||||
backendConn.write(packet.retain());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy);
|
String channel = packet.getChannel();
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||||
if (pme.getResult().isAllowed()) {
|
if (pme.getResult().isAllowed()) {
|
||||||
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
||||||
@@ -378,7 +363,6 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -535,9 +519,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
// Config state clears everything in the client. No need to clear later.
|
// Config state clears everything in the client. No need to clear later.
|
||||||
spawned = false;
|
spawned = false;
|
||||||
serverBossBars.clear();
|
|
||||||
player.clearPlayerListHeaderAndFooterSilent();
|
player.clearPlayerListHeaderAndFooterSilent();
|
||||||
player.getTabList().clearAllSilent();
|
player.getTabList().clearAllSilent();
|
||||||
|
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||||
|
player.getBossBarManager().dropPackets();
|
||||||
|
} else {
|
||||||
|
serverBossBars.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.switchToConfigState();
|
player.switchToConfigState();
|
||||||
@@ -575,8 +563,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove previous boss bars. These don't get cleared when sending JoinGame, thus the need to
|
destination.setEntityId(joinGame.getEntityId()); // used for sound api
|
||||||
// track them.
|
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||||
|
player.getBossBarManager().sendBossBars();
|
||||||
|
} else {
|
||||||
|
// Remove previous boss bars. These don't get cleared when sending JoinGame (up until 1.20.2),
|
||||||
|
// thus the need to track them.
|
||||||
for (UUID serverBossBar : serverBossBars) {
|
for (UUID serverBossBar : serverBossBars) {
|
||||||
BossBarPacket deletePacket = new BossBarPacket();
|
BossBarPacket deletePacket = new BossBarPacket();
|
||||||
deletePacket.setUuid(serverBossBar);
|
deletePacket.setUuid(serverBossBar);
|
||||||
@@ -584,6 +576,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
player.getConnection().delayedWrite(deletePacket);
|
player.getConnection().delayedWrite(deletePacket);
|
||||||
}
|
}
|
||||||
serverBossBars.clear();
|
serverBossBars.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the server about the proxy's plugin message channels.
|
// Tell the server about the proxy's plugin message channels.
|
||||||
ProtocolVersion serverVersion = serverMc.getProtocolVersion();
|
ProtocolVersion serverVersion = serverMc.getProtocolVersion();
|
||||||
@@ -694,23 +687,35 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int startPos = -1;
|
||||||
|
for (var suggestion : suggestions.getList()) {
|
||||||
|
if (startPos == -1 || startPos > suggestion.getRange().getStart()) {
|
||||||
|
startPos = suggestion.getRange().getStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPos > 0) {
|
||||||
List<Offer> offers = new ArrayList<>();
|
List<Offer> offers = new ArrayList<>();
|
||||||
for (Suggestion suggestion : suggestions.getList()) {
|
for (Suggestion suggestion : suggestions.getList()) {
|
||||||
String offer = suggestion.getText();
|
String offer;
|
||||||
|
if (suggestion.getRange().getStart() == startPos) {
|
||||||
|
offer = suggestion.getText();
|
||||||
|
} else {
|
||||||
|
offer = command.substring(startPos, suggestion.getRange().getStart()) + suggestion.getText();
|
||||||
|
}
|
||||||
ComponentHolder tooltip = null;
|
ComponentHolder tooltip = null;
|
||||||
if (suggestion.getTooltip() != null
|
if (suggestion.getTooltip() instanceof ComponentLike componentLike) {
|
||||||
&& suggestion.getTooltip() instanceof VelocityBrigadierMessage) {
|
tooltip = new ComponentHolder(player.getProtocolVersion(), componentLike.asComponent());
|
||||||
tooltip = new ComponentHolder(player.getProtocolVersion(),
|
} else if (suggestion.getTooltip() != null) {
|
||||||
((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent());
|
tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
|
||||||
}
|
}
|
||||||
offers.add(new Offer(offer, tooltip));
|
offers.add(new Offer(offer, tooltip));
|
||||||
}
|
}
|
||||||
int startPos = packet.getCommand().lastIndexOf(' ') + 1;
|
|
||||||
if (startPos > 0) {
|
|
||||||
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
|
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
|
||||||
resp.setTransactionId(packet.getTransactionId());
|
resp.setTransactionId(packet.getTransactionId());
|
||||||
resp.setStart(startPos);
|
resp.setStart(startPos + 1);
|
||||||
resp.setLength(packet.getCommand().length() - startPos);
|
resp.setLength(packet.getCommand().length() - startPos - 1);
|
||||||
resp.getOffers().addAll(offers);
|
resp.getOffers().addAll(offers);
|
||||||
player.getConnection().write(resp);
|
player.getConnection().write(resp);
|
||||||
}
|
}
|
||||||
@@ -765,10 +770,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
offer = offer.substring(command.length());
|
offer = offer.substring(command.length());
|
||||||
}
|
}
|
||||||
ComponentHolder tooltip = null;
|
ComponentHolder tooltip = null;
|
||||||
if (suggestion.getTooltip() != null
|
if (suggestion.getTooltip() instanceof ComponentLike componentLike) {
|
||||||
&& suggestion.getTooltip() instanceof VelocityBrigadierMessage) {
|
tooltip = new ComponentHolder(player.getProtocolVersion(), componentLike.asComponent());
|
||||||
tooltip = new ComponentHolder(player.getProtocolVersion(),
|
} else if (suggestion.getTooltip() != null) {
|
||||||
((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent());
|
tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
|
||||||
}
|
}
|
||||||
response.getOffers().add(new Offer(offer, tooltip));
|
response.getOffers().add(new Offer(offer, tooltip));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import com.velocitypowered.proxy.adventure.VelocityBossBarImplementation;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
||||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||||
|
import com.velocitypowered.proxy.connection.player.bossbar.BossBarManager;
|
||||||
import com.velocitypowered.proxy.connection.player.bundle.BundleDelimiterHandler;
|
import com.velocitypowered.proxy.connection.player.bundle.BundleDelimiterHandler;
|
||||||
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
|
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.connection.player.resourcepack.handler.ResourcePackHandler;
|
import com.velocitypowered.proxy.connection.player.resourcepack.handler.ResourcePackHandler;
|
||||||
@@ -73,6 +74,8 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.HeaderAndFooterPacket;
|
import com.velocitypowered.proxy.protocol.packet.HeaderAndFooterPacket;
|
||||||
@@ -127,6 +130,8 @@ import net.kyori.adventure.pointer.PointersSupplier;
|
|||||||
import net.kyori.adventure.resource.ResourcePackInfoLike;
|
import net.kyori.adventure.resource.ResourcePackInfoLike;
|
||||||
import net.kyori.adventure.resource.ResourcePackRequest;
|
import net.kyori.adventure.resource.ResourcePackRequest;
|
||||||
import net.kyori.adventure.resource.ResourcePackRequestLike;
|
import net.kyori.adventure.resource.ResourcePackRequestLike;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
|
import net.kyori.adventure.sound.SoundStop;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||||
@@ -197,6 +202,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
private @Nullable ClientSettingsPacket clientSettingsPacket;
|
private @Nullable ClientSettingsPacket clientSettingsPacket;
|
||||||
private volatile ChatQueue chatQueue;
|
private volatile ChatQueue chatQueue;
|
||||||
private final ChatBuilderFactory chatBuilderFactory;
|
private final ChatBuilderFactory chatBuilderFactory;
|
||||||
|
private final BossBarManager bossBarManager;
|
||||||
|
|
||||||
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
||||||
@Nullable InetSocketAddress virtualHost, @Nullable String rawVirtualHost, boolean onlineMode,
|
@Nullable InetSocketAddress virtualHost, @Nullable String rawVirtualHost, boolean onlineMode,
|
||||||
@@ -223,6 +229,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
this.chatQueue = new ChatQueue(this);
|
this.chatQueue = new ChatQueue(this);
|
||||||
this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion());
|
this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion());
|
||||||
this.resourcePackHandler = ResourcePackHandler.create(this, server);
|
this.resourcePackHandler = ResourcePackHandler.create(this, server);
|
||||||
|
this.bossBarManager = new BossBarManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -733,15 +740,19 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
Component disconnectReason = disconnect.getReason().getComponent();
|
Component disconnectReason = disconnect.getReason().getComponent();
|
||||||
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
|
String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason);
|
||||||
if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
|
if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) {
|
||||||
|
if (this.server.getConfiguration().isLogPlayerConnections()) {
|
||||||
logger.info("{}: kicked from server {}: {}", this, server.getServerInfo().getName(),
|
logger.info("{}: kicked from server {}: {}", this, server.getServerInfo().getName(),
|
||||||
plainTextReason);
|
plainTextReason);
|
||||||
|
}
|
||||||
handleConnectionException(server, disconnectReason,
|
handleConnectionException(server, disconnectReason,
|
||||||
Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED,
|
Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED,
|
||||||
Component.text(server.getServerInfo().getName()),
|
Component.text(server.getServerInfo().getName()),
|
||||||
disconnectReason), safe);
|
disconnectReason), safe);
|
||||||
} else {
|
} else {
|
||||||
|
if (this.server.getConfiguration().isLogPlayerConnections()) {
|
||||||
logger.error("{}: disconnected while connecting to {}: {}", this,
|
logger.error("{}: disconnected while connecting to {}: {}", this,
|
||||||
server.getServerInfo().getName(), plainTextReason);
|
server.getServerInfo().getName(), plainTextReason);
|
||||||
|
}
|
||||||
handleConnectionException(server, disconnectReason,
|
handleConnectionException(server, disconnectReason,
|
||||||
Component.translatable("velocity.error.cant-connect", NamedTextColor.RED,
|
Component.translatable("velocity.error.cant-connect", NamedTextColor.RED,
|
||||||
Component.text(server.getServerInfo().getName()),
|
Component.text(server.getServerInfo().getName()),
|
||||||
@@ -806,9 +817,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
createConnectionRequest(res.getServer(), previousConnection).connect()
|
createConnectionRequest(res.getServer(), previousConnection).connect()
|
||||||
.whenCompleteAsync((status, throwable) -> {
|
.whenCompleteAsync((status, throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
handleConnectionException(
|
handleConnectionException(res.getServer(), throwable, true);
|
||||||
status != null ? status.getAttemptedConnection() : res.getServer(), throwable,
|
|
||||||
true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,6 +1047,50 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
this.clientBrand = clientBrand;
|
this.clientBrand = clientBrand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playSound(@NotNull Sound sound, @NotNull Sound.Emitter emitter) {
|
||||||
|
Preconditions.checkNotNull(sound, "sound");
|
||||||
|
Preconditions.checkNotNull(emitter, "emitter");
|
||||||
|
VelocityServerConnection soundTargetServerConn = getConnectedServer();
|
||||||
|
if (getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_19_3)
|
||||||
|
|| connection.getState() != StateRegistry.PLAY
|
||||||
|
|| soundTargetServerConn == null
|
||||||
|
|| (sound.source() == Sound.Source.UI
|
||||||
|
&& getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_5))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VelocityServerConnection soundEmitterServerConn;
|
||||||
|
if (emitter == Sound.Emitter.self()) {
|
||||||
|
soundEmitterServerConn = soundTargetServerConn;
|
||||||
|
} else if (emitter instanceof ConnectedPlayer player) {
|
||||||
|
if ((soundEmitterServerConn = player.getConnectedServer()) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!soundEmitterServerConn.getServer().equals(soundTargetServerConn.getServer())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.write(new ClientboundSoundEntityPacket(sound, null, soundEmitterServerConn.getEntityId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopSound(@NotNull SoundStop stop) {
|
||||||
|
Preconditions.checkNotNull(stop, "stop");
|
||||||
|
if (getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_19_3)
|
||||||
|
|| connection.getState() != StateRegistry.PLAY
|
||||||
|
|| (stop.source() == Sound.Source.UI
|
||||||
|
&& getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_5))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.write(new ClientboundStopSoundPacket(stop));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transferToHost(final InetSocketAddress address) {
|
public void transferToHost(final InetSocketAddress address) {
|
||||||
Preconditions.checkNotNull(address);
|
Preconditions.checkNotNull(address);
|
||||||
@@ -1379,6 +1432,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
return handshakeIntent;
|
return handshakeIntent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BossBarManager getBossBarManager() {
|
||||||
|
return bossBarManager;
|
||||||
|
}
|
||||||
|
|
||||||
private final class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
|
private final class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
|
||||||
|
|
||||||
private final RegisteredServer toConnect;
|
private final RegisteredServer toConnect;
|
||||||
@@ -1438,7 +1495,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
VelocityServerConnection con =
|
VelocityServerConnection con =
|
||||||
new VelocityServerConnection(vrs, previousServer, ConnectedPlayer.this, server);
|
new VelocityServerConnection(vrs, previousServer, ConnectedPlayer.this, server);
|
||||||
connectionInFlight = con;
|
connectionInFlight = con;
|
||||||
return con.connect().whenCompleteAsync((result, exception) -> this.resetIfInFlightIs(con),
|
|
||||||
|
return con.connect().whenCompleteAsync((result, exception) -> {
|
||||||
|
if (result != null && !result.isSuccessful() && !result.isSafe()) {
|
||||||
|
handleConnectionException(result.getAttemptedConnection(),
|
||||||
|
// The only way for the reason to be null is if the result is safe
|
||||||
|
DisconnectPacket.create(result.getReasonComponent().orElseThrow(),
|
||||||
|
getProtocolVersion(), connection.getState()), false);
|
||||||
|
}
|
||||||
|
this.resetIfInFlightIs(con);
|
||||||
|
},
|
||||||
connection.eventLoop());
|
connection.eventLoop());
|
||||||
}, connection.eventLoop());
|
}, connection.eventLoop());
|
||||||
});
|
});
|
||||||
@@ -1452,22 +1518,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Result> connect() {
|
public CompletableFuture<Result> connect() {
|
||||||
return this.internalConnect().whenCompleteAsync((status, throwable) -> {
|
return this.internalConnect().thenApply(x -> x);
|
||||||
if (status != null && !status.isSuccessful()) {
|
|
||||||
if (!status.isSafe()) {
|
|
||||||
handleConnectionException(status.getAttemptedConnection(), throwable, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, connection.eventLoop()).thenApply(x -> x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> connectWithIndication() {
|
public CompletableFuture<Boolean> connectWithIndication() {
|
||||||
return internalConnect().whenCompleteAsync((status, throwable) -> {
|
return internalConnect().whenCompleteAsync((status, throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
// TODO: The exception handling from this is not very good. Find a better way.
|
handleConnectionException(toConnect, throwable, true);
|
||||||
handleConnectionException(status != null ? status.getAttemptedConnection() : toConnect,
|
|
||||||
throwable, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019-2023 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.connection.player.bossbar;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.adventure.VelocityBossBarImplementation;
|
||||||
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles dropping and resending boss bar packets on versions 1.20.2 and newer because the client now
|
||||||
|
* deletes all boss bars during the login phase, and sending update packets would cause the client to be disconnected.
|
||||||
|
*/
|
||||||
|
public final class BossBarManager {
|
||||||
|
|
||||||
|
private final ConnectedPlayer player;
|
||||||
|
private final Set<VelocityBossBarImplementation> bossBars = new HashSet<>();
|
||||||
|
|
||||||
|
private boolean dropPackets = false;
|
||||||
|
|
||||||
|
public BossBarManager(ConnectedPlayer player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the specified boss bar to be re-sent when a player changes server, and sends the update packet
|
||||||
|
* if the client is able to receive it and not be disconnected.
|
||||||
|
*/
|
||||||
|
public synchronized void writeUpdate(VelocityBossBarImplementation bar, BossBarPacket packet) {
|
||||||
|
this.bossBars.add(bar);
|
||||||
|
if (!this.dropPackets) {
|
||||||
|
this.player.getConnection().write(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified boss bar from the player to ensure it is not re-sent.
|
||||||
|
*/
|
||||||
|
public synchronized void remove(VelocityBossBarImplementation bar, BossBarPacket packet) {
|
||||||
|
this.bossBars.remove(bar);
|
||||||
|
if (!this.dropPackets) {
|
||||||
|
this.player.getConnection().write(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-creates the boss bars the player can see with any updates that may have occurred in the meantime,
|
||||||
|
* and allows update packets for those boss bars to be sent.
|
||||||
|
*/
|
||||||
|
public synchronized void sendBossBars() {
|
||||||
|
for (VelocityBossBarImplementation bossBar : bossBars) {
|
||||||
|
bossBar.createDirect(player);
|
||||||
|
}
|
||||||
|
this.dropPackets = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents the player from receiving boss bar update packets while logging in to a new server.
|
||||||
|
*/
|
||||||
|
public synchronized void dropPackets() {
|
||||||
|
this.dropPackets = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -111,7 +111,7 @@ public abstract sealed class ResourcePackHandler
|
|||||||
}
|
}
|
||||||
request.setRequired(queued.getShouldForce());
|
request.setRequired(queued.getShouldForce());
|
||||||
request.setPrompt(queued.getPrompt() == null ? null :
|
request.setPrompt(queued.getPrompt() == null ? null :
|
||||||
new ComponentHolder(player.getProtocolVersion(), queued.getPrompt()));
|
new ComponentHolder(player.getProtocolVersion(), player.translateMessage(queued.getPrompt())));
|
||||||
|
|
||||||
player.getConnection().write(request);
|
player.getConnection().write(request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import java.util.Locale;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common utilities for handling server list ping results.
|
* Common utilities for handling server list ping results.
|
||||||
@@ -107,6 +108,13 @@ public class ServerListPingHandler {
|
|||||||
if (response == fallback) {
|
if (response == fallback) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.getDescriptionComponent() == null) {
|
||||||
|
return response.asBuilder()
|
||||||
|
.description(Component.empty())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
return fallback;
|
return fallback;
|
||||||
|
|||||||
@@ -136,6 +136,10 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons
|
|||||||
if (!this.server.getCommandManager().executeAsync(this, command).join()) {
|
if (!this.server.getCommandManager().executeAsync(this, command).join()) {
|
||||||
sendMessage(Component.translatable("velocity.command.command-does-not-exist",
|
sendMessage(Component.translatable("velocity.command.command-does-not-exist",
|
||||||
NamedTextColor.RED));
|
NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (server.getConfiguration().isLogCommandExecutions()) {
|
||||||
|
logger.info("CONSOLE -> executed command /{}", command);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("An error occurred while running this command.", e);
|
logger.error("An error occurred while running this command.", e);
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public enum TransportType {
|
|||||||
return NIO;
|
return NIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IoUring.isAvailable() && !Boolean.getBoolean("velocity.disable-iouring-transport")) {
|
if (IoUring.isAvailable() && Boolean.getBoolean("velocity.enable-iouring-transport")) {
|
||||||
return IO_URING;
|
return IO_URING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,18 @@ public interface MinecraftPacket {
|
|||||||
|
|
||||||
boolean handle(MinecraftSessionHandler handler);
|
boolean handle(MinecraftSessionHandler handler);
|
||||||
|
|
||||||
default int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
default int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
default int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
default int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default int encodeSizeHint(ProtocolUtils.Direction direction,
|
||||||
|
ProtocolVersion version) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import net.kyori.adventure.nbt.BinaryTagIO;
|
|||||||
import net.kyori.adventure.nbt.BinaryTagType;
|
import net.kyori.adventure.nbt.BinaryTagType;
|
||||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
import net.kyori.adventure.text.serializer.json.JSONOptions;
|
||||||
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
|
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
|
||||||
@@ -61,6 +62,8 @@ public enum ProtocolUtils {
|
|||||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||||
.options(
|
.options(
|
||||||
OptionSchema.globalSchema().stateBuilder()
|
OptionSchema.globalSchema().stateBuilder()
|
||||||
|
// general options
|
||||||
|
.value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
|
||||||
// before 1.16
|
// before 1.16
|
||||||
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
|
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
|
||||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.VALUE_FIELD)
|
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.VALUE_FIELD)
|
||||||
@@ -69,6 +72,8 @@ public enum ProtocolUtils {
|
|||||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
||||||
|
// before 1.21.5
|
||||||
|
.value(JSONOptions.EMIT_CHANGE_PAGE_CLICK_EVENT_PAGE_AS_STRING, Boolean.TRUE)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
@@ -77,6 +82,8 @@ public enum ProtocolUtils {
|
|||||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||||
.options(
|
.options(
|
||||||
OptionSchema.globalSchema().stateBuilder()
|
OptionSchema.globalSchema().stateBuilder()
|
||||||
|
// general options
|
||||||
|
.value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
|
||||||
// after 1.16
|
// after 1.16
|
||||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
||||||
@@ -86,6 +93,8 @@ public enum ProtocolUtils {
|
|||||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
|
||||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
|
||||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
|
||||||
|
// before 1.21.5
|
||||||
|
.value(JSONOptions.EMIT_CHANGE_PAGE_CLICK_EVENT_PAGE_AS_STRING, Boolean.TRUE)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
@@ -94,6 +103,8 @@ public enum ProtocolUtils {
|
|||||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||||
.options(
|
.options(
|
||||||
OptionSchema.globalSchema().stateBuilder()
|
OptionSchema.globalSchema().stateBuilder()
|
||||||
|
// general options
|
||||||
|
.value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
|
||||||
// after 1.16
|
// after 1.16
|
||||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
|
||||||
@@ -103,6 +114,8 @@ public enum ProtocolUtils {
|
|||||||
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
|
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
|
||||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
|
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
|
||||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
||||||
|
// before 1.21.5
|
||||||
|
.value(JSONOptions.EMIT_CHANGE_PAGE_CLICK_EVENT_PAGE_AS_STRING, Boolean.TRUE)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
@@ -111,6 +124,8 @@ public enum ProtocolUtils {
|
|||||||
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
|
||||||
.options(
|
.options(
|
||||||
OptionSchema.globalSchema().stateBuilder()
|
OptionSchema.globalSchema().stateBuilder()
|
||||||
|
// general options
|
||||||
|
.value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
|
||||||
// after 1.16
|
// after 1.16
|
||||||
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
|
||||||
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.SNAKE_CASE)
|
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.SNAKE_CASE)
|
||||||
@@ -121,6 +136,7 @@ public enum ProtocolUtils {
|
|||||||
// after 1.21.5
|
// after 1.21.5
|
||||||
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, Boolean.FALSE)
|
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, Boolean.FALSE)
|
||||||
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
|
||||||
|
.value(JSONOptions.EMIT_CHANGE_PAGE_CLICK_EVENT_PAGE_AS_STRING, Boolean.FALSE)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
@@ -134,7 +150,7 @@ public enum ProtocolUtils {
|
|||||||
BinaryTagTypes.COMPOUND, BinaryTagTypes.INT_ARRAY, BinaryTagTypes.LONG_ARRAY};
|
BinaryTagTypes.COMPOUND, BinaryTagTypes.INT_ARRAY, BinaryTagTypes.LONG_ARRAY};
|
||||||
private static final QuietDecoderException BAD_VARINT_CACHED =
|
private static final QuietDecoderException BAD_VARINT_CACHED =
|
||||||
new QuietDecoderException("Bad VarInt decoded");
|
new QuietDecoderException("Bad VarInt decoded");
|
||||||
private static final int[] VAR_INT_LENGTHS = new int[65];
|
private static final int[] VAR_INT_LENGTHS = new int[33];
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (int i = 0; i <= 32; ++i) {
|
for (int i = 0; i <= 32; ++i) {
|
||||||
@@ -234,16 +250,15 @@ public enum ProtocolUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}.
|
* Directly encodes a 21-bit Minecraft VarInt, ready to be written with {@link ByteBuf#writeMedium(int)}.
|
||||||
* The upper 11 bits will be discarded.
|
* The upper 11 bits will be discarded.
|
||||||
*
|
*
|
||||||
* @param buf the buffer to read from
|
* @param value the value to encode
|
||||||
* @param value the integer to write
|
* @return the encoded value
|
||||||
*/
|
*/
|
||||||
public static void write21BitVarInt(ByteBuf buf, int value) {
|
public static int encode21BitVarInt(int value) {
|
||||||
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||||
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
return (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
||||||
buf.writeMedium(w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readString(ByteBuf buf) {
|
public static String readString(ByteBuf buf) {
|
||||||
@@ -272,12 +287,22 @@ public enum ProtocolUtils {
|
|||||||
checkFrame(buf.isReadable(length),
|
checkFrame(buf.isReadable(length),
|
||||||
"Trying to read a string that is too long (wanted %s, only have %s)", length,
|
"Trying to read a string that is too long (wanted %s, only have %s)", length,
|
||||||
buf.readableBytes());
|
buf.readableBytes());
|
||||||
String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8);
|
String str = buf.readString(length, StandardCharsets.UTF_8);
|
||||||
buf.skipBytes(length);
|
|
||||||
checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", str.length(), cap);
|
checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", str.length(), cap);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the size of the written {@code str} if encoded as a VarInt-prefixed UTF-8 string.
|
||||||
|
*
|
||||||
|
* @param str the string to write
|
||||||
|
* @return the encoded size
|
||||||
|
*/
|
||||||
|
public static int stringSizeHint(CharSequence str) {
|
||||||
|
int size = ByteBufUtil.utf8Bytes(str);
|
||||||
|
return varIntBytes(size) + size;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the specified {@code str} to the {@code buf} with a VarInt prefix.
|
* Writes the specified {@code str} to the {@code buf} with a VarInt prefix.
|
||||||
*
|
*
|
||||||
@@ -310,6 +335,16 @@ public enum ProtocolUtils {
|
|||||||
writeString(buf, key.asString());
|
writeString(buf, key.asString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the key to the buffer, dropping the "minecraft:" namespace when present.
|
||||||
|
*
|
||||||
|
* @param buf the buffer to write to
|
||||||
|
* @param key the key to write
|
||||||
|
*/
|
||||||
|
public static void writeMinimalKey(ByteBuf buf, Key key) {
|
||||||
|
writeString(buf, key.asMinimalString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a standard Mojang Text namespaced:key array from the buffer.
|
* Reads a standard Mojang Text namespaced:key array from the buffer.
|
||||||
*
|
*
|
||||||
@@ -775,6 +810,40 @@ public enum ProtocolUtils {
|
|||||||
return new IdentifiedKeyImpl(revision, key, expiry, signature);
|
return new IdentifiedKeyImpl(revision, key, expiry, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a {@link Sound.Source} from the buffer.
|
||||||
|
*
|
||||||
|
* @param buf the buffer
|
||||||
|
* @param version the protocol version
|
||||||
|
* @return the sound source
|
||||||
|
*/
|
||||||
|
public static Sound.Source readSoundSource(ByteBuf buf, ProtocolVersion version) {
|
||||||
|
int ordinal = readVarInt(buf);
|
||||||
|
|
||||||
|
if (version.lessThan(ProtocolVersion.MINECRAFT_1_21_5)
|
||||||
|
&& ordinal == Sound.Source.UI.ordinal()) {
|
||||||
|
throw new UnsupportedOperationException("UI sound-source is only supported in 1.21.5+");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sound.Source.values()[ordinal];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a {@link Sound.Source} to the buffer.
|
||||||
|
*
|
||||||
|
* @param buf the buffer
|
||||||
|
* @param version the protocol version
|
||||||
|
* @param source the sound source to write
|
||||||
|
*/
|
||||||
|
public static void writeSoundSource(ByteBuf buf, ProtocolVersion version, Sound.Source source) {
|
||||||
|
if (version.lessThan(ProtocolVersion.MINECRAFT_1_21_5)
|
||||||
|
&& source == Sound.Source.UI) {
|
||||||
|
throw new UnsupportedOperationException("UI sound-source is only supported in 1.21.5+");
|
||||||
|
}
|
||||||
|
|
||||||
|
writeVarInt(buf, source.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the direction in which a packet flows.
|
* Represents the direction in which a packet flows.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_2;
|
|||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_4;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_4;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_5;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_5;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_6;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_6;
|
||||||
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_9;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
||||||
@@ -58,7 +59,11 @@ import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.DialogClearPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.DialogShowPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.EncryptionRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.EncryptionRequestPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.EncryptionResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.EncryptionResponsePacket;
|
||||||
@@ -81,6 +86,7 @@ import com.velocitypowered.proxy.protocol.packet.ServerDataPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ServerboundCustomClickActionPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.SetCompressionPacket;
|
import com.velocitypowered.proxy.protocol.packet.SetCompressionPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
|
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.StatusRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.StatusRequestPacket;
|
||||||
@@ -88,6 +94,7 @@ import com.velocitypowered.proxy.protocol.packet.StatusResponsePacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
|
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
|
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
|
||||||
@@ -101,6 +108,8 @@ import com.velocitypowered.proxy.protocol.packet.chat.session.UnsignedPlayerComm
|
|||||||
import com.velocitypowered.proxy.protocol.packet.config.ActiveFeaturesPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ActiveFeaturesPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductAcceptPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
|
||||||
@@ -183,6 +192,12 @@ public enum StateRegistry {
|
|||||||
KnownPacksPacket.class,
|
KnownPacksPacket.class,
|
||||||
KnownPacksPacket::new,
|
KnownPacksPacket::new,
|
||||||
map(0x07, MINECRAFT_1_20_5, false));
|
map(0x07, MINECRAFT_1_20_5, false));
|
||||||
|
serverbound.register(ServerboundCustomClickActionPacket.class, ServerboundCustomClickActionPacket::new,
|
||||||
|
map(0x08, MINECRAFT_1_21_6, false));
|
||||||
|
serverbound.register(
|
||||||
|
CodeOfConductAcceptPacket.class,
|
||||||
|
() -> CodeOfConductAcceptPacket.INSTANCE,
|
||||||
|
map(0x09, MINECRAFT_1_21_9, false));
|
||||||
|
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
||||||
@@ -237,6 +252,12 @@ public enum StateRegistry {
|
|||||||
map(0x0F, MINECRAFT_1_21, false));
|
map(0x0F, MINECRAFT_1_21, false));
|
||||||
clientbound.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket::new,
|
clientbound.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket::new,
|
||||||
map(0x10, MINECRAFT_1_21, false));
|
map(0x10, MINECRAFT_1_21, false));
|
||||||
|
clientbound.register(DialogClearPacket.class, () -> DialogClearPacket.INSTANCE,
|
||||||
|
map(0x11, MINECRAFT_1_21_6, false));
|
||||||
|
clientbound.register(DialogShowPacket.class, () -> new DialogShowPacket(this),
|
||||||
|
map(0x12, MINECRAFT_1_21_6, false));
|
||||||
|
clientbound.register(CodeOfConductPacket.class, CodeOfConductPacket::new,
|
||||||
|
map(0x13, MINECRAFT_1_21_9, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PLAY {
|
PLAY {
|
||||||
@@ -430,6 +451,26 @@ public enum StateRegistry {
|
|||||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
||||||
map(0x16, MINECRAFT_1_20_5, false),
|
map(0x16, MINECRAFT_1_20_5, false),
|
||||||
map(0x15, MINECRAFT_1_21_5, false));
|
map(0x15, MINECRAFT_1_21_5, false));
|
||||||
|
clientbound.register(
|
||||||
|
ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
|
||||||
|
map(0x5D, MINECRAFT_1_19_3, true),
|
||||||
|
map(0x61, MINECRAFT_1_19_4, true),
|
||||||
|
map(0x63, MINECRAFT_1_20_2, true),
|
||||||
|
map(0x65, MINECRAFT_1_20_3, true),
|
||||||
|
map(0x67, MINECRAFT_1_20_5, true),
|
||||||
|
map(0x6E, MINECRAFT_1_21_2, true),
|
||||||
|
map(0x6D, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x72, MINECRAFT_1_21_9, true));
|
||||||
|
clientbound.register(
|
||||||
|
ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
|
||||||
|
map(0x5F, MINECRAFT_1_19_3, true),
|
||||||
|
map(0x63, MINECRAFT_1_19_4, true),
|
||||||
|
map(0x66, MINECRAFT_1_20_2, true),
|
||||||
|
map(0x68, MINECRAFT_1_20_3, true),
|
||||||
|
map(0x6A, MINECRAFT_1_20_5, true),
|
||||||
|
map(0x71, MINECRAFT_1_21_2, true),
|
||||||
|
map(0x70, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x75, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PluginMessagePacket.class,
|
PluginMessagePacket.class,
|
||||||
PluginMessagePacket::new,
|
PluginMessagePacket::new,
|
||||||
@@ -465,7 +506,8 @@ public enum StateRegistry {
|
|||||||
map(0x1A, MINECRAFT_1_19_4, false),
|
map(0x1A, MINECRAFT_1_19_4, false),
|
||||||
map(0x1B, MINECRAFT_1_20_2, false),
|
map(0x1B, MINECRAFT_1_20_2, false),
|
||||||
map(0x1D, MINECRAFT_1_20_5, false),
|
map(0x1D, MINECRAFT_1_20_5, false),
|
||||||
map(0x1C, MINECRAFT_1_21_5, false));
|
map(0x1C, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x20, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
KeepAlivePacket.class,
|
KeepAlivePacket.class,
|
||||||
KeepAlivePacket::new,
|
KeepAlivePacket::new,
|
||||||
@@ -484,7 +526,8 @@ public enum StateRegistry {
|
|||||||
map(0x24, MINECRAFT_1_20_2, false),
|
map(0x24, MINECRAFT_1_20_2, false),
|
||||||
map(0x26, MINECRAFT_1_20_5, false),
|
map(0x26, MINECRAFT_1_20_5, false),
|
||||||
map(0x27, MINECRAFT_1_21_2, false),
|
map(0x27, MINECRAFT_1_21_2, false),
|
||||||
map(0x26, MINECRAFT_1_21_5, false));
|
map(0x26, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x2B, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
JoinGamePacket.class,
|
JoinGamePacket.class,
|
||||||
JoinGamePacket::new,
|
JoinGamePacket::new,
|
||||||
@@ -503,7 +546,8 @@ public enum StateRegistry {
|
|||||||
map(0x29, MINECRAFT_1_20_2, false),
|
map(0x29, MINECRAFT_1_20_2, false),
|
||||||
map(0x2B, MINECRAFT_1_20_5, false),
|
map(0x2B, MINECRAFT_1_20_5, false),
|
||||||
map(0x2C, MINECRAFT_1_21_2, false),
|
map(0x2C, MINECRAFT_1_21_2, false),
|
||||||
map(0x2B, MINECRAFT_1_21_5, false));
|
map(0x2B, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x30, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RespawnPacket.class,
|
RespawnPacket.class,
|
||||||
RespawnPacket::new,
|
RespawnPacket::new,
|
||||||
@@ -525,14 +569,16 @@ public enum StateRegistry {
|
|||||||
map(0x45, MINECRAFT_1_20_3, true),
|
map(0x45, MINECRAFT_1_20_3, true),
|
||||||
map(0x47, MINECRAFT_1_20_5, true),
|
map(0x47, MINECRAFT_1_20_5, true),
|
||||||
map(0x4C, MINECRAFT_1_21_2, true),
|
map(0x4C, MINECRAFT_1_21_2, true),
|
||||||
map(0x4B, MINECRAFT_1_21_5, true));
|
map(0x4B, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x50, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RemoveResourcePackPacket.class,
|
RemoveResourcePackPacket.class,
|
||||||
RemoveResourcePackPacket::new,
|
RemoveResourcePackPacket::new,
|
||||||
map(0x43, MINECRAFT_1_20_3, false),
|
map(0x43, MINECRAFT_1_20_3, false),
|
||||||
map(0x45, MINECRAFT_1_20_5, false),
|
map(0x45, MINECRAFT_1_20_5, false),
|
||||||
map(0x4A, MINECRAFT_1_21_2, false),
|
map(0x4A, MINECRAFT_1_21_2, false),
|
||||||
map(0x49, MINECRAFT_1_21_5, false));
|
map(0x49, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x4E, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ResourcePackRequestPacket.class,
|
ResourcePackRequestPacket.class,
|
||||||
ResourcePackRequestPacket::new,
|
ResourcePackRequestPacket::new,
|
||||||
@@ -554,7 +600,8 @@ public enum StateRegistry {
|
|||||||
map(0x44, MINECRAFT_1_20_3, false),
|
map(0x44, MINECRAFT_1_20_3, false),
|
||||||
map(0x46, MINECRAFT_1_20_5, false),
|
map(0x46, MINECRAFT_1_20_5, false),
|
||||||
map(0x4B, MINECRAFT_1_21_2, false),
|
map(0x4B, MINECRAFT_1_21_2, false),
|
||||||
map(0x4A, MINECRAFT_1_21_5, false));
|
map(0x4A, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x4F, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
HeaderAndFooterPacket.class,
|
HeaderAndFooterPacket.class,
|
||||||
HeaderAndFooterPacket::new,
|
HeaderAndFooterPacket::new,
|
||||||
@@ -577,7 +624,8 @@ public enum StateRegistry {
|
|||||||
map(0x6A, MINECRAFT_1_20_3, true),
|
map(0x6A, MINECRAFT_1_20_3, true),
|
||||||
map(0x6D, MINECRAFT_1_20_5, true),
|
map(0x6D, MINECRAFT_1_20_5, true),
|
||||||
map(0x74, MINECRAFT_1_21_2, true),
|
map(0x74, MINECRAFT_1_21_2, true),
|
||||||
map(0x73, MINECRAFT_1_21_5, true));
|
map(0x73, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x78, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LegacyTitlePacket.class,
|
LegacyTitlePacket.class,
|
||||||
LegacyTitlePacket::new,
|
LegacyTitlePacket::new,
|
||||||
@@ -599,7 +647,8 @@ public enum StateRegistry {
|
|||||||
map(0x61, MINECRAFT_1_20_3, true),
|
map(0x61, MINECRAFT_1_20_3, true),
|
||||||
map(0x63, MINECRAFT_1_20_5, true),
|
map(0x63, MINECRAFT_1_20_5, true),
|
||||||
map(0x6A, MINECRAFT_1_21_2, true),
|
map(0x6A, MINECRAFT_1_21_2, true),
|
||||||
map(0x69, MINECRAFT_1_21_5, true));
|
map(0x69, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x6E, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTextPacket.class,
|
TitleTextPacket.class,
|
||||||
TitleTextPacket::new,
|
TitleTextPacket::new,
|
||||||
@@ -612,7 +661,8 @@ public enum StateRegistry {
|
|||||||
map(0x63, MINECRAFT_1_20_3, true),
|
map(0x63, MINECRAFT_1_20_3, true),
|
||||||
map(0x65, MINECRAFT_1_20_5, true),
|
map(0x65, MINECRAFT_1_20_5, true),
|
||||||
map(0x6C, MINECRAFT_1_21_2, true),
|
map(0x6C, MINECRAFT_1_21_2, true),
|
||||||
map(0x6B, MINECRAFT_1_21_5, true));
|
map(0x6B, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x70, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleActionbarPacket.class,
|
TitleActionbarPacket.class,
|
||||||
TitleActionbarPacket::new,
|
TitleActionbarPacket::new,
|
||||||
@@ -625,7 +675,8 @@ public enum StateRegistry {
|
|||||||
map(0x4A, MINECRAFT_1_20_3, true),
|
map(0x4A, MINECRAFT_1_20_3, true),
|
||||||
map(0x4C, MINECRAFT_1_20_5, true),
|
map(0x4C, MINECRAFT_1_20_5, true),
|
||||||
map(0x51, MINECRAFT_1_21_2, true),
|
map(0x51, MINECRAFT_1_21_2, true),
|
||||||
map(0x50, MINECRAFT_1_21_5, true));
|
map(0x50, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x55, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTimesPacket.class,
|
TitleTimesPacket.class,
|
||||||
TitleTimesPacket::new,
|
TitleTimesPacket::new,
|
||||||
@@ -638,7 +689,8 @@ public enum StateRegistry {
|
|||||||
map(0x64, MINECRAFT_1_20_3, true),
|
map(0x64, MINECRAFT_1_20_3, true),
|
||||||
map(0x66, MINECRAFT_1_20_5, true),
|
map(0x66, MINECRAFT_1_20_5, true),
|
||||||
map(0x6D, MINECRAFT_1_21_2, true),
|
map(0x6D, MINECRAFT_1_21_2, true),
|
||||||
map(0x6C, MINECRAFT_1_21_5, true));
|
map(0x6C, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x71, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleClearPacket.class,
|
TitleClearPacket.class,
|
||||||
TitleClearPacket::new,
|
TitleClearPacket::new,
|
||||||
@@ -668,7 +720,8 @@ public enum StateRegistry {
|
|||||||
map(0x3B, MINECRAFT_1_20_2, false),
|
map(0x3B, MINECRAFT_1_20_2, false),
|
||||||
map(0x3D, MINECRAFT_1_20_5, false),
|
map(0x3D, MINECRAFT_1_20_5, false),
|
||||||
map(0x3F, MINECRAFT_1_21_2, false),
|
map(0x3F, MINECRAFT_1_21_2, false),
|
||||||
map(0x3E, MINECRAFT_1_21_5, false));
|
map(0x3E, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x43, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
UpsertPlayerInfoPacket.class,
|
UpsertPlayerInfoPacket.class,
|
||||||
UpsertPlayerInfoPacket::new,
|
UpsertPlayerInfoPacket::new,
|
||||||
@@ -677,12 +730,14 @@ public enum StateRegistry {
|
|||||||
map(0x3C, MINECRAFT_1_20_2, false),
|
map(0x3C, MINECRAFT_1_20_2, false),
|
||||||
map(0x3E, MINECRAFT_1_20_5, false),
|
map(0x3E, MINECRAFT_1_20_5, false),
|
||||||
map(0x40, MINECRAFT_1_21_2, false),
|
map(0x40, MINECRAFT_1_21_2, false),
|
||||||
map(0x3F, MINECRAFT_1_21_5, false));
|
map(0x3F, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x44, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
||||||
map(0x6B, MINECRAFT_1_20_5, false),
|
map(0x6B, MINECRAFT_1_20_5, false),
|
||||||
map(0x72, MINECRAFT_1_21_2, false),
|
map(0x72, MINECRAFT_1_21_2, false),
|
||||||
map(0x71, MINECRAFT_1_21_5, false));
|
map(0x71, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x76, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
SystemChatPacket.class,
|
SystemChatPacket.class,
|
||||||
SystemChatPacket::new,
|
SystemChatPacket::new,
|
||||||
@@ -694,7 +749,8 @@ public enum StateRegistry {
|
|||||||
map(0x69, MINECRAFT_1_20_3, true),
|
map(0x69, MINECRAFT_1_20_3, true),
|
||||||
map(0x6C, MINECRAFT_1_20_5, true),
|
map(0x6C, MINECRAFT_1_20_5, true),
|
||||||
map(0x73, MINECRAFT_1_21_2, true),
|
map(0x73, MINECRAFT_1_21_2, true),
|
||||||
map(0x72, MINECRAFT_1_21_5, true));
|
map(0x72, MINECRAFT_1_21_5, true),
|
||||||
|
map(0x77, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PlayerChatCompletionPacket.class,
|
PlayerChatCompletionPacket.class,
|
||||||
PlayerChatCompletionPacket::new,
|
PlayerChatCompletionPacket::new,
|
||||||
@@ -715,7 +771,8 @@ public enum StateRegistry {
|
|||||||
map(0x49, MINECRAFT_1_20_3, false),
|
map(0x49, MINECRAFT_1_20_3, false),
|
||||||
map(0x4B, MINECRAFT_1_20_5, false),
|
map(0x4B, MINECRAFT_1_20_5, false),
|
||||||
map(0x50, MINECRAFT_1_21_2, false),
|
map(0x50, MINECRAFT_1_21_2, false),
|
||||||
map(0x4F, MINECRAFT_1_21_5, false));
|
map(0x4F, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x54, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
StartUpdatePacket.class,
|
StartUpdatePacket.class,
|
||||||
() -> StartUpdatePacket.INSTANCE,
|
() -> StartUpdatePacket.INSTANCE,
|
||||||
@@ -723,7 +780,8 @@ public enum StateRegistry {
|
|||||||
map(0x67, MINECRAFT_1_20_3, false),
|
map(0x67, MINECRAFT_1_20_3, false),
|
||||||
map(0x69, MINECRAFT_1_20_5, false),
|
map(0x69, MINECRAFT_1_20_5, false),
|
||||||
map(0x70, MINECRAFT_1_21_2, false),
|
map(0x70, MINECRAFT_1_21_2, false),
|
||||||
map(0x6F, MINECRAFT_1_21_5, false));
|
map(0x6F, MINECRAFT_1_21_5, false),
|
||||||
|
map(0x74, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
BundleDelimiterPacket.class,
|
BundleDelimiterPacket.class,
|
||||||
() -> BundleDelimiterPacket.INSTANCE,
|
() -> BundleDelimiterPacket.INSTANCE,
|
||||||
@@ -732,17 +790,36 @@ public enum StateRegistry {
|
|||||||
TransferPacket.class,
|
TransferPacket.class,
|
||||||
TransferPacket::new,
|
TransferPacket::new,
|
||||||
map(0x73, MINECRAFT_1_20_5, false),
|
map(0x73, MINECRAFT_1_20_5, false),
|
||||||
map(0x7A, MINECRAFT_1_21_2, false));
|
map(0x7A, MINECRAFT_1_21_2, false),
|
||||||
|
map(0x7F, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCustomReportDetailsPacket.class,
|
ClientboundCustomReportDetailsPacket.class,
|
||||||
ClientboundCustomReportDetailsPacket::new,
|
ClientboundCustomReportDetailsPacket::new,
|
||||||
map(0x7A, MINECRAFT_1_21, false),
|
map(0x7A, MINECRAFT_1_21, false),
|
||||||
map(0x81, MINECRAFT_1_21_2, false));
|
map(0x81, MINECRAFT_1_21_2, false),
|
||||||
|
map(0x86, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundServerLinksPacket.class,
|
ClientboundServerLinksPacket.class,
|
||||||
ClientboundServerLinksPacket::new,
|
ClientboundServerLinksPacket::new,
|
||||||
map(0x7B, MINECRAFT_1_21, false),
|
map(0x7B, MINECRAFT_1_21, false),
|
||||||
map(0x82, MINECRAFT_1_21_2, false));
|
map(0x82, MINECRAFT_1_21_2, false),
|
||||||
|
map(0x87, MINECRAFT_1_21_9, false));
|
||||||
|
clientbound.register(UpdateTeamsPacket.class, UpdateTeamsPacket::new,
|
||||||
|
map(0x41, ProtocolVersion.MINECRAFT_1_9, true),
|
||||||
|
map(0x43, ProtocolVersion.MINECRAFT_1_12, true),
|
||||||
|
map(0x44, ProtocolVersion.MINECRAFT_1_12_1, true),
|
||||||
|
map(0x47, ProtocolVersion.MINECRAFT_1_13, true),
|
||||||
|
map(0x4B, ProtocolVersion.MINECRAFT_1_14, true),
|
||||||
|
map(0x4C, ProtocolVersion.MINECRAFT_1_15, true),
|
||||||
|
map(0x55, ProtocolVersion.MINECRAFT_1_17, true),
|
||||||
|
map(0x58, ProtocolVersion.MINECRAFT_1_19_1, true),
|
||||||
|
map(0x56, ProtocolVersion.MINECRAFT_1_19_3, true),
|
||||||
|
map(0x5A, ProtocolVersion.MINECRAFT_1_19_4, true),
|
||||||
|
map(0x5C, ProtocolVersion.MINECRAFT_1_20_2, true),
|
||||||
|
map(0x5E, ProtocolVersion.MINECRAFT_1_20_3, true),
|
||||||
|
map(0x60, ProtocolVersion.MINECRAFT_1_20_5, true),
|
||||||
|
map(0x67, ProtocolVersion.MINECRAFT_1_21_2, true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LOGIN {
|
LOGIN {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder<By
|
|||||||
if (uncompressed < threshold) {
|
if (uncompressed < threshold) {
|
||||||
// Under the threshold, there is nothing to do.
|
// Under the threshold, there is nothing to do.
|
||||||
ProtocolUtils.writeVarInt(out, uncompressed + 1);
|
ProtocolUtils.writeVarInt(out, uncompressed + 1);
|
||||||
ProtocolUtils.writeVarInt(out, 0);
|
out.writeByte(0);
|
||||||
out.writeBytes(msg);
|
out.writeBytes(msg);
|
||||||
} else {
|
} else {
|
||||||
handleCompressed(ctx, msg, out);
|
handleCompressed(ctx, msg, out);
|
||||||
@@ -57,7 +57,7 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder<By
|
|||||||
throws DataFormatException {
|
throws DataFormatException {
|
||||||
int uncompressed = msg.readableBytes();
|
int uncompressed = msg.readableBytes();
|
||||||
|
|
||||||
ProtocolUtils.write21BitVarInt(out, 0); // Dummy packet length
|
out.writeMedium(0); // Reserve the packet length
|
||||||
ProtocolUtils.writeVarInt(out, uncompressed);
|
ProtocolUtils.writeVarInt(out, uncompressed);
|
||||||
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, msg);
|
ByteBuf compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, msg);
|
||||||
|
|
||||||
@@ -72,11 +72,8 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder<By
|
|||||||
throw new DataFormatException("The server sent a very large (over 2MiB compressed) packet.");
|
throw new DataFormatException("The server sent a very large (over 2MiB compressed) packet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int writerIndex = out.writerIndex();
|
|
||||||
int packetLength = out.readableBytes() - 3;
|
int packetLength = out.readableBytes() - 3;
|
||||||
out.writerIndex(0);
|
out.setMedium(0, ProtocolUtils.encode21BitVarInt(packetLength)); // Rewrite packet length
|
||||||
ProtocolUtils.write21BitVarInt(out, packetLength); // Rewrite packet length
|
|
||||||
out.writerIndex(writerIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -96,8 +96,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
|
private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
|
||||||
int expectedMinLen = packet.expectedMinLength(buf, direction, registry.version);
|
int expectedMinLen = packet.decodeExpectedMinLength(buf, direction, registry.version);
|
||||||
int expectedMaxLen = packet.expectedMaxLength(buf, direction, registry.version);
|
int expectedMaxLen = packet.decodeExpectedMaxLength(buf, direction, registry.version);
|
||||||
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
|
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
|
||||||
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
|
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,19 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
|
|||||||
msg.encode(out, direction, registry.version);
|
msg.encode(out, direction, registry.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, MinecraftPacket msg,
|
||||||
|
boolean preferDirect) throws Exception {
|
||||||
|
int hint = msg.encodeSizeHint(direction, registry.version);
|
||||||
|
if (hint < 0) {
|
||||||
|
return super.allocateBuffer(ctx, msg, preferDirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
int packetId = this.registry.getPacketId(msg);
|
||||||
|
int totalHint = ProtocolUtils.varIntBytes(packetId) + hint;
|
||||||
|
return preferDirect ? ctx.alloc().ioBuffer(totalHint) : ctx.alloc().heapBuffer(totalHint);
|
||||||
|
}
|
||||||
|
|
||||||
public void setProtocolVersion(final ProtocolVersion protocolVersion) {
|
public void setProtocolVersion(final ProtocolVersion protocolVersion) {
|
||||||
this.registry = state.getProtocolRegistry(direction, protocolVersion);
|
this.registry = state.getProtocolRegistry(direction, protocolVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,9 +83,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
// try to read the length of the packet
|
// try to read the length of the packet
|
||||||
in.markReaderIndex();
|
in.markReaderIndex();
|
||||||
int preIndex = in.readerIndex();
|
|
||||||
int length = readRawVarInt21(in);
|
int length = readRawVarInt21(in);
|
||||||
if (preIndex == in.readerIndex()) {
|
if (packetStart == in.readerIndex()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
@@ -94,6 +93,23 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
|
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
|
||||||
|
if (validateServerboundHandshakePacket(in, length)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that zero-length packets are ignored
|
||||||
|
if (length > 0) {
|
||||||
|
if (in.readableBytes() < length) {
|
||||||
|
in.resetReaderIndex();
|
||||||
|
} else {
|
||||||
|
out.add(in.readRetainedSlice(length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateServerboundHandshakePacket(ByteBuf in, int length) throws Exception {
|
||||||
StateRegistry.PacketRegistry.ProtocolRegistry registry =
|
StateRegistry.PacketRegistry.ProtocolRegistry registry =
|
||||||
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
|
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
|
||||||
|
|
||||||
@@ -102,7 +118,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
// Index hasn't changed, we've read nothing
|
// Index hasn't changed, we've read nothing
|
||||||
if (index == in.readerIndex()) {
|
if (index == in.readerIndex()) {
|
||||||
in.resetReaderIndex();
|
in.resetReaderIndex();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
||||||
|
|
||||||
@@ -115,8 +131,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
||||||
// the packet if needed, so, we'll take advantage of the existing methods
|
// the packet if needed, so, we'll take advantage of the existing methods
|
||||||
int expectedMinLen = packet.expectedMinLength(in, direction, registry.version);
|
int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version);
|
||||||
int expectedMaxLen = packet.expectedMaxLength(in, direction, registry.version);
|
int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version);
|
||||||
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
||||||
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
@@ -124,19 +140,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
in.readerIndex(index);
|
in.readerIndex(index);
|
||||||
}
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// note that zero-length packets are ignored
|
|
||||||
if (length > 0) {
|
|
||||||
if (in.readableBytes() < length) {
|
|
||||||
in.resetReaderIndex();
|
|
||||||
} else {
|
|
||||||
out.add(in.readRetainedSlice(length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -362,4 +362,12 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
|||||||
return builder.buildFuture();
|
return builder.buildFuture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
// This is a very complex packet to encode. Paper 1.21.10 + Velocity with Spark has a size of
|
||||||
|
// 30,334, but this is likely on the lower side. We'll use 128KiB as a more realistically-sized
|
||||||
|
// amount.
|
||||||
|
return 128 * 1024;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class ClientboundSoundEntityPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
private static final Random SEEDS_RANDOM = new Random();
|
||||||
|
|
||||||
|
private Sound sound;
|
||||||
|
private @Nullable Float fixedRange;
|
||||||
|
private int emitterEntityId;
|
||||||
|
|
||||||
|
public ClientboundSoundEntityPacket() {}
|
||||||
|
|
||||||
|
public ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange, int emitterEntityId) {
|
||||||
|
this.sound = sound;
|
||||||
|
this.fixedRange = fixedRange;
|
||||||
|
this.emitterEntityId = emitterEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
throw new UnsupportedOperationException("Decode is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
ProtocolUtils.writeVarInt(buf, 0); // version-dependent, hardcoded sound ID
|
||||||
|
|
||||||
|
ProtocolUtils.writeMinimalKey(buf, sound.name());
|
||||||
|
|
||||||
|
buf.writeBoolean(fixedRange != null);
|
||||||
|
if (fixedRange != null)
|
||||||
|
buf.writeFloat(fixedRange);
|
||||||
|
|
||||||
|
ProtocolUtils.writeSoundSource(buf, protocolVersion, sound.source());
|
||||||
|
|
||||||
|
ProtocolUtils.writeVarInt(buf, emitterEntityId);
|
||||||
|
|
||||||
|
buf.writeFloat(sound.volume());
|
||||||
|
|
||||||
|
buf.writeFloat(sound.pitch());
|
||||||
|
|
||||||
|
buf.writeLong(sound.seed().orElse(SEEDS_RANDOM.nextLong()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sound getSound() {
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSound(Sound sound) {
|
||||||
|
this.sound = sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Float getFixedRange() {
|
||||||
|
return fixedRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixedRange(@Nullable Float fixedRange) {
|
||||||
|
this.fixedRange = fixedRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEmitterEntityId() {
|
||||||
|
return emitterEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmitterEntityId(int emitterEntityId) {
|
||||||
|
this.emitterEntityId = emitterEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
|
import net.kyori.adventure.sound.SoundStop;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class ClientboundStopSoundPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
private @Nullable Sound.Source source;
|
||||||
|
private @Nullable Key soundName;
|
||||||
|
|
||||||
|
public ClientboundStopSoundPacket() {}
|
||||||
|
|
||||||
|
public ClientboundStopSoundPacket(SoundStop soundStop) {
|
||||||
|
this(soundStop.source(), soundStop.sound());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientboundStopSoundPacket(@Nullable Sound.Source source, @Nullable Key soundName) {
|
||||||
|
this.source = source;
|
||||||
|
this.soundName = soundName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
int flagsBitmask = buf.readByte();
|
||||||
|
|
||||||
|
if ((flagsBitmask & 1) != 0) {
|
||||||
|
source = ProtocolUtils.readSoundSource(buf, protocolVersion);
|
||||||
|
} else {
|
||||||
|
source = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flagsBitmask & 2) != 0) {
|
||||||
|
soundName = ProtocolUtils.readKey(buf);
|
||||||
|
} else {
|
||||||
|
soundName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
int flagsBitmask = 0;
|
||||||
|
if (source != null && soundName == null) {
|
||||||
|
flagsBitmask |= 1;
|
||||||
|
} else if (soundName != null && source == null) {
|
||||||
|
flagsBitmask |= 2;
|
||||||
|
} else if (source != null /*&& sound != null*/) {
|
||||||
|
flagsBitmask |= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.writeByte(flagsBitmask);
|
||||||
|
|
||||||
|
if (source != null) {
|
||||||
|
ProtocolUtils.writeSoundSource(buf, protocolVersion, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (soundName != null) {
|
||||||
|
ProtocolUtils.writeMinimalKey(buf, soundName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Sound.Source getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(@Nullable Sound.Source source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Key getSoundName() {
|
||||||
|
return soundName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoundName(@Nullable Key soundName) {
|
||||||
|
this.soundName = soundName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class DialogClearPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
public static final DialogClearPacket INSTANCE = new DialogClearPacket();
|
||||||
|
|
||||||
|
private DialogClearPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.nbt.BinaryTag;
|
||||||
|
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||||
|
|
||||||
|
public class DialogShowPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
private final StateRegistry state;
|
||||||
|
private int id;
|
||||||
|
private BinaryTag nbt;
|
||||||
|
|
||||||
|
public DialogShowPacket(final StateRegistry state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
this.id = this.state == StateRegistry.CONFIG ? 0 : ProtocolUtils.readVarInt(buf);
|
||||||
|
if (this.id == 0) {
|
||||||
|
this.nbt = ProtocolUtils.readBinaryTag(buf, protocolVersion, BinaryTagIO.reader());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
if (this.state == StateRegistry.CONFIG) {
|
||||||
|
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
||||||
|
} else {
|
||||||
|
ProtocolUtils.writeVarInt(buf, this.id);
|
||||||
|
if (this.id == 0) {
|
||||||
|
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,7 +107,7 @@ public class EncryptionResponsePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
|
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
|
||||||
// The length prefix always winds up being 2 bytes.
|
// The length prefix always winds up being 2 bytes.
|
||||||
int base = 256 + 2 + 2;
|
int base = 256 + 2 + 2;
|
||||||
@@ -123,8 +123,8 @@ public class EncryptionResponsePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
int base = expectedMaxLength(buf, direction, version);
|
int base = decodeExpectedMaxLength(buf, direction, version);
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||||
// These are "optional"
|
// These are "optional"
|
||||||
base -= 128 + 8;
|
base -= 128 + 8;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class HandshakePacket implements MinecraftPacket {
|
public class HandshakePacket implements MinecraftPacket {
|
||||||
@@ -108,14 +109,21 @@ public class HandshakePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||||
|
// sizes of this packet.
|
||||||
|
return 4 * 1024;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class LoginAcknowledgedPacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
@@ -86,4 +87,9 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
@@ -88,4 +89,9 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
@@ -143,4 +144,9 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr
|
|||||||
public PluginMessagePacket touch(Object hint) {
|
public PluginMessagePacket touch(Object hint) {
|
||||||
return (PluginMessagePacket) super.touch(hint);
|
return (PluginMessagePacket) super.touch(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.velocitypowered.api.util.Favicon;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -121,4 +122,9 @@ public class ServerDataPacket implements MinecraftPacket {
|
|||||||
public void setSecureChatEnforced(boolean secureChatEnforced) {
|
public void setSecureChatEnforced(boolean secureChatEnforced) {
|
||||||
this.secureChatEnforced = secureChatEnforced;
|
this.secureChatEnforced = secureChatEnforced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return 8 * 1024;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ public class ServerLoginPacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
|
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
|
||||||
// legal on the protocol level.
|
// legal on the protocol level.
|
||||||
int base = 1 + (16 * 3);
|
int base = 1 + (16 * 3);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.velocitypowered.api.util.UuidUtils;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.util.VelocityProperties;
|
import com.velocitypowered.proxy.util.VelocityProperties;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -132,4 +133,11 @@ public class ServerLoginSuccessPacket implements MinecraftPacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||||
|
// sizes of this packet.
|
||||||
|
return 4 * 1024;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||||
|
|
||||||
|
public ServerboundCustomClickActionPacket() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||||
|
replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||||
|
buf.writeBytes(content());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,12 +44,12 @@ public class StatusPingPacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class StatusRequestPacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
@@ -66,4 +67,9 @@ public class StatusResponsePacket implements MinecraftPacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return ProtocolUtils.stringSizeHint(this.status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UpdateTeamsPacket implements MinecraftPacket {
|
||||||
|
private String name;
|
||||||
|
private Mode mode;
|
||||||
|
|
||||||
|
private Component displayName;
|
||||||
|
private Component prefix;
|
||||||
|
private Component suffix;
|
||||||
|
private NameTagVisibility nameTagVisibility;
|
||||||
|
private CollisionRule collisionRule;
|
||||||
|
private int color;
|
||||||
|
private byte friendlyFlags;
|
||||||
|
|
||||||
|
private List<String> players;
|
||||||
|
|
||||||
|
public UpdateTeamsPacket(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
|
||||||
|
this.name = name;
|
||||||
|
this.mode = mode;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.suffix = suffix;
|
||||||
|
this.nameTagVisibility = nameTagVisibility;
|
||||||
|
this.collisionRule = collisionRule;
|
||||||
|
this.color = color;
|
||||||
|
this.friendlyFlags = friendlyFlags;
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateTeamsPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
throw new UnsupportedOperationException("Packet is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, name);
|
||||||
|
byteBuf.writeByte(mode.ordinal());
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CREATE, UPDATE:
|
||||||
|
new ComponentHolder(protocolVersion, displayName).write(byteBuf);
|
||||||
|
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||||
|
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||||
|
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||||
|
}
|
||||||
|
byteBuf.writeByte(friendlyFlags);
|
||||||
|
ProtocolUtils.writeString(byteBuf, nameTagVisibility.getValue());
|
||||||
|
ProtocolUtils.writeString(byteBuf, collisionRule.getValue());
|
||||||
|
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, color);
|
||||||
|
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||||
|
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||||
|
} else {
|
||||||
|
byteBuf.writeByte((byte) color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||||
|
for (String player : players) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, player);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADD_PLAYER, REMOVE_PLAYER:
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||||
|
for (String player : players) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, player);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Mode {
|
||||||
|
CREATE,
|
||||||
|
REMOVE,
|
||||||
|
UPDATE,
|
||||||
|
ADD_PLAYER,
|
||||||
|
REMOVE_PLAYER,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NameTagVisibility {
|
||||||
|
ALWAYS("always"),
|
||||||
|
NEVER("never"),
|
||||||
|
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
|
||||||
|
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
NameTagVisibility(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CollisionRule {
|
||||||
|
ALWAYS("always"),
|
||||||
|
NEVER("never"),
|
||||||
|
PUSH_OTHER_TEAMS("pushOtherTeams"),
|
||||||
|
PUSH_OWN_TEAM("pushOwnTeam");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
CollisionRule(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mode getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getSuffix() {
|
||||||
|
return suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameTagVisibility getNameTagVisibility() {
|
||||||
|
return nameTagVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollisionRule getCollisionRule() {
|
||||||
|
return collisionRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getFriendlyFlags() {
|
||||||
|
return friendlyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMode(Mode mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(Component displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(Component prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuffix(Component suffix) {
|
||||||
|
this.suffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNameTagVisibility(NameTagVisibility nameTagVisibility) {
|
||||||
|
this.nameTagVisibility = nameTagVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollisionRule(CollisionRule collisionRule) {
|
||||||
|
this.collisionRule = collisionRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFriendlyFlags(byte friendlyFlags) {
|
||||||
|
this.friendlyFlags = friendlyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayers(List<String> players) {
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,8 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
private static final Action[] ALL_ACTIONS = Action.class.getEnumConstants();
|
||||||
|
|
||||||
private final EnumSet<Action> actions;
|
private final EnumSet<Action> actions;
|
||||||
private final List<Entry> entries;
|
private final List<Entry> entries;
|
||||||
|
|
||||||
@@ -85,14 +87,13 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion protocolVersion) {
|
ProtocolVersion protocolVersion) {
|
||||||
Action[] actions = Action.class.getEnumConstants();
|
byte[] bytes = new byte[-Math.floorDiv(-ALL_ACTIONS.length, 8)];
|
||||||
byte[] bytes = new byte[-Math.floorDiv(-actions.length, 8)];
|
|
||||||
buf.readBytes(bytes);
|
buf.readBytes(bytes);
|
||||||
BitSet actionSet = BitSet.valueOf(bytes);
|
BitSet actionSet = BitSet.valueOf(bytes);
|
||||||
|
|
||||||
for (int idx = 0; idx < actions.length; idx++) {
|
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||||
if (actionSet.get(idx)) {
|
if (actionSet.get(idx)) {
|
||||||
addAction(actions[idx]);
|
addAction(ALL_ACTIONS[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,14 +110,13 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion protocolVersion) {
|
ProtocolVersion protocolVersion) {
|
||||||
Action[] actions = Action.class.getEnumConstants();
|
BitSet set = new BitSet(ALL_ACTIONS.length);
|
||||||
BitSet set = new BitSet(actions.length);
|
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||||
for (int idx = 0; idx < actions.length; idx++) {
|
set.set(idx, this.actions.contains(ALL_ACTIONS[idx]));
|
||||||
set.set(idx, this.actions.contains(actions[idx]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = set.toByteArray();
|
byte[] bytes = set.toByteArray();
|
||||||
buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-actions.length, 8)));
|
buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-ALL_ACTIONS.length, 8)));
|
||||||
|
|
||||||
ProtocolUtils.writeVarInt(buf, this.entries.size());
|
ProtocolUtils.writeVarInt(buf, this.entries.size());
|
||||||
for (Entry entry : this.entries) {
|
for (Entry entry : this.entries) {
|
||||||
@@ -133,12 +133,6 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitSet readFixedBitSet(ByteBuf buf, int param0) {
|
|
||||||
byte[] var0 = new byte[-Math.floorDiv(-param0, 8)];
|
|
||||||
buf.readBytes(var0);
|
|
||||||
return BitSet.valueOf(var0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Action {
|
public enum Action {
|
||||||
ADD_PLAYER((ignored, buf, info) -> { // read
|
ADD_PLAYER((ignored, buf, info) -> { // read
|
||||||
info.profile = new GameProfile(
|
info.profile = new GameProfile(
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ import com.mojang.brigadier.arguments.StringArgumentType;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -87,9 +89,6 @@ public class ArgumentPropertyRegistry {
|
|||||||
ArgumentIdentifier identifier = readIdentifier(buf, protocolVersion);
|
ArgumentIdentifier identifier = readIdentifier(buf, protocolVersion);
|
||||||
|
|
||||||
ArgumentPropertySerializer<?> serializer = byIdentifier.get(identifier);
|
ArgumentPropertySerializer<?> serializer = byIdentifier.get(identifier);
|
||||||
if (serializer == null) {
|
|
||||||
throw new IllegalArgumentException("Argument type identifier " + identifier + " unknown.");
|
|
||||||
}
|
|
||||||
Object result = serializer.deserialize(buf, protocolVersion);
|
Object result = serializer.deserialize(buf, protocolVersion);
|
||||||
|
|
||||||
if (result instanceof ArgumentType) {
|
if (result instanceof ArgumentType) {
|
||||||
@@ -156,7 +155,7 @@ public class ArgumentPropertyRegistry {
|
|||||||
* @param protocolVersion the protocol version to use
|
* @param protocolVersion the protocol version to use
|
||||||
* @return the identifier read from the buffer
|
* @return the identifier read from the buffer
|
||||||
*/
|
*/
|
||||||
public static ArgumentIdentifier readIdentifier(ByteBuf buf, ProtocolVersion protocolVersion) {
|
public static @NotNull ArgumentIdentifier readIdentifier(ByteBuf buf, ProtocolVersion protocolVersion) {
|
||||||
if (protocolVersion.noLessThan(MINECRAFT_1_19)) {
|
if (protocolVersion.noLessThan(MINECRAFT_1_19)) {
|
||||||
int id = ProtocolUtils.readVarInt(buf);
|
int id = ProtocolUtils.readVarInt(buf);
|
||||||
for (ArgumentIdentifier i : byIdentifier.keySet()) {
|
for (ArgumentIdentifier i : byIdentifier.keySet()) {
|
||||||
@@ -173,8 +172,8 @@ public class ArgumentPropertyRegistry {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw new IllegalArgumentException("Argument type identifier " + identifier + " unknown.");
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.readByteArray(buf));
|
ProtocolUtils.readByteArray(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
|||||||
unsigned = true;
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
|||||||
this.salt = buf.readLong();
|
this.salt = buf.readLong();
|
||||||
this.signed = buf.readBoolean();
|
this.signed = buf.readBoolean();
|
||||||
if (this.signed) {
|
if (this.signed) {
|
||||||
|
this.signed = false;
|
||||||
this.signature = readMessageSignature(buf);
|
this.signature = readMessageSignature(buf);
|
||||||
} else {
|
} else {
|
||||||
this.signature = new byte[0];
|
this.signature = new byte[0];
|
||||||
|
|||||||
@@ -41,11 +41,14 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
this.command = ProtocolUtils.readString(buf, 256);
|
int cap = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5) ? 256 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE;
|
||||||
|
this.command = ProtocolUtils.readString(buf, cap);
|
||||||
this.timeStamp = Instant.ofEpochMilli(buf.readLong());
|
this.timeStamp = Instant.ofEpochMilli(buf.readLong());
|
||||||
this.salt = buf.readLong();
|
this.salt = buf.readLong();
|
||||||
this.argumentSignatures = new ArgumentSignatures(buf);
|
this.argumentSignatures = new ArgumentSignatures(buf);
|
||||||
this.lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
this.lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||||
|
|
||||||
|
this.argumentSignatures = new ArgumentSignatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
this.command = ProtocolUtils.readString(buf, 256);
|
this.command = ProtocolUtils.readString(buf, ProtocolUtils.DEFAULT_MAX_STRING_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet.config;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class CodeOfConductAcceptPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket();
|
||||||
|
|
||||||
|
private CodeOfConductAcceptPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2025 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet.config;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class CodeOfConductPacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||||
|
|
||||||
|
public CodeOfConductPacket() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
buf.writeBytes(this.content());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ public class FinishedUpdatePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
@@ -47,4 +48,9 @@ public class RegistrySyncPacket extends DeferredByteBufHolder implements Minecra
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
return content().readableBytes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class StartUpdatePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion version) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -79,4 +80,22 @@ public class TagsUpdatePacket implements MinecraftPacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
|
int size = ProtocolUtils.varIntBytes(tags.size());
|
||||||
|
for (Map.Entry<String, Map<String, int[]>> entry : tags.entrySet()) {
|
||||||
|
size += ProtocolUtils.stringSizeHint(entry.getKey());
|
||||||
|
size += ProtocolUtils.varIntBytes(entry.getValue().size());
|
||||||
|
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
||||||
|
size += ProtocolUtils.stringSizeHint(innerEntry.getKey());
|
||||||
|
size += ProtocolUtils.varIntBytes(innerEntry.getValue().length);
|
||||||
|
for (int innerEntryValue : innerEntry.getValue()) {
|
||||||
|
size += ProtocolUtils.varIntBytes(innerEntryValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=هناك {0} لاعبين متصلون با
|
|||||||
velocity.command.glist-view-all=لعرض اللاعبين على جميع السيرفرات استخدم /glist all
|
velocity.command.glist-view-all=لعرض اللاعبين على جميع السيرفرات استخدم /glist all
|
||||||
velocity.command.reload-success=تم إعادة تحميل إعدادات Velocity بنجاح.
|
velocity.command.reload-success=تم إعادة تحميل إعدادات Velocity بنجاح.
|
||||||
velocity.command.reload-failure=فشلت إعادة تحميل إعدادات Velocity. تفقد الـconsole للمزيد من التفاصيل.
|
velocity.command.reload-failure=فشلت إعادة تحميل إعدادات Velocity. تفقد الـconsole للمزيد من التفاصيل.
|
||||||
velocity.command.version-copyright=حقوق الطبع والنشر 2018-2023 {0}. {1} مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3).
|
velocity.command.version-copyright=حقوق الطبع والنشر 2018-{2} {0}. {1} مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3).
|
||||||
velocity.command.no-plugins=لا توجد إضافات مثبتة على Velocity.
|
velocity.command.no-plugins=لا توجد إضافات مثبتة على Velocity.
|
||||||
velocity.command.plugins-list=الإضافات\: {0}
|
velocity.command.plugins-list=الإضافات\: {0}
|
||||||
velocity.command.plugin-tooltip-website=موقعها\: {0}
|
velocity.command.plugin-tooltip-website=موقعها\: {0}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ velocity.command.generic-error=Възникна грешка при изпълн
|
|||||||
velocity.command.command-does-not-exist=Тази команда не съществува.
|
velocity.command.command-does-not-exist=Тази команда не съществува.
|
||||||
velocity.command.players-only=Само играчи могат да изпълняват тази команда.
|
velocity.command.players-only=Само играчи могат да изпълняват тази команда.
|
||||||
velocity.command.server-does-not-exist=Сървър с името {0} не съществува.
|
velocity.command.server-does-not-exist=Сървър с името {0} не съществува.
|
||||||
velocity.command.player-not-found=Този играч {0} не съществува.
|
velocity.command.player-not-found=Играч с името {0} не съществува.
|
||||||
velocity.command.server-current-server=В момента сте свързан към {0}.
|
velocity.command.server-current-server=В момента сте свързан към {0}.
|
||||||
velocity.command.server-too-many=Има прекалено много регистрирани сървъри. Използвайте TAB, за да видите всички налични сървъри.
|
velocity.command.server-too-many=Има прекалено много регистрирани сървъри. Използвайте TAB, за да видите всички налични сървъри.
|
||||||
velocity.command.server-available=Налични сървъри\:
|
velocity.command.server-available=Налични сървъри\:
|
||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} играчи са свързани къ
|
|||||||
velocity.command.glist-view-all=За да видите всички играчи, разпределени по сървъри, използвайте /glist all.
|
velocity.command.glist-view-all=За да видите всички играчи, разпределени по сървъри, използвайте /glist all.
|
||||||
velocity.command.reload-success=Настройките на Velocity бяха презаредени успешно.
|
velocity.command.reload-success=Настройките на Velocity бяха презаредени успешно.
|
||||||
velocity.command.reload-failure=Не успяхме да презаредим настройките на Velocity. Моля, проверете конзолата за повече информация.
|
velocity.command.reload-failure=Не успяхме да презаредим настройките на Velocity. Моля, проверете конзолата за повече информация.
|
||||||
velocity.command.version-copyright=Авторско право 2018-2023 {0}. {1} е лицензиран под условията на GNU General Public License v3.
|
velocity.command.version-copyright=Авторско право 2018-{2} {0}. {1} е лицензиран под условията на GNU General Public License v3.
|
||||||
velocity.command.no-plugins=За момента няма инсталирани добавки.
|
velocity.command.no-plugins=За момента няма инсталирани добавки.
|
||||||
velocity.command.plugins-list=Добавки\: {0}
|
velocity.command.plugins-list=Добавки\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Уебсайт\: {0}
|
velocity.command.plugin-tooltip-website=Уебсайт\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=Počet hráčů připojených k tomuto prox
|
|||||||
velocity.command.glist-view-all=Ke zobrazení všech hráčů na všech serverech použij /glist all.
|
velocity.command.glist-view-all=Ke zobrazení všech hráčů na všech serverech použij /glist all.
|
||||||
velocity.command.reload-success=Konfigurace Velocity úspěšně načtena.
|
velocity.command.reload-success=Konfigurace Velocity úspěšně načtena.
|
||||||
velocity.command.reload-failure=Nebylo možné načíst konfiguraci Velocity. Podrobnosti jsou na konzoli.
|
velocity.command.reload-failure=Nebylo možné načíst konfiguraci Velocity. Podrobnosti jsou na konzoli.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} je licencovaný pod podmínkami GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licencovaný pod podmínkami GNU General Public License v3.
|
||||||
velocity.command.no-plugins=V tuto chvíli nejsou nainstalovány žádné zásuvné moduly.
|
velocity.command.no-plugins=V tuto chvíli nejsou nainstalovány žádné zásuvné moduly.
|
||||||
velocity.command.plugins-list=Zásuvné moduly\: {0}
|
velocity.command.plugins-list=Zásuvné moduly\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Webová stránka\: {0}
|
velocity.command.plugin-tooltip-website=Webová stránka\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spillere er i øjeblikket forbundet til
|
|||||||
velocity.command.glist-view-all=For at se alle spillere på servere, brug /glist all.
|
velocity.command.glist-view-all=For at se alle spillere på servere, brug /glist all.
|
||||||
velocity.command.reload-success=Velocity konfiguration blev genindlæst.
|
velocity.command.reload-success=Velocity konfiguration blev genindlæst.
|
||||||
velocity.command.reload-failure=Kan ikke genindlæse din Velocity konfiguration. Tjek konsollen for flere detaljer.
|
velocity.command.reload-failure=Kan ikke genindlæse din Velocity konfiguration. Tjek konsollen for flere detaljer.
|
||||||
velocity.command.version-copyright=Ophavsret 2018-2023 {0}. {1} er licenseret under betingelserne i GNU General Public License v3.
|
velocity.command.version-copyright=Ophavsret 2018-{2} {0}. {1} er licenseret under betingelserne i GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Der er ingen plugins installeret i øjeblikket.
|
velocity.command.no-plugins=Der er ingen plugins installeret i øjeblikket.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Hjemmeside\: {0}
|
velocity.command.plugin-tooltip-website=Hjemmeside\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} Spieler sind derzeit mit dem Proxy verb
|
|||||||
velocity.command.glist-view-all=Um alle Spieler auf Servern aufzulisten, verwende /glist all.
|
velocity.command.glist-view-all=Um alle Spieler auf Servern aufzulisten, verwende /glist all.
|
||||||
velocity.command.reload-success=Velocity-Konfiguration erfolgreich neu geladen.
|
velocity.command.reload-success=Velocity-Konfiguration erfolgreich neu geladen.
|
||||||
velocity.command.reload-failure=Die Velocity-Konfiguration konnte nicht neu geladen werden. Prüfe die Konsole für weitere Details.
|
velocity.command.reload-failure=Die Velocity-Konfiguration konnte nicht neu geladen werden. Prüfe die Konsole für weitere Details.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} ist lizenziert unter den Bedingungen der GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} ist lizenziert unter den Bedingungen der GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Es sind derzeit keine Plugins installiert.
|
velocity.command.no-plugins=Es sind derzeit keine Plugins installiert.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Webseite\: {0}
|
velocity.command.plugin-tooltip-website=Webseite\: {0}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ velocity.error.modern-forwarding-needs-new-client=Este servidor solo es compatib
|
|||||||
velocity.error.modern-forwarding-failed=El servidor no ha enviado una solicitud de reenvío al proxy. Asegúrate de que tu servidor está configurado para usar el método de reenvío de Velocity.
|
velocity.error.modern-forwarding-failed=El servidor no ha enviado una solicitud de reenvío al proxy. Asegúrate de que tu servidor está configurado para usar el método de reenvío de Velocity.
|
||||||
velocity.error.moved-to-new-server=Has sido echado de {0}\: {1}
|
velocity.error.moved-to-new-server=Has sido echado de {0}\: {1}
|
||||||
velocity.error.no-available-servers=No hay servidores disponibles a los que conectarte. Inténtalo de nuevo más tarde o contacta con un administrador.
|
velocity.error.no-available-servers=No hay servidores disponibles a los que conectarte. Inténtalo de nuevo más tarde o contacta con un administrador.
|
||||||
velocity.error.illegal-chat-characters=Illegal characters in chat
|
velocity.error.illegal-chat-characters=Caracteres no válidos en el chat
|
||||||
# Commands
|
# Commands
|
||||||
velocity.command.generic-error=Se ha producido un error al ejecutar este comando.
|
velocity.command.generic-error=Se ha producido un error al ejecutar este comando.
|
||||||
velocity.command.command-does-not-exist=Este comando no existe.
|
velocity.command.command-does-not-exist=Este comando no existe.
|
||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} jugadores están conectados al proxy.
|
|||||||
velocity.command.glist-view-all=Para ver todos los jugadores por servidores, usa /glist all.
|
velocity.command.glist-view-all=Para ver todos los jugadores por servidores, usa /glist all.
|
||||||
velocity.command.reload-success=La configuración de Velocity ha sido recargada correctamente.
|
velocity.command.reload-success=La configuración de Velocity ha sido recargada correctamente.
|
||||||
velocity.command.reload-failure=No ha sido posible recargar la configuración de Velocity. Para obtener más información, revisa la consola.
|
velocity.command.reload-failure=No ha sido posible recargar la configuración de Velocity. Para obtener más información, revisa la consola.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} está licenciado bajo los términos de la Licencia Pública General de GNU v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} está licenciado bajo los términos de la Licencia Pública General de GNU v3.
|
||||||
velocity.command.no-plugins=Actualmente no hay plugins instalados.
|
velocity.command.no-plugins=Actualmente no hay plugins instalados.
|
||||||
velocity.command.plugins-list=Complementos\: {0}
|
velocity.command.plugins-list=Complementos\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Página web\: {0}
|
velocity.command.plugin-tooltip-website=Página web\: {0}
|
||||||
@@ -60,6 +60,6 @@ velocity.command.dump-success=Se ha creado un informe anónimo que contiene info
|
|||||||
velocity.command.dump-will-expire=Este enlace caducará en unos días.
|
velocity.command.dump-will-expire=Este enlace caducará en unos días.
|
||||||
velocity.command.dump-server-error=Se ha producido un error en los servidores de Velocity y la subida no se ha podido completar. Notifica al equipo de Velocity sobre este problema y proporciona los detalles sobre este error disponibles en el archivo de registro o la consola de tu servidor Velocity.
|
velocity.command.dump-server-error=Se ha producido un error en los servidores de Velocity y la subida no se ha podido completar. Notifica al equipo de Velocity sobre este problema y proporciona los detalles sobre este error disponibles en el archivo de registro o la consola de tu servidor Velocity.
|
||||||
velocity.command.dump-offline=Causa probable\: la configuración DNS del sistema no es válida o no hay conexión a internet
|
velocity.command.dump-offline=Causa probable\: la configuración DNS del sistema no es válida o no hay conexión a internet
|
||||||
velocity.command.send-usage=/send <player> <server>
|
velocity.command.send-usage=/send <jugador> <servidor>
|
||||||
# Kick
|
# Kick
|
||||||
velocity.kick.shutdown=Proxy shutting down.
|
velocity.kick.shutdown=El proxy se ha apagado.
|
||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} players are currently connected to the
|
|||||||
velocity.command.glist-view-all=Et näha kõiki mängijaid kõikides serverites, kasuta käsklust /glist all.
|
velocity.command.glist-view-all=Et näha kõiki mängijaid kõikides serverites, kasuta käsklust /glist all.
|
||||||
velocity.command.reload-success=Velocity seadistus edukalt taaslaetud.
|
velocity.command.reload-success=Velocity seadistus edukalt taaslaetud.
|
||||||
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
|
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||||
velocity.command.no-plugins=There are no plugins currently installed.
|
velocity.command.no-plugins=There are no plugins currently installed.
|
||||||
velocity.command.plugins-list=Pluginad\: {0}
|
velocity.command.plugins-list=Pluginad\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Veebileht\: {0}
|
velocity.command.plugin-tooltip-website=Veebileht\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} pelaajaa on tällä hetkellä yhdistän
|
|||||||
velocity.command.glist-view-all=Nähdäksesi pelaajat kaikilla palvelimilla, käytä komentoa /glist all.
|
velocity.command.glist-view-all=Nähdäksesi pelaajat kaikilla palvelimilla, käytä komentoa /glist all.
|
||||||
velocity.command.reload-success=Velocityn konfiguraatio uudelleenladattiin onnistuneesti.
|
velocity.command.reload-success=Velocityn konfiguraatio uudelleenladattiin onnistuneesti.
|
||||||
velocity.command.reload-failure=Velocityn konfiguraation uudelleenlataus epäonnistui. Katso tarkemmat lisätiedot konsolista.
|
velocity.command.reload-failure=Velocityn konfiguraation uudelleenlataus epäonnistui. Katso tarkemmat lisätiedot konsolista.
|
||||||
velocity.command.version-copyright=Tekijänoikeus 2018-2023 {0}. {1} on lisensoitu GNU General Public License v3\:n ehtojen mukaisesti.
|
velocity.command.version-copyright=Tekijänoikeus 2018-{2} {0}. {1} on lisensoitu GNU General Public License v3\:n ehtojen mukaisesti.
|
||||||
velocity.command.no-plugins=Yhtäkään pluginia ei ole asennettu.
|
velocity.command.no-plugins=Yhtäkään pluginia ei ole asennettu.
|
||||||
velocity.command.plugins-list=Pluginit\: {0}
|
velocity.command.plugins-list=Pluginit\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Verkkosivu\: {0}
|
velocity.command.plugin-tooltip-website=Verkkosivu\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} joueurs sont actuellement connectés au
|
|||||||
velocity.command.glist-view-all=Pour afficher tous les joueurs connectés aux serveurs, utilisez /glist all.
|
velocity.command.glist-view-all=Pour afficher tous les joueurs connectés aux serveurs, utilisez /glist all.
|
||||||
velocity.command.reload-success=Configuration de Velocity rechargée avec succès.
|
velocity.command.reload-success=Configuration de Velocity rechargée avec succès.
|
||||||
velocity.command.reload-failure=Impossible de recharger votre configuration de Velocity. Consultez la console pour plus de détails.
|
velocity.command.reload-failure=Impossible de recharger votre configuration de Velocity. Consultez la console pour plus de détails.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} est sous la licence GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} est sous la licence GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Il n'y a aucun plugin actuellement installé.
|
velocity.command.no-plugins=Il n'y a aucun plugin actuellement installé.
|
||||||
velocity.command.plugins-list=Plugins \: {0}
|
velocity.command.plugins-list=Plugins \: {0}
|
||||||
velocity.command.plugin-tooltip-website=Site Internet \: {0}
|
velocity.command.plugin-tooltip-website=Site Internet \: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} שחקנים מחוברים כעת ל-
|
|||||||
velocity.command.glist-view-all=כדי להציג את כל השחקנים בשרתים, השתמש ב- glist all/.
|
velocity.command.glist-view-all=כדי להציג את כל השחקנים בשרתים, השתמש ב- glist all/.
|
||||||
velocity.command.reload-success=תצורת Velocity נטענה מחדש בהצלחה.
|
velocity.command.reload-success=תצורת Velocity נטענה מחדש בהצלחה.
|
||||||
velocity.command.reload-failure=אין אפשרות לטעון מחדש את תצורת ה- Velocity שלך. עיין בקונסולה לקבלת פרטים נוספים.
|
velocity.command.reload-failure=אין אפשרות לטעון מחדש את תצורת ה- Velocity שלך. עיין בקונסולה לקבלת פרטים נוספים.
|
||||||
velocity.command.version-copyright=זכויות יוצרים 2018-2023 {0}. {1} מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU.
|
velocity.command.version-copyright=זכויות יוצרים 2018-{2} {0}. {1} מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU.
|
||||||
velocity.command.no-plugins=לא מותקנים כעת תוספים.
|
velocity.command.no-plugins=לא מותקנים כעת תוספים.
|
||||||
velocity.command.plugins-list=תוספים\: {0}
|
velocity.command.plugins-list=תוספים\: {0}
|
||||||
velocity.command.plugin-tooltip-website=אתר אינטרנט\: {0}
|
velocity.command.plugin-tooltip-website=אתר אינטרנט\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} játékos van jelenleg csatlakozva a pr
|
|||||||
velocity.command.glist-view-all=Hogy megnézd az összes játékost az összes szerveren, használd a /glist all parancsot.
|
velocity.command.glist-view-all=Hogy megnézd az összes játékost az összes szerveren, használd a /glist all parancsot.
|
||||||
velocity.command.reload-success=A Velocity beállításai sikeresen frissítve lettek.
|
velocity.command.reload-success=A Velocity beállításai sikeresen frissítve lettek.
|
||||||
velocity.command.reload-failure=Hiba történt a Velocity beállításainak frissítése közben. Több információt a konzolban találsz.
|
velocity.command.reload-failure=Hiba történt a Velocity beállításainak frissítése közben. Több információt a konzolban találsz.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} licenszelve van a GNU General Public License v3 alatt.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} licenszelve van a GNU General Public License v3 alatt.
|
||||||
velocity.command.no-plugins=Jelenleg egyetlen plugin sincs telepítve.
|
velocity.command.no-plugins=Jelenleg egyetlen plugin sincs telepítve.
|
||||||
velocity.command.plugins-list=Pluginok\: {0}
|
velocity.command.plugins-list=Pluginok\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Weboldal\: {0}
|
velocity.command.plugin-tooltip-website=Weboldal\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} giocatori sono attualmente connessi al
|
|||||||
velocity.command.glist-view-all=Per visualizzare tutti i giocatori sui server, usa /glist all.
|
velocity.command.glist-view-all=Per visualizzare tutti i giocatori sui server, usa /glist all.
|
||||||
velocity.command.reload-success=La configurazione di Velocity è stata ricaricata con successo.
|
velocity.command.reload-success=La configurazione di Velocity è stata ricaricata con successo.
|
||||||
velocity.command.reload-failure=Impossibile ricaricare la configurazione di Velocity. Controlla la console per maggiori dettagli.
|
velocity.command.reload-failure=Impossibile ricaricare la configurazione di Velocity. Controlla la console per maggiori dettagli.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} è concesso in licenza secondo i termini della GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} è concesso in licenza secondo i termini della GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Non ci sono plugin installati.
|
velocity.command.no-plugins=Non ci sono plugin installati.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Sito web\: {0}
|
velocity.command.plugin-tooltip-website=Sito web\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} 人が現在プロキシに接続して
|
|||||||
velocity.command.glist-view-all=サーバー上のすべてのプレイヤーを表示するには、/glist allを使用してください。
|
velocity.command.glist-view-all=サーバー上のすべてのプレイヤーを表示するには、/glist allを使用してください。
|
||||||
velocity.command.reload-success=Velocityの設定が再読み込みされました。
|
velocity.command.reload-success=Velocityの設定が再読み込みされました。
|
||||||
velocity.command.reload-failure=Velocityの設定を再読み込みできません。詳細はコンソールで確認してください。
|
velocity.command.reload-failure=Velocityの設定を再読み込みできません。詳細はコンソールで確認してください。
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} は、GNU General Public License v3に基づいてライセンスされています。
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} は、GNU General Public License v3に基づいてライセンスされています。
|
||||||
velocity.command.no-plugins=現在インストールされているプラグインはありません。
|
velocity.command.no-plugins=現在インストールされているプラグインはありません。
|
||||||
velocity.command.plugins-list=プラグイン\: {0}
|
velocity.command.plugins-list=プラグイン\: {0}
|
||||||
velocity.command.plugin-tooltip-website=ウェブサイト\: {0}
|
velocity.command.plugin-tooltip-website=ウェブサイト\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=플레이어 {0}명이 현재 프록시에
|
|||||||
velocity.command.glist-view-all=서버에 있는 모든 플레이어를 보려면, /glist all을 사용하세요.
|
velocity.command.glist-view-all=서버에 있는 모든 플레이어를 보려면, /glist all을 사용하세요.
|
||||||
velocity.command.reload-success=Velocity 설정을 성공적으로 다시 불러왔습니다.
|
velocity.command.reload-success=Velocity 설정을 성공적으로 다시 불러왔습니다.
|
||||||
velocity.command.reload-failure=Velocity 설정을 다시 불러올 수 없습니다. 자세한 내용은 콘솔을 확인하세요.
|
velocity.command.reload-failure=Velocity 설정을 다시 불러올 수 없습니다. 자세한 내용은 콘솔을 확인하세요.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1}은(는) GNU General Public License v3 라이센스의 약관을 따릅니다.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1}은(는) GNU General Public License v3 라이센스의 약관을 따릅니다.
|
||||||
velocity.command.no-plugins=설치된 플러그인이 없습니다.
|
velocity.command.no-plugins=설치된 플러그인이 없습니다.
|
||||||
velocity.command.plugins-list=플러그인\: {0}
|
velocity.command.plugins-list=플러그인\: {0}
|
||||||
velocity.command.plugin-tooltip-website=웹사이트\: {0}
|
velocity.command.plugin-tooltip-website=웹사이트\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spillere er for øyeblikket tilkoblet d
|
|||||||
velocity.command.glist-view-all=For å se alle tilkoblede spillere, utfør /glist all.
|
velocity.command.glist-view-all=For å se alle tilkoblede spillere, utfør /glist all.
|
||||||
velocity.command.reload-success=Velocity konfigurasjonen ble lastet inn på nytt.
|
velocity.command.reload-success=Velocity konfigurasjonen ble lastet inn på nytt.
|
||||||
velocity.command.reload-failure=Kan ikke laste inn Velocity konfigurasjonen din. Sjekk konsollen for mer detaljer.
|
velocity.command.reload-failure=Kan ikke laste inn Velocity konfigurasjonen din. Sjekk konsollen for mer detaljer.
|
||||||
velocity.command.version-copyright=Opphavsrett 2018-2023 {0}. {1} er lisensiert under betingelsene av GNU General Public License v3.
|
velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} er lisensiert under betingelsene av GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Ingen plugin er installert.
|
velocity.command.no-plugins=Ingen plugin er installert.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Hjemmeside\: {0}
|
velocity.command.plugin-tooltip-website=Hjemmeside\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelers zijn momenteel verbonden met de
|
|||||||
velocity.command.glist-view-all=Om alle spelers op de servers te bekijken, gebruik /glist all.
|
velocity.command.glist-view-all=Om alle spelers op de servers te bekijken, gebruik /glist all.
|
||||||
velocity.command.reload-success=Velocity configuratie succesvol herladen.
|
velocity.command.reload-success=Velocity configuratie succesvol herladen.
|
||||||
velocity.command.reload-failure=De Velocity-configuratie kan niet opnieuw worden geladen. Kijk in de console voor meer details.
|
velocity.command.reload-failure=De Velocity-configuratie kan niet opnieuw worden geladen. Kijk in de console voor meer details.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is gelicentieerd onder de voorwaarden van de GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is gelicentieerd onder de voorwaarden van de GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Er zijn momenteel geen plugins geïnstalleerd.
|
velocity.command.no-plugins=Er zijn momenteel geen plugins geïnstalleerd.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Website\: {0}
|
velocity.command.plugin-tooltip-website=Website\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelare er for augneblinken tilkopla de
|
|||||||
velocity.command.glist-view-all=For å sjå alle tilkopla spelarar, gjer /glist all.
|
velocity.command.glist-view-all=For å sjå alle tilkopla spelarar, gjer /glist all.
|
||||||
velocity.command.reload-success=Velocity konfigurasjonen blei lasta inn på nytt.
|
velocity.command.reload-success=Velocity konfigurasjonen blei lasta inn på nytt.
|
||||||
velocity.command.reload-failure=Kan ikkje lasta inn Velocity konfigurasjonen din. Sjekk konsollen for meir detaljar.
|
velocity.command.reload-failure=Kan ikkje lasta inn Velocity konfigurasjonen din. Sjekk konsollen for meir detaljar.
|
||||||
velocity.command.version-copyright=Opphavsrett 2018-2023 {0}. {1} er lisensiert under vilkåra av GNU General Public License v3.
|
velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} er lisensiert under vilkåra av GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Det er ingen plugins installert.
|
velocity.command.no-plugins=Det er ingen plugins installert.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Heimeside\: {0}
|
velocity.command.plugin-tooltip-website=Heimeside\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=Z tym proxy jest obecnie połączonych {0}
|
|||||||
velocity.command.glist-view-all=Aby zobaczyć wszystkich graczy na wszystkich serwerach, użyj /glist all.
|
velocity.command.glist-view-all=Aby zobaczyć wszystkich graczy na wszystkich serwerach, użyj /glist all.
|
||||||
velocity.command.reload-success=Konfiguracja Velocity została pomyślnie załadowana ponownie.
|
velocity.command.reload-success=Konfiguracja Velocity została pomyślnie załadowana ponownie.
|
||||||
velocity.command.reload-failure=Nie udało się ponownie załadować twojej konfiguracji Velocity. Sprawdź konsolę po więcej szczegółów.
|
velocity.command.reload-failure=Nie udało się ponownie załadować twojej konfiguracji Velocity. Sprawdź konsolę po więcej szczegółów.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} jest objęty licencją na warunkach GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} jest objęty licencją na warunkach GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Obecnie nie ma zainstalowanych żadnych pluginów.
|
velocity.command.no-plugins=Obecnie nie ma zainstalowanych żadnych pluginów.
|
||||||
velocity.command.plugins-list=Pluginy\: {0}
|
velocity.command.plugins-list=Pluginy\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Strona internetowa\: {0}
|
velocity.command.plugin-tooltip-website=Strona internetowa\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} jogadores estão atualmente conectados
|
|||||||
velocity.command.glist-view-all=Para ver todos os jogadores em todos os servidores, use /glist all.
|
velocity.command.glist-view-all=Para ver todos os jogadores em todos os servidores, use /glist all.
|
||||||
velocity.command.reload-success=Configuração do Velocity recarregada com êxito.
|
velocity.command.reload-success=Configuração do Velocity recarregada com êxito.
|
||||||
velocity.command.reload-failure=Não foi possível recarregar a configuração do Velocity. Verifique o console para mais detalhes.
|
velocity.command.reload-failure=Não foi possível recarregar a configuração do Velocity. Verifique o console para mais detalhes.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} está licenciado sobre os termos da Licença Pública Geral GNU v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} está licenciado sobre os termos da Licença Pública Geral GNU v3.
|
||||||
velocity.command.no-plugins=Não há plugins instalados atualmente.
|
velocity.command.no-plugins=Não há plugins instalados atualmente.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Site\: {0}
|
velocity.command.plugin-tooltip-website=Site\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} players are currently connected to the
|
|||||||
velocity.command.glist-view-all=To view all players on servers, use /glist all.
|
velocity.command.glist-view-all=To view all players on servers, use /glist all.
|
||||||
velocity.command.reload-success=Velocity configuration successfully reloaded.
|
velocity.command.reload-success=Velocity configuration successfully reloaded.
|
||||||
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
|
velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||||
velocity.command.no-plugins=There are no plugins currently installed.
|
velocity.command.no-plugins=There are no plugins currently installed.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Website\: {0}
|
velocity.command.plugin-tooltip-website=Website\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} игрок(а, ов) подключен
|
|||||||
velocity.command.glist-view-all=Чтобы просмотреть всех игроков на серверах, используйте /glist all.
|
velocity.command.glist-view-all=Чтобы просмотреть всех игроков на серверах, используйте /glist all.
|
||||||
velocity.command.reload-success=Конфигурация Velocity успешно перезагружена.
|
velocity.command.reload-success=Конфигурация Velocity успешно перезагружена.
|
||||||
velocity.command.reload-failure=Не удалось перезагрузить конфигурацию Velocity. Проверьте консоль для получения более подробной информации.
|
velocity.command.reload-failure=Не удалось перезагрузить конфигурацию Velocity. Проверьте консоль для получения более подробной информации.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} лицензирована на условиях GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} лицензирована на условиях GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Ни одного плагина не установлено.
|
velocity.command.no-plugins=Ни одного плагина не установлено.
|
||||||
velocity.command.plugins-list=Плагины\: {0}
|
velocity.command.plugins-list=Плагины\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Веб-сайт\: {0}
|
velocity.command.plugin-tooltip-website=Веб-сайт\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} hráčov je pripojených na tento proxy
|
|||||||
velocity.command.glist-view-all=Pre zobrazenie všetkých hráčov na všetkých serveroch použi /glist all.
|
velocity.command.glist-view-all=Pre zobrazenie všetkých hráčov na všetkých serveroch použi /glist all.
|
||||||
velocity.command.reload-success=Konfigurácia Velocity úspešne načítaná.
|
velocity.command.reload-success=Konfigurácia Velocity úspešne načítaná.
|
||||||
velocity.command.reload-failure=Nepodarilo sa načítať konfiguráciu Velocity. Pozri sa do konzoly pre viac informácií.
|
velocity.command.reload-failure=Nepodarilo sa načítať konfiguráciu Velocity. Pozri sa do konzoly pre viac informácií.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} je licencovaný pod podmienkami GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licencovaný pod podmienkami GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Aktuálne nie sú nainštalované žiadne pluginy.
|
velocity.command.no-plugins=Aktuálne nie sú nainštalované žiadne pluginy.
|
||||||
velocity.command.plugins-list=Pluginy\: {0}
|
velocity.command.plugins-list=Pluginy\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Webstránka\: {0}
|
velocity.command.plugin-tooltip-website=Webstránka\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} lojtarët janë aktualisht të lidhur m
|
|||||||
velocity.command.glist-view-all=Për të parë të gjithë lojtarët në servera, përdorni /glist all.
|
velocity.command.glist-view-all=Për të parë të gjithë lojtarët në servera, përdorni /glist all.
|
||||||
velocity.command.reload-success=Konfigurimi i shpejtësisë u ringarkua me sukses.
|
velocity.command.reload-success=Konfigurimi i shpejtësisë u ringarkua me sukses.
|
||||||
velocity.command.reload-failure=Nuk mund të ringarkohet konfigurimi i shpejtësisë. Kontrolloni konsolën për më shumë detaje.
|
velocity.command.reload-failure=Nuk mund të ringarkohet konfigurimi i shpejtësisë. Kontrolloni konsolën për më shumë detaje.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||||
velocity.command.no-plugins=There are no plugins currently installed.
|
velocity.command.no-plugins=There are no plugins currently installed.
|
||||||
velocity.command.plugins-list=Plugins\: {0}
|
velocity.command.plugins-list=Plugins\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Website\: {0}
|
velocity.command.plugin-tooltip-website=Website\: {0}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ velocity.command.glist-player-plural={0} igrača je trenutno povezano na proxy.
|
|||||||
velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all.
|
velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all.
|
||||||
velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana.
|
velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana.
|
||||||
velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja.
|
velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} je licenciran pod uslovima licence GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licenciran pod uslovima licence GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Trenutno nema instaliranih plugin-a.
|
velocity.command.no-plugins=Trenutno nema instaliranih plugin-a.
|
||||||
velocity.command.plugins-list=Plugin-i\: {0}
|
velocity.command.plugins-list=Plugin-i\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Web stranica\: {0}
|
velocity.command.plugin-tooltip-website=Web stranica\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} igrača je trenutno povezano na proxy.
|
|||||||
velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all.
|
velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all.
|
||||||
velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana.
|
velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana.
|
||||||
velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja.
|
velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Trenutno nema instaliranih plugin-a.
|
velocity.command.no-plugins=Trenutno nema instaliranih plugin-a.
|
||||||
velocity.command.plugins-list=Plugin-i\: {0}
|
velocity.command.plugins-list=Plugin-i\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Web stranica\: {0}
|
velocity.command.plugin-tooltip-website=Web stranica\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelare är just nu ansluten till proxy
|
|||||||
velocity.command.glist-view-all=För att se alla spelare på servrar, använd /glist all.
|
velocity.command.glist-view-all=För att se alla spelare på servrar, använd /glist all.
|
||||||
velocity.command.reload-success=Velocity konfigurationen har laddats om.
|
velocity.command.reload-success=Velocity konfigurationen har laddats om.
|
||||||
velocity.command.reload-failure=Det gick inte att ladda om din Velocity konfiguration. Kontrollera konsolen för mer information.
|
velocity.command.reload-failure=Det gick inte att ladda om din Velocity konfiguration. Kontrollera konsolen för mer information.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} är licensierad enligt villkoren i GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} är licensierad enligt villkoren i GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Det finns inga tillägg installerade.
|
velocity.command.no-plugins=Det finns inga tillägg installerade.
|
||||||
velocity.command.plugins-list=Tillägg\: {0}
|
velocity.command.plugins-list=Tillägg\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Webbsida\: {0}
|
velocity.command.plugin-tooltip-website=Webbsida\: {0}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} mga manlalaro nasa proxy.
|
|||||||
velocity.command.glist-view-all=Para sa makita ang mga lahat ng manlalaro sa mga serbidor, magamit ka ng /glist all.
|
velocity.command.glist-view-all=Para sa makita ang mga lahat ng manlalaro sa mga serbidor, magamit ka ng /glist all.
|
||||||
velocity.command.reload-success=Matagumpay ang reload ng konfigurasyon ng Velocity.
|
velocity.command.reload-success=Matagumpay ang reload ng konfigurasyon ng Velocity.
|
||||||
velocity.command.reload-failure=Hindi kaya ang magreload ng konfigurasyon mo sa Velocity. Magsiyasat ang konsole para mas maraming detalye.
|
velocity.command.reload-failure=Hindi kaya ang magreload ng konfigurasyon mo sa Velocity. Magsiyasat ang konsole para mas maraming detalye.
|
||||||
velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3.
|
||||||
velocity.command.no-plugins=Walang plugin nang naka-install.
|
velocity.command.no-plugins=Walang plugin nang naka-install.
|
||||||
velocity.command.plugins-list=Mga plugin\: {0}
|
velocity.command.plugins-list=Mga plugin\: {0}
|
||||||
velocity.command.plugin-tooltip-website=Website\: {0}
|
velocity.command.plugin-tooltip-website=Website\: {0}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user