Compare commits
64
Commits
15b6ddd1bf
...
664826fec3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
664826fec3 | ||
|
|
fb0f21f425 | ||
|
|
5bb1992014 | ||
|
|
f975230f14 | ||
|
|
a6f9de9581 | ||
|
|
5000227d11 | ||
|
|
c10b492554 | ||
|
|
dff94da2b3 | ||
|
|
1b48f40534 | ||
|
|
bc55300123 | ||
|
|
a3b6177059 | ||
|
|
3ef5b2ab99 | ||
|
|
7a8bf8a5e0 | ||
|
|
05de745780 | ||
|
|
75ce1a9bf7 | ||
|
|
7a39ebb058 | ||
|
|
57e9cd7f24 | ||
|
|
b9463125d1 | ||
|
|
67e16a308e
|
||
|
|
4b8ceb5264 | ||
|
|
2d1cade7bd | ||
|
|
4067c44cd1 | ||
|
|
45bb5de601 | ||
|
|
ebb9eb046d | ||
|
|
afc84b88ac | ||
|
|
e6caa87865 | ||
|
|
cdeabe91d0 | ||
|
|
babb22bf88
|
||
|
|
468127996c
|
||
|
|
873fca763d | ||
|
|
67d63faeca | ||
|
|
871b053561 | ||
|
|
c2edc26d8e | ||
|
|
76417b13d4 | ||
|
|
47f36e3ff9 | ||
|
|
75bb48d00e | ||
|
|
11834de220 | ||
|
|
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,18 +6,28 @@ on: [push, pull_request]
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: namespace-profile-linux-default
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v6
|
uses: namespacelabs/nscloud-checkout-action@v9
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
- name: Set up cache
|
||||||
|
uses: namespacelabs/nscloud-cache-action@v1
|
||||||
|
with:
|
||||||
|
cache: gradle
|
||||||
|
- name: Setup gradle build cache
|
||||||
|
run: |
|
||||||
|
nsc cache gradle setup --init-gradle /tmp/init.gradle
|
||||||
- name: Set up Gradle
|
- name: Set up Gradle
|
||||||
uses: gradle/actions/setup-gradle@v5
|
uses: gradle/actions/setup-gradle@v6
|
||||||
|
with:
|
||||||
|
cache-disabled: true # namespace handles this
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v6
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 21
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
|
cache: "" # namespace handles this
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew --init-script=/tmp/init.gradle build
|
||||||
|
|||||||
@@ -40,3 +40,5 @@ page.
|
|||||||
Translations are handled using [Crowdin](https://papermc-io.crowdin.com/velocity).
|
Translations are handled using [Crowdin](https://papermc-io.crowdin.com/velocity).
|
||||||
If you want to translate a language not available on Crowdin,
|
If you want to translate a language not available on Crowdin,
|
||||||
you might want to ask in the [Discord](https://discord.gg/papermc) about it.
|
you might want to ask in the [Discord](https://discord.gg/papermc) about it.
|
||||||
|
|
||||||
|
[](https://namespace.so/github-actions/?utm_source=oss&utm_campaign=papermc)
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public final class PreLoginEvent implements ResultedEvent<PreLoginEvent.PreLogin
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the UUID of the connecting player.
|
* Returns the UUID of the connecting player.
|
||||||
|
*
|
||||||
* <p>This value is {@code null} on 1.19.2 and lower,
|
* <p>This value is {@code null} on 1.19.2 and lower,
|
||||||
* up to 1.20.1 it is optional and from 1.20.2 it will always be available.</p>
|
* up to 1.20.1 it is optional and from 1.20.2 it will always be available.</p>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public final class PlayerClientBrandEvent {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PlayerClientBrandEvent{"
|
return "PlayerClientBrandEvent{"
|
||||||
+ "player=" + player
|
+ "player=" + player
|
||||||
+ ", brand='" + brand + '\''
|
+ ", brand='" + brand + '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is executed when a player entered the configuration state and can be configured by Velocity.
|
* This event is executed when a player entered the configuration state and can be configured by Velocity.
|
||||||
|
*
|
||||||
* <p>Velocity will wait for this event before continuing/ending the configuration state.</p>
|
* <p>Velocity will wait for this event before continuing/ending the configuration state.</p>
|
||||||
*
|
*
|
||||||
* @param player The player who can be configured.
|
* @param player The player who can be configured.
|
||||||
|
|||||||
+1
@@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
/**
|
/**
|
||||||
* This event is executed when a player is about to enter the configuration state.
|
* This event is executed when a player is about to enter the configuration state.
|
||||||
* It is <b>not</b> called for the initial configuration of a player after login.
|
* It is <b>not</b> called for the initial configuration of a player after login.
|
||||||
|
*
|
||||||
* <p>Velocity will wait for this event before asking the client to enter configuration state.
|
* <p>Velocity will wait for this event before asking the client to enter configuration state.
|
||||||
* However due to backend server being unable to keep the connection alive during state changes,
|
* However due to backend server being unable to keep the connection alive during state changes,
|
||||||
* Velocity will only wait for a maximum of 5 seconds.</p>
|
* Velocity will only wait for a maximum of 5 seconds.</p>
|
||||||
|
|||||||
+1
@@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is executed when a player has entered the configuration state.
|
* This event is executed when a player has entered the configuration state.
|
||||||
|
*
|
||||||
* <p>From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed,
|
* <p>From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed,
|
||||||
* the {@linkplain Player#getProtocolState()} method is guaranteed
|
* the {@linkplain Player#getProtocolState()} method is guaranteed
|
||||||
* to return {@link ProtocolState#CONFIGURATION}.</p>
|
* to return {@link ProtocolState#CONFIGURATION}.</p>
|
||||||
|
|||||||
+1
@@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is executed when a player is about to finish the configuration state.
|
* This event is executed when a player is about to finish the configuration state.
|
||||||
|
*
|
||||||
* <p>Velocity will wait for this event before asking the client to finish the configuration state.
|
* <p>Velocity will wait for this event before asking the client to finish the configuration state.
|
||||||
* However due to backend server being unable to keep the connection alive during state changes,
|
* However due to backend server being unable to keep the connection alive during state changes,
|
||||||
* Velocity will only wait for a maximum of 5 seconds. If you need to hold a player in configuration
|
* Velocity will only wait for a maximum of 5 seconds. If you need to hold a player in configuration
|
||||||
|
|||||||
+1
@@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is executed when a player has finished the configuration state.
|
* This event is executed when a player has finished the configuration state.
|
||||||
|
*
|
||||||
* <p>From this moment on, the {@link Player#getProtocolState()} method
|
* <p>From this moment on, the {@link Player#getProtocolState()} method
|
||||||
* will return {@link ProtocolState#PLAY}.</p>
|
* will return {@link ProtocolState#PLAY}.</p>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package com.velocitypowered.api.network;
|
|||||||
public enum ProtocolState {
|
public enum ProtocolState {
|
||||||
/**
|
/**
|
||||||
* Initial connection State.
|
* Initial connection State.
|
||||||
|
*
|
||||||
* <p>This status can be caused by a {@link HandshakeIntent#STATUS},
|
* <p>This status can be caused by a {@link HandshakeIntent#STATUS},
|
||||||
* {@link HandshakeIntent#LOGIN} or {@link HandshakeIntent#TRANSFER} intent.</p>
|
* {@link HandshakeIntent#LOGIN} or {@link HandshakeIntent#TRANSFER} intent.</p>
|
||||||
* If the intent is LOGIN or TRANSFER, the next state will be {@link #LOGIN},
|
* If the intent is LOGIN or TRANSFER, the next state will be {@link #LOGIN},
|
||||||
@@ -24,6 +25,7 @@ public enum ProtocolState {
|
|||||||
HANDSHAKE,
|
HANDSHAKE,
|
||||||
/**
|
/**
|
||||||
* Ping State of a connection.
|
* Ping State of a connection.
|
||||||
|
*
|
||||||
* <p>Connections with the {@link HandshakeIntent#STATUS} intent will pass through this state
|
* <p>Connections with the {@link HandshakeIntent#STATUS} intent will pass through this state
|
||||||
* and be disconnected after it requests the ping from the server
|
* and be disconnected after it requests the ping from the server
|
||||||
* and the server responds with the respective ping.</p>
|
* and the server responds with the respective ping.</p>
|
||||||
@@ -31,11 +33,13 @@ public enum ProtocolState {
|
|||||||
STATUS,
|
STATUS,
|
||||||
/**
|
/**
|
||||||
* Authentication State of a connection.
|
* Authentication State of a connection.
|
||||||
|
*
|
||||||
* <p>At this moment the player is authenticating with the authentication servers.</p>
|
* <p>At this moment the player is authenticating with the authentication servers.</p>
|
||||||
*/
|
*/
|
||||||
LOGIN,
|
LOGIN,
|
||||||
/**
|
/**
|
||||||
* Configuration State of a connection.
|
* Configuration State of a connection.
|
||||||
|
*
|
||||||
* <p>At this point the player allows the server to send information
|
* <p>At this point the player allows the server to send information
|
||||||
* such as resource packs and plugin messages, at the same time the player
|
* such as resource packs and plugin messages, at the same time the player
|
||||||
* will send his client brand and the respective plugin messages
|
* will send his client brand and the respective plugin messages
|
||||||
@@ -46,6 +50,7 @@ public enum ProtocolState {
|
|||||||
CONFIGURATION,
|
CONFIGURATION,
|
||||||
/**
|
/**
|
||||||
* Game State of a connection.
|
* Game State of a connection.
|
||||||
|
*
|
||||||
* <p>In this state is where the whole game runs, the server is able to change
|
* <p>In this state is where the whole game runs, the server is able to change
|
||||||
* the player's state to {@link #CONFIGURATION} as needed in versions 1.20.2 and higher.</p>
|
* the player's state to {@link #CONFIGURATION} as needed in versions 1.20.2 and higher.</p>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
|||||||
MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"),
|
MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"),
|
||||||
MINECRAFT_1_21_11(774, "1.21.11"),
|
MINECRAFT_1_21_11(774, "1.21.11"),
|
||||||
MINECRAFT_26_1(775, "26.1", "26.1.1", "26.1.2"),
|
MINECRAFT_26_1(775, "26.1", "26.1.1", "26.1.2"),
|
||||||
MINECRAFT_26_2(776, "26.2");
|
MINECRAFT_26_2(776, "26.2"),
|
||||||
|
MINECRAFT_26_3(777, "26.3");
|
||||||
|
|
||||||
private static final int SNAPSHOT_BIT = 30;
|
private static final int SNAPSHOT_BIT = 30;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
* Represents three different states of a setting.
|
* Represents three different states of a setting.
|
||||||
*
|
*
|
||||||
* <p>Possible values:</p>
|
* <p>Possible values:</p>
|
||||||
* <p></p>
|
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link #TRUE} - a positive setting</li>
|
* <li>{@link #TRUE} - a positive setting</li>
|
||||||
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
* <li>{@link #FALSE} - a negative (negated) setting</li>
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ public interface Player extends
|
|||||||
* Gets the {@link ResourcePackInfo} of the currently applied
|
* Gets the {@link ResourcePackInfo} of the currently applied
|
||||||
* resource-pack or null if none.
|
* resource-pack or null if none.
|
||||||
*
|
*
|
||||||
* <p> Note that since 1.20.3 it is no longer recommended to use
|
* <p>Note that since 1.20.3 it is no longer recommended to use
|
||||||
* this method as it will only return the last applied
|
* this method as it will only return the last applied
|
||||||
* resource pack. To get all applied resource packs, use
|
* resource pack. To get all applied resource packs, use
|
||||||
* {@link #getAppliedResourcePacks()} instead. </p>
|
* {@link #getAppliedResourcePacks()} instead. </p>
|
||||||
@@ -260,7 +260,7 @@ public interface Player extends
|
|||||||
* the user is currently downloading or is currently
|
* the user is currently downloading or is currently
|
||||||
* prompted to install or null if none.
|
* prompted to install or null if none.
|
||||||
*
|
*
|
||||||
* <p> Note that since 1.20.3 it is no longer recommended to use
|
* <p>Note that since 1.20.3 it is no longer recommended to use
|
||||||
* this method as it will only return the last pending
|
* this method as it will only return the last pending
|
||||||
* resource pack. To get all pending resource packs, use
|
* resource pack. To get all pending resource packs, use
|
||||||
* {@link #getPendingResourcePacks()} instead. </p>
|
* {@link #getPendingResourcePacks()} instead. </p>
|
||||||
@@ -315,6 +315,7 @@ public interface Player extends
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
* <p><strong>Note that this method does not send a plugin message to the server the player
|
* <p><strong>Note that this method does not send a plugin message to the server the player
|
||||||
* is connected to.</strong> You should only use this method if you are trying to communicate
|
* is connected to.</strong> You should only use this method if you are trying to communicate
|
||||||
* with a mod that is installed on the player's client.</p>
|
* with a mod that is installed on the player's client.</p>
|
||||||
@@ -400,7 +401,7 @@ public interface Player extends
|
|||||||
* and will not perform any actions.</b>
|
* and will not perform any actions.</b>
|
||||||
* @see #playSound(Sound, Sound.Emitter)
|
* @see #playSound(Sound, Sound.Emitter)
|
||||||
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
* Unsupported Adventure Operations</a>
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void playSound(@NotNull Sound sound) {
|
default void playSound(@NotNull Sound sound) {
|
||||||
@@ -413,7 +414,7 @@ public interface Player extends
|
|||||||
* and will not perform any actions.</b>
|
* and will not perform any actions.</b>
|
||||||
* @see #playSound(Sound, Sound.Emitter)
|
* @see #playSound(Sound, Sound.Emitter)
|
||||||
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
* Unsupported Adventure Operations</a>
|
* 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) {
|
||||||
@@ -456,7 +457,7 @@ public interface Player extends
|
|||||||
* 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">
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
* Unsupported Adventure Operations</a>
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void openBook(@NotNull Book book) {
|
default void openBook(@NotNull Book book) {
|
||||||
@@ -469,7 +470,7 @@ public interface Player extends
|
|||||||
* 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">
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
* Unsupported Adventure Operations</a>
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void showDialog(@NotNull DialogLike dialog) {
|
default void showDialog(@NotNull DialogLike dialog) {
|
||||||
@@ -482,7 +483,7 @@ public interface Player extends
|
|||||||
* 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">
|
* @see <a href="https://docs.papermc.io/velocity/dev/pitfalls/#audience-operations-are-not-fully-supported">
|
||||||
* Unsupported Adventure Operations</a>
|
* Unsupported Adventure Operations</a>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void closeDialog() {
|
default void closeDialog() {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public interface KeySigned {
|
|||||||
* Validates the signature, expiry temporal and key against the
|
* Validates the signature, expiry temporal and key against the
|
||||||
* signer public key. Note: This will **not** check for
|
* signer public key. Note: This will **not** check for
|
||||||
* expiry. You can check for expiry with {@link KeySigned#hasExpired()}.
|
* expiry. You can check for expiry with {@link KeySigned#hasExpired()}.
|
||||||
|
*
|
||||||
* <p>DOES NOT WORK YET FOR MESSAGES AND COMMANDS!</p>
|
* <p>DOES NOT WORK YET FOR MESSAGES AND COMMANDS!</p>
|
||||||
* Addendum: Does not work for 1.19.1 until the user has authenticated.
|
* Addendum: Does not work for 1.19.1 until the user has authenticated.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -237,8 +237,11 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link IdentifiedKey} of the {@link TabListEntry}.
|
* Sets the {@link IdentifiedKey} of the {@link TabListEntry}.
|
||||||
|
*
|
||||||
* <p>This only works for players currently <b>not</b> connected to this proxy.</p>
|
* <p>This only works for players currently <b>not</b> connected to this proxy.</p>
|
||||||
|
*
|
||||||
* <p>For any player currently connected to this proxy this will be filled automatically.</p>
|
* <p>For any player currently connected to this proxy this will be filled automatically.</p>
|
||||||
|
*
|
||||||
* <p>Will ignore mismatching key revisions data.</p>
|
* <p>Will ignore mismatching key revisions data.</p>
|
||||||
*
|
*
|
||||||
* @param chatSession session to set
|
* @param chatSession session to set
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public final class ServerPing {
|
|||||||
private final @Nullable 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) {
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ subprojects {
|
|||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion.set(JavaLanguageVersion.of(25))
|
languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
group=com.velocitypowered
|
group=com.velocitypowered
|
||||||
version=4.1.2-SNAPSHOT
|
version=4.2.1-SNAPSHOT
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT"
|
|||||||
bstats = "org.bstats:bstats-base:3.2.1"
|
bstats = "org.bstats:bstats-base:3.2.1"
|
||||||
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.4"
|
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.4"
|
||||||
checker-qual = "org.checkerframework:checker-qual:4.2.3"
|
checker-qual = "org.checkerframework:checker-qual:4.2.3"
|
||||||
checkstyle = "com.puppycrawl.tools:checkstyle:10.9.3"
|
checkstyle = "com.puppycrawl.tools:checkstyle:14.1.0"
|
||||||
completablefutures = "com.spotify:completable-futures:0.3.6"
|
completablefutures = "com.spotify:completable-futures:0.3.6"
|
||||||
configurate3-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate3" }
|
configurate3-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate3" }
|
||||||
configurate3-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate3" }
|
configurate3-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate3" }
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ public class MoreByteBufUtils {
|
|||||||
BufferPreference preferred = nativeStuff.preferredBufferType();
|
BufferPreference preferred = nativeStuff.preferredBufferType();
|
||||||
return switch (preferred) {
|
return switch (preferred) {
|
||||||
case DIRECT_PREFERRED, HEAP_PREFERRED ->
|
case DIRECT_PREFERRED, HEAP_PREFERRED ->
|
||||||
// The native prefers this type, but doesn't strictly require we provide it.
|
// The native prefers this type, but doesn't strictly require we provide it.
|
||||||
true;
|
true;
|
||||||
case DIRECT_REQUIRED -> buf.hasMemoryAddress();
|
case DIRECT_REQUIRED -> buf.hasMemoryAddress();
|
||||||
case HEAP_REQUIRED -> buf.hasArray();
|
case HEAP_REQUIRED -> buf.hasArray();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -488,23 +488,46 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-register servers. If a server is being replaced, make sure to note what players need to
|
// Re-register servers. If a server is being replaced or removed, make sure to note what
|
||||||
// move back to a fallback server.
|
// players need to move back to a fallback server.
|
||||||
Collection<ConnectedPlayer> evacuate = new ArrayList<>();
|
Collection<ConnectedPlayer> evacuate = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> entry : configuration.getServers().entrySet()) {
|
||||||
|
if (newConfiguration.getServers().keySet().stream()
|
||||||
|
.anyMatch(name -> name.equalsIgnoreCase(entry.getKey()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredServer rs = servers.getServer(entry.getKey()).orElse(null);
|
||||||
|
if (rs == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player player : rs.getPlayersConnected()) {
|
||||||
|
if (!(player instanceof ConnectedPlayer)) {
|
||||||
|
throw new IllegalStateException("Expected ConnectedPlayer for player " + player
|
||||||
|
+ " on server " + rs.getServerInfo().getName() + ", got "
|
||||||
|
+ player.getClass().getName());
|
||||||
|
}
|
||||||
|
evacuate.add((ConnectedPlayer) player);
|
||||||
|
}
|
||||||
|
servers.unregister(rs.getServerInfo());
|
||||||
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, String> entry : newConfiguration.getServers().entrySet()) {
|
for (Map.Entry<String, String> entry : newConfiguration.getServers().entrySet()) {
|
||||||
ServerInfo newInfo = new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()));
|
ServerInfo newInfo = new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue()));
|
||||||
Optional<RegisteredServer> rs = servers.getServer(entry.getKey());
|
RegisteredServer rs = servers.getServer(entry.getKey()).orElse(null);
|
||||||
if (rs.isEmpty()) {
|
if (rs == null) {
|
||||||
servers.register(newInfo);
|
servers.register(newInfo);
|
||||||
} else if (!rs.get().getServerInfo().equals(newInfo)) {
|
} else if (!rs.getServerInfo().equals(newInfo)) {
|
||||||
for (Player player : rs.get().getPlayersConnected()) {
|
for (Player player : rs.getPlayersConnected()) {
|
||||||
if (!(player instanceof ConnectedPlayer)) {
|
if (!(player instanceof ConnectedPlayer)) {
|
||||||
throw new IllegalStateException("ConnectedPlayer not found for player " + player
|
throw new IllegalStateException("Expected ConnectedPlayer for player " + player
|
||||||
+ " in server " + rs.get().getServerInfo().getName());
|
+ " on server " + rs.getServerInfo().getName() + ", got "
|
||||||
|
+ player.getClass().getName());
|
||||||
}
|
}
|
||||||
evacuate.add((ConnectedPlayer) player);
|
evacuate.add((ConnectedPlayer) player);
|
||||||
}
|
}
|
||||||
servers.unregister(rs.get().getServerInfo());
|
servers.unregister(rs.getServerInfo());
|
||||||
servers.register(newInfo);
|
servers.register(newInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -653,7 +676,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down."
|
* Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down".
|
||||||
*
|
*
|
||||||
* @param explicitExit whether the user explicitly shut down the proxy
|
* @param explicitExit whether the user explicitly shut down the proxy
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,6 +59,6 @@ public record PingPassthroughMode(boolean version, boolean players,
|
|||||||
|
|
||||||
public boolean enabled() {
|
public boolean enabled() {
|
||||||
return this.version || this.players || this.description || this.favicon
|
return this.version || this.players || this.description || this.favicon
|
||||||
|| this.modinfo;
|
|| this.modinfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ 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.ClientboundPostEffectsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
|
||||||
@@ -404,4 +405,8 @@ public interface MinecraftSessionHandler {
|
|||||||
default boolean handle(ClientboundStopSoundPacket packet) {
|
default boolean handle(ClientboundStopSoundPacket packet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean handle(ClientboundPostEffectsPacket packet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-6
@@ -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;
|
||||||
@@ -55,6 +57,7 @@ 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.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.JoinGamePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket;
|
import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket;
|
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
|
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
|
||||||
@@ -164,6 +167,13 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return false; // forwards on
|
return false; // forwards on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(JoinGamePacket packet) {
|
||||||
|
// We receive this if the connection is reconfigured
|
||||||
|
packet.setOnlineMode(serverConn.getPlayer().isOnlineMode());
|
||||||
|
return false; // forward
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(ClientSettingsPacket packet) {
|
public boolean handle(ClientSettingsPacket packet) {
|
||||||
serverConn.ensureConnected().write(packet);
|
serverConn.ensureConnected().write(packet);
|
||||||
@@ -312,13 +322,9 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
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(
|
||||||
|
|||||||
+2
@@ -31,6 +31,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;
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modern (Minecraft 1.20.3+) ResourcePackHandler
|
* Modern (Minecraft 1.20.3+) ResourcePackHandler.
|
||||||
*/
|
*/
|
||||||
public final class ModernResourcePackHandler extends ResourcePackHandler {
|
public final class ModernResourcePackHandler extends ResourcePackHandler {
|
||||||
private final ListMultimap<UUID, ResourcePackInfo> outstandingResourcePacks =
|
private final ListMultimap<UUID, ResourcePackInfo> outstandingResourcePacks =
|
||||||
|
|||||||
+1
@@ -118,6 +118,7 @@ public abstract sealed class ResourcePackHandler
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a client response to a sent resource-pack.
|
* Processes a client response to a sent resource-pack.
|
||||||
|
*
|
||||||
* <p>Cases in which no action will be taken:</p>
|
* <p>Cases in which no action will be taken:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -545,6 +545,36 @@ public class VelocityEventManager implements EventManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <E> void fire(final @Nullable CompletableFuture<E> future, final E event,
|
||||||
|
final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) {
|
||||||
|
for (int i = offset; i < registrations.length; i++) {
|
||||||
|
final HandlerRegistration registration = registrations[i];
|
||||||
|
try {
|
||||||
|
final EventTask eventTask = registration.handler.executeAsync(event);
|
||||||
|
if (eventTask == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ContinuationTask<E> continuationTask = new ContinuationTask<>(eventTask,
|
||||||
|
registrations, future, event, i, currentlyAsync);
|
||||||
|
if (currentlyAsync || !eventTask.requiresAsync()) {
|
||||||
|
if (continuationTask.execute()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
registration.plugin.getExecutorService().execute(continuationTask);
|
||||||
|
}
|
||||||
|
// fire will continue in another thread once the async task is
|
||||||
|
// executed and the continuation is resumed
|
||||||
|
return;
|
||||||
|
} catch (final Throwable t) {
|
||||||
|
logHandlerException(registration, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (future != null) {
|
||||||
|
future.complete(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final int TASK_STATE_DEFAULT = 0;
|
private static final int TASK_STATE_DEFAULT = 0;
|
||||||
private static final int TASK_STATE_EXECUTING = 1;
|
private static final int TASK_STATE_EXECUTING = 1;
|
||||||
private static final int TASK_STATE_CONTINUE_IMMEDIATELY = 2;
|
private static final int TASK_STATE_CONTINUE_IMMEDIATELY = 2;
|
||||||
@@ -669,36 +699,6 @@ public class VelocityEventManager implements EventManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <E> void fire(final @Nullable CompletableFuture<E> future, final E event,
|
|
||||||
final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) {
|
|
||||||
for (int i = offset; i < registrations.length; i++) {
|
|
||||||
final HandlerRegistration registration = registrations[i];
|
|
||||||
try {
|
|
||||||
final EventTask eventTask = registration.handler.executeAsync(event);
|
|
||||||
if (eventTask == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final ContinuationTask<E> continuationTask = new ContinuationTask<>(eventTask,
|
|
||||||
registrations, future, event, i, currentlyAsync);
|
|
||||||
if (currentlyAsync || !eventTask.requiresAsync()) {
|
|
||||||
if (continuationTask.execute()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
registration.plugin.getExecutorService().execute(continuationTask);
|
|
||||||
}
|
|
||||||
// fire will continue in another thread once the async task is
|
|
||||||
// executed and the continuation is resumed
|
|
||||||
return;
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
logHandlerException(registration, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (future != null) {
|
|
||||||
future.complete(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logHandlerException(
|
private static void logHandlerException(
|
||||||
final HandlerRegistration registration, final Throwable t) {
|
final HandlerRegistration registration, final Throwable t) {
|
||||||
final PluginDescription pluginDescription = registration.plugin.getDescription();
|
final PluginDescription pluginDescription = registration.plugin.getDescription();
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ public enum ProtocolUtils {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||||
|
private static final int DEFAULT_MAX_KEY_ARRAY_SIZE = 1024;
|
||||||
private static final int MAXIMUM_VARINT_SIZE = 5;
|
private static final int MAXIMUM_VARINT_SIZE = 5;
|
||||||
private static final BinaryTagType<? extends BinaryTag>[] BINARY_TAG_TYPES = new BinaryTagType[] {
|
private static final BinaryTagType<? extends BinaryTag>[] BINARY_TAG_TYPES = new BinaryTagType[] {
|
||||||
BinaryTagTypes.END, BinaryTagTypes.BYTE, BinaryTagTypes.SHORT, BinaryTagTypes.INT,
|
BinaryTagTypes.END, BinaryTagTypes.BYTE, BinaryTagTypes.SHORT, BinaryTagTypes.INT,
|
||||||
@@ -349,15 +350,20 @@ public enum ProtocolUtils {
|
|||||||
writeString(buf, key.asMinimalString());
|
writeString(buf, key.asMinimalString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Key[] readKeyArray(ByteBuf buf) {
|
||||||
|
return readKeyArray(buf, DEFAULT_MAX_KEY_ARRAY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a standard Mojang Text namespaced:key array from the buffer.
|
* Reads a standard Mojang Text namespaced:key array from the buffer.
|
||||||
*
|
*
|
||||||
* @param buf the buffer to read from
|
* @param buf the buffer to read from
|
||||||
* @return the decoded key array
|
* @return the decoded key array
|
||||||
*/
|
*/
|
||||||
public static Key[] readKeyArray(ByteBuf buf) {
|
public static Key[] readKeyArray(ByteBuf buf, int cap) {
|
||||||
int length = readVarInt(buf);
|
int length = readVarInt(buf);
|
||||||
checkFrame(length >= 0, "Got a negative-length array (%s)", length);
|
checkFrame(length >= 0, "Got a negative-length array (%s)", length);
|
||||||
|
checkFrame(length <= cap, "Bad key array size (got %s, maximum is %s)", length, cap);
|
||||||
checkFrame(buf.isReadable(length),
|
checkFrame(buf.isReadable(length),
|
||||||
"Trying to read an array that is too long (wanted %s, only have %s)", length,
|
"Trying to read an array that is too long (wanted %s, only have %s)", length,
|
||||||
buf.readableBytes());
|
buf.readableBytes());
|
||||||
@@ -644,7 +650,7 @@ public enum ProtocolUtils {
|
|||||||
private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A;
|
private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads an byte array for legacy version 1.7 from the specified {@code buf}
|
* Reads an byte array for legacy version 1.7 from the specified {@code buf}.
|
||||||
*
|
*
|
||||||
* @param buf the buffer to read from
|
* @param buf the buffer to read from
|
||||||
* @return the read byte array
|
* @return the read byte array
|
||||||
@@ -685,7 +691,7 @@ public enum ProtocolUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes an byte array for legacy version 1.7 to the specified {@code buf}
|
* Writes an byte array for legacy version 1.7 to the specified {@code buf}.
|
||||||
*
|
*
|
||||||
* @param b array
|
* @param b array
|
||||||
* @param buf buf
|
* @param buf buf
|
||||||
@@ -709,7 +715,7 @@ public enum ProtocolUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf}
|
* Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf}.
|
||||||
*
|
*
|
||||||
* @param b array
|
* @param b array
|
||||||
* @param buf buf
|
* @param buf buf
|
||||||
|
|||||||
@@ -18,37 +18,7 @@
|
|||||||
package com.velocitypowered.proxy.protocol;
|
package com.velocitypowered.proxy.protocol;
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.getLast;
|
import static com.google.common.collect.Iterables.getLast;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12;
|
import static com.velocitypowered.api.network.ProtocolVersion.*;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12_1;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_2;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_4;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_17;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18_2;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_1;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_3;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_2;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_3;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_5;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21;
|
|
||||||
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_5;
|
|
||||||
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_8;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9_4;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_26_1;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINIMUM_VERSION;
|
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.SUPPORTED_VERSIONS;
|
|
||||||
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.CLIENTBOUND;
|
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.CLIENTBOUND;
|
||||||
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND;
|
import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND;
|
||||||
@@ -234,31 +204,44 @@ public enum StateRegistry {
|
|||||||
map(0x06, MINECRAFT_1_20_2, false),
|
map(0x06, MINECRAFT_1_20_2, false),
|
||||||
map(0x07, MINECRAFT_1_20_3, false),
|
map(0x07, MINECRAFT_1_20_3, false),
|
||||||
map(0x09, MINECRAFT_1_20_5, false));
|
map(0x09, MINECRAFT_1_20_5, false));
|
||||||
|
clientbound.register(
|
||||||
|
ClientboundPostEffectsPacket.class, ClientboundPostEffectsPacket::new,
|
||||||
|
map(0x0A, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
||||||
map(0x0A, MINECRAFT_1_20_5, false));
|
map(0x0A, MINECRAFT_1_20_5, false),
|
||||||
|
map(0x0B, MINECRAFT_26_3, false));
|
||||||
clientbound.register(TransferPacket.class, TransferPacket::new,
|
clientbound.register(TransferPacket.class, TransferPacket::new,
|
||||||
map(0x0B, MINECRAFT_1_20_5, false));
|
map(0x0B, MINECRAFT_1_20_5, false),
|
||||||
|
map(0x0C, MINECRAFT_26_3, false));
|
||||||
clientbound.register(ActiveFeaturesPacket.class, ActiveFeaturesPacket::new,
|
clientbound.register(ActiveFeaturesPacket.class, ActiveFeaturesPacket::new,
|
||||||
map(0x07, MINECRAFT_1_20_2, false),
|
map(0x07, MINECRAFT_1_20_2, false),
|
||||||
map(0x08, MINECRAFT_1_20_3, false),
|
map(0x08, MINECRAFT_1_20_3, false),
|
||||||
map(0x0C, MINECRAFT_1_20_5, false));
|
map(0x0C, MINECRAFT_1_20_5, false),
|
||||||
|
map(0x0D, MINECRAFT_26_3, false));
|
||||||
clientbound.register(TagsUpdatePacket.class, TagsUpdatePacket::new,
|
clientbound.register(TagsUpdatePacket.class, TagsUpdatePacket::new,
|
||||||
map(0x08, MINECRAFT_1_20_2, false),
|
map(0x08, MINECRAFT_1_20_2, false),
|
||||||
map(0x09, MINECRAFT_1_20_3, false),
|
map(0x09, MINECRAFT_1_20_3, false),
|
||||||
map(0x0D, MINECRAFT_1_20_5, false));
|
map(0x0D, MINECRAFT_1_20_5, false),
|
||||||
|
map(0x0E, MINECRAFT_26_3, false));
|
||||||
clientbound.register(KnownPacksPacket.class, KnownPacksPacket::new,
|
clientbound.register(KnownPacksPacket.class, KnownPacksPacket::new,
|
||||||
map(0x0E, MINECRAFT_1_20_5, false));
|
map(0x0E, MINECRAFT_1_20_5, false),
|
||||||
|
map(0x0F, MINECRAFT_26_3, false));
|
||||||
clientbound.register(ClientboundCustomReportDetailsPacket.class, ClientboundCustomReportDetailsPacket::new,
|
clientbound.register(ClientboundCustomReportDetailsPacket.class, ClientboundCustomReportDetailsPacket::new,
|
||||||
map(0x0F, MINECRAFT_1_21, false));
|
map(0x0F, MINECRAFT_1_21, false),
|
||||||
|
map(0x10, MINECRAFT_26_3, 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),
|
||||||
|
map(0x11, MINECRAFT_26_3, false));
|
||||||
clientbound.register(DialogClearPacket.class, () -> DialogClearPacket.INSTANCE,
|
clientbound.register(DialogClearPacket.class, () -> DialogClearPacket.INSTANCE,
|
||||||
map(0x11, MINECRAFT_1_21_6, false));
|
map(0x11, MINECRAFT_1_21_6, false),
|
||||||
|
map(0x12, MINECRAFT_26_3, false));
|
||||||
clientbound.register(DialogShowPacket.class, () -> new DialogShowPacket(this),
|
clientbound.register(DialogShowPacket.class, () -> new DialogShowPacket(this),
|
||||||
map(0x12, MINECRAFT_1_21_6, false));
|
map(0x12, MINECRAFT_1_21_6, false),
|
||||||
|
map(0x13, MINECRAFT_26_3, false));
|
||||||
clientbound.register(CodeOfConductPacket.class, CodeOfConductPacket::new,
|
clientbound.register(CodeOfConductPacket.class, CodeOfConductPacket::new,
|
||||||
map(0x13, MINECRAFT_1_21_9, false));
|
map(0x13, MINECRAFT_1_21_9, false),
|
||||||
|
map(0x14, MINECRAFT_26_3, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PLAY {
|
PLAY {
|
||||||
@@ -410,7 +393,8 @@ public enum StateRegistry {
|
|||||||
map(0x2D, MINECRAFT_1_21_2, false),
|
map(0x2D, MINECRAFT_1_21_2, false),
|
||||||
map(0x2F, MINECRAFT_1_21_4, false),
|
map(0x2F, MINECRAFT_1_21_4, false),
|
||||||
map(0x30, MINECRAFT_1_21_6, false),
|
map(0x30, MINECRAFT_1_21_6, false),
|
||||||
map(0x31, MINECRAFT_26_1, false));
|
map(0x31, MINECRAFT_26_1, false),
|
||||||
|
map(0x32, MINECRAFT_26_3, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
||||||
map(0x0B, MINECRAFT_1_20_2, false),
|
map(0x0B, MINECRAFT_1_20_2, false),
|
||||||
@@ -469,6 +453,9 @@ 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(
|
||||||
|
ClientboundPostEffectsPacket.class, ClientboundPostEffectsPacket::new,
|
||||||
|
map(0x53, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
|
ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
|
||||||
map(0x5D, MINECRAFT_1_19_3, true),
|
map(0x5D, MINECRAFT_1_19_3, true),
|
||||||
@@ -479,7 +466,8 @@ public enum StateRegistry {
|
|||||||
map(0x6E, MINECRAFT_1_21_2, true),
|
map(0x6E, MINECRAFT_1_21_2, true),
|
||||||
map(0x6D, MINECRAFT_1_21_5, true),
|
map(0x6D, MINECRAFT_1_21_5, true),
|
||||||
map(0x72, MINECRAFT_1_21_9, true),
|
map(0x72, MINECRAFT_1_21_9, true),
|
||||||
map(0x74, MINECRAFT_26_1, true));
|
map(0x74, MINECRAFT_26_1, true),
|
||||||
|
map(0x76, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
|
ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
|
||||||
map(0x5F, MINECRAFT_1_19_3, true),
|
map(0x5F, MINECRAFT_1_19_3, true),
|
||||||
@@ -490,7 +478,8 @@ public enum StateRegistry {
|
|||||||
map(0x71, MINECRAFT_1_21_2, true),
|
map(0x71, MINECRAFT_1_21_2, true),
|
||||||
map(0x70, MINECRAFT_1_21_5, true),
|
map(0x70, MINECRAFT_1_21_5, true),
|
||||||
map(0x75, MINECRAFT_1_21_9, true),
|
map(0x75, MINECRAFT_1_21_9, true),
|
||||||
map(0x77, MINECRAFT_26_1, true));
|
map(0x77, MINECRAFT_26_1, true),
|
||||||
|
map(0x79, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PluginMessagePacket.class,
|
PluginMessagePacket.class,
|
||||||
PluginMessagePacket::new,
|
PluginMessagePacket::new,
|
||||||
@@ -548,7 +537,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x2B, MINECRAFT_1_21_9, false),
|
||||||
map(0x2C, MINECRAFT_26_1, false));
|
map(0x2C, MINECRAFT_26_1, false),
|
||||||
|
map(0x2D, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
JoinGamePacket.class,
|
JoinGamePacket.class,
|
||||||
JoinGamePacket::new,
|
JoinGamePacket::new,
|
||||||
@@ -569,7 +559,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x30, MINECRAFT_1_21_9, false),
|
||||||
map(0x31, MINECRAFT_26_1, false));
|
map(0x31, MINECRAFT_26_1, false),
|
||||||
|
map(0x32, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RespawnPacket.class,
|
RespawnPacket.class,
|
||||||
RespawnPacket::new,
|
RespawnPacket::new,
|
||||||
@@ -593,7 +584,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x50, MINECRAFT_1_21_9, true),
|
||||||
map(0x52, MINECRAFT_26_1, true));
|
map(0x52, MINECRAFT_26_1, true),
|
||||||
|
map(0x54, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RemoveResourcePackPacket.class,
|
RemoveResourcePackPacket.class,
|
||||||
RemoveResourcePackPacket::new,
|
RemoveResourcePackPacket::new,
|
||||||
@@ -602,7 +594,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x4E, MINECRAFT_1_21_9, false),
|
||||||
map(0x50, MINECRAFT_26_1, false));
|
map(0x50, MINECRAFT_26_1, false),
|
||||||
|
map(0x51, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ResourcePackRequestPacket.class,
|
ResourcePackRequestPacket.class,
|
||||||
ResourcePackRequestPacket::new,
|
ResourcePackRequestPacket::new,
|
||||||
@@ -626,7 +619,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x4F, MINECRAFT_1_21_9, false),
|
||||||
map(0x51, MINECRAFT_26_1, false));
|
map(0x51, MINECRAFT_26_1, false),
|
||||||
|
map(0x52, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
HeaderAndFooterPacket.class,
|
HeaderAndFooterPacket.class,
|
||||||
HeaderAndFooterPacket::new,
|
HeaderAndFooterPacket::new,
|
||||||
@@ -651,7 +645,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x78, MINECRAFT_1_21_9, true),
|
||||||
map(0x7A, MINECRAFT_26_1, true));
|
map(0x7A, MINECRAFT_26_1, true),
|
||||||
|
map(0x7D, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LegacyTitlePacket.class,
|
LegacyTitlePacket.class,
|
||||||
LegacyTitlePacket::new,
|
LegacyTitlePacket::new,
|
||||||
@@ -675,7 +670,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x6E, MINECRAFT_1_21_9, true),
|
||||||
map(0x70, MINECRAFT_26_1, true));
|
map(0x70, MINECRAFT_26_1, true),
|
||||||
|
map(0x72, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTextPacket.class,
|
TitleTextPacket.class,
|
||||||
TitleTextPacket::new,
|
TitleTextPacket::new,
|
||||||
@@ -690,7 +686,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x70, MINECRAFT_1_21_9, true),
|
||||||
map(0x72, MINECRAFT_26_1, true));
|
map(0x72, MINECRAFT_26_1, true),
|
||||||
|
map(0x74, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleActionbarPacket.class,
|
TitleActionbarPacket.class,
|
||||||
TitleActionbarPacket::new,
|
TitleActionbarPacket::new,
|
||||||
@@ -705,7 +702,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x55, MINECRAFT_1_21_9, true),
|
||||||
map(0x57, MINECRAFT_26_1, true));
|
map(0x57, MINECRAFT_26_1, true),
|
||||||
|
map(0x59, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTimesPacket.class,
|
TitleTimesPacket.class,
|
||||||
TitleTimesPacket::new,
|
TitleTimesPacket::new,
|
||||||
@@ -720,7 +718,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x71, MINECRAFT_1_21_9, true),
|
||||||
map(0x73, MINECRAFT_26_1, true));
|
map(0x73, MINECRAFT_26_1, true),
|
||||||
|
map(0x75, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleClearPacket.class,
|
TitleClearPacket.class,
|
||||||
TitleClearPacket::new,
|
TitleClearPacket::new,
|
||||||
@@ -752,7 +751,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x43, MINECRAFT_1_21_9, false),
|
||||||
map(0x45, MINECRAFT_26_1, false));
|
map(0x45, MINECRAFT_26_1, false),
|
||||||
|
map(0x46, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
UpsertPlayerInfoPacket.class,
|
UpsertPlayerInfoPacket.class,
|
||||||
UpsertPlayerInfoPacket::new,
|
UpsertPlayerInfoPacket::new,
|
||||||
@@ -763,14 +763,16 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x44, MINECRAFT_1_21_9, false),
|
||||||
map(0x46, MINECRAFT_26_1, false));
|
map(0x46, MINECRAFT_26_1, false),
|
||||||
|
map(0x47, MINECRAFT_26_3, 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),
|
map(0x76, MINECRAFT_1_21_9, false),
|
||||||
map(0x78, MINECRAFT_26_1, false));
|
map(0x78, MINECRAFT_26_1, false),
|
||||||
|
map(0x7A, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
SystemChatPacket.class,
|
SystemChatPacket.class,
|
||||||
SystemChatPacket::new,
|
SystemChatPacket::new,
|
||||||
@@ -784,7 +786,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x77, MINECRAFT_1_21_9, true),
|
||||||
map(0x79, MINECRAFT_26_1, true));
|
map(0x79, MINECRAFT_26_1, true),
|
||||||
|
map(0x7C, MINECRAFT_26_3, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PlayerChatCompletionPacket.class,
|
PlayerChatCompletionPacket.class,
|
||||||
PlayerChatCompletionPacket::new,
|
PlayerChatCompletionPacket::new,
|
||||||
@@ -807,7 +810,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x54, MINECRAFT_1_21_9, false),
|
||||||
map(0x56, MINECRAFT_26_1, false));
|
map(0x56, MINECRAFT_26_1, false),
|
||||||
|
map(0x58, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
StartUpdatePacket.class,
|
StartUpdatePacket.class,
|
||||||
() -> StartUpdatePacket.INSTANCE,
|
() -> StartUpdatePacket.INSTANCE,
|
||||||
@@ -817,7 +821,8 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x74, MINECRAFT_1_21_9, false),
|
||||||
map(0x76, MINECRAFT_26_1, false));
|
map(0x76, MINECRAFT_26_1, false),
|
||||||
|
map(0x78, MINECRAFT_26_3, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
BundleDelimiterPacket.class,
|
BundleDelimiterPacket.class,
|
||||||
() -> BundleDelimiterPacket.INSTANCE,
|
() -> BundleDelimiterPacket.INSTANCE,
|
||||||
@@ -828,21 +833,46 @@ public enum StateRegistry {
|
|||||||
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),
|
map(0x7F, MINECRAFT_1_21_9, false),
|
||||||
map(0x81, MINECRAFT_26_1, false));
|
map(0x81, MINECRAFT_26_1, false),
|
||||||
|
map(0x84, MINECRAFT_26_3, 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),
|
map(0x86, MINECRAFT_1_21_9, false),
|
||||||
map(0x88, MINECRAFT_26_1, false));
|
map(0x88, MINECRAFT_26_1, false),
|
||||||
|
map(0x8B, MINECRAFT_26_3, 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),
|
map(0x87, MINECRAFT_1_21_9, false),
|
||||||
|
map(0x89, MINECRAFT_26_1, false),
|
||||||
|
map(0x8C, MINECRAFT_26_3, false));
|
||||||
map(0x89, MINECRAFT_26_1, false));
|
map(0x89, MINECRAFT_26_1, false));
|
||||||
|
clientbound.register(
|
||||||
|
UpdateTeamsPacket.class,
|
||||||
|
UpdateTeamsPacket::new,
|
||||||
|
map(0x41, MINECRAFT_1_9, true),
|
||||||
|
map(0x43, MINECRAFT_1_12, true),
|
||||||
|
map(0x44, MINECRAFT_1_12_1, true),
|
||||||
|
map(0x47, MINECRAFT_1_13, true),
|
||||||
|
map(0x4B, MINECRAFT_1_14, true),
|
||||||
|
map(0x4C, MINECRAFT_1_15, true),
|
||||||
|
map(0x55, MINECRAFT_1_17, true),
|
||||||
|
map(0x58, MINECRAFT_1_19_1, true),
|
||||||
|
map(0x56, MINECRAFT_1_19_3, true),
|
||||||
|
map(0x5A, MINECRAFT_1_19_4, true),
|
||||||
|
map(0x5C, MINECRAFT_1_20_2, true),
|
||||||
|
map(0x5E, MINECRAFT_1_20_3, true),
|
||||||
|
map(0x60, MINECRAFT_1_20_5, true),
|
||||||
|
map(0x67, MINECRAFT_1_21_2, true),
|
||||||
|
map(0x6B, MINECRAFT_1_21_9, true),
|
||||||
|
map(0x63, MINECRAFT_1_21_11, true),
|
||||||
|
map(0x6D, MINECRAFT_26_1, true),
|
||||||
|
map(0x6D, MINECRAFT_26_2, true));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LOGIN {
|
LOGIN {
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2026 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 io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
|
||||||
|
public final class ClientboundPostEffectsPacket implements MinecraftPacket {
|
||||||
|
|
||||||
|
private Key[] postEffects;
|
||||||
|
|
||||||
|
public ClientboundPostEffectsPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientboundPostEffectsPacket(Key[] postEffects) {
|
||||||
|
this.postEffects = postEffects;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
this.postEffects = ProtocolUtils.readKeyArray(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
ProtocolUtils.writeKeyArray(buf, this.postEffects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
|
return handler.handle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
|
|
||||||
private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024);
|
private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024);
|
||||||
private int entityId;
|
private int entityId;
|
||||||
private short gamemode;
|
private int gamemode;
|
||||||
private int dimension;
|
private int dimension;
|
||||||
private long partialHashedSeed; // 1.15+
|
private long partialHashedSeed; // 1.15+
|
||||||
private short difficulty;
|
private short difficulty;
|
||||||
@@ -47,7 +47,7 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
private CompoundBinaryTag registry; // 1.16+
|
private CompoundBinaryTag registry; // 1.16+
|
||||||
private DimensionInfo dimensionInfo; // 1.16+
|
private DimensionInfo dimensionInfo; // 1.16+
|
||||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
||||||
private short previousGamemode; // 1.16+
|
private int previousGamemode; // 1.16+
|
||||||
private int simulationDistance; // 1.18+
|
private int simulationDistance; // 1.18+
|
||||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
||||||
private int portalCooldown; // 1.20+
|
private int portalCooldown; // 1.20+
|
||||||
@@ -63,11 +63,11 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
this.entityId = entityId;
|
this.entityId = entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getGamemode() {
|
public int getGamemode() {
|
||||||
return gamemode;
|
return gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGamemode(short gamemode) {
|
public void setGamemode(int gamemode) {
|
||||||
this.gamemode = gamemode;
|
this.gamemode = gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,11 +131,11 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
this.dimensionInfo = dimensionInfo;
|
this.dimensionInfo = dimensionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getPreviousGamemode() {
|
public int getPreviousGamemode() {
|
||||||
return previousGamemode;
|
return previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousGamemode(short previousGamemode) {
|
public void setPreviousGamemode(int previousGamemode) {
|
||||||
this.previousGamemode = previousGamemode;
|
this.previousGamemode = previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,8 +345,13 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
String levelName = ProtocolUtils.readString(buf);
|
String levelName = ProtocolUtils.readString(buf);
|
||||||
this.partialHashedSeed = buf.readLong();
|
this.partialHashedSeed = buf.readLong();
|
||||||
|
|
||||||
this.gamemode = buf.readByte();
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
this.previousGamemode = buf.readByte();
|
this.gamemode = ProtocolUtils.readVarInt(buf);
|
||||||
|
this.previousGamemode = ProtocolUtils.readVarInt(buf); // game mode + 1 or 0
|
||||||
|
} else {
|
||||||
|
this.gamemode = buf.readByte();
|
||||||
|
this.previousGamemode = buf.readByte(); // game mode or -1
|
||||||
|
}
|
||||||
|
|
||||||
boolean isDebug = buf.readBoolean();
|
boolean isDebug = buf.readBoolean();
|
||||||
boolean isFlat = buf.readBoolean();
|
boolean isFlat = buf.readBoolean();
|
||||||
@@ -498,8 +503,13 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||||
buf.writeLong(partialHashedSeed);
|
buf.writeLong(partialHashedSeed);
|
||||||
|
|
||||||
buf.writeByte(gamemode);
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
buf.writeByte(previousGamemode);
|
ProtocolUtils.writeVarInt(buf, this.gamemode);
|
||||||
|
ProtocolUtils.writeVarInt(buf, this.previousGamemode);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(this.gamemode);
|
||||||
|
buf.writeByte(this.previousGamemode);
|
||||||
|
}
|
||||||
|
|
||||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||||
buf.writeBoolean(dimensionInfo.isFlat());
|
buf.writeBoolean(dimensionInfo.isFlat());
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
private int dimension;
|
private int dimension;
|
||||||
private long partialHashedSeed;
|
private long partialHashedSeed;
|
||||||
private short difficulty;
|
private short difficulty;
|
||||||
private short gamemode;
|
private int gamemode;
|
||||||
private String levelType = "";
|
private String levelType = "";
|
||||||
private byte dataToKeep; // 1.16+
|
private byte dataToKeep; // 1.16+
|
||||||
private DimensionInfo dimensionInfo; // 1.16-1.16.1
|
private DimensionInfo dimensionInfo; // 1.16-1.16.1
|
||||||
private short previousGamemode; // 1.16+
|
private int previousGamemode; // 1.16+
|
||||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
||||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
||||||
private int portalCooldown; // 1.20+
|
private int portalCooldown; // 1.20+
|
||||||
@@ -46,9 +46,9 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
public RespawnPacket() {
|
public RespawnPacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode,
|
public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, int gamemode,
|
||||||
String levelType, byte dataToKeep, DimensionInfo dimensionInfo,
|
String levelType, byte dataToKeep, DimensionInfo dimensionInfo,
|
||||||
short previousGamemode, CompoundBinaryTag currentDimensionData,
|
int previousGamemode, CompoundBinaryTag currentDimensionData,
|
||||||
@Nullable Pair<String, Long> lastDeathPosition, int portalCooldown,
|
@Nullable Pair<String, Long> lastDeathPosition, int portalCooldown,
|
||||||
int seaLevel) {
|
int seaLevel) {
|
||||||
this.dimension = dimension;
|
this.dimension = dimension;
|
||||||
@@ -97,11 +97,11 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
this.difficulty = difficulty;
|
this.difficulty = difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getGamemode() {
|
public int getGamemode() {
|
||||||
return gamemode;
|
return gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGamemode(short gamemode) {
|
public void setGamemode(int gamemode) {
|
||||||
this.gamemode = gamemode;
|
this.gamemode = gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,11 +121,11 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
this.dataToKeep = dataToKeep;
|
this.dataToKeep = dataToKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getPreviousGamemode() {
|
public int getPreviousGamemode() {
|
||||||
return previousGamemode;
|
return previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousGamemode(short previousGamemode) {
|
public void setPreviousGamemode(int previousGamemode) {
|
||||||
this.previousGamemode = previousGamemode;
|
this.previousGamemode = previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,9 +197,17 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||||
this.partialHashedSeed = buf.readLong();
|
this.partialHashedSeed = buf.readLong();
|
||||||
}
|
}
|
||||||
this.gamemode = buf.readByte();
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
|
this.gamemode = ProtocolUtils.readVarInt(buf);
|
||||||
|
} else {
|
||||||
|
this.gamemode = buf.readByte();
|
||||||
|
}
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||||
this.previousGamemode = buf.readByte();
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
|
this.previousGamemode = ProtocolUtils.readVarInt(buf);
|
||||||
|
} else {
|
||||||
|
this.previousGamemode = buf.readByte();
|
||||||
|
}
|
||||||
boolean isDebug = buf.readBoolean();
|
boolean isDebug = buf.readBoolean();
|
||||||
boolean isFlat = buf.readBoolean();
|
boolean isFlat = buf.readBoolean();
|
||||||
this.dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
this.dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
||||||
@@ -249,9 +257,17 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||||
buf.writeLong(partialHashedSeed);
|
buf.writeLong(partialHashedSeed);
|
||||||
}
|
}
|
||||||
buf.writeByte(gamemode);
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
|
ProtocolUtils.writeVarInt(buf, this.gamemode);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(this.gamemode);
|
||||||
|
}
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||||
buf.writeByte(previousGamemode);
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_26_3)) {
|
||||||
|
ProtocolUtils.writeVarInt(buf, this.previousGamemode);
|
||||||
|
} else {
|
||||||
|
buf.writeByte(this.previousGamemode);
|
||||||
|
}
|
||||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||||
buf.writeBoolean(dimensionInfo.isFlat());
|
buf.writeBoolean(dimensionInfo.isFlat());
|
||||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* 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.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UpdateTeamsPacket implements MinecraftPacket {
|
||||||
|
protected String name;
|
||||||
|
protected Mode mode;
|
||||||
|
|
||||||
|
protected Component displayName;
|
||||||
|
protected Component prefix;
|
||||||
|
protected Component suffix;
|
||||||
|
protected NameTagVisibility nameTagVisibility;
|
||||||
|
protected CollisionRule collisionRule;
|
||||||
|
protected int color;
|
||||||
|
protected byte friendlyFlags;
|
||||||
|
|
||||||
|
protected 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) {
|
||||||
|
throw new UnsupportedOperationException("Packet is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-3
@@ -25,6 +25,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_5;
|
|||||||
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_26_2;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_26_2;
|
||||||
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_26_3;
|
||||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.id;
|
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.id;
|
||||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.mapSet;
|
import static com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentIdentifier.mapSet;
|
||||||
import static com.velocitypowered.proxy.protocol.packet.brigadier.DoubleArgumentPropertySerializer.DOUBLE;
|
import static com.velocitypowered.proxy.protocol.packet.brigadier.DoubleArgumentPropertySerializer.DOUBLE;
|
||||||
@@ -273,16 +274,21 @@ public class ArgumentPropertyRegistry {
|
|||||||
empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_6, 51), mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49),
|
empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_6, 51), mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49),
|
||||||
mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4
|
mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4
|
||||||
|
|
||||||
empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54),mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48),
|
empty(id("minecraft:uuid", mapSet(MINECRAFT_26_3, 61), mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54), mapSet(MINECRAFT_1_20_5, 53),
|
||||||
mapSet(MINECRAFT_1_19_4, 48), mapSet(MINECRAFT_1_19, 47))); // added in 1.16
|
mapSet(MINECRAFT_1_20_3, 48), mapSet(MINECRAFT_1_19_4, 48), mapSet(MINECRAFT_1_19, 47))); // added in 1.16
|
||||||
|
|
||||||
empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_6, 52), mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50)));
|
empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_6, 52), mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50)));
|
||||||
empty(id("minecraft:loot_predicate", mapSet(MINECRAFT_1_21_6, 53), mapSet(MINECRAFT_1_21_5, 52), mapSet(MINECRAFT_1_20_5, 51)));
|
empty(id("minecraft:loot_predicate", mapSet(MINECRAFT_1_21_6, 53), mapSet(MINECRAFT_1_21_5, 52), mapSet(MINECRAFT_1_20_5, 51)));
|
||||||
empty(id("minecraft:loot_modifier", mapSet(MINECRAFT_1_21_6, 54), mapSet(MINECRAFT_1_21_5, 53), mapSet(MINECRAFT_1_20_5, 52)));
|
empty(id("minecraft:loot_modifier", mapSet(MINECRAFT_1_21_6, 54), mapSet(MINECRAFT_1_21_5, 53), mapSet(MINECRAFT_1_20_5, 52)));
|
||||||
|
|
||||||
empty(id("minecraft:hex_color", mapSet(MINECRAFT_1_21_6, 17))); // added in 1.21.6
|
empty(id("minecraft:hex_color", mapSet(MINECRAFT_1_21_6, 17))); // added in 1.21.6
|
||||||
empty(id("minecraft:dialog", mapSet(MINECRAFT_1_21_6, 55))); // added in 1.21.6
|
empty(id("minecraft:dialog", mapSet(MINECRAFT_26_3, 58), mapSet(MINECRAFT_1_21_6, 55))); // added in 1.21.6
|
||||||
empty(id("minecraft:team_color", mapSet(MINECRAFT_26_2, 16))); // renamed from color in 26.2
|
empty(id("minecraft:team_color", mapSet(MINECRAFT_26_2, 16))); // renamed from color in 26.2
|
||||||
|
empty(id("minecraft:context_float_provider", mapSet(MINECRAFT_26_3, 55))); // added in 26.3
|
||||||
|
empty(id("minecraft:context_int_provider", mapSet(MINECRAFT_26_3, 56))); // added in 26.3
|
||||||
|
empty(id("minecraft:slot_source", mapSet(MINECRAFT_26_3, 57))); // added in 26.3
|
||||||
|
empty(id("minecraft:feature", mapSet(MINECRAFT_26_3, 59))); // added in 26.3
|
||||||
|
empty(id("minecraft:swing_animation", mapSet(MINECRAFT_26_3, 60))); // added in 26.3
|
||||||
|
|
||||||
// Crossstitch support
|
// Crossstitch support
|
||||||
register(id("crossstitch:mod_argument", mapSet(MINECRAFT_1_19, -256)), ModArgumentProperty.class, MOD);
|
register(id("crossstitch:mod_argument", mapSet(MINECRAFT_1_19, -256)), ModArgumentProperty.class, MOD);
|
||||||
|
|||||||
+2
@@ -116,6 +116,8 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.readByteArray(buf));
|
ProtocolUtils.readByteArray(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
@@ -132,6 +132,7 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
|||||||
unsigned = true;
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
@@ -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];
|
||||||
|
|||||||
+2
@@ -47,6 +47,8 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
|||||||
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
|
||||||
|
|||||||
@@ -30,40 +30,51 @@ package com.velocitypowered.proxy.util;
|
|||||||
* <p>This class is not thread-safe. If multiple threads access an instance concurrently,
|
* <p>This class is not thread-safe. If multiple threads access an instance concurrently,
|
||||||
* external synchronization is required.</p>
|
* external synchronization is required.</p>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("checkstyle:WhitespaceAfter") // Not our class
|
|
||||||
public final class IntervalledCounter {
|
public final class IntervalledCounter {
|
||||||
|
|
||||||
private static final int INITIAL_SIZE = 8;
|
private static final int INITIAL_SIZE = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data points within this many nanoseconds of the newest one are merged into it, bounding the
|
||||||
|
* number of stored data points to roughly {@code interval / COALESCE_INTERVAL}.
|
||||||
|
*/
|
||||||
|
private static final long COALESCE_INTERVAL = 1_000_000L; // 1ms
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ring buffer holding the timestamp (in nanoseconds) for each data point.
|
* Ring buffer holding the timestamp (in nanoseconds) for each data point.
|
||||||
*/
|
*/
|
||||||
protected long[] times;
|
private long[] times;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ring buffer holding the count associated with each timestamp.
|
* Ring buffer holding the count associated with each timestamp.
|
||||||
*/
|
*/
|
||||||
protected long[] counts;
|
private long[] counts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sliding window size in nanoseconds. Only entries with time >= (currentTime - interval)
|
* The sliding window size in nanoseconds. Only entries with time >= (currentTime - interval)
|
||||||
* are considered part of the window.
|
* are considered part of the window.
|
||||||
*/
|
*/
|
||||||
protected final long interval;
|
private final long interval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached lower bound of the window (in nanoseconds) after the last update.
|
* Cached lower bound of the window (in nanoseconds) after the last update.
|
||||||
*/
|
*/
|
||||||
protected long minTime;
|
private long minTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Running sum of all counts currently within the window.
|
* Running sum of all counts currently within the window.
|
||||||
*/
|
*/
|
||||||
protected long sum;
|
private long sum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Head index (inclusive) of the ring buffer.
|
* Head index (inclusive) of the ring buffer.
|
||||||
*/
|
*/
|
||||||
protected int head; // inclusive
|
private int head; // inclusive
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tail index (exclusive) of the ring buffer.
|
* Tail index (exclusive) of the ring buffer.
|
||||||
*/
|
*/
|
||||||
protected int tail; // exclusive
|
private int tail; // exclusive
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new counter with the specified interval.
|
* Creates a new counter with the specified interval.
|
||||||
@@ -131,6 +142,8 @@ public final class IntervalledCounter {
|
|||||||
/**
|
/**
|
||||||
* Adds {@code count} units at the specified timestamp, assuming the timestamp is within the
|
* Adds {@code count} units at the specified timestamp, assuming the timestamp is within the
|
||||||
* current window. If the timestamp is older than {@code minTime}, the value is ignored.
|
* current window. If the timestamp is older than {@code minTime}, the value is ignored.
|
||||||
|
* If the timestamp is within {@link #COALESCE_INTERVAL} of the newest stored data point, the
|
||||||
|
* count is merged into that data point instead of creating a new one.
|
||||||
* This method does not automatically advance the window; callers should invoke
|
* This method does not automatically advance the window; callers should invoke
|
||||||
* {@link #updateCurrentTime()} or {@link #updateCurrentTime(long)} beforehand.
|
* {@link #updateCurrentTime()} or {@link #updateCurrentTime(long)} beforehand.
|
||||||
*
|
*
|
||||||
@@ -142,6 +155,15 @@ public final class IntervalledCounter {
|
|||||||
if (currTime - this.minTime < 0) {
|
if (currTime - this.minTime < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.head != this.tail) {
|
||||||
|
final int last = this.tail == 0 ? this.times.length - 1 : this.tail - 1;
|
||||||
|
// guard against overflow by using subtraction
|
||||||
|
if (currTime - this.times[last] < COALESCE_INTERVAL) {
|
||||||
|
this.counts[last] += count;
|
||||||
|
this.sum += count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
int nextTail = (this.tail + 1) % this.times.length;
|
int nextTail = (this.tail + 1) % this.times.length;
|
||||||
if (nextTail == this.head) {
|
if (nextTail == this.head) {
|
||||||
this.resize();
|
this.resize();
|
||||||
@@ -219,7 +241,7 @@ public final class IntervalledCounter {
|
|||||||
* @return the rate in units per second for the current window
|
* @return the rate in units per second for the current window
|
||||||
*/
|
*/
|
||||||
public double getRate() {
|
public double getRate() {
|
||||||
return (double)this.sum / ((double)this.interval * 1.0E-9);
|
return (double) this.sum / ((double) this.interval * 1.0E-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2026 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.util;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class IntervalledCounterTest {
|
||||||
|
|
||||||
|
private static final long INTERVAL = TimeUnit.SECONDS.toNanos(7);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sumAndRateTrackAddedCounts() {
|
||||||
|
IntervalledCounter counter = new IntervalledCounter(INTERVAL);
|
||||||
|
long now = 0;
|
||||||
|
|
||||||
|
counter.updateAndAdd(700, now);
|
||||||
|
assertEquals(700, counter.getSum());
|
||||||
|
assertEquals(100.0, counter.getRate(), 1e-9);
|
||||||
|
|
||||||
|
now += TimeUnit.SECONDS.toNanos(1);
|
||||||
|
counter.updateAndAdd(1400, now);
|
||||||
|
assertEquals(2100, counter.getSum());
|
||||||
|
assertEquals(300.0, counter.getRate(), 1e-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void dataPointsOutsideTheWindowAreEvicted() {
|
||||||
|
IntervalledCounter counter = new IntervalledCounter(INTERVAL);
|
||||||
|
long now = 0;
|
||||||
|
|
||||||
|
counter.updateAndAdd(10, now);
|
||||||
|
now += TimeUnit.SECONDS.toNanos(3);
|
||||||
|
counter.updateAndAdd(20, now);
|
||||||
|
assertEquals(30, counter.getSum());
|
||||||
|
assertEquals(2, counter.totalDataPoints());
|
||||||
|
|
||||||
|
// 7.5s after the first point: only the second point remains
|
||||||
|
now = TimeUnit.MILLISECONDS.toNanos(7500);
|
||||||
|
counter.updateCurrentTime(now);
|
||||||
|
assertEquals(20, counter.getSum());
|
||||||
|
assertEquals(1, counter.totalDataPoints());
|
||||||
|
|
||||||
|
// 10.5s: everything has expired
|
||||||
|
now = TimeUnit.MILLISECONDS.toNanos(10500);
|
||||||
|
counter.updateCurrentTime(now);
|
||||||
|
assertEquals(0, counter.getSum());
|
||||||
|
assertEquals(0, counter.totalDataPoints());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void storedDataPointsAreBoundedByTimeNotByCallCount() {
|
||||||
|
IntervalledCounter counter = new IntervalledCounter(INTERVAL);
|
||||||
|
|
||||||
|
// Simulate a flood of tiny (even zero-sized) packets arriving far faster than one per
|
||||||
|
// millisecond for the whole window. Before coalescing was introduced, each call stored a
|
||||||
|
// separate data point, so an attacker could grow the ring buffer without bound while staying
|
||||||
|
// under a bytes-per-second limit.
|
||||||
|
final long stepNanos = 100;
|
||||||
|
final long calls = INTERVAL / stepNanos;
|
||||||
|
long now = 0;
|
||||||
|
for (long i = 0; i < calls; i++) {
|
||||||
|
counter.updateAndAdd(i % 2, now);
|
||||||
|
now += stepNanos;
|
||||||
|
}
|
||||||
|
|
||||||
|
long expectedSum = calls / 2;
|
||||||
|
assertEquals(expectedSum, counter.getSum());
|
||||||
|
// 7s window at 1ms coalescing granularity is ~7000 points; leave some slack.
|
||||||
|
assertTrue(counter.totalDataPoints() <= 7100,
|
||||||
|
"expected at most ~7000 data points, got " + counter.totalDataPoints());
|
||||||
|
assertTrue(counter.totalDataPoints() >= 7000,
|
||||||
|
"expected at least 7000 data points, got " + counter.totalDataPoints());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void coalescedDataPointsExpireTogether() {
|
||||||
|
IntervalledCounter counter = new IntervalledCounter(INTERVAL);
|
||||||
|
|
||||||
|
long now = 0;
|
||||||
|
counter.updateAndAdd(5, now);
|
||||||
|
// Within the same 1ms bucket: merged into the previous point
|
||||||
|
counter.updateAndAdd(7, now + 500_000L);
|
||||||
|
assertEquals(12, counter.getSum());
|
||||||
|
assertEquals(1, counter.totalDataPoints());
|
||||||
|
|
||||||
|
// A new bucket starts a new point
|
||||||
|
counter.updateAndAdd(1, now + 1_000_000L);
|
||||||
|
assertEquals(13, counter.getSum());
|
||||||
|
assertEquals(2, counter.totalDataPoints());
|
||||||
|
|
||||||
|
// The merged bucket carries the timestamp of its first point and expires with it
|
||||||
|
counter.updateCurrentTime(now + INTERVAL + 1);
|
||||||
|
assertEquals(1, counter.getSum());
|
||||||
|
assertEquals(1, counter.totalDataPoints());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
build:
|
||||||
|
- "./gradlew build -x check -x javadoc --no-daemon"
|
||||||
|
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
"/jars/Velocity.jar": "proxy/build/libs/velocity-proxy-4.1.0-SNAPSHOT-all.jar"
|
||||||
|
|
||||||
|
release:
|
||||||
|
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=velocity -Dversion=RELEASE -Dpackaging=jar -Dfile=/jars/Velocity.jar -Durl=file:///var/www/maven/"
|
||||||
Reference in New Issue
Block a user