Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-26 00:00:55 +01:00
Implement Velocity native IP forwarding for 1.13+
No other server implements this (as of yet). We plan to get support for this into at least Paper and Sponge.
Dieser Commit ist enthalten in:
Ursprung
a45adbc8ec
Commit
d9f68140d6
@ -0,0 +1,9 @@
|
|||||||
|
package com.velocitypowered.proxy.connection;
|
||||||
|
|
||||||
|
public class VelocityConstants {
|
||||||
|
private VelocityConstants() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String VELOCITY_IP_FORWARDING_CHANNEL = "velocity:player_info";
|
||||||
|
}
|
@ -3,14 +3,12 @@ package com.velocitypowered.proxy.connection.backend;
|
|||||||
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
|
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import com.velocitypowered.proxy.protocol.packets.Disconnect;
|
import com.velocitypowered.proxy.protocol.packets.*;
|
||||||
import com.velocitypowered.proxy.protocol.packets.EncryptionRequest;
|
|
||||||
import com.velocitypowered.proxy.protocol.packets.ServerLoginSuccess;
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.packets.SetCompression;
|
|
||||||
|
|
||||||
public class LoginSessionHandler implements MinecraftSessionHandler {
|
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||||
private final ServerConnection connection;
|
private final ServerConnection connection;
|
||||||
|
private int forwardingPacketId = -1;
|
||||||
|
|
||||||
public LoginSessionHandler(ServerConnection connection) {
|
public LoginSessionHandler(ServerConnection connection) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
@ -20,20 +18,21 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
public void handle(MinecraftPacket packet) {
|
public void handle(MinecraftPacket packet) {
|
||||||
if (packet instanceof EncryptionRequest) {
|
if (packet instanceof EncryptionRequest) {
|
||||||
throw new IllegalStateException("Backend server is online-mode!");
|
throw new IllegalStateException("Backend server is online-mode!");
|
||||||
|
} else if (packet instanceof LoginPluginResponse) {
|
||||||
|
LoginPluginResponse lpr = (LoginPluginResponse) packet;
|
||||||
|
if (lpr.getId() == forwardingPacketId) {
|
||||||
|
if (!lpr.isSuccess()) {
|
||||||
|
throw new IllegalStateException("Unable to forward player information to server! Is it configured properly?");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (packet instanceof Disconnect) {
|
} else if (packet instanceof Disconnect) {
|
||||||
Disconnect disconnect = (Disconnect) packet;
|
Disconnect disconnect = (Disconnect) packet;
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), disconnect);
|
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), disconnect);
|
||||||
}
|
} else if (packet instanceof SetCompression) {
|
||||||
|
|
||||||
if (packet instanceof SetCompression) {
|
|
||||||
SetCompression sc = (SetCompression) packet;
|
SetCompression sc = (SetCompression) packet;
|
||||||
connection.getChannel().setCompressionThreshold(sc.getThreshold());
|
connection.getChannel().setCompressionThreshold(sc.getThreshold());
|
||||||
}
|
} else if (packet instanceof ServerLoginSuccess) {
|
||||||
|
|
||||||
if (packet instanceof ServerLoginSuccess) {
|
|
||||||
// The player has been logged on to the backend server.
|
// The player has been logged on to the backend server.
|
||||||
connection.getChannel().setState(StateRegistry.PLAY);
|
connection.getChannel().setState(StateRegistry.PLAY);
|
||||||
ServerConnection existingConnection = connection.getProxyPlayer().getConnectedServer();
|
ServerConnection existingConnection = connection.getProxyPlayer().getConnectedServer();
|
||||||
@ -53,4 +52,12 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
public void exception(Throwable throwable) {
|
public void exception(Throwable throwable) {
|
||||||
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), throwable);
|
connection.getProxyPlayer().handleConnectionException(connection.getServerInfo(), throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getForwardingPacketId() {
|
||||||
|
return forwardingPacketId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForwardingPacketId(int forwardingPacketId) {
|
||||||
|
this.forwardingPacketId = forwardingPacketId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,28 @@ package com.velocitypowered.proxy.connection.backend;
|
|||||||
|
|
||||||
import com.velocitypowered.proxy.config.IPForwardingMode;
|
import com.velocitypowered.proxy.config.IPForwardingMode;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
|
||||||
|
import com.velocitypowered.proxy.connection.VelocityConstants;
|
||||||
|
import com.velocitypowered.proxy.data.GameProfile;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder;
|
||||||
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
|
import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder;
|
||||||
import com.velocitypowered.proxy.protocol.packets.Handshake;
|
import com.velocitypowered.proxy.protocol.packets.Handshake;
|
||||||
|
import com.velocitypowered.proxy.protocol.packets.LoginPluginMessage;
|
||||||
import com.velocitypowered.proxy.protocol.packets.ServerLogin;
|
import com.velocitypowered.proxy.protocol.packets.ServerLogin;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import com.velocitypowered.proxy.data.ServerInfo;
|
import com.velocitypowered.proxy.data.ServerInfo;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
import com.velocitypowered.proxy.VelocityServer;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.*;
|
import io.netty.channel.*;
|
||||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.velocitypowered.network.Connections.FRAME_DECODER;
|
import static com.velocitypowered.network.Connections.FRAME_DECODER;
|
||||||
@ -99,9 +104,29 @@ public class ServerConnection implements MinecraftConnectionAssociation {
|
|||||||
handshake.setPort(serverInfo.getAddress().getPort());
|
handshake.setPort(serverInfo.getAddress().getPort());
|
||||||
channel.write(handshake);
|
channel.write(handshake);
|
||||||
|
|
||||||
channel.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion());
|
int protocolVersion = proxyPlayer.getConnection().getProtocolVersion();
|
||||||
|
channel.setProtocolVersion(protocolVersion);
|
||||||
channel.setState(StateRegistry.LOGIN);
|
channel.setState(StateRegistry.LOGIN);
|
||||||
|
|
||||||
|
// 1.13 stuff
|
||||||
|
if (protocolVersion >= ProtocolConstants.MINECRAFT_1_13) {
|
||||||
|
if (VelocityServer.getServer().getConfiguration().getIpForwardingMode() == IPForwardingMode.MODERN) {
|
||||||
|
// Velocity's IP forwarding includes the player's IP address and their game profile.
|
||||||
|
GameProfile profile = proxyPlayer.getProfile();
|
||||||
|
ByteBuf buf = createForwardingData(proxyPlayer.getRemoteAddress().getHostString(), profile);
|
||||||
|
|
||||||
|
// Send the message on
|
||||||
|
LoginPluginMessage forwarding = new LoginPluginMessage();
|
||||||
|
forwarding.setId(ThreadLocalRandom.current().nextInt());
|
||||||
|
forwarding.setChannel(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL);
|
||||||
|
forwarding.setData(buf);
|
||||||
|
|
||||||
|
LoginSessionHandler lsh = (LoginSessionHandler) channel.getSessionHandler();
|
||||||
|
lsh.setForwardingPacketId(forwarding.getId());
|
||||||
|
channel.write(forwarding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
ServerLogin login = new ServerLogin();
|
ServerLogin login = new ServerLogin();
|
||||||
login.setUsername(proxyPlayer.getUsername());
|
login.setUsername(proxyPlayer.getUsername());
|
||||||
@ -129,4 +154,24 @@ public class ServerConnection implements MinecraftConnectionAssociation {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + serverInfo.getName();
|
return "[server connection] " + proxyPlayer.getProfile().getName() + " -> " + serverInfo.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ByteBuf createForwardingData(String address, GameProfile profile) {
|
||||||
|
ByteBuf buf = Unpooled.buffer();
|
||||||
|
ProtocolUtils.writeString(buf, address);
|
||||||
|
ProtocolUtils.writeString(buf, profile.getName());
|
||||||
|
ProtocolUtils.writeString(buf, profile.idAsUuid().toString());
|
||||||
|
ProtocolUtils.writeVarInt(buf, profile.getProperties().size());
|
||||||
|
for (GameProfile.Property property : profile.getProperties()) {
|
||||||
|
ProtocolUtils.writeString(buf, property.getName());
|
||||||
|
ProtocolUtils.writeString(buf, property.getValue());
|
||||||
|
String signature = property.getSignature();
|
||||||
|
if (signature != null) {
|
||||||
|
buf.writeBoolean(true);
|
||||||
|
ProtocolUtils.writeString(buf, signature);
|
||||||
|
} else {
|
||||||
|
buf.writeBoolean(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.velocitypowered.proxy.connection.client;
|
package com.velocitypowered.proxy.connection.client;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.proxy.connection.VelocityConstants;
|
||||||
import com.velocitypowered.proxy.data.GameProfile;
|
import com.velocitypowered.proxy.data.GameProfile;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
@ -12,6 +13,7 @@ import com.velocitypowered.proxy.connection.backend.ServerConnection;
|
|||||||
import com.velocitypowered.proxy.data.ServerInfo;
|
import com.velocitypowered.proxy.data.ServerInfo;
|
||||||
import com.velocitypowered.proxy.util.EncryptionUtils;
|
import com.velocitypowered.proxy.util.EncryptionUtils;
|
||||||
import com.velocitypowered.proxy.util.UuidUtils;
|
import com.velocitypowered.proxy.util.UuidUtils;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import net.kyori.text.TextComponent;
|
import net.kyori.text.TextComponent;
|
||||||
import net.kyori.text.format.TextColor;
|
import net.kyori.text.format.TextColor;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -27,7 +29,6 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||||||
|
|
||||||
public class LoginSessionHandler implements MinecraftSessionHandler {
|
public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||||
private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class);
|
private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class);
|
||||||
|
|
||||||
private static final String MOJANG_SERVER_AUTH_URL =
|
private static final String MOJANG_SERVER_AUTH_URL =
|
||||||
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s";
|
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s";
|
||||||
|
|
||||||
@ -41,7 +42,22 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(MinecraftPacket packet) throws Exception {
|
public void handle(MinecraftPacket packet) throws Exception {
|
||||||
if (packet instanceof ServerLogin) {
|
if (packet instanceof LoginPluginMessage) {
|
||||||
|
LoginPluginMessage lpm = (LoginPluginMessage) packet;
|
||||||
|
if (lpm.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
|
||||||
|
// Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening.
|
||||||
|
inbound.closeWith(Disconnect.create(
|
||||||
|
TextComponent.of("Running Velocity behind Velocity isn't supported.", TextColor.RED)
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
// We don't know what this message is.
|
||||||
|
LoginPluginResponse response = new LoginPluginResponse();
|
||||||
|
response.setId(lpm.getId());
|
||||||
|
response.setSuccess(false);
|
||||||
|
response.setData(Unpooled.EMPTY_BUFFER);
|
||||||
|
inbound.write(response);
|
||||||
|
}
|
||||||
|
} else if (packet instanceof ServerLogin) {
|
||||||
this.login = (ServerLogin) packet;
|
this.login = (ServerLogin) packet;
|
||||||
|
|
||||||
if (VelocityServer.getServer().getConfiguration().isOnlineMode()) {
|
if (VelocityServer.getServer().getConfiguration().isOnlineMode()) {
|
||||||
@ -53,9 +69,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
// Offline-mode, don't try to request encryption.
|
// Offline-mode, don't try to request encryption.
|
||||||
handleSuccessfulLogin(GameProfile.forOfflinePlayer(login.getUsername()));
|
handleSuccessfulLogin(GameProfile.forOfflinePlayer(login.getUsername()));
|
||||||
}
|
}
|
||||||
}
|
} else if (packet instanceof EncryptionResponse) {
|
||||||
|
|
||||||
if (packet instanceof EncryptionResponse) {
|
|
||||||
KeyPair serverKeyPair = VelocityServer.getServer().getServerKeyPair();
|
KeyPair serverKeyPair = VelocityServer.getServer().getServerKeyPair();
|
||||||
EncryptionResponse response = (EncryptionResponse) packet;
|
EncryptionResponse response = (EncryptionResponse) packet;
|
||||||
byte[] decryptedVerifyToken = EncryptionUtils.decryptRsa(serverKeyPair, response.getVerifyToken());
|
byte[] decryptedVerifyToken = EncryptionUtils.decryptRsa(serverKeyPair, response.getVerifyToken());
|
||||||
|
@ -108,6 +108,8 @@ public enum StateRegistry {
|
|||||||
genericMappings(0x00));
|
genericMappings(0x00));
|
||||||
SERVERBOUND.register(EncryptionResponse.class, EncryptionResponse::new,
|
SERVERBOUND.register(EncryptionResponse.class, EncryptionResponse::new,
|
||||||
genericMappings(0x01));
|
genericMappings(0x01));
|
||||||
|
SERVERBOUND.register(LoginPluginMessage.class, LoginPluginMessage::new,
|
||||||
|
map(0x02, MINECRAFT_1_13));
|
||||||
|
|
||||||
CLIENTBOUND.register(Disconnect.class, Disconnect::new,
|
CLIENTBOUND.register(Disconnect.class, Disconnect::new,
|
||||||
genericMappings(0x00));
|
genericMappings(0x00));
|
||||||
@ -117,6 +119,8 @@ public enum StateRegistry {
|
|||||||
genericMappings(0x02));
|
genericMappings(0x02));
|
||||||
CLIENTBOUND.register(SetCompression.class, SetCompression::new,
|
CLIENTBOUND.register(SetCompression.class, SetCompression::new,
|
||||||
genericMappings(0x03));
|
genericMappings(0x03));
|
||||||
|
CLIENTBOUND.register(LoginPluginResponse.class, LoginPluginResponse::new,
|
||||||
|
map(0x04, MINECRAFT_1_13));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.velocitypowered.proxy.protocol.packets;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
public class LoginPluginMessage implements MinecraftPacket {
|
||||||
|
private int id;
|
||||||
|
private String channel;
|
||||||
|
private ByteBuf data;
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChannel(String channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ByteBuf data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "LoginPluginMessage{" +
|
||||||
|
"id=" + id +
|
||||||
|
", channel='" + channel + '\'' +
|
||||||
|
", data=" + data +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
|
this.id = ProtocolUtils.readVarInt(buf);
|
||||||
|
this.channel = ProtocolUtils.readString(buf);
|
||||||
|
if (buf.isReadable()) {
|
||||||
|
this.data = buf.readRetainedSlice(buf.readableBytes());
|
||||||
|
} else {
|
||||||
|
this.data = Unpooled.EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
|
ProtocolUtils.writeVarInt(buf, id);
|
||||||
|
ProtocolUtils.writeString(buf, channel);
|
||||||
|
buf.writeBytes(data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.velocitypowered.proxy.protocol.packets;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolConstants;
|
||||||
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
|
||||||
|
public class LoginPluginResponse implements MinecraftPacket {
|
||||||
|
private int id;
|
||||||
|
private boolean success;
|
||||||
|
private ByteBuf data;
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(boolean success) {
|
||||||
|
this.success = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuf getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(ByteBuf data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "LoginPluginResponse{" +
|
||||||
|
"id=" + id +
|
||||||
|
", success=" + success +
|
||||||
|
", data=" + data +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
|
this.id = ProtocolUtils.readVarInt(buf);
|
||||||
|
this.success = buf.readBoolean();
|
||||||
|
if (buf.isReadable()) {
|
||||||
|
this.data = buf.readRetainedSlice(buf.readableBytes());
|
||||||
|
} else {
|
||||||
|
this.data = Unpooled.EMPTY_BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
|
||||||
|
ProtocolUtils.writeVarInt(buf, id);
|
||||||
|
buf.writeBoolean(success);
|
||||||
|
buf.writeBytes(data);
|
||||||
|
}
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren