Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-24 15:20:35 +01:00
Convert Velocity to use ByteBuf-derived plugin message packets
Only tested with 1.12.2, not 1.13 or Forge
Dieser Commit ist enthalten in:
Ursprung
39c505f6fd
Commit
11a86e9bb9
@ -1,5 +1,7 @@
|
||||
package com.velocitypowered.proxy;
|
||||
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import io.netty.util.ResourceLeakDetector.Level;
|
||||
import java.text.DecimalFormat;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -35,6 +37,8 @@ public class Velocity {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceLeakDetector.setLevel(Level.PARANOID);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
VelocityServer server = new VelocityServer(options);
|
||||
|
@ -131,8 +131,8 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
|
||||
try {
|
||||
sessionHandler.exception(cause);
|
||||
} catch (Exception ex) {
|
||||
logger.error("{}: exception handling exception", (association != null ? association :
|
||||
channel.remoteAddress()), cause);
|
||||
logger.error("{}: exception handling exception in {}",
|
||||
(association != null ? association : channel.remoteAddress()), sessionHandler, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
|
||||
if (cause instanceof ReadTimeoutException) {
|
||||
logger.error("{}: read timed out", association);
|
||||
} else {
|
||||
logger.error("{}: exception encountered", association, cause);
|
||||
logger.error("{}: exception encountered in {}", association, sessionHandler, cause);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@ import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse;
|
||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@ -119,12 +121,15 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id,
|
||||
packet.getData());
|
||||
copy);
|
||||
server.getEventManager().fire(event)
|
||||
.thenAcceptAsync(pme -> {
|
||||
if (pme.getResult().isAllowed() && !playerConnection.isClosed()) {
|
||||
playerConnection.write(packet);
|
||||
PluginMessage copied = new PluginMessage(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
playerConnection.write(copied);
|
||||
}
|
||||
}, playerConnection.eventLoop());
|
||||
return true;
|
||||
@ -163,6 +168,9 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void handleGeneric(MinecraftPacket packet) {
|
||||
if (packet instanceof PluginMessage) {
|
||||
((PluginMessage) packet).retain();
|
||||
}
|
||||
playerConnection.write(packet);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import com.velocitypowered.proxy.protocol.packet.Handshake;
|
||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerLogin;
|
||||
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
@ -212,9 +213,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
|
||||
MinecraftConnection mc = ensureConnected();
|
||||
|
||||
PluginMessage message = new PluginMessage();
|
||||
message.setChannel(identifier.getId());
|
||||
message.setData(data);
|
||||
PluginMessage message = new PluginMessage(identifier.getId(), Unpooled.wrappedBuffer(data));
|
||||
mc.write(message);
|
||||
return true;
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse.Offer;
|
||||
import com.velocitypowered.proxy.protocol.packet.TitlePacket;
|
||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -80,6 +83,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivated() {
|
||||
for (PluginMessage message : loginPluginMessages) {
|
||||
ReferenceCountUtil.release(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(KeepAlive packet) {
|
||||
VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||
@ -213,10 +223,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
+ "ready. Channel: {}. Packet discarded.", packet.getChannel());
|
||||
} else if (PluginMessageUtil.isRegister(packet)) {
|
||||
player.getKnownChannels().addAll(PluginMessageUtil.getChannels(packet));
|
||||
backendConn.write(packet);
|
||||
backendConn.write(packet.retain());
|
||||
} else if (PluginMessageUtil.isUnregister(packet)) {
|
||||
player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet));
|
||||
backendConn.write(packet);
|
||||
backendConn.write(packet.retain());
|
||||
} else if (PluginMessageUtil.isMcBrand(packet)) {
|
||||
backendConn.write(PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion()));
|
||||
} else {
|
||||
@ -236,16 +246,23 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// 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.
|
||||
loginPluginMessages.add(packet);
|
||||
//
|
||||
// We also need to make sure to retain these packets so they can be flushed
|
||||
// appropriately.
|
||||
loginPluginMessages.add(packet.retain());
|
||||
} else {
|
||||
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
|
||||
if (id == null) {
|
||||
backendConn.write(packet);
|
||||
backendConn.write(packet.retain());
|
||||
} else {
|
||||
byte[] copy = ByteBufUtil.getBytes(packet.content());
|
||||
PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id,
|
||||
packet.getData());
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> backendConn.write(packet),
|
||||
backendConn.eventLoop());
|
||||
ByteBufUtil.getBytes(packet.content()));
|
||||
server.getEventManager().fire(event).thenAcceptAsync(pme -> {
|
||||
PluginMessage message = new PluginMessage(packet.getChannel(),
|
||||
Unpooled.wrappedBuffer(copy));
|
||||
backendConn.write(message);
|
||||
}, backendConn.eventLoop());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,6 +289,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
MinecraftConnection smc = serverConnection.getConnection();
|
||||
if (smc != null && serverConnection.getPhase().consideredComplete()) {
|
||||
if (packet instanceof PluginMessage) {
|
||||
((PluginMessage) packet).retain();
|
||||
}
|
||||
smc.write(packet);
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ import com.velocitypowered.proxy.tablist.VelocityTabList;
|
||||
import com.velocitypowered.proxy.util.VelocityMessages;
|
||||
import com.velocitypowered.proxy.util.collect.CappedSet;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -570,9 +571,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
|
||||
public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) {
|
||||
Preconditions.checkNotNull(identifier, "identifier");
|
||||
Preconditions.checkNotNull(data, "data");
|
||||
PluginMessage message = new PluginMessage();
|
||||
message.setChannel(identifier.getId());
|
||||
message.setData(data);
|
||||
PluginMessage message = new PluginMessage(identifier.getId(), Unpooled.wrappedBuffer(data));
|
||||
minecraftConnection.write(message);
|
||||
return true;
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ public enum LegacyForgeHandshakeBackendPhase implements BackendConnectionPhase {
|
||||
serverConnection.setConnectionPhase(newPhase);
|
||||
|
||||
// Write the packet to the player, we don't need it now.
|
||||
player.getMinecraftConnection().write(message);
|
||||
player.getMinecraftConnection().write(message.retain());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase {
|
||||
PluginMessage message,
|
||||
MinecraftConnection backendConn) {
|
||||
// Send the packet on to the server.
|
||||
backendConn.write(message);
|
||||
backendConn.write(message.retain());
|
||||
|
||||
// We handled the packet. No need to continue processing.
|
||||
return true;
|
||||
|
@ -27,9 +27,8 @@ class LegacyForgeUtil {
|
||||
*/
|
||||
static byte getHandshakePacketDiscriminator(PluginMessage message) {
|
||||
Preconditions.checkArgument(message.getChannel().equals(FORGE_LEGACY_HANDSHAKE_CHANNEL));
|
||||
byte[] data = message.getData();
|
||||
Preconditions.checkArgument(data.length >= 1);
|
||||
return data[0];
|
||||
Preconditions.checkArgument(message.content().isReadable());
|
||||
return message.content().getByte(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +43,7 @@ class LegacyForgeUtil {
|
||||
.checkArgument(message.getChannel().equals(FORGE_LEGACY_HANDSHAKE_CHANNEL),
|
||||
"message is not a FML HS plugin message");
|
||||
|
||||
ByteBuf byteBuf = Unpooled.wrappedBuffer(message.getData());
|
||||
ByteBuf byteBuf = message.content().retainedSlice();
|
||||
try {
|
||||
byte discriminator = byteBuf.readByte();
|
||||
|
||||
@ -75,7 +74,7 @@ class LegacyForgeUtil {
|
||||
static PluginMessage resetPacket() {
|
||||
PluginMessage msg = new PluginMessage();
|
||||
msg.setChannel(FORGE_LEGACY_HANDSHAKE_CHANNEL);
|
||||
msg.setData(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone());
|
||||
msg.replace(Unpooled.wrappedBuffer(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone()));
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
@ -4,24 +4,24 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LoginPluginMessage implements MinecraftPacket {
|
||||
public class LoginPluginMessage extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
|
||||
private int id;
|
||||
private @Nullable String channel;
|
||||
private ByteBuf data = Unpooled.EMPTY_BUFFER;
|
||||
|
||||
public LoginPluginMessage() {
|
||||
|
||||
super(null);
|
||||
}
|
||||
|
||||
public LoginPluginMessage(int id, @Nullable String channel, ByteBuf data) {
|
||||
super(data);
|
||||
this.id = id;
|
||||
this.channel = channel;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@ -35,16 +35,12 @@ public class LoginPluginMessage implements MinecraftPacket {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public ByteBuf getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LoginPluginMessage{"
|
||||
+ "id=" + id
|
||||
+ ", channel='" + channel + '\''
|
||||
+ ", data=" + data
|
||||
+ ", data=" + super.toString()
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@ -53,9 +49,9 @@ public class LoginPluginMessage implements MinecraftPacket {
|
||||
this.id = ProtocolUtils.readVarInt(buf);
|
||||
this.channel = ProtocolUtils.readString(buf);
|
||||
if (buf.isReadable()) {
|
||||
this.data = buf.readSlice(buf.readableBytes());
|
||||
this.replace(buf.readSlice(buf.readableBytes()));
|
||||
} else {
|
||||
this.data = Unpooled.EMPTY_BUFFER;
|
||||
this.replace(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +62,7 @@ public class LoginPluginMessage implements MinecraftPacket {
|
||||
throw new IllegalStateException("Channel is not specified!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, channel);
|
||||
buf.writeBytes(data);
|
||||
buf.writeBytes(content());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,21 +1,29 @@
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||
import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.transformLegacyToModernChannel;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class PluginMessage implements MinecraftPacket {
|
||||
public class PluginMessage extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
|
||||
private @Nullable String channel;
|
||||
private byte[] data = EMPTY_BYTE_ARRAY;
|
||||
|
||||
public PluginMessage() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public PluginMessage(String channel,
|
||||
@MonotonicNonNull ByteBuf backing) {
|
||||
super(backing);
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
if (channel == null) {
|
||||
@ -28,19 +36,11 @@ public class PluginMessage implements MinecraftPacket {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginMessage{"
|
||||
+ "channel='" + channel + '\''
|
||||
+ ", data=<removed>"
|
||||
+ ", data=" + super.toString()
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@ -50,8 +50,7 @@ public class PluginMessage implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0) {
|
||||
this.channel = transformLegacyToModernChannel(this.channel);
|
||||
}
|
||||
this.data = new byte[buf.readableBytes()];
|
||||
buf.readBytes(data);
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,11 +63,51 @@ public class PluginMessage implements MinecraftPacket {
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, this.channel);
|
||||
}
|
||||
buf.writeBytes(data);
|
||||
buf.writeBytes(content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage copy() {
|
||||
return (PluginMessage) super.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage duplicate() {
|
||||
return (PluginMessage) super.duplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage retainedDuplicate() {
|
||||
return (PluginMessage) super.retainedDuplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage replace(ByteBuf content) {
|
||||
return (PluginMessage) super.replace(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage retain() {
|
||||
return (PluginMessage) super.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage retain(int increment) {
|
||||
return (PluginMessage) super.retain(increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage touch() {
|
||||
return (PluginMessage) super.touch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMessage touch(Object hint) {
|
||||
return (PluginMessage) super.touch(hint);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,136 @@
|
||||
package com.velocitypowered.proxy.protocol.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufHolder;
|
||||
import io.netty.util.IllegalReferenceCountException;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/**
|
||||
* A special-purpose implementation of {@code ByteBufHolder} that can defer accepting its buffer.
|
||||
* This is required because Velocity packets are, for better or worse, mutable.
|
||||
*/
|
||||
public class DeferredByteBufHolder implements ByteBufHolder {
|
||||
|
||||
@MonotonicNonNull
|
||||
private ByteBuf backing;
|
||||
|
||||
public DeferredByteBufHolder(
|
||||
@MonotonicNonNull ByteBuf backing) {
|
||||
this.backing = backing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf content() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
if (backing.refCnt() <= 0) {
|
||||
throw new IllegalReferenceCountException(backing.refCnt());
|
||||
}
|
||||
return backing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder copy() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return new DeferredByteBufHolder(backing.copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder duplicate() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return new DeferredByteBufHolder(backing.duplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder retainedDuplicate() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return new DeferredByteBufHolder(backing.retainedDuplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder replace(ByteBuf content) {
|
||||
if (content == null) {
|
||||
throw new NullPointerException("content");
|
||||
}
|
||||
this.backing = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return backing.refCnt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder retain() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
backing.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder retain(int increment) {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
backing.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder touch() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
backing.touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufHolder touch(Object hint) {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
backing.touch(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return backing.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
if (backing == null) {
|
||||
throw new IllegalStateException("Trying to obtain contents of holder with a null buffer");
|
||||
}
|
||||
return backing.release(decrement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "DeferredByteBufHolder[";
|
||||
if (backing == null) {
|
||||
str += "null";
|
||||
} else {
|
||||
str += backing.toString();
|
||||
}
|
||||
return str + "]";
|
||||
}
|
||||
}
|
@ -11,7 +11,9 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -93,12 +95,12 @@ public class PluginMessageUtil {
|
||||
checkNotNull(message, "message");
|
||||
checkArgument(isRegister(message) || isUnregister(message), "Unknown channel type %s",
|
||||
message.getChannel());
|
||||
if (message.getData().length == 0) {
|
||||
if (!message.content().isReadable()) {
|
||||
// If we try to split this, we will get an one-element array with the empty string, which
|
||||
// has caused issues with 1.13+ compatibility. Just return an empty list.
|
||||
return ImmutableList.of();
|
||||
}
|
||||
String channels = new String(message.getData(), StandardCharsets.UTF_8);
|
||||
String channels = message.content().toString(StandardCharsets.UTF_8);
|
||||
return ImmutableList.copyOf(channels.split("\0"));
|
||||
}
|
||||
|
||||
@ -114,10 +116,9 @@ public class PluginMessageUtil {
|
||||
Preconditions.checkArgument(channels.size() > 0, "no channels specified");
|
||||
String channelName = protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0
|
||||
? REGISTER_CHANNEL : REGISTER_CHANNEL_LEGACY;
|
||||
PluginMessage message = new PluginMessage();
|
||||
message.setChannel(channelName);
|
||||
message.setData(String.join("\0", channels).getBytes(StandardCharsets.UTF_8));
|
||||
return message;
|
||||
ByteBuf contents = Unpooled.buffer();
|
||||
contents.writeCharSequence(String.join("\0", channels), StandardCharsets.UTF_8);
|
||||
return new PluginMessage(channelName, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,21 +134,11 @@ public class PluginMessageUtil {
|
||||
|
||||
String toAppend = " (" + version.getName() + ")";
|
||||
|
||||
byte[] rewrittenData;
|
||||
ByteBuf rewrittenBuf = Unpooled.buffer();
|
||||
try {
|
||||
String currentBrand = ProtocolUtils.readString(Unpooled.wrappedBuffer(message.getData()));
|
||||
String currentBrand = ProtocolUtils.readString(message.content().slice());
|
||||
ProtocolUtils.writeString(rewrittenBuf, currentBrand + toAppend);
|
||||
rewrittenData = new byte[rewrittenBuf.readableBytes()];
|
||||
rewrittenBuf.readBytes(rewrittenData);
|
||||
} finally {
|
||||
rewrittenBuf.release();
|
||||
}
|
||||
|
||||
PluginMessage newMsg = new PluginMessage();
|
||||
newMsg.setChannel(message.getChannel());
|
||||
newMsg.setData(rewrittenData);
|
||||
return newMsg;
|
||||
return new PluginMessage(message.getChannel(), rewrittenBuf);
|
||||
}
|
||||
|
||||
private static final Pattern INVALID_IDENTIFIER_REGEX = Pattern.compile("[^a-z0-9\\-_]*");
|
||||
@ -185,5 +176,4 @@ public class PluginMessageUtil {
|
||||
return "legacy:" + INVALID_IDENTIFIER_REGEX.matcher(lower).replaceAll("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren