Merge remote-tracking branch 'upstream/dev/3.0.0'
SteamWarCI Build failed

# Conflicts:
#	proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
This commit is contained in:
2026-05-21 08:23:49 +02:00
131 changed files with 2623 additions and 1356 deletions
+2 -2
View File
@@ -59,11 +59,11 @@ tasks {
val o = options as StandardJavadocDocletOptions
o.encoding = "UTF-8"
o.source = "17"
o.source = "21"
o.use()
o.links(
"https://www.slf4j.org/apidocs/",
"https://www.javadocs.dev/org.slf4j/slf4j-api/${libs.slf4j.get().version}/",
"https://guava.dev/releases/${libs.guava.get().version}/api/docs/",
"https://google.github.io/guice/api-docs/${libs.guice.get().version}/javadoc/",
"https://docs.oracle.com/en/java/javase/17/docs/api/",
@@ -24,7 +24,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
public final class SerializedPluginDescription {
public static final Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}");
public static final String ID_PATTERN_STRING = "[a-z][a-z0-9-_]{0,63}";
public static final Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING);
// @Nullable is used here to make GSON skip these in the serialized file
private final String id;
@@ -23,7 +23,7 @@ public interface CommandSource extends Audience, PermissionSubject {
* Sends a message with the MiniMessage format to this source.
*
* @param message MiniMessage content
* @see <a href="https://docs.advntr.dev/minimessage/format.html">MiniMessage docs</a>
* @see <a href="https://docs.papermc.io/adventure/minimessage/format/">MiniMessage docs</a>
* for more information on the format.
**/
default void sendRichMessage(final @NotNull String message) {
@@ -31,14 +31,14 @@ public interface CommandSource extends Audience, PermissionSubject {
}
/**
* Sends a message with the MiniMessage format to this source.
*
* @param message MiniMessage content
* @param resolvers resolvers to use
* @see <a href="https://docs.advntr.dev/minimessage/">MiniMessage docs</a>
* and <a href="https://docs.advntr.dev/minimessage/dynamic-replacements">MiniMessage Placeholders docs</a>
* for more information on the format.
**/
* Sends a message with the MiniMessage format to this source.
*
* @param message MiniMessage content
* @param resolvers resolvers to use
* @see <a href="https://docs.papermc.io/adventure/minimessage/">MiniMessage docs</a>
* and <a href="https://docs.papermc.io/adventure/minimessage/dynamic-replacements">MiniMessage Placeholders docs</a>
* for more information on the format.
*/
default void sendRichMessage(
final @NotNull String message,
final @NotNull TagResolver @NotNull... resolvers
@@ -11,6 +11,7 @@ import com.google.common.base.Preconditions;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.annotation.AwaitingEvent;
import com.velocitypowered.api.proxy.Player;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* This event is fired once the player has been authenticated, but before they connect to a server.
@@ -22,10 +23,24 @@ import com.velocitypowered.api.proxy.Player;
public final class LoginEvent implements ResultedEvent<ResultedEvent.ComponentResult> {
private final Player player;
private final String serverIdHash;
private ComponentResult result;
@Deprecated(forRemoval = true)
public LoginEvent(Player player) {
this(player, null);
}
/**
* Constructs a new {@link LoginEvent}.
*
* @param player the player who has completed authentication
* @param serverIdHash the server ID hash sent to Mojang for authentication,
* or {@code null} if the connection is in offline-mode
*/
public LoginEvent(Player player, @Nullable String serverIdHash) {
this.player = Preconditions.checkNotNull(player, "player");
this.serverIdHash = serverIdHash;
this.result = ComponentResult.allowed();
}
@@ -33,6 +48,16 @@ public final class LoginEvent implements ResultedEvent<ResultedEvent.ComponentRe
return player;
}
/**
* Returns the server ID hash that was sent to Mojang to authenticate the player.
* If the connection was in offline-mode, this returns {@code null}.
*
* @return the server ID hash that was sent to Mojang to authenticate the player
*/
public @Nullable String getServerIdHash() {
return serverIdHash;
}
@Override
public ComponentResult getResult() {
return result;
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2025 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.event.player;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import java.util.List;
/**
* This event is fired when a client ({@link Player}) sends a plugin message through the
* unregister channel. Velocity will not wait on this event to finish firing.
*/
public final class PlayerChannelUnregisterEvent {
private final Player player;
private final List<ChannelIdentifier> channels;
public PlayerChannelUnregisterEvent(Player player, List<ChannelIdentifier> channels) {
this.player = Preconditions.checkNotNull(player, "player");
this.channels = Preconditions.checkNotNull(channels, "channels");
}
public Player getPlayer() {
return player;
}
public List<ChannelIdentifier> getChannels() {
return channels;
}
@Override
public String toString() {
return "PlayerChannelUnregisterEvent{"
+ "player=" + player
+ ", channels=" + channels
+ '}';
}
}
@@ -143,7 +143,7 @@ public final class ServerPreConnectEvent implements
* is used, then {@link ConnectionRequestBuilder#connect()}'s result will have the status
* {@link Status#CONNECTION_CANCELLED}.
*
* @return a result to deny conneections
* @return a result to deny connections
*/
public static ServerResult denied() {
return DENIED;
@@ -93,7 +93,9 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
MINECRAFT_1_21_5(770, "1.21.5"),
MINECRAFT_1_21_6(771, "1.21.6"),
MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"),
MINECRAFT_1_21_9(773, "1.21.9", "1.21.10");
MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"),
MINECRAFT_1_21_11(774, "1.21.11"),
MINECRAFT_26_1(775, "26.1", "26.1.1", "26.1.2");
private static final int SNAPSHOT_BIT = 30;
@@ -7,9 +7,11 @@
package com.velocitypowered.api.plugin;
import com.velocitypowered.api.plugin.ap.SerializedPluginDescription;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.intellij.lang.annotations.Pattern;
/**
* Indicates that the {@link Plugin} depends on another plugin in order to enable.
@@ -24,6 +26,7 @@ public @interface Dependency {
* @return The dependency plugin ID
* @see Plugin#id()
*/
@Pattern(SerializedPluginDescription.ID_PATTERN_STRING)
String id();
/**
@@ -7,10 +7,12 @@
package com.velocitypowered.api.plugin;
import com.velocitypowered.api.plugin.ap.SerializedPluginDescription;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.intellij.lang.annotations.Pattern;
/**
* Annotation used to describe a Velocity plugin.
@@ -26,6 +28,7 @@ public @interface Plugin {
*
* @return the ID for this plugin
*/
@Pattern(SerializedPluginDescription.ID_PATTERN_STRING)
String id();
/**
@@ -39,6 +39,7 @@ import net.kyori.adventure.sound.SoundStop;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEventSource;
import net.kyori.adventure.text.object.PlayerHeadObjectContents;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
@@ -49,7 +50,8 @@ public interface Player extends
/* Fundamental Velocity interfaces */
CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink,
/* Adventure-specific interfaces */
Identified, HoverEventSource<HoverEvent.ShowEntity>, Keyed, KeyIdentifiable, Sound.Emitter {
Identified, HoverEventSource<HoverEvent.ShowEntity>, Keyed, KeyIdentifiable, Sound.Emitter,
PlayerHeadObjectContents.SkinSource {
/**
* Returns the player's current username.
@@ -336,6 +338,15 @@ public interface Player extends
Component.text(getUsername()))));
}
@SuppressWarnings("UnstableApiUsage") // permitted implementation
@Override
default void applySkinToPlayerHeadContents(
final PlayerHeadObjectContents.@NotNull Builder builder) {
builder.skin(this.getGameProfile());
if (this.hasSentPlayerSettings()) {
builder.hat(this.getPlayerSettings().getSkinParts().hasHat());
}
}
/**
* Gets the player's client brand.
@@ -11,11 +11,14 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import net.kyori.adventure.text.object.PlayerHeadObjectContents;
import org.jetbrains.annotations.NotNull;
/**
* Represents a Mojang game profile. This class is immutable.
*/
public final class GameProfile {
public final class GameProfile implements PlayerHeadObjectContents.SkinSource {
private final UUID id;
private final String undashedId;
@@ -169,6 +172,23 @@ public final class GameProfile {
ImmutableList.of());
}
@SuppressWarnings("UnstableApiUsage") // permitted implementation
@Override
public void applySkinToPlayerHeadContents(
final PlayerHeadObjectContents.@NotNull Builder builder) {
if (this.properties.isEmpty()) {
builder.id(this.id);
return;
}
builder.id(this.id)
.name(this.name)
.profileProperties(this.properties.stream()
.map(property -> PlayerHeadObjectContents.property(property.getName(),
property.getValue(), property.getSignature()))
.collect(Collectors.toList()));
}
@Override
public String toString() {
return "GameProfile{"