Compare commits
26 Commits
08a42b3723
...
19e51a2b12
| Author | SHA1 | Date | |
|---|---|---|---|
| 19e51a2b12 | |||
| 965db127a9 | |||
| be5f0ace26 | |||
| b89a5c5ce9 | |||
| a33f2d1af5 | |||
| 65d3277319 | |||
| 9cfcfcf2ed | |||
| a22bfa10f9 | |||
| d9d1319a3a | |||
| cefa3b272e | |||
| 15ecbf4345 | |||
| 5e3bbcd427 | |||
| a6c79db07b | |||
| 6e33bc6c17 | |||
| 01208bb359 | |||
| fa88aaae52 | |||
| 2da400a267 | |||
| 8103135dfb | |||
| cfabff7288 | |||
| 2f5a27a708 | |||
| fdfe8bcc4b | |||
| a19fd8db74 | |||
| e63d71423d | |||
| a7afe35fab | |||
| 56d6339313 | |||
| 2475572573 |
@ -26,6 +26,7 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
private final CommandSource commandSource;
|
private final CommandSource commandSource;
|
||||||
private final String command;
|
private final String command;
|
||||||
private CommandResult result;
|
private CommandResult result;
|
||||||
|
private InvocationInfo invocationInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a CommandExecuteEvent.
|
* Constructs a CommandExecuteEvent.
|
||||||
@ -34,9 +35,21 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
* @param command the command being executed without first slash
|
* @param command the command being executed without first slash
|
||||||
*/
|
*/
|
||||||
public CommandExecuteEvent(CommandSource commandSource, String command) {
|
public CommandExecuteEvent(CommandSource commandSource, String command) {
|
||||||
|
this(commandSource, command, new InvocationInfo(SignedState.UNSUPPORTED, Source.API));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CommandExecuteEvent.
|
||||||
|
*
|
||||||
|
* @param commandSource the source executing the command
|
||||||
|
* @param command the command being executed without first slash
|
||||||
|
* @param invocationInfo the invocation info of this command
|
||||||
|
*/
|
||||||
|
public CommandExecuteEvent(CommandSource commandSource, String command, InvocationInfo invocationInfo) {
|
||||||
this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource");
|
this.commandSource = Preconditions.checkNotNull(commandSource, "commandSource");
|
||||||
this.command = Preconditions.checkNotNull(command, "command");
|
this.command = Preconditions.checkNotNull(command, "command");
|
||||||
this.result = CommandResult.allowed();
|
this.result = CommandResult.allowed();
|
||||||
|
this.invocationInfo = invocationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,6 +74,16 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the info of the command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
* @return invocation info
|
||||||
|
*/
|
||||||
|
public InvocationInfo getInvocationInfo() {
|
||||||
|
return this.invocationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult getResult() {
|
public CommandResult getResult() {
|
||||||
return result;
|
return result;
|
||||||
@ -80,6 +103,75 @@ public final class CommandExecuteEvent implements ResultedEvent<CommandResult> {
|
|||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents information about a command invocation, including its signed state and source.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public record InvocationInfo(SignedState signedState, Source source) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the signed state of a command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public enum SignedState {
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from a signed source with signed message arguments,
|
||||||
|
* This is currently only possible by typing a command in chat with signed arguments.
|
||||||
|
*
|
||||||
|
* <p><b>Note:</b> Cancelling the {@link CommandExecuteEvent} in this state will result in the player being kicked.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
SIGNED_WITH_ARGS,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from an signed source with no signed message arguments,
|
||||||
|
* This is currently only possible by typing a command in chat.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
SIGNED_WITHOUT_ARGS,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was executed from an unsigned source,
|
||||||
|
* such as clicking on a component with a {@link net.kyori.adventure.text.event.ClickEvent.Action#RUN_COMMAND}.
|
||||||
|
*
|
||||||
|
* <p>Clients running version 1.20.5 or later will send this state.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
UNSIGNED,
|
||||||
|
/**
|
||||||
|
* Indicates that the command invocation does not support signing.
|
||||||
|
*
|
||||||
|
* <p>This state is sent by clients running versions prior to 1.19.3.</p>
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
UNSUPPORTED
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the source of a command invocation.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
public enum Source {
|
||||||
|
/**
|
||||||
|
* Indicates that the command was invoked by a player.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
PLAYER,
|
||||||
|
/**
|
||||||
|
* Indicates that the command was invoked programmatically through an API call.
|
||||||
|
*
|
||||||
|
* @since 3.4.0
|
||||||
|
*/
|
||||||
|
API
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the result of the {@link CommandExecuteEvent}.
|
* Represents the result of the {@link CommandExecuteEvent}.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -88,7 +88,8 @@ public enum ProtocolVersion implements Ordered<ProtocolVersion> {
|
|||||||
MINECRAFT_1_20_3(765, "1.20.3", "1.20.4"),
|
MINECRAFT_1_20_3(765, "1.20.3", "1.20.4"),
|
||||||
MINECRAFT_1_20_5(766, "1.20.5", "1.20.6"),
|
MINECRAFT_1_20_5(766, "1.20.5", "1.20.6"),
|
||||||
MINECRAFT_1_21(767, "1.21", "1.21.1"),
|
MINECRAFT_1_21(767, "1.21", "1.21.1"),
|
||||||
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3");
|
MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"),
|
||||||
|
MINECRAFT_1_21_4(769, "1.21.4");
|
||||||
|
|
||||||
private static final int SNAPSHOT_BIT = 30;
|
private static final int SNAPSHOT_BIT = 30;
|
||||||
|
|
||||||
|
|||||||
@ -168,6 +168,25 @@ public interface TabList {
|
|||||||
* @deprecated Internal usage. Use {@link TabListEntry.Builder} instead.
|
* @deprecated Internal usage. Use {@link TabListEntry.Builder} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
default TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||||
int gameMode, @Nullable ChatSession chatSession, boolean listed);
|
int gameMode, @Nullable ChatSession chatSession, boolean listed) {
|
||||||
|
return buildEntry(profile, displayName, latency, gameMode, chatSession, listed, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an entry in a {@link Player}'s tab list.
|
||||||
|
*
|
||||||
|
* @param profile the profile
|
||||||
|
* @param displayName the display name
|
||||||
|
* @param latency the latency
|
||||||
|
* @param gameMode the game mode
|
||||||
|
* @param chatSession the chat session
|
||||||
|
* @param listed the visible status of entry
|
||||||
|
* @param listOrder the order/priority of entry in the tab list
|
||||||
|
* @return the entry
|
||||||
|
* @deprecated Internal usage. Use {@link TabListEntry.Builder} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||||
|
int gameMode, @Nullable ChatSession chatSession, boolean listed, int listOrder);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,6 +139,27 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the order/priority of this entry in the tab list.
|
||||||
|
*
|
||||||
|
* @return order of this entry
|
||||||
|
* @sinceMinecraft 1.21.2
|
||||||
|
*/
|
||||||
|
default int getListOrder() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the order/priority of this entry in the tab list.
|
||||||
|
*
|
||||||
|
* @param order order of this entry
|
||||||
|
* @return {@code this}, for chaining
|
||||||
|
* @sinceMinecraft 1.21.2
|
||||||
|
*/
|
||||||
|
default TabListEntry setListOrder(int order) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Builder} to create a {@link TabListEntry}.
|
* Returns a {@link Builder} to create a {@link TabListEntry}.
|
||||||
*
|
*
|
||||||
@ -161,6 +182,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
private int latency = 0;
|
private int latency = 0;
|
||||||
private int gameMode = 0;
|
private int gameMode = 0;
|
||||||
private boolean listed = true;
|
private boolean listed = true;
|
||||||
|
private int listOrder = 0;
|
||||||
|
|
||||||
private @Nullable ChatSession chatSession;
|
private @Nullable ChatSession chatSession;
|
||||||
|
|
||||||
@ -243,7 +265,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets wether this entry should be visible.
|
* Sets whether this entry should be visible.
|
||||||
*
|
*
|
||||||
* @param listed to set
|
* @param listed to set
|
||||||
* @return ${code this}, for chaining
|
* @return ${code this}, for chaining
|
||||||
@ -254,6 +276,19 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the order/priority of this entry in the tab list.
|
||||||
|
*
|
||||||
|
* @param order to set
|
||||||
|
* @return ${code this}, for chaining
|
||||||
|
* @sinceMinecraft 1.21.2
|
||||||
|
* @see TabListEntry#getListOrder()
|
||||||
|
*/
|
||||||
|
public Builder listOrder(int order) {
|
||||||
|
this.listOrder = order;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the {@link TabListEntry} specified by {@code this} {@link Builder}.
|
* Constructs the {@link TabListEntry} specified by {@code this} {@link Builder}.
|
||||||
*
|
*
|
||||||
@ -266,7 +301,7 @@ public interface TabListEntry extends KeyIdentifiable {
|
|||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
throw new IllegalStateException("The GameProfile must be set when building a TabListEntry");
|
throw new IllegalStateException("The GameProfile must be set when building a TabListEntry");
|
||||||
}
|
}
|
||||||
return tabList.buildEntry(profile, displayName, latency, gameMode, chatSession, listed);
|
return tabList.buildEntry(profile, displayName, latency, gameMode, chatSession, listed, listOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public final class ServerPing {
|
|||||||
private final net.kyori.adventure.text.Component description;
|
private final net.kyori.adventure.text.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) {
|
||||||
|
|||||||
@ -53,6 +53,7 @@ netty-codec-haproxy = { module = "io.netty:netty-codec-haproxy", version.ref = "
|
|||||||
netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
||||||
netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" }
|
netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" }
|
||||||
netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" }
|
netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" }
|
||||||
|
netty-transport-native-iouring = { module = "io.netty.incubator:netty-incubator-transport-native-io_uring", version = "0.0.25.Final" }
|
||||||
netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" }
|
netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" }
|
||||||
nightconfig = "com.electronwill.night-config:toml:3.6.7"
|
nightconfig = "com.electronwill.night-config:toml:3.6.7"
|
||||||
slf4j = "org.slf4j:slf4j-api:2.0.12"
|
slf4j = "org.slf4j:slf4j-api:2.0.12"
|
||||||
|
|||||||
@ -117,6 +117,9 @@ dependencies {
|
|||||||
implementation(libs.netty.transport.native.epoll)
|
implementation(libs.netty.transport.native.epoll)
|
||||||
implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-x86_64") })
|
implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-x86_64") })
|
||||||
implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-aarch_64") })
|
implementation(variantOf(libs.netty.transport.native.epoll) { classifier("linux-aarch_64") })
|
||||||
|
implementation(libs.netty.transport.native.iouring)
|
||||||
|
implementation(variantOf(libs.netty.transport.native.iouring) { classifier("linux-x86_64") })
|
||||||
|
implementation(variantOf(libs.netty.transport.native.iouring) { classifier("linux-aarch_64") })
|
||||||
implementation(libs.netty.transport.native.kqueue)
|
implementation(libs.netty.transport.native.kqueue)
|
||||||
implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-x86_64") })
|
implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-x86_64") })
|
||||||
implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-aarch_64") })
|
implementation(variantOf(libs.netty.transport.native.kqueue) { classifier("osx-aarch_64") })
|
||||||
|
|||||||
@ -253,7 +253,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
commandManager.metaBuilder(callbackCommand)
|
commandManager.metaBuilder(callbackCommand)
|
||||||
.plugin(VelocityVirtualPlugin.INSTANCE)
|
.plugin(VelocityVirtualPlugin.INSTANCE)
|
||||||
.build(),
|
.build(),
|
||||||
velocityParentCommand
|
callbackCommand
|
||||||
);
|
);
|
||||||
final BrigadierCommand serverCommand = ServerCommand.create(this);
|
final BrigadierCommand serverCommand = ServerCommand.create(this);
|
||||||
commandManager.register(
|
commandManager.register(
|
||||||
|
|||||||
@ -218,13 +218,14 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
*
|
*
|
||||||
* @param source the source to execute the command for
|
* @param source the source to execute the command for
|
||||||
* @param cmdLine the command to execute
|
* @param cmdLine the command to execute
|
||||||
|
* @param invocationInfo the invocation info
|
||||||
* @return the {@link CompletableFuture} of the event
|
* @return the {@link CompletableFuture} of the event
|
||||||
*/
|
*/
|
||||||
public CompletableFuture<CommandExecuteEvent> callCommandEvent(final CommandSource source,
|
public CompletableFuture<CommandExecuteEvent> callCommandEvent(final CommandSource source,
|
||||||
final String cmdLine) {
|
final String cmdLine, final CommandExecuteEvent.InvocationInfo invocationInfo) {
|
||||||
Preconditions.checkNotNull(source, "source");
|
Preconditions.checkNotNull(source, "source");
|
||||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||||
return eventManager.fire(new CommandExecuteEvent(source, cmdLine));
|
return eventManager.fire(new CommandExecuteEvent(source, cmdLine, invocationInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean executeImmediately0(final CommandSource source, final ParseResults<CommandSource> parsed) {
|
private boolean executeImmediately0(final CommandSource source, final ParseResults<CommandSource> parsed) {
|
||||||
@ -266,7 +267,12 @@ public class VelocityCommandManager implements CommandManager {
|
|||||||
Preconditions.checkNotNull(source, "source");
|
Preconditions.checkNotNull(source, "source");
|
||||||
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
Preconditions.checkNotNull(cmdLine, "cmdLine");
|
||||||
|
|
||||||
return callCommandEvent(source, cmdLine).thenComposeAsync(event -> {
|
CommandExecuteEvent.InvocationInfo invocationInfo = new CommandExecuteEvent.InvocationInfo(
|
||||||
|
CommandExecuteEvent.SignedState.UNSUPPORTED,
|
||||||
|
CommandExecuteEvent.Source.API
|
||||||
|
);
|
||||||
|
|
||||||
|
return callCommandEvent(source, cmdLine, invocationInfo).thenComposeAsync(event -> {
|
||||||
CommandExecuteEvent.CommandResult commandResult = event.getResult();
|
CommandExecuteEvent.CommandResult commandResult = event.getResult();
|
||||||
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
|
if (commandResult.isForwardToServer() || !commandResult.isAllowed()) {
|
||||||
return CompletableFuture.completedFuture(false);
|
return CompletableFuture.completedFuture(false);
|
||||||
|
|||||||
@ -34,6 +34,8 @@ import com.velocitypowered.api.event.player.ServerResourcePackSendEvent;
|
|||||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.command.CommandGraphInjector;
|
import com.velocitypowered.proxy.command.CommandGraphInjector;
|
||||||
@ -288,31 +290,14 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register and unregister packets are simply forwarded to the server as-is.
|
|
||||||
if (PluginMessageUtil.isRegister(packet) || PluginMessageUtil.isUnregister(packet)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PluginMessageUtil.isMcBrand(packet)) {
|
|
||||||
PluginMessagePacket rewritten = PluginMessageUtil
|
|
||||||
.rewriteMinecraftBrand(packet,
|
|
||||||
server.getVersion(), playerConnection.getProtocolVersion());
|
|
||||||
playerConnection.write(rewritten);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) {
|
||||||
// Handled.
|
// Handled.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, copy);
|
String channel = packet.getChannel();
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||||
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
||||||
PluginMessagePacket copied = new PluginMessagePacket(
|
PluginMessagePacket copied = new PluginMessagePacket(
|
||||||
|
|||||||
@ -340,26 +340,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!player.getPhase().handle(player, packet, serverConn)) {
|
if (!player.getPhase().handle(player, packet, serverConn)) {
|
||||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
|
||||||
if (id == null) {
|
|
||||||
// We don't have any plugins listening on this channel, process the packet now.
|
|
||||||
if (!player.getPhase().consideredComplete() || !serverConn.getPhase()
|
|
||||||
.consideredComplete()) {
|
|
||||||
// The client is trying to send messages too early. This is primarily caused by mods,
|
|
||||||
// but further aggravated by Velocity. To work around these issues, we will queue any
|
|
||||||
// non-FML handshake messages to be sent once the FML handshake has completed or the
|
|
||||||
// JoinGame packet has been received by the proxy, whichever comes first.
|
|
||||||
//
|
|
||||||
// We also need to make sure to retain these packets, so they can be flushed
|
|
||||||
// appropriately.
|
|
||||||
loginPluginMessages.add(packet.retain());
|
|
||||||
} else {
|
|
||||||
// The connection is ready, send the packet now.
|
|
||||||
backendConn.write(packet.retain());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy);
|
String channel = packet.getChannel();
|
||||||
|
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, channel.indexOf(':') == -1 ? new LegacyChannelIdentifier(channel) : MinecraftChannelIdentifier.from(channel), copy);
|
||||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||||
if (pme.getResult().isAllowed()) {
|
if (pme.getResult().isAllowed()) {
|
||||||
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
PluginMessagePacket message = new PluginMessagePacket(packet.getChannel(),
|
||||||
@ -379,7 +362,6 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,7 +100,7 @@ public final class ConnectionManager {
|
|||||||
.childOption(ChannelOption.IP_TOS, 0x18)
|
.childOption(ChannelOption.IP_TOS, 0x18)
|
||||||
.localAddress(address);
|
.localAddress(address);
|
||||||
|
|
||||||
if (server.getConfiguration().useTcpFastOpen()) {
|
if (transportType.supportsTcpFastOpenServer() && server.getConfiguration().useTcpFastOpen()) {
|
||||||
bootstrap.option(ChannelOption.TCP_FASTOPEN, 3);
|
bootstrap.option(ChannelOption.TCP_FASTOPEN, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ public final class ConnectionManager {
|
|||||||
this.server.getConfiguration().getConnectTimeout())
|
this.server.getConfiguration().getConnectTimeout())
|
||||||
.group(group == null ? this.workerGroup : group)
|
.group(group == null ? this.workerGroup : group)
|
||||||
.resolver(this.resolver.asGroup());
|
.resolver(this.resolver.asGroup());
|
||||||
if (server.getConfiguration().useTcpFastOpen()) {
|
if (transportType.supportsTcpFastOpenClient() && server.getConfiguration().useTcpFastOpen()) {
|
||||||
bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true);
|
bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true);
|
||||||
}
|
}
|
||||||
return bootstrap;
|
return bootstrap;
|
||||||
|
|||||||
@ -37,6 +37,8 @@ import io.netty.channel.socket.SocketChannel;
|
|||||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.incubator.channel.uring.*;
|
||||||
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
@ -47,32 +49,50 @@ public enum TransportType {
|
|||||||
NIO("NIO", NioServerSocketChannel::new,
|
NIO("NIO", NioServerSocketChannel::new,
|
||||||
NioSocketChannel::new,
|
NioSocketChannel::new,
|
||||||
NioDatagramChannel::new,
|
NioDatagramChannel::new,
|
||||||
(name, type) -> new NioEventLoopGroup(0, createThreadFactory(name, type))),
|
(name, type) -> new NioEventLoopGroup(0, createThreadFactory(name, type)),
|
||||||
|
false,
|
||||||
|
false),
|
||||||
EPOLL("epoll", EpollServerSocketChannel::new,
|
EPOLL("epoll", EpollServerSocketChannel::new,
|
||||||
EpollSocketChannel::new,
|
EpollSocketChannel::new,
|
||||||
EpollDatagramChannel::new,
|
EpollDatagramChannel::new,
|
||||||
(name, type) -> new EpollEventLoopGroup(0, createThreadFactory(name, type))),
|
(name, type) -> new EpollEventLoopGroup(0, createThreadFactory(name, type)),
|
||||||
|
Epoll.isTcpFastOpenServerSideAvailable(),
|
||||||
|
Epoll.isTcpFastOpenClientSideAvailable()),
|
||||||
|
IO_URING("io_uring", IOUringServerSocketChannel::new,
|
||||||
|
IOUringSocketChannel::new,
|
||||||
|
IOUringDatagramChannel::new,
|
||||||
|
(name, type) -> new IOUringEventLoopGroup(0, createThreadFactory(name, type)),
|
||||||
|
IOUring.isTcpFastOpenServerSideAvailable(),
|
||||||
|
IOUring.isTcpFastOpenClientSideAvailable()),
|
||||||
KQUEUE("kqueue", KQueueServerSocketChannel::new,
|
KQUEUE("kqueue", KQueueServerSocketChannel::new,
|
||||||
KQueueSocketChannel::new,
|
KQueueSocketChannel::new,
|
||||||
KQueueDatagramChannel::new,
|
KQueueDatagramChannel::new,
|
||||||
(name, type) -> new KQueueEventLoopGroup(0, createThreadFactory(name, type)));
|
(name, type) -> new KQueueEventLoopGroup(0, createThreadFactory(name, type)),
|
||||||
|
KQueue.isTcpFastOpenServerSideAvailable(),
|
||||||
|
KQueue.isTcpFastOpenClientSideAvailable());
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory;
|
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory;
|
||||||
final ChannelFactory<? extends SocketChannel> socketChannelFactory;
|
final ChannelFactory<? extends SocketChannel> socketChannelFactory;
|
||||||
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory;
|
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory;
|
||||||
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory;
|
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory;
|
||||||
|
final boolean supportsTcpFastOpenServer;
|
||||||
|
final boolean supportsTcpFastOpenClient;
|
||||||
|
|
||||||
TransportType(final String name,
|
TransportType(final String name,
|
||||||
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory,
|
final ChannelFactory<? extends ServerSocketChannel> serverSocketChannelFactory,
|
||||||
final ChannelFactory<? extends SocketChannel> socketChannelFactory,
|
final ChannelFactory<? extends SocketChannel> socketChannelFactory,
|
||||||
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory,
|
final ChannelFactory<? extends DatagramChannel> datagramChannelFactory,
|
||||||
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory) {
|
final BiFunction<String, Type, EventLoopGroup> eventLoopGroupFactory,
|
||||||
|
final boolean supportsTcpFastOpenServer,
|
||||||
|
final boolean supportsTcpFastOpenClient) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.serverSocketChannelFactory = serverSocketChannelFactory;
|
this.serverSocketChannelFactory = serverSocketChannelFactory;
|
||||||
this.socketChannelFactory = socketChannelFactory;
|
this.socketChannelFactory = socketChannelFactory;
|
||||||
this.datagramChannelFactory = datagramChannelFactory;
|
this.datagramChannelFactory = datagramChannelFactory;
|
||||||
this.eventLoopGroupFactory = eventLoopGroupFactory;
|
this.eventLoopGroupFactory = eventLoopGroupFactory;
|
||||||
|
this.supportsTcpFastOpenServer = supportsTcpFastOpenServer;
|
||||||
|
this.supportsTcpFastOpenClient = supportsTcpFastOpenClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,6 +104,14 @@ public enum TransportType {
|
|||||||
return this.eventLoopGroupFactory.apply(this.name, type);
|
return this.eventLoopGroupFactory.apply(this.name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean supportsTcpFastOpenServer() {
|
||||||
|
return supportsTcpFastOpenServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsTcpFastOpenClient() {
|
||||||
|
return supportsTcpFastOpenClient;
|
||||||
|
}
|
||||||
|
|
||||||
private static ThreadFactory createThreadFactory(final String name, final Type type) {
|
private static ThreadFactory createThreadFactory(final String name, final Type type) {
|
||||||
return new VelocityNettyThreadFactory("Netty " + name + ' ' + type.toString() + " #%d");
|
return new VelocityNettyThreadFactory("Netty " + name + ' ' + type.toString() + " #%d");
|
||||||
}
|
}
|
||||||
@ -98,6 +126,10 @@ public enum TransportType {
|
|||||||
return NIO;
|
return NIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(IOUring.isAvailable()) {
|
||||||
|
return IO_URING;
|
||||||
|
}
|
||||||
|
|
||||||
if (Epoll.isAvailable()) {
|
if (Epoll.isAvailable()) {
|
||||||
return EPOLL;
|
return EPOLL;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ 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_20_5;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21;
|
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_2;
|
||||||
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_4;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
||||||
@ -85,6 +86,7 @@ import com.velocitypowered.proxy.protocol.packet.StatusResponsePacket;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
|
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
|
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
|
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
|
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
|
||||||
@ -358,7 +360,8 @@ public enum StateRegistry {
|
|||||||
map(0x27, MINECRAFT_1_20_2, false),
|
map(0x27, MINECRAFT_1_20_2, false),
|
||||||
map(0x28, MINECRAFT_1_20_3, false),
|
map(0x28, MINECRAFT_1_20_3, false),
|
||||||
map(0x2B, MINECRAFT_1_20_5, false),
|
map(0x2B, MINECRAFT_1_20_5, false),
|
||||||
map(0x2D, MINECRAFT_1_21_2, false));
|
map(0x2D, MINECRAFT_1_21_2, false),
|
||||||
|
map(0x2F, MINECRAFT_1_21_4, 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),
|
||||||
@ -704,6 +707,22 @@ public enum StateRegistry {
|
|||||||
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));
|
||||||
|
clientbound.register(UpdateTeamsPacket.class, UpdateTeamsPacket::new,
|
||||||
|
map(0x41, ProtocolVersion.MINECRAFT_1_9, true),
|
||||||
|
map(0x43, ProtocolVersion.MINECRAFT_1_12, true),
|
||||||
|
map(0x44, ProtocolVersion.MINECRAFT_1_12_1, true),
|
||||||
|
map(0x47, ProtocolVersion.MINECRAFT_1_13, true),
|
||||||
|
map(0x4B, ProtocolVersion.MINECRAFT_1_14, true),
|
||||||
|
map(0x4C, ProtocolVersion.MINECRAFT_1_15, true),
|
||||||
|
map(0x55, ProtocolVersion.MINECRAFT_1_17, true),
|
||||||
|
map(0x58, ProtocolVersion.MINECRAFT_1_19_1, true),
|
||||||
|
map(0x56, ProtocolVersion.MINECRAFT_1_19_3, true),
|
||||||
|
map(0x5A, ProtocolVersion.MINECRAFT_1_19_4, true),
|
||||||
|
map(0x5C, ProtocolVersion.MINECRAFT_1_20_2, true),
|
||||||
|
map(0x5E, ProtocolVersion.MINECRAFT_1_20_3, true),
|
||||||
|
map(0x60, ProtocolVersion.MINECRAFT_1_20_5, true),
|
||||||
|
map(0x67, ProtocolVersion.MINECRAFT_1_21_2, true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LOGIN {
|
LOGIN {
|
||||||
|
|||||||
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UpdateTeamsPacket implements MinecraftPacket {
|
||||||
|
private String name;
|
||||||
|
private Mode mode;
|
||||||
|
|
||||||
|
private Component displayName;
|
||||||
|
private Component prefix;
|
||||||
|
private Component suffix;
|
||||||
|
private NameTagVisibility nameTagVisibility;
|
||||||
|
private CollisionRule collisionRule;
|
||||||
|
private int color;
|
||||||
|
private byte friendlyFlags;
|
||||||
|
|
||||||
|
private List<String> players;
|
||||||
|
|
||||||
|
public UpdateTeamsPacket(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
|
||||||
|
this.name = name;
|
||||||
|
this.mode = mode;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.suffix = suffix;
|
||||||
|
this.nameTagVisibility = nameTagVisibility;
|
||||||
|
this.collisionRule = collisionRule;
|
||||||
|
this.color = color;
|
||||||
|
this.friendlyFlags = friendlyFlags;
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateTeamsPacket() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
throw new UnsupportedOperationException("Packet is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(MinecraftSessionHandler minecraftSessionHandler) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, name);
|
||||||
|
byteBuf.writeByte(mode.ordinal());
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CREATE, UPDATE:
|
||||||
|
new ComponentHolder(protocolVersion, displayName).write(byteBuf);
|
||||||
|
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||||
|
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||||
|
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||||
|
}
|
||||||
|
byteBuf.writeByte(friendlyFlags);
|
||||||
|
ProtocolUtils.writeString(byteBuf, nameTagVisibility.getValue());
|
||||||
|
ProtocolUtils.writeString(byteBuf, collisionRule.getValue());
|
||||||
|
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, color);
|
||||||
|
new ComponentHolder(protocolVersion, prefix).write(byteBuf);
|
||||||
|
new ComponentHolder(protocolVersion, suffix).write(byteBuf);
|
||||||
|
} else {
|
||||||
|
byteBuf.writeByte((byte) color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||||
|
for (String player : players) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, player);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADD_PLAYER, REMOVE_PLAYER:
|
||||||
|
ProtocolUtils.writeVarInt(byteBuf, players.size());
|
||||||
|
for (String player : players) {
|
||||||
|
ProtocolUtils.writeString(byteBuf, player);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Mode {
|
||||||
|
CREATE,
|
||||||
|
REMOVE,
|
||||||
|
UPDATE,
|
||||||
|
ADD_PLAYER,
|
||||||
|
REMOVE_PLAYER,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NameTagVisibility {
|
||||||
|
ALWAYS("always"),
|
||||||
|
NEVER("never"),
|
||||||
|
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
|
||||||
|
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
NameTagVisibility(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CollisionRule {
|
||||||
|
ALWAYS("always"),
|
||||||
|
NEVER("never"),
|
||||||
|
PUSH_OTHER_TEAMS("pushOtherTeams"),
|
||||||
|
PUSH_OWN_TEAM("pushOwnTeam");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
CollisionRule(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mode getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getSuffix() {
|
||||||
|
return suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameTagVisibility getNameTagVisibility() {
|
||||||
|
return nameTagVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollisionRule getCollisionRule() {
|
||||||
|
return collisionRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getFriendlyFlags() {
|
||||||
|
return friendlyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMode(Mode mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(Component displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(Component prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuffix(Component suffix) {
|
||||||
|
this.suffix = suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNameTagVisibility(NameTagVisibility nameTagVisibility) {
|
||||||
|
this.nameTagVisibility = nameTagVisibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollisionRule(CollisionRule collisionRule) {
|
||||||
|
this.collisionRule = collisionRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFriendlyFlags(byte friendlyFlags) {
|
||||||
|
this.friendlyFlags = friendlyFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayers(List<String> players) {
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -193,6 +193,11 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
info.listOrder = ProtocolUtils.readVarInt(buf);
|
info.listOrder = ProtocolUtils.readVarInt(buf);
|
||||||
}, (version, buf, info) -> { // write
|
}, (version, buf, info) -> { // write
|
||||||
ProtocolUtils.writeVarInt(buf, info.listOrder);
|
ProtocolUtils.writeVarInt(buf, info.listOrder);
|
||||||
|
}),
|
||||||
|
UPDATE_HAT((version, buf, info) -> { // read
|
||||||
|
info.showHat = buf.readBoolean();
|
||||||
|
}, (version, buf, info) -> { // write
|
||||||
|
buf.writeBoolean(info.showHat);
|
||||||
});
|
});
|
||||||
|
|
||||||
private final Read read;
|
private final Read read;
|
||||||
@ -223,6 +228,7 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
private int gameMode;
|
private int gameMode;
|
||||||
@Nullable
|
@Nullable
|
||||||
private ComponentHolder displayName;
|
private ComponentHolder displayName;
|
||||||
|
private boolean showHat;
|
||||||
private int listOrder;
|
private int listOrder;
|
||||||
@Nullable
|
@Nullable
|
||||||
private RemoteChatSession chatSession;
|
private RemoteChatSession chatSession;
|
||||||
@ -256,6 +262,10 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isShowHat() {
|
||||||
|
return showHat;
|
||||||
|
}
|
||||||
|
|
||||||
public int getListOrder() {
|
public int getListOrder() {
|
||||||
return listOrder;
|
return listOrder;
|
||||||
}
|
}
|
||||||
@ -285,6 +295,10 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setShowHat(boolean showHat) {
|
||||||
|
this.showHat = showHat;
|
||||||
|
}
|
||||||
|
|
||||||
public void setListOrder(int listOrder) {
|
public void setListOrder(int listOrder) {
|
||||||
this.listOrder = listOrder;
|
this.listOrder = listOrder;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,8 +56,10 @@ public interface CommandHandler<T extends MinecraftPacket> {
|
|||||||
|
|
||||||
default void queueCommandResult(VelocityServer server, ConnectedPlayer player,
|
default void queueCommandResult(VelocityServer server, ConnectedPlayer player,
|
||||||
BiFunction<CommandExecuteEvent, LastSeenMessages, CompletableFuture<MinecraftPacket>> futurePacketCreator,
|
BiFunction<CommandExecuteEvent, LastSeenMessages, CompletableFuture<MinecraftPacket>> futurePacketCreator,
|
||||||
String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) {
|
String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages,
|
||||||
CompletableFuture<CommandExecuteEvent> eventFuture = server.getCommandManager().callCommandEvent(player, message);
|
CommandExecuteEvent.InvocationInfo invocationInfo) {
|
||||||
|
CompletableFuture<CommandExecuteEvent> eventFuture = server.getCommandManager().callCommandEvent(player, message,
|
||||||
|
invocationInfo);
|
||||||
player.getChatQueue().queuePacket(
|
player.getChatQueue().queuePacket(
|
||||||
newLastSeenMessages -> eventFuture
|
newLastSeenMessages -> eventFuture
|
||||||
.thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages))
|
.thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages))
|
||||||
|
|||||||
@ -47,9 +47,12 @@ public class SystemChatPacket implements MinecraftPacket {
|
|||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||||
component = ComponentHolder.read(buf, version);
|
component = ComponentHolder.read(buf, version);
|
||||||
// System chat is never decoded so this doesn't matter for now
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)){
|
||||||
|
type = buf.readBoolean() ? ChatType.GAME_INFO : ChatType.SYSTEM;
|
||||||
|
} else {
|
||||||
type = ChatType.values()[ProtocolUtils.readVarInt(buf)];
|
type = ChatType.values()[ProtocolUtils.readVarInt(buf)];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||||
|
|||||||
@ -111,6 +111,6 @@ public class KeyedCommandHandler implements CommandHandler<KeyedPlayerCommandPac
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}, packet.getCommand(), packet.getTimestamp(), null);
|
}, packet.getCommand(), packet.getTimestamp(), null, new CommandExecuteEvent.InvocationInfo(CommandExecuteEvent.SignedState.UNSUPPORTED, CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,6 +116,8 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.readByteArray(buf));
|
ProtocolUtils.readByteArray(buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -132,6 +132,7 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
|||||||
unsigned = true;
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -62,6 +62,6 @@ public class LegacyCommandHandler implements CommandHandler<LegacyChatPacket> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}, command, Instant.now(), null);
|
}, command, Instant.now(), null, new CommandExecuteEvent.InvocationInfo(CommandExecuteEvent.SignedState.UNSUPPORTED, CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,6 +117,7 @@ public class SessionCommandHandler implements CommandHandler<SessionPlayerComman
|
|||||||
}
|
}
|
||||||
return forwardCommand(fixedPacket, commandToRun);
|
return forwardCommand(fixedPacket, commandToRun);
|
||||||
});
|
});
|
||||||
}, packet.command, packet.timeStamp, packet.lastSeenMessages);
|
}, packet.command, packet.timeStamp, packet.lastSeenMessages,
|
||||||
|
new CommandExecuteEvent.InvocationInfo(packet.getEventSignedState(), CommandExecuteEvent.Source.PLAYER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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];
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
@ -45,6 +46,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);
|
this.lastSeenMessages = new LastSeenMessages(buf);
|
||||||
|
|
||||||
|
this.argumentSignatures = new ArgumentSignatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,6 +71,10 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
|||||||
return !argumentSignatures.isEmpty();
|
return !argumentSignatures.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandExecuteEvent.SignedState getEventSignedState() {
|
||||||
|
return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||||
@ -44,6 +45,11 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandExecuteEvent.SignedState getEventSignedState() {
|
||||||
|
return CommandExecuteEvent.SignedState.UNSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "UnsignedPlayerCommandPacket{" +
|
return "UnsignedPlayerCommandPacket{" +
|
||||||
|
|||||||
@ -159,12 +159,17 @@ public class KeyedVelocityTabList implements InternalTabList {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||||
int gameMode,
|
int gameMode, @Nullable ChatSession chatSession, boolean listed) {
|
||||||
@Nullable ChatSession chatSession, boolean listed) {
|
|
||||||
return new KeyedVelocityTabListEntry(this, profile, displayName, latency, gameMode,
|
return new KeyedVelocityTabListEntry(this, profile, displayName, latency, gameMode,
|
||||||
chatSession == null ? null : chatSession.getIdentifiedKey());
|
chatSession == null ? null : chatSession.getIdentifiedKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||||
|
int gameMode, @Nullable ChatSession chatSession, boolean listed, int listOrder) {
|
||||||
|
return buildEntry(profile, displayName, latency, gameMode, chatSession, listed);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processLegacy(LegacyPlayerListItemPacket packet) {
|
public void processLegacy(LegacyPlayerListItemPacket packet) {
|
||||||
// Packets are already forwarded on, so no need to do that here
|
// Packets are already forwarded on, so no need to do that here
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package com.velocitypowered.proxy.tablist;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import com.velocitypowered.api.proxy.player.ChatSession;
|
import com.velocitypowered.api.proxy.player.ChatSession;
|
||||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||||
@ -89,7 +90,7 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
} else {
|
} else {
|
||||||
entry = new VelocityTabListEntry(this, entry1.getProfile(),
|
entry = new VelocityTabListEntry(this, entry1.getProfile(),
|
||||||
entry1.getDisplayNameComponent().orElse(null),
|
entry1.getDisplayNameComponent().orElse(null),
|
||||||
entry1.getLatency(), entry1.getGameMode(), entry1.getChatSession(), entry1.isListed());
|
entry1.getLatency(), entry1.getGameMode(), entry1.getChatSession(), entry1.isListed(), entry1.getListOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumSet<UpsertPlayerInfoPacket.Action> actions = EnumSet
|
EnumSet<UpsertPlayerInfoPacket.Action> actions = EnumSet
|
||||||
@ -128,6 +129,11 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
actions.add(UpsertPlayerInfoPacket.Action.UPDATE_LISTED);
|
actions.add(UpsertPlayerInfoPacket.Action.UPDATE_LISTED);
|
||||||
playerInfoEntry.setListed(entry.isListed());
|
playerInfoEntry.setListed(entry.isListed());
|
||||||
}
|
}
|
||||||
|
if (!Objects.equals(previousEntry.getListOrder(), entry.getListOrder())
|
||||||
|
&& player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||||
|
actions.add(UpsertPlayerInfoPacket.Action.UPDATE_LIST_ORDER);
|
||||||
|
playerInfoEntry.setListOrder(entry.getListOrder());
|
||||||
|
}
|
||||||
if (!Objects.equals(previousEntry.getChatSession(), entry.getChatSession())) {
|
if (!Objects.equals(previousEntry.getChatSession(), entry.getChatSession())) {
|
||||||
ChatSession from = entry.getChatSession();
|
ChatSession from = entry.getChatSession();
|
||||||
if (from != null) {
|
if (from != null) {
|
||||||
@ -162,6 +168,11 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
}
|
}
|
||||||
playerInfoEntry.setLatency(entry.getLatency());
|
playerInfoEntry.setLatency(entry.getLatency());
|
||||||
playerInfoEntry.setListed(entry.isListed());
|
playerInfoEntry.setListed(entry.isListed());
|
||||||
|
if (entry.getListOrder() != 0
|
||||||
|
&& player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||||
|
actions.add(UpsertPlayerInfoPacket.Action.UPDATE_LIST_ORDER);
|
||||||
|
playerInfoEntry.setListOrder(entry.getListOrder());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
});
|
});
|
||||||
@ -207,9 +218,9 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
@Override
|
@Override
|
||||||
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
public TabListEntry buildEntry(GameProfile profile, @Nullable Component displayName, int latency,
|
||||||
int gameMode,
|
int gameMode,
|
||||||
@Nullable ChatSession chatSession, boolean listed) {
|
@Nullable ChatSession chatSession, boolean listed, int listOrder) {
|
||||||
return new VelocityTabListEntry(this, profile, displayName, latency, gameMode, chatSession,
|
return new VelocityTabListEntry(this, profile, displayName, latency, gameMode, chatSession,
|
||||||
listed);
|
listed, listOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -246,7 +257,8 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
0,
|
0,
|
||||||
-1,
|
-1,
|
||||||
null,
|
null,
|
||||||
false
|
false,
|
||||||
|
0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -274,6 +286,9 @@ public class VelocityTabList implements InternalTabList {
|
|||||||
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_LISTED)) {
|
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_LISTED)) {
|
||||||
currentEntry.setListedWithoutUpdate(entry.isListed());
|
currentEntry.setListedWithoutUpdate(entry.isListed());
|
||||||
}
|
}
|
||||||
|
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_LIST_ORDER)) {
|
||||||
|
currentEntry.setListOrderWithoutUpdate(entry.getListOrder());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.tablist;
|
package com.velocitypowered.proxy.tablist;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.player.ChatSession;
|
import com.velocitypowered.api.proxy.player.ChatSession;
|
||||||
import com.velocitypowered.api.proxy.player.TabList;
|
import com.velocitypowered.api.proxy.player.TabList;
|
||||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||||
@ -38,6 +39,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
|||||||
private int latency;
|
private int latency;
|
||||||
private int gameMode;
|
private int gameMode;
|
||||||
private boolean listed;
|
private boolean listed;
|
||||||
|
private int listOrder;
|
||||||
private @Nullable ChatSession session;
|
private @Nullable ChatSession session;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +47,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
|||||||
*/
|
*/
|
||||||
public VelocityTabListEntry(VelocityTabList tabList, GameProfile profile, Component displayName,
|
public VelocityTabListEntry(VelocityTabList tabList, GameProfile profile, Component displayName,
|
||||||
int latency,
|
int latency,
|
||||||
int gameMode, @Nullable ChatSession session, boolean listed) {
|
int gameMode, @Nullable ChatSession session, boolean listed, int listOrder) {
|
||||||
this.tabList = tabList;
|
this.tabList = tabList;
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
@ -53,6 +55,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
|||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.listed = listed;
|
this.listed = listed;
|
||||||
|
this.listOrder = listOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -150,4 +153,24 @@ public class VelocityTabListEntry implements TabListEntry {
|
|||||||
void setListedWithoutUpdate(boolean listed) {
|
void setListedWithoutUpdate(boolean listed) {
|
||||||
this.listed = listed;
|
this.listed = listed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getListOrder() {
|
||||||
|
return listOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VelocityTabListEntry setListOrder(int listOrder) {
|
||||||
|
this.listOrder = listOrder;
|
||||||
|
if (tabList.getPlayer().getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||||
|
UpsertPlayerInfoPacket.Entry upsertEntry = this.tabList.createRawEntry(this);
|
||||||
|
upsertEntry.setListOrder(listOrder);
|
||||||
|
tabList.emitActionRaw(UpsertPlayerInfoPacket.Action.UPDATE_LIST_ORDER, upsertEntry);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setListOrderWithoutUpdate(int listOrder) {
|
||||||
|
this.listOrder = listOrder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
10
steamwarci.yml
Normal file
10
steamwarci.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
build:
|
||||||
|
- "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./gradlew build -x check"
|
||||||
|
- "./gradlew --stop"
|
||||||
|
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
"/binarys/velocity.jar": "proxy/build/libs/velocity-proxy-3.4.0-SNAPSHOT-all.jar"
|
||||||
|
|
||||||
|
release:
|
||||||
|
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=velocity -Dversion=RELEASE -Dpackaging=jar -Dfile=proxy/build/libs/velocity-proxy-3.4.0-SNAPSHOT-all.jar -Durl=file:///var/www/html/maven/"
|
||||||
Reference in New Issue
Block a user