Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-25 15:50:19 +01:00
Snapshot 21w15a
Dieser Commit ist enthalten in:
Ursprung
2220209495
Commit
8def411b2b
@ -8,7 +8,11 @@
|
|||||||
package com.velocitypowered.api.event.player;
|
package com.velocitypowered.api.event.player;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is fired when the status of a resource pack sent to the player by the server is
|
* This event is fired when the status of a resource pack sent to the player by the server is
|
||||||
@ -18,10 +22,29 @@ public class PlayerResourcePackStatusEvent {
|
|||||||
|
|
||||||
private final Player player;
|
private final Player player;
|
||||||
private final Status status;
|
private final Status status;
|
||||||
|
private final @MonotonicNonNull ResourcePackInfo packInfo;
|
||||||
|
private boolean overwriteKick;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instates this event.
|
||||||
|
* @deprecated Use {@link PlayerResourcePackStatusEvent#PlayerResourcePackStatusEvent
|
||||||
|
* (Player, Status, ResourcePackInfo)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public PlayerResourcePackStatusEvent(Player player, Status status) {
|
public PlayerResourcePackStatusEvent(Player player, Status status) {
|
||||||
this.player = Preconditions.checkNotNull(player, "player");
|
this.player = Preconditions.checkNotNull(player, "player");
|
||||||
this.status = Preconditions.checkNotNull(status, "status");
|
this.status = Preconditions.checkNotNull(status, "status");
|
||||||
|
this.packInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instates this event.
|
||||||
|
*/
|
||||||
|
public PlayerResourcePackStatusEvent(Player player, Status status, ResourcePackInfo packInfo) {
|
||||||
|
this.player = Preconditions.checkNotNull(player, "player");
|
||||||
|
this.status = Preconditions.checkNotNull(status, "status");
|
||||||
|
this.packInfo = packInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,11 +65,49 @@ public class PlayerResourcePackStatusEvent {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ResourcePackInfo} this response is for.
|
||||||
|
*
|
||||||
|
* @return the resource-pack info or null if no request was recorded
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ResourcePackInfo getPackInfo() {
|
||||||
|
return packInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether or not to override the kick resulting from
|
||||||
|
* {@link ResourcePackInfo#getShouldForce()} being true.
|
||||||
|
*
|
||||||
|
* @return whether or not to overwrite the result
|
||||||
|
*/
|
||||||
|
public boolean isOverwriteKick() {
|
||||||
|
return overwriteKick;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true to prevent {@link ResourcePackInfo#getShouldForce()}
|
||||||
|
* from kicking the player.
|
||||||
|
* Overwriting this kick is only possible on versions older than 1.17,
|
||||||
|
* as the client or server will enforce this regardless. Cancelling the resulting
|
||||||
|
* kick-events will not prevent the player from disconnecting from the proxy.
|
||||||
|
*
|
||||||
|
* @param overwriteKick whether or not to cancel the kick
|
||||||
|
* @throws IllegalArgumentException if the player version is 1.17 or newer
|
||||||
|
*/
|
||||||
|
public void setOverwriteKick(boolean overwriteKick) {
|
||||||
|
Preconditions.checkArgument(player.getProtocolVersion()
|
||||||
|
.compareTo(ProtocolVersion.MINECRAFT_1_17) < 0,
|
||||||
|
"overwriteKick is not supported on 1.17 or newer");
|
||||||
|
this.overwriteKick = overwriteKick;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PlayerResourcePackStatusEvent{"
|
return "PlayerResourcePackStatusEvent{"
|
||||||
+ "player=" + player
|
+ "player=" + player
|
||||||
+ ", status=" + status
|
+ ", status=" + status
|
||||||
|
+ ", packInfo=" + packInfo
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public enum ProtocolVersion {
|
|||||||
MINECRAFT_1_16_2(751, "1.16.2"),
|
MINECRAFT_1_16_2(751, "1.16.2"),
|
||||||
MINECRAFT_1_16_3(753, "1.16.3"),
|
MINECRAFT_1_16_3(753, "1.16.3"),
|
||||||
MINECRAFT_1_16_4(754, "1.16.4", "1.16.5"),
|
MINECRAFT_1_16_4(754, "1.16.4", "1.16.5"),
|
||||||
MINECRAFT_1_17(-1, 21, "1.17"); // Snapshot: 21w14a, future protocol: 755
|
MINECRAFT_1_17(-1, 22, "1.17"); // Snapshot: 21w15a, future protocol: 755
|
||||||
|
|
||||||
private static final int SNAPSHOT_BIT = 30;
|
private static final int SNAPSHOT_BIT = 30;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
|||||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
|
import com.velocitypowered.api.proxy.messages.ChannelMessageSink;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
||||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.api.proxy.player.TabList;
|
import com.velocitypowered.api.proxy.player.TabList;
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.util.GameProfile;
|
import com.velocitypowered.api.util.GameProfile;
|
||||||
@ -25,6 +26,7 @@ import java.util.UUID;
|
|||||||
import net.kyori.adventure.identity.Identified;
|
import net.kyori.adventure.identity.Identified;
|
||||||
import net.kyori.adventure.identity.Identity;
|
import net.kyori.adventure.identity.Identity;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a player who is connected to the proxy.
|
* Represents a player who is connected to the proxy.
|
||||||
@ -215,7 +217,9 @@ public interface Player extends CommandSource, Identified, InboundConnection,
|
|||||||
* sent resource pack, subscribe to {@link PlayerResourcePackStatusEvent}.
|
* sent resource pack, subscribe to {@link PlayerResourcePackStatusEvent}.
|
||||||
*
|
*
|
||||||
* @param url the URL for the resource pack
|
* @param url the URL for the resource pack
|
||||||
|
* @deprecated Use {@link #sendResourcePackOffer(ResourcePackInfo)} instead
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void sendResourcePack(String url);
|
void sendResourcePack(String url);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,10 +229,37 @@ public interface Player extends CommandSource, Identified, InboundConnection,
|
|||||||
*
|
*
|
||||||
* @param url the URL for the resource pack
|
* @param url the URL for the resource pack
|
||||||
* @param hash the SHA-1 hash value for the resource pack
|
* @param hash the SHA-1 hash value for the resource pack
|
||||||
|
* @deprecated Use {@link #sendResourcePackOffer(ResourcePackInfo)} instead
|
||||||
*/
|
*/
|
||||||
default void sendResourcePack(String url, byte[] hash) {
|
@Deprecated
|
||||||
sendResourcePack(url, hash, false);
|
void sendResourcePack(String url, byte[] hash);
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Queues and sends a new Resource-pack offer to the player.
|
||||||
|
* To monitor the status of the sent resource pack, subscribe to
|
||||||
|
* {@link PlayerResourcePackStatusEvent}.
|
||||||
|
*
|
||||||
|
* @param packInfo the resource-pack in question
|
||||||
|
*/
|
||||||
|
void sendResourcePackOffer(ResourcePackInfo packInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link ResourcePackInfo} of the currently applied
|
||||||
|
* resource-pack or null if none.
|
||||||
|
*
|
||||||
|
* @return the applied resource pack
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ResourcePackInfo getAppliedResourcePack();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link ResourcePackInfo} of the currently accepted
|
||||||
|
* and currently downloading resource-pack or null if none.
|
||||||
|
*
|
||||||
|
* @return the pending resource pack
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ResourcePackInfo getPendingResourcePack();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <strong>Note that this method does not send a plugin message to the server the player
|
* <strong>Note that this method does not send a plugin message to the server the player
|
||||||
@ -241,21 +272,4 @@ public interface Player extends CommandSource, Identified, InboundConnection,
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
|
boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data);
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends the specified resource pack from {@code url} to the user, using the specified 20-byte
|
|
||||||
* SHA-1 hash. To monitor the status of the sent resource pack, subscribe to
|
|
||||||
* {@link PlayerResourcePackStatusEvent}.
|
|
||||||
* In 1.17 and newer you can additionally specify
|
|
||||||
* whether the resource pack is required or not. Setting this for an older client will have
|
|
||||||
* no effect.
|
|
||||||
*
|
|
||||||
* @param url the URL for the resource pack
|
|
||||||
* @param hash the SHA-1 hash value for the resource pack
|
|
||||||
* @param isRequired Only in 1.17+ or newer: If true shows the pack as required to play,
|
|
||||||
* and removes the decline option. Declining it anyway will disconnect the user.
|
|
||||||
*/
|
|
||||||
void sendResourcePack(String url, byte[] hash, boolean isRequired);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import com.velocitypowered.api.event.EventManager;
|
|||||||
import com.velocitypowered.api.plugin.PluginManager;
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
import com.velocitypowered.api.proxy.config.ProxyConfig;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
|
import com.velocitypowered.api.proxy.messages.ChannelRegistrar;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||||
import com.velocitypowered.api.scheduler.Scheduler;
|
import com.velocitypowered.api.scheduler.Scheduler;
|
||||||
@ -217,4 +218,24 @@ public interface ProxyServer extends Audience {
|
|||||||
@NonNull
|
@NonNull
|
||||||
BossBar createBossBar(net.kyori.text.Component title, @NonNull BossBarColor color,
|
BossBar createBossBar(net.kyori.text.Component title, @NonNull BossBarColor color,
|
||||||
@NonNull BossBarOverlay overlay, float progress);
|
@NonNull BossBarOverlay overlay, float progress);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a builder to build a {@link ResourcePackInfo} instance for use with
|
||||||
|
* {@link com.velocitypowered.api.proxy.Player#sendResourcePackOffer(ResourcePackInfo)}.
|
||||||
|
*
|
||||||
|
* <p>Note: The resource-pack location should always:
|
||||||
|
* - Use HTTPS with a valid certificate.
|
||||||
|
* - Be in a crawler-accessible location. Having it behind Cloudflare or Cloudfront
|
||||||
|
* may cause issues in downloading.
|
||||||
|
* - Be in location with appropriate bandwidth so the download does not time out or fail.</p>
|
||||||
|
*
|
||||||
|
* <p>Do also make sure that the resource pack is in the correct format for the version
|
||||||
|
* of the client. It is also highly recommended to always provide the resource-pack SHA-1 hash
|
||||||
|
* of the resource pack with {@link ResourcePackInfo.Builder#setHash(byte[])}
|
||||||
|
* whenever possible to save bandwidth.</p>
|
||||||
|
*
|
||||||
|
* @param url The url where the resource pack can be found
|
||||||
|
* @return a ResourcePackInfo builder
|
||||||
|
*/
|
||||||
|
ResourcePackInfo.Builder createResourcePackBuilder(String url);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.proxy.player;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
public interface ResourcePackInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the link the resource-pack can be found at.
|
||||||
|
*
|
||||||
|
* @return the location of the resource-pack
|
||||||
|
*/
|
||||||
|
String getUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Component} that is displayed on the resource-pack prompt.
|
||||||
|
* This is only displayed if the client version is 1.17 or newer.
|
||||||
|
*
|
||||||
|
* @return the prompt if present or null otherwise
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
Component getPrompt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether or not the acceptance of the resource-pack is enforced.
|
||||||
|
* See {@link Builder#setShouldForce(boolean)} for more information.
|
||||||
|
*
|
||||||
|
* @return whether or not to force usage of this resource-pack
|
||||||
|
*/
|
||||||
|
boolean getShouldForce();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the SHA-1 hash of the resource-pack
|
||||||
|
* See {@link Builder#setHash(byte[])} for more information.
|
||||||
|
*
|
||||||
|
* @return the hash if present or null otherwise
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
byte[] getHash();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Origin} of the resource-pack.
|
||||||
|
*
|
||||||
|
* @return the origin of the resource pack
|
||||||
|
*/
|
||||||
|
Origin getOrigin();
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the resource-pack as required to play on the network.
|
||||||
|
* This feature was introduced in 1.17.
|
||||||
|
* Setting this to true has one of two effects:
|
||||||
|
* If the client is on 1.17 or newer:
|
||||||
|
* - The resource-pack prompt will display without a decline button
|
||||||
|
* - Accept or disconnect are the only available options but players may still press escape.
|
||||||
|
* - Forces the resource-pack offer prompt to display even if the player has
|
||||||
|
* previously declined or disabled resource packs
|
||||||
|
* - The player will be disconnected from the network if they close/skip the prompt.
|
||||||
|
* If the client is on a version older than 1.17:
|
||||||
|
* - If the player accepts the resource pack or has previously accepted a resource-pack
|
||||||
|
* then nothing else will happen.
|
||||||
|
* - If the player declines the resource pack or has previously declined a resource-pack
|
||||||
|
* the player will be disconnected from the network
|
||||||
|
*
|
||||||
|
* @param shouldForce whether or not to force the client to accept the resource pack
|
||||||
|
*/
|
||||||
|
Builder setShouldForce(boolean shouldForce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the SHA-1 hash of the provided resource pack.
|
||||||
|
* Note: It is recommended to always set this hash.
|
||||||
|
* If this hash is not set/ not present then the client will always download
|
||||||
|
* the resource pack even if it may still be cached. By having this hash present,
|
||||||
|
* the client will check first whether or not a resource pack by this hash is cached
|
||||||
|
* before downloading.
|
||||||
|
*
|
||||||
|
* @param hash the SHA-1 hash of the resource-pack
|
||||||
|
*/
|
||||||
|
Builder setHash(@Nullable byte[] hash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a {@link Component} to display on the download prompt.
|
||||||
|
* This will only display if the client version is 1.17 or newer.
|
||||||
|
*
|
||||||
|
* @param prompt the component to display
|
||||||
|
*/
|
||||||
|
Builder setPrompt(@Nullable Component prompt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the {@link ResourcePackInfo} from the provided info for use with
|
||||||
|
* {@link com.velocitypowered.api.proxy.Player#sendResourcePackOffer(ResourcePackInfo)}.
|
||||||
|
* Note: Some features may be version-dependent. Check before use.
|
||||||
|
*
|
||||||
|
* @return a ResourcePackInfo instance from the provided information
|
||||||
|
*/
|
||||||
|
ResourcePackInfo build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the origin of the resource-pack.
|
||||||
|
*/
|
||||||
|
enum Origin {
|
||||||
|
/**
|
||||||
|
* Resource-pack originated from the downstream server.
|
||||||
|
*/
|
||||||
|
DOWNSTREAM_SERVER,
|
||||||
|
/**
|
||||||
|
* The player declined to download the resource pack.
|
||||||
|
*/
|
||||||
|
PLUGIN_ON_PROXY
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ import com.velocitypowered.api.plugin.PluginContainer;
|
|||||||
import com.velocitypowered.api.plugin.PluginManager;
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||||
import com.velocitypowered.api.util.Favicon;
|
import com.velocitypowered.api.util.Favicon;
|
||||||
@ -45,6 +46,7 @@ import com.velocitypowered.proxy.command.builtin.ShutdownCommand;
|
|||||||
import com.velocitypowered.proxy.command.builtin.VelocityCommand;
|
import com.velocitypowered.proxy.command.builtin.VelocityCommand;
|
||||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.console.VelocityConsole;
|
import com.velocitypowered.proxy.console.VelocityConsole;
|
||||||
import com.velocitypowered.proxy.network.ConnectionManager;
|
import com.velocitypowered.proxy.network.ConnectionManager;
|
||||||
import com.velocitypowered.proxy.plugin.VelocityEventManager;
|
import com.velocitypowered.proxy.plugin.VelocityEventManager;
|
||||||
@ -682,4 +684,9 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
|||||||
return version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0 ? POST_1_16_PING_SERIALIZER
|
return version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0 ? POST_1_16_PING_SERIALIZER
|
||||||
: PRE_1_16_PING_SERIALIZER;
|
: PRE_1_16_PING_SERIALIZER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourcePackInfo.Builder createResourcePackBuilder(String url) {
|
||||||
|
return new VelocityResourcePackInfo.BuilderImpl(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package com.velocitypowered.proxy.connection.backend;
|
|||||||
|
|
||||||
import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResponder.getBungeeCordChannel;
|
import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResponder.getBungeeCordChannel;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
@ -28,10 +29,12 @@ import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent;
|
|||||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||||
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.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
|
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
|
||||||
|
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
|
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.AvailableCommands;
|
import com.velocitypowered.proxy.protocol.packet.AvailableCommands;
|
||||||
@ -40,6 +43,7 @@ import com.velocitypowered.proxy.protocol.packet.Disconnect;
|
|||||||
import com.velocitypowered.proxy.protocol.packet.KeepAlive;
|
import com.velocitypowered.proxy.protocol.packet.KeepAlive;
|
||||||
import com.velocitypowered.proxy.protocol.packet.PlayerListItem;
|
import com.velocitypowered.proxy.protocol.packet.PlayerListItem;
|
||||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest;
|
||||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse;
|
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse;
|
||||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@ -128,6 +132,21 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
return false; // forward
|
return false; // forward
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(ResourcePackRequest packet) {
|
||||||
|
ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(
|
||||||
|
Preconditions.checkNotNull(packet.getUrl()))
|
||||||
|
.setPrompt(packet.getPrompt())
|
||||||
|
.setShouldForce(packet.isRequired());
|
||||||
|
// Why SpotBugs decides that this is unsafe I have no idea;
|
||||||
|
if (packet.getHash() != null && !Preconditions.checkNotNull(packet.getHash()).isEmpty()) {
|
||||||
|
builder.setHash(ByteBufUtil.decodeHexDump(packet.getHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConn.getPlayer().queueResourcePack(builder.build());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(PluginMessage packet) {
|
public boolean handle(PluginMessage packet) {
|
||||||
if (bungeecordMessageResponder.process(packet)) {
|
if (bungeecordMessageResponder.process(packet)) {
|
||||||
|
@ -33,6 +33,7 @@ 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.LegacyChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
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;
|
||||||
@ -72,6 +73,7 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -283,9 +285,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(ResourcePackResponse packet) {
|
public boolean handle(ResourcePackResponse packet) {
|
||||||
server.getEventManager().fireAndForget(new PlayerResourcePackStatusEvent(player,
|
return player.onResourcePackResponse(packet.getStatus(),
|
||||||
packet.getStatus()));
|
ByteBufUtil.decodeHexDump(packet.getHash()));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,7 @@ import com.velocitypowered.api.event.player.KickedFromServerEvent.Notify;
|
|||||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.RedirectPlayer;
|
import com.velocitypowered.api.event.player.KickedFromServerEvent.RedirectPlayer;
|
||||||
import com.velocitypowered.api.event.player.KickedFromServerEvent.ServerKickResult;
|
import com.velocitypowered.api.event.player.KickedFromServerEvent.ServerKickResult;
|
||||||
import com.velocitypowered.api.event.player.PlayerModInfoEvent;
|
import com.velocitypowered.api.event.player.PlayerModInfoEvent;
|
||||||
|
import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
|
||||||
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
|
||||||
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
@ -42,6 +43,7 @@ import com.velocitypowered.api.proxy.Player;
|
|||||||
import com.velocitypowered.api.proxy.ServerConnection;
|
import com.velocitypowered.api.proxy.ServerConnection;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.api.util.GameProfile;
|
import com.velocitypowered.api.util.GameProfile;
|
||||||
import com.velocitypowered.api.util.MessagePosition;
|
import com.velocitypowered.api.util.MessagePosition;
|
||||||
@ -55,6 +57,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection;
|
|||||||
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
||||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||||
import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants;
|
import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants;
|
||||||
|
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
|
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
|
||||||
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl;
|
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
@ -76,12 +79,14 @@ import com.velocitypowered.proxy.util.collect.CappedSet;
|
|||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
@ -133,6 +138,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
private final Collection<String> knownChannels;
|
private final Collection<String> knownChannels;
|
||||||
private final CompletableFuture<Void> teardownFuture = new CompletableFuture<>();
|
private final CompletableFuture<Void> teardownFuture = new CompletableFuture<>();
|
||||||
private @MonotonicNonNull List<String> serversToTry = null;
|
private @MonotonicNonNull List<String> serversToTry = null;
|
||||||
|
private @MonotonicNonNull Boolean previousResourceResponse;
|
||||||
|
private final Queue<ResourcePackInfo> outstandingResourcePacks = new ArrayDeque<>();
|
||||||
|
private @Nullable ResourcePackInfo pendingResourcePack;
|
||||||
|
private @Nullable ResourcePackInfo appliedResourcePack;
|
||||||
|
|
||||||
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
|
||||||
@Nullable InetSocketAddress virtualHost, boolean onlineMode) {
|
@Nullable InetSocketAddress virtualHost, boolean onlineMode) {
|
||||||
@ -871,31 +880,133 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public void sendResourcePack(String url) {
|
public void sendResourcePack(String url) {
|
||||||
Preconditions.checkNotNull(url, "url");
|
sendResourcePackOffer(new VelocityResourcePackInfo.BuilderImpl(url).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void sendResourcePack(String url, byte[] hash) {
|
||||||
|
sendResourcePackOffer(new VelocityResourcePackInfo.BuilderImpl(url).setHash(hash).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendResourcePackOffer(ResourcePackInfo packInfo) {
|
||||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
||||||
|
Preconditions.checkNotNull(packInfo, "packInfo");
|
||||||
|
queueResourcePack(packInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queues a resource-pack for sending to the player and sends it
|
||||||
|
* immediately if the queue is empty.
|
||||||
|
*/
|
||||||
|
public void queueResourcePack(ResourcePackInfo info) {
|
||||||
|
outstandingResourcePacks.add(info);
|
||||||
|
if (outstandingResourcePacks.size() == 1) {
|
||||||
|
tickResourcePackQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickResourcePackQueue() {
|
||||||
|
ResourcePackInfo queued = outstandingResourcePacks.peek();
|
||||||
|
|
||||||
|
if (queued != null) {
|
||||||
|
// Check if the player declined a resource pack once already
|
||||||
|
if (previousResourceResponse != null && !previousResourceResponse) {
|
||||||
|
// If that happened we can flush the queue right away.
|
||||||
|
// Unless its 1.17+ and forced it will come back denied anyway
|
||||||
|
while (!outstandingResourcePacks.isEmpty()) {
|
||||||
|
queued = outstandingResourcePacks.peek();
|
||||||
|
if (queued.getShouldForce() && getProtocolVersion()
|
||||||
|
.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
onResourcePackResponse(PlayerResourcePackStatusEvent.Status.DECLINED, new byte[0]);
|
||||||
|
queued = null;
|
||||||
|
}
|
||||||
|
if (queued == null) {
|
||||||
|
// Exit as the queue was cleared
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ResourcePackRequest request = new ResourcePackRequest();
|
ResourcePackRequest request = new ResourcePackRequest();
|
||||||
request.setUrl(url);
|
request.setUrl(queued.getUrl());
|
||||||
request.setHash("");
|
if (queued.getHash() != null) {
|
||||||
request.setRequired(false);
|
request.setHash(ByteBufUtil.hexDump(queued.getHash()));
|
||||||
|
} else {
|
||||||
|
request.setHash("");
|
||||||
|
}
|
||||||
|
request.setRequired(queued.getShouldForce());
|
||||||
|
request.setPrompt(queued.getPrompt());
|
||||||
|
|
||||||
connection.write(request);
|
connection.write(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendResourcePack(String url, byte[] hash, boolean isRequired) {
|
public @Nullable ResourcePackInfo getAppliedResourcePack() {
|
||||||
Preconditions.checkNotNull(url, "url");
|
return appliedResourcePack;
|
||||||
Preconditions.checkNotNull(hash, "hash");
|
}
|
||||||
Preconditions.checkArgument(hash.length == 20, "Hash length is not 20");
|
|
||||||
|
|
||||||
if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
|
@Override
|
||||||
ResourcePackRequest request = new ResourcePackRequest();
|
public @Nullable ResourcePackInfo getPendingResourcePack() {
|
||||||
request.setUrl(url);
|
return pendingResourcePack;
|
||||||
request.setHash(ByteBufUtil.hexDump(hash));
|
}
|
||||||
request.setRequired(isRequired);
|
|
||||||
connection.write(request);
|
/**
|
||||||
|
* Processes a client response to a sent resource-pack.
|
||||||
|
*/
|
||||||
|
public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status status,
|
||||||
|
@Nullable byte[] hash) {
|
||||||
|
|
||||||
|
final boolean peek = status == PlayerResourcePackStatusEvent.Status.ACCEPTED;
|
||||||
|
final ResourcePackInfo queued = peek
|
||||||
|
? outstandingResourcePacks.peek() : outstandingResourcePacks.poll();
|
||||||
|
|
||||||
|
server.getEventManager().fire(new PlayerResourcePackStatusEvent(this, status, queued))
|
||||||
|
.thenAcceptAsync(event -> {
|
||||||
|
if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED
|
||||||
|
&& event.getPackInfo() != null && event.getPackInfo().getShouldForce()
|
||||||
|
&& (!event.isOverwriteKick() || event.getPlayer()
|
||||||
|
.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0)
|
||||||
|
) {
|
||||||
|
event.getPlayer().disconnect(Component
|
||||||
|
.translatable("multiplayer.requiredTexturePrompt.disconnect"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case ACCEPTED:
|
||||||
|
previousResourceResponse = true;
|
||||||
|
pendingResourcePack = queued;
|
||||||
|
break;
|
||||||
|
case DECLINED:
|
||||||
|
previousResourceResponse = false;
|
||||||
|
break;
|
||||||
|
case SUCCESSFUL:
|
||||||
|
appliedResourcePack = queued;
|
||||||
|
pendingResourcePack = null;
|
||||||
|
break;
|
||||||
|
case FAILED_DOWNLOAD:
|
||||||
|
pendingResourcePack = null;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!peek) {
|
||||||
|
CompletableFuture.supplyAsync(() -> {
|
||||||
|
tickResourcePackQueue();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return queued != null && queued.getOrigin() == ResourcePackInfo.Origin.DOWNSTREAM_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Velocity Contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.velocitypowered.proxy.connection.player;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
|
public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||||
|
private final String url;
|
||||||
|
private final @Nullable byte[] hash;
|
||||||
|
private final boolean shouldForce;
|
||||||
|
private final @Nullable Component prompt; // 1.17+ only
|
||||||
|
private final Origin origin;
|
||||||
|
|
||||||
|
private VelocityResourcePackInfo(String url, @Nullable byte[] hash, boolean shouldForce,
|
||||||
|
@Nullable Component prompt, Origin origin) {
|
||||||
|
this.url = url;
|
||||||
|
this.hash = hash;
|
||||||
|
this.shouldForce = shouldForce;
|
||||||
|
this.prompt = prompt;
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Component getPrompt() {
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getShouldForce() {
|
||||||
|
return shouldForce;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable byte[] getHash() {
|
||||||
|
return hash == null ? null : hash.clone(); // Thanks spotbugs, very helpful.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Origin getOrigin() {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class BuilderImpl implements ResourcePackInfo.Builder {
|
||||||
|
private final String url;
|
||||||
|
private boolean shouldForce;
|
||||||
|
private @Nullable byte[] hash;
|
||||||
|
private @Nullable Component prompt;
|
||||||
|
private Origin origin = Origin.PLUGIN_ON_PROXY;
|
||||||
|
|
||||||
|
public BuilderImpl(String url) {
|
||||||
|
this.url = Preconditions.checkNotNull(url, "url");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BuilderImpl setShouldForce(boolean shouldForce) {
|
||||||
|
this.shouldForce = shouldForce;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BuilderImpl setHash(@Nullable byte[] hash) {
|
||||||
|
if (hash != null) {
|
||||||
|
Preconditions.checkArgument(hash.length == 20, "Hash length is not 20");
|
||||||
|
this.hash = hash.clone(); // Thanks spotbugs, very helpful.
|
||||||
|
} else {
|
||||||
|
this.hash = null;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BuilderImpl setPrompt(@Nullable Component prompt) {
|
||||||
|
this.prompt = prompt;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourcePackInfo build() {
|
||||||
|
return new VelocityResourcePackInfo(url, hash, shouldForce, prompt, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrigin(Origin origin) {
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -226,16 +226,16 @@ public enum StateRegistry {
|
|||||||
map(0x39, MINECRAFT_1_16_2, true),
|
map(0x39, MINECRAFT_1_16_2, true),
|
||||||
map(0x3C, MINECRAFT_1_17, true));
|
map(0x3C, MINECRAFT_1_17, true));
|
||||||
clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new,
|
clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new,
|
||||||
map(0x48, MINECRAFT_1_8, true),
|
map(0x48, MINECRAFT_1_8, false),
|
||||||
map(0x32, MINECRAFT_1_9, true),
|
map(0x32, MINECRAFT_1_9, false),
|
||||||
map(0x33, MINECRAFT_1_12, true),
|
map(0x33, MINECRAFT_1_12, false),
|
||||||
map(0x34, MINECRAFT_1_12_1, true),
|
map(0x34, MINECRAFT_1_12_1, false),
|
||||||
map(0x37, MINECRAFT_1_13, true),
|
map(0x37, MINECRAFT_1_13, false),
|
||||||
map(0x39, MINECRAFT_1_14, true),
|
map(0x39, MINECRAFT_1_14, false),
|
||||||
map(0x3A, MINECRAFT_1_15, true),
|
map(0x3A, MINECRAFT_1_15, false),
|
||||||
map(0x39, MINECRAFT_1_16, true),
|
map(0x39, MINECRAFT_1_16, false),
|
||||||
map(0x38, MINECRAFT_1_16_2, true),
|
map(0x38, MINECRAFT_1_16_2, false),
|
||||||
map(0x3B, MINECRAFT_1_17, true));
|
map(0x3B, MINECRAFT_1_17, false));
|
||||||
clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new,
|
clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new,
|
||||||
map(0x47, MINECRAFT_1_8, true),
|
map(0x47, MINECRAFT_1_8, true),
|
||||||
map(0x48, MINECRAFT_1_9, true),
|
map(0x48, MINECRAFT_1_9, true),
|
||||||
|
@ -23,6 +23,8 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
|||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ public class ResourcePackRequest implements MinecraftPacket {
|
|||||||
private @MonotonicNonNull String url;
|
private @MonotonicNonNull String url;
|
||||||
private @MonotonicNonNull String hash;
|
private @MonotonicNonNull String hash;
|
||||||
private boolean isRequired; // 1.17+
|
private boolean isRequired; // 1.17+
|
||||||
|
private @Nullable Component prompt; // 1.17+
|
||||||
|
|
||||||
public @Nullable String getUrl() {
|
public @Nullable String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
@ -56,12 +59,25 @@ public class ResourcePackRequest implements MinecraftPacket {
|
|||||||
isRequired = required;
|
isRequired = required;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Component getPrompt() {
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrompt(Component prompt) {
|
||||||
|
this.prompt = prompt;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
this.url = ProtocolUtils.readString(buf);
|
this.url = ProtocolUtils.readString(buf);
|
||||||
this.hash = ProtocolUtils.readString(buf);
|
this.hash = ProtocolUtils.readString(buf);
|
||||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
||||||
this.isRequired = buf.readBoolean();
|
this.isRequired = buf.readBoolean();
|
||||||
|
if (buf.readBoolean()) {
|
||||||
|
this.prompt = GsonComponentSerializer.gson().deserialize(ProtocolUtils.readString(buf));
|
||||||
|
} else {
|
||||||
|
this.prompt = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +90,12 @@ public class ResourcePackRequest implements MinecraftPacket {
|
|||||||
ProtocolUtils.writeString(buf, hash);
|
ProtocolUtils.writeString(buf, hash);
|
||||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
||||||
buf.writeBoolean(isRequired);
|
buf.writeBoolean(isRequired);
|
||||||
|
if (prompt != null) {
|
||||||
|
buf.writeBoolean(true);
|
||||||
|
ProtocolUtils.writeString(buf, GsonComponentSerializer.gson().serialize(prompt));
|
||||||
|
} else {
|
||||||
|
buf.writeBoolean(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +109,8 @@ public class ResourcePackRequest implements MinecraftPacket {
|
|||||||
return "ResourcePackRequest{"
|
return "ResourcePackRequest{"
|
||||||
+ "url='" + url + '\''
|
+ "url='" + url + '\''
|
||||||
+ ", hash='" + hash + '\''
|
+ ", hash='" + hash + '\''
|
||||||
|
+ ", isRequired=" + isRequired
|
||||||
|
+ ", prompt='" + prompt + '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,10 @@ public class ResourcePackResponse implements MinecraftPacket {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHash() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_9_4) <= 0) {
|
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_9_4) <= 0) {
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren