mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 14:37:43 +01:00
Make packets immutable
This commit is contained in:
@@ -69,7 +69,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
|
||||
|
||||
public boolean viewerRemove(final ConnectedPlayer viewer) {
|
||||
if (this.viewers.remove(viewer)) {
|
||||
viewer.getBossBarManager().remove(this, BossBarPacket.createRemovePacket(this.id, this.bar));
|
||||
viewer.getBossBarManager().remove(this, BossBarPacket.createRemovePacket(this.id));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -55,6 +55,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
@@ -70,6 +71,7 @@ import org.apache.logging.log4j.Logger;
|
||||
*/
|
||||
public final class VelocityCommand {
|
||||
private static final String USAGE = "/velocity <%s>";
|
||||
private static final JoinConfiguration COMMA_JOINER = JoinConfiguration.commas(true);
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public static BrigadierCommand create(final VelocityServer server) {
|
||||
@@ -208,19 +210,14 @@ public final class VelocityCommand {
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
final TextComponent.Builder listBuilder = Component.text();
|
||||
for (int i = 0; i < pluginCount; i++) {
|
||||
final PluginContainer plugin = plugins.get(i);
|
||||
listBuilder.append(componentForPlugin(plugin.getDescription()));
|
||||
if (i + 1 < pluginCount) {
|
||||
listBuilder.append(Component.text(", "));
|
||||
}
|
||||
}
|
||||
final Component pluginListComponents = plugins.stream()
|
||||
.map(container -> componentForPlugin(container.getDescription()))
|
||||
.collect(Component.toComponent(Component.text(", ")));
|
||||
|
||||
final TranslatableComponent output = Component.translatable()
|
||||
.key("velocity.command.plugins-list")
|
||||
.color(NamedTextColor.YELLOW)
|
||||
.arguments(listBuilder.build())
|
||||
.arguments(pluginListComponents)
|
||||
.build();
|
||||
source.sendMessage(output);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
|
||||
@@ -420,7 +420,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ClientboundStoreCookiePacket packet) {
|
||||
server.getEventManager()
|
||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.getKey(), packet.getPayload()))
|
||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.key(), packet.payload()))
|
||||
.thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
final Key resultedKey = event.getResult().getKey() == null
|
||||
|
||||
@@ -328,7 +328,7 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ClientboundStoreCookiePacket packet) {
|
||||
server.getEventManager()
|
||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.getKey(), packet.getPayload()))
|
||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.key(), packet.payload()))
|
||||
.thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
final Key resultedKey = event.getResult().getKey() == null
|
||||
|
||||
@@ -157,7 +157,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
if (smc.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture));
|
||||
} else {
|
||||
smc.write(new LoginAcknowledgedPacket());
|
||||
smc.write(LoginAcknowledgedPacket.INSTANCE);
|
||||
smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture));
|
||||
ConnectedPlayer player = serverConn.getPlayer();
|
||||
if (player.getClientSettingsPacket() != null) {
|
||||
|
||||
@@ -170,26 +170,26 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
||||
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
||||
.getHostString();
|
||||
|
||||
HandshakePacket handshake = new HandshakePacket();
|
||||
handshake.setIntent(HandshakeIntent.LOGIN);
|
||||
handshake.setProtocolVersion(protocolVersion);
|
||||
String serverAddress;
|
||||
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
|
||||
handshake.setServerAddress(createLegacyForwardingAddress());
|
||||
serverAddress = createLegacyForwardingAddress();
|
||||
} else if (forwardingMode == PlayerInfoForwarding.BUNGEEGUARD) {
|
||||
byte[] secret = server.getConfiguration().getForwardingSecret();
|
||||
handshake.setServerAddress(createBungeeGuardForwardingAddress(secret));
|
||||
serverAddress = createBungeeGuardForwardingAddress(secret);
|
||||
} else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
|
||||
handshake.setServerAddress(playerVhost + HANDSHAKE_HOSTNAME_TOKEN);
|
||||
serverAddress = playerVhost + HANDSHAKE_HOSTNAME_TOKEN;
|
||||
} else if (proxyPlayer.getConnection().getType() instanceof ModernForgeConnectionType) {
|
||||
handshake.setServerAddress(playerVhost + ((ModernForgeConnectionType) proxyPlayer
|
||||
.getConnection().getType()).getModernToken());
|
||||
serverAddress = playerVhost + ((ModernForgeConnectionType) proxyPlayer
|
||||
.getConnection().getType()).getModernToken();
|
||||
} else {
|
||||
handshake.setServerAddress(playerVhost);
|
||||
serverAddress = playerVhost;
|
||||
}
|
||||
|
||||
handshake.setPort(proxyPlayer.getVirtualHost()
|
||||
int port = proxyPlayer.getVirtualHost()
|
||||
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
||||
.getPort());
|
||||
.getPort();
|
||||
|
||||
HandshakePacket handshake = new HandshakePacket(protocolVersion, serverAddress, port, HandshakeIntent.LOGIN);
|
||||
mc.delayedWrite(handshake);
|
||||
|
||||
mc.setProtocolVersion(protocolVersion);
|
||||
|
||||
@@ -230,10 +230,9 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerLoginSuccessPacket success = new ServerLoginSuccessPacket();
|
||||
success.setUsername(player.getUsername());
|
||||
success.setProperties(player.getGameProfileProperties());
|
||||
success.setUuid(player.getUniqueId());
|
||||
ServerLoginSuccessPacket success = new ServerLoginSuccessPacket(
|
||||
player.getUniqueId(), player.getUsername(), player.getGameProfileProperties()
|
||||
);
|
||||
mcConnection.write(success);
|
||||
|
||||
loginState = State.SUCCESS_SENT;
|
||||
|
||||
@@ -387,8 +387,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
public boolean handle(ResourcePackResponsePacket packet) {
|
||||
return player.resourcePackHandler().onResourcePackResponse(
|
||||
new ResourcePackResponseBundle(packet.getId(),
|
||||
packet.getHash(),
|
||||
packet.getStatus()));
|
||||
packet.hash(),
|
||||
packet.status()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,7 +428,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
@Override
|
||||
public boolean handle(ServerboundCookieResponsePacket packet) {
|
||||
server.getEventManager()
|
||||
.fire(new CookieReceiveEvent(player, packet.getKey(), packet.getPayload()))
|
||||
.fire(new CookieReceiveEvent(player, packet.key(), packet.payload()))
|
||||
.thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
final VelocityServerConnection serverConnection = player.getConnectedServer();
|
||||
@@ -586,10 +586,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// Remove previous boss bars. These don't get cleared when sending JoinGame (up until 1.20.2),
|
||||
// thus the need to track them.
|
||||
for (UUID serverBossBar : serverBossBars) {
|
||||
BossBarPacket deletePacket = new BossBarPacket();
|
||||
deletePacket.setUuid(serverBossBar);
|
||||
deletePacket.setAction(BossBarPacket.REMOVE);
|
||||
player.getConnection().delayedWrite(deletePacket);
|
||||
player.getConnection().delayedWrite(BossBarPacket.createRemovePacket(serverBossBar));
|
||||
}
|
||||
serverBossBars.clear();
|
||||
}
|
||||
@@ -615,7 +612,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// Clear any title from the previous server.
|
||||
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
player.getConnection().delayedWrite(
|
||||
GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET,
|
||||
GenericTitlePacket.createClearTitlePacket(GenericTitlePacket.ActionType.RESET,
|
||||
player.getProtocolVersion()));
|
||||
}
|
||||
|
||||
@@ -634,14 +631,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
// Most notably, by having the client accept the join game packet, we can work around the need
|
||||
// to perform entity ID rewrites, eliminating potential issues from rewriting packets and
|
||||
// improving compatibility with mods.
|
||||
final RespawnPacket respawn = RespawnPacket.fromJoinGame(joinGame);
|
||||
|
||||
int dim = joinGame.getDimension();
|
||||
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
// Before Minecraft 1.16, we could not switch to the same dimension without sending an
|
||||
// additional respawn. On older versions of Minecraft this forces the client to perform
|
||||
// garbage collection which adds additional latency.
|
||||
joinGame.setDimension(joinGame.getDimension() == 0 ? -1 : 0);
|
||||
dim = joinGame.getDimension() == 0 ? -1 : 0;
|
||||
}
|
||||
final RespawnPacket respawn = RespawnPacket.fromJoinGame(joinGame, dim);
|
||||
|
||||
player.getConnection().delayedWrite(joinGame);
|
||||
player.getConnection().delayedWrite(respawn);
|
||||
}
|
||||
@@ -655,8 +653,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
player.getConnection().delayedWrite(joinGame);
|
||||
|
||||
// Send a respawn packet in a different dimension.
|
||||
final RespawnPacket fakeSwitchPacket = RespawnPacket.fromJoinGame(joinGame);
|
||||
fakeSwitchPacket.setDimension(joinGame.getDimension() == 0 ? -1 : 0);
|
||||
final RespawnPacket fakeSwitchPacket = RespawnPacket.fromJoinGame(joinGame, joinGame.getDimension() == 0 ? -1 : 0);
|
||||
player.getConnection().delayedWrite(fakeSwitchPacket);
|
||||
|
||||
// Now send a respawn packet in the correct dimension.
|
||||
@@ -728,11 +725,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
offers.add(new Offer(offer, tooltip));
|
||||
}
|
||||
|
||||
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
|
||||
resp.setTransactionId(packet.getTransactionId());
|
||||
resp.setStart(startPos + 1);
|
||||
resp.setLength(packet.getCommand().length() - startPos - 1);
|
||||
resp.getOffers().addAll(offers);
|
||||
TabCompleteResponsePacket resp = new TabCompleteResponsePacket(
|
||||
packet.transactionId(), startPos + 1, packet.getCommand().length() - startPos - 1, offers
|
||||
);
|
||||
player.getConnection().write(resp);
|
||||
}
|
||||
}, player.getConnection().eventLoop()).exceptionally((ex) -> {
|
||||
@@ -778,6 +773,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
.thenAcceptAsync(offers -> {
|
||||
boolean legacy =
|
||||
player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13);
|
||||
List<Offer> extendedOffers = new ArrayList<>(response.offers());
|
||||
try {
|
||||
for (Suggestion suggestion : offers.getList()) {
|
||||
String offer = suggestion.getText();
|
||||
@@ -791,10 +787,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
} else if (suggestion.getTooltip() != null) {
|
||||
tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
|
||||
}
|
||||
response.getOffers().add(new Offer(offer, tooltip));
|
||||
extendedOffers.add(new Offer(offer, tooltip));
|
||||
}
|
||||
response.getOffers().sort(null);
|
||||
player.getConnection().write(response);
|
||||
extendedOffers.sort(null);
|
||||
player.getConnection().write(response.withOffers(extendedOffers));
|
||||
} catch (Exception e) {
|
||||
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
||||
player.getUsername(), command,
|
||||
@@ -811,17 +807,17 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
private void finishRegularTabComplete(TabCompleteRequestPacket request,
|
||||
TabCompleteResponsePacket response) {
|
||||
List<String> offers = new ArrayList<>();
|
||||
for (Offer offer : response.getOffers()) {
|
||||
offers.add(offer.getText());
|
||||
List<String> textOffers = new ArrayList<>();
|
||||
for (Offer offer : response.offers()) {
|
||||
textOffers.add(offer.getText());
|
||||
}
|
||||
server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers))
|
||||
server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), textOffers))
|
||||
.thenAcceptAsync(e -> {
|
||||
response.getOffers().clear();
|
||||
List<Offer> newOffers = new ArrayList<>();
|
||||
for (String s : e.getSuggestions()) {
|
||||
response.getOffers().add(new Offer(s));
|
||||
newOffers.add(new Offer(s));
|
||||
}
|
||||
player.getConnection().write(response);
|
||||
player.getConnection().write(response.withOffers(newOffers));
|
||||
}, player.getConnection().eventLoop()).exceptionally((ex) -> {
|
||||
logger.error(
|
||||
"Exception while finishing regular tab completion,"
|
||||
|
||||
@@ -38,25 +38,25 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
||||
|
||||
ClientSettingsWrapper(ClientSettingsPacket settings) {
|
||||
this.settings = settings;
|
||||
this.parts = new SkinParts((byte) settings.getSkinParts());
|
||||
this.parts = new SkinParts((byte) settings.skinParts());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
if (locale == null) {
|
||||
locale = Locale.forLanguageTag(settings.getLocale().replaceAll("_", "-"));
|
||||
locale = Locale.forLanguageTag(settings.locale().replaceAll("_", "-"));
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getViewDistance() {
|
||||
return settings.getViewDistance();
|
||||
return settings.viewDistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatMode getChatMode() {
|
||||
return switch (settings.getChatVisibility()) {
|
||||
return switch (settings.chatVisibility()) {
|
||||
case 1 -> ChatMode.COMMANDS_ONLY;
|
||||
case 2 -> ChatMode.HIDDEN;
|
||||
default -> ChatMode.SHOWN;
|
||||
@@ -65,7 +65,7 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
||||
|
||||
@Override
|
||||
public boolean hasChatColors() {
|
||||
return settings.isChatColors();
|
||||
return settings.chatColors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,22 +75,22 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
||||
|
||||
@Override
|
||||
public MainHand getMainHand() {
|
||||
return settings.getMainHand() == 1 ? MainHand.RIGHT : MainHand.LEFT;
|
||||
return settings.mainHand() == 1 ? MainHand.RIGHT : MainHand.LEFT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClientListingAllowed() {
|
||||
return settings.isClientListingAllowed();
|
||||
return settings.clientListingAllowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTextFilteringEnabled() {
|
||||
return settings.isTextFilteringEnabled();
|
||||
return settings.textFilteringEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParticleStatus getParticleStatus() {
|
||||
return switch (settings.getParticleStatus()) {
|
||||
return switch (settings.particleStatus()) {
|
||||
case 1 -> ParticleStatus.DECREASED;
|
||||
case 2 -> ParticleStatus.MINIMAL;
|
||||
default -> ParticleStatus.ALL;
|
||||
|
||||
@@ -451,9 +451,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
ProtocolVersion playerVersion = getProtocolVersion();
|
||||
if (playerVersion.noLessThan(ProtocolVersion.MINECRAFT_1_11)) {
|
||||
// Use the title packet instead.
|
||||
GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion);
|
||||
pkt.setComponent(new ComponentHolder(playerVersion, translated));
|
||||
GenericTitlePacket pkt = GenericTitlePacket.createComponentTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_ACTION_BAR,
|
||||
new ComponentHolder(playerVersion, translated), playerVersion);
|
||||
connection.write(pkt);
|
||||
} else {
|
||||
// Due to issues with action bar packets, we'll need to convert the text message into a
|
||||
@@ -461,9 +461,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("text", LegacyComponentSerializer.legacySection()
|
||||
.serialize(translated));
|
||||
LegacyChatPacket legacyChat = new LegacyChatPacket();
|
||||
legacyChat.setMessage(object.toString());
|
||||
legacyChat.setType(LegacyChatPacket.GAME_INFO_TYPE);
|
||||
LegacyChatPacket legacyChat = new LegacyChatPacket(object.toString(), LegacyChatPacket.GAME_INFO_TYPE, null);
|
||||
connection.write(legacyChat);
|
||||
}
|
||||
}
|
||||
@@ -504,26 +502,26 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
@Override
|
||||
public void showTitle(net.kyori.adventure.title.@NonNull Title title) {
|
||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion());
|
||||
net.kyori.adventure.title.Title.Times times = title.times();
|
||||
if (times != null) {
|
||||
timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn()));
|
||||
timesPkt.setStay((int) DurationUtils.toTicks(times.stay()));
|
||||
timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut()));
|
||||
GenericTitlePacket timesPkt = GenericTitlePacket.createTimesTitlePacket(
|
||||
(int) DurationUtils.toTicks(times.fadeIn()),
|
||||
(int) DurationUtils.toTicks(times.stay()),
|
||||
(int) DurationUtils.toTicks(times.fadeOut()),
|
||||
this.getProtocolVersion());
|
||||
connection.delayedWrite(timesPkt);
|
||||
}
|
||||
connection.delayedWrite(timesPkt);
|
||||
|
||||
GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion());
|
||||
subtitlePkt.setComponent(new ComponentHolder(
|
||||
this.getProtocolVersion(), translateMessage(title.subtitle())));
|
||||
GenericTitlePacket subtitlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_SUBTITLE,
|
||||
new ComponentHolder(this.getProtocolVersion(), translateMessage(title.subtitle())),
|
||||
this.getProtocolVersion());
|
||||
connection.delayedWrite(subtitlePkt);
|
||||
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion());
|
||||
titlePkt.setComponent(new ComponentHolder(
|
||||
this.getProtocolVersion(), translateMessage(title.title())));
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TITLE,
|
||||
new ComponentHolder(this.getProtocolVersion(), translateMessage(title.title())),
|
||||
this.getProtocolVersion());
|
||||
connection.delayedWrite(titlePkt);
|
||||
|
||||
connection.flush();
|
||||
@@ -545,24 +543,24 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
}
|
||||
|
||||
if (part == TitlePart.TITLE) {
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion());
|
||||
titlePkt.setComponent(new ComponentHolder(
|
||||
this.getProtocolVersion(), translateMessage((Component) value)));
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TITLE,
|
||||
new ComponentHolder(this.getProtocolVersion(), translateMessage((Component) value)),
|
||||
this.getProtocolVersion());
|
||||
connection.write(titlePkt);
|
||||
} else if (part == TitlePart.SUBTITLE) {
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion());
|
||||
titlePkt.setComponent(new ComponentHolder(
|
||||
this.getProtocolVersion(), translateMessage((Component) value)));
|
||||
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_SUBTITLE,
|
||||
new ComponentHolder(this.getProtocolVersion(), translateMessage((Component) value)),
|
||||
this.getProtocolVersion());
|
||||
connection.write(titlePkt);
|
||||
} else if (part == TitlePart.TIMES) {
|
||||
Times times = (Times) value;
|
||||
GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket(
|
||||
GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion());
|
||||
timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn()));
|
||||
timesPkt.setStay((int) DurationUtils.toTicks(times.stay()));
|
||||
timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut()));
|
||||
GenericTitlePacket timesPkt = GenericTitlePacket.createTimesTitlePacket(
|
||||
(int) DurationUtils.toTicks(times.fadeIn()),
|
||||
(int) DurationUtils.toTicks(times.stay()),
|
||||
(int) DurationUtils.toTicks(times.fadeOut()),
|
||||
this.getProtocolVersion());
|
||||
connection.write(timesPkt);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Title part " + part + " is not valid");
|
||||
@@ -572,7 +570,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
@Override
|
||||
public void clearTitle() {
|
||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
connection.write(GenericTitlePacket.constructTitlePacket(
|
||||
connection.write(GenericTitlePacket.createClearTitlePacket(
|
||||
GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion()));
|
||||
}
|
||||
}
|
||||
@@ -580,7 +578,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
@Override
|
||||
public void resetTitle() {
|
||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
connection.write(GenericTitlePacket.constructTitlePacket(
|
||||
connection.write(GenericTitlePacket.createClearTitlePacket(
|
||||
GenericTitlePacket.ActionType.RESET, this.getProtocolVersion()));
|
||||
}
|
||||
}
|
||||
@@ -1262,7 +1260,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
@Override
|
||||
public void clearResourcePacks() {
|
||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
connection.write(new RemoveResourcePackPacket());
|
||||
connection.write(new RemoveResourcePackPacket(null));
|
||||
this.resourcePackHandler.clearAppliedResourcePacks();
|
||||
}
|
||||
}
|
||||
@@ -1333,8 +1331,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
public void sendKeepAlive() {
|
||||
if (connection.getState() == StateRegistry.PLAY
|
||||
|| connection.getState() == StateRegistry.CONFIG) {
|
||||
KeepAlivePacket keepAlive = new KeepAlivePacket();
|
||||
keepAlive.setRandomId(ThreadLocalRandom.current().nextLong());
|
||||
KeepAlivePacket keepAlive = new KeepAlivePacket(ThreadLocalRandom.current().nextLong());
|
||||
connection.write(keepAlive);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,19 +87,19 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(final HandshakePacket handshake) {
|
||||
final StateRegistry nextState = getStateForProtocol(handshake.getNextStatus());
|
||||
final StateRegistry nextState = getStateForProtocol(handshake.nextStatus());
|
||||
if (nextState == null) {
|
||||
LOGGER.error("{} provided invalid protocol {}", this, handshake.getNextStatus());
|
||||
LOGGER.error("{} provided invalid protocol {}", this, handshake.nextStatus());
|
||||
connection.close(true);
|
||||
} else {
|
||||
final InitialInboundConnection ic = new InitialInboundConnection(connection,
|
||||
cleanVhost(handshake.getServerAddress()), handshake);
|
||||
if (handshake.getIntent() == HandshakeIntent.TRANSFER
|
||||
cleanVhost(handshake.serverAddress()), handshake);
|
||||
if (handshake.intent() == HandshakeIntent.TRANSFER
|
||||
&& !server.getConfiguration().isAcceptTransfers()) {
|
||||
ic.disconnect(Component.translatable("multiplayer.disconnect.transfers_disabled"));
|
||||
return true;
|
||||
}
|
||||
connection.setProtocolVersion(handshake.getProtocolVersion());
|
||||
connection.setProtocolVersion(handshake.protocolVersion());
|
||||
connection.setAssociation(ic);
|
||||
|
||||
switch (nextState) {
|
||||
@@ -124,7 +124,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
}
|
||||
|
||||
private void handleLogin(HandshakePacket handshake, InitialInboundConnection ic) {
|
||||
if (!handshake.getProtocolVersion().isSupported()) {
|
||||
if (!handshake.protocolVersion().isSupported()) {
|
||||
// Bump connection into correct protocol state so that we can send the disconnect packet.
|
||||
connection.setState(StateRegistry.LOGIN);
|
||||
ic.disconnectQuietly(Component.translatable()
|
||||
@@ -147,7 +147,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
// If the proxy is configured for modern forwarding, we must deny connections from 1.12.2
|
||||
// and lower, otherwise IP information will never get forwarded.
|
||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
||||
&& handshake.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
&& handshake.protocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
// Bump connection into correct protocol state so that we can send the disconnect packet.
|
||||
connection.setState(StateRegistry.LOGIN);
|
||||
ic.disconnectQuietly(
|
||||
@@ -157,21 +157,23 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
final LoginInboundConnection lic = new LoginInboundConnection(ic);
|
||||
server.getEventManager().fireAndForget(
|
||||
new ConnectionHandshakeEvent(lic, handshake.getIntent()));
|
||||
new ConnectionHandshakeEvent(lic, handshake.intent()));
|
||||
connection.setActiveSessionHandler(StateRegistry.LOGIN,
|
||||
new InitialLoginSessionHandler(server, connection, lic));
|
||||
}
|
||||
|
||||
private ConnectionType getHandshakeConnectionType(HandshakePacket handshake) {
|
||||
if (handshake.getServerAddress().contains(ModernForgeConstants.MODERN_FORGE_TOKEN)
|
||||
&& handshake.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
return new ModernForgeConnectionType(handshake.getServerAddress());
|
||||
final String serverAddress = handshake.serverAddress();
|
||||
final ProtocolVersion protocolVersion = handshake.protocolVersion();
|
||||
if (serverAddress.contains(ModernForgeConstants.MODERN_FORGE_TOKEN)
|
||||
&& protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
return new ModernForgeConnectionType(serverAddress);
|
||||
}
|
||||
// Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13).
|
||||
if (handshake.getServerAddress().endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN)
|
||||
&& handshake.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
if (serverAddress.endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN)
|
||||
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
return ConnectionTypes.LEGACY_FORGE;
|
||||
} else if (handshake.getProtocolVersion().noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
} else if (protocolVersion.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
// 1.7 Forge will not notify us during handshake. UNDETERMINED will listen for incoming
|
||||
// forge handshake attempts. Also sends a reset handshake packet on every transition.
|
||||
return ConnectionTypes.UNDETERMINED_17;
|
||||
|
||||
@@ -91,7 +91,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
||||
public boolean handle(ServerLoginPacket packet) {
|
||||
assertState(LoginState.LOGIN_PACKET_EXPECTED);
|
||||
this.currentState = LoginState.LOGIN_PACKET_RECEIVED;
|
||||
IdentifiedKey playerKey = packet.getPlayerKey();
|
||||
IdentifiedKey playerKey = packet.playerKey();
|
||||
if (playerKey != null) {
|
||||
if (playerKey.hasExpired()) {
|
||||
inbound.disconnect(
|
||||
@@ -102,7 +102,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
||||
boolean isKeyValid;
|
||||
if (playerKey.getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
|
||||
&& playerKey instanceof final IdentifiedKeyImpl keyImpl) {
|
||||
isKeyValid = keyImpl.internalAddHolder(packet.getHolderUuid());
|
||||
isKeyValid = keyImpl.internalAddHolder(packet.holderUuid());
|
||||
} else {
|
||||
isKeyValid = playerKey.isSignatureValid();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
||||
inbound.setPlayerKey(playerKey);
|
||||
this.login = packet;
|
||||
|
||||
final PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername(), login.getHolderUuid());
|
||||
final PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername(), login.holderUuid());
|
||||
server.getEventManager().fire(event).thenRunAsync(() -> {
|
||||
if (mcConnection.isClosed()) {
|
||||
// The player was disconnected
|
||||
@@ -289,9 +289,8 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
||||
byte[] verify = new byte[4];
|
||||
ThreadLocalRandom.current().nextBytes(verify);
|
||||
|
||||
EncryptionRequestPacket request = new EncryptionRequestPacket();
|
||||
request.setPublicKey(server.getServerKeyPair().getPublic().getEncoded());
|
||||
request.setVerifyToken(verify);
|
||||
EncryptionRequestPacket request = new EncryptionRequestPacket("",
|
||||
server.getServerKeyPair().getPublic().getEncoded(), verify, true);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@ class LegacyForgeUtil {
|
||||
* @return A copy of the reset packet
|
||||
*/
|
||||
static PluginMessagePacket resetPacket() {
|
||||
PluginMessagePacket msg = new PluginMessagePacket();
|
||||
msg.setChannel(FORGE_LEGACY_HANDSHAKE_CHANNEL);
|
||||
msg.replace(Unpooled.wrappedBuffer(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone()));
|
||||
return msg;
|
||||
return new PluginMessagePacket(
|
||||
FORGE_LEGACY_HANDSHAKE_CHANNEL,
|
||||
Unpooled.wrappedBuffer(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,17 +101,15 @@ public abstract sealed class ResourcePackHandler
|
||||
}
|
||||
|
||||
protected void sendResourcePackRequestPacket(final @NotNull ResourcePackInfo queued) {
|
||||
final ResourcePackRequestPacket request = new ResourcePackRequestPacket();
|
||||
request.setId(queued.getId());
|
||||
request.setUrl(queued.getUrl());
|
||||
if (queued.getHash() != null) {
|
||||
request.setHash(ByteBufUtil.hexDump(queued.getHash()));
|
||||
} else {
|
||||
request.setHash("");
|
||||
}
|
||||
request.setRequired(queued.getShouldForce());
|
||||
request.setPrompt(queued.getPrompt() == null ? null :
|
||||
new ComponentHolder(player.getProtocolVersion(), player.translateMessage(queued.getPrompt())));
|
||||
final String hash = queued.getHash() != null ? ByteBufUtil.hexDump(queued.getHash()) : "";
|
||||
final ComponentHolder prompt = queued.getPrompt() == null ? null :
|
||||
new ComponentHolder(player.getProtocolVersion(), player.translateMessage(queued.getPrompt()));
|
||||
final ResourcePackRequestPacket request = new ResourcePackRequestPacket(
|
||||
queued.getId(),
|
||||
queued.getUrl(),
|
||||
hash,
|
||||
queued.getShouldForce(),
|
||||
prompt);
|
||||
|
||||
player.getConnection().write(request);
|
||||
}
|
||||
|
||||
@@ -17,33 +17,23 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft packet.
|
||||
* Represents a Minecraft packet. Packets are immutable data holders that use separate
|
||||
* {@link PacketCodec} implementations for encoding and decoding.
|
||||
*
|
||||
* @see PacketCodec
|
||||
* @see PacketEncoder
|
||||
* @see PacketDecoder
|
||||
*/
|
||||
public interface MinecraftPacket {
|
||||
|
||||
void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
|
||||
|
||||
void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
|
||||
|
||||
/**
|
||||
* Handles this packet using the visitor pattern.
|
||||
*
|
||||
* @param handler the session handler
|
||||
* @return true if the packet was handled
|
||||
*/
|
||||
boolean handle(MinecraftSessionHandler handler);
|
||||
|
||||
default int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
default int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default int encodeSizeHint(ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2025 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.protocol;
|
||||
|
||||
/**
|
||||
* A combined codec that can both encode and decode packets.
|
||||
*
|
||||
* @param <T> the packet type
|
||||
*/
|
||||
public interface PacketCodec<T extends MinecraftPacket>
|
||||
extends PacketEncoder<T>, PacketDecoder<T> {
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2025 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.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* Decodes a packet from a ByteBuf.
|
||||
*
|
||||
* @param <T> the packet type
|
||||
*/
|
||||
public interface PacketDecoder<T extends MinecraftPacket> {
|
||||
|
||||
/**
|
||||
* Decodes a packet from the provided ByteBuf.
|
||||
*
|
||||
* @param buf the buffer to read from
|
||||
* @param direction the direction of the packet
|
||||
* @param protocolVersion the protocol version
|
||||
* @return the decoded packet instance
|
||||
*/
|
||||
T decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
|
||||
|
||||
/**
|
||||
* Returns the expected maximum length of the packet. This is used for validation during
|
||||
* decoding. Return -1 if no maximum is enforced.
|
||||
*
|
||||
* @param buf the buffer containing the packet
|
||||
* @param direction the direction of the packet
|
||||
* @param version the protocol version
|
||||
* @return the maximum expected length, or -1 if no limit
|
||||
*/
|
||||
default int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expected minimum length of the packet. This is used for validation during
|
||||
* decoding. Return 0 if no minimum is enforced.
|
||||
*
|
||||
* @param buf the buffer containing the packet
|
||||
* @param direction the direction of the packet
|
||||
* @param version the protocol version
|
||||
* @return the minimum expected length
|
||||
*/
|
||||
default int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2025 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.protocol;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* Encodes a packet into a ByteBuf.
|
||||
*
|
||||
* @param <T> the packet type
|
||||
*/
|
||||
public interface PacketEncoder<T extends MinecraftPacket> {
|
||||
|
||||
/**
|
||||
* Encodes the given packet into the provided ByteBuf.
|
||||
*
|
||||
* @param packet the packet to encode
|
||||
* @param buf the buffer to write to
|
||||
* @param direction the direction of the packet
|
||||
* @param protocolVersion the protocol version
|
||||
*/
|
||||
void encode(T packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion);
|
||||
|
||||
/**
|
||||
* Returns a hint for the expected size of the encoded packet. This is used to pre-allocate
|
||||
* buffers for better performance. Return -1 if no hint is available.
|
||||
*
|
||||
* @param packet the packet to encode
|
||||
* @param direction the direction of the packet
|
||||
* @param version the protocol version
|
||||
* @return the size hint, or -1 if unknown
|
||||
*/
|
||||
default int encodeSizeHint(T packet, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -128,9 +128,9 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
@@ -140,122 +140,122 @@ public enum StateRegistry {
|
||||
|
||||
HANDSHAKE {
|
||||
{
|
||||
serverbound.register(HandshakePacket.class, HandshakePacket::new,
|
||||
serverbound.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false));
|
||||
}
|
||||
},
|
||||
STATUS {
|
||||
{
|
||||
serverbound.register(
|
||||
StatusRequestPacket.class, () -> StatusRequestPacket.INSTANCE,
|
||||
StatusRequestPacket.class, new StatusRequestPacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false));
|
||||
serverbound.register(StatusPingPacket.class, StatusPingPacket::new,
|
||||
serverbound.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false));
|
||||
|
||||
clientbound.register(
|
||||
StatusResponsePacket.class, StatusResponsePacket::new,
|
||||
StatusResponsePacket.class, new StatusResponsePacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false));
|
||||
clientbound.register(StatusPingPacket.class, StatusPingPacket::new,
|
||||
clientbound.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false));
|
||||
}
|
||||
},
|
||||
CONFIG {
|
||||
{
|
||||
serverbound.register(
|
||||
ClientSettingsPacket.class, ClientSettingsPacket::new,
|
||||
ClientSettingsPacket.class, new ClientSettingsPacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_20_2, false));
|
||||
serverbound.register(
|
||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
||||
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(
|
||||
PluginMessagePacket.class, PluginMessagePacket::new,
|
||||
PluginMessagePacket.class, new PluginMessagePacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_20_2, false),
|
||||
map(0x02, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(
|
||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
||||
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||
map(0x02, MINECRAFT_1_20_2, false),
|
||||
map(0x03, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
serverbound.register(KeepAlivePacket.class, new KeepAlivePacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_20_2, false),
|
||||
map(0x04, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(
|
||||
PingIdentifyPacket.class, PingIdentifyPacket::new,
|
||||
PingIdentifyPacket.class, new PingIdentifyPacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_20_2, false),
|
||||
map(0x05, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(
|
||||
ResourcePackResponsePacket.class,
|
||||
ResourcePackResponsePacket::new,
|
||||
new ResourcePackResponsePacket.Codec(),
|
||||
map(0x05, MINECRAFT_1_20_2, false),
|
||||
map(0x06, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(
|
||||
KnownPacksPacket.class,
|
||||
KnownPacksPacket::new,
|
||||
new KnownPacksPacket.Codec(),
|
||||
map(0x07, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(ServerboundCustomClickActionPacket.class, ServerboundCustomClickActionPacket::new,
|
||||
serverbound.register(ServerboundCustomClickActionPacket.class, new ServerboundCustomClickActionPacket.Codec(),
|
||||
map(0x08, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
CodeOfConductAcceptPacket.class,
|
||||
() -> CodeOfConductAcceptPacket.INSTANCE,
|
||||
new CodeOfConductAcceptPacket.Codec(),
|
||||
map(0x09, MINECRAFT_1_21_9, false));
|
||||
|
||||
clientbound.register(
|
||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
||||
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
PluginMessagePacket.class, PluginMessagePacket::new,
|
||||
PluginMessagePacket.class, new PluginMessagePacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_20_2, false),
|
||||
map(0x01, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
DisconnectPacket.class, () -> new DisconnectPacket(this),
|
||||
DisconnectPacket.class, new DisconnectPacket.Codec(this),
|
||||
map(0x01, MINECRAFT_1_20_2, false),
|
||||
map(0x02, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
||||
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||
map(0x02, MINECRAFT_1_20_2, false),
|
||||
map(0x03, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
clientbound.register(KeepAlivePacket.class, new KeepAlivePacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_20_2, false),
|
||||
map(0x04, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
PingIdentifyPacket.class, PingIdentifyPacket::new,
|
||||
PingIdentifyPacket.class, new PingIdentifyPacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_20_2, false),
|
||||
map(0x05, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
RegistrySyncPacket.class, RegistrySyncPacket::new,
|
||||
RegistrySyncPacket.class, new RegistrySyncPacket.Codec(),
|
||||
map(0x05, MINECRAFT_1_20_2, false),
|
||||
map(0x07, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
RemoveResourcePackPacket.class, RemoveResourcePackPacket::new,
|
||||
RemoveResourcePackPacket.class, new RemoveResourcePackPacket.Codec(),
|
||||
map(0x06, MINECRAFT_1_20_3, false),
|
||||
map(0x08, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(ResourcePackRequestPacket.class, ResourcePackRequestPacket::new,
|
||||
clientbound.register(ResourcePackRequestPacket.class, new ResourcePackRequestPacket.Codec(),
|
||||
map(0x06, MINECRAFT_1_20_2, false),
|
||||
map(0x07, MINECRAFT_1_20_3, false),
|
||||
map(0x09, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(
|
||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
||||
ClientboundStoreCookiePacket.class, new ClientboundStoreCookiePacket.Codec(),
|
||||
map(0x0A, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(TransferPacket.class, TransferPacket::new,
|
||||
clientbound.register(TransferPacket.class, new TransferPacket.Codec(),
|
||||
map(0x0B, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(ActiveFeaturesPacket.class, ActiveFeaturesPacket::new,
|
||||
clientbound.register(ActiveFeaturesPacket.class, new ActiveFeaturesPacket.Codec(),
|
||||
map(0x07, MINECRAFT_1_20_2, false),
|
||||
map(0x08, MINECRAFT_1_20_3, false),
|
||||
map(0x0C, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(TagsUpdatePacket.class, TagsUpdatePacket::new,
|
||||
clientbound.register(TagsUpdatePacket.class, new TagsUpdatePacket.Codec(),
|
||||
map(0x08, MINECRAFT_1_20_2, false),
|
||||
map(0x09, MINECRAFT_1_20_3, false),
|
||||
map(0x0D, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(KnownPacksPacket.class, KnownPacksPacket::new,
|
||||
clientbound.register(KnownPacksPacket.class, new KnownPacksPacket.Codec(),
|
||||
map(0x0E, MINECRAFT_1_20_5, false));
|
||||
clientbound.register(ClientboundCustomReportDetailsPacket.class, ClientboundCustomReportDetailsPacket::new,
|
||||
clientbound.register(ClientboundCustomReportDetailsPacket.class, new ClientboundCustomReportDetailsPacket.Codec(),
|
||||
map(0x0F, MINECRAFT_1_21, false));
|
||||
clientbound.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket::new,
|
||||
clientbound.register(ClientboundServerLinksPacket.class, new ClientboundServerLinksPacket.Codec(),
|
||||
map(0x10, MINECRAFT_1_21, false));
|
||||
clientbound.register(DialogClearPacket.class, () -> DialogClearPacket.INSTANCE,
|
||||
clientbound.register(DialogClearPacket.class, new DialogClearPacket.Codec(),
|
||||
map(0x11, MINECRAFT_1_21_6, false));
|
||||
clientbound.register(DialogShowPacket.class, () -> new DialogShowPacket(this),
|
||||
clientbound.register(DialogShowPacket.class, new DialogShowPacket.Codec(this),
|
||||
map(0x12, MINECRAFT_1_21_6, false));
|
||||
clientbound.register(CodeOfConductPacket.class, CodeOfConductPacket::new,
|
||||
clientbound.register(CodeOfConductPacket.class, new CodeOfConductPacket.Codec(),
|
||||
map(0x13, MINECRAFT_1_21_9, false));
|
||||
}
|
||||
},
|
||||
@@ -264,7 +264,7 @@ public enum StateRegistry {
|
||||
serverbound.fallback = false;
|
||||
clientbound.fallback = false;
|
||||
|
||||
serverbound.register(TabCompleteRequestPacket.class, TabCompleteRequestPacket::new,
|
||||
serverbound.register(TabCompleteRequestPacket.class, new TabCompleteRequestPacket.Codec(),
|
||||
map(0x14, MINECRAFT_1_7_2, false),
|
||||
map(0x01, MINECRAFT_1_9, false),
|
||||
map(0x02, MINECRAFT_1_12, false),
|
||||
@@ -281,7 +281,7 @@ public enum StateRegistry {
|
||||
map(0x0E, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
LegacyChatPacket.class,
|
||||
LegacyChatPacket::new,
|
||||
new LegacyChatPacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false),
|
||||
map(0x02, MINECRAFT_1_9, false),
|
||||
map(0x03, MINECRAFT_1_12, false),
|
||||
@@ -289,35 +289,35 @@ public enum StateRegistry {
|
||||
map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false));
|
||||
serverbound.register(
|
||||
ChatAcknowledgementPacket.class,
|
||||
ChatAcknowledgementPacket::new,
|
||||
new ChatAcknowledgementPacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_19_3, false),
|
||||
map(0x04, MINECRAFT_1_21_2, false),
|
||||
map(0x05, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(KeyedPlayerCommandPacket.class, KeyedPlayerCommandPacket::new,
|
||||
serverbound.register(KeyedPlayerCommandPacket.class, new KeyedPlayerCommandPacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_19, false),
|
||||
map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false));
|
||||
serverbound.register(KeyedPlayerChatPacket.class, KeyedPlayerChatPacket::new,
|
||||
serverbound.register(KeyedPlayerChatPacket.class, new KeyedPlayerChatPacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_19, false),
|
||||
map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false));
|
||||
serverbound.register(SessionPlayerCommandPacket.class, SessionPlayerCommandPacket::new,
|
||||
serverbound.register(SessionPlayerCommandPacket.class, new SessionPlayerCommandPacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_19_3, false),
|
||||
map(0x05, MINECRAFT_1_20_5, false),
|
||||
map(0x06, MINECRAFT_1_21_2, false),
|
||||
map(0x07, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(UnsignedPlayerCommandPacket.class, UnsignedPlayerCommandPacket::new,
|
||||
serverbound.register(UnsignedPlayerCommandPacket.class, new UnsignedPlayerCommandPacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_20_5, false),
|
||||
map(0x05, MINECRAFT_1_21_2, false),
|
||||
map(0x06, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
SessionPlayerChatPacket.class,
|
||||
SessionPlayerChatPacket::new,
|
||||
new SessionPlayerChatPacket.Codec(),
|
||||
map(0x05, MINECRAFT_1_19_3, false),
|
||||
map(0x06, MINECRAFT_1_20_5, false),
|
||||
map(0x07, MINECRAFT_1_21_2, false),
|
||||
map(0x08, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
ClientSettingsPacket.class,
|
||||
ClientSettingsPacket::new,
|
||||
new ClientSettingsPacket.Codec(),
|
||||
map(0x15, MINECRAFT_1_7_2, false),
|
||||
map(0x04, MINECRAFT_1_9, false),
|
||||
map(0x05, MINECRAFT_1_12, false),
|
||||
@@ -332,13 +332,13 @@ public enum StateRegistry {
|
||||
map(0x0C, MINECRAFT_1_21_2, false),
|
||||
map(0x0D, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
||||
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||
map(0x11, MINECRAFT_1_20_5, false),
|
||||
map(0x13, MINECRAFT_1_21_2, false),
|
||||
map(0x14, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
PluginMessagePacket.class,
|
||||
PluginMessagePacket::new,
|
||||
new PluginMessagePacket.Codec(),
|
||||
map(0x17, MINECRAFT_1_7_2, false),
|
||||
map(0x09, MINECRAFT_1_9, false),
|
||||
map(0x0A, MINECRAFT_1_12, false),
|
||||
@@ -357,7 +357,7 @@ public enum StateRegistry {
|
||||
map(0x15, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
KeepAlivePacket.class,
|
||||
KeepAlivePacket::new,
|
||||
new KeepAlivePacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false),
|
||||
map(0x0B, MINECRAFT_1_9, false),
|
||||
map(0x0C, MINECRAFT_1_12, false),
|
||||
@@ -377,7 +377,7 @@ public enum StateRegistry {
|
||||
map(0x1B, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
ResourcePackResponsePacket.class,
|
||||
ResourcePackResponsePacket::new,
|
||||
new ResourcePackResponsePacket.Codec(),
|
||||
map(0x19, MINECRAFT_1_8, false),
|
||||
map(0x16, MINECRAFT_1_9, false),
|
||||
map(0x18, MINECRAFT_1_12, false),
|
||||
@@ -394,7 +394,7 @@ public enum StateRegistry {
|
||||
map(0x2F, MINECRAFT_1_21_4, false),
|
||||
map(0x30, MINECRAFT_1_21_6, false));
|
||||
serverbound.register(
|
||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
||||
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||
map(0x0B, MINECRAFT_1_20_2, false),
|
||||
map(0x0C, MINECRAFT_1_20_5, false),
|
||||
map(0x0E, MINECRAFT_1_21_2, false),
|
||||
@@ -402,7 +402,7 @@ public enum StateRegistry {
|
||||
|
||||
clientbound.register(
|
||||
BossBarPacket.class,
|
||||
BossBarPacket::new,
|
||||
new BossBarPacket.Codec(),
|
||||
map(0x0C, MINECRAFT_1_9, false),
|
||||
map(0x0D, MINECRAFT_1_15, false),
|
||||
map(0x0C, MINECRAFT_1_16, false),
|
||||
@@ -413,14 +413,14 @@ public enum StateRegistry {
|
||||
map(0x09, MINECRAFT_1_21_5, false));
|
||||
clientbound.register(
|
||||
LegacyChatPacket.class,
|
||||
LegacyChatPacket::new,
|
||||
new LegacyChatPacket.Codec(),
|
||||
map(0x02, MINECRAFT_1_7_2, true),
|
||||
map(0x0F, MINECRAFT_1_9, true),
|
||||
map(0x0E, MINECRAFT_1_13, true),
|
||||
map(0x0F, MINECRAFT_1_15, true),
|
||||
map(0x0E, MINECRAFT_1_16, true),
|
||||
map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true));
|
||||
clientbound.register(TabCompleteResponsePacket.class, TabCompleteResponsePacket::new,
|
||||
clientbound.register(TabCompleteResponsePacket.class, new TabCompleteResponsePacket.Codec(),
|
||||
map(0x3A, MINECRAFT_1_7_2, false),
|
||||
map(0x0E, MINECRAFT_1_9, false),
|
||||
map(0x10, MINECRAFT_1_13, false),
|
||||
@@ -435,7 +435,7 @@ public enum StateRegistry {
|
||||
map(0x0F, MINECRAFT_1_21_5, false));
|
||||
clientbound.register(
|
||||
AvailableCommandsPacket.class,
|
||||
AvailableCommandsPacket::new,
|
||||
new AvailableCommandsPacket.Codec(),
|
||||
map(0x11, MINECRAFT_1_13, false),
|
||||
map(0x12, MINECRAFT_1_15, false),
|
||||
map(0x11, MINECRAFT_1_16, false),
|
||||
@@ -447,11 +447,11 @@ public enum StateRegistry {
|
||||
map(0x11, MINECRAFT_1_20_2, false),
|
||||
map(0x10, MINECRAFT_1_21_5, false));
|
||||
clientbound.register(
|
||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
||||
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||
map(0x16, MINECRAFT_1_20_5, false),
|
||||
map(0x15, MINECRAFT_1_21_5, false));
|
||||
clientbound.register(
|
||||
ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
|
||||
ClientboundSoundEntityPacket.class, new ClientboundSoundEntityPacket.Codec(),
|
||||
map(0x5D, MINECRAFT_1_19_3, true),
|
||||
map(0x61, MINECRAFT_1_19_4, true),
|
||||
map(0x63, MINECRAFT_1_20_2, true),
|
||||
@@ -461,7 +461,7 @@ public enum StateRegistry {
|
||||
map(0x6D, MINECRAFT_1_21_5, true),
|
||||
map(0x72, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
|
||||
ClientboundStopSoundPacket.class, new ClientboundStopSoundPacket.Codec(),
|
||||
map(0x5F, MINECRAFT_1_19_3, true),
|
||||
map(0x63, MINECRAFT_1_19_4, true),
|
||||
map(0x66, MINECRAFT_1_20_2, true),
|
||||
@@ -472,7 +472,7 @@ public enum StateRegistry {
|
||||
map(0x75, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
PluginMessagePacket.class,
|
||||
PluginMessagePacket::new,
|
||||
new PluginMessagePacket.Codec(),
|
||||
map(0x3F, MINECRAFT_1_7_2, false),
|
||||
map(0x18, MINECRAFT_1_9, false),
|
||||
map(0x19, MINECRAFT_1_13, false),
|
||||
@@ -490,7 +490,7 @@ public enum StateRegistry {
|
||||
map(0x18, MINECRAFT_1_21_5, false));
|
||||
clientbound.register(
|
||||
DisconnectPacket.class,
|
||||
() -> new DisconnectPacket(this),
|
||||
new DisconnectPacket.Codec(this),
|
||||
map(0x40, MINECRAFT_1_7_2, false),
|
||||
map(0x1A, MINECRAFT_1_9, false),
|
||||
map(0x1B, MINECRAFT_1_13, false),
|
||||
@@ -509,7 +509,7 @@ public enum StateRegistry {
|
||||
map(0x20, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
KeepAlivePacket.class,
|
||||
KeepAlivePacket::new,
|
||||
new KeepAlivePacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false),
|
||||
map(0x1F, MINECRAFT_1_9, false),
|
||||
map(0x21, MINECRAFT_1_13, false),
|
||||
@@ -529,7 +529,7 @@ public enum StateRegistry {
|
||||
map(0x2B, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
JoinGamePacket.class,
|
||||
JoinGamePacket::new,
|
||||
new JoinGamePacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false),
|
||||
map(0x23, MINECRAFT_1_9, false),
|
||||
map(0x25, MINECRAFT_1_13, false),
|
||||
@@ -549,7 +549,7 @@ public enum StateRegistry {
|
||||
map(0x30, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
RespawnPacket.class,
|
||||
RespawnPacket::new,
|
||||
new RespawnPacket.Codec(),
|
||||
map(0x07, MINECRAFT_1_7_2, true),
|
||||
map(0x33, MINECRAFT_1_9, true),
|
||||
map(0x34, MINECRAFT_1_12, true),
|
||||
@@ -572,7 +572,7 @@ public enum StateRegistry {
|
||||
map(0x50, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
RemoveResourcePackPacket.class,
|
||||
RemoveResourcePackPacket::new,
|
||||
new RemoveResourcePackPacket.Codec(),
|
||||
map(0x43, MINECRAFT_1_20_3, false),
|
||||
map(0x45, MINECRAFT_1_20_5, false),
|
||||
map(0x4A, MINECRAFT_1_21_2, false),
|
||||
@@ -580,7 +580,7 @@ public enum StateRegistry {
|
||||
map(0x4E, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
ResourcePackRequestPacket.class,
|
||||
ResourcePackRequestPacket::new,
|
||||
new ResourcePackRequestPacket.Codec(),
|
||||
map(0x48, MINECRAFT_1_8, false),
|
||||
map(0x32, MINECRAFT_1_9, false),
|
||||
map(0x33, MINECRAFT_1_12, false),
|
||||
@@ -603,7 +603,7 @@ public enum StateRegistry {
|
||||
map(0x4F, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
HeaderAndFooterPacket.class,
|
||||
HeaderAndFooterPacket::new,
|
||||
new HeaderAndFooterPacket.Codec(),
|
||||
map(0x47, MINECRAFT_1_8, true),
|
||||
map(0x48, MINECRAFT_1_9, true),
|
||||
map(0x47, MINECRAFT_1_9_4, true),
|
||||
@@ -627,7 +627,7 @@ public enum StateRegistry {
|
||||
map(0x78, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
LegacyTitlePacket.class,
|
||||
LegacyTitlePacket::new,
|
||||
new LegacyTitlePacket.Codec(),
|
||||
map(0x45, MINECRAFT_1_8, true),
|
||||
map(0x45, MINECRAFT_1_9, true),
|
||||
map(0x47, MINECRAFT_1_12, true),
|
||||
@@ -636,7 +636,7 @@ public enum StateRegistry {
|
||||
map(0x4F, MINECRAFT_1_14, true),
|
||||
map(0x50, MINECRAFT_1_15, true),
|
||||
map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true));
|
||||
clientbound.register(TitleSubtitlePacket.class, TitleSubtitlePacket::new,
|
||||
clientbound.register(TitleSubtitlePacket.class, new TitleSubtitlePacket.Codec(),
|
||||
map(0x57, MINECRAFT_1_17, true),
|
||||
map(0x58, MINECRAFT_1_18, true),
|
||||
map(0x5B, MINECRAFT_1_19_1, true),
|
||||
@@ -650,7 +650,7 @@ public enum StateRegistry {
|
||||
map(0x6E, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
TitleTextPacket.class,
|
||||
TitleTextPacket::new,
|
||||
new TitleTextPacket.Codec(),
|
||||
map(0x59, MINECRAFT_1_17, true),
|
||||
map(0x5A, MINECRAFT_1_18, true),
|
||||
map(0x5D, MINECRAFT_1_19_1, true),
|
||||
@@ -664,7 +664,7 @@ public enum StateRegistry {
|
||||
map(0x70, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
TitleActionbarPacket.class,
|
||||
TitleActionbarPacket::new,
|
||||
new TitleActionbarPacket.Codec(),
|
||||
map(0x41, MINECRAFT_1_17, true),
|
||||
map(0x40, MINECRAFT_1_19, true),
|
||||
map(0x43, MINECRAFT_1_19_1, true),
|
||||
@@ -678,7 +678,7 @@ public enum StateRegistry {
|
||||
map(0x55, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
TitleTimesPacket.class,
|
||||
TitleTimesPacket::new,
|
||||
new TitleTimesPacket.Codec(),
|
||||
map(0x5A, MINECRAFT_1_17, true),
|
||||
map(0x5B, MINECRAFT_1_18, true),
|
||||
map(0x5E, MINECRAFT_1_19_1, true),
|
||||
@@ -692,7 +692,7 @@ public enum StateRegistry {
|
||||
map(0x71, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
TitleClearPacket.class,
|
||||
TitleClearPacket::new,
|
||||
new TitleClearPacket.Codec(),
|
||||
map(0x10, MINECRAFT_1_17, true),
|
||||
map(0x0D, MINECRAFT_1_19, true),
|
||||
map(0x0C, MINECRAFT_1_19_3, true),
|
||||
@@ -701,7 +701,7 @@ public enum StateRegistry {
|
||||
map(0x0E, MINECRAFT_1_21_5, true));
|
||||
clientbound.register(
|
||||
LegacyPlayerListItemPacket.class,
|
||||
LegacyPlayerListItemPacket::new,
|
||||
new LegacyPlayerListItemPacket.Codec(),
|
||||
map(0x38, MINECRAFT_1_7_2, false),
|
||||
map(0x2D, MINECRAFT_1_9, false),
|
||||
map(0x2E, MINECRAFT_1_12_1, false),
|
||||
@@ -713,7 +713,7 @@ public enum StateRegistry {
|
||||
map(0x36, MINECRAFT_1_17, false),
|
||||
map(0x34, MINECRAFT_1_19, false),
|
||||
map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false));
|
||||
clientbound.register(RemovePlayerInfoPacket.class, RemovePlayerInfoPacket::new,
|
||||
clientbound.register(RemovePlayerInfoPacket.class, new RemovePlayerInfoPacket.Codec(),
|
||||
map(0x35, MINECRAFT_1_19_3, false),
|
||||
map(0x39, MINECRAFT_1_19_4, false),
|
||||
map(0x3B, MINECRAFT_1_20_2, false),
|
||||
@@ -723,7 +723,7 @@ public enum StateRegistry {
|
||||
map(0x43, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
UpsertPlayerInfoPacket.class,
|
||||
UpsertPlayerInfoPacket::new,
|
||||
new UpsertPlayerInfoPacket.Codec(),
|
||||
map(0x36, MINECRAFT_1_19_3, false),
|
||||
map(0x3A, MINECRAFT_1_19_4, false),
|
||||
map(0x3C, MINECRAFT_1_20_2, false),
|
||||
@@ -732,14 +732,14 @@ public enum StateRegistry {
|
||||
map(0x3F, MINECRAFT_1_21_5, false),
|
||||
map(0x44, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
||||
ClientboundStoreCookiePacket.class, new ClientboundStoreCookiePacket.Codec(),
|
||||
map(0x6B, MINECRAFT_1_20_5, false),
|
||||
map(0x72, MINECRAFT_1_21_2, false),
|
||||
map(0x71, MINECRAFT_1_21_5, false),
|
||||
map(0x76, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
SystemChatPacket.class,
|
||||
SystemChatPacket::new,
|
||||
new SystemChatPacket.Codec(),
|
||||
map(0x5F, MINECRAFT_1_19, true),
|
||||
map(0x62, MINECRAFT_1_19_1, true),
|
||||
map(0x60, MINECRAFT_1_19_3, true),
|
||||
@@ -752,7 +752,7 @@ public enum StateRegistry {
|
||||
map(0x77, MINECRAFT_1_21_9, true));
|
||||
clientbound.register(
|
||||
PlayerChatCompletionPacket.class,
|
||||
PlayerChatCompletionPacket::new,
|
||||
new PlayerChatCompletionPacket.Codec(),
|
||||
map(0x15, MINECRAFT_1_19_1, true),
|
||||
map(0x14, MINECRAFT_1_19_3, true),
|
||||
map(0x16, MINECRAFT_1_19_4, true),
|
||||
@@ -761,7 +761,7 @@ public enum StateRegistry {
|
||||
map(0x17, MINECRAFT_1_21_5, true));
|
||||
clientbound.register(
|
||||
ServerDataPacket.class,
|
||||
ServerDataPacket::new,
|
||||
new ServerDataPacket.Codec(),
|
||||
map(0x3F, MINECRAFT_1_19, false),
|
||||
map(0x42, MINECRAFT_1_19_1, false),
|
||||
map(0x41, MINECRAFT_1_19_3, false),
|
||||
@@ -774,7 +774,7 @@ public enum StateRegistry {
|
||||
map(0x54, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
StartUpdatePacket.class,
|
||||
() -> StartUpdatePacket.INSTANCE,
|
||||
new StartUpdatePacket.Codec(),
|
||||
map(0x65, MINECRAFT_1_20_2, false),
|
||||
map(0x67, MINECRAFT_1_20_3, false),
|
||||
map(0x69, MINECRAFT_1_20_5, false),
|
||||
@@ -783,23 +783,23 @@ public enum StateRegistry {
|
||||
map(0x74, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
BundleDelimiterPacket.class,
|
||||
() -> BundleDelimiterPacket.INSTANCE,
|
||||
new BundleDelimiterPacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_19_4, false));
|
||||
clientbound.register(
|
||||
TransferPacket.class,
|
||||
TransferPacket::new,
|
||||
new TransferPacket.Codec(),
|
||||
map(0x73, MINECRAFT_1_20_5, false),
|
||||
map(0x7A, MINECRAFT_1_21_2, false),
|
||||
map(0x7F, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
ClientboundCustomReportDetailsPacket.class,
|
||||
ClientboundCustomReportDetailsPacket::new,
|
||||
new ClientboundCustomReportDetailsPacket.Codec(),
|
||||
map(0x7A, MINECRAFT_1_21, false),
|
||||
map(0x81, MINECRAFT_1_21_2, false),
|
||||
map(0x86, MINECRAFT_1_21_9, false));
|
||||
clientbound.register(
|
||||
ClientboundServerLinksPacket.class,
|
||||
ClientboundServerLinksPacket::new,
|
||||
new ClientboundServerLinksPacket.Codec(),
|
||||
map(0x7B, MINECRAFT_1_21, false),
|
||||
map(0x82, MINECRAFT_1_21_2, false),
|
||||
map(0x87, MINECRAFT_1_21_9, false));
|
||||
@@ -808,39 +808,39 @@ public enum StateRegistry {
|
||||
LOGIN {
|
||||
{
|
||||
serverbound.register(ServerLoginPacket.class,
|
||||
ServerLoginPacket::new,
|
||||
new ServerLoginPacket.Codec(),
|
||||
map(0x00, MINECRAFT_1_7_2, false));
|
||||
serverbound.register(
|
||||
EncryptionResponsePacket.class, EncryptionResponsePacket::new,
|
||||
EncryptionResponsePacket.class, new EncryptionResponsePacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false));
|
||||
serverbound.register(
|
||||
LoginPluginResponsePacket.class, LoginPluginResponsePacket::new,
|
||||
LoginPluginResponsePacket.class, new LoginPluginResponsePacket.Codec(),
|
||||
map(0x02, MINECRAFT_1_13, false));
|
||||
serverbound.register(
|
||||
LoginAcknowledgedPacket.class, LoginAcknowledgedPacket::new,
|
||||
LoginAcknowledgedPacket.class, new LoginAcknowledgedPacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_20_2, false));
|
||||
serverbound.register(
|
||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
||||
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_20_5, false));
|
||||
|
||||
clientbound.register(
|
||||
DisconnectPacket.class, () -> new DisconnectPacket(this),
|
||||
DisconnectPacket.class, new DisconnectPacket.Codec(this),
|
||||
map(0x00, MINECRAFT_1_7_2, false));
|
||||
clientbound.register(
|
||||
EncryptionRequestPacket.class, EncryptionRequestPacket::new,
|
||||
EncryptionRequestPacket.class, new EncryptionRequestPacket.Codec(),
|
||||
map(0x01, MINECRAFT_1_7_2, false));
|
||||
clientbound.register(
|
||||
ServerLoginSuccessPacket.class, ServerLoginSuccessPacket::new,
|
||||
ServerLoginSuccessPacket.class, new ServerLoginSuccessPacket.Codec(),
|
||||
map(0x02, MINECRAFT_1_7_2, false));
|
||||
clientbound.register(
|
||||
SetCompressionPacket.class, SetCompressionPacket::new,
|
||||
SetCompressionPacket.class, new SetCompressionPacket.Codec(),
|
||||
map(0x03, MINECRAFT_1_8, false));
|
||||
clientbound.register(
|
||||
LoginPluginMessagePacket.class,
|
||||
LoginPluginMessagePacket::new,
|
||||
new LoginPluginMessagePacket.Codec(),
|
||||
map(0x04, MINECRAFT_1_13, false));
|
||||
clientbound.register(
|
||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
||||
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||
map(0x05, MINECRAFT_1_20_5, false));
|
||||
}
|
||||
};
|
||||
@@ -906,7 +906,7 @@ public enum StateRegistry {
|
||||
return registry;
|
||||
}
|
||||
|
||||
<P extends MinecraftPacket> void register(Class<P> clazz, Supplier<P> packetSupplier,
|
||||
<P extends MinecraftPacket> void register(Class<P> clazz, PacketCodec<P> codec,
|
||||
PacketMapping... mappings) {
|
||||
if (mappings.length == 0) {
|
||||
throw new IllegalArgumentException("At least one mapping must be provided.");
|
||||
@@ -947,7 +947,7 @@ public enum StateRegistry {
|
||||
"Unknown protocol version " + current.protocolVersion);
|
||||
}
|
||||
|
||||
if (registry.packetIdToSupplier.containsKey(current.id)) {
|
||||
if (registry.packetIdToCodec.containsKey(current.id)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can not register class "
|
||||
+ clazz.getSimpleName()
|
||||
@@ -964,8 +964,9 @@ public enum StateRegistry {
|
||||
}
|
||||
|
||||
if (!current.encodeOnly) {
|
||||
registry.packetIdToSupplier.put(current.id, packetSupplier);
|
||||
registry.packetIdToCodec.put(current.id, codec);
|
||||
}
|
||||
registry.packetClassToCodec.put(clazz, codec);
|
||||
registry.packetClassToId.put(clazz, current.id);
|
||||
}
|
||||
}
|
||||
@@ -977,8 +978,11 @@ public enum StateRegistry {
|
||||
public class ProtocolRegistry {
|
||||
|
||||
public final ProtocolVersion version;
|
||||
final IntObjectMap<Supplier<? extends MinecraftPacket>> packetIdToSupplier =
|
||||
final IntObjectMap<PacketCodec<? extends MinecraftPacket>> packetIdToCodec =
|
||||
new IntObjectHashMap<>(16, 0.5f);
|
||||
|
||||
final Map<Class<? extends MinecraftPacket>, PacketCodec<? extends MinecraftPacket>> packetClassToCodec =
|
||||
new HashMap<>(16, 0.5f);
|
||||
final Object2IntMap<Class<? extends MinecraftPacket>> packetClassToId =
|
||||
new Object2IntOpenHashMap<>(16, 0.5f);
|
||||
|
||||
@@ -988,17 +992,25 @@ public enum StateRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a packet from the specified {@code id}.
|
||||
* Gets the codec for the specified packet {@code id}.
|
||||
*
|
||||
* @param id the packet ID
|
||||
* @return the packet instance, or {@code null} if the ID is not registered
|
||||
* @return the packet codec, or {@code null} if the ID is not registered
|
||||
*/
|
||||
public @Nullable MinecraftPacket createPacket(final int id) {
|
||||
final Supplier<? extends MinecraftPacket> supplier = this.packetIdToSupplier.get(id);
|
||||
if (supplier == null) {
|
||||
return null;
|
||||
}
|
||||
return supplier.get();
|
||||
public @Nullable PacketCodec<? extends MinecraftPacket> getCodec(final int id) {
|
||||
return this.packetIdToCodec.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the codec for the specified packet class.
|
||||
*
|
||||
* @param packetClass the packet class
|
||||
* @return the packet codec, or {@code null} if the class is not registered
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends MinecraftPacket> @Nullable PacketCodec<T> getCodec(
|
||||
final Class<T> packetClass) {
|
||||
return (PacketCodec<T>) this.packetClassToCodec.get(packetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LegacyPingDecoder extends ByteToMessageDecoder {
|
||||
out.add(readExtended16Data(in));
|
||||
} else if (first == 0x02 && in.isReadable()) {
|
||||
in.skipBytes(in.readableBytes());
|
||||
out.add(new LegacyHandshakePacket());
|
||||
out.add(LegacyHandshakePacket.INSTANCE);
|
||||
} else {
|
||||
in.readerIndex(originalReaderIndex);
|
||||
ctx.pipeline().remove(this);
|
||||
|
||||
@@ -71,18 +71,20 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
||||
|
||||
int originalReaderIndex = buf.readerIndex();
|
||||
int packetId = ProtocolUtils.readVarInt(buf);
|
||||
MinecraftPacket packet = this.registry.createPacket(packetId);
|
||||
if (packet == null) {
|
||||
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec =
|
||||
this.registry.getCodec(packetId);
|
||||
if (codec == null) {
|
||||
buf.readerIndex(originalReaderIndex);
|
||||
ctx.fireChannelRead(buf);
|
||||
} else {
|
||||
try {
|
||||
doLengthSanityChecks(buf, packet);
|
||||
doLengthSanityChecks(buf, codec);
|
||||
|
||||
MinecraftPacket packet;
|
||||
try {
|
||||
packet.decode(buf, direction, registry.version);
|
||||
packet = codec.decode(buf, direction, registry.version);
|
||||
} catch (Exception e) {
|
||||
throw handleDecodeFailure(e, packet, packetId);
|
||||
throw handleDecodeFailure(e, codec, packetId);
|
||||
}
|
||||
|
||||
if (buf.isReadable()) {
|
||||
@@ -95,14 +97,16 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
|
||||
int expectedMinLen = packet.decodeExpectedMinLength(buf, direction, registry.version);
|
||||
int expectedMaxLen = packet.decodeExpectedMaxLength(buf, direction, registry.version);
|
||||
private void doLengthSanityChecks(ByteBuf buf,
|
||||
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec)
|
||||
throws Exception {
|
||||
int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, registry.version);
|
||||
int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, registry.version);
|
||||
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
|
||||
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
|
||||
throw handleOverflow(codec, expectedMaxLen, buf.readableBytes());
|
||||
}
|
||||
if (buf.readableBytes() < expectedMinLen) {
|
||||
throw handleUnderflow(packet, expectedMaxLen, buf.readableBytes());
|
||||
throw handleUnderflow(codec, expectedMaxLen, buf.readableBytes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,19 +119,34 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
|
||||
private Exception handleOverflow(
|
||||
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec,
|
||||
int expected, int actual) {
|
||||
if (DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
|
||||
return new CorruptedFrameException("Packet sent for " + codec.getClass() + " was too "
|
||||
+ "big (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return DECODE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
private Exception handleUnderflow(
|
||||
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec,
|
||||
int expected, int actual) {
|
||||
if (DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + codec.getClass() + " was too "
|
||||
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return DECODE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
private Exception handleDecodeFailure(Exception cause, MinecraftPacket packet, int packetId) {
|
||||
private Exception handleDecodeFailure(Exception cause,
|
||||
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec,
|
||||
int packetId) {
|
||||
if (DEBUG) {
|
||||
return new CorruptedFrameException(
|
||||
"Error decoding " + packet.getClass() + " " + getExtraConnectionDetail(packetId), cause);
|
||||
"Error decoding " + codec.getClass() + " " + getExtraConnectionDetail(packetId), cause);
|
||||
} else {
|
||||
return DECODE_FAILED;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.netty;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -48,16 +49,31 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void encode(ChannelHandlerContext ctx, MinecraftPacket msg, ByteBuf out) {
|
||||
PacketCodec<MinecraftPacket> codec = (PacketCodec<MinecraftPacket>) this.registry.getCodec(msg.getClass());
|
||||
if (codec == null) {
|
||||
throw new IllegalArgumentException("No codec found for packet: " + msg.getClass());
|
||||
}
|
||||
|
||||
int packetId = this.registry.getPacketId(msg);
|
||||
ProtocolUtils.writeVarInt(out, packetId);
|
||||
msg.encode(out, direction, registry.version);
|
||||
codec.encode(msg, out, direction, registry.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, MinecraftPacket msg,
|
||||
boolean preferDirect) throws Exception {
|
||||
int hint = msg.encodeSizeHint(direction, registry.version);
|
||||
PacketCodec<MinecraftPacket> codec =
|
||||
(PacketCodec<MinecraftPacket>)
|
||||
this.registry.getCodec(msg.getClass());
|
||||
|
||||
int hint = -1;
|
||||
if (codec != null) {
|
||||
hint = codec.encodeSizeHint(msg, direction, registry.version);
|
||||
}
|
||||
|
||||
if (hint < 0) {
|
||||
return super.allocateBuffer(ctx, msg, preferDirect);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.velocitypowered.proxy.protocol.netty;
|
||||
import static io.netty.util.ByteProcessor.FIND_NON_NUL;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
@@ -122,22 +122,21 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
||||
|
||||
MinecraftPacket packet = registry.createPacket(packetId);
|
||||
|
||||
PacketCodec<?> codec = registry.getCodec(packetId);
|
||||
// We handle every packet in this phase, if you said something we don't know, something is really wrong
|
||||
if (packet == null) {
|
||||
if (codec == null) {
|
||||
throw UNKNOWN_PACKET;
|
||||
}
|
||||
|
||||
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
||||
// the packet if needed, so, we'll take advantage of the existing methods
|
||||
int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version);
|
||||
int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version);
|
||||
int expectedMinLen = codec.decodeExpectedMinLength(in, direction, registry.version);
|
||||
int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, registry.version);
|
||||
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
||||
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
||||
throw handleOverflow(expectedMaxLen, in.readableBytes());
|
||||
}
|
||||
if (payloadLength < expectedMinLen) {
|
||||
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
||||
throw handleUnderflow(expectedMaxLen, in.readableBytes());
|
||||
}
|
||||
|
||||
in.readerIndex(index);
|
||||
@@ -224,18 +223,18 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
||||
return result | (tmp & 0x7F) << 14;
|
||||
}
|
||||
|
||||
private Exception handleOverflow(MinecraftPacket packet, int expected, int actual) {
|
||||
private Exception handleOverflow(int expected, int actual) {
|
||||
if (MinecraftDecoder.DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
|
||||
return new CorruptedFrameException("Packet sent for handshake was too "
|
||||
+ "big (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return FRAME_DECODER_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
|
||||
private Exception handleUnderflow(int expected, int actual) {
|
||||
if (MinecraftDecoder.DEBUG) {
|
||||
return new CorruptedFrameException("Packet sent for " + packet.getClass() + " was too "
|
||||
return new CorruptedFrameException("Packet sent for handshake was too "
|
||||
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||
} else {
|
||||
return FRAME_DECODER_FAILED;
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentPropertyRegistry;
|
||||
@@ -54,7 +55,7 @@ import java.util.function.Predicate;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
public final class AvailableCommandsPacket implements MinecraftPacket {
|
||||
|
||||
private static final Command<CommandSource> PLACEHOLDER_COMMAND = source -> 0;
|
||||
private static final Predicate<CommandSource> PLACEHOLDER_REQUIREMENT = source -> true;
|
||||
@@ -69,160 +70,169 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
private static final byte FLAG_HAS_SUGGESTIONS = 0x10;
|
||||
private static final byte FLAG_IS_RESTRICTED = 0x20;
|
||||
|
||||
private @MonotonicNonNull RootCommandNode<CommandSource> rootNode;
|
||||
private final RootCommandNode<CommandSource> rootNode;
|
||||
|
||||
public AvailableCommandsPacket(RootCommandNode<CommandSource> rootNode) {
|
||||
this.rootNode = rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root node.
|
||||
*
|
||||
* @return the root node
|
||||
*/
|
||||
public RootCommandNode<CommandSource> getRootNode() {
|
||||
if (rootNode == null) {
|
||||
throw new IllegalStateException("Packet not yet deserialized");
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
int commands = ProtocolUtils.readVarInt(buf);
|
||||
WireNode[] wireNodes = new WireNode[commands];
|
||||
for (int i = 0; i < commands; i++) {
|
||||
wireNodes[i] = deserializeNode(buf, i, protocolVersion);
|
||||
}
|
||||
|
||||
// Iterate over the deserialized nodes and attempt to form a graph. We also resolve any cycles
|
||||
// that exist.
|
||||
Queue<WireNode> nodeQueue = new ArrayDeque<>(Arrays.asList(wireNodes));
|
||||
while (!nodeQueue.isEmpty()) {
|
||||
boolean cycling = false;
|
||||
|
||||
for (Iterator<WireNode> it = nodeQueue.iterator(); it.hasNext(); ) {
|
||||
WireNode node = it.next();
|
||||
if (node.toNode(wireNodes)) {
|
||||
cycling = true;
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cycling) {
|
||||
// Uh-oh. We can't cycle. This is bad.
|
||||
throw new IllegalStateException("Stopped cycling; the root node can't be built.");
|
||||
}
|
||||
}
|
||||
|
||||
int rootIdx = ProtocolUtils.readVarInt(buf);
|
||||
rootNode = (RootCommandNode<CommandSource>) wireNodes[rootIdx].built;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
// Assign all the children an index.
|
||||
Deque<CommandNode<CommandSource>> childrenQueue = new ArrayDeque<>(ImmutableList.of(rootNode));
|
||||
Object2IntMap<CommandNode<CommandSource>> idMappings = new Object2IntLinkedOpenCustomHashMap<>(
|
||||
IdentityHashStrategy.instance());
|
||||
while (!childrenQueue.isEmpty()) {
|
||||
CommandNode<CommandSource> child = childrenQueue.poll();
|
||||
if (!idMappings.containsKey(child)) {
|
||||
idMappings.put(child, idMappings.size());
|
||||
childrenQueue.addAll(child.getChildren());
|
||||
if (child.getRedirect() != null) {
|
||||
childrenQueue.add(child.getRedirect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now serialize the children.
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.size());
|
||||
for (CommandNode<CommandSource> child : idMappings.keySet()) {
|
||||
serializeNode(child, buf, idMappings, protocolVersion);
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(rootNode));
|
||||
}
|
||||
|
||||
private static void serializeNode(CommandNode<CommandSource> node, ByteBuf buf,
|
||||
Object2IntMap<CommandNode<CommandSource>> idMappings, ProtocolVersion protocolVersion) {
|
||||
byte flags = 0;
|
||||
if (node.getRedirect() != null) {
|
||||
flags |= FLAG_IS_REDIRECT;
|
||||
}
|
||||
if (node.getCommand() != null) {
|
||||
flags |= FLAG_EXECUTABLE;
|
||||
}
|
||||
if (node.getRequirement() == PLACEHOLDER_REQUIREMENT) {
|
||||
flags |= FLAG_IS_RESTRICTED;
|
||||
}
|
||||
|
||||
if (node instanceof LiteralCommandNode<?>) {
|
||||
flags |= NODE_TYPE_LITERAL;
|
||||
} else if (node instanceof ArgumentCommandNode<?, ?>) {
|
||||
flags |= NODE_TYPE_ARGUMENT;
|
||||
if (((ArgumentCommandNode<CommandSource, ?>) node).getCustomSuggestions() != null) {
|
||||
flags |= FLAG_HAS_SUGGESTIONS;
|
||||
}
|
||||
} else if (!(node instanceof RootCommandNode<?>)) {
|
||||
throw new IllegalArgumentException("Unknown node type " + node.getClass().getName());
|
||||
}
|
||||
|
||||
buf.writeByte(flags);
|
||||
ProtocolUtils.writeVarInt(buf, node.getChildren().size());
|
||||
for (CommandNode<CommandSource> child : node.getChildren()) {
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(child));
|
||||
}
|
||||
if (node.getRedirect() != null) {
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(node.getRedirect()));
|
||||
}
|
||||
|
||||
if (node instanceof ArgumentCommandNode<?, ?>) {
|
||||
ProtocolUtils.writeString(buf, node.getName());
|
||||
ArgumentPropertyRegistry.serialize(buf,
|
||||
((ArgumentCommandNode<CommandSource, ?>) node).getType(), protocolVersion);
|
||||
|
||||
if (((ArgumentCommandNode<CommandSource, ?>) node).getCustomSuggestions() != null) {
|
||||
SuggestionProvider<CommandSource> provider = ((ArgumentCommandNode<CommandSource, ?>) node)
|
||||
.getCustomSuggestions();
|
||||
String name = "minecraft:ask_server";
|
||||
if (provider instanceof ProtocolSuggestionProvider) {
|
||||
name = ((ProtocolSuggestionProvider) provider).name;
|
||||
}
|
||||
ProtocolUtils.writeString(buf, name);
|
||||
}
|
||||
} else if (node instanceof LiteralCommandNode<?>) {
|
||||
ProtocolUtils.writeString(buf, node.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
private static WireNode deserializeNode(ByteBuf buf, int idx, ProtocolVersion version) {
|
||||
byte flags = buf.readByte();
|
||||
int[] children = ProtocolUtils.readIntegerArray(buf);
|
||||
int redirectTo = -1;
|
||||
if ((flags & FLAG_IS_REDIRECT) > 0) {
|
||||
redirectTo = ProtocolUtils.readVarInt(buf);
|
||||
public static class Codec implements PacketCodec<AvailableCommandsPacket> {
|
||||
@Override
|
||||
public AvailableCommandsPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int commands = ProtocolUtils.readVarInt(buf);
|
||||
WireNode[] wireNodes = new WireNode[commands];
|
||||
for (int i = 0; i < commands; i++) {
|
||||
wireNodes[i] = deserializeNode(buf, i, protocolVersion);
|
||||
}
|
||||
|
||||
// Iterate over the deserialized nodes and attempt to form a graph. We also resolve any cycles
|
||||
// that exist.
|
||||
Queue<WireNode> nodeQueue = new ArrayDeque<>(Arrays.asList(wireNodes));
|
||||
while (!nodeQueue.isEmpty()) {
|
||||
boolean cycling = false;
|
||||
|
||||
for (Iterator<WireNode> it = nodeQueue.iterator(); it.hasNext(); ) {
|
||||
WireNode node = it.next();
|
||||
if (node.toNode(wireNodes)) {
|
||||
cycling = true;
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cycling) {
|
||||
// Uh-oh. We can't cycle. This is bad.
|
||||
throw new IllegalStateException("Stopped cycling; the root node can't be built.");
|
||||
}
|
||||
}
|
||||
|
||||
int rootIdx = ProtocolUtils.readVarInt(buf);
|
||||
RootCommandNode<CommandSource> rootNode = (RootCommandNode<CommandSource>) wireNodes[rootIdx].built;
|
||||
return new AvailableCommandsPacket(rootNode);
|
||||
}
|
||||
|
||||
switch (flags & FLAG_NODE_TYPE) {
|
||||
case NODE_TYPE_ROOT:
|
||||
return new WireNode(idx, flags, children, redirectTo, null);
|
||||
case NODE_TYPE_LITERAL:
|
||||
return new WireNode(idx, flags, children, redirectTo, LiteralArgumentBuilder
|
||||
.literal(ProtocolUtils.readString(buf)));
|
||||
case NODE_TYPE_ARGUMENT:
|
||||
String name = ProtocolUtils.readString(buf);
|
||||
ArgumentType<?> argumentType = ArgumentPropertyRegistry.deserialize(buf, version);
|
||||
|
||||
RequiredArgumentBuilder<CommandSource, ?> argumentBuilder = RequiredArgumentBuilder
|
||||
.argument(name, argumentType);
|
||||
if ((flags & FLAG_HAS_SUGGESTIONS) != 0) {
|
||||
argumentBuilder.suggests(new ProtocolSuggestionProvider(ProtocolUtils.readString(buf)));
|
||||
@Override
|
||||
public void encode(AvailableCommandsPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
// Assign all the children an index.
|
||||
Deque<CommandNode<CommandSource>> childrenQueue = new ArrayDeque<>(ImmutableList.of(packet.rootNode));
|
||||
Object2IntMap<CommandNode<CommandSource>> idMappings = new Object2IntLinkedOpenCustomHashMap<>(
|
||||
IdentityHashStrategy.instance());
|
||||
while (!childrenQueue.isEmpty()) {
|
||||
CommandNode<CommandSource> child = childrenQueue.poll();
|
||||
if (!idMappings.containsKey(child)) {
|
||||
idMappings.put(child, idMappings.size());
|
||||
childrenQueue.addAll(child.getChildren());
|
||||
if (child.getRedirect() != null) {
|
||||
childrenQueue.add(child.getRedirect());
|
||||
}
|
||||
}
|
||||
return new WireNode(idx, flags, children, redirectTo, argumentBuilder);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown node type " + (flags & FLAG_NODE_TYPE));
|
||||
}
|
||||
|
||||
// Now serialize the children.
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.size());
|
||||
for (CommandNode<CommandSource> child : idMappings.keySet()) {
|
||||
serializeNode(child, buf, idMappings, protocolVersion);
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(packet.rootNode));
|
||||
}
|
||||
|
||||
private static void serializeNode(CommandNode<CommandSource> node, ByteBuf buf,
|
||||
Object2IntMap<CommandNode<CommandSource>> idMappings, ProtocolVersion protocolVersion) {
|
||||
byte flags = 0;
|
||||
if (node.getRedirect() != null) {
|
||||
flags |= FLAG_IS_REDIRECT;
|
||||
}
|
||||
if (node.getCommand() != null) {
|
||||
flags |= FLAG_EXECUTABLE;
|
||||
}
|
||||
if (node.getRequirement() == PLACEHOLDER_REQUIREMENT) {
|
||||
flags |= FLAG_IS_RESTRICTED;
|
||||
}
|
||||
|
||||
if (node instanceof LiteralCommandNode<?>) {
|
||||
flags |= NODE_TYPE_LITERAL;
|
||||
} else if (node instanceof ArgumentCommandNode<?, ?>) {
|
||||
flags |= NODE_TYPE_ARGUMENT;
|
||||
if (((ArgumentCommandNode<CommandSource, ?>) node).getCustomSuggestions() != null) {
|
||||
flags |= FLAG_HAS_SUGGESTIONS;
|
||||
}
|
||||
} else if (!(node instanceof RootCommandNode<?>)) {
|
||||
throw new IllegalArgumentException("Unknown node type " + node.getClass().getName());
|
||||
}
|
||||
|
||||
buf.writeByte(flags);
|
||||
ProtocolUtils.writeVarInt(buf, node.getChildren().size());
|
||||
for (CommandNode<CommandSource> child : node.getChildren()) {
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(child));
|
||||
}
|
||||
if (node.getRedirect() != null) {
|
||||
ProtocolUtils.writeVarInt(buf, idMappings.getInt(node.getRedirect()));
|
||||
}
|
||||
|
||||
if (node instanceof ArgumentCommandNode<?, ?>) {
|
||||
ProtocolUtils.writeString(buf, node.getName());
|
||||
ArgumentPropertyRegistry.serialize(buf,
|
||||
((ArgumentCommandNode<CommandSource, ?>) node).getType(), protocolVersion);
|
||||
|
||||
if (((ArgumentCommandNode<CommandSource, ?>) node).getCustomSuggestions() != null) {
|
||||
SuggestionProvider<CommandSource> provider = ((ArgumentCommandNode<CommandSource, ?>) node)
|
||||
.getCustomSuggestions();
|
||||
String name = "minecraft:ask_server";
|
||||
if (provider instanceof ProtocolSuggestionProvider) {
|
||||
name = ((ProtocolSuggestionProvider) provider).name;
|
||||
}
|
||||
ProtocolUtils.writeString(buf, name);
|
||||
}
|
||||
} else if (node instanceof LiteralCommandNode<?>) {
|
||||
ProtocolUtils.writeString(buf, node.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static WireNode deserializeNode(ByteBuf buf, int idx, ProtocolVersion version) {
|
||||
byte flags = buf.readByte();
|
||||
int[] children = ProtocolUtils.readIntegerArray(buf);
|
||||
int redirectTo = -1;
|
||||
if ((flags & FLAG_IS_REDIRECT) > 0) {
|
||||
redirectTo = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
switch (flags & FLAG_NODE_TYPE) {
|
||||
case NODE_TYPE_ROOT:
|
||||
return new WireNode(idx, flags, children, redirectTo, null);
|
||||
case NODE_TYPE_LITERAL:
|
||||
return new WireNode(idx, flags, children, redirectTo, LiteralArgumentBuilder
|
||||
.literal(ProtocolUtils.readString(buf)));
|
||||
case NODE_TYPE_ARGUMENT:
|
||||
String name = ProtocolUtils.readString(buf);
|
||||
ArgumentType<?> argumentType = ArgumentPropertyRegistry.deserialize(buf, version);
|
||||
|
||||
RequiredArgumentBuilder<CommandSource, ?> argumentBuilder = RequiredArgumentBuilder
|
||||
.argument(name, argumentType);
|
||||
if ((flags & FLAG_HAS_SUGGESTIONS) != 0) {
|
||||
argumentBuilder.suggests(new ProtocolSuggestionProvider(ProtocolUtils.readString(buf)));
|
||||
}
|
||||
return new WireNode(idx, flags, children, redirectTo, argumentBuilder);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown node type " + (flags & FLAG_NODE_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(AvailableCommandsPacket packet, Direction direction, ProtocolVersion version) {
|
||||
// This is a very complex packet to encode. Paper 1.21.10 + Velocity with Spark has a size of
|
||||
// 30,334, but this is likely on the lower side. We'll use 128KiB as a more realistically-sized
|
||||
// amount.
|
||||
return 128 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,12 +372,4 @@ public class AvailableCommandsPacket implements MinecraftPacket {
|
||||
return builder.buildFuture();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
// This is a very complex packet to encode. Paper 1.21.10 + Velocity with Spark has a size of
|
||||
// 30,334, but this is likely on the lower side. We'll use 128KiB as a more realistically-sized
|
||||
// amount.
|
||||
return 128 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.util.collect.Enum2IntMap;
|
||||
@@ -29,7 +30,8 @@ import java.util.UUID;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BossBarPacket implements MinecraftPacket {
|
||||
public record BossBarPacket(UUID uuid, int action, @Nullable ComponentHolder name,
|
||||
float percent, int color, int overlay, short flags) implements MinecraftPacket {
|
||||
|
||||
private static final Enum2IntMap<BossBar.Color> COLORS_TO_PROTOCOL =
|
||||
new Enum2IntMap.Builder<>(BossBar.Color.class)
|
||||
@@ -62,43 +64,31 @@ public class BossBarPacket implements MinecraftPacket {
|
||||
public static final int UPDATE_NAME = 3;
|
||||
public static final int UPDATE_STYLE = 4;
|
||||
public static final int UPDATE_PROPERTIES = 5;
|
||||
private @Nullable UUID uuid;
|
||||
private int action;
|
||||
private @Nullable ComponentHolder name;
|
||||
private float percent;
|
||||
private int color;
|
||||
private int overlay;
|
||||
private short flags;
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public int getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public static BossBarPacket createAddPacket(
|
||||
final UUID id,
|
||||
final BossBar bar,
|
||||
final ComponentHolder name
|
||||
) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(BossBarPacket.ADD);
|
||||
packet.setName(name);
|
||||
packet.setColor(COLORS_TO_PROTOCOL.get(bar.color()));
|
||||
packet.setOverlay(OVERLAY_TO_PROTOCOL.get(bar.overlay()));
|
||||
packet.setPercent(bar.progress());
|
||||
packet.setFlags(serializeFlags(bar.flags()));
|
||||
return packet;
|
||||
return new BossBarPacket(id, ADD, name, bar.progress(),
|
||||
COLORS_TO_PROTOCOL.get(bar.color()), OVERLAY_TO_PROTOCOL.get(bar.overlay()),
|
||||
serializeFlags(bar.flags()));
|
||||
}
|
||||
|
||||
public static BossBarPacket createRemovePacket(final UUID id, final BossBar bar) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(REMOVE);
|
||||
return packet;
|
||||
public static BossBarPacket createRemovePacket(final UUID id) {
|
||||
return new BossBarPacket(id, REMOVE, null, 0, 0, 0, (short) 0);
|
||||
}
|
||||
|
||||
public static BossBarPacket createUpdateProgressPacket(final UUID id, final BossBar bar) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(UPDATE_PERCENT);
|
||||
packet.setPercent(bar.progress());
|
||||
return packet;
|
||||
return new BossBarPacket(id, UPDATE_PERCENT, null, bar.progress(), 0, 0, (short) 0);
|
||||
}
|
||||
|
||||
public static BossBarPacket createUpdateNamePacket(
|
||||
@@ -106,177 +96,20 @@ public class BossBarPacket implements MinecraftPacket {
|
||||
final BossBar bar,
|
||||
final ComponentHolder name
|
||||
) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(UPDATE_NAME);
|
||||
packet.setName(name);
|
||||
return packet;
|
||||
return new BossBarPacket(id, UPDATE_NAME, name, 0, 0, 0, (short) 0);
|
||||
}
|
||||
|
||||
public static BossBarPacket createUpdateStylePacket(final UUID id, final BossBar bar) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(UPDATE_STYLE);
|
||||
packet.setColor(COLORS_TO_PROTOCOL.get(bar.color()));
|
||||
packet.setOverlay(OVERLAY_TO_PROTOCOL.get(bar.overlay()));
|
||||
return packet;
|
||||
return new BossBarPacket(id, UPDATE_STYLE, null, 0,
|
||||
COLORS_TO_PROTOCOL.get(bar.color()), OVERLAY_TO_PROTOCOL.get(bar.overlay()), (short) 0);
|
||||
}
|
||||
|
||||
public static BossBarPacket createUpdatePropertiesPacket(final UUID id, final BossBar bar) {
|
||||
final BossBarPacket packet = new BossBarPacket();
|
||||
packet.setUuid(id);
|
||||
packet.setAction(UPDATE_PROPERTIES);
|
||||
packet.setFlags(serializeFlags(bar.flags()));
|
||||
return packet;
|
||||
return new BossBarPacket(id, UPDATE_PROPERTIES, null, 0, 0, 0, serializeFlags(bar.flags()));
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
if (uuid == null) {
|
||||
throw new IllegalStateException("No boss bar UUID specified");
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public int getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(int action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public @Nullable ComponentHolder getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(ComponentHolder name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public float getPercent() {
|
||||
return percent;
|
||||
}
|
||||
|
||||
public void setPercent(float percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public int getOverlay() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
public void setOverlay(int overlay) {
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
public short getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void setFlags(short flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BossBar{"
|
||||
+ "uuid=" + uuid
|
||||
+ ", action=" + action
|
||||
+ ", name='" + name + '\''
|
||||
+ ", percent=" + percent
|
||||
+ ", color=" + color
|
||||
+ ", overlay=" + overlay
|
||||
+ ", flags=" + flags
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.uuid = ProtocolUtils.readUuid(buf);
|
||||
this.action = ProtocolUtils.readVarInt(buf);
|
||||
switch (action) {
|
||||
case ADD:
|
||||
this.name = ComponentHolder.read(buf, version);
|
||||
this.percent = buf.readFloat();
|
||||
this.color = ProtocolUtils.readVarInt(buf);
|
||||
this.overlay = ProtocolUtils.readVarInt(buf);
|
||||
this.flags = buf.readUnsignedByte();
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_PERCENT:
|
||||
this.percent = buf.readFloat();
|
||||
break;
|
||||
case UPDATE_NAME:
|
||||
this.name = ComponentHolder.read(buf, version);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
this.color = ProtocolUtils.readVarInt(buf);
|
||||
this.overlay = ProtocolUtils.readVarInt(buf);
|
||||
break;
|
||||
case UPDATE_PROPERTIES:
|
||||
this.flags = buf.readUnsignedByte();
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (uuid == null) {
|
||||
throw new IllegalStateException("No boss bar UUID specified");
|
||||
}
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
ProtocolUtils.writeVarInt(buf, action);
|
||||
switch (action) {
|
||||
case ADD:
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
name.write(buf);
|
||||
buf.writeFloat(percent);
|
||||
ProtocolUtils.writeVarInt(buf, color);
|
||||
ProtocolUtils.writeVarInt(buf, overlay);
|
||||
buf.writeByte(flags);
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_PERCENT:
|
||||
buf.writeFloat(percent);
|
||||
break;
|
||||
case UPDATE_NAME:
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
name.write(buf);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
ProtocolUtils.writeVarInt(buf, color);
|
||||
ProtocolUtils.writeVarInt(buf, overlay);
|
||||
break;
|
||||
case UPDATE_PROPERTIES:
|
||||
buf.writeByte(flags);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte serializeFlags(Set<BossBar.Flag> flags) {
|
||||
byte val = 0x0;
|
||||
private static short serializeFlags(Set<BossBar.Flag> flags) {
|
||||
short val = 0x0;
|
||||
for (BossBar.Flag flag : flags) {
|
||||
val |= FLAG_BITS_TO_PROTOCOL.get(flag);
|
||||
}
|
||||
@@ -287,4 +120,86 @@ public class BossBarPacket implements MinecraftPacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<BossBarPacket> {
|
||||
@Override
|
||||
public BossBarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
UUID uuid = ProtocolUtils.readUuid(buf);
|
||||
int action = ProtocolUtils.readVarInt(buf);
|
||||
ComponentHolder name = null;
|
||||
float percent = 0;
|
||||
int color = 0;
|
||||
int overlay = 0;
|
||||
short flags = 0;
|
||||
|
||||
switch (action) {
|
||||
case ADD:
|
||||
name = ComponentHolder.read(buf, version);
|
||||
percent = buf.readFloat();
|
||||
color = ProtocolUtils.readVarInt(buf);
|
||||
overlay = ProtocolUtils.readVarInt(buf);
|
||||
flags = buf.readUnsignedByte();
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_PERCENT:
|
||||
percent = buf.readFloat();
|
||||
break;
|
||||
case UPDATE_NAME:
|
||||
name = ComponentHolder.read(buf, version);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
color = ProtocolUtils.readVarInt(buf);
|
||||
overlay = ProtocolUtils.readVarInt(buf);
|
||||
break;
|
||||
case UPDATE_PROPERTIES:
|
||||
flags = buf.readUnsignedByte();
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
|
||||
return new BossBarPacket(uuid, action, name, percent, color, overlay, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(BossBarPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
ProtocolUtils.writeUuid(buf, packet.uuid);
|
||||
ProtocolUtils.writeVarInt(buf, packet.action);
|
||||
switch (packet.action) {
|
||||
case ADD:
|
||||
if (packet.name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
packet.name.write(buf);
|
||||
buf.writeFloat(packet.percent);
|
||||
ProtocolUtils.writeVarInt(buf, packet.color);
|
||||
ProtocolUtils.writeVarInt(buf, packet.overlay);
|
||||
buf.writeByte(packet.flags);
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_PERCENT:
|
||||
buf.writeFloat(packet.percent);
|
||||
break;
|
||||
case UPDATE_NAME:
|
||||
if (packet.name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
packet.name.write(buf);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
ProtocolUtils.writeVarInt(buf, packet.color);
|
||||
ProtocolUtils.writeVarInt(buf, packet.overlay);
|
||||
break;
|
||||
case UPDATE_PROPERTIES:
|
||||
buf.writeByte(packet.flags);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + packet.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@@ -29,18 +30,21 @@ public final class BundleDelimiterPacket implements MinecraftPacket {
|
||||
private BundleDelimiterPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<BundleDelimiterPacket> {
|
||||
@Override
|
||||
public BundleDelimiterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(BundleDelimiterPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,34 +20,46 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ClientSettingsPacket implements MinecraftPacket {
|
||||
private @Nullable String locale;
|
||||
private byte viewDistance;
|
||||
private int chatVisibility;
|
||||
private boolean chatColors;
|
||||
private byte difficulty; // 1.7 Protocol
|
||||
private short skinParts;
|
||||
private int mainHand;
|
||||
private boolean textFilteringEnabled; // Added in 1.17
|
||||
private boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode
|
||||
private int particleStatus; // Added in 1.21.2
|
||||
public final class ClientSettingsPacket implements MinecraftPacket {
|
||||
private final @Nullable String locale;
|
||||
private final byte viewDistance;
|
||||
private final int chatVisibility;
|
||||
private final boolean chatColors;
|
||||
private final byte difficulty; // 1.7 Protocol
|
||||
private final short skinParts;
|
||||
private final int mainHand;
|
||||
private final boolean textFilteringEnabled; // Added in 1.17
|
||||
private final boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode
|
||||
private final int particleStatus; // Added in 1.21.2
|
||||
|
||||
public ClientSettingsPacket() {
|
||||
this(null, (byte) 0, 0, false, (byte) 0, (short) 0, 0, false, false, 0);
|
||||
}
|
||||
|
||||
public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility, boolean chatColors,
|
||||
short skinParts, int mainHand, boolean textFilteringEnabled, boolean clientListingAllowed,
|
||||
int particleStatus) {
|
||||
public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility,
|
||||
boolean chatColors, short skinParts, int mainHand,
|
||||
boolean textFilteringEnabled, boolean clientListingAllowed,
|
||||
int particleStatus) {
|
||||
this(locale, viewDistance, chatVisibility, chatColors, (byte) 0, skinParts, mainHand,
|
||||
textFilteringEnabled, clientListingAllowed, particleStatus);
|
||||
}
|
||||
|
||||
public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility,
|
||||
boolean chatColors, byte difficulty, short skinParts, int mainHand,
|
||||
boolean textFilteringEnabled, boolean clientListingAllowed,
|
||||
int particleStatus) {
|
||||
this.locale = locale;
|
||||
this.viewDistance = viewDistance;
|
||||
this.chatVisibility = chatVisibility;
|
||||
this.chatColors = chatColors;
|
||||
this.difficulty = difficulty;
|
||||
this.skinParts = skinParts;
|
||||
this.mainHand = mainHand;
|
||||
this.textFilteringEnabled = textFilteringEnabled;
|
||||
@@ -55,150 +67,51 @@ public class ClientSettingsPacket implements MinecraftPacket {
|
||||
this.particleStatus = particleStatus;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
public String locale() {
|
||||
if (locale == null) {
|
||||
throw new IllegalStateException("No locale specified");
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public byte getViewDistance() {
|
||||
public byte viewDistance() {
|
||||
return viewDistance;
|
||||
}
|
||||
|
||||
public void setViewDistance(byte viewDistance) {
|
||||
this.viewDistance = viewDistance;
|
||||
}
|
||||
|
||||
public int getChatVisibility() {
|
||||
public int chatVisibility() {
|
||||
return chatVisibility;
|
||||
}
|
||||
|
||||
public void setChatVisibility(int chatVisibility) {
|
||||
this.chatVisibility = chatVisibility;
|
||||
}
|
||||
|
||||
public boolean isChatColors() {
|
||||
public boolean chatColors() {
|
||||
return chatColors;
|
||||
}
|
||||
|
||||
public void setChatColors(boolean chatColors) {
|
||||
this.chatColors = chatColors;
|
||||
public byte difficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public short getSkinParts() {
|
||||
public short skinParts() {
|
||||
return skinParts;
|
||||
}
|
||||
|
||||
public void setSkinParts(short skinParts) {
|
||||
this.skinParts = skinParts;
|
||||
}
|
||||
|
||||
public int getMainHand() {
|
||||
public int mainHand() {
|
||||
return mainHand;
|
||||
}
|
||||
|
||||
public void setMainHand(int mainHand) {
|
||||
this.mainHand = mainHand;
|
||||
}
|
||||
|
||||
public boolean isTextFilteringEnabled() {
|
||||
public boolean textFilteringEnabled() {
|
||||
return textFilteringEnabled;
|
||||
}
|
||||
|
||||
public void setTextFilteringEnabled(boolean textFilteringEnabled) {
|
||||
this.textFilteringEnabled = textFilteringEnabled;
|
||||
}
|
||||
|
||||
public boolean isClientListingAllowed() {
|
||||
public boolean clientListingAllowed() {
|
||||
return clientListingAllowed;
|
||||
}
|
||||
|
||||
public void setClientListingAllowed(boolean clientListingAllowed) {
|
||||
this.clientListingAllowed = clientListingAllowed;
|
||||
}
|
||||
|
||||
public int getParticleStatus() {
|
||||
public int particleStatus() {
|
||||
return particleStatus;
|
||||
}
|
||||
|
||||
public void setParticleStatus(int particleStatus) {
|
||||
this.particleStatus = particleStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance +
|
||||
", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" +
|
||||
skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled +
|
||||
", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.locale = ProtocolUtils.readString(buf, 16);
|
||||
this.viewDistance = buf.readByte();
|
||||
this.chatVisibility = ProtocolUtils.readVarInt(buf);
|
||||
this.chatColors = buf.readBoolean();
|
||||
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
this.difficulty = buf.readByte();
|
||||
}
|
||||
|
||||
this.skinParts = buf.readUnsignedByte();
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9)) {
|
||||
this.mainHand = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
this.textFilteringEnabled = buf.readBoolean();
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
this.clientListingAllowed = buf.readBoolean();
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
this.particleStatus = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (locale == null) {
|
||||
throw new IllegalStateException("No locale specified");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, locale);
|
||||
buf.writeByte(viewDistance);
|
||||
ProtocolUtils.writeVarInt(buf, chatVisibility);
|
||||
buf.writeBoolean(chatColors);
|
||||
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
buf.writeByte(difficulty);
|
||||
}
|
||||
|
||||
buf.writeByte(skinParts);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9)) {
|
||||
ProtocolUtils.writeVarInt(buf, mainHand);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
buf.writeBoolean(textFilteringEnabled);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
buf.writeBoolean(clientListingAllowed);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, particleStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
public String getLocale() {
|
||||
return locale();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,18 +140,79 @@ public class ClientSettingsPacket implements MinecraftPacket {
|
||||
&& Objects.equals(locale, that.locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
locale,
|
||||
viewDistance,
|
||||
chatVisibility,
|
||||
chatColors,
|
||||
difficulty,
|
||||
skinParts,
|
||||
mainHand,
|
||||
textFilteringEnabled,
|
||||
clientListingAllowed,
|
||||
particleStatus);
|
||||
public static class Codec implements PacketCodec<ClientSettingsPacket> {
|
||||
@Override
|
||||
public ClientSettingsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String locale = ProtocolUtils.readString(buf, 16);
|
||||
byte viewDistance = buf.readByte();
|
||||
int chatVisibility = ProtocolUtils.readVarInt(buf);
|
||||
boolean chatColors = buf.readBoolean();
|
||||
byte difficulty = 0;
|
||||
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
difficulty = buf.readByte();
|
||||
}
|
||||
|
||||
short skinParts = buf.readUnsignedByte();
|
||||
int mainHand = 0;
|
||||
boolean textFilteringEnabled = false;
|
||||
boolean clientListingAllowed = false;
|
||||
int particleStatus = 0;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9)) {
|
||||
mainHand = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
textFilteringEnabled = buf.readBoolean();
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
clientListingAllowed = buf.readBoolean();
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
particleStatus = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ClientSettingsPacket(locale, viewDistance, chatVisibility, chatColors,
|
||||
difficulty, skinParts, mainHand, textFilteringEnabled, clientListingAllowed,
|
||||
particleStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientSettingsPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (packet.locale == null) {
|
||||
throw new IllegalStateException("No locale specified");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.locale);
|
||||
buf.writeByte(packet.viewDistance);
|
||||
ProtocolUtils.writeVarInt(buf, packet.chatVisibility);
|
||||
buf.writeBoolean(packet.chatColors);
|
||||
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
buf.writeByte(packet.difficulty);
|
||||
}
|
||||
|
||||
buf.writeByte(packet.skinParts);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.mainHand);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
buf.writeBoolean(packet.textFilteringEnabled);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
buf.writeBoolean(packet.clientListingAllowed);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.particleStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,38 +20,34 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
public class ClientboundCookieRequestPacket implements MinecraftPacket {
|
||||
|
||||
private Key key;
|
||||
public record ClientboundCookieRequestPacket(Key key) implements MinecraftPacket {
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public ClientboundCookieRequestPacket() {
|
||||
}
|
||||
|
||||
public ClientboundCookieRequestPacket(final Key key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.key = ProtocolUtils.readKey(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ClientboundCookieRequestPacket> {
|
||||
@Override
|
||||
public ClientboundCookieRequestPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new ClientboundCookieRequestPacket(ProtocolUtils.readKey(buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientboundCookieRequestPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, packet.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,82 +20,50 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class ClientboundSoundEntityPacket implements MinecraftPacket {
|
||||
|
||||
private static final Random SEEDS_RANDOM = new Random();
|
||||
|
||||
private Sound sound;
|
||||
private @Nullable Float fixedRange;
|
||||
private int emitterEntityId;
|
||||
|
||||
public ClientboundSoundEntityPacket() {}
|
||||
|
||||
public ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange, int emitterEntityId) {
|
||||
this.sound = sound;
|
||||
this.fixedRange = fixedRange;
|
||||
this.emitterEntityId = emitterEntityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException("Decode is not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, 0); // version-dependent, hardcoded sound ID
|
||||
|
||||
ProtocolUtils.writeMinimalKey(buf, sound.name());
|
||||
|
||||
buf.writeBoolean(fixedRange != null);
|
||||
if (fixedRange != null)
|
||||
buf.writeFloat(fixedRange);
|
||||
|
||||
ProtocolUtils.writeSoundSource(buf, protocolVersion, sound.source());
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, emitterEntityId);
|
||||
|
||||
buf.writeFloat(sound.volume());
|
||||
|
||||
buf.writeFloat(sound.pitch());
|
||||
|
||||
buf.writeLong(sound.seed().orElse(SEEDS_RANDOM.nextLong()));
|
||||
}
|
||||
public record ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange,
|
||||
int emitterEntityId) implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public Sound getSound() {
|
||||
return sound;
|
||||
}
|
||||
public static class Codec implements PacketCodec<ClientboundSoundEntityPacket> {
|
||||
@Override
|
||||
public ClientboundSoundEntityPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException("Decode is not implemented");
|
||||
}
|
||||
|
||||
public void setSound(Sound sound) {
|
||||
this.sound = sound;
|
||||
}
|
||||
@Override
|
||||
public void encode(ClientboundSoundEntityPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, 0); // version-dependent, hardcoded sound ID
|
||||
|
||||
public @Nullable Float getFixedRange() {
|
||||
return fixedRange;
|
||||
}
|
||||
ProtocolUtils.writeMinimalKey(buf, packet.sound.name());
|
||||
|
||||
public void setFixedRange(@Nullable Float fixedRange) {
|
||||
this.fixedRange = fixedRange;
|
||||
}
|
||||
buf.writeBoolean(packet.fixedRange != null);
|
||||
if (packet.fixedRange != null) {
|
||||
buf.writeFloat(packet.fixedRange);
|
||||
}
|
||||
|
||||
public int getEmitterEntityId() {
|
||||
return emitterEntityId;
|
||||
}
|
||||
ProtocolUtils.writeSoundSource(buf, protocolVersion, packet.sound.source());
|
||||
|
||||
public void setEmitterEntityId(int emitterEntityId) {
|
||||
this.emitterEntityId = emitterEntityId;
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, packet.emitterEntityId);
|
||||
|
||||
buf.writeFloat(packet.sound.volume());
|
||||
|
||||
buf.writeFloat(packet.sound.pitch());
|
||||
|
||||
buf.writeLong(packet.sound.seed().orElse(ThreadLocalRandom.current().nextLong()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.key.Key;
|
||||
@@ -28,82 +29,58 @@ import net.kyori.adventure.sound.SoundStop;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ClientboundStopSoundPacket implements MinecraftPacket {
|
||||
|
||||
private @Nullable Sound.Source source;
|
||||
private @Nullable Key soundName;
|
||||
|
||||
public ClientboundStopSoundPacket() {}
|
||||
public record ClientboundStopSoundPacket(@Nullable Sound.Source source,
|
||||
@Nullable Key soundName) implements MinecraftPacket {
|
||||
|
||||
public ClientboundStopSoundPacket(SoundStop soundStop) {
|
||||
this(soundStop.source(), soundStop.sound());
|
||||
}
|
||||
|
||||
public ClientboundStopSoundPacket(@Nullable Sound.Source source, @Nullable Key soundName) {
|
||||
this.source = source;
|
||||
this.soundName = soundName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
int flagsBitmask = buf.readByte();
|
||||
|
||||
if ((flagsBitmask & 1) != 0) {
|
||||
source = ProtocolUtils.readSoundSource(buf, protocolVersion);
|
||||
} else {
|
||||
source = null;
|
||||
}
|
||||
|
||||
if ((flagsBitmask & 2) != 0) {
|
||||
soundName = ProtocolUtils.readKey(buf);
|
||||
} else {
|
||||
soundName = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
int flagsBitmask = 0;
|
||||
if (source != null && soundName == null) {
|
||||
flagsBitmask |= 1;
|
||||
} else if (soundName != null && source == null) {
|
||||
flagsBitmask |= 2;
|
||||
} else if (source != null /*&& sound != null*/) {
|
||||
flagsBitmask |= 3;
|
||||
}
|
||||
|
||||
buf.writeByte(flagsBitmask);
|
||||
|
||||
if (source != null) {
|
||||
ProtocolUtils.writeSoundSource(buf, protocolVersion, source);
|
||||
}
|
||||
|
||||
if (soundName != null) {
|
||||
ProtocolUtils.writeMinimalKey(buf, soundName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Sound.Source getSource() {
|
||||
return source;
|
||||
}
|
||||
public static class Codec implements PacketCodec<ClientboundStopSoundPacket> {
|
||||
@Override
|
||||
public ClientboundStopSoundPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int flagsBitmask = buf.readByte();
|
||||
|
||||
public void setSource(@Nullable Sound.Source source) {
|
||||
this.source = source;
|
||||
}
|
||||
Sound.Source source = null;
|
||||
if ((flagsBitmask & 1) != 0) {
|
||||
source = ProtocolUtils.readSoundSource(buf, protocolVersion);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Key getSoundName() {
|
||||
return soundName;
|
||||
}
|
||||
Key soundName = null;
|
||||
if ((flagsBitmask & 2) != 0) {
|
||||
soundName = ProtocolUtils.readKey(buf);
|
||||
}
|
||||
|
||||
public void setSoundName(@Nullable Key soundName) {
|
||||
this.soundName = soundName;
|
||||
}
|
||||
return new ClientboundStopSoundPacket(source, soundName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientboundStopSoundPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
int flagsBitmask = 0;
|
||||
if (packet.source != null && packet.soundName == null) {
|
||||
flagsBitmask |= 1;
|
||||
} else if (packet.soundName != null && packet.source == null) {
|
||||
flagsBitmask |= 2;
|
||||
} else if (packet.source != null /*&& sound != null*/) {
|
||||
flagsBitmask |= 3;
|
||||
}
|
||||
|
||||
buf.writeByte(flagsBitmask);
|
||||
|
||||
if (packet.source != null) {
|
||||
ProtocolUtils.writeSoundSource(buf, protocolVersion, packet.source);
|
||||
}
|
||||
|
||||
if (packet.soundName != null) {
|
||||
ProtocolUtils.writeMinimalKey(buf, packet.soundName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,46 +20,32 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
public class ClientboundStoreCookiePacket implements MinecraftPacket {
|
||||
|
||||
private Key key;
|
||||
private byte[] payload;
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public ClientboundStoreCookiePacket() {
|
||||
}
|
||||
|
||||
public ClientboundStoreCookiePacket(final Key key, final byte[] payload) {
|
||||
this.key = key;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.key = ProtocolUtils.readKey(buf);
|
||||
this.payload = ProtocolUtils.readByteArray(buf, 5120);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, key);
|
||||
ProtocolUtils.writeByteArray(buf, payload);
|
||||
}
|
||||
public record ClientboundStoreCookiePacket(Key key, byte[] payload) implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ClientboundStoreCookiePacket> {
|
||||
@Override
|
||||
public ClientboundStoreCookiePacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new ClientboundStoreCookiePacket(ProtocolUtils.readKey(buf),
|
||||
ProtocolUtils.readByteArray(buf, 5120));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientboundStoreCookiePacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, packet.key);
|
||||
ProtocolUtils.writeByteArray(buf, packet.payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,26 +20,32 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class DialogClearPacket implements MinecraftPacket {
|
||||
public final class DialogClearPacket implements MinecraftPacket {
|
||||
|
||||
public static final DialogClearPacket INSTANCE = new DialogClearPacket();
|
||||
|
||||
private DialogClearPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<DialogClearPacket> {
|
||||
@Override
|
||||
public DialogClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(DialogClearPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,45 +20,71 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
|
||||
public class DialogShowPacket implements MinecraftPacket {
|
||||
public final class DialogShowPacket implements MinecraftPacket {
|
||||
|
||||
private final StateRegistry state;
|
||||
private int id;
|
||||
private BinaryTag nbt;
|
||||
private final int id;
|
||||
private final BinaryTag nbt;
|
||||
|
||||
public DialogShowPacket(final StateRegistry state) {
|
||||
public DialogShowPacket(StateRegistry state, int id, BinaryTag nbt) {
|
||||
this.state = state;
|
||||
this.id = id;
|
||||
this.nbt = nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.id = this.state == StateRegistry.CONFIG ? 0 : ProtocolUtils.readVarInt(buf);
|
||||
if (this.id == 0) {
|
||||
this.nbt = ProtocolUtils.readBinaryTag(buf, protocolVersion, BinaryTagIO.reader());
|
||||
}
|
||||
public StateRegistry state() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (this.state == StateRegistry.CONFIG) {
|
||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, this.id);
|
||||
if (this.id == 0) {
|
||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
||||
}
|
||||
}
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public BinaryTag nbt() {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<DialogShowPacket> {
|
||||
private final StateRegistry state;
|
||||
|
||||
public Codec(StateRegistry state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogShowPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int id = state == StateRegistry.CONFIG ? 0 : ProtocolUtils.readVarInt(buf);
|
||||
BinaryTag nbt = null;
|
||||
if (id == 0) {
|
||||
nbt = ProtocolUtils.readBinaryTag(buf, protocolVersion, BinaryTagIO.reader());
|
||||
}
|
||||
return new DialogShowPacket(state, id, nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(DialogShowPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (packet.state == StateRegistry.CONFIG) {
|
||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, packet.nbt);
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, packet.id);
|
||||
if (packet.id == 0) {
|
||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, packet.nbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,36 +21,36 @@ import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class DisconnectPacket implements MinecraftPacket {
|
||||
public final class DisconnectPacket implements MinecraftPacket {
|
||||
|
||||
private @Nullable ComponentHolder reason;
|
||||
private final ComponentHolder reason;
|
||||
private final StateRegistry state;
|
||||
|
||||
public DisconnectPacket(StateRegistry state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
private DisconnectPacket(StateRegistry state, ComponentHolder reason) {
|
||||
public DisconnectPacket(StateRegistry state, ComponentHolder reason) {
|
||||
this.state = state;
|
||||
this.reason = Preconditions.checkNotNull(reason, "reason");
|
||||
}
|
||||
|
||||
public ComponentHolder getReason() {
|
||||
public ComponentHolder reason() {
|
||||
if (reason == null) {
|
||||
throw new IllegalStateException("No reason specified");
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
public void setReason(@Nullable ComponentHolder reason) {
|
||||
this.reason = reason;
|
||||
public ComponentHolder getReason() {
|
||||
return reason();
|
||||
}
|
||||
|
||||
public StateRegistry state() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,25 +60,37 @@ public class DisconnectPacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN
|
||||
? ProtocolVersion.MINECRAFT_1_20_2 : version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
getReason().write(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static DisconnectPacket create(Component component, ProtocolVersion version, StateRegistry state) {
|
||||
public static DisconnectPacket create(Component component, ProtocolVersion version,
|
||||
StateRegistry state) {
|
||||
Preconditions.checkNotNull(component, "component");
|
||||
return new DisconnectPacket(state, new ComponentHolder(state == StateRegistry.LOGIN
|
||||
? ProtocolVersion.MINECRAFT_1_20_2 : version, component));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<DisconnectPacket> {
|
||||
private final StateRegistry state;
|
||||
|
||||
public Codec(StateRegistry state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisconnectPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ComponentHolder reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN
|
||||
? ProtocolVersion.MINECRAFT_1_20_2 : protocolVersion);
|
||||
return new DisconnectPacket(state, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(DisconnectPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
packet.reason().write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,36 +17,52 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EncryptionRequestPacket implements MinecraftPacket {
|
||||
public final class EncryptionRequestPacket implements MinecraftPacket {
|
||||
|
||||
private String serverId = "";
|
||||
private byte[] publicKey = EMPTY_BYTE_ARRAY;
|
||||
private byte[] verifyToken = EMPTY_BYTE_ARRAY;
|
||||
private boolean shouldAuthenticate = true;
|
||||
private final String serverId;
|
||||
private final byte[] publicKey;
|
||||
private final byte[] verifyToken;
|
||||
private final boolean shouldAuthenticate;
|
||||
|
||||
public byte[] getPublicKey() {
|
||||
public EncryptionRequestPacket(String serverId, byte[] publicKey, byte[] verifyToken,
|
||||
boolean shouldAuthenticate) {
|
||||
this.serverId = serverId;
|
||||
this.publicKey = publicKey.clone();
|
||||
this.verifyToken = verifyToken.clone();
|
||||
this.shouldAuthenticate = shouldAuthenticate;
|
||||
}
|
||||
|
||||
public String serverId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
public byte[] publicKey() {
|
||||
return publicKey.clone();
|
||||
}
|
||||
|
||||
public void setPublicKey(byte[] publicKey) {
|
||||
this.publicKey = publicKey.clone();
|
||||
}
|
||||
|
||||
public byte[] getVerifyToken() {
|
||||
public byte[] verifyToken() {
|
||||
return verifyToken.clone();
|
||||
}
|
||||
|
||||
public void setVerifyToken(byte[] verifyToken) {
|
||||
this.verifyToken = verifyToken.clone();
|
||||
public boolean shouldAuthenticate() {
|
||||
return shouldAuthenticate;
|
||||
}
|
||||
|
||||
public byte[] getPublicKey() {
|
||||
return publicKey();
|
||||
}
|
||||
|
||||
public byte[] getVerifyToken() {
|
||||
return verifyToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,40 +73,49 @@ public class EncryptionRequestPacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.serverId = ProtocolUtils.readString(buf, 20);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
publicKey = ProtocolUtils.readByteArray(buf, 256);
|
||||
verifyToken = ProtocolUtils.readByteArray(buf, 16);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
shouldAuthenticate = buf.readBoolean();
|
||||
}
|
||||
} else {
|
||||
publicKey = ProtocolUtils.readByteArray17(buf);
|
||||
verifyToken = ProtocolUtils.readByteArray17(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeString(buf, this.serverId);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeByteArray(buf, publicKey);
|
||||
ProtocolUtils.writeByteArray(buf, verifyToken);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(shouldAuthenticate);
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeByteArray17(publicKey, buf, false);
|
||||
ProtocolUtils.writeByteArray17(verifyToken, buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<EncryptionRequestPacket> {
|
||||
@Override
|
||||
public EncryptionRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String serverId = ProtocolUtils.readString(buf, 20);
|
||||
byte[] publicKey;
|
||||
byte[] verifyToken;
|
||||
boolean shouldAuthenticate = true;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
publicKey = ProtocolUtils.readByteArray(buf, 256);
|
||||
verifyToken = ProtocolUtils.readByteArray(buf, 16);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
shouldAuthenticate = buf.readBoolean();
|
||||
}
|
||||
} else {
|
||||
publicKey = ProtocolUtils.readByteArray17(buf);
|
||||
verifyToken = ProtocolUtils.readByteArray17(buf);
|
||||
}
|
||||
|
||||
return new EncryptionRequestPacket(serverId, publicKey, verifyToken, shouldAuthenticate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncryptionRequestPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
ProtocolUtils.writeString(buf, packet.serverId);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeByteArray(buf, packet.publicKey);
|
||||
ProtocolUtils.writeByteArray(buf, packet.verifyToken);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(packet.shouldAuthenticate);
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeByteArray17(packet.publicKey, buf, false);
|
||||
ProtocolUtils.writeByteArray17(packet.verifyToken, buf, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,43 +17,60 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EncryptionResponsePacket implements MinecraftPacket {
|
||||
public final class EncryptionResponsePacket implements MinecraftPacket {
|
||||
|
||||
private static final QuietDecoderException NO_SALT = new QuietDecoderException(
|
||||
"Encryption response didn't contain salt");
|
||||
|
||||
private byte[] sharedSecret = EMPTY_BYTE_ARRAY;
|
||||
private byte[] verifyToken = EMPTY_BYTE_ARRAY;
|
||||
private @Nullable Long salt;
|
||||
private final byte[] sharedSecret;
|
||||
private final byte[] verifyToken;
|
||||
private final @Nullable Long salt;
|
||||
|
||||
public byte[] getSharedSecret() {
|
||||
public EncryptionResponsePacket(byte[] sharedSecret, byte[] verifyToken, @Nullable Long salt) {
|
||||
this.sharedSecret = sharedSecret.clone();
|
||||
this.verifyToken = verifyToken.clone();
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public byte[] sharedSecret() {
|
||||
return sharedSecret.clone();
|
||||
}
|
||||
|
||||
public byte[] getVerifyToken() {
|
||||
public byte[] verifyToken() {
|
||||
return verifyToken.clone();
|
||||
}
|
||||
|
||||
public long getSalt() {
|
||||
public long salt() {
|
||||
if (salt == null) {
|
||||
throw NO_SALT;
|
||||
}
|
||||
return salt;
|
||||
}
|
||||
|
||||
public byte[] getSharedSecret() {
|
||||
return sharedSecret();
|
||||
}
|
||||
|
||||
public byte[] getVerifyToken() {
|
||||
return verifyToken();
|
||||
}
|
||||
|
||||
public long getSalt() {
|
||||
return salt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EncryptionResponse{"
|
||||
@@ -62,73 +79,85 @@ public class EncryptionResponsePacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
this.sharedSecret = ProtocolUtils.readByteArray(buf, 128);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)
|
||||
&& !buf.readBoolean()) {
|
||||
salt = buf.readLong();
|
||||
}
|
||||
|
||||
this.verifyToken = ProtocolUtils.readByteArray(buf,
|
||||
version.noLessThan(ProtocolVersion.MINECRAFT_1_19) ? 256 : 128);
|
||||
} else {
|
||||
this.sharedSecret = ProtocolUtils.readByteArray17(buf);
|
||||
this.verifyToken = ProtocolUtils.readByteArray17(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeByteArray(buf, sharedSecret);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
if (salt != null) {
|
||||
buf.writeBoolean(false);
|
||||
buf.writeLong(salt);
|
||||
} else {
|
||||
buf.writeBoolean(true);
|
||||
}
|
||||
}
|
||||
ProtocolUtils.writeByteArray(buf, verifyToken);
|
||||
} else {
|
||||
ProtocolUtils.writeByteArray17(sharedSecret, buf, false);
|
||||
ProtocolUtils.writeByteArray17(verifyToken, buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
|
||||
// The length prefix always winds up being 2 bytes.
|
||||
int base = 256 + 2 + 2;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
return base + 128;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
// Verify token is twice as long on 1.19+
|
||||
// Additional 1 byte for left <> right and 8 bytes for salt
|
||||
base += 128 + 8 + 1;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
public static class Codec implements PacketCodec<EncryptionResponsePacket> {
|
||||
@Override
|
||||
public EncryptionResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
byte[] sharedSecret;
|
||||
byte[] verifyToken;
|
||||
Long salt = null;
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
int base = decodeExpectedMaxLength(buf, direction, version);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
// These are "optional"
|
||||
base -= 128 + 8;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
sharedSecret = ProtocolUtils.readByteArray(buf, 128);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)
|
||||
&& !buf.readBoolean()) {
|
||||
salt = buf.readLong();
|
||||
}
|
||||
|
||||
verifyToken = ProtocolUtils.readByteArray(buf,
|
||||
version.noLessThan(ProtocolVersion.MINECRAFT_1_19) ? 256 : 128);
|
||||
} else {
|
||||
sharedSecret = ProtocolUtils.readByteArray17(buf);
|
||||
verifyToken = ProtocolUtils.readByteArray17(buf);
|
||||
}
|
||||
|
||||
return new EncryptionResponsePacket(sharedSecret, verifyToken, salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(EncryptionResponsePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeByteArray(buf, packet.sharedSecret);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
if (packet.salt != null) {
|
||||
buf.writeBoolean(false);
|
||||
buf.writeLong(packet.salt);
|
||||
} else {
|
||||
buf.writeBoolean(true);
|
||||
}
|
||||
}
|
||||
ProtocolUtils.writeByteArray(buf, packet.verifyToken);
|
||||
} else {
|
||||
ProtocolUtils.writeByteArray17(packet.sharedSecret, buf, false);
|
||||
ProtocolUtils.writeByteArray17(packet.verifyToken, buf, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
|
||||
// The length prefix always winds up being 2 bytes.
|
||||
int base = 256 + 2 + 2;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
return base + 128;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
// Verify token is twice as long on 1.19+
|
||||
// Additional 1 byte for left <> right and 8 bytes for salt
|
||||
base += 128 + 8 + 1;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
int base = decodeExpectedMaxLength(buf, direction, version);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
// These are "optional"
|
||||
base -= 128 + 8;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,58 +23,71 @@ import com.velocitypowered.api.network.HandshakeIntent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class HandshakePacket implements MinecraftPacket {
|
||||
public final class HandshakePacket implements MinecraftPacket {
|
||||
|
||||
// This size was chosen to ensure Forge clients can still connect even with very long hostnames.
|
||||
// While DNS technically allows any character to be used, in practice ASCII is used.
|
||||
private static final int MAXIMUM_HOSTNAME_LENGTH = 255 + HANDSHAKE_HOSTNAME_TOKEN.length() + 1;
|
||||
private ProtocolVersion protocolVersion;
|
||||
private String serverAddress = "";
|
||||
private int port;
|
||||
private HandshakeIntent intent;
|
||||
private int nextStatus;
|
||||
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
return protocolVersion;
|
||||
private final ProtocolVersion protocolVersion;
|
||||
private final String serverAddress;
|
||||
private final int port;
|
||||
private final HandshakeIntent intent;
|
||||
private final int nextStatus;
|
||||
|
||||
public HandshakePacket() {
|
||||
this(ProtocolVersion.MINIMUM_VERSION, "", 0, HandshakeIntent.LOGIN);
|
||||
}
|
||||
|
||||
public void setProtocolVersion(ProtocolVersion protocolVersion) {
|
||||
public HandshakePacket(ProtocolVersion protocolVersion, String serverAddress, int port,
|
||||
HandshakeIntent intent) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
public String getServerAddress() {
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
public void setServerAddress(String serverAddress) {
|
||||
this.serverAddress = serverAddress;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getNextStatus() {
|
||||
return this.nextStatus;
|
||||
}
|
||||
|
||||
public void setIntent(HandshakeIntent intent) {
|
||||
this.intent = intent;
|
||||
this.nextStatus = intent.id();
|
||||
}
|
||||
|
||||
public HandshakeIntent getIntent() {
|
||||
public ProtocolVersion protocolVersion() {
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
public String serverAddress() {
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
public int port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public int nextStatus() {
|
||||
return this.nextStatus;
|
||||
}
|
||||
|
||||
public HandshakeIntent intent() {
|
||||
return this.intent;
|
||||
}
|
||||
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
return protocolVersion();
|
||||
}
|
||||
|
||||
public String getServerAddress() {
|
||||
return serverAddress();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port();
|
||||
}
|
||||
|
||||
public HandshakeIntent getIntent() {
|
||||
return intent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Handshake{"
|
||||
@@ -85,45 +98,50 @@ public class HandshakePacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion ignored) {
|
||||
int realProtocolVersion = ProtocolUtils.readVarInt(buf);
|
||||
this.protocolVersion = ProtocolVersion.getProtocolVersion(realProtocolVersion);
|
||||
this.serverAddress = ProtocolUtils.readString(buf, MAXIMUM_HOSTNAME_LENGTH);
|
||||
this.port = buf.readUnsignedShort();
|
||||
this.nextStatus = ProtocolUtils.readVarInt(buf);
|
||||
this.intent = HandshakeIntent.getById(nextStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion ignored) {
|
||||
ProtocolUtils.writeVarInt(buf, this.protocolVersion.getProtocol());
|
||||
ProtocolUtils.writeString(buf, this.serverAddress);
|
||||
buf.writeShort(this.port);
|
||||
ProtocolUtils.writeVarInt(buf, this.nextStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 7;
|
||||
}
|
||||
public static class Codec implements PacketCodec<HandshakePacket> {
|
||||
@Override
|
||||
public HandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion ignored) {
|
||||
int realProtocolVersion = ProtocolUtils.readVarInt(buf);
|
||||
ProtocolVersion protocolVersion = ProtocolVersion.getProtocolVersion(realProtocolVersion);
|
||||
String serverAddress = ProtocolUtils.readString(buf, MAXIMUM_HOSTNAME_LENGTH);
|
||||
int port = buf.readUnsignedShort();
|
||||
int nextStatus = ProtocolUtils.readVarInt(buf);
|
||||
HandshakeIntent intent = HandshakeIntent.getById(nextStatus);
|
||||
return new HandshakePacket(protocolVersion, serverAddress, port, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
||||
}
|
||||
@Override
|
||||
public void encode(HandshakePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion ignored) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.protocolVersion.getProtocol());
|
||||
ProtocolUtils.writeString(buf, packet.serverAddress);
|
||||
buf.writeShort(packet.port);
|
||||
ProtocolUtils.writeVarInt(buf, packet.nextStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||
// sizes of this packet.
|
||||
return 4 * 1024;
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(HandshakePacket packet, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||
// sizes of this packet.
|
||||
return 4 * 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,42 +21,18 @@ import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class HeaderAndFooterPacket implements MinecraftPacket {
|
||||
public record HeaderAndFooterPacket(ComponentHolder header,
|
||||
ComponentHolder footer) implements MinecraftPacket {
|
||||
|
||||
private final ComponentHolder header;
|
||||
private final ComponentHolder footer;
|
||||
|
||||
public HeaderAndFooterPacket() {
|
||||
throw new UnsupportedOperationException("Decode is not implemented");
|
||||
}
|
||||
|
||||
public HeaderAndFooterPacket(ComponentHolder header, ComponentHolder footer) {
|
||||
this.header = Preconditions.checkNotNull(header, "header");
|
||||
this.footer = Preconditions.checkNotNull(footer, "footer");
|
||||
}
|
||||
|
||||
public ComponentHolder getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public ComponentHolder getFooter() {
|
||||
return footer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException("Decode is not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
header.write(buf);
|
||||
footer.write(buf);
|
||||
public HeaderAndFooterPacket {
|
||||
Preconditions.checkNotNull(header, "header");
|
||||
Preconditions.checkNotNull(footer, "footer");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,4 +50,19 @@ public class HeaderAndFooterPacket implements MinecraftPacket {
|
||||
ComponentHolder empty = new ComponentHolder(version, Component.empty());
|
||||
return new HeaderAndFooterPacket(empty, empty);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<HeaderAndFooterPacket> {
|
||||
@Override
|
||||
public HeaderAndFooterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException("Decode is not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(HeaderAndFooterPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
packet.header.write(buf);
|
||||
packet.footer.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,62 +22,83 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
||||
import com.velocitypowered.proxy.protocol.*;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class JoinGamePacket implements MinecraftPacket {
|
||||
public final class JoinGamePacket implements MinecraftPacket {
|
||||
|
||||
private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024);
|
||||
private int entityId;
|
||||
private short gamemode;
|
||||
private int dimension;
|
||||
private long partialHashedSeed; // 1.15+
|
||||
private short difficulty;
|
||||
private boolean isHardcore;
|
||||
private int maxPlayers;
|
||||
private @Nullable String levelType;
|
||||
private int viewDistance; // 1.14+
|
||||
private boolean reducedDebugInfo;
|
||||
private boolean showRespawnScreen;
|
||||
private boolean doLimitedCrafting; // 1.20.2+
|
||||
private ImmutableSet<String> levelNames; // 1.16+
|
||||
private CompoundBinaryTag registry; // 1.16+
|
||||
private DimensionInfo dimensionInfo; // 1.16+
|
||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
||||
private short previousGamemode; // 1.16+
|
||||
private int simulationDistance; // 1.18+
|
||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
||||
private int portalCooldown; // 1.20+
|
||||
private int seaLevel; // 1.21.2+
|
||||
private boolean enforcesSecureChat; // 1.20.5+
|
||||
|
||||
private final int entityId;
|
||||
private final short gamemode;
|
||||
private final int dimension;
|
||||
private final long partialHashedSeed;
|
||||
private final short difficulty;
|
||||
private final boolean isHardcore;
|
||||
private final int maxPlayers;
|
||||
private final @Nullable String levelType;
|
||||
private final int viewDistance;
|
||||
private final boolean reducedDebugInfo;
|
||||
private final boolean showRespawnScreen;
|
||||
private final boolean doLimitedCrafting;
|
||||
private final ImmutableSet<String> levelNames;
|
||||
private final CompoundBinaryTag registry;
|
||||
private final DimensionInfo dimensionInfo;
|
||||
private final CompoundBinaryTag currentDimensionData;
|
||||
private final short previousGamemode;
|
||||
private final int simulationDistance;
|
||||
private final @Nullable Pair<String, Long> lastDeathPosition;
|
||||
private final int portalCooldown;
|
||||
private final int seaLevel;
|
||||
private final boolean enforcesSecureChat;
|
||||
|
||||
public JoinGamePacket(int entityId, short gamemode, int dimension, long partialHashedSeed,
|
||||
short difficulty, boolean isHardcore, int maxPlayers, @Nullable String levelType,
|
||||
int viewDistance, boolean reducedDebugInfo, boolean showRespawnScreen,
|
||||
boolean doLimitedCrafting, ImmutableSet<String> levelNames, CompoundBinaryTag registry,
|
||||
DimensionInfo dimensionInfo, CompoundBinaryTag currentDimensionData, short previousGamemode,
|
||||
int simulationDistance, @Nullable Pair<String, Long> lastDeathPosition, int portalCooldown,
|
||||
int seaLevel, boolean enforcesSecureChat) {
|
||||
this.entityId = entityId;
|
||||
this.gamemode = gamemode;
|
||||
this.dimension = dimension;
|
||||
this.partialHashedSeed = partialHashedSeed;
|
||||
this.difficulty = difficulty;
|
||||
this.isHardcore = isHardcore;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.levelType = levelType;
|
||||
this.viewDistance = viewDistance;
|
||||
this.reducedDebugInfo = reducedDebugInfo;
|
||||
this.showRespawnScreen = showRespawnScreen;
|
||||
this.doLimitedCrafting = doLimitedCrafting;
|
||||
this.levelNames = levelNames;
|
||||
this.registry = registry;
|
||||
this.dimensionInfo = dimensionInfo;
|
||||
this.currentDimensionData = currentDimensionData;
|
||||
this.previousGamemode = previousGamemode;
|
||||
this.simulationDistance = simulationDistance;
|
||||
this.lastDeathPosition = lastDeathPosition;
|
||||
this.portalCooldown = portalCooldown;
|
||||
this.seaLevel = seaLevel;
|
||||
this.enforcesSecureChat = enforcesSecureChat;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public short getGamemode() {
|
||||
return gamemode;
|
||||
}
|
||||
|
||||
public void setGamemode(short gamemode) {
|
||||
this.gamemode = gamemode;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public void setDimension(int dimension) {
|
||||
this.dimension = dimension;
|
||||
}
|
||||
|
||||
public long getPartialHashedSeed() {
|
||||
return partialHashedSeed;
|
||||
}
|
||||
@@ -86,74 +107,38 @@ public class JoinGamePacket implements MinecraftPacket {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public void setDifficulty(short difficulty) {
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
public void setMaxPlayers(int maxPlayers) {
|
||||
this.maxPlayers = maxPlayers;
|
||||
}
|
||||
|
||||
public @Nullable String getLevelType() {
|
||||
return levelType;
|
||||
}
|
||||
|
||||
public void setLevelType(@Nullable String levelType) {
|
||||
this.levelType = levelType;
|
||||
}
|
||||
|
||||
public int getViewDistance() {
|
||||
return viewDistance;
|
||||
}
|
||||
|
||||
public void setViewDistance(int viewDistance) {
|
||||
this.viewDistance = viewDistance;
|
||||
}
|
||||
|
||||
public boolean isReducedDebugInfo() {
|
||||
return reducedDebugInfo;
|
||||
}
|
||||
|
||||
public void setReducedDebugInfo(boolean reducedDebugInfo) {
|
||||
this.reducedDebugInfo = reducedDebugInfo;
|
||||
}
|
||||
|
||||
public DimensionInfo getDimensionInfo() {
|
||||
return dimensionInfo;
|
||||
}
|
||||
|
||||
public void setDimensionInfo(DimensionInfo dimensionInfo) {
|
||||
this.dimensionInfo = dimensionInfo;
|
||||
}
|
||||
|
||||
public short getPreviousGamemode() {
|
||||
return previousGamemode;
|
||||
}
|
||||
|
||||
public void setPreviousGamemode(short previousGamemode) {
|
||||
this.previousGamemode = previousGamemode;
|
||||
}
|
||||
|
||||
public boolean getIsHardcore() {
|
||||
return isHardcore;
|
||||
}
|
||||
|
||||
public void setIsHardcore(boolean isHardcore) {
|
||||
this.isHardcore = isHardcore;
|
||||
}
|
||||
|
||||
public boolean getDoLimitedCrafting() {
|
||||
return doLimitedCrafting;
|
||||
}
|
||||
|
||||
public void setDoLimitedCrafting(boolean doLimitedCrafting) {
|
||||
this.doLimitedCrafting = doLimitedCrafting;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCurrentDimensionData() {
|
||||
return currentDimensionData;
|
||||
}
|
||||
@@ -162,46 +147,34 @@ public class JoinGamePacket implements MinecraftPacket {
|
||||
return simulationDistance;
|
||||
}
|
||||
|
||||
public void setSimulationDistance(int simulationDistance) {
|
||||
this.simulationDistance = simulationDistance;
|
||||
}
|
||||
|
||||
public Pair<String, Long> getLastDeathPosition() {
|
||||
return lastDeathPosition;
|
||||
}
|
||||
|
||||
public void setLastDeathPosition(Pair<String, Long> lastDeathPosition) {
|
||||
this.lastDeathPosition = lastDeathPosition;
|
||||
}
|
||||
|
||||
public int getPortalCooldown() {
|
||||
return portalCooldown;
|
||||
}
|
||||
|
||||
public void setPortalCooldown(int portalCooldown) {
|
||||
this.portalCooldown = portalCooldown;
|
||||
}
|
||||
|
||||
public int getSeaLevel() {
|
||||
return seaLevel;
|
||||
}
|
||||
|
||||
public void setSeaLevel(int seaLevel) {
|
||||
this.seaLevel = seaLevel;
|
||||
}
|
||||
|
||||
public boolean getEnforcesSecureChat() {
|
||||
return this.enforcesSecureChat;
|
||||
}
|
||||
|
||||
public void setEnforcesSecureChat(final boolean enforcesSecureChat) {
|
||||
this.enforcesSecureChat = enforcesSecureChat;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public boolean getShowRespawnScreen() {
|
||||
return showRespawnScreen;
|
||||
}
|
||||
|
||||
public ImmutableSet<String> getLevelNames() {
|
||||
return levelNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" +
|
||||
@@ -217,306 +190,349 @@ public class JoinGamePacket implements MinecraftPacket {
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
// haha funny, they made 1.20.2 more complicated
|
||||
this.decode1202Up(buf, version);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
this.decode116Up(buf, version);
|
||||
} else {
|
||||
this.decodeLegacy(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
this.gamemode = buf.readByte();
|
||||
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||
this.gamemode &= ~0x08;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9_1)) {
|
||||
this.dimension = buf.readInt();
|
||||
} else {
|
||||
this.dimension = buf.readByte();
|
||||
}
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
this.difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
}
|
||||
this.maxPlayers = buf.readUnsignedByte();
|
||||
this.levelType = ProtocolUtils.readString(buf, 16);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_14)) {
|
||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
this.reducedDebugInfo = buf.readBoolean();
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
this.showRespawnScreen = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
private void decode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
this.isHardcore = buf.readBoolean();
|
||||
this.gamemode = buf.readByte();
|
||||
} else {
|
||||
this.gamemode = buf.readByte();
|
||||
this.isHardcore = (this.gamemode & 0x08) != 0;
|
||||
this.gamemode &= ~0x08;
|
||||
}
|
||||
this.previousGamemode = buf.readByte();
|
||||
|
||||
this.levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
this.registry = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
String dimensionIdentifier;
|
||||
String levelName = null;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
this.maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
this.maxPlayers = buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
this.simulationDistance = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
this.reducedDebugInfo = buf.readBoolean();
|
||||
this.showRespawnScreen = buf.readBoolean();
|
||||
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug, version);
|
||||
|
||||
// optional death location
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19) && buf.readBoolean()) {
|
||||
this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
this.portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:VariableDeclarationUsageDistance")
|
||||
private void decode1202Up(ByteBuf buf, ProtocolVersion version) {
|
||||
this.entityId = buf.readInt();
|
||||
this.isHardcore = buf.readBoolean();
|
||||
|
||||
this.levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
|
||||
this.maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
this.viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
this.simulationDistance = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
this.reducedDebugInfo = buf.readBoolean();
|
||||
this.showRespawnScreen = buf.readBoolean();
|
||||
this.doLimitedCrafting = buf.readBoolean();
|
||||
|
||||
String dimensionKey = "";
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
dimension = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
}
|
||||
String levelName = ProtocolUtils.readString(buf);
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
|
||||
this.gamemode = buf.readByte();
|
||||
this.previousGamemode = buf.readByte();
|
||||
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
this.dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
||||
|
||||
// optional death location
|
||||
if (buf.readBoolean()) {
|
||||
this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
|
||||
this.portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
this.seaLevel = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
this.enforcesSecureChat = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
// haha funny, they made 1.20.2 more complicated
|
||||
this.encode1202Up(buf, version);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
this.encode116Up(buf, version);
|
||||
} else {
|
||||
this.encodeLegacy(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(entityId);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
buf.writeBoolean(isHardcore);
|
||||
buf.writeByte(gamemode);
|
||||
} else {
|
||||
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9_1)) {
|
||||
buf.writeInt(dimension);
|
||||
} else {
|
||||
buf.writeByte(dimension);
|
||||
}
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
buf.writeByte(difficulty);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeLong(partialHashedSeed);
|
||||
}
|
||||
buf.writeByte(maxPlayers);
|
||||
if (levelType == null) {
|
||||
throw new IllegalStateException("No level type specified.");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, levelType);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_14)) {
|
||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeBoolean(reducedDebugInfo);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeBoolean(showRespawnScreen);
|
||||
}
|
||||
}
|
||||
|
||||
private void encode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(entityId);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
buf.writeBoolean(isHardcore);
|
||||
buf.writeByte(gamemode);
|
||||
} else {
|
||||
buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode);
|
||||
}
|
||||
buf.writeByte(previousGamemode);
|
||||
|
||||
ProtocolUtils.writeStringArray(buf, levelNames.toArray(String[]::new));
|
||||
ProtocolUtils.writeBinaryTag(buf, version, this.registry);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2) && version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeBinaryTag(buf, version, currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||
}
|
||||
|
||||
buf.writeLong(partialHashedSeed);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, maxPlayers);
|
||||
} else {
|
||||
buf.writeByte(maxPlayers);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
ProtocolUtils.writeVarInt(buf, simulationDistance);
|
||||
}
|
||||
|
||||
buf.writeBoolean(reducedDebugInfo);
|
||||
buf.writeBoolean(showRespawnScreen);
|
||||
|
||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(dimensionInfo.isFlat());
|
||||
|
||||
// optional death location
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, lastDeathPosition.key());
|
||||
buf.writeLong(lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
ProtocolUtils.writeVarInt(buf, portalCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
private void encode1202Up(ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(entityId);
|
||||
buf.writeBoolean(isHardcore);
|
||||
|
||||
ProtocolUtils.writeStringArray(buf, levelNames.toArray(String[]::new));
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, maxPlayers);
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, viewDistance);
|
||||
ProtocolUtils.writeVarInt(buf, simulationDistance);
|
||||
|
||||
buf.writeBoolean(reducedDebugInfo);
|
||||
buf.writeBoolean(showRespawnScreen);
|
||||
buf.writeBoolean(doLimitedCrafting);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
ProtocolUtils.writeVarInt(buf, dimension);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
}
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||
buf.writeLong(partialHashedSeed);
|
||||
|
||||
buf.writeByte(gamemode);
|
||||
buf.writeByte(previousGamemode);
|
||||
|
||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(dimensionInfo.isFlat());
|
||||
|
||||
// optional death location
|
||||
if (lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, lastDeathPosition.key());
|
||||
buf.writeLong(lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, portalCooldown);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, seaLevel);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(this.enforcesSecureChat);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<JoinGamePacket> {
|
||||
@Override
|
||||
public JoinGamePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
// haha funny, they made 1.20.2 more complicated
|
||||
return decode1202Up(buf, version);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
return decode116Up(buf, version);
|
||||
} else {
|
||||
return decodeLegacy(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(JoinGamePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
// haha funny, they made 1.20.2 more complicated
|
||||
encode1202Up(packet, buf, version);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
// Minecraft 1.16 and above have significantly more complicated logic for reading this packet,
|
||||
// so separate it out.
|
||||
encode116Up(packet, buf, version);
|
||||
} else {
|
||||
encodeLegacy(packet, buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
private static JoinGamePacket decodeLegacy(ByteBuf buf, ProtocolVersion version) {
|
||||
int entityId = buf.readInt();
|
||||
short gamemode = buf.readByte();
|
||||
boolean isHardcore = (gamemode & 0x08) != 0;
|
||||
gamemode &= ~0x08;
|
||||
|
||||
int dimension;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9_1)) {
|
||||
dimension = buf.readInt();
|
||||
} else {
|
||||
dimension = buf.readByte();
|
||||
}
|
||||
|
||||
short difficulty = 0;
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
long partialHashedSeed = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
partialHashedSeed = buf.readLong();
|
||||
}
|
||||
|
||||
int maxPlayers = buf.readUnsignedByte();
|
||||
String levelType = ProtocolUtils.readString(buf, 16);
|
||||
|
||||
int viewDistance = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_14)) {
|
||||
viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
boolean reducedDebugInfo = false;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
reducedDebugInfo = buf.readBoolean();
|
||||
}
|
||||
|
||||
boolean showRespawnScreen = true;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
showRespawnScreen = buf.readBoolean();
|
||||
}
|
||||
|
||||
return new JoinGamePacket(entityId, gamemode, dimension, partialHashedSeed, difficulty,
|
||||
isHardcore, maxPlayers, levelType, viewDistance, reducedDebugInfo, showRespawnScreen,
|
||||
false, ImmutableSet.of(), null, null, null, (short) 0, 0, null, 0, 0, false);
|
||||
}
|
||||
|
||||
private static JoinGamePacket decode116Up(ByteBuf buf, ProtocolVersion version) {
|
||||
int entityId = buf.readInt();
|
||||
boolean isHardcore;
|
||||
short gamemode;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
isHardcore = buf.readBoolean();
|
||||
gamemode = buf.readByte();
|
||||
} else {
|
||||
gamemode = buf.readByte();
|
||||
isHardcore = (gamemode & 0x08) != 0;
|
||||
gamemode &= ~0x08;
|
||||
}
|
||||
short previousGamemode = buf.readByte();
|
||||
|
||||
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
CompoundBinaryTag registry = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
|
||||
String dimensionIdentifier;
|
||||
String levelName = null;
|
||||
CompoundBinaryTag currentDimensionData = null;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
|
||||
long partialHashedSeed = buf.readLong();
|
||||
|
||||
int maxPlayers;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
maxPlayers = buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
int viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
int simulationDistance = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
simulationDistance = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
boolean reducedDebugInfo = buf.readBoolean();
|
||||
boolean showRespawnScreen = buf.readBoolean();
|
||||
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
DimensionInfo dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug, version);
|
||||
|
||||
Pair<String, Long> lastDeathPosition = null;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19) && buf.readBoolean()) {
|
||||
lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
|
||||
int portalCooldown = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
return new JoinGamePacket(entityId, gamemode, 0, partialHashedSeed, (short) 0, isHardcore,
|
||||
maxPlayers, null, viewDistance, reducedDebugInfo, showRespawnScreen, false, levelNames,
|
||||
registry, dimensionInfo, currentDimensionData, previousGamemode, simulationDistance,
|
||||
lastDeathPosition, portalCooldown, 0, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:VariableDeclarationUsageDistance")
|
||||
private static JoinGamePacket decode1202Up(ByteBuf buf, ProtocolVersion version) {
|
||||
int entityId = buf.readInt();
|
||||
boolean isHardcore = buf.readBoolean();
|
||||
|
||||
ImmutableSet<String> levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
|
||||
int maxPlayers = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
int viewDistance = ProtocolUtils.readVarInt(buf);
|
||||
int simulationDistance = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
boolean reducedDebugInfo = buf.readBoolean();
|
||||
boolean showRespawnScreen = buf.readBoolean();
|
||||
boolean doLimitedCrafting = buf.readBoolean();
|
||||
|
||||
int dimension = 0;
|
||||
String dimensionKey = "";
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
dimension = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
}
|
||||
String levelName = ProtocolUtils.readString(buf);
|
||||
long partialHashedSeed = buf.readLong();
|
||||
|
||||
short gamemode = buf.readByte();
|
||||
short previousGamemode = buf.readByte();
|
||||
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
DimensionInfo dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
||||
|
||||
Pair<String, Long> lastDeathPosition = null;
|
||||
if (buf.readBoolean()) {
|
||||
lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
|
||||
int portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
int seaLevel = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
seaLevel = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
boolean enforcesSecureChat = false;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
enforcesSecureChat = buf.readBoolean();
|
||||
}
|
||||
|
||||
return new JoinGamePacket(entityId, gamemode, dimension, partialHashedSeed, (short) 0,
|
||||
isHardcore, maxPlayers, null, viewDistance, reducedDebugInfo, showRespawnScreen,
|
||||
doLimitedCrafting, levelNames, null, dimensionInfo, null, previousGamemode,
|
||||
simulationDistance, lastDeathPosition, portalCooldown, seaLevel, enforcesSecureChat);
|
||||
}
|
||||
|
||||
private static void encodeLegacy(JoinGamePacket packet, ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(packet.entityId);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
buf.writeBoolean(packet.isHardcore);
|
||||
buf.writeByte(packet.gamemode);
|
||||
} else {
|
||||
buf.writeByte(packet.isHardcore ? packet.gamemode | 0x8 : packet.gamemode);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_9_1)) {
|
||||
buf.writeInt(packet.dimension);
|
||||
} else {
|
||||
buf.writeByte(packet.dimension);
|
||||
}
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
buf.writeByte(packet.difficulty);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeLong(packet.partialHashedSeed);
|
||||
}
|
||||
buf.writeByte(packet.maxPlayers);
|
||||
if (packet.levelType == null) {
|
||||
throw new IllegalStateException("No level type specified.");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.levelType);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_14)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.viewDistance);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeBoolean(packet.reducedDebugInfo);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeBoolean(packet.showRespawnScreen);
|
||||
}
|
||||
}
|
||||
|
||||
private static void encode116Up(JoinGamePacket packet, ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(packet.entityId);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
buf.writeBoolean(packet.isHardcore);
|
||||
buf.writeByte(packet.gamemode);
|
||||
} else {
|
||||
buf.writeByte(packet.isHardcore ? packet.gamemode | 0x8 : packet.gamemode);
|
||||
}
|
||||
buf.writeByte(packet.previousGamemode);
|
||||
|
||||
ProtocolUtils.writeStringArray(buf, packet.levelNames.toArray(String[]::new));
|
||||
ProtocolUtils.writeBinaryTag(buf, version, packet.registry);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2) && version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeBinaryTag(buf, version, packet.currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getRegistryIdentifier());
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getLevelName());
|
||||
}
|
||||
|
||||
buf.writeLong(packet.partialHashedSeed);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.maxPlayers);
|
||||
} else {
|
||||
buf.writeByte(packet.maxPlayers);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, packet.viewDistance);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_18)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.simulationDistance);
|
||||
}
|
||||
|
||||
buf.writeBoolean(packet.reducedDebugInfo);
|
||||
buf.writeBoolean(packet.showRespawnScreen);
|
||||
|
||||
buf.writeBoolean(packet.dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(packet.dimensionInfo.isFlat());
|
||||
|
||||
// optional death location
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (packet.lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, packet.lastDeathPosition.key());
|
||||
buf.writeLong(packet.lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.portalCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
private static void encode1202Up(JoinGamePacket packet, ByteBuf buf, ProtocolVersion version) {
|
||||
buf.writeInt(packet.entityId);
|
||||
buf.writeBoolean(packet.isHardcore);
|
||||
|
||||
ProtocolUtils.writeStringArray(buf, packet.levelNames.toArray(String[]::new));
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, packet.maxPlayers);
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, packet.viewDistance);
|
||||
ProtocolUtils.writeVarInt(buf, packet.simulationDistance);
|
||||
|
||||
buf.writeBoolean(packet.reducedDebugInfo);
|
||||
buf.writeBoolean(packet.showRespawnScreen);
|
||||
buf.writeBoolean(packet.doLimitedCrafting);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.dimension);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getRegistryIdentifier());
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getLevelName());
|
||||
buf.writeLong(packet.partialHashedSeed);
|
||||
|
||||
buf.writeByte(packet.gamemode);
|
||||
buf.writeByte(packet.previousGamemode);
|
||||
|
||||
buf.writeBoolean(packet.dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(packet.dimensionInfo.isFlat());
|
||||
|
||||
// optional death location
|
||||
if (packet.lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, packet.lastDeathPosition.key());
|
||||
buf.writeLong(packet.lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, packet.portalCooldown);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.seaLevel);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(packet.enforcesSecureChat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,21 +20,16 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class KeepAlivePacket implements MinecraftPacket {
|
||||
|
||||
private long randomId;
|
||||
public record KeepAlivePacket(long randomId) implements MinecraftPacket {
|
||||
|
||||
public long getRandomId() {
|
||||
return randomId;
|
||||
}
|
||||
|
||||
public void setRandomId(long randomId) {
|
||||
this.randomId = randomId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeepAlive{"
|
||||
@@ -42,30 +37,36 @@ public class KeepAlivePacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
randomId = buf.readLong();
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
randomId = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
randomId = buf.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
buf.writeLong(randomId);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeVarInt(buf, (int) randomId);
|
||||
} else {
|
||||
buf.writeInt((int) randomId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<KeepAlivePacket> {
|
||||
@Override
|
||||
public KeepAlivePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
long randomId;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
randomId = buf.readLong();
|
||||
} else if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
randomId = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
randomId = buf.readInt();
|
||||
}
|
||||
return new KeepAlivePacket(randomId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(KeepAlivePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
buf.writeLong(packet.randomId);
|
||||
} else if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeVarInt(buf, (int) packet.randomId);
|
||||
} else {
|
||||
buf.writeInt((int) packet.randomId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,23 +20,33 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class LegacyHandshakePacket implements MinecraftPacket {
|
||||
public final class LegacyHandshakePacket implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public static final LegacyHandshakePacket INSTANCE = new LegacyHandshakePacket();
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
private LegacyHandshakePacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<LegacyHandshakePacket> {
|
||||
@Override
|
||||
public LegacyHandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LegacyHandshakePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,14 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.legacyping.LegacyMinecraftPingVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LegacyPingPacket implements MinecraftPacket {
|
||||
public final class LegacyPingPacket implements MinecraftPacket {
|
||||
|
||||
private final LegacyMinecraftPingVersion version;
|
||||
private final @Nullable InetSocketAddress vhost;
|
||||
@@ -41,26 +42,38 @@ public class LegacyPingPacket implements MinecraftPacket {
|
||||
this.vhost = vhost;
|
||||
}
|
||||
|
||||
public LegacyMinecraftPingVersion getVersion() {
|
||||
public LegacyMinecraftPingVersion version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public @Nullable InetSocketAddress getVhost() {
|
||||
public @Nullable InetSocketAddress vhost() {
|
||||
return vhost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
public LegacyMinecraftPingVersion getVersion() {
|
||||
return version();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
public @Nullable InetSocketAddress getVhost() {
|
||||
return vhost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<LegacyPingPacket> {
|
||||
@Override
|
||||
public LegacyPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LegacyPingPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
@@ -33,22 +34,20 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LegacyPlayerListItemPacket implements MinecraftPacket {
|
||||
public final class LegacyPlayerListItemPacket implements MinecraftPacket {
|
||||
|
||||
public static final int ADD_PLAYER = 0;
|
||||
public static final int UPDATE_GAMEMODE = 1;
|
||||
public static final int UPDATE_LATENCY = 2;
|
||||
public static final int UPDATE_DISPLAY_NAME = 3;
|
||||
public static final int REMOVE_PLAYER = 4;
|
||||
private int action;
|
||||
private final List<Item> items = new ArrayList<>();
|
||||
|
||||
private final int action;
|
||||
private final List<Item> items;
|
||||
|
||||
public LegacyPlayerListItemPacket(int action, List<Item> items) {
|
||||
this.action = action;
|
||||
this.items.addAll(items);
|
||||
}
|
||||
|
||||
public LegacyPlayerListItemPacket() {
|
||||
this.items = ImmutableList.copyOf(items);
|
||||
}
|
||||
|
||||
public int getAction() {
|
||||
@@ -59,131 +58,137 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
action = ProtocolUtils.readVarInt(buf);
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Item item = new Item(ProtocolUtils.readUuid(buf));
|
||||
items.add(item);
|
||||
switch (action) {
|
||||
case ADD_PLAYER:
|
||||
item.setName(ProtocolUtils.readString(buf));
|
||||
item.setProperties(ProtocolUtils.readProperties(buf));
|
||||
item.setGameMode(ProtocolUtils.readVarInt(buf));
|
||||
item.setLatency(ProtocolUtils.readVarInt(buf));
|
||||
item.setDisplayName(readOptionalComponent(buf, version));
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (buf.readBoolean()) {
|
||||
item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
item.setGameMode(ProtocolUtils.readVarInt(buf));
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
item.setLatency(ProtocolUtils.readVarInt(buf));
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
item.setDisplayName(readOptionalComponent(buf, version));
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
//Do nothing, all that is needed is the uuid
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Item item = new Item();
|
||||
item.setName(ProtocolUtils.readString(buf));
|
||||
action = buf.readBoolean() ? ADD_PLAYER : REMOVE_PLAYER;
|
||||
item.setLatency(buf.readShort());
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Component readOptionalComponent(ByteBuf buf, ProtocolVersion version) {
|
||||
if (buf.readBoolean()) {
|
||||
return ProtocolUtils.getJsonChatSerializer(version)
|
||||
.deserialize(ProtocolUtils.readString(buf));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeVarInt(buf, action);
|
||||
ProtocolUtils.writeVarInt(buf, items.size());
|
||||
for (Item item : items) {
|
||||
UUID uuid = item.getUuid();
|
||||
assert uuid != null : "UUID-less entry serialization attempt - 1.7 component!";
|
||||
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
switch (action) {
|
||||
case ADD_PLAYER:
|
||||
ProtocolUtils.writeString(buf, item.getName());
|
||||
ProtocolUtils.writeProperties(buf, item.getProperties());
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (item.getPlayerKey() != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writePlayerKey(buf, item.getPlayerKey());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
// Do nothing, all that is needed is the uuid
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Item item = items.get(0);
|
||||
Component displayNameComponent = item.getDisplayName();
|
||||
if (displayNameComponent != null) {
|
||||
String displayName = LegacyComponentSerializer.legacySection()
|
||||
.serialize(displayNameComponent);
|
||||
ProtocolUtils.writeString(buf,
|
||||
displayName.length() > 16 ? displayName.substring(0, 16) : displayName);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, item.getName());
|
||||
}
|
||||
buf.writeBoolean(action != REMOVE_PLAYER);
|
||||
buf.writeShort(item.getLatency());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
private void writeDisplayName(ByteBuf buf, @Nullable Component displayName,
|
||||
ProtocolVersion version) {
|
||||
buf.writeBoolean(displayName != null);
|
||||
if (displayName != null) {
|
||||
ProtocolUtils.writeString(buf, ProtocolUtils.getJsonChatSerializer(version)
|
||||
.serialize(displayName));
|
||||
public static class Codec implements PacketCodec<LegacyPlayerListItemPacket> {
|
||||
@Override
|
||||
public LegacyPlayerListItemPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
int action = ProtocolUtils.readVarInt(buf);
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
List<Item> items = new ArrayList<>(length);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
Item item = new Item(ProtocolUtils.readUuid(buf));
|
||||
items.add(item);
|
||||
switch (action) {
|
||||
case ADD_PLAYER:
|
||||
item.setName(ProtocolUtils.readString(buf));
|
||||
item.setProperties(ProtocolUtils.readProperties(buf));
|
||||
item.setGameMode(ProtocolUtils.readVarInt(buf));
|
||||
item.setLatency(ProtocolUtils.readVarInt(buf));
|
||||
item.setDisplayName(readOptionalComponent(buf, version));
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (buf.readBoolean()) {
|
||||
item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
item.setGameMode(ProtocolUtils.readVarInt(buf));
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
item.setLatency(ProtocolUtils.readVarInt(buf));
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
item.setDisplayName(readOptionalComponent(buf, version));
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
//Do nothing, all that is needed is the uuid
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + action);
|
||||
}
|
||||
}
|
||||
return new LegacyPlayerListItemPacket(action, items);
|
||||
} else {
|
||||
Item item = new Item();
|
||||
item.setName(ProtocolUtils.readString(buf));
|
||||
int action = buf.readBoolean() ? ADD_PLAYER : REMOVE_PLAYER;
|
||||
item.setLatency(buf.readShort());
|
||||
return new LegacyPlayerListItemPacket(action, ImmutableList.of(item));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LegacyPlayerListItemPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.action);
|
||||
ProtocolUtils.writeVarInt(buf, packet.items.size());
|
||||
for (Item item : packet.items) {
|
||||
UUID uuid = item.getUuid();
|
||||
assert uuid != null : "UUID-less entry serialization attempt - 1.7 component!";
|
||||
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
switch (packet.action) {
|
||||
case ADD_PLAYER:
|
||||
ProtocolUtils.writeString(buf, item.getName());
|
||||
ProtocolUtils.writeProperties(buf, item.getProperties());
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (item.getPlayerKey() != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writePlayerKey(buf, item.getPlayerKey());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_GAMEMODE:
|
||||
ProtocolUtils.writeVarInt(buf, item.getGameMode());
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
ProtocolUtils.writeVarInt(buf, item.getLatency());
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
writeDisplayName(buf, item.getDisplayName(), version);
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
// Do nothing, all that is needed is the uuid
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + packet.action);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Item item = packet.items.get(0);
|
||||
Component displayNameComponent = item.getDisplayName();
|
||||
if (displayNameComponent != null) {
|
||||
String displayName = LegacyComponentSerializer.legacySection()
|
||||
.serialize(displayNameComponent);
|
||||
ProtocolUtils.writeString(buf,
|
||||
displayName.length() > 16 ? displayName.substring(0, 16) : displayName);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, item.getName());
|
||||
}
|
||||
buf.writeBoolean(packet.action != REMOVE_PLAYER);
|
||||
buf.writeShort(item.getLatency());
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Component readOptionalComponent(ByteBuf buf, ProtocolVersion version) {
|
||||
if (buf.readBoolean()) {
|
||||
return ProtocolUtils.getJsonChatSerializer(version)
|
||||
.deserialize(ProtocolUtils.readString(buf));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void writeDisplayName(ByteBuf buf, @Nullable Component displayName,
|
||||
ProtocolVersion version) {
|
||||
buf.writeBoolean(displayName != null);
|
||||
if (displayName != null) {
|
||||
ProtocolUtils.writeString(buf, ProtocolUtils.getJsonChatSerializer(version)
|
||||
.serialize(displayName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,29 +20,38 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class LoginAcknowledgedPacket implements MinecraftPacket {
|
||||
public final class LoginAcknowledgedPacket implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
public static final LoginAcknowledgedPacket INSTANCE = new LoginAcknowledgedPacket();
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 0;
|
||||
private LoginAcknowledgedPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<LoginAcknowledgedPacket> {
|
||||
@Override
|
||||
public LoginAcknowledgedPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LoginAcknowledgedPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,23 +20,19 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LoginPluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public final class LoginPluginMessagePacket extends DefaultByteBufHolder implements MinecraftPacket {
|
||||
|
||||
private int id;
|
||||
private @Nullable String channel;
|
||||
private final int id;
|
||||
private final String channel;
|
||||
|
||||
public LoginPluginMessagePacket() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public LoginPluginMessagePacket(int id, @Nullable String channel, ByteBuf data) {
|
||||
public LoginPluginMessagePacket(int id, String channel, ByteBuf data) {
|
||||
super(data);
|
||||
this.id = id;
|
||||
this.channel = channel;
|
||||
@@ -47,9 +43,6 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
if (channel == null) {
|
||||
throw new IllegalStateException("Channel is not specified!");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
@@ -62,34 +55,40 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.id = ProtocolUtils.readVarInt(buf);
|
||||
this.channel = ProtocolUtils.readString(buf);
|
||||
if (buf.isReadable()) {
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
} else {
|
||||
this.replace(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeVarInt(buf, id);
|
||||
if (channel == null) {
|
||||
throw new IllegalStateException("Channel is not specified!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, channel);
|
||||
buf.writeBytes(content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
public static class Codec implements PacketCodec<LoginPluginMessagePacket> {
|
||||
@Override
|
||||
public LoginPluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
int id = ProtocolUtils.readVarInt(buf);
|
||||
String channel = ProtocolUtils.readString(buf);
|
||||
ByteBuf data;
|
||||
if (buf.isReadable()) {
|
||||
data = buf.readRetainedSlice(buf.readableBytes());
|
||||
} else {
|
||||
data = Unpooled.EMPTY_BUFFER;
|
||||
}
|
||||
return new LoginPluginMessagePacket(id, channel, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LoginPluginMessagePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.id);
|
||||
ProtocolUtils.writeString(buf, packet.channel);
|
||||
buf.writeBytes(packet.content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(LoginPluginMessagePacket packet, Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return ProtocolUtils.varIntBytes(packet.id)
|
||||
+ ProtocolUtils.stringSizeHint(packet.channel)
|
||||
+ packet.content().readableBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,21 +20,18 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
public class LoginPluginResponsePacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public final class LoginPluginResponsePacket extends DefaultByteBufHolder
|
||||
implements MinecraftPacket {
|
||||
|
||||
private int id;
|
||||
private boolean success;
|
||||
|
||||
public LoginPluginResponsePacket() {
|
||||
super(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
private final int id;
|
||||
private final boolean success;
|
||||
|
||||
public LoginPluginResponsePacket(int id, boolean success, @MonotonicNonNull ByteBuf buf) {
|
||||
super(buf);
|
||||
@@ -42,20 +39,20 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
public boolean success() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
public int getId() {
|
||||
return id();
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,31 +64,36 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.id = ProtocolUtils.readVarInt(buf);
|
||||
this.success = buf.readBoolean();
|
||||
if (buf.isReadable()) {
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
} else {
|
||||
this.replace(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeVarInt(buf, id);
|
||||
buf.writeBoolean(success);
|
||||
buf.writeBytes(content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
public static class Codec implements PacketCodec<LoginPluginResponsePacket> {
|
||||
@Override
|
||||
public LoginPluginResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
int id = ProtocolUtils.readVarInt(buf);
|
||||
boolean success = buf.readBoolean();
|
||||
ByteBuf data;
|
||||
if (buf.isReadable()) {
|
||||
data = buf.readRetainedSlice(buf.readableBytes());
|
||||
} else {
|
||||
data = Unpooled.EMPTY_BUFFER;
|
||||
}
|
||||
return new LoginPluginResponsePacket(id, success, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LoginPluginResponsePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.id);
|
||||
buf.writeBoolean(packet.success);
|
||||
buf.writeBytes(packet.content());
|
||||
}
|
||||
|
||||
public int encodeSizeHint(LoginPluginResponsePacket packet, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
return ProtocolUtils.varIntBytes(packet.id) + 1 + packet.content().readableBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,30 +20,28 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class PingIdentifyPacket implements MinecraftPacket {
|
||||
|
||||
private int id;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ping{" + "id=" + id + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
id = buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
buf.writeInt(id);
|
||||
}
|
||||
public record PingIdentifyPacket(int id) implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<PingIdentifyPacket> {
|
||||
@Override
|
||||
public PingIdentifyPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new PingIdentifyPacket(buf.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PingIdentifyPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
buf.writeInt(packet.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,38 +22,24 @@ import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.transfor
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
|
||||
public class PluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public final class PluginMessagePacket extends DefaultByteBufHolder implements MinecraftPacket {
|
||||
|
||||
private @Nullable String channel;
|
||||
private final String channel;
|
||||
|
||||
public PluginMessagePacket() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public PluginMessagePacket(String channel,
|
||||
@MonotonicNonNull ByteBuf backing) {
|
||||
public PluginMessagePacket(String channel, ByteBuf backing) {
|
||||
super(backing);
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
if (channel == null) {
|
||||
throw new IllegalStateException("Channel is not specified.");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PluginMessage{"
|
||||
@@ -62,44 +48,6 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.channel = ProtocolUtils.readString(buf);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
this.channel = transformLegacyToModernChannel(this.channel);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
} else {
|
||||
this.replace(ProtocolUtils.readRetainedByteBufSlice17(buf));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (channel == null) {
|
||||
throw new IllegalStateException("Channel is not specified.");
|
||||
}
|
||||
|
||||
if (refCnt() == 0) {
|
||||
throw new IllegalStateException("Plugin message contents for " + this.channel
|
||||
+ " freed too many times.");
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeString(buf, transformLegacyToModernChannel(this.channel));
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, this.channel);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeBytes(content());
|
||||
} else {
|
||||
ProtocolUtils.writeByteBuf17(content(), buf, true); // True for Forge support
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
@@ -145,8 +93,41 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr
|
||||
return (PluginMessagePacket) super.touch(hint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
public static class Codec implements PacketCodec<PluginMessagePacket> {
|
||||
@Override
|
||||
public PluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String channel = ProtocolUtils.readString(buf);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
channel = transformLegacyToModernChannel(channel);
|
||||
}
|
||||
ByteBuf data;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
data = buf.readRetainedSlice(buf.readableBytes());
|
||||
} else {
|
||||
data = ProtocolUtils.readRetainedByteBufSlice17(buf);
|
||||
}
|
||||
return new PluginMessagePacket(channel, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PluginMessagePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (packet.refCnt() == 0) {
|
||||
throw new IllegalStateException("Plugin message contents for " + packet.channel
|
||||
+ " freed too many times.");
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeString(buf, transformLegacyToModernChannel(packet.channel));
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.channel);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeBytes(packet.content());
|
||||
} else {
|
||||
ProtocolUtils.writeByteBuf17(packet.content(), buf, true); // True for Forge support
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,54 +21,42 @@ import com.google.common.collect.Lists;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RemovePlayerInfoPacket implements MinecraftPacket {
|
||||
|
||||
private Collection<UUID> profilesToRemove;
|
||||
|
||||
public RemovePlayerInfoPacket() {
|
||||
this.profilesToRemove = new ArrayList<>();
|
||||
}
|
||||
|
||||
public RemovePlayerInfoPacket(Collection<UUID> profilesToRemove) {
|
||||
this.profilesToRemove = profilesToRemove;
|
||||
}
|
||||
public record RemovePlayerInfoPacket(Collection<UUID> profilesToRemove) implements MinecraftPacket {
|
||||
|
||||
public Collection<UUID> getProfilesToRemove() {
|
||||
return profilesToRemove;
|
||||
}
|
||||
|
||||
public void setProfilesToRemove(Collection<UUID> profilesToRemove) {
|
||||
this.profilesToRemove = profilesToRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
Collection<UUID> profilesToRemove = Lists.newArrayListWithCapacity(length);
|
||||
for (int idx = 0; idx < length; idx++) {
|
||||
profilesToRemove.add(ProtocolUtils.readUuid(buf));
|
||||
}
|
||||
this.profilesToRemove = profilesToRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, this.profilesToRemove.size());
|
||||
for (UUID uuid : this.profilesToRemove) {
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<RemovePlayerInfoPacket> {
|
||||
@Override
|
||||
public RemovePlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
Collection<UUID> profilesToRemove = Lists.newArrayListWithCapacity(length);
|
||||
for (int idx = 0; idx < length; idx++) {
|
||||
profilesToRemove.add(ProtocolUtils.readUuid(buf));
|
||||
}
|
||||
return new RemovePlayerInfoPacket(profilesToRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(RemovePlayerInfoPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.profilesToRemove.size());
|
||||
for (UUID uuid : packet.profilesToRemove) {
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,44 +20,42 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class RemoveResourcePackPacket implements MinecraftPacket {
|
||||
public record RemoveResourcePackPacket(@Nullable UUID id) implements MinecraftPacket {
|
||||
|
||||
private UUID id;
|
||||
|
||||
public RemoveResourcePackPacket() {
|
||||
}
|
||||
|
||||
public RemoveResourcePackPacket(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
public @Nullable UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (buf.readBoolean()) {
|
||||
this.id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
buf.writeBoolean(id != null);
|
||||
|
||||
if (id != null) {
|
||||
ProtocolUtils.writeUuid(buf, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<RemoveResourcePackPacket> {
|
||||
@Override
|
||||
public RemoveResourcePackPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
UUID id = null;
|
||||
if (buf.readBoolean()) {
|
||||
id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
return new RemoveResourcePackPacket(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(RemoveResourcePackPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeBoolean(packet.id != null);
|
||||
if (packet.id != null) {
|
||||
ProtocolUtils.writeUuid(buf, packet.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
@@ -30,100 +31,47 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ResourcePackRequestPacket implements MinecraftPacket {
|
||||
public final class ResourcePackRequestPacket implements MinecraftPacket {
|
||||
|
||||
private @MonotonicNonNull UUID id; // 1.20.3+
|
||||
private @MonotonicNonNull String url;
|
||||
private @MonotonicNonNull String hash;
|
||||
private boolean isRequired; // 1.17+
|
||||
private @Nullable ComponentHolder prompt; // 1.17+
|
||||
private final @Nullable UUID id; // 1.20.3+
|
||||
private final String url;
|
||||
private final String hash;
|
||||
private final boolean isRequired; // 1.17+
|
||||
private final @Nullable ComponentHolder prompt; // 1.17+
|
||||
|
||||
private static final Pattern PLAUSIBLE_SHA1_HASH = Pattern.compile("^[a-z0-9]{40}$"); // 1.20.2+
|
||||
|
||||
public ResourcePackRequestPacket(@Nullable UUID id, String url, String hash,
|
||||
boolean isRequired, @Nullable ComponentHolder prompt) {
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.hash = hash;
|
||||
this.isRequired = isRequired;
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
public @Nullable UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public @Nullable String getUrl() {
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return isRequired;
|
||||
}
|
||||
|
||||
public @Nullable String getHash() {
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void setHash(String hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
isRequired = required;
|
||||
}
|
||||
|
||||
public @Nullable ComponentHolder getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
public void setPrompt(@Nullable ComponentHolder prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
this.id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
this.url = ProtocolUtils.readString(buf);
|
||||
this.hash = ProtocolUtils.readString(buf);
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
this.isRequired = buf.readBoolean();
|
||||
if (buf.readBoolean()) {
|
||||
this.prompt = ComponentHolder.read(buf, protocolVersion);
|
||||
} else {
|
||||
this.prompt = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
if (id == null) {
|
||||
throw new IllegalStateException("Resource pack id not set yet!");
|
||||
}
|
||||
ProtocolUtils.writeUuid(buf, id);
|
||||
}
|
||||
if (url == null || hash == null) {
|
||||
throw new IllegalStateException("Packet not fully filled in yet!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, url);
|
||||
ProtocolUtils.writeString(buf, hash);
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
buf.writeBoolean(isRequired);
|
||||
if (prompt != null) {
|
||||
buf.writeBoolean(true);
|
||||
prompt.write(buf);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public VelocityResourcePackInfo toServerPromptedPack() {
|
||||
final ResourcePackInfo.Builder builder =
|
||||
new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url))
|
||||
@@ -153,4 +101,51 @@ public class ResourcePackRequestPacket implements MinecraftPacket {
|
||||
", prompt=" + prompt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ResourcePackRequestPacket> {
|
||||
@Override
|
||||
public ResourcePackRequestPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
UUID id = null;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
String url = ProtocolUtils.readString(buf);
|
||||
String hash = ProtocolUtils.readString(buf);
|
||||
boolean isRequired = false;
|
||||
ComponentHolder prompt = null;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
isRequired = buf.readBoolean();
|
||||
if (buf.readBoolean()) {
|
||||
prompt = ComponentHolder.read(buf, protocolVersion);
|
||||
}
|
||||
}
|
||||
return new ResourcePackRequestPacket(id, url, hash, isRequired, prompt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ResourcePackRequestPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
if (packet.id == null) {
|
||||
throw new IllegalStateException("Resource pack id not set yet!");
|
||||
}
|
||||
ProtocolUtils.writeUuid(buf, packet.id);
|
||||
}
|
||||
if (packet.url == null || packet.hash == null) {
|
||||
throw new IllegalStateException("Packet not fully filled in yet!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.url);
|
||||
ProtocolUtils.writeString(buf, packet.hash);
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
buf.writeBoolean(packet.isRequired);
|
||||
if (packet.prompt != null) {
|
||||
buf.writeBoolean(true);
|
||||
packet.prompt.write(buf);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,63 +21,26 @@ import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent.Status
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ResourcePackResponsePacket implements MinecraftPacket {
|
||||
public record ResourcePackResponsePacket(UUID id, String hash,
|
||||
Status status) implements MinecraftPacket {
|
||||
|
||||
private UUID id;
|
||||
private String hash = "";
|
||||
private @MonotonicNonNull Status status;
|
||||
|
||||
public ResourcePackResponsePacket() {
|
||||
}
|
||||
|
||||
public ResourcePackResponsePacket(UUID id, String hash, @MonotonicNonNull Status status) {
|
||||
this.id = id;
|
||||
this.hash = hash;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
if (status == null) {
|
||||
throw new IllegalStateException("Packet not yet deserialized");
|
||||
}
|
||||
return status;
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
this.id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
if (protocolVersion.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) {
|
||||
this.hash = ProtocolUtils.readString(buf);
|
||||
}
|
||||
this.status = Status.values()[ProtocolUtils.readVarInt(buf)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
ProtocolUtils.writeUuid(buf, id);
|
||||
}
|
||||
if (protocolVersion.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) {
|
||||
ProtocolUtils.writeString(buf, hash);
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, status.ordinal());
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,12 +48,32 @@ public class ResourcePackResponsePacket implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResourcePackResponsePacket{" +
|
||||
"id=" + id +
|
||||
", hash='" + hash + '\'' +
|
||||
", status=" + status +
|
||||
'}';
|
||||
public static class Codec implements PacketCodec<ResourcePackResponsePacket> {
|
||||
@Override
|
||||
public ResourcePackResponsePacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
UUID id = null;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
String hash = "";
|
||||
if (protocolVersion.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) {
|
||||
hash = ProtocolUtils.readString(buf);
|
||||
}
|
||||
Status status = Status.values()[ProtocolUtils.readVarInt(buf)];
|
||||
return new ResourcePackResponsePacket(id, hash, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ResourcePackResponsePacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||
ProtocolUtils.writeUuid(buf, packet.id);
|
||||
}
|
||||
if (protocolVersion.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) {
|
||||
ProtocolUtils.writeString(buf, packet.hash);
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, packet.status.ordinal());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
@@ -28,23 +29,20 @@ import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class RespawnPacket implements MinecraftPacket {
|
||||
public final class RespawnPacket implements MinecraftPacket {
|
||||
|
||||
private int dimension;
|
||||
private long partialHashedSeed;
|
||||
private short difficulty;
|
||||
private short gamemode;
|
||||
private String levelType = "";
|
||||
private byte dataToKeep; // 1.16+
|
||||
private DimensionInfo dimensionInfo; // 1.16-1.16.1
|
||||
private short previousGamemode; // 1.16+
|
||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
||||
private int portalCooldown; // 1.20+
|
||||
private int seaLevel; // 1.21.2+
|
||||
|
||||
public RespawnPacket() {
|
||||
}
|
||||
private final int dimension;
|
||||
private final long partialHashedSeed;
|
||||
private final short difficulty;
|
||||
private final short gamemode;
|
||||
private final String levelType;
|
||||
private final byte dataToKeep;
|
||||
private final DimensionInfo dimensionInfo;
|
||||
private final short previousGamemode;
|
||||
private final CompoundBinaryTag currentDimensionData;
|
||||
private final @Nullable Pair<String, Long> lastDeathPosition;
|
||||
private final int portalCooldown;
|
||||
private final int seaLevel;
|
||||
|
||||
public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode,
|
||||
String levelType, byte dataToKeep, DimensionInfo dimensionInfo,
|
||||
@@ -73,84 +71,60 @@ public class RespawnPacket implements MinecraftPacket {
|
||||
joinGame.getPortalCooldown(), joinGame.getSeaLevel());
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return dimension;
|
||||
public static RespawnPacket fromJoinGame(JoinGamePacket joinGame, int newDimension) {
|
||||
return new RespawnPacket(newDimension, joinGame.getPartialHashedSeed(),
|
||||
joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType(),
|
||||
(byte) 0, joinGame.getDimensionInfo(), joinGame.getPreviousGamemode(),
|
||||
joinGame.getCurrentDimensionData(), joinGame.getLastDeathPosition(),
|
||||
joinGame.getPortalCooldown(), joinGame.getSeaLevel());
|
||||
}
|
||||
|
||||
public void setDimension(int dimension) {
|
||||
this.dimension = dimension;
|
||||
public int getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public long getPartialHashedSeed() {
|
||||
return partialHashedSeed;
|
||||
}
|
||||
|
||||
public void setPartialHashedSeed(long partialHashedSeed) {
|
||||
this.partialHashedSeed = partialHashedSeed;
|
||||
}
|
||||
|
||||
public short getDifficulty() {
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public void setDifficulty(short difficulty) {
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
|
||||
public short getGamemode() {
|
||||
return gamemode;
|
||||
}
|
||||
|
||||
public void setGamemode(short gamemode) {
|
||||
this.gamemode = gamemode;
|
||||
}
|
||||
|
||||
public String getLevelType() {
|
||||
return levelType;
|
||||
}
|
||||
|
||||
public void setLevelType(String levelType) {
|
||||
this.levelType = levelType;
|
||||
}
|
||||
|
||||
public byte getDataToKeep() {
|
||||
return dataToKeep;
|
||||
}
|
||||
|
||||
public void setDataToKeep(byte dataToKeep) {
|
||||
this.dataToKeep = dataToKeep;
|
||||
}
|
||||
|
||||
public short getPreviousGamemode() {
|
||||
return previousGamemode;
|
||||
}
|
||||
|
||||
public void setPreviousGamemode(short previousGamemode) {
|
||||
this.previousGamemode = previousGamemode;
|
||||
}
|
||||
|
||||
public Pair<String, Long> getLastDeathPosition() {
|
||||
return lastDeathPosition;
|
||||
}
|
||||
|
||||
public void setLastDeathPosition(Pair<String, Long> lastDeathPosition) {
|
||||
this.lastDeathPosition = lastDeathPosition;
|
||||
}
|
||||
|
||||
public int getPortalCooldown() {
|
||||
return portalCooldown;
|
||||
}
|
||||
|
||||
public void setPortalCooldown(int portalCooldown) {
|
||||
this.portalCooldown = portalCooldown;
|
||||
}
|
||||
|
||||
public int getSeaLevel() {
|
||||
return seaLevel;
|
||||
}
|
||||
|
||||
public void setSeaLevel(int seaLevel) {
|
||||
this.seaLevel = seaLevel;
|
||||
public DimensionInfo getDimensionInfo() {
|
||||
return dimensionInfo;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getCurrentDimensionData() {
|
||||
return currentDimensionData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,124 +145,157 @@ public class RespawnPacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
String dimensionKey = "";
|
||||
String levelName = null;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, BinaryTagIO.reader());
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
dimension = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
}
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
} else {
|
||||
this.dimension = buf.readInt();
|
||||
}
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
this.difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
this.partialHashedSeed = buf.readLong();
|
||||
}
|
||||
this.gamemode = buf.readByte();
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
this.previousGamemode = buf.readByte();
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
this.dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
this.dataToKeep = (byte) (buf.readBoolean() ? 1 : 0);
|
||||
} else if (version.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
this.dataToKeep = buf.readByte();
|
||||
}
|
||||
} else {
|
||||
this.levelType = ProtocolUtils.readString(buf, 16);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19) && buf.readBoolean()) {
|
||||
this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
this.portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
this.seaLevel = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
this.dataToKeep = buf.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeBinaryTag(buf, version, currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
ProtocolUtils.writeVarInt(buf, dimension);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
}
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getLevelName());
|
||||
}
|
||||
} else {
|
||||
buf.writeInt(dimension);
|
||||
}
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
buf.writeByte(difficulty);
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeLong(partialHashedSeed);
|
||||
}
|
||||
buf.writeByte(gamemode);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
buf.writeByte(previousGamemode);
|
||||
buf.writeBoolean(dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(dimensionInfo.isFlat());
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.writeBoolean(dataToKeep != 0);
|
||||
} else if (version.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
buf.writeByte(dataToKeep);
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, levelType);
|
||||
}
|
||||
|
||||
// optional death location
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, lastDeathPosition.key());
|
||||
buf.writeLong(lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
ProtocolUtils.writeVarInt(buf, portalCooldown);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, seaLevel);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
buf.writeByte(dataToKeep);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<RespawnPacket> {
|
||||
@Override
|
||||
public RespawnPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String dimensionKey = "";
|
||||
String levelName = null;
|
||||
int dimension = 0;
|
||||
CompoundBinaryTag currentDimensionData = null;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, BinaryTagIO.reader());
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
dimension = ProtocolUtils.readVarInt(buf);
|
||||
} else {
|
||||
dimensionKey = ProtocolUtils.readString(buf);
|
||||
}
|
||||
levelName = ProtocolUtils.readString(buf);
|
||||
}
|
||||
} else {
|
||||
dimension = buf.readInt();
|
||||
}
|
||||
|
||||
short difficulty = 0;
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
difficulty = buf.readUnsignedByte();
|
||||
}
|
||||
|
||||
long partialHashedSeed = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
partialHashedSeed = buf.readLong();
|
||||
}
|
||||
|
||||
short gamemode = buf.readByte();
|
||||
|
||||
DimensionInfo dimensionInfo = null;
|
||||
String levelType = "";
|
||||
short previousGamemode = 0;
|
||||
byte dataToKeep = 0;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
previousGamemode = buf.readByte();
|
||||
boolean isDebug = buf.readBoolean();
|
||||
boolean isFlat = buf.readBoolean();
|
||||
dimensionInfo = new DimensionInfo(dimensionKey, levelName, isFlat, isDebug, version);
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
dataToKeep = (byte) (buf.readBoolean() ? 1 : 0);
|
||||
} else if (version.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
dataToKeep = buf.readByte();
|
||||
}
|
||||
} else {
|
||||
levelType = ProtocolUtils.readString(buf, 16);
|
||||
}
|
||||
|
||||
Pair<String, Long> lastDeathPosition = null;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19) && buf.readBoolean()) {
|
||||
lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong());
|
||||
}
|
||||
|
||||
int portalCooldown = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
portalCooldown = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
int seaLevel = 0;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
seaLevel = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
dataToKeep = buf.readByte();
|
||||
}
|
||||
|
||||
return new RespawnPacket(dimension, partialHashedSeed, difficulty, gamemode, levelType,
|
||||
dataToKeep, dimensionInfo, previousGamemode, currentDimensionData, lastDeathPosition,
|
||||
portalCooldown, seaLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(RespawnPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16_2)
|
||||
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeBinaryTag(buf, version, packet.currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.dimension);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getRegistryIdentifier());
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.dimensionInfo.getLevelName());
|
||||
}
|
||||
} else {
|
||||
buf.writeInt(packet.dimension);
|
||||
}
|
||||
|
||||
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_13_2)) {
|
||||
buf.writeByte(packet.difficulty);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_15)) {
|
||||
buf.writeLong(packet.partialHashedSeed);
|
||||
}
|
||||
|
||||
buf.writeByte(packet.gamemode);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
buf.writeByte(packet.previousGamemode);
|
||||
buf.writeBoolean(packet.dimensionInfo.isDebugType());
|
||||
buf.writeBoolean(packet.dimensionInfo.isFlat());
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.writeBoolean(packet.dataToKeep != 0);
|
||||
} else if (version.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
buf.writeByte(packet.dataToKeep);
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.levelType);
|
||||
}
|
||||
|
||||
// optional death location
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (packet.lastDeathPosition != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, packet.lastDeathPosition.key());
|
||||
buf.writeLong(packet.lastDeathPosition.value());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.portalCooldown);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.seaLevel);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
buf.writeByte(packet.dataToKeep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
@@ -29,14 +30,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public class ServerDataPacket implements MinecraftPacket {
|
||||
public final class ServerDataPacket implements MinecraftPacket {
|
||||
|
||||
private @Nullable ComponentHolder description;
|
||||
private @Nullable Favicon favicon;
|
||||
private boolean secureChatEnforced; // Added in 1.19.1 - Removed in 1.20.5
|
||||
|
||||
public ServerDataPacket() {
|
||||
}
|
||||
private final @Nullable ComponentHolder description;
|
||||
private final @Nullable Favicon favicon;
|
||||
private final boolean secureChatEnforced; // Added in 1.19.1 - Removed in 1.20.5
|
||||
|
||||
public ServerDataPacket(@Nullable ComponentHolder description, @Nullable Favicon favicon,
|
||||
boolean secureChatEnforced) {
|
||||
@@ -45,63 +43,6 @@ public class ServerDataPacket implements MinecraftPacket {
|
||||
this.secureChatEnforced = secureChatEnforced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4) || buf.readBoolean()) {
|
||||
this.description = ComponentHolder.read(buf, protocolVersion);
|
||||
}
|
||||
if (buf.readBoolean()) {
|
||||
String iconBase64;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
byte[] iconBytes = ProtocolUtils.readByteArray(buf);
|
||||
iconBase64 = "data:image/png;base64," + new String(Base64.getEncoder().encode(iconBytes), StandardCharsets.UTF_8);
|
||||
} else {
|
||||
iconBase64 = ProtocolUtils.readString(buf);
|
||||
}
|
||||
this.favicon = new Favicon(iconBase64);
|
||||
}
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.readBoolean();
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
this.secureChatEnforced = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
boolean hasDescription = this.description != null;
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
buf.writeBoolean(hasDescription);
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4) || hasDescription) {
|
||||
this.description.write(buf);
|
||||
}
|
||||
|
||||
boolean hasFavicon = this.favicon != null;
|
||||
buf.writeBoolean(hasFavicon);
|
||||
if (hasFavicon) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
String cutIconBase64 = favicon.getBase64Url().substring("data:image/png;base64,".length());
|
||||
byte[] iconBytes = Base64.getDecoder().decode(cutIconBase64.getBytes(StandardCharsets.UTF_8));
|
||||
ProtocolUtils.writeByteArray(buf, iconBytes);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, favicon.getBase64Url());
|
||||
}
|
||||
}
|
||||
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(this.secureChatEnforced);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
@@ -119,12 +60,68 @@ public class ServerDataPacket implements MinecraftPacket {
|
||||
return secureChatEnforced;
|
||||
}
|
||||
|
||||
public void setSecureChatEnforced(boolean secureChatEnforced) {
|
||||
this.secureChatEnforced = secureChatEnforced;
|
||||
}
|
||||
public static class Codec implements PacketCodec<ServerDataPacket> {
|
||||
@Override
|
||||
public ServerDataPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ComponentHolder description = null;
|
||||
Favicon favicon = null;
|
||||
boolean secureChatEnforced = false;
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return 8 * 1024;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4) || buf.readBoolean()) {
|
||||
description = ComponentHolder.read(buf, protocolVersion);
|
||||
}
|
||||
if (buf.readBoolean()) {
|
||||
String iconBase64;
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
byte[] iconBytes = ProtocolUtils.readByteArray(buf);
|
||||
iconBase64 = "data:image/png;base64," + new String(Base64.getEncoder().encode(iconBytes), StandardCharsets.UTF_8);
|
||||
} else {
|
||||
iconBase64 = ProtocolUtils.readString(buf);
|
||||
}
|
||||
favicon = new Favicon(iconBase64);
|
||||
}
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.readBoolean();
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
secureChatEnforced = buf.readBoolean();
|
||||
}
|
||||
|
||||
return new ServerDataPacket(description, favicon, secureChatEnforced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ServerDataPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
boolean hasDescription = packet.description != null;
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
buf.writeBoolean(hasDescription);
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4) || hasDescription) {
|
||||
packet.description.write(buf);
|
||||
}
|
||||
|
||||
boolean hasFavicon = packet.favicon != null;
|
||||
buf.writeBoolean(hasFavicon);
|
||||
if (hasFavicon) {
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
String cutIconBase64 = packet.favicon.getBase64Url().substring("data:image/png;base64,".length());
|
||||
byte[] iconBytes = Base64.getDecoder().decode(cutIconBase64.getBytes(StandardCharsets.UTF_8));
|
||||
ProtocolUtils.writeByteArray(buf, iconBytes);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.favicon.getBase64Url());
|
||||
}
|
||||
}
|
||||
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
buf.writeBoolean(packet.secureChatEnforced);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,165 +17,172 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.crypto.IdentifiedKey;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ServerLoginPacket implements MinecraftPacket {
|
||||
public final class ServerLoginPacket implements MinecraftPacket {
|
||||
|
||||
private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException(
|
||||
"Empty username!");
|
||||
|
||||
private @Nullable String username;
|
||||
private @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3
|
||||
private @Nullable UUID holderUuid; // Used for key revision 2
|
||||
|
||||
public ServerLoginPacket() {
|
||||
}
|
||||
private final String username;
|
||||
private final @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3
|
||||
private final @Nullable UUID holderUuid; // Used for key revision 2
|
||||
|
||||
public ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey) {
|
||||
this.username = Preconditions.checkNotNull(username, "username");
|
||||
this.playerKey = playerKey;
|
||||
this(username, playerKey, null);
|
||||
}
|
||||
|
||||
public ServerLoginPacket(String username, @Nullable UUID holderUuid) {
|
||||
this.username = Preconditions.checkNotNull(username, "username");
|
||||
this.holderUuid = holderUuid;
|
||||
this.playerKey = null;
|
||||
this(username, null, holderUuid);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if (username == null) {
|
||||
throw new IllegalStateException("No username found!");
|
||||
}
|
||||
private ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey,
|
||||
@Nullable UUID holderUuid) {
|
||||
this.username = username;
|
||||
this.playerKey = playerKey;
|
||||
this.holderUuid = holderUuid;
|
||||
}
|
||||
|
||||
public String username() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public @Nullable IdentifiedKey getPlayerKey() {
|
||||
public String getUsername() {
|
||||
return username();
|
||||
}
|
||||
|
||||
public @Nullable IdentifiedKey playerKey() {
|
||||
return this.playerKey;
|
||||
}
|
||||
|
||||
public void setPlayerKey(IdentifiedKey playerKey) {
|
||||
this.playerKey = playerKey;
|
||||
}
|
||||
|
||||
public @Nullable UUID getHolderUuid() {
|
||||
public @Nullable UUID holderUuid() {
|
||||
return holderUuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerLogin{"
|
||||
+ "username='" + username + '\''
|
||||
+ "playerKey='" + playerKey + '\''
|
||||
+ "holderUUID='" + holderUuid + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
username = ProtocolUtils.readString(buf, 16);
|
||||
if (username.isEmpty()) {
|
||||
throw EMPTY_USERNAME;
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
playerKey = null;
|
||||
} else {
|
||||
if (buf.readBoolean()) {
|
||||
playerKey = ProtocolUtils.readPlayerKey(version, buf);
|
||||
} else {
|
||||
playerKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
this.holderUuid = ProtocolUtils.readUuid(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
if (buf.readBoolean()) {
|
||||
holderUuid = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
playerKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (username == null) {
|
||||
throw new IllegalStateException("No username found!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, username);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
if (playerKey != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writePlayerKey(buf, playerKey);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
ProtocolUtils.writeUuid(buf, this.holderUuid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
if (playerKey != null && playerKey.getSignatureHolder() != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, playerKey.getSignatureHolder());
|
||||
} else if (this.holderUuid != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, this.holderUuid);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
|
||||
// legal on the protocol level.
|
||||
int base = 1 + (16 * 3);
|
||||
// Adjustments for Key-authentication
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
// + 1 for the boolean present/ not present
|
||||
// + 8 for the long expiry
|
||||
// + 2 len for varint key size
|
||||
// + 294 for the key
|
||||
// + 2 len for varint signature size
|
||||
// + 512 for signature
|
||||
base += 1 + 8 + 2 + 294 + 2 + 512;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
// +1 boolean uuid optional
|
||||
// + 2 * 8 for the long msb/lsb
|
||||
base += 1 + 8 + 8;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
+ "username='" + username + '\''
|
||||
+ "playerKey='" + playerKey + '\''
|
||||
+ "holderUUID='" + holderUuid + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ServerLoginPacket> {
|
||||
@Override
|
||||
public ServerLoginPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String username = ProtocolUtils.readString(buf, 16);
|
||||
if (username.isEmpty()) {
|
||||
throw EMPTY_USERNAME;
|
||||
}
|
||||
|
||||
IdentifiedKey playerKey = null;
|
||||
UUID holderUuid = null;
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
playerKey = null;
|
||||
} else {
|
||||
if (buf.readBoolean()) {
|
||||
playerKey = ProtocolUtils.readPlayerKey(version, buf);
|
||||
} else {
|
||||
playerKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
holderUuid = ProtocolUtils.readUuid(buf);
|
||||
return new ServerLoginPacket(username, playerKey, holderUuid);
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
if (buf.readBoolean()) {
|
||||
holderUuid = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
playerKey = null;
|
||||
}
|
||||
|
||||
return new ServerLoginPacket(username, playerKey, holderUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ServerLoginPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (packet.username == null) {
|
||||
throw new IllegalStateException("No username found!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.username);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
if (packet.playerKey != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writePlayerKey(buf, packet.playerKey);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
ProtocolUtils.writeUuid(buf, packet.holderUuid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
if (packet.playerKey != null && packet.playerKey.getSignatureHolder() != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, packet.playerKey.getSignatureHolder());
|
||||
} else if (packet.holderUuid != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, packet.holderUuid);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
|
||||
// legal on the protocol level.
|
||||
int base = 1 + (16 * 3);
|
||||
// Adjustments for Key-authentication
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
// + 1 for the boolean present/ not present
|
||||
// + 8 for the long expiry
|
||||
// + 2 len for varint key size
|
||||
// + 294 for the key
|
||||
// + 2 len for varint signature size
|
||||
// + 512 for signature
|
||||
base += 1 + 8 + 2 + 294 + 2 + 512;
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
// +1 boolean uuid optional
|
||||
// + 2 * 8 for the long msb/lsb
|
||||
base += 1 + 8 + 8;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,52 +22,40 @@ import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.util.UuidUtils;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.util.VelocityProperties;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ServerLoginSuccessPacket implements MinecraftPacket {
|
||||
public final class ServerLoginSuccessPacket implements MinecraftPacket {
|
||||
|
||||
private @Nullable UUID uuid;
|
||||
private @Nullable String username;
|
||||
private @Nullable List<GameProfile.Property> properties;
|
||||
private final UUID uuid;
|
||||
private final String username;
|
||||
private final List<GameProfile.Property> properties;
|
||||
private static final boolean strictErrorHandling = VelocityProperties
|
||||
.readBoolean("velocity.strictErrorHandling", true);
|
||||
|
||||
public ServerLoginSuccessPacket(UUID uuid, String username, List<GameProfile.Property> properties) {
|
||||
this.uuid = uuid;
|
||||
this.username = username;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
if (uuid == null) {
|
||||
throw new IllegalStateException("No UUID specified!");
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if (username == null) {
|
||||
throw new IllegalStateException("No username specified!");
|
||||
}
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public List<GameProfile.Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(List<GameProfile.Property> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerLoginSuccess{"
|
||||
@@ -77,67 +65,70 @@ public class ServerLoginSuccessPacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
uuid = ProtocolUtils.readUuid(buf);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
uuid = ProtocolUtils.readUuidIntArray(buf);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
uuid = UUID.fromString(ProtocolUtils.readString(buf, 36));
|
||||
} else {
|
||||
uuid = UuidUtils.fromUndashed(ProtocolUtils.readString(buf, 32));
|
||||
}
|
||||
username = ProtocolUtils.readString(buf, 16);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
properties = ProtocolUtils.readProperties(buf);
|
||||
}
|
||||
if (version == ProtocolVersion.MINECRAFT_1_20_5 || version == ProtocolVersion.MINECRAFT_1_21) {
|
||||
buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (uuid == null) {
|
||||
throw new IllegalStateException("No UUID specified!");
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeUuid(buf, uuid);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuidIntArray(buf, uuid);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
ProtocolUtils.writeString(buf, uuid.toString());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, UuidUtils.toUndashed(uuid));
|
||||
}
|
||||
if (username == null) {
|
||||
throw new IllegalStateException("No username specified!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, username);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (properties == null) {
|
||||
ProtocolUtils.writeVarInt(buf, 0);
|
||||
} else {
|
||||
ProtocolUtils.writeProperties(buf, properties);
|
||||
}
|
||||
}
|
||||
if (version == ProtocolVersion.MINECRAFT_1_20_5 || version == ProtocolVersion.MINECRAFT_1_21) {
|
||||
buf.writeBoolean(strictErrorHandling);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||
// sizes of this packet.
|
||||
return 4 * 1024;
|
||||
public static class Codec implements PacketCodec<ServerLoginSuccessPacket> {
|
||||
@Override
|
||||
public ServerLoginSuccessPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion version) {
|
||||
UUID uuid;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
uuid = ProtocolUtils.readUuid(buf);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
uuid = ProtocolUtils.readUuidIntArray(buf);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
uuid = UUID.fromString(ProtocolUtils.readString(buf, 36));
|
||||
} else {
|
||||
uuid = UuidUtils.fromUndashed(ProtocolUtils.readString(buf, 32));
|
||||
}
|
||||
String username = ProtocolUtils.readString(buf, 16);
|
||||
|
||||
List<GameProfile.Property> properties = null;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
properties = ProtocolUtils.readProperties(buf);
|
||||
}
|
||||
if (version == ProtocolVersion.MINECRAFT_1_20_5 || version == ProtocolVersion.MINECRAFT_1_21) {
|
||||
buf.readBoolean();
|
||||
}
|
||||
|
||||
return new ServerLoginSuccessPacket(uuid, username, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ServerLoginSuccessPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
ProtocolUtils.writeUuid(buf, packet.uuid);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuidIntArray(buf, packet.uuid);
|
||||
} else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||
ProtocolUtils.writeString(buf, packet.uuid.toString());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, UuidUtils.toUndashed(packet.uuid));
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.username);
|
||||
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
||||
if (packet.properties == null) {
|
||||
ProtocolUtils.writeVarInt(buf, 0);
|
||||
} else {
|
||||
ProtocolUtils.writeProperties(buf, packet.properties);
|
||||
}
|
||||
}
|
||||
if (version == ProtocolVersion.MINECRAFT_1_20_5 || version == ProtocolVersion.MINECRAFT_1_21) {
|
||||
buf.writeBoolean(strictErrorHandling);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(ServerLoginSuccessPacket packet, Direction direction, ProtocolVersion version) {
|
||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
||||
// sizes of this packet.
|
||||
return 4 * 1024;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,15 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ServerboundCookieResponsePacket implements MinecraftPacket {
|
||||
|
||||
private Key key;
|
||||
private byte @Nullable [] payload;
|
||||
public record ServerboundCookieResponsePacket(Key key,
|
||||
byte @Nullable [] payload) implements MinecraftPacket {
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
@@ -39,34 +38,32 @@ public class ServerboundCookieResponsePacket implements MinecraftPacket {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public ServerboundCookieResponsePacket() {
|
||||
}
|
||||
|
||||
public ServerboundCookieResponsePacket(final Key key, final byte @Nullable [] payload) {
|
||||
this.key = key;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.key = ProtocolUtils.readKey(buf);
|
||||
if (buf.readBoolean()) {
|
||||
this.payload = ProtocolUtils.readByteArray(buf, 5120);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, key);
|
||||
final boolean hasPayload = payload != null && payload.length > 0;
|
||||
buf.writeBoolean(hasPayload);
|
||||
if (hasPayload) {
|
||||
ProtocolUtils.writeByteArray(buf, payload);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ServerboundCookieResponsePacket> {
|
||||
@Override
|
||||
public ServerboundCookieResponsePacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
Key key = ProtocolUtils.readKey(buf);
|
||||
byte[] payload = null;
|
||||
if (buf.readBoolean()) {
|
||||
payload = ProtocolUtils.readByteArray(buf, 5120);
|
||||
}
|
||||
return new ServerboundCookieResponsePacket(key, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ServerboundCookieResponsePacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKey(buf, packet.key);
|
||||
final boolean hasPayload = packet.payload != null && packet.payload.length > 0;
|
||||
buf.writeBoolean(hasPayload);
|
||||
if (hasPayload) {
|
||||
ProtocolUtils.writeByteArray(buf, packet.payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,25 +20,17 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
|
||||
public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public class ServerboundCustomClickActionPacket extends DefaultByteBufHolder
|
||||
implements MinecraftPacket {
|
||||
|
||||
public ServerboundCustomClickActionPacket() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
buf.writeBytes(content());
|
||||
public ServerboundCustomClickActionPacket(ByteBuf backing) {
|
||||
super(backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +39,61 @@ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder im
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
public ServerboundCustomClickActionPacket copy() {
|
||||
return (ServerboundCustomClickActionPacket) super.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket duplicate() {
|
||||
return (ServerboundCustomClickActionPacket) super.duplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket retainedDuplicate() {
|
||||
return (ServerboundCustomClickActionPacket) super.retainedDuplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket replace(ByteBuf content) {
|
||||
return (ServerboundCustomClickActionPacket) super.replace(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket retain() {
|
||||
return (ServerboundCustomClickActionPacket) super.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket retain(int increment) {
|
||||
return (ServerboundCustomClickActionPacket) super.retain(increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket touch() {
|
||||
return (ServerboundCustomClickActionPacket) super.touch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket touch(Object hint) {
|
||||
return (ServerboundCustomClickActionPacket) super.touch(hint);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ServerboundCustomClickActionPacket> {
|
||||
@Override
|
||||
public ServerboundCustomClickActionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new ServerboundCustomClickActionPacket(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ServerboundCustomClickActionPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
buf.writeBytes(packet.content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(ServerboundCustomClickActionPacket packet, Direction direction, ProtocolVersion protocolVersion) {
|
||||
return packet.content().readableBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,28 +20,16 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class SetCompressionPacket implements MinecraftPacket {
|
||||
|
||||
private int threshold;
|
||||
|
||||
public SetCompressionPacket() {
|
||||
}
|
||||
|
||||
public SetCompressionPacket(int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
public record SetCompressionPacket(int threshold) implements MinecraftPacket {
|
||||
|
||||
public int getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetCompression{"
|
||||
@@ -49,18 +37,22 @@ public class SetCompressionPacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
this.threshold = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
ProtocolUtils.writeVarInt(buf, threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<SetCompressionPacket> {
|
||||
@Override
|
||||
public SetCompressionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new SetCompressionPacket(ProtocolUtils.readVarInt(buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(SetCompressionPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,36 +20,41 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class StatusPingPacket implements MinecraftPacket {
|
||||
|
||||
private long randomId;
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
randomId = buf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
buf.writeLong(randomId);
|
||||
}
|
||||
public record StatusPingPacket(long randomId) implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
return 8;
|
||||
}
|
||||
public static class Codec implements PacketCodec<StatusPingPacket> {
|
||||
@Override
|
||||
public StatusPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new StatusPingPacket(buf.readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
return 8;
|
||||
@Override
|
||||
public void encode(StatusPingPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeLong(packet.randomId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMinLength(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
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.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class StatusRequestPacket implements MinecraftPacket {
|
||||
public final class StatusRequestPacket implements MinecraftPacket {
|
||||
|
||||
public static final StatusRequestPacket INSTANCE = new StatusRequestPacket();
|
||||
|
||||
@@ -32,16 +32,6 @@ public class StatusRequestPacket implements MinecraftPacket {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
// There is no additional data to decode.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
// There is no data to decode.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StatusRequest";
|
||||
@@ -52,8 +42,22 @@ public class StatusRequestPacket implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
||||
return 0;
|
||||
public static class Codec implements PacketCodec<StatusRequestPacket> {
|
||||
@Override
|
||||
public StatusRequestPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(StatusRequestPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,29 +20,30 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class StatusResponsePacket implements MinecraftPacket {
|
||||
public final class StatusResponsePacket implements MinecraftPacket {
|
||||
|
||||
private @Nullable CharSequence status;
|
||||
|
||||
public StatusResponsePacket() {
|
||||
}
|
||||
private final @Nullable CharSequence status;
|
||||
|
||||
public StatusResponsePacket(CharSequence status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
public String status() {
|
||||
if (status == null) {
|
||||
throw new IllegalStateException("Status is not specified");
|
||||
}
|
||||
return status.toString();
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StatusResponse{"
|
||||
@@ -50,26 +51,31 @@ public class StatusResponsePacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
status = ProtocolUtils.readString(buf, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (status == null) {
|
||||
throw new IllegalStateException("Status is not specified");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return ProtocolUtils.stringSizeHint(this.status);
|
||||
public static class Codec implements PacketCodec<StatusResponsePacket> {
|
||||
@Override
|
||||
public StatusResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
CharSequence status = ProtocolUtils.readString(buf, Short.MAX_VALUE);
|
||||
return new StatusResponsePacket(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(StatusResponsePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (packet.status == null) {
|
||||
throw new IllegalStateException("Status is not specified");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, packet.status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(StatusResponsePacket packet, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
return ProtocolUtils.stringSizeHint(packet.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,122 +21,125 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class TabCompleteRequestPacket implements MinecraftPacket {
|
||||
public final class TabCompleteRequestPacket implements MinecraftPacket {
|
||||
|
||||
private static final int VANILLA_MAX_TAB_COMPLETE_LEN = 2048;
|
||||
|
||||
private @Nullable String command;
|
||||
private int transactionId;
|
||||
private boolean assumeCommand;
|
||||
private boolean hasPosition;
|
||||
private long position;
|
||||
private final @Nullable String command;
|
||||
private final int transactionId;
|
||||
private final boolean assumeCommand;
|
||||
private final boolean hasPosition;
|
||||
private final long position;
|
||||
|
||||
public String getCommand() {
|
||||
public TabCompleteRequestPacket() {
|
||||
this(null, 0, false, false, 0);
|
||||
}
|
||||
|
||||
public TabCompleteRequestPacket(@Nullable String command, int transactionId,
|
||||
boolean assumeCommand, boolean hasPosition, long position) {
|
||||
this.command = command;
|
||||
this.transactionId = transactionId;
|
||||
this.assumeCommand = assumeCommand;
|
||||
this.hasPosition = hasPosition;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public String command() {
|
||||
if (command == null) {
|
||||
throw new IllegalStateException("Command is not specified");
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
public String getCommand() {
|
||||
return command();
|
||||
}
|
||||
|
||||
public boolean isAssumeCommand() {
|
||||
public boolean assumeCommand() {
|
||||
return assumeCommand;
|
||||
}
|
||||
|
||||
public void setAssumeCommand(boolean assumeCommand) {
|
||||
this.assumeCommand = assumeCommand;
|
||||
public boolean isAssumeCommand() {
|
||||
return assumeCommand();
|
||||
}
|
||||
|
||||
public boolean hasPosition() {
|
||||
return hasPosition;
|
||||
}
|
||||
|
||||
public void setHasPosition(boolean hasPosition) {
|
||||
this.hasPosition = hasPosition;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
public long position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(long position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getTransactionId() {
|
||||
public int transactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(int transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("command", command)
|
||||
.add("transactionId", transactionId)
|
||||
.add("assumeCommand", assumeCommand)
|
||||
.add("hasPosition", hasPosition)
|
||||
.add("position", position)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
this.transactionId = ProtocolUtils.readVarInt(buf);
|
||||
this.command = ProtocolUtils.readString(buf, VANILLA_MAX_TAB_COMPLETE_LEN);
|
||||
} else {
|
||||
this.command = ProtocolUtils.readString(buf, VANILLA_MAX_TAB_COMPLETE_LEN);
|
||||
if (version.noLessThan(MINECRAFT_1_9)) {
|
||||
this.assumeCommand = buf.readBoolean();
|
||||
}
|
||||
if (version.noLessThan(MINECRAFT_1_8)) {
|
||||
this.hasPosition = buf.readBoolean();
|
||||
if (hasPosition) {
|
||||
this.position = buf.readLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (command == null) {
|
||||
throw new IllegalStateException("Command is not specified");
|
||||
}
|
||||
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeVarInt(buf, transactionId);
|
||||
ProtocolUtils.writeString(buf, command);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, command);
|
||||
if (version.noLessThan(MINECRAFT_1_9)) {
|
||||
buf.writeBoolean(assumeCommand);
|
||||
}
|
||||
if (version.noLessThan(MINECRAFT_1_8)) {
|
||||
buf.writeBoolean(hasPosition);
|
||||
if (hasPosition) {
|
||||
buf.writeLong(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TabCompleteRequestPacket> {
|
||||
@Override
|
||||
public TabCompleteRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String command;
|
||||
int transactionId = 0;
|
||||
boolean assumeCommand = false;
|
||||
boolean hasPosition = false;
|
||||
long position = 0;
|
||||
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
transactionId = ProtocolUtils.readVarInt(buf);
|
||||
command = ProtocolUtils.readString(buf, VANILLA_MAX_TAB_COMPLETE_LEN);
|
||||
} else {
|
||||
command = ProtocolUtils.readString(buf, VANILLA_MAX_TAB_COMPLETE_LEN);
|
||||
if (version.noLessThan(MINECRAFT_1_9)) {
|
||||
assumeCommand = buf.readBoolean();
|
||||
}
|
||||
if (version.noLessThan(MINECRAFT_1_8)) {
|
||||
hasPosition = buf.readBoolean();
|
||||
if (hasPosition) {
|
||||
position = buf.readLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TabCompleteRequestPacket(command, transactionId, assumeCommand, hasPosition,
|
||||
position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TabCompleteRequestPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (packet.command == null) {
|
||||
throw new IllegalStateException("Command is not specified");
|
||||
}
|
||||
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.transactionId);
|
||||
ProtocolUtils.writeString(buf, packet.command);
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, packet.command);
|
||||
if (version.noLessThan(MINECRAFT_1_9)) {
|
||||
buf.writeBoolean(packet.assumeCommand);
|
||||
}
|
||||
if (version.noLessThan(MINECRAFT_1_8)) {
|
||||
buf.writeBoolean(packet.hasPosition);
|
||||
if (packet.hasPosition) {
|
||||
buf.writeLong(packet.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.common.base.MoreObjects;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -30,39 +31,54 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class TabCompleteResponsePacket implements MinecraftPacket {
|
||||
public final class TabCompleteResponsePacket implements MinecraftPacket {
|
||||
|
||||
private int transactionId;
|
||||
private int start;
|
||||
private int length;
|
||||
private final List<Offer> offers = new ArrayList<>();
|
||||
private final int transactionId;
|
||||
private final int start;
|
||||
private final int length;
|
||||
private final List<Offer> offers;
|
||||
|
||||
public int getTransactionId() {
|
||||
public TabCompleteResponsePacket(int transactionId, int start, int length, List<Offer> offers) {
|
||||
this.transactionId = transactionId;
|
||||
this.start = start;
|
||||
this.length = length;
|
||||
this.offers = offers;
|
||||
}
|
||||
|
||||
public int transactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(int transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
public int start() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
public int length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
public List<Offer> offers() {
|
||||
return offers;
|
||||
}
|
||||
|
||||
public int getTransactionId() {
|
||||
return transactionId();
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start();
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return length();
|
||||
}
|
||||
|
||||
public List<Offer> getOffers() {
|
||||
return offers;
|
||||
return offers();
|
||||
}
|
||||
|
||||
public TabCompleteResponsePacket withOffers(List<Offer> offers) {
|
||||
return new TabCompleteResponsePacket(transactionId, start, length, offers);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,53 +91,61 @@ public class TabCompleteResponsePacket implements MinecraftPacket {
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
this.transactionId = ProtocolUtils.readVarInt(buf);
|
||||
this.start = ProtocolUtils.readVarInt(buf);
|
||||
this.length = ProtocolUtils.readVarInt(buf);
|
||||
int offersAvailable = ProtocolUtils.readVarInt(buf);
|
||||
for (int i = 0; i < offersAvailable; i++) {
|
||||
String offer = ProtocolUtils.readString(buf);
|
||||
ComponentHolder tooltip = buf.readBoolean() ? ComponentHolder.read(buf, version) : null;
|
||||
offers.add(new Offer(offer, tooltip));
|
||||
}
|
||||
} else {
|
||||
int offersAvailable = ProtocolUtils.readVarInt(buf);
|
||||
for (int i = 0; i < offersAvailable; i++) {
|
||||
offers.add(new Offer(ProtocolUtils.readString(buf), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeVarInt(buf, this.transactionId);
|
||||
ProtocolUtils.writeVarInt(buf, this.start);
|
||||
ProtocolUtils.writeVarInt(buf, this.length);
|
||||
ProtocolUtils.writeVarInt(buf, offers.size());
|
||||
for (Offer offer : offers) {
|
||||
ProtocolUtils.writeString(buf, offer.text);
|
||||
buf.writeBoolean(offer.tooltip != null);
|
||||
if (offer.tooltip != null) {
|
||||
offer.tooltip.write(buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, offers.size());
|
||||
for (Offer offer : offers) {
|
||||
ProtocolUtils.writeString(buf, offer.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TabCompleteResponsePacket> {
|
||||
@Override
|
||||
public TabCompleteResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
int transactionId = ProtocolUtils.readVarInt(buf);
|
||||
int start = ProtocolUtils.readVarInt(buf);
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
int offersAvailable = ProtocolUtils.readVarInt(buf);
|
||||
List<Offer> offers = new ArrayList<>(offersAvailable);
|
||||
for (int i = 0; i < offersAvailable; i++) {
|
||||
String offer = ProtocolUtils.readString(buf);
|
||||
ComponentHolder tooltip = buf.readBoolean() ? ComponentHolder.read(buf, version) : null;
|
||||
offers.add(new Offer(offer, tooltip));
|
||||
}
|
||||
return new TabCompleteResponsePacket(transactionId, start, length, offers);
|
||||
} else {
|
||||
int offersAvailable = ProtocolUtils.readVarInt(buf);
|
||||
List<Offer> offers = new ArrayList<>(offersAvailable);
|
||||
for (int i = 0; i < offersAvailable; i++) {
|
||||
offers.add(new Offer(ProtocolUtils.readString(buf), null));
|
||||
}
|
||||
return new TabCompleteResponsePacket(0, 0, 0, offers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TabCompleteResponsePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.noLessThan(MINECRAFT_1_13)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.transactionId);
|
||||
ProtocolUtils.writeVarInt(buf, packet.start);
|
||||
ProtocolUtils.writeVarInt(buf, packet.length);
|
||||
ProtocolUtils.writeVarInt(buf, packet.offers.size());
|
||||
for (Offer offer : packet.offers) {
|
||||
ProtocolUtils.writeString(buf, offer.text);
|
||||
buf.writeBoolean(offer.tooltip != null);
|
||||
if (offer.tooltip != null) {
|
||||
offer.tooltip.write(buf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, packet.offers.size());
|
||||
for (Offer offer : packet.offers) {
|
||||
ProtocolUtils.writeString(buf, offer.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Offer implements Comparable<Offer> {
|
||||
|
||||
private final String text;
|
||||
|
||||
@@ -20,22 +20,13 @@ package com.velocitypowered.proxy.protocol.packet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetSocketAddress;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TransferPacket implements MinecraftPacket {
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
public TransferPacket() {
|
||||
}
|
||||
|
||||
public TransferPacket(final String host, final int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
public record TransferPacket(String host, int port) implements MinecraftPacket {
|
||||
|
||||
@Nullable
|
||||
public InetSocketAddress address() {
|
||||
@@ -45,20 +36,31 @@ public class TransferPacket implements MinecraftPacket {
|
||||
return new InetSocketAddress(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.host = ProtocolUtils.readString(buf);
|
||||
this.port = ProtocolUtils.readVarInt(buf);
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, host);
|
||||
ProtocolUtils.writeVarInt(buf, port);
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TransferPacket> {
|
||||
@Override
|
||||
public TransferPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new TransferPacket(ProtocolUtils.readString(buf), ProtocolUtils.readVarInt(buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TransferPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.host);
|
||||
ProtocolUtils.writeVarInt(buf, packet.port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.RemoteChatSession;
|
||||
@@ -28,29 +29,18 @@ import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
||||
public final class UpsertPlayerInfoPacket implements MinecraftPacket {
|
||||
|
||||
private static final Action[] ALL_ACTIONS = Action.class.getEnumConstants();
|
||||
|
||||
private final EnumSet<Action> actions;
|
||||
private final List<Entry> entries;
|
||||
|
||||
public UpsertPlayerInfoPacket() {
|
||||
this.actions = EnumSet.noneOf(Action.class);
|
||||
this.entries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public UpsertPlayerInfoPacket(Action action) {
|
||||
this.actions = EnumSet.of(action);
|
||||
this.entries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public UpsertPlayerInfoPacket(EnumSet<Action> actions, List<Entry> entries) {
|
||||
this.actions = actions;
|
||||
this.entries = entries;
|
||||
@@ -68,71 +58,60 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
||||
return this.actions.contains(action);
|
||||
}
|
||||
|
||||
public void addAction(Action action) {
|
||||
this.actions.add(action);
|
||||
}
|
||||
|
||||
public void addAllActions(Collection<? extends Action> actions) {
|
||||
this.actions.addAll(actions);
|
||||
}
|
||||
|
||||
public void addEntry(Entry entry) {
|
||||
this.entries.add(entry);
|
||||
}
|
||||
|
||||
public void addAllEntries(Collection<? extends Entry> entries) {
|
||||
this.entries.addAll(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
byte[] bytes = new byte[-Math.floorDiv(-ALL_ACTIONS.length, 8)];
|
||||
buf.readBytes(bytes);
|
||||
BitSet actionSet = BitSet.valueOf(bytes);
|
||||
|
||||
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||
if (actionSet.get(idx)) {
|
||||
addAction(ALL_ACTIONS[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
for (int idx = 0; idx < length; idx++) {
|
||||
Entry entry = new Entry(ProtocolUtils.readUuid(buf));
|
||||
for (Action action : this.actions) {
|
||||
action.read.read(protocolVersion, buf, entry);
|
||||
}
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
BitSet set = new BitSet(ALL_ACTIONS.length);
|
||||
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||
set.set(idx, this.actions.contains(ALL_ACTIONS[idx]));
|
||||
}
|
||||
|
||||
byte[] bytes = set.toByteArray();
|
||||
buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-ALL_ACTIONS.length, 8)));
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, this.entries.size());
|
||||
for (Entry entry : this.entries) {
|
||||
ProtocolUtils.writeUuid(buf, entry.profileId);
|
||||
|
||||
for (Action action : this.actions) {
|
||||
action.write.write(protocolVersion, buf, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<UpsertPlayerInfoPacket> {
|
||||
@Override
|
||||
public UpsertPlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
byte[] bytes = new byte[-Math.floorDiv(-ALL_ACTIONS.length, 8)];
|
||||
buf.readBytes(bytes);
|
||||
BitSet actionSet = BitSet.valueOf(bytes);
|
||||
|
||||
EnumSet<Action> actions = EnumSet.noneOf(Action.class);
|
||||
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||
if (actionSet.get(idx)) {
|
||||
actions.add(ALL_ACTIONS[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
int length = ProtocolUtils.readVarInt(buf);
|
||||
List<Entry> entries = new ArrayList<>(length);
|
||||
for (int idx = 0; idx < length; idx++) {
|
||||
Entry entry = new Entry(ProtocolUtils.readUuid(buf));
|
||||
for (Action action : actions) {
|
||||
action.read.read(protocolVersion, buf, entry);
|
||||
}
|
||||
entries.add(entry);
|
||||
}
|
||||
return new UpsertPlayerInfoPacket(actions, entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(UpsertPlayerInfoPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
BitSet set = new BitSet(ALL_ACTIONS.length);
|
||||
for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
|
||||
set.set(idx, packet.actions.contains(ALL_ACTIONS[idx]));
|
||||
}
|
||||
|
||||
byte[] bytes = set.toByteArray();
|
||||
buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-ALL_ACTIONS.length, 8)));
|
||||
|
||||
ProtocolUtils.writeVarInt(buf, packet.entries.size());
|
||||
for (Entry entry : packet.entries) {
|
||||
ProtocolUtils.writeUuid(buf, entry.profileId);
|
||||
|
||||
for (Action action : packet.actions) {
|
||||
action.write.write(protocolVersion, buf, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ADD_PLAYER((ignored, buf, info) -> { // read
|
||||
info.profile = new GameProfile(
|
||||
@@ -315,4 +294,4 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,42 +20,35 @@ package com.velocitypowered.proxy.protocol.packet.chat;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class ChatAcknowledgementPacket implements MinecraftPacket {
|
||||
int offset;
|
||||
public record ChatAcknowledgementPacket(int offset) implements MinecraftPacket {
|
||||
|
||||
public ChatAcknowledgementPacket(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public ChatAcknowledgementPacket() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChatAcknowledgement{" +
|
||||
"offset=" + offset +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ChatAcknowledgementPacket> {
|
||||
@Override
|
||||
public ChatAcknowledgementPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return new ChatAcknowledgementPacket(ProtocolUtils.readVarInt(buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
offset = ProtocolUtils.readVarInt(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChatAcknowledgement{" +
|
||||
"offset=" + offset +
|
||||
'}';
|
||||
}
|
||||
|
||||
public int offset() {
|
||||
return offset;
|
||||
public void encode(ChatAcknowledgementPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,17 @@ package com.velocitypowered.proxy.protocol.packet.chat;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class PlayerChatCompletionPacket implements MinecraftPacket {
|
||||
public final class PlayerChatCompletionPacket implements MinecraftPacket {
|
||||
|
||||
private String[] completions;
|
||||
private Action action;
|
||||
private final String[] completions;
|
||||
private final Action action;
|
||||
|
||||
public PlayerChatCompletionPacket() {
|
||||
this(new String[0], Action.ADD);
|
||||
}
|
||||
|
||||
public PlayerChatCompletionPacket(String[] completions, Action action) {
|
||||
@@ -36,36 +38,14 @@ public class PlayerChatCompletionPacket implements MinecraftPacket {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String[] getCompletions() {
|
||||
public String[] completions() {
|
||||
return completions;
|
||||
}
|
||||
|
||||
public Action getAction() {
|
||||
public Action action() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setCompletions(String[] completions) {
|
||||
this.completions = completions;
|
||||
}
|
||||
|
||||
public void setAction(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
action = Action.values()[ProtocolUtils.readVarInt(buf)];
|
||||
completions = ProtocolUtils.readStringArray(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, action.ordinal());
|
||||
ProtocolUtils.writeStringArray(buf, completions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
@@ -76,4 +56,21 @@ public class PlayerChatCompletionPacket implements MinecraftPacket {
|
||||
REMOVE,
|
||||
SET
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<PlayerChatCompletionPacket> {
|
||||
@Override
|
||||
public PlayerChatCompletionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
Action action = Action.values()[ProtocolUtils.readVarInt(buf)];
|
||||
String[] completions = ProtocolUtils.readStringArray(buf);
|
||||
return new PlayerChatCompletionPacket(completions, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(PlayerChatCompletionPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.action.ordinal());
|
||||
ProtocolUtils.writeStringArray(buf, packet.completions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,17 @@ package com.velocitypowered.proxy.protocol.packet.chat;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class SystemChatPacket implements MinecraftPacket {
|
||||
public final class SystemChatPacket implements MinecraftPacket {
|
||||
|
||||
private final ComponentHolder component;
|
||||
private final ChatType type;
|
||||
|
||||
public SystemChatPacket() {
|
||||
this(null, ChatType.SYSTEM);
|
||||
}
|
||||
|
||||
public SystemChatPacket(ComponentHolder component, ChatType type) {
|
||||
@@ -33,48 +38,59 @@ public class SystemChatPacket implements MinecraftPacket {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private ComponentHolder component;
|
||||
private ChatType type;
|
||||
|
||||
public ChatType getType() {
|
||||
public ChatType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ComponentHolder getComponent() {
|
||||
public ComponentHolder component() {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
component = ComponentHolder.read(buf, version);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)){
|
||||
type = buf.readBoolean() ? ChatType.GAME_INFO : ChatType.SYSTEM;
|
||||
} else {
|
||||
type = ChatType.values()[ProtocolUtils.readVarInt(buf)];
|
||||
}
|
||||
public ComponentHolder getComponent() {
|
||||
return component();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
component.write(buf);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
switch (type) {
|
||||
case SYSTEM:
|
||||
buf.writeBoolean(false);
|
||||
break;
|
||||
case GAME_INFO:
|
||||
buf.writeBoolean(true);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid chat type");
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, type.getId());
|
||||
}
|
||||
public ChatType getType() {
|
||||
return type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<SystemChatPacket> {
|
||||
@Override
|
||||
public SystemChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
ComponentHolder component = ComponentHolder.read(buf, version);
|
||||
ChatType type;
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
type = buf.readBoolean() ? ChatType.GAME_INFO : ChatType.SYSTEM;
|
||||
} else {
|
||||
type = ChatType.values()[ProtocolUtils.readVarInt(buf)];
|
||||
}
|
||||
return new SystemChatPacket(component, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(SystemChatPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
packet.component.write(buf);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
switch (packet.type) {
|
||||
case SYSTEM:
|
||||
buf.writeBoolean(false);
|
||||
break;
|
||||
case GAME_INFO:
|
||||
buf.writeBoolean(true);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid chat type");
|
||||
}
|
||||
} else {
|
||||
ProtocolUtils.writeVarInt(buf, packet.type.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet.chat.keyed;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatType;
|
||||
@@ -42,12 +41,13 @@ public class KeyedChatBuilder extends ChatBuilderV2 {
|
||||
@Override
|
||||
public MinecraftPacket toServer() {
|
||||
if (message.startsWith("/")) {
|
||||
return new KeyedPlayerCommandPacket(message.substring(1), ImmutableList.of(), timestamp);
|
||||
return new KeyedPlayerCommandPacket(false, message.substring(1), timestamp, 0L,
|
||||
false, new com.velocitypowered.proxy.crypto.SignaturePair[0], null,
|
||||
java.util.Collections.emptyMap());
|
||||
} else {
|
||||
// This will produce an error on the server, but needs to be here.
|
||||
KeyedPlayerChatPacket v1Chat = new KeyedPlayerChatPacket(message);
|
||||
v1Chat.setExpiry(this.timestamp);
|
||||
return v1Chat;
|
||||
return new KeyedPlayerChatPacket(message, false, false, timestamp, null, null,
|
||||
new com.velocitypowered.proxy.crypto.SignaturePair[0], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,41 +23,43 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.crypto.EncryptionUtils;
|
||||
import com.velocitypowered.proxy.crypto.SignaturePair;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.time.Instant;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class KeyedPlayerChatPacket implements MinecraftPacket {
|
||||
|
||||
private String message;
|
||||
private boolean signedPreview;
|
||||
private boolean unsigned = false;
|
||||
private @Nullable Instant expiry;
|
||||
private @Nullable byte[] signature;
|
||||
private @Nullable byte[] salt;
|
||||
private SignaturePair[] previousMessages = new SignaturePair[0];
|
||||
private @Nullable SignaturePair lastMessage;
|
||||
public final class KeyedPlayerChatPacket implements MinecraftPacket {
|
||||
|
||||
public static final int MAXIMUM_PREVIOUS_MESSAGE_COUNT = 5;
|
||||
|
||||
public static final QuietDecoderException INVALID_PREVIOUS_MESSAGES =
|
||||
new QuietDecoderException("Invalid previous messages");
|
||||
|
||||
public KeyedPlayerChatPacket() {
|
||||
}
|
||||
private final String message;
|
||||
private final boolean signedPreview;
|
||||
private final boolean unsigned;
|
||||
private final @Nullable Instant expiry;
|
||||
private final @Nullable byte[] signature;
|
||||
private final @Nullable byte[] salt;
|
||||
private final SignaturePair[] previousMessages;
|
||||
private final @Nullable SignaturePair lastMessage;
|
||||
|
||||
public KeyedPlayerChatPacket(String message) {
|
||||
public KeyedPlayerChatPacket(String message, boolean signedPreview, boolean unsigned,
|
||||
@Nullable Instant expiry, @Nullable byte[] signature, @Nullable byte[] salt,
|
||||
SignaturePair[] previousMessages, @Nullable SignaturePair lastMessage) {
|
||||
this.message = message;
|
||||
this.unsigned = true;
|
||||
}
|
||||
|
||||
public void setExpiry(@Nullable Instant expiry) {
|
||||
this.signedPreview = signedPreview;
|
||||
this.unsigned = unsigned;
|
||||
this.expiry = expiry;
|
||||
this.signature = signature;
|
||||
this.salt = salt;
|
||||
this.previousMessages = previousMessages;
|
||||
this.lastMessage = lastMessage;
|
||||
}
|
||||
|
||||
public Instant getExpiry() {
|
||||
public @Nullable Instant getExpiry() {
|
||||
return expiry;
|
||||
}
|
||||
|
||||
@@ -73,82 +75,96 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
||||
return signedPreview;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
message = ProtocolUtils.readString(buf, 256);
|
||||
|
||||
long expiresAt = buf.readLong();
|
||||
long saltLong = buf.readLong();
|
||||
byte[] signatureBytes = ProtocolUtils.readByteArray(buf);
|
||||
|
||||
if (saltLong != 0L && signatureBytes.length > 0) {
|
||||
salt = Longs.toByteArray(saltLong);
|
||||
signature = signatureBytes;
|
||||
expiry = Instant.ofEpochMilli(expiresAt);
|
||||
} else if ((protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
|| saltLong == 0L) && signatureBytes.length == 0) {
|
||||
unsigned = true;
|
||||
} else {
|
||||
throw EncryptionUtils.INVALID_SIGNATURE;
|
||||
}
|
||||
|
||||
signedPreview = buf.readBoolean();
|
||||
if (signedPreview && unsigned) {
|
||||
throw EncryptionUtils.PREVIEW_SIGNATURE_MISSING;
|
||||
}
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
if (size < 0 || size > MAXIMUM_PREVIOUS_MESSAGE_COUNT) {
|
||||
throw INVALID_PREVIOUS_MESSAGES;
|
||||
}
|
||||
|
||||
SignaturePair[] lastSignatures = new SignaturePair[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
lastSignatures[i] = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
previousMessages = lastSignatures;
|
||||
|
||||
if (buf.readBoolean()) {
|
||||
lastMessage = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, message);
|
||||
|
||||
buf.writeLong(unsigned ? Instant.now().toEpochMilli() : expiry.toEpochMilli());
|
||||
buf.writeLong(unsigned ? 0L : Longs.fromByteArray(salt));
|
||||
|
||||
ProtocolUtils.writeByteArray(buf, unsigned ? EncryptionUtils.EMPTY : signature);
|
||||
|
||||
buf.writeBoolean(signedPreview);
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
ProtocolUtils.writeVarInt(buf, previousMessages.length);
|
||||
for (SignaturePair previousMessage : previousMessages) {
|
||||
ProtocolUtils.writeUuid(buf, previousMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, previousMessage.getSignature());
|
||||
}
|
||||
|
||||
if (lastMessage != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, lastMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, lastMessage.getSignature());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<KeyedPlayerChatPacket> {
|
||||
@Override
|
||||
public KeyedPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
String message = ProtocolUtils.readString(buf, 256);
|
||||
|
||||
long expiresAt = buf.readLong();
|
||||
long saltLong = buf.readLong();
|
||||
byte[] signatureBytes = ProtocolUtils.readByteArray(buf);
|
||||
|
||||
byte[] salt = null;
|
||||
byte[] signature = null;
|
||||
Instant expiry = null;
|
||||
boolean unsigned;
|
||||
|
||||
if (saltLong != 0L && signatureBytes.length > 0) {
|
||||
salt = Longs.toByteArray(saltLong);
|
||||
signature = signatureBytes;
|
||||
expiry = Instant.ofEpochMilli(expiresAt);
|
||||
unsigned = false;
|
||||
} else if ((protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)
|
||||
|| saltLong == 0L) && signatureBytes.length == 0) {
|
||||
unsigned = true;
|
||||
} else {
|
||||
throw EncryptionUtils.INVALID_SIGNATURE;
|
||||
}
|
||||
|
||||
boolean signedPreview = buf.readBoolean();
|
||||
if (signedPreview && unsigned) {
|
||||
throw EncryptionUtils.PREVIEW_SIGNATURE_MISSING;
|
||||
}
|
||||
|
||||
SignaturePair[] previousMessages = new SignaturePair[0];
|
||||
SignaturePair lastMessage = null;
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
if (size < 0 || size > MAXIMUM_PREVIOUS_MESSAGE_COUNT) {
|
||||
throw INVALID_PREVIOUS_MESSAGES;
|
||||
}
|
||||
|
||||
SignaturePair[] lastSignatures = new SignaturePair[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
lastSignatures[i] = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
previousMessages = lastSignatures;
|
||||
|
||||
if (buf.readBoolean()) {
|
||||
lastMessage = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
}
|
||||
|
||||
return new KeyedPlayerChatPacket(message, signedPreview, unsigned, expiry, signature, salt,
|
||||
previousMessages, lastMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(KeyedPlayerChatPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.message);
|
||||
|
||||
buf.writeLong(packet.unsigned ? Instant.now().toEpochMilli() : packet.expiry.toEpochMilli());
|
||||
buf.writeLong(packet.unsigned ? 0L : Longs.fromByteArray(packet.salt));
|
||||
|
||||
ProtocolUtils.writeByteArray(buf, packet.unsigned ? EncryptionUtils.EMPTY : packet.signature);
|
||||
|
||||
buf.writeBoolean(packet.signedPreview);
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.previousMessages.length);
|
||||
for (SignaturePair previousMessage : packet.previousMessages) {
|
||||
ProtocolUtils.writeUuid(buf, previousMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, previousMessage.getSignature());
|
||||
}
|
||||
|
||||
if (packet.lastMessage != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, packet.lastMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, packet.lastMessage.getSignature());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,30 +26,43 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.crypto.EncryptionUtils;
|
||||
import com.velocitypowered.proxy.crypto.SignaturePair;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
||||
public final class KeyedPlayerCommandPacket implements MinecraftPacket {
|
||||
|
||||
private static final int MAX_NUM_ARGUMENTS = 8;
|
||||
private static final int MAX_LENGTH_ARGUMENTS = 16;
|
||||
private static final QuietDecoderException LIMITS_VIOLATION =
|
||||
new QuietDecoderException("Command arguments incorrect size");
|
||||
|
||||
private boolean unsigned = false;
|
||||
private String command;
|
||||
private Instant timestamp;
|
||||
private long salt;
|
||||
private boolean signedPreview; // purely for pass through for 1.19 -> 1.19.2 - this will never be implemented
|
||||
private SignaturePair[] previousMessages = new SignaturePair[0];
|
||||
private @Nullable SignaturePair lastMessage;
|
||||
private Map<String, byte[]> arguments = ImmutableMap.of();
|
||||
private final boolean unsigned;
|
||||
private final String command;
|
||||
private final Instant timestamp;
|
||||
private final long salt;
|
||||
private final boolean signedPreview;
|
||||
private final SignaturePair[] previousMessages;
|
||||
private final @Nullable SignaturePair lastMessage;
|
||||
private final Map<String, byte[]> arguments;
|
||||
|
||||
public KeyedPlayerCommandPacket(boolean unsigned, String command, Instant timestamp, long salt,
|
||||
boolean signedPreview, SignaturePair[] previousMessages, @Nullable SignaturePair lastMessage,
|
||||
Map<String, byte[]> arguments) {
|
||||
this.unsigned = unsigned;
|
||||
this.command = command;
|
||||
this.timestamp = timestamp;
|
||||
this.salt = salt;
|
||||
this.signedPreview = signedPreview;
|
||||
this.previousMessages = previousMessages;
|
||||
this.lastMessage = lastMessage;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public Instant getTimestamp() {
|
||||
return timestamp;
|
||||
@@ -63,116 +76,6 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
||||
return command;
|
||||
}
|
||||
|
||||
public KeyedPlayerCommandPacket() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link KeyedPlayerCommandPacket} packet based on a command and list of arguments.
|
||||
*
|
||||
* @param command the command to run
|
||||
* @param arguments the arguments of the command
|
||||
* @param timestamp the timestamp of the command execution
|
||||
*/
|
||||
public KeyedPlayerCommandPacket(String command, List<String> arguments, Instant timestamp) {
|
||||
this.unsigned = true;
|
||||
ImmutableMap.Builder<String, byte[]> builder = ImmutableMap.builder();
|
||||
arguments.forEach(entry -> builder.put(entry, EncryptionUtils.EMPTY));
|
||||
this.arguments = builder.build();
|
||||
this.timestamp = timestamp;
|
||||
this.command = command;
|
||||
this.signedPreview = false;
|
||||
this.salt = 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
command = ProtocolUtils.readString(buf, 256);
|
||||
timestamp = Instant.ofEpochMilli(buf.readLong());
|
||||
|
||||
salt = buf.readLong();
|
||||
|
||||
int mapSize = ProtocolUtils.readVarInt(buf);
|
||||
if (mapSize > MAX_NUM_ARGUMENTS) {
|
||||
throw LIMITS_VIOLATION;
|
||||
}
|
||||
// Mapped as Argument : signature
|
||||
ImmutableMap.Builder<String, byte[]> entries = ImmutableMap.builderWithExpectedSize(mapSize);
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
entries.put(ProtocolUtils.readString(buf, MAX_LENGTH_ARGUMENTS),
|
||||
ProtocolUtils.readByteArray(buf, unsigned ? 0 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE));
|
||||
}
|
||||
arguments = entries.build();
|
||||
|
||||
this.signedPreview = buf.readBoolean();
|
||||
if (unsigned && signedPreview) {
|
||||
throw EncryptionUtils.PREVIEW_SIGNATURE_MISSING;
|
||||
}
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
if (size < 0 || size > MAXIMUM_PREVIOUS_MESSAGE_COUNT) {
|
||||
throw INVALID_PREVIOUS_MESSAGES;
|
||||
}
|
||||
|
||||
SignaturePair[] lastSignatures = new SignaturePair[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
lastSignatures[i] = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
previousMessages = lastSignatures;
|
||||
|
||||
if (buf.readBoolean()) {
|
||||
lastMessage = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
}
|
||||
|
||||
if (salt == 0L && previousMessages.length == 0) {
|
||||
unsigned = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, command);
|
||||
buf.writeLong(timestamp.toEpochMilli());
|
||||
|
||||
buf.writeLong(unsigned ? 0L : salt);
|
||||
|
||||
int size = arguments.size();
|
||||
if (size > MAX_NUM_ARGUMENTS) {
|
||||
throw LIMITS_VIOLATION;
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, size);
|
||||
for (Map.Entry<String, byte[]> entry : arguments.entrySet()) {
|
||||
// What annoys me is that this isn't "sorted"
|
||||
ProtocolUtils.writeString(buf, entry.getKey());
|
||||
ProtocolUtils.writeByteArray(buf, unsigned ? EncryptionUtils.EMPTY : entry.getValue());
|
||||
}
|
||||
|
||||
buf.writeBoolean(signedPreview);
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
ProtocolUtils.writeVarInt(buf, previousMessages.length);
|
||||
for (SignaturePair previousMessage : previousMessages) {
|
||||
ProtocolUtils.writeUuid(buf, previousMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, previousMessage.getSignature());
|
||||
}
|
||||
|
||||
if (lastMessage != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, lastMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, lastMessage.getSignature());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlayerCommand{"
|
||||
@@ -190,4 +93,100 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<KeyedPlayerCommandPacket> {
|
||||
@Override
|
||||
public KeyedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
String command = ProtocolUtils.readString(buf, 256);
|
||||
Instant timestamp = Instant.ofEpochMilli(buf.readLong());
|
||||
|
||||
long salt = buf.readLong();
|
||||
|
||||
int mapSize = ProtocolUtils.readVarInt(buf);
|
||||
if (mapSize > MAX_NUM_ARGUMENTS) {
|
||||
throw LIMITS_VIOLATION;
|
||||
}
|
||||
|
||||
boolean unsigned = false;
|
||||
ImmutableMap.Builder<String, byte[]> entries = ImmutableMap.builderWithExpectedSize(mapSize);
|
||||
for (int i = 0; i < mapSize; i++) {
|
||||
entries.put(ProtocolUtils.readString(buf, MAX_LENGTH_ARGUMENTS),
|
||||
ProtocolUtils.readByteArray(buf, unsigned ? 0 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE));
|
||||
}
|
||||
Map<String, byte[]> arguments = entries.build();
|
||||
|
||||
boolean signedPreview = buf.readBoolean();
|
||||
if (unsigned && signedPreview) {
|
||||
throw EncryptionUtils.PREVIEW_SIGNATURE_MISSING;
|
||||
}
|
||||
|
||||
SignaturePair[] previousMessages = new SignaturePair[0];
|
||||
SignaturePair lastMessage = null;
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
if (size < 0 || size > MAXIMUM_PREVIOUS_MESSAGE_COUNT) {
|
||||
throw INVALID_PREVIOUS_MESSAGES;
|
||||
}
|
||||
|
||||
SignaturePair[] lastSignatures = new SignaturePair[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
lastSignatures[i] = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
previousMessages = lastSignatures;
|
||||
|
||||
if (buf.readBoolean()) {
|
||||
lastMessage = new SignaturePair(ProtocolUtils.readUuid(buf),
|
||||
ProtocolUtils.readByteArray(buf));
|
||||
}
|
||||
}
|
||||
|
||||
if (salt == 0L && previousMessages.length == 0) {
|
||||
unsigned = true;
|
||||
}
|
||||
|
||||
return new KeyedPlayerCommandPacket(unsigned, command, timestamp, salt, signedPreview,
|
||||
previousMessages, lastMessage, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(KeyedPlayerCommandPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.command);
|
||||
buf.writeLong(packet.timestamp.toEpochMilli());
|
||||
|
||||
buf.writeLong(packet.unsigned ? 0L : packet.salt);
|
||||
|
||||
int size = packet.arguments.size();
|
||||
if (size > MAX_NUM_ARGUMENTS) {
|
||||
throw LIMITS_VIOLATION;
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, size);
|
||||
for (Map.Entry<String, byte[]> entry : packet.arguments.entrySet()) {
|
||||
// What annoys me is that this isn't "sorted"
|
||||
ProtocolUtils.writeString(buf, entry.getKey());
|
||||
ProtocolUtils.writeByteArray(buf, packet.unsigned ? EncryptionUtils.EMPTY : entry.getValue());
|
||||
}
|
||||
|
||||
buf.writeBoolean(packet.signedPreview);
|
||||
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.previousMessages.length);
|
||||
for (SignaturePair previousMessage : packet.previousMessages) {
|
||||
ProtocolUtils.writeUuid(buf, previousMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, previousMessage.getSignature());
|
||||
}
|
||||
|
||||
if (packet.lastMessage != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeUuid(buf, packet.lastMessage.getSigner());
|
||||
ProtocolUtils.writeByteArray(buf, packet.lastMessage.getSignature());
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ public class LegacyChatBuilder extends ChatBuilderV2 {
|
||||
|
||||
@Override
|
||||
public MinecraftPacket toServer() {
|
||||
LegacyChatPacket chat = new LegacyChatPacket();
|
||||
chat.setMessage(message);
|
||||
return chat;
|
||||
return new LegacyChatPacket(message, (byte) 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,13 @@ package com.velocitypowered.proxy.protocol.packet.chat.legacy;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LegacyChatPacket implements MinecraftPacket {
|
||||
public record LegacyChatPacket(String message, byte type, @Nullable UUID sender) implements MinecraftPacket {
|
||||
|
||||
public static final byte CHAT_TYPE = (byte) 0;
|
||||
public static final byte SYSTEM_TYPE = (byte) 1;
|
||||
@@ -34,91 +35,44 @@ public class LegacyChatPacket implements MinecraftPacket {
|
||||
public static final int MAX_SERVERBOUND_MESSAGE_LENGTH = 256;
|
||||
public static final UUID EMPTY_SENDER = new UUID(0, 0);
|
||||
|
||||
private @Nullable String message;
|
||||
private byte type;
|
||||
private @Nullable UUID sender;
|
||||
|
||||
public LegacyChatPacket() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Chat packet.
|
||||
*/
|
||||
public LegacyChatPacket(String message, byte type, UUID sender) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Chat message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
if (message == null) {
|
||||
throw new IllegalStateException("Message is not specified");
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(byte type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public UUID getSenderUuid() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSenderUuid(UUID sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Chat{"
|
||||
+ "message='" + message + '\''
|
||||
+ ", type=" + type
|
||||
+ ", sender=" + sender
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
message = ProtocolUtils.readString(buf, direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
? 262144 : version.noLessThan(ProtocolVersion.MINECRAFT_1_11) ? 256 : 100);
|
||||
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
type = buf.readByte();
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
sender = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (message == null) {
|
||||
throw new IllegalStateException("Message is not specified");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, message);
|
||||
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeByte(type);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuid(buf, sender == null ? EMPTY_SENDER : sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<LegacyChatPacket> {
|
||||
@Override
|
||||
public LegacyChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
String message = ProtocolUtils.readString(buf, direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
? 262144 : version.noLessThan(ProtocolVersion.MINECRAFT_1_11) ? 256 : 100);
|
||||
byte type = 0;
|
||||
UUID sender = null;
|
||||
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
type = buf.readByte();
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
sender = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
}
|
||||
return new LegacyChatPacket(message, type, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LegacyChatPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
ProtocolUtils.writeString(buf, packet.message);
|
||||
if (direction == ProtocolUtils.Direction.CLIENTBOUND
|
||||
&& version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
buf.writeByte(packet.type);
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||
ProtocolUtils.writeUuid(buf, packet.sender == null ? EMPTY_SENDER : packet.sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,27 +44,14 @@ public class SessionChatBuilder extends ChatBuilderV2 {
|
||||
LastSeenMessages lastSeenMessages = this.lastSeenMessages != null ? this.lastSeenMessages : new LastSeenMessages();
|
||||
if (message.startsWith("/")) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
UnsignedPlayerCommandPacket command = new UnsignedPlayerCommandPacket();
|
||||
command.command = message.substring(1);
|
||||
return command;
|
||||
return new UnsignedPlayerCommandPacket(message.substring(1));
|
||||
} else {
|
||||
SessionPlayerCommandPacket command = new SessionPlayerCommandPacket();
|
||||
command.command = message.substring(1);
|
||||
command.salt = 0L;
|
||||
command.timeStamp = timestamp;
|
||||
command.argumentSignatures = new SessionPlayerCommandPacket.ArgumentSignatures();
|
||||
command.lastSeenMessages = lastSeenMessages;
|
||||
return command;
|
||||
return new SessionPlayerCommandPacket(message.substring(1), timestamp, 0L,
|
||||
new SessionPlayerCommandPacket.ArgumentSignatures(), lastSeenMessages);
|
||||
}
|
||||
} else {
|
||||
SessionPlayerChatPacket chat = new SessionPlayerChatPacket();
|
||||
chat.message = message;
|
||||
chat.signed = false;
|
||||
chat.signature = new byte[0];
|
||||
chat.timestamp = timestamp;
|
||||
chat.salt = 0L;
|
||||
chat.lastSeenMessages = lastSeenMessages;
|
||||
return chat;
|
||||
return new SessionPlayerChatPacket(message, timestamp, 0L, false, new byte[0],
|
||||
lastSeenMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -27,14 +28,21 @@ import java.time.Instant;
|
||||
|
||||
public class SessionPlayerChatPacket implements MinecraftPacket {
|
||||
|
||||
protected String message;
|
||||
protected Instant timestamp;
|
||||
protected long salt;
|
||||
protected boolean signed;
|
||||
protected byte[] signature;
|
||||
protected LastSeenMessages lastSeenMessages;
|
||||
protected final String message;
|
||||
protected final Instant timestamp;
|
||||
protected final long salt;
|
||||
protected final boolean signed;
|
||||
protected final byte[] signature;
|
||||
protected final LastSeenMessages lastSeenMessages;
|
||||
|
||||
public SessionPlayerChatPacket() {
|
||||
public SessionPlayerChatPacket(String message, Instant timestamp, long salt, boolean signed,
|
||||
byte[] signature, LastSeenMessages lastSeenMessages) {
|
||||
this.message = message;
|
||||
this.timestamp = timestamp;
|
||||
this.salt = salt;
|
||||
this.signed = signed;
|
||||
this.signature = signature;
|
||||
this.lastSeenMessages = lastSeenMessages;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
@@ -61,34 +69,6 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
||||
return lastSeenMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
this.message = ProtocolUtils.readString(buf, 256);
|
||||
this.timestamp = Instant.ofEpochMilli(buf.readLong());
|
||||
this.salt = buf.readLong();
|
||||
this.signed = buf.readBoolean();
|
||||
if (this.signed) {
|
||||
this.signature = readMessageSignature(buf);
|
||||
} else {
|
||||
this.signature = new byte[0];
|
||||
}
|
||||
this.lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, this.message);
|
||||
buf.writeLong(this.timestamp.toEpochMilli());
|
||||
buf.writeLong(this.salt);
|
||||
buf.writeBoolean(this.signed);
|
||||
if (this.signed) {
|
||||
buf.writeBytes(this.signature);
|
||||
}
|
||||
this.lastSeenMessages.encode(buf, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
@@ -101,13 +81,38 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
||||
}
|
||||
|
||||
public SessionPlayerChatPacket withLastSeenMessages(LastSeenMessages lastSeenMessages) {
|
||||
SessionPlayerChatPacket packet = new SessionPlayerChatPacket();
|
||||
packet.message = message;
|
||||
packet.timestamp = timestamp;
|
||||
packet.salt = salt;
|
||||
packet.signed = signed;
|
||||
packet.signature = signature;
|
||||
packet.lastSeenMessages = lastSeenMessages;
|
||||
return packet;
|
||||
return new SessionPlayerChatPacket(message, timestamp, salt, signed, signature, lastSeenMessages);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<SessionPlayerChatPacket> {
|
||||
@Override
|
||||
public SessionPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
String message = ProtocolUtils.readString(buf, 256);
|
||||
Instant timestamp = Instant.ofEpochMilli(buf.readLong());
|
||||
long salt = buf.readLong();
|
||||
boolean signed = buf.readBoolean();
|
||||
byte[] signature;
|
||||
if (signed) {
|
||||
signature = readMessageSignature(buf);
|
||||
} else {
|
||||
signature = new byte[0];
|
||||
}
|
||||
LastSeenMessages lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||
return new SessionPlayerChatPacket(message, timestamp, salt, signed, signature, lastSeenMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(SessionPlayerChatPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.message);
|
||||
buf.writeLong(packet.timestamp.toEpochMilli());
|
||||
buf.writeLong(packet.salt);
|
||||
buf.writeBoolean(packet.signed);
|
||||
if (packet.signed) {
|
||||
buf.writeBytes(packet.signature);
|
||||
}
|
||||
packet.lastSeenMessages.encode(buf, protocolVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
@@ -33,29 +34,19 @@ import java.util.List;
|
||||
|
||||
public class SessionPlayerCommandPacket implements MinecraftPacket {
|
||||
|
||||
protected String command;
|
||||
protected Instant timeStamp;
|
||||
protected long salt;
|
||||
protected ArgumentSignatures argumentSignatures;
|
||||
protected LastSeenMessages lastSeenMessages;
|
||||
protected final String command;
|
||||
protected final Instant timeStamp;
|
||||
protected final long salt;
|
||||
protected final ArgumentSignatures argumentSignatures;
|
||||
protected final LastSeenMessages lastSeenMessages;
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
int cap = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5) ? 256 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE;
|
||||
this.command = ProtocolUtils.readString(buf, cap);
|
||||
this.timeStamp = Instant.ofEpochMilli(buf.readLong());
|
||||
this.salt = buf.readLong();
|
||||
this.argumentSignatures = new ArgumentSignatures(buf);
|
||||
this.lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, this.command);
|
||||
buf.writeLong(this.timeStamp.toEpochMilli());
|
||||
buf.writeLong(this.salt);
|
||||
this.argumentSignatures.encode(buf);
|
||||
this.lastSeenMessages.encode(buf, protocolVersion);
|
||||
public SessionPlayerCommandPacket(String command, Instant timeStamp, long salt,
|
||||
ArgumentSignatures argumentSignatures, LastSeenMessages lastSeenMessages) {
|
||||
this.command = command;
|
||||
this.timeStamp = timeStamp;
|
||||
this.salt = salt;
|
||||
this.argumentSignatures = argumentSignatures;
|
||||
this.lastSeenMessages = lastSeenMessages;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
@@ -92,17 +83,33 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
||||
|
||||
public SessionPlayerCommandPacket withLastSeenMessages(@Nullable LastSeenMessages lastSeenMessages) {
|
||||
if (lastSeenMessages == null) {
|
||||
UnsignedPlayerCommandPacket packet = new UnsignedPlayerCommandPacket();
|
||||
packet.command = command;
|
||||
return packet;
|
||||
return new UnsignedPlayerCommandPacket(command);
|
||||
}
|
||||
return new SessionPlayerCommandPacket(command, timeStamp, salt, argumentSignatures, lastSeenMessages);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<SessionPlayerCommandPacket> {
|
||||
@Override
|
||||
public SessionPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int cap = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5) ? 256 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE;
|
||||
String command = ProtocolUtils.readString(buf, cap);
|
||||
Instant timeStamp = Instant.ofEpochMilli(buf.readLong());
|
||||
long salt = buf.readLong();
|
||||
ArgumentSignatures argumentSignatures = new ArgumentSignatures(buf);
|
||||
LastSeenMessages lastSeenMessages = new LastSeenMessages(buf, protocolVersion);
|
||||
return new SessionPlayerCommandPacket(command, timeStamp, salt, argumentSignatures, lastSeenMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(SessionPlayerCommandPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.command);
|
||||
buf.writeLong(packet.timeStamp.toEpochMilli());
|
||||
buf.writeLong(packet.salt);
|
||||
packet.argumentSignatures.encode(buf);
|
||||
packet.lastSeenMessages.encode(buf, protocolVersion);
|
||||
}
|
||||
SessionPlayerCommandPacket packet = new SessionPlayerCommandPacket();
|
||||
packet.command = command;
|
||||
packet.timeStamp = timeStamp;
|
||||
packet.salt = salt;
|
||||
packet.argumentSignatures = argumentSignatures;
|
||||
packet.lastSeenMessages = lastSeenMessages;
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static class ArgumentSignatures {
|
||||
|
||||
@@ -19,21 +19,18 @@ package com.velocitypowered.proxy.protocol.packet.chat.session;
|
||||
|
||||
import com.velocitypowered.api.event.command.CommandExecuteEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
||||
import java.time.Instant;
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.command = ProtocolUtils.readString(buf, ProtocolUtils.DEFAULT_MAX_STRING_SIZE);
|
||||
}
|
||||
public final class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, this.command);
|
||||
public UnsignedPlayerCommandPacket(String command) {
|
||||
super(command, Instant.EPOCH, 0L, new ArgumentSignatures(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,6 +38,7 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSigned() {
|
||||
return false;
|
||||
}
|
||||
@@ -56,4 +54,19 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
||||
"command='" + command + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<UnsignedPlayerCommandPacket> {
|
||||
@Override
|
||||
public UnsignedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
String command = ProtocolUtils.readString(buf, ProtocolUtils.DEFAULT_MAX_STRING_SIZE);
|
||||
return new UnsignedPlayerCommandPacket(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(UnsignedPlayerCommandPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(buf, packet.command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,44 +20,38 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
public class ActiveFeaturesPacket implements MinecraftPacket {
|
||||
|
||||
private Key[] activeFeatures;
|
||||
|
||||
public ActiveFeaturesPacket(Key[] activeFeatures) {
|
||||
this.activeFeatures = activeFeatures;
|
||||
}
|
||||
public record ActiveFeaturesPacket(Key[] activeFeatures) implements MinecraftPacket {
|
||||
|
||||
public ActiveFeaturesPacket() {
|
||||
this.activeFeatures = new Key[0];
|
||||
}
|
||||
|
||||
public void setActiveFeatures(Key[] activeFeatures) {
|
||||
this.activeFeatures = activeFeatures;
|
||||
this(new Key[0]);
|
||||
}
|
||||
|
||||
public Key[] getActiveFeatures() {
|
||||
return activeFeatures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
activeFeatures = ProtocolUtils.readKeyArray(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKeyArray(buf, activeFeatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ActiveFeaturesPacket> {
|
||||
@Override
|
||||
public ActiveFeaturesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
Key[] activeFeatures = ProtocolUtils.readKeyArray(buf);
|
||||
return new ActiveFeaturesPacket(activeFeatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ActiveFeaturesPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeKeyArray(buf, packet.activeFeatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,40 +20,16 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClientboundCustomReportDetailsPacket implements MinecraftPacket {
|
||||
|
||||
private Map<String, String> details;
|
||||
public record ClientboundCustomReportDetailsPacket(Map<String, String> details) implements MinecraftPacket {
|
||||
|
||||
public ClientboundCustomReportDetailsPacket() {
|
||||
}
|
||||
|
||||
public ClientboundCustomReportDetailsPacket(Map<String, String> details) {
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
int detailsCount = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
this.details = new HashMap<>(detailsCount);
|
||||
for (int i = 0; i < detailsCount; i++) {
|
||||
details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, details.size());
|
||||
|
||||
details.forEach((key, detail) -> {
|
||||
ProtocolUtils.writeString(buf, key);
|
||||
ProtocolUtils.writeString(buf, detail);
|
||||
});
|
||||
this(Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +37,28 @@ public class ClientboundCustomReportDetailsPacket implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return details;
|
||||
public static class Codec implements PacketCodec<ClientboundCustomReportDetailsPacket> {
|
||||
@Override
|
||||
public ClientboundCustomReportDetailsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
int detailsCount = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
Map<String, String> details = new HashMap<>(detailsCount);
|
||||
for (int i = 0; i < detailsCount; i++) {
|
||||
details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf));
|
||||
}
|
||||
return new ClientboundCustomReportDetailsPacket(details);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientboundCustomReportDetailsPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.details.size());
|
||||
|
||||
packet.details.forEach((key, detail) -> {
|
||||
ProtocolUtils.writeString(buf, key);
|
||||
ProtocolUtils.writeString(buf, detail);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,40 +21,17 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.util.ServerLink;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ClientboundServerLinksPacket implements MinecraftPacket {
|
||||
|
||||
private List<ServerLink> serverLinks;
|
||||
public record ClientboundServerLinksPacket(List<ServerLink> serverLinks) implements MinecraftPacket {
|
||||
|
||||
public ClientboundServerLinksPacket() {
|
||||
}
|
||||
|
||||
public ClientboundServerLinksPacket(List<ServerLink> serverLinks) {
|
||||
this.serverLinks = serverLinks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
int linksCount = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
this.serverLinks = new ArrayList<>(linksCount);
|
||||
for (int i = 0; i < linksCount; i++) {
|
||||
serverLinks.add(ServerLink.read(buf, version));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, serverLinks.size());
|
||||
|
||||
for (ServerLink serverLink : serverLinks) {
|
||||
serverLink.write(buf);
|
||||
}
|
||||
this(List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,10 +39,6 @@ public class ClientboundServerLinksPacket implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public List<ServerLink> getServerLinks() {
|
||||
return serverLinks;
|
||||
}
|
||||
|
||||
public record ServerLink(int id, ComponentHolder displayName, String url) {
|
||||
|
||||
private static ServerLink read(ByteBuf buf, ProtocolVersion version) {
|
||||
@@ -87,4 +60,28 @@ public class ClientboundServerLinksPacket implements MinecraftPacket {
|
||||
ProtocolUtils.writeString(buf, url);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<ClientboundServerLinksPacket> {
|
||||
@Override
|
||||
public ClientboundServerLinksPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
int linksCount = ProtocolUtils.readVarInt(buf);
|
||||
|
||||
List<ServerLink> serverLinks = new ArrayList<>(linksCount);
|
||||
for (int i = 0; i < linksCount; i++) {
|
||||
serverLinks.add(ServerLink.read(buf, version));
|
||||
}
|
||||
return new ClientboundServerLinksPacket(serverLinks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ClientboundServerLinksPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.serverLinks.size());
|
||||
|
||||
for (ServerLink serverLink : packet.serverLinks) {
|
||||
serverLink.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,26 +20,32 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class CodeOfConductAcceptPacket implements MinecraftPacket {
|
||||
public final class CodeOfConductAcceptPacket implements MinecraftPacket {
|
||||
|
||||
public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket();
|
||||
|
||||
private CodeOfConductAcceptPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<CodeOfConductAcceptPacket> {
|
||||
@Override
|
||||
public CodeOfConductAcceptPacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(CodeOfConductAcceptPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,24 +20,15 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
|
||||
public class CodeOfConductPacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public class CodeOfConductPacket extends DefaultByteBufHolder implements MinecraftPacket {
|
||||
|
||||
public CodeOfConductPacket() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
buf.writeBytes(this.content());
|
||||
public CodeOfConductPacket(ByteBuf buf) {
|
||||
super(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,7 +37,61 @@ public class CodeOfConductPacket extends DeferredByteBufHolder implements Minecr
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
public CodeOfConductPacket copy() {
|
||||
return (CodeOfConductPacket) super.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket duplicate() {
|
||||
return (CodeOfConductPacket) super.duplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket retainedDuplicate() {
|
||||
return (CodeOfConductPacket) super.retainedDuplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket replace(ByteBuf content) {
|
||||
return (CodeOfConductPacket) super.replace(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket retain() {
|
||||
return (CodeOfConductPacket) super.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket retain(int increment) {
|
||||
return (CodeOfConductPacket) super.retain(increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket touch() {
|
||||
return (CodeOfConductPacket) super.touch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeOfConductPacket touch(Object hint) {
|
||||
return (CodeOfConductPacket) super.touch(hint);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<CodeOfConductPacket> {
|
||||
@Override
|
||||
public CodeOfConductPacket decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
return new CodeOfConductPacket(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(CodeOfConductPacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeBytes(packet.content());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(CodeOfConductPacket packet, Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return packet.content().readableBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,33 +20,37 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class FinishedUpdatePacket implements MinecraftPacket {
|
||||
public final class FinishedUpdatePacket implements MinecraftPacket {
|
||||
public static final FinishedUpdatePacket INSTANCE = new FinishedUpdatePacket();
|
||||
|
||||
private FinishedUpdatePacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<FinishedUpdatePacket> {
|
||||
@Override
|
||||
public FinishedUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(FinishedUpdatePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,43 +20,15 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class KnownPacksPacket implements MinecraftPacket {
|
||||
public record KnownPacksPacket(KnownPack[] packs) implements MinecraftPacket {
|
||||
|
||||
private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64);
|
||||
private static final QuietDecoderException TOO_MANY_PACKS =
|
||||
new QuietDecoderException("too many known packs");
|
||||
|
||||
private KnownPack[] packs;
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
final int packCount = ProtocolUtils.readVarInt(buf);
|
||||
if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) {
|
||||
throw TOO_MANY_PACKS;
|
||||
}
|
||||
|
||||
final KnownPack[] packs = new KnownPack[packCount];
|
||||
|
||||
for (int i = 0; i < packCount; i++) {
|
||||
packs[i] = KnownPack.read(buf);
|
||||
}
|
||||
|
||||
this.packs = packs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packs.length);
|
||||
|
||||
for (KnownPack pack : packs) {
|
||||
pack.write(buf);
|
||||
}
|
||||
public KnownPacksPacket() {
|
||||
this(new KnownPack[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,4 +47,37 @@ public class KnownPacksPacket implements MinecraftPacket {
|
||||
ProtocolUtils.writeString(buf, version);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<KnownPacksPacket> {
|
||||
private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64);
|
||||
private static final QuietDecoderException TOO_MANY_PACKS =
|
||||
new QuietDecoderException("too many known packs");
|
||||
|
||||
@Override
|
||||
public KnownPacksPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
final int packCount = ProtocolUtils.readVarInt(buf);
|
||||
if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) {
|
||||
throw TOO_MANY_PACKS;
|
||||
}
|
||||
|
||||
final KnownPack[] packs = new KnownPack[packCount];
|
||||
|
||||
for (int i = 0; i < packCount; i++) {
|
||||
packs[i] = KnownPack.read(buf);
|
||||
}
|
||||
|
||||
return new KnownPacksPacket(packs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(KnownPacksPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.packs.length);
|
||||
|
||||
for (KnownPack pack : packet.packs) {
|
||||
pack.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,28 +20,16 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.DefaultByteBufHolder;
|
||||
|
||||
public class RegistrySyncPacket extends DeferredByteBufHolder implements MinecraftPacket {
|
||||
public final class RegistrySyncPacket extends DefaultByteBufHolder implements MinecraftPacket {
|
||||
|
||||
public RegistrySyncPacket() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
// NBT change in 1.20.2 makes it difficult to parse this packet.
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
this.replace(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeBytes(content());
|
||||
public RegistrySyncPacket(ByteBuf backing) {
|
||||
super(backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,8 +37,22 @@ public class RegistrySyncPacket extends DeferredByteBufHolder implements Minecra
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
return content().readableBytes();
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<RegistrySyncPacket> {
|
||||
@Override
|
||||
public RegistrySyncPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
// NBT change in 1.20.2 makes it difficult to parse this packet.
|
||||
return new RegistrySyncPacket(buf.readRetainedSlice(buf.readableBytes()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(RegistrySyncPacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
buf.writeBytes(packet.content());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,33 +20,37 @@ package com.velocitypowered.proxy.protocol.packet.config;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class StartUpdatePacket implements MinecraftPacket {
|
||||
public final class StartUpdatePacket implements MinecraftPacket {
|
||||
public static final StartUpdatePacket INSTANCE = new StartUpdatePacket();
|
||||
|
||||
private StartUpdatePacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<StartUpdatePacket> {
|
||||
@Override
|
||||
public StartUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(StartUpdatePacket packet, ByteBuf buf,
|
||||
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,59 +21,23 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TagsUpdatePacket implements MinecraftPacket {
|
||||
public final class TagsUpdatePacket implements MinecraftPacket {
|
||||
|
||||
private Map<String, Map<String, int[]>> tags;
|
||||
private final Map<String, Map<String, int[]>> tags;
|
||||
|
||||
public TagsUpdatePacket(Map<String, Map<String, int[]>> tags) {
|
||||
this.tags = tags;
|
||||
this.tags = ImmutableMap.copyOf(tags);
|
||||
}
|
||||
|
||||
public TagsUpdatePacket() {
|
||||
this.tags = Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ImmutableMap.Builder<String, Map<String, int[]>> builder = ImmutableMap.builder();
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
for (int i = 0; i < size; i++) {
|
||||
String key = ProtocolUtils.readString(buf);
|
||||
|
||||
int innerSize = ProtocolUtils.readVarInt(buf);
|
||||
ImmutableMap.Builder<String, int[]> innerBuilder = ImmutableMap.builder();
|
||||
for (int j = 0; j < innerSize; j++) {
|
||||
String innerKey = ProtocolUtils.readString(buf);
|
||||
int[] innerValue = ProtocolUtils.readVarIntArray(buf);
|
||||
innerBuilder.put(innerKey, innerValue);
|
||||
}
|
||||
|
||||
builder.put(key, innerBuilder.build());
|
||||
}
|
||||
tags = builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, tags.size());
|
||||
for (Map.Entry<String, Map<String, int[]>> entry : tags.entrySet()) {
|
||||
ProtocolUtils.writeString(buf, entry.getKey());
|
||||
// Oh, joy
|
||||
ProtocolUtils.writeVarInt(buf, entry.getValue().size());
|
||||
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
||||
// Yea, object oriented programming be damned
|
||||
ProtocolUtils.writeString(buf, innerEntry.getKey());
|
||||
ProtocolUtils.writeVarIntArray(buf, innerEntry.getValue());
|
||||
}
|
||||
}
|
||||
public Map<String, Map<String, int[]>> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,21 +45,61 @@ public class TagsUpdatePacket implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||
int size = ProtocolUtils.varIntBytes(tags.size());
|
||||
for (Map.Entry<String, Map<String, int[]>> entry : tags.entrySet()) {
|
||||
size += ProtocolUtils.stringSizeHint(entry.getKey());
|
||||
size += ProtocolUtils.varIntBytes(entry.getValue().size());
|
||||
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
||||
size += ProtocolUtils.stringSizeHint(innerEntry.getKey());
|
||||
size += ProtocolUtils.varIntBytes(innerEntry.getValue().length);
|
||||
for (int innerEntryValue : innerEntry.getValue()) {
|
||||
size += ProtocolUtils.varIntBytes(innerEntryValue);
|
||||
public static class Codec implements PacketCodec<TagsUpdatePacket> {
|
||||
@Override
|
||||
public TagsUpdatePacket decode(ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ImmutableMap.Builder<String, Map<String, int[]>> builder = ImmutableMap.builder();
|
||||
int size = ProtocolUtils.readVarInt(buf);
|
||||
for (int i = 0; i < size; i++) {
|
||||
String key = ProtocolUtils.readString(buf);
|
||||
|
||||
int innerSize = ProtocolUtils.readVarInt(buf);
|
||||
ImmutableMap.Builder<String, int[]> innerBuilder = ImmutableMap.builder();
|
||||
for (int j = 0; j < innerSize; j++) {
|
||||
String innerKey = ProtocolUtils.readString(buf);
|
||||
int[] innerValue = ProtocolUtils.readVarIntArray(buf);
|
||||
innerBuilder.put(innerKey, innerValue);
|
||||
}
|
||||
|
||||
builder.put(key, innerBuilder.build());
|
||||
}
|
||||
return new TagsUpdatePacket(builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TagsUpdatePacket packet, ByteBuf buf, Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeVarInt(buf, packet.tags.size());
|
||||
for (Map.Entry<String, Map<String, int[]>> entry : packet.tags.entrySet()) {
|
||||
ProtocolUtils.writeString(buf, entry.getKey());
|
||||
// Oh, joy
|
||||
ProtocolUtils.writeVarInt(buf, entry.getValue().size());
|
||||
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
||||
// Yea, object oriented programming be damned
|
||||
ProtocolUtils.writeString(buf, innerEntry.getKey());
|
||||
ProtocolUtils.writeVarIntArray(buf, innerEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
@Override
|
||||
public int encodeSizeHint(TagsUpdatePacket packet, Direction direction, ProtocolVersion version) {
|
||||
var tags = packet.tags;
|
||||
int size = ProtocolUtils.varIntBytes(tags.size());
|
||||
for (Map.Entry<String, Map<String, int[]>> entry : tags.entrySet()) {
|
||||
size += ProtocolUtils.stringSizeHint(entry.getKey());
|
||||
size += ProtocolUtils.varIntBytes(entry.getValue().size());
|
||||
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
||||
size += ProtocolUtils.stringSizeHint(innerEntry.getKey());
|
||||
size += ProtocolUtils.varIntBytes(innerEntry.getValue().length);
|
||||
for (int innerEntryValue : innerEntry.getValue()) {
|
||||
size += ProtocolUtils.varIntBytes(innerEntryValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,7 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public abstract class GenericTitlePacket implements MinecraftPacket {
|
||||
|
||||
@@ -45,10 +43,9 @@ public abstract class GenericTitlePacket implements MinecraftPacket {
|
||||
}
|
||||
}
|
||||
|
||||
private final ActionType action;
|
||||
|
||||
private ActionType action;
|
||||
|
||||
protected void setAction(ActionType action) {
|
||||
protected GenericTitlePacket(ActionType action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@@ -60,76 +57,77 @@ public abstract class GenericTitlePacket implements MinecraftPacket {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public void setComponent(ComponentHolder component) {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public int getFadeIn() {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public void setFadeIn(int fadeIn) {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public int getStay() {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public void setStay(int stay) {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public int getFadeOut() {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
public void setFadeOut(int fadeOut) {
|
||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion version) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version and type dependent TitlePacket.
|
||||
* Creates a version and type dependent TitlePacket for HIDE/RESET actions.
|
||||
*
|
||||
* @param type Action the packet should invoke
|
||||
* @param type Action the packet should invoke (HIDE or RESET)
|
||||
* @param version Protocol version of the target player
|
||||
* @return GenericTitlePacket instance that follows the invoker type/version
|
||||
*/
|
||||
public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) {
|
||||
GenericTitlePacket packet = null;
|
||||
public static GenericTitlePacket createClearTitlePacket(ActionType type, ProtocolVersion version) {
|
||||
if (type != ActionType.HIDE && type != ActionType.RESET) {
|
||||
throw new IllegalArgumentException("createClearTitlePacket only accepts HIDE and RESET actions");
|
||||
}
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
return new TitleClearPacket(type == ActionType.RESET);
|
||||
} else {
|
||||
return new LegacyTitlePacket(type, null, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version and type dependent TitlePacket for component-based actions.
|
||||
*
|
||||
* @param type Action the packet should invoke
|
||||
* @param component Component to display
|
||||
* @param version Protocol version of the target player
|
||||
* @return GenericTitlePacket instance that follows the invoker type/version
|
||||
*/
|
||||
public static GenericTitlePacket createComponentTitlePacket(ActionType type,
|
||||
ComponentHolder component, ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
switch (type) {
|
||||
case SET_ACTION_BAR:
|
||||
packet = new TitleActionbarPacket();
|
||||
break;
|
||||
return new TitleActionbarPacket(component);
|
||||
case SET_SUBTITLE:
|
||||
packet = new TitleSubtitlePacket();
|
||||
break;
|
||||
case SET_TIMES:
|
||||
packet = new TitleTimesPacket();
|
||||
break;
|
||||
return new TitleSubtitlePacket(component);
|
||||
case SET_TITLE:
|
||||
packet = new TitleTextPacket();
|
||||
break;
|
||||
case HIDE:
|
||||
case RESET:
|
||||
packet = new TitleClearPacket();
|
||||
break;
|
||||
return new TitleTextPacket(component);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid ActionType");
|
||||
throw new IllegalArgumentException("Invalid ActionType for component title: " + type);
|
||||
}
|
||||
} else {
|
||||
packet = new LegacyTitlePacket();
|
||||
return new LegacyTitlePacket(type, component, 0, 0, 0);
|
||||
}
|
||||
packet.setAction(type);
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a version dependent TitlePacket for times.
|
||||
*
|
||||
* @param fadeIn Fade in time
|
||||
* @param stay Stay time
|
||||
* @param fadeOut Fade out time
|
||||
* @param version Protocol version of the target player
|
||||
* @return GenericTitlePacket instance that follows the invoker type/version
|
||||
*/
|
||||
public static GenericTitlePacket createTimesTitlePacket(int fadeIn, int stay, int fadeOut,
|
||||
ProtocolVersion version) {
|
||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||
return new TitleTimesPacket(fadeIn, stay, fadeOut);
|
||||
} else {
|
||||
return new LegacyTitlePacket(ActionType.SET_TIMES, null, fadeIn, stay, fadeOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,52 +19,26 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class LegacyTitlePacket extends GenericTitlePacket {
|
||||
public final class LegacyTitlePacket extends GenericTitlePacket {
|
||||
|
||||
private @Nullable ComponentHolder component;
|
||||
private int fadeIn;
|
||||
private int stay;
|
||||
private int fadeOut;
|
||||
private final @Nullable ComponentHolder component;
|
||||
private final int fadeIn;
|
||||
private final int stay;
|
||||
private final int fadeOut;
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_11)
|
||||
&& getAction() == ActionType.SET_ACTION_BAR) {
|
||||
throw new IllegalStateException("Action bars are only supported on 1.11 and newer");
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, getAction().getAction(version));
|
||||
|
||||
switch (getAction()) {
|
||||
case SET_TITLE:
|
||||
case SET_SUBTITLE:
|
||||
case SET_ACTION_BAR:
|
||||
if (component == null) {
|
||||
throw new IllegalStateException("No component found for " + getAction());
|
||||
}
|
||||
component.write(buf);
|
||||
break;
|
||||
case SET_TIMES:
|
||||
buf.writeInt(fadeIn);
|
||||
buf.writeInt(stay);
|
||||
buf.writeInt(fadeOut);
|
||||
break;
|
||||
case HIDE:
|
||||
case RESET:
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + getAction());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAction(ActionType action) {
|
||||
super.setAction(action);
|
||||
public LegacyTitlePacket(ActionType action, @Nullable ComponentHolder component,
|
||||
int fadeIn, int stay, int fadeOut) {
|
||||
super(action);
|
||||
this.component = component;
|
||||
this.fadeIn = fadeIn;
|
||||
this.stay = stay;
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,44 +46,24 @@ public class LegacyTitlePacket extends GenericTitlePacket {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComponent(@Nullable ComponentHolder component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeIn(int fadeIn) {
|
||||
this.fadeIn = fadeIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStay() {
|
||||
return stay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStay(int stay) {
|
||||
this.stay = stay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeOut(int fadeOut) {
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GenericTitlePacket{"
|
||||
return "LegacyTitlePacket{"
|
||||
+ "action=" + getAction()
|
||||
+ ", component='" + component + '\''
|
||||
+ ", fadeIn=" + fadeIn
|
||||
@@ -122,4 +76,43 @@ public class LegacyTitlePacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<LegacyTitlePacket> {
|
||||
@Override
|
||||
public LegacyTitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(LegacyTitlePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_11)
|
||||
&& packet.getAction() == ActionType.SET_ACTION_BAR) {
|
||||
throw new IllegalStateException("Action bars are only supported on 1.11 and newer");
|
||||
}
|
||||
ProtocolUtils.writeVarInt(buf, packet.getAction().getAction(protocolVersion));
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case SET_TITLE:
|
||||
case SET_SUBTITLE:
|
||||
case SET_ACTION_BAR:
|
||||
if (packet.component == null) {
|
||||
throw new IllegalStateException("No component found for " + packet.getAction());
|
||||
}
|
||||
packet.component.write(buf);
|
||||
break;
|
||||
case SET_TIMES:
|
||||
buf.writeInt(packet.fadeIn);
|
||||
buf.writeInt(packet.stay);
|
||||
buf.writeInt(packet.fadeOut);
|
||||
break;
|
||||
case HIDE:
|
||||
case RESET:
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown action " + packet.getAction());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,18 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class TitleActionbarPacket extends GenericTitlePacket {
|
||||
public final class TitleActionbarPacket extends GenericTitlePacket {
|
||||
|
||||
private ComponentHolder component;
|
||||
private final ComponentHolder component;
|
||||
|
||||
public TitleActionbarPacket() {
|
||||
setAction(ActionType.SET_TITLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
component.write(buf);
|
||||
public TitleActionbarPacket(ComponentHolder component) {
|
||||
super(ActionType.SET_ACTION_BAR);
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,15 +38,10 @@ public class TitleActionbarPacket extends GenericTitlePacket {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComponent(ComponentHolder component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TitleActionbarPacket{"
|
||||
+ ", component='" + component + '\''
|
||||
+ "component='" + component + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -57,4 +49,18 @@ public class TitleActionbarPacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TitleActionbarPacket> {
|
||||
@Override
|
||||
public TitleActionbarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TitleActionbarPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
packet.component.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,32 +19,27 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class TitleClearPacket extends GenericTitlePacket {
|
||||
public final class TitleClearPacket extends GenericTitlePacket {
|
||||
|
||||
public TitleClearPacket() {
|
||||
setAction(ActionType.HIDE);
|
||||
private final boolean reset;
|
||||
|
||||
public TitleClearPacket(boolean reset) {
|
||||
super(reset ? ActionType.RESET : ActionType.HIDE);
|
||||
this.reset = reset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAction(ActionType action) {
|
||||
if (action != ActionType.HIDE && action != ActionType.RESET) {
|
||||
throw new IllegalArgumentException("TitleClearPacket only accepts CLEAR and RESET actions");
|
||||
}
|
||||
super.setAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
buf.writeBoolean(getAction() == ActionType.RESET);
|
||||
public boolean isReset() {
|
||||
return reset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TitleClearPacket{"
|
||||
+ ", resetTimes=" + (getAction() == ActionType.RESET)
|
||||
+ "resetTimes=" + reset
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -52,4 +47,18 @@ public class TitleClearPacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TitleClearPacket> {
|
||||
@Override
|
||||
public TitleClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TitleClearPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeBoolean(packet.reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,18 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class TitleSubtitlePacket extends GenericTitlePacket {
|
||||
public final class TitleSubtitlePacket extends GenericTitlePacket {
|
||||
|
||||
private ComponentHolder component;
|
||||
private final ComponentHolder component;
|
||||
|
||||
public TitleSubtitlePacket() {
|
||||
setAction(ActionType.SET_SUBTITLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
component.write(buf);
|
||||
public TitleSubtitlePacket(ComponentHolder component) {
|
||||
super(ActionType.SET_SUBTITLE);
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,15 +38,10 @@ public class TitleSubtitlePacket extends GenericTitlePacket {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComponent(ComponentHolder component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TitleSubtitlePacket{"
|
||||
+ ", component='" + component + '\''
|
||||
+ "component='" + component + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -57,4 +49,18 @@ public class TitleSubtitlePacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TitleSubtitlePacket> {
|
||||
@Override
|
||||
public TitleSubtitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TitleSubtitlePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
packet.component.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,21 +19,18 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class TitleTextPacket extends GenericTitlePacket {
|
||||
public final class TitleTextPacket extends GenericTitlePacket {
|
||||
|
||||
private ComponentHolder component;
|
||||
private final ComponentHolder component;
|
||||
|
||||
public TitleTextPacket() {
|
||||
setAction(ActionType.SET_TITLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
component.write(buf);
|
||||
public TitleTextPacket(ComponentHolder component) {
|
||||
super(ActionType.SET_TITLE);
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,15 +38,10 @@ public class TitleTextPacket extends GenericTitlePacket {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComponent(ComponentHolder component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TitleTextPacket{"
|
||||
+ ", component='" + component + '\''
|
||||
+ "component='" + component + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -57,4 +49,18 @@ public class TitleTextPacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TitleTextPacket> {
|
||||
@Override
|
||||
public TitleTextPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TitleTextPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
packet.component.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,24 +19,21 @@ package com.velocitypowered.proxy.protocol.packet.title;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class TitleTimesPacket extends GenericTitlePacket {
|
||||
public final class TitleTimesPacket extends GenericTitlePacket {
|
||||
|
||||
private int fadeIn;
|
||||
private int stay;
|
||||
private int fadeOut;
|
||||
private final int fadeIn;
|
||||
private final int stay;
|
||||
private final int fadeOut;
|
||||
|
||||
public TitleTimesPacket() {
|
||||
setAction(ActionType.SET_TIMES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
buf.writeInt(fadeIn);
|
||||
buf.writeInt(stay);
|
||||
buf.writeInt(fadeOut);
|
||||
public TitleTimesPacket(int fadeIn, int stay, int fadeOut) {
|
||||
super(ActionType.SET_TIMES);
|
||||
this.fadeIn = fadeIn;
|
||||
this.stay = stay;
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,35 +41,20 @@ public class TitleTimesPacket extends GenericTitlePacket {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeIn(int fadeIn) {
|
||||
this.fadeIn = fadeIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStay() {
|
||||
return stay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStay(int stay) {
|
||||
this.stay = stay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeOut(int fadeOut) {
|
||||
this.fadeOut = fadeOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TitleTimesPacket{"
|
||||
+ ", fadeIn=" + fadeIn
|
||||
+ "fadeIn=" + fadeIn
|
||||
+ ", stay=" + stay
|
||||
+ ", fadeOut=" + fadeOut
|
||||
+ '}';
|
||||
@@ -82,4 +64,20 @@ public class TitleTimesPacket extends GenericTitlePacket {
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public static class Codec implements PacketCodec<TitleTimesPacket> {
|
||||
@Override
|
||||
public TitleTimesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException(); // encode only
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(TitleTimesPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
buf.writeInt(packet.fadeIn);
|
||||
buf.writeInt(packet.stay);
|
||||
buf.writeInt(packet.fadeOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2021 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.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 + "]";
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,10 @@ public class PingSessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public void activated() {
|
||||
HandshakePacket handshake = new HandshakePacket();
|
||||
handshake.setIntent(HandshakeIntent.STATUS);
|
||||
handshake.setServerAddress(this.virtualHostString == null || this.virtualHostString.isEmpty()
|
||||
? server.getServerInfo().getAddress().getHostString() : this.virtualHostString);
|
||||
handshake.setPort(server.getServerInfo().getAddress().getPort());
|
||||
handshake.setProtocolVersion(version);
|
||||
String serverAddress = this.virtualHostString == null || this.virtualHostString.isEmpty()
|
||||
? server.getServerInfo().getAddress().getHostString() : this.virtualHostString;
|
||||
HandshakePacket handshake = new HandshakePacket(version, serverAddress,
|
||||
server.getServerInfo().getAddress().getPort(), HandshakeIntent.STATUS);
|
||||
connection.delayedWrite(handshake);
|
||||
|
||||
connection.setActiveSessionHandler(StateRegistry.STATUS);
|
||||
|
||||
@@ -45,7 +45,7 @@ class PacketRegistryTest {
|
||||
private StateRegistry.PacketRegistry setupRegistry() {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, null, false),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_15, MINECRAFT_1_16, false));
|
||||
@@ -55,29 +55,30 @@ class PacketRegistryTest {
|
||||
@Test
|
||||
void packetRegistryWorks() {
|
||||
StateRegistry.PacketRegistry registry = setupRegistry();
|
||||
MinecraftPacket packet = registry.getProtocolRegistry(MINECRAFT_1_12).createPacket(0);
|
||||
PacketCodec<?> packet = registry.getProtocolRegistry(MINECRAFT_1_12).getCodec(0);
|
||||
assertNotNull(packet, "Packet was not found in registry");
|
||||
assertEquals(HandshakePacket.class, packet.getClass(), "Registry returned wrong class");
|
||||
assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class");
|
||||
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12).getPacketId(packet),
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12).getPacketId(new HandshakePacket()),
|
||||
"Registry did not return the correct packet ID");
|
||||
}
|
||||
|
||||
@Test
|
||||
void packetRegistryLinkingWorks() {
|
||||
StateRegistry.PacketRegistry registry = setupRegistry();
|
||||
MinecraftPacket packet = registry.getProtocolRegistry(MINECRAFT_1_12_1).createPacket(0);
|
||||
PacketCodec<?> packet = registry.getProtocolRegistry(MINECRAFT_1_12_1).getCodec(0);
|
||||
assertNotNull(packet, "Packet was not found in registry");
|
||||
assertEquals(HandshakePacket.class, packet.getClass(), "Registry returned wrong class");
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12_1).getPacketId(packet),
|
||||
assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class");
|
||||
HandshakePacket handshakePacket = new HandshakePacket();
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12_1).getPacketId(handshakePacket),
|
||||
"Registry did not return the correct packet ID");
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_14_2).getPacketId(packet),
|
||||
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_14_2).getPacketId(handshakePacket),
|
||||
"Registry did not return the correct packet ID");
|
||||
assertEquals(1, registry.getProtocolRegistry(MINECRAFT_1_11).getPacketId(packet),
|
||||
assertEquals(1, registry.getProtocolRegistry(MINECRAFT_1_11).getPacketId(handshakePacket),
|
||||
"Registry did not return the correct packet ID");
|
||||
assertNull(registry.getProtocolRegistry(MINECRAFT_1_14_2).createPacket(0x01),
|
||||
assertNull(registry.getProtocolRegistry(MINECRAFT_1_14_2).getCodec(0x01),
|
||||
"Registry should return a null");
|
||||
assertNull(registry.getProtocolRegistry(MINECRAFT_1_16_2).createPacket(0),
|
||||
assertNull(registry.getProtocolRegistry(MINECRAFT_1_16_2).getCodec(0),
|
||||
"Registry should return null");
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ class PacketRegistryTest {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new));
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec()));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.getProtocolRegistry(ProtocolVersion.UNKNOWN)
|
||||
.getPacketId(new HandshakePacket()));
|
||||
@@ -97,18 +98,18 @@ class PacketRegistryTest {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false)));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false)));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, MINECRAFT_1_8, false)));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, MINECRAFT_1_14, false),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_16, null, false)));
|
||||
}
|
||||
@@ -117,13 +118,13 @@ class PacketRegistryTest {
|
||||
void failOnDuplicate() {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12, null, false)));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> registry.register(StatusPingPacket.class, StatusPingPacket::new,
|
||||
() -> registry.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_13, null, false)));
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ class PacketRegistryTest {
|
||||
void shouldNotFailWhenRegisterLatestProtocolVersion() {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
assertDoesNotThrow(() -> registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
assertDoesNotThrow(() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false),
|
||||
new StateRegistry.PacketMapping(0x01, getLast(ProtocolVersion.SUPPORTED_VERSIONS),
|
||||
null, false)));
|
||||
@@ -141,19 +142,19 @@ class PacketRegistryTest {
|
||||
void registrySuppliesCorrectPacketsByProtocol() {
|
||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||
registry.register(HandshakePacket.class, HandshakePacket::new,
|
||||
registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false),
|
||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, null, false),
|
||||
new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, null, false));
|
||||
assertEquals(HandshakePacket.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12).createPacket(0x00).getClass());
|
||||
assertEquals(HandshakePacket.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12_1).createPacket(0x01).getClass());
|
||||
assertEquals(HandshakePacket.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12_2).createPacket(0x01).getClass());
|
||||
assertEquals(HandshakePacket.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_13).createPacket(0x02).getClass());
|
||||
assertEquals(HandshakePacket.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_14_2).createPacket(0x02).getClass());
|
||||
assertEquals(HandshakePacket.Codec.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12).getCodec(0x00).getClass());
|
||||
assertEquals(HandshakePacket.Codec.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12_1).getCodec(0x01).getClass());
|
||||
assertEquals(HandshakePacket.Codec.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_12_2).getCodec(0x01).getClass());
|
||||
assertEquals(HandshakePacket.Codec.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_13).getCodec(0x02).getClass());
|
||||
assertEquals(HandshakePacket.Codec.class,
|
||||
registry.getProtocolRegistry(MINECRAFT_1_14_2).getCodec(0x02).getClass());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user