Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +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();
|
||||
|
||||
/**
|
||||
* Gets the {@link Origin} of the resource-pack.
|
||||
* Gets the {@link Origin} of this resource-pack.
|
||||
*
|
||||
* @return the origin of the resource pack
|
||||
*/
|
||||
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 {
|
||||
|
||||
/**
|
||||
|
@ -21,12 +21,12 @@ import static com.velocitypowered.proxy.connection.backend.BungeeCordMessageResp
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
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.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.command.PlayerAvailableCommandsEvent;
|
||||
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.proxy.messages.ChannelIdentifier;
|
||||
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.PluginMessage;
|
||||
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.util.PluginMessageUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@ -52,7 +53,7 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.timeout.ReadTimeoutException;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -140,15 +141,48 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
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()) {
|
||||
if (PLAUSIBLE_SHA1_HASH.matcher(packet.getHash()).matches()) {
|
||||
builder.setHash(ByteBufUtil.decodeHexDump(packet.getHash()));
|
||||
.setShouldForce(packet.isRequired())
|
||||
.setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER);
|
||||
|
||||
String hash = packet.getHash();
|
||||
if (hash != null && !hash.isEmpty()) {
|
||||
if (PLAUSIBLE_SHA1_HASH.matcher(hash).matches()) {
|
||||
builder.setHash(ByteBufUtil.decodeHexDump(hash));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -985,7 +985,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
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 @Nullable Component prompt; // 1.17+ only
|
||||
private final Origin origin;
|
||||
private Origin originalOrigin;
|
||||
|
||||
private VelocityResourcePackInfo(String url, @Nullable byte[] hash, boolean shouldForce,
|
||||
@Nullable Component prompt, Origin origin) {
|
||||
@ -36,6 +37,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
this.shouldForce = shouldForce;
|
||||
this.prompt = prompt;
|
||||
this.origin = origin;
|
||||
this.originalOrigin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,6 +65,31 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
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 {
|
||||
private final String url;
|
||||
private boolean shouldForce;
|
||||
@ -102,8 +129,9 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
return new VelocityResourcePackInfo(url, hash, shouldForce, prompt, origin);
|
||||
}
|
||||
|
||||
public void setOrigin(Origin origin) {
|
||||
public BuilderImpl setOrigin(Origin origin) {
|
||||
this.origin = origin;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,14 @@ public class ResourcePackResponse implements MinecraftPacket {
|
||||
private String hash = "";
|
||||
private @MonotonicNonNull Status status;
|
||||
|
||||
public ResourcePackResponse() {
|
||||
}
|
||||
|
||||
public ResourcePackResponse(String hash, @MonotonicNonNull Status status) {
|
||||
this.hash = hash;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
if (status == null) {
|
||||
throw new IllegalStateException("Packet not yet deserialized");
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren