Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Implement resource pack send event. (#625)
Dieser Commit ist enthalten in:
Ursprung
b8f1df4470
Commit
596d4758ba
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.event.player;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.ResultedEvent;
|
||||||
|
import com.velocitypowered.api.event.annotation.AwaitingEvent;
|
||||||
|
import com.velocitypowered.api.proxy.ServerConnection;
|
||||||
|
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is fired when the downstream server tries to send a player a ResourcePack packet.
|
||||||
|
* The proxy will wait on this event to finish before forwarding the resource pack to the user.
|
||||||
|
* If this event is denied, it will retroactively send a DENIED status to the downstream
|
||||||
|
* server in response.
|
||||||
|
* If the downstream server has it set to "forced" it will forcefully disconnect the user.
|
||||||
|
*/
|
||||||
|
@AwaitingEvent
|
||||||
|
public class ServerResourcePackSendEvent implements ResultedEvent<ResultedEvent.GenericResult> {
|
||||||
|
private GenericResult result;
|
||||||
|
private final ResourcePackInfo receivedResourcePack;
|
||||||
|
private ResourcePackInfo providedResourcePack;
|
||||||
|
private final ServerConnection serverConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new ServerResourcePackSendEvent.
|
||||||
|
*
|
||||||
|
* @param receivedResourcePack The resource pack the server sent.
|
||||||
|
* @param serverConnection The connection this occurred on.
|
||||||
|
*/
|
||||||
|
public ServerResourcePackSendEvent(
|
||||||
|
ResourcePackInfo receivedResourcePack,
|
||||||
|
ServerConnection serverConnection
|
||||||
|
) {
|
||||||
|
this.result = ResultedEvent.GenericResult.allowed();
|
||||||
|
this.receivedResourcePack = receivedResourcePack;
|
||||||
|
this.serverConnection = serverConnection;
|
||||||
|
this.providedResourcePack = receivedResourcePack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerConnection getServerConnection() {
|
||||||
|
return serverConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackInfo getReceivedResourcePack() {
|
||||||
|
return receivedResourcePack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackInfo getProvidedResourcePack() {
|
||||||
|
return providedResourcePack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProvidedResourcePack(ResourcePackInfo providedResourcePack) {
|
||||||
|
this.providedResourcePack = providedResourcePack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GenericResult getResult() {
|
||||||
|
return this.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResult(GenericResult result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
@ -46,12 +46,48 @@ public interface ResourcePackInfo {
|
|||||||
byte[] getHash();
|
byte[] getHash();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link Origin} of the resource-pack.
|
* Gets the {@link Origin} of this resource-pack.
|
||||||
*
|
*
|
||||||
* @return the origin of the resource pack
|
* @return the origin of the resource pack
|
||||||
*/
|
*/
|
||||||
Origin getOrigin();
|
Origin getOrigin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the original {@link Origin} of the resource-pack.
|
||||||
|
* The original origin may differ if the resource pack was altered in the event
|
||||||
|
* {@link com.velocitypowered.api.event.player.ServerResourcePackSendEvent}.
|
||||||
|
*
|
||||||
|
* @return the origin of the resource pack
|
||||||
|
*/
|
||||||
|
Origin getOriginalOrigin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this {@link ResourcePackInfo} instance as a builder so that it can
|
||||||
|
* be modified.
|
||||||
|
* It is <b>not</b> guaranteed that
|
||||||
|
* {@code resourcePackInfo.asBuilder().build().equals(resourcePackInfo)} is true. That is due to
|
||||||
|
* the transient {@link ResourcePackInfo#getOrigin()} and
|
||||||
|
* {@link ResourcePackInfo#getOriginalOrigin()} fields.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return a content-copy of this instance as a {@link ResourcePackInfo.Builder}
|
||||||
|
*/
|
||||||
|
ResourcePackInfo.Builder asBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this {@link ResourcePackInfo} instance as a builder with the new URL as the pack URL so that
|
||||||
|
* it can be modified.
|
||||||
|
* It is <b>not</b> guaranteed that
|
||||||
|
* {@code resourcePackInfo.asBuilder(resourcePackInfo.getUrl()).build().equals(resourcePackInfo)} is true.
|
||||||
|
* That is due to the transient {@link ResourcePackInfo#getOrigin()} and
|
||||||
|
* {@link ResourcePackInfo#getOriginalOrigin()} fields.
|
||||||
|
*
|
||||||
|
* @param newUrl The new URL to use in the updated builder.
|
||||||
|
*
|
||||||
|
* @return a content-copy of this instance as a {@link ResourcePackInfo.Builder}
|
||||||
|
*/
|
||||||
|
ResourcePackInfo.Builder asBuilder(String newUrl);
|
||||||
|
|
||||||
interface Builder {
|
interface Builder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,12 +21,12 @@ import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResp
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
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.tree.CommandNode;
|
|
||||||
import com.mojang.brigadier.tree.RootCommandNode;
|
import com.mojang.brigadier.tree.RootCommandNode;
|
||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent;
|
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.event.player.PlayerResourcePackStatusEvent;
|
||||||
|
import com.velocitypowered.api.event.player.ServerResourcePackSendEvent;
|
||||||
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.api.proxy.player.ResourcePackInfo;
|
||||||
@ -45,6 +45,7 @@ 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.ResourcePackRequest;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse;
|
||||||
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;
|
||||||
@ -52,7 +53,7 @@ import io.netty.buffer.ByteBufUtil;
|
|||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.handler.timeout.ReadTimeoutException;
|
import io.netty.handler.timeout.ReadTimeoutException;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -138,17 +139,50 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(ResourcePackRequest packet) {
|
public boolean handle(ResourcePackRequest packet) {
|
||||||
ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(
|
ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(
|
||||||
Preconditions.checkNotNull(packet.getUrl()))
|
Preconditions.checkNotNull(packet.getUrl()))
|
||||||
.setPrompt(packet.getPrompt())
|
.setPrompt(packet.getPrompt())
|
||||||
.setShouldForce(packet.isRequired());
|
.setShouldForce(packet.isRequired())
|
||||||
// Why SpotBugs decides that this is unsafe I have no idea;
|
.setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER);
|
||||||
if (packet.getHash() != null && !Preconditions.checkNotNull(packet.getHash()).isEmpty()) {
|
|
||||||
if (PLAUSIBLE_SHA1_HASH.matcher(packet.getHash()).matches()) {
|
String hash = packet.getHash();
|
||||||
builder.setHash(ByteBufUtil.decodeHexDump(packet.getHash()));
|
if (hash != null && !hash.isEmpty()) {
|
||||||
|
if (PLAUSIBLE_SHA1_HASH.matcher(hash).matches()) {
|
||||||
|
builder.setHash(ByteBufUtil.decodeHexDump(hash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConn.getPlayer().queueResourcePack(builder.build());
|
ServerResourcePackSendEvent event = new ServerResourcePackSendEvent(
|
||||||
|
builder.build(), this.serverConn);
|
||||||
|
|
||||||
|
server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> {
|
||||||
|
if (playerConnection.isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (serverResourcePackSendEvent.getResult().isAllowed()) {
|
||||||
|
ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack();
|
||||||
|
if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) {
|
||||||
|
((VelocityResourcePackInfo) toSend)
|
||||||
|
.setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConn.getPlayer().queueResourcePack(builder.build());
|
||||||
|
} else if (serverConn.getConnection() != null) {
|
||||||
|
serverConn.getConnection().write(new ResourcePackResponse(
|
||||||
|
packet.getHash(),
|
||||||
|
PlayerResourcePackStatusEvent.Status.DECLINED
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}, playerConnection.eventLoop()).exceptionally((ex) -> {
|
||||||
|
if (serverConn.getConnection() != null) {
|
||||||
|
serverConn.getConnection().write(new ResourcePackResponse(
|
||||||
|
packet.getHash(),
|
||||||
|
PlayerResourcePackStatusEvent.Status.DECLINED
|
||||||
|
));
|
||||||
|
}
|
||||||
|
logger.error("Exception while handling resource pack send for {}", playerConnection, ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,7 +985,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
|||||||
connection.eventLoop().execute(this::tickResourcePackQueue);
|
connection.eventLoop().execute(this::tickResourcePackQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return queued != null && queued.getOrigin() == ResourcePackInfo.Origin.DOWNSTREAM_SERVER;
|
return queued != null
|
||||||
|
&& queued.getOriginalOrigin() == ResourcePackInfo.Origin.DOWNSTREAM_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +28,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
|||||||
private final boolean shouldForce;
|
private final boolean shouldForce;
|
||||||
private final @Nullable Component prompt; // 1.17+ only
|
private final @Nullable Component prompt; // 1.17+ only
|
||||||
private final Origin origin;
|
private final Origin origin;
|
||||||
|
private Origin originalOrigin;
|
||||||
|
|
||||||
private VelocityResourcePackInfo(String url, @Nullable byte[] hash, boolean shouldForce,
|
private VelocityResourcePackInfo(String url, @Nullable byte[] hash, boolean shouldForce,
|
||||||
@Nullable Component prompt, Origin origin) {
|
@Nullable Component prompt, Origin origin) {
|
||||||
@ -36,6 +37,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
|||||||
this.shouldForce = shouldForce;
|
this.shouldForce = shouldForce;
|
||||||
this.prompt = prompt;
|
this.prompt = prompt;
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
|
this.originalOrigin = origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,6 +65,31 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
|||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOriginalOrigin(Origin originalOrigin) {
|
||||||
|
this.originalOrigin = originalOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Origin getOriginalOrigin() {
|
||||||
|
return originalOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder asBuilder() {
|
||||||
|
return new BuilderImpl(url)
|
||||||
|
.setShouldForce(shouldForce)
|
||||||
|
.setHash(hash)
|
||||||
|
.setPrompt(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder asBuilder(String newUrl) {
|
||||||
|
return new BuilderImpl(newUrl)
|
||||||
|
.setShouldForce(shouldForce)
|
||||||
|
.setHash(hash)
|
||||||
|
.setPrompt(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
public static final class BuilderImpl implements ResourcePackInfo.Builder {
|
public static final class BuilderImpl implements ResourcePackInfo.Builder {
|
||||||
private final String url;
|
private final String url;
|
||||||
private boolean shouldForce;
|
private boolean shouldForce;
|
||||||
@ -102,8 +129,9 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
|||||||
return new VelocityResourcePackInfo(url, hash, shouldForce, prompt, origin);
|
return new VelocityResourcePackInfo(url, hash, shouldForce, prompt, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrigin(Origin origin) {
|
public BuilderImpl setOrigin(Origin origin) {
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,14 @@ public class ResourcePackResponse implements MinecraftPacket {
|
|||||||
private String hash = "";
|
private String hash = "";
|
||||||
private @MonotonicNonNull Status status;
|
private @MonotonicNonNull Status status;
|
||||||
|
|
||||||
|
public ResourcePackResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackResponse(String hash, @MonotonicNonNull Status status) {
|
||||||
|
this.hash = hash;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
throw new IllegalStateException("Packet not yet deserialized");
|
throw new IllegalStateException("Packet not yet deserialized");
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren