mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-19 07:27:42 +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) {
|
public boolean viewerRemove(final ConnectedPlayer viewer) {
|
||||||
if (this.viewers.remove(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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.JoinConfiguration;
|
||||||
import net.kyori.adventure.text.TextComponent;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import net.kyori.adventure.text.TranslatableComponent;
|
import net.kyori.adventure.text.TranslatableComponent;
|
||||||
import net.kyori.adventure.text.event.ClickEvent;
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
@@ -70,6 +71,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
*/
|
*/
|
||||||
public final class VelocityCommand {
|
public final class VelocityCommand {
|
||||||
private static final String USAGE = "/velocity <%s>";
|
private static final String USAGE = "/velocity <%s>";
|
||||||
|
private static final JoinConfiguration COMMA_JOINER = JoinConfiguration.commas(true);
|
||||||
|
|
||||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||||
public static BrigadierCommand create(final VelocityServer server) {
|
public static BrigadierCommand create(final VelocityServer server) {
|
||||||
@@ -208,19 +210,14 @@ public final class VelocityCommand {
|
|||||||
return Command.SINGLE_SUCCESS;
|
return Command.SINGLE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
final TextComponent.Builder listBuilder = Component.text();
|
final Component pluginListComponents = plugins.stream()
|
||||||
for (int i = 0; i < pluginCount; i++) {
|
.map(container -> componentForPlugin(container.getDescription()))
|
||||||
final PluginContainer plugin = plugins.get(i);
|
.collect(Component.toComponent(Component.text(", ")));
|
||||||
listBuilder.append(componentForPlugin(plugin.getDescription()));
|
|
||||||
if (i + 1 < pluginCount) {
|
|
||||||
listBuilder.append(Component.text(", "));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final TranslatableComponent output = Component.translatable()
|
final TranslatableComponent output = Component.translatable()
|
||||||
.key("velocity.command.plugins-list")
|
.key("velocity.command.plugins-list")
|
||||||
.color(NamedTextColor.YELLOW)
|
.color(NamedTextColor.YELLOW)
|
||||||
.arguments(listBuilder.build())
|
.arguments(pluginListComponents)
|
||||||
.build();
|
.build();
|
||||||
source.sendMessage(output);
|
source.sendMessage(output);
|
||||||
return Command.SINGLE_SUCCESS;
|
return Command.SINGLE_SUCCESS;
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(ClientboundStoreCookiePacket packet) {
|
public boolean handle(ClientboundStoreCookiePacket packet) {
|
||||||
server.getEventManager()
|
server.getEventManager()
|
||||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.getKey(), packet.getPayload()))
|
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.key(), packet.payload()))
|
||||||
.thenAcceptAsync(event -> {
|
.thenAcceptAsync(event -> {
|
||||||
if (event.getResult().isAllowed()) {
|
if (event.getResult().isAllowed()) {
|
||||||
final Key resultedKey = event.getResult().getKey() == null
|
final Key resultedKey = event.getResult().getKey() == null
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(ClientboundStoreCookiePacket packet) {
|
public boolean handle(ClientboundStoreCookiePacket packet) {
|
||||||
server.getEventManager()
|
server.getEventManager()
|
||||||
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.getKey(), packet.getPayload()))
|
.fire(new CookieStoreEvent(serverConn.getPlayer(), packet.key(), packet.payload()))
|
||||||
.thenAcceptAsync(event -> {
|
.thenAcceptAsync(event -> {
|
||||||
if (event.getResult().isAllowed()) {
|
if (event.getResult().isAllowed()) {
|
||||||
final Key resultedKey = event.getResult().getKey() == null
|
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)) {
|
if (smc.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||||
smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture));
|
smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture));
|
||||||
} else {
|
} else {
|
||||||
smc.write(new LoginAcknowledgedPacket());
|
smc.write(LoginAcknowledgedPacket.INSTANCE);
|
||||||
smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture));
|
smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture));
|
||||||
ConnectedPlayer player = serverConn.getPlayer();
|
ConnectedPlayer player = serverConn.getPlayer();
|
||||||
if (player.getClientSettingsPacket() != null) {
|
if (player.getClientSettingsPacket() != null) {
|
||||||
|
|||||||
@@ -170,26 +170,26 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
|
|||||||
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
||||||
.getHostString();
|
.getHostString();
|
||||||
|
|
||||||
HandshakePacket handshake = new HandshakePacket();
|
String serverAddress;
|
||||||
handshake.setIntent(HandshakeIntent.LOGIN);
|
|
||||||
handshake.setProtocolVersion(protocolVersion);
|
|
||||||
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
|
if (forwardingMode == PlayerInfoForwarding.LEGACY) {
|
||||||
handshake.setServerAddress(createLegacyForwardingAddress());
|
serverAddress = createLegacyForwardingAddress();
|
||||||
} else if (forwardingMode == PlayerInfoForwarding.BUNGEEGUARD) {
|
} else if (forwardingMode == PlayerInfoForwarding.BUNGEEGUARD) {
|
||||||
byte[] secret = server.getConfiguration().getForwardingSecret();
|
byte[] secret = server.getConfiguration().getForwardingSecret();
|
||||||
handshake.setServerAddress(createBungeeGuardForwardingAddress(secret));
|
serverAddress = createBungeeGuardForwardingAddress(secret);
|
||||||
} else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) {
|
} 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) {
|
} else if (proxyPlayer.getConnection().getType() instanceof ModernForgeConnectionType) {
|
||||||
handshake.setServerAddress(playerVhost + ((ModernForgeConnectionType) proxyPlayer
|
serverAddress = playerVhost + ((ModernForgeConnectionType) proxyPlayer
|
||||||
.getConnection().getType()).getModernToken());
|
.getConnection().getType()).getModernToken();
|
||||||
} else {
|
} else {
|
||||||
handshake.setServerAddress(playerVhost);
|
serverAddress = playerVhost;
|
||||||
}
|
}
|
||||||
|
|
||||||
handshake.setPort(proxyPlayer.getVirtualHost()
|
int port = proxyPlayer.getVirtualHost()
|
||||||
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
.orElseGet(() -> registeredServer.getServerInfo().getAddress())
|
||||||
.getPort());
|
.getPort();
|
||||||
|
|
||||||
|
HandshakePacket handshake = new HandshakePacket(protocolVersion, serverAddress, port, HandshakeIntent.LOGIN);
|
||||||
mc.delayedWrite(handshake);
|
mc.delayedWrite(handshake);
|
||||||
|
|
||||||
mc.setProtocolVersion(protocolVersion);
|
mc.setProtocolVersion(protocolVersion);
|
||||||
|
|||||||
@@ -230,10 +230,9 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerLoginSuccessPacket success = new ServerLoginSuccessPacket();
|
ServerLoginSuccessPacket success = new ServerLoginSuccessPacket(
|
||||||
success.setUsername(player.getUsername());
|
player.getUniqueId(), player.getUsername(), player.getGameProfileProperties()
|
||||||
success.setProperties(player.getGameProfileProperties());
|
);
|
||||||
success.setUuid(player.getUniqueId());
|
|
||||||
mcConnection.write(success);
|
mcConnection.write(success);
|
||||||
|
|
||||||
loginState = State.SUCCESS_SENT;
|
loginState = State.SUCCESS_SENT;
|
||||||
|
|||||||
@@ -387,8 +387,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
public boolean handle(ResourcePackResponsePacket packet) {
|
public boolean handle(ResourcePackResponsePacket packet) {
|
||||||
return player.resourcePackHandler().onResourcePackResponse(
|
return player.resourcePackHandler().onResourcePackResponse(
|
||||||
new ResourcePackResponseBundle(packet.getId(),
|
new ResourcePackResponseBundle(packet.getId(),
|
||||||
packet.getHash(),
|
packet.hash(),
|
||||||
packet.getStatus()));
|
packet.status()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -428,7 +428,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean handle(ServerboundCookieResponsePacket packet) {
|
public boolean handle(ServerboundCookieResponsePacket packet) {
|
||||||
server.getEventManager()
|
server.getEventManager()
|
||||||
.fire(new CookieReceiveEvent(player, packet.getKey(), packet.getPayload()))
|
.fire(new CookieReceiveEvent(player, packet.key(), packet.payload()))
|
||||||
.thenAcceptAsync(event -> {
|
.thenAcceptAsync(event -> {
|
||||||
if (event.getResult().isAllowed()) {
|
if (event.getResult().isAllowed()) {
|
||||||
final VelocityServerConnection serverConnection = player.getConnectedServer();
|
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),
|
// Remove previous boss bars. These don't get cleared when sending JoinGame (up until 1.20.2),
|
||||||
// thus the need to track them.
|
// thus the need to track them.
|
||||||
for (UUID serverBossBar : serverBossBars) {
|
for (UUID serverBossBar : serverBossBars) {
|
||||||
BossBarPacket deletePacket = new BossBarPacket();
|
player.getConnection().delayedWrite(BossBarPacket.createRemovePacket(serverBossBar));
|
||||||
deletePacket.setUuid(serverBossBar);
|
|
||||||
deletePacket.setAction(BossBarPacket.REMOVE);
|
|
||||||
player.getConnection().delayedWrite(deletePacket);
|
|
||||||
}
|
}
|
||||||
serverBossBars.clear();
|
serverBossBars.clear();
|
||||||
}
|
}
|
||||||
@@ -615,7 +612,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
// Clear any title from the previous server.
|
// Clear any title from the previous server.
|
||||||
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
player.getConnection().delayedWrite(
|
player.getConnection().delayedWrite(
|
||||||
GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET,
|
GenericTitlePacket.createClearTitlePacket(GenericTitlePacket.ActionType.RESET,
|
||||||
player.getProtocolVersion()));
|
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
|
// 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
|
// to perform entity ID rewrites, eliminating potential issues from rewriting packets and
|
||||||
// improving compatibility with mods.
|
// improving compatibility with mods.
|
||||||
final RespawnPacket respawn = RespawnPacket.fromJoinGame(joinGame);
|
int dim = joinGame.getDimension();
|
||||||
|
|
||||||
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_16)) {
|
||||||
// Before Minecraft 1.16, we could not switch to the same dimension without sending an
|
// 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
|
// additional respawn. On older versions of Minecraft this forces the client to perform
|
||||||
// garbage collection which adds additional latency.
|
// 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(joinGame);
|
||||||
player.getConnection().delayedWrite(respawn);
|
player.getConnection().delayedWrite(respawn);
|
||||||
}
|
}
|
||||||
@@ -655,8 +653,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
player.getConnection().delayedWrite(joinGame);
|
player.getConnection().delayedWrite(joinGame);
|
||||||
|
|
||||||
// Send a respawn packet in a different dimension.
|
// Send a respawn packet in a different dimension.
|
||||||
final RespawnPacket fakeSwitchPacket = RespawnPacket.fromJoinGame(joinGame);
|
final RespawnPacket fakeSwitchPacket = RespawnPacket.fromJoinGame(joinGame, joinGame.getDimension() == 0 ? -1 : 0);
|
||||||
fakeSwitchPacket.setDimension(joinGame.getDimension() == 0 ? -1 : 0);
|
|
||||||
player.getConnection().delayedWrite(fakeSwitchPacket);
|
player.getConnection().delayedWrite(fakeSwitchPacket);
|
||||||
|
|
||||||
// Now send a respawn packet in the correct dimension.
|
// Now send a respawn packet in the correct dimension.
|
||||||
@@ -728,11 +725,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
offers.add(new Offer(offer, tooltip));
|
offers.add(new Offer(offer, tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
|
TabCompleteResponsePacket resp = new TabCompleteResponsePacket(
|
||||||
resp.setTransactionId(packet.getTransactionId());
|
packet.transactionId(), startPos + 1, packet.getCommand().length() - startPos - 1, offers
|
||||||
resp.setStart(startPos + 1);
|
);
|
||||||
resp.setLength(packet.getCommand().length() - startPos - 1);
|
|
||||||
resp.getOffers().addAll(offers);
|
|
||||||
player.getConnection().write(resp);
|
player.getConnection().write(resp);
|
||||||
}
|
}
|
||||||
}, player.getConnection().eventLoop()).exceptionally((ex) -> {
|
}, player.getConnection().eventLoop()).exceptionally((ex) -> {
|
||||||
@@ -778,6 +773,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
.thenAcceptAsync(offers -> {
|
.thenAcceptAsync(offers -> {
|
||||||
boolean legacy =
|
boolean legacy =
|
||||||
player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13);
|
player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13);
|
||||||
|
List<Offer> extendedOffers = new ArrayList<>(response.offers());
|
||||||
try {
|
try {
|
||||||
for (Suggestion suggestion : offers.getList()) {
|
for (Suggestion suggestion : offers.getList()) {
|
||||||
String offer = suggestion.getText();
|
String offer = suggestion.getText();
|
||||||
@@ -791,10 +787,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
} else if (suggestion.getTooltip() != null) {
|
} else if (suggestion.getTooltip() != null) {
|
||||||
tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
|
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);
|
extendedOffers.sort(null);
|
||||||
player.getConnection().write(response);
|
player.getConnection().write(response.withOffers(extendedOffers));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
logger.error("Unable to provide tab list completions for {} for command '{}'",
|
||||||
player.getUsername(), command,
|
player.getUsername(), command,
|
||||||
@@ -811,17 +807,17 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
private void finishRegularTabComplete(TabCompleteRequestPacket request,
|
private void finishRegularTabComplete(TabCompleteRequestPacket request,
|
||||||
TabCompleteResponsePacket response) {
|
TabCompleteResponsePacket response) {
|
||||||
List<String> offers = new ArrayList<>();
|
List<String> textOffers = new ArrayList<>();
|
||||||
for (Offer offer : response.getOffers()) {
|
for (Offer offer : response.offers()) {
|
||||||
offers.add(offer.getText());
|
textOffers.add(offer.getText());
|
||||||
}
|
}
|
||||||
server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers))
|
server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), textOffers))
|
||||||
.thenAcceptAsync(e -> {
|
.thenAcceptAsync(e -> {
|
||||||
response.getOffers().clear();
|
List<Offer> newOffers = new ArrayList<>();
|
||||||
for (String s : e.getSuggestions()) {
|
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) -> {
|
}, player.getConnection().eventLoop()).exceptionally((ex) -> {
|
||||||
logger.error(
|
logger.error(
|
||||||
"Exception while finishing regular tab completion,"
|
"Exception while finishing regular tab completion,"
|
||||||
|
|||||||
@@ -38,25 +38,25 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
|||||||
|
|
||||||
ClientSettingsWrapper(ClientSettingsPacket settings) {
|
ClientSettingsWrapper(ClientSettingsPacket settings) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.parts = new SkinParts((byte) settings.getSkinParts());
|
this.parts = new SkinParts((byte) settings.skinParts());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
locale = Locale.forLanguageTag(settings.getLocale().replaceAll("_", "-"));
|
locale = Locale.forLanguageTag(settings.locale().replaceAll("_", "-"));
|
||||||
}
|
}
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getViewDistance() {
|
public byte getViewDistance() {
|
||||||
return settings.getViewDistance();
|
return settings.viewDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChatMode getChatMode() {
|
public ChatMode getChatMode() {
|
||||||
return switch (settings.getChatVisibility()) {
|
return switch (settings.chatVisibility()) {
|
||||||
case 1 -> ChatMode.COMMANDS_ONLY;
|
case 1 -> ChatMode.COMMANDS_ONLY;
|
||||||
case 2 -> ChatMode.HIDDEN;
|
case 2 -> ChatMode.HIDDEN;
|
||||||
default -> ChatMode.SHOWN;
|
default -> ChatMode.SHOWN;
|
||||||
@@ -65,7 +65,7 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasChatColors() {
|
public boolean hasChatColors() {
|
||||||
return settings.isChatColors();
|
return settings.chatColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,22 +75,22 @@ public class ClientSettingsWrapper implements PlayerSettings {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MainHand getMainHand() {
|
public MainHand getMainHand() {
|
||||||
return settings.getMainHand() == 1 ? MainHand.RIGHT : MainHand.LEFT;
|
return settings.mainHand() == 1 ? MainHand.RIGHT : MainHand.LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isClientListingAllowed() {
|
public boolean isClientListingAllowed() {
|
||||||
return settings.isClientListingAllowed();
|
return settings.clientListingAllowed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTextFilteringEnabled() {
|
public boolean isTextFilteringEnabled() {
|
||||||
return settings.isTextFilteringEnabled();
|
return settings.textFilteringEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParticleStatus getParticleStatus() {
|
public ParticleStatus getParticleStatus() {
|
||||||
return switch (settings.getParticleStatus()) {
|
return switch (settings.particleStatus()) {
|
||||||
case 1 -> ParticleStatus.DECREASED;
|
case 1 -> ParticleStatus.DECREASED;
|
||||||
case 2 -> ParticleStatus.MINIMAL;
|
case 2 -> ParticleStatus.MINIMAL;
|
||||||
default -> ParticleStatus.ALL;
|
default -> ParticleStatus.ALL;
|
||||||
|
|||||||
@@ -451,9 +451,9 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
ProtocolVersion playerVersion = getProtocolVersion();
|
ProtocolVersion playerVersion = getProtocolVersion();
|
||||||
if (playerVersion.noLessThan(ProtocolVersion.MINECRAFT_1_11)) {
|
if (playerVersion.noLessThan(ProtocolVersion.MINECRAFT_1_11)) {
|
||||||
// Use the title packet instead.
|
// Use the title packet instead.
|
||||||
GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket pkt = GenericTitlePacket.createComponentTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion);
|
GenericTitlePacket.ActionType.SET_ACTION_BAR,
|
||||||
pkt.setComponent(new ComponentHolder(playerVersion, translated));
|
new ComponentHolder(playerVersion, translated), playerVersion);
|
||||||
connection.write(pkt);
|
connection.write(pkt);
|
||||||
} else {
|
} else {
|
||||||
// Due to issues with action bar packets, we'll need to convert the text message into a
|
// 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();
|
JsonObject object = new JsonObject();
|
||||||
object.addProperty("text", LegacyComponentSerializer.legacySection()
|
object.addProperty("text", LegacyComponentSerializer.legacySection()
|
||||||
.serialize(translated));
|
.serialize(translated));
|
||||||
LegacyChatPacket legacyChat = new LegacyChatPacket();
|
LegacyChatPacket legacyChat = new LegacyChatPacket(object.toString(), LegacyChatPacket.GAME_INFO_TYPE, null);
|
||||||
legacyChat.setMessage(object.toString());
|
|
||||||
legacyChat.setType(LegacyChatPacket.GAME_INFO_TYPE);
|
|
||||||
connection.write(legacyChat);
|
connection.write(legacyChat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -504,26 +502,26 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
@Override
|
@Override
|
||||||
public void showTitle(net.kyori.adventure.title.@NonNull Title title) {
|
public void showTitle(net.kyori.adventure.title.@NonNull Title title) {
|
||||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
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();
|
net.kyori.adventure.title.Title.Times times = title.times();
|
||||||
if (times != null) {
|
if (times != null) {
|
||||||
timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn()));
|
GenericTitlePacket timesPkt = GenericTitlePacket.createTimesTitlePacket(
|
||||||
timesPkt.setStay((int) DurationUtils.toTicks(times.stay()));
|
(int) DurationUtils.toTicks(times.fadeIn()),
|
||||||
timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut()));
|
(int) DurationUtils.toTicks(times.stay()),
|
||||||
|
(int) DurationUtils.toTicks(times.fadeOut()),
|
||||||
|
this.getProtocolVersion());
|
||||||
|
connection.delayedWrite(timesPkt);
|
||||||
}
|
}
|
||||||
connection.delayedWrite(timesPkt);
|
|
||||||
|
|
||||||
GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket subtitlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion());
|
GenericTitlePacket.ActionType.SET_SUBTITLE,
|
||||||
subtitlePkt.setComponent(new ComponentHolder(
|
new ComponentHolder(this.getProtocolVersion(), translateMessage(title.subtitle())),
|
||||||
this.getProtocolVersion(), translateMessage(title.subtitle())));
|
this.getProtocolVersion());
|
||||||
connection.delayedWrite(subtitlePkt);
|
connection.delayedWrite(subtitlePkt);
|
||||||
|
|
||||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion());
|
GenericTitlePacket.ActionType.SET_TITLE,
|
||||||
titlePkt.setComponent(new ComponentHolder(
|
new ComponentHolder(this.getProtocolVersion(), translateMessage(title.title())),
|
||||||
this.getProtocolVersion(), translateMessage(title.title())));
|
this.getProtocolVersion());
|
||||||
connection.delayedWrite(titlePkt);
|
connection.delayedWrite(titlePkt);
|
||||||
|
|
||||||
connection.flush();
|
connection.flush();
|
||||||
@@ -545,24 +543,24 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (part == TitlePart.TITLE) {
|
if (part == TitlePart.TITLE) {
|
||||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion());
|
GenericTitlePacket.ActionType.SET_TITLE,
|
||||||
titlePkt.setComponent(new ComponentHolder(
|
new ComponentHolder(this.getProtocolVersion(), translateMessage((Component) value)),
|
||||||
this.getProtocolVersion(), translateMessage((Component) value)));
|
this.getProtocolVersion());
|
||||||
connection.write(titlePkt);
|
connection.write(titlePkt);
|
||||||
} else if (part == TitlePart.SUBTITLE) {
|
} else if (part == TitlePart.SUBTITLE) {
|
||||||
GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket titlePkt = GenericTitlePacket.createComponentTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion());
|
GenericTitlePacket.ActionType.SET_SUBTITLE,
|
||||||
titlePkt.setComponent(new ComponentHolder(
|
new ComponentHolder(this.getProtocolVersion(), translateMessage((Component) value)),
|
||||||
this.getProtocolVersion(), translateMessage((Component) value)));
|
this.getProtocolVersion());
|
||||||
connection.write(titlePkt);
|
connection.write(titlePkt);
|
||||||
} else if (part == TitlePart.TIMES) {
|
} else if (part == TitlePart.TIMES) {
|
||||||
Times times = (Times) value;
|
Times times = (Times) value;
|
||||||
GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket(
|
GenericTitlePacket timesPkt = GenericTitlePacket.createTimesTitlePacket(
|
||||||
GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion());
|
(int) DurationUtils.toTicks(times.fadeIn()),
|
||||||
timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn()));
|
(int) DurationUtils.toTicks(times.stay()),
|
||||||
timesPkt.setStay((int) DurationUtils.toTicks(times.stay()));
|
(int) DurationUtils.toTicks(times.fadeOut()),
|
||||||
timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut()));
|
this.getProtocolVersion());
|
||||||
connection.write(timesPkt);
|
connection.write(timesPkt);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Title part " + part + " is not valid");
|
throw new IllegalArgumentException("Title part " + part + " is not valid");
|
||||||
@@ -572,7 +570,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
@Override
|
@Override
|
||||||
public void clearTitle() {
|
public void clearTitle() {
|
||||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
connection.write(GenericTitlePacket.constructTitlePacket(
|
connection.write(GenericTitlePacket.createClearTitlePacket(
|
||||||
GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion()));
|
GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,7 +578,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
@Override
|
@Override
|
||||||
public void resetTitle() {
|
public void resetTitle() {
|
||||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
connection.write(GenericTitlePacket.constructTitlePacket(
|
connection.write(GenericTitlePacket.createClearTitlePacket(
|
||||||
GenericTitlePacket.ActionType.RESET, this.getProtocolVersion()));
|
GenericTitlePacket.ActionType.RESET, this.getProtocolVersion()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1262,7 +1260,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
@Override
|
@Override
|
||||||
public void clearResourcePacks() {
|
public void clearResourcePacks() {
|
||||||
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
if (this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) {
|
||||||
connection.write(new RemoveResourcePackPacket());
|
connection.write(new RemoveResourcePackPacket(null));
|
||||||
this.resourcePackHandler.clearAppliedResourcePacks();
|
this.resourcePackHandler.clearAppliedResourcePacks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1333,8 +1331,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
|||||||
public void sendKeepAlive() {
|
public void sendKeepAlive() {
|
||||||
if (connection.getState() == StateRegistry.PLAY
|
if (connection.getState() == StateRegistry.PLAY
|
||||||
|| connection.getState() == StateRegistry.CONFIG) {
|
|| connection.getState() == StateRegistry.CONFIG) {
|
||||||
KeepAlivePacket keepAlive = new KeepAlivePacket();
|
KeepAlivePacket keepAlive = new KeepAlivePacket(ThreadLocalRandom.current().nextLong());
|
||||||
keepAlive.setRandomId(ThreadLocalRandom.current().nextLong());
|
|
||||||
connection.write(keepAlive);
|
connection.write(keepAlive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,19 +87,19 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(final HandshakePacket handshake) {
|
public boolean handle(final HandshakePacket handshake) {
|
||||||
final StateRegistry nextState = getStateForProtocol(handshake.getNextStatus());
|
final StateRegistry nextState = getStateForProtocol(handshake.nextStatus());
|
||||||
if (nextState == null) {
|
if (nextState == null) {
|
||||||
LOGGER.error("{} provided invalid protocol {}", this, handshake.getNextStatus());
|
LOGGER.error("{} provided invalid protocol {}", this, handshake.nextStatus());
|
||||||
connection.close(true);
|
connection.close(true);
|
||||||
} else {
|
} else {
|
||||||
final InitialInboundConnection ic = new InitialInboundConnection(connection,
|
final InitialInboundConnection ic = new InitialInboundConnection(connection,
|
||||||
cleanVhost(handshake.getServerAddress()), handshake);
|
cleanVhost(handshake.serverAddress()), handshake);
|
||||||
if (handshake.getIntent() == HandshakeIntent.TRANSFER
|
if (handshake.intent() == HandshakeIntent.TRANSFER
|
||||||
&& !server.getConfiguration().isAcceptTransfers()) {
|
&& !server.getConfiguration().isAcceptTransfers()) {
|
||||||
ic.disconnect(Component.translatable("multiplayer.disconnect.transfers_disabled"));
|
ic.disconnect(Component.translatable("multiplayer.disconnect.transfers_disabled"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
connection.setProtocolVersion(handshake.getProtocolVersion());
|
connection.setProtocolVersion(handshake.protocolVersion());
|
||||||
connection.setAssociation(ic);
|
connection.setAssociation(ic);
|
||||||
|
|
||||||
switch (nextState) {
|
switch (nextState) {
|
||||||
@@ -124,7 +124,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleLogin(HandshakePacket handshake, InitialInboundConnection ic) {
|
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.
|
// Bump connection into correct protocol state so that we can send the disconnect packet.
|
||||||
connection.setState(StateRegistry.LOGIN);
|
connection.setState(StateRegistry.LOGIN);
|
||||||
ic.disconnectQuietly(Component.translatable()
|
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
|
// 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.
|
// and lower, otherwise IP information will never get forwarded.
|
||||||
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN
|
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.
|
// Bump connection into correct protocol state so that we can send the disconnect packet.
|
||||||
connection.setState(StateRegistry.LOGIN);
|
connection.setState(StateRegistry.LOGIN);
|
||||||
ic.disconnectQuietly(
|
ic.disconnectQuietly(
|
||||||
@@ -157,21 +157,23 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
|
|||||||
|
|
||||||
final LoginInboundConnection lic = new LoginInboundConnection(ic);
|
final LoginInboundConnection lic = new LoginInboundConnection(ic);
|
||||||
server.getEventManager().fireAndForget(
|
server.getEventManager().fireAndForget(
|
||||||
new ConnectionHandshakeEvent(lic, handshake.getIntent()));
|
new ConnectionHandshakeEvent(lic, handshake.intent()));
|
||||||
connection.setActiveSessionHandler(StateRegistry.LOGIN,
|
connection.setActiveSessionHandler(StateRegistry.LOGIN,
|
||||||
new InitialLoginSessionHandler(server, connection, lic));
|
new InitialLoginSessionHandler(server, connection, lic));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionType getHandshakeConnectionType(HandshakePacket handshake) {
|
private ConnectionType getHandshakeConnectionType(HandshakePacket handshake) {
|
||||||
if (handshake.getServerAddress().contains(ModernForgeConstants.MODERN_FORGE_TOKEN)
|
final String serverAddress = handshake.serverAddress();
|
||||||
&& handshake.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
final ProtocolVersion protocolVersion = handshake.protocolVersion();
|
||||||
return new ModernForgeConnectionType(handshake.getServerAddress());
|
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).
|
// 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)
|
if (serverAddress.endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN)
|
||||||
&& handshake.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
&& protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||||
return ConnectionTypes.LEGACY_FORGE;
|
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
|
// 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.
|
// forge handshake attempts. Also sends a reset handshake packet on every transition.
|
||||||
return ConnectionTypes.UNDETERMINED_17;
|
return ConnectionTypes.UNDETERMINED_17;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
public boolean handle(ServerLoginPacket packet) {
|
public boolean handle(ServerLoginPacket packet) {
|
||||||
assertState(LoginState.LOGIN_PACKET_EXPECTED);
|
assertState(LoginState.LOGIN_PACKET_EXPECTED);
|
||||||
this.currentState = LoginState.LOGIN_PACKET_RECEIVED;
|
this.currentState = LoginState.LOGIN_PACKET_RECEIVED;
|
||||||
IdentifiedKey playerKey = packet.getPlayerKey();
|
IdentifiedKey playerKey = packet.playerKey();
|
||||||
if (playerKey != null) {
|
if (playerKey != null) {
|
||||||
if (playerKey.hasExpired()) {
|
if (playerKey.hasExpired()) {
|
||||||
inbound.disconnect(
|
inbound.disconnect(
|
||||||
@@ -102,7 +102,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
boolean isKeyValid;
|
boolean isKeyValid;
|
||||||
if (playerKey.getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
|
if (playerKey.getKeyRevision() == IdentifiedKey.Revision.LINKED_V2
|
||||||
&& playerKey instanceof final IdentifiedKeyImpl keyImpl) {
|
&& playerKey instanceof final IdentifiedKeyImpl keyImpl) {
|
||||||
isKeyValid = keyImpl.internalAddHolder(packet.getHolderUuid());
|
isKeyValid = keyImpl.internalAddHolder(packet.holderUuid());
|
||||||
} else {
|
} else {
|
||||||
isKeyValid = playerKey.isSignatureValid();
|
isKeyValid = playerKey.isSignatureValid();
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
inbound.setPlayerKey(playerKey);
|
inbound.setPlayerKey(playerKey);
|
||||||
this.login = packet;
|
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(() -> {
|
server.getEventManager().fire(event).thenRunAsync(() -> {
|
||||||
if (mcConnection.isClosed()) {
|
if (mcConnection.isClosed()) {
|
||||||
// The player was disconnected
|
// The player was disconnected
|
||||||
@@ -289,9 +289,8 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler {
|
|||||||
byte[] verify = new byte[4];
|
byte[] verify = new byte[4];
|
||||||
ThreadLocalRandom.current().nextBytes(verify);
|
ThreadLocalRandom.current().nextBytes(verify);
|
||||||
|
|
||||||
EncryptionRequestPacket request = new EncryptionRequestPacket();
|
EncryptionRequestPacket request = new EncryptionRequestPacket("",
|
||||||
request.setPublicKey(server.getServerKeyPair().getPublic().getEncoded());
|
server.getServerKeyPair().getPublic().getEncoded(), verify, true);
|
||||||
request.setVerifyToken(verify);
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,9 +84,9 @@ class LegacyForgeUtil {
|
|||||||
* @return A copy of the reset packet
|
* @return A copy of the reset packet
|
||||||
*/
|
*/
|
||||||
static PluginMessagePacket resetPacket() {
|
static PluginMessagePacket resetPacket() {
|
||||||
PluginMessagePacket msg = new PluginMessagePacket();
|
return new PluginMessagePacket(
|
||||||
msg.setChannel(FORGE_LEGACY_HANDSHAKE_CHANNEL);
|
FORGE_LEGACY_HANDSHAKE_CHANNEL,
|
||||||
msg.replace(Unpooled.wrappedBuffer(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone()));
|
Unpooled.wrappedBuffer(FORGE_LEGACY_HANDSHAKE_RESET_DATA.clone())
|
||||||
return msg;
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,17 +101,15 @@ public abstract sealed class ResourcePackHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void sendResourcePackRequestPacket(final @NotNull ResourcePackInfo queued) {
|
protected void sendResourcePackRequestPacket(final @NotNull ResourcePackInfo queued) {
|
||||||
final ResourcePackRequestPacket request = new ResourcePackRequestPacket();
|
final String hash = queued.getHash() != null ? ByteBufUtil.hexDump(queued.getHash()) : "";
|
||||||
request.setId(queued.getId());
|
final ComponentHolder prompt = queued.getPrompt() == null ? null :
|
||||||
request.setUrl(queued.getUrl());
|
new ComponentHolder(player.getProtocolVersion(), player.translateMessage(queued.getPrompt()));
|
||||||
if (queued.getHash() != null) {
|
final ResourcePackRequestPacket request = new ResourcePackRequestPacket(
|
||||||
request.setHash(ByteBufUtil.hexDump(queued.getHash()));
|
queued.getId(),
|
||||||
} else {
|
queued.getUrl(),
|
||||||
request.setHash("");
|
hash,
|
||||||
}
|
queued.getShouldForce(),
|
||||||
request.setRequired(queued.getShouldForce());
|
prompt);
|
||||||
request.setPrompt(queued.getPrompt() == null ? null :
|
|
||||||
new ComponentHolder(player.getProtocolVersion(), player.translateMessage(queued.getPrompt())));
|
|
||||||
|
|
||||||
player.getConnection().write(request);
|
player.getConnection().write(request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,33 +17,23 @@
|
|||||||
|
|
||||||
package com.velocitypowered.proxy.protocol;
|
package com.velocitypowered.proxy.protocol;
|
||||||
|
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
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 {
|
public interface MinecraftPacket {
|
||||||
|
|
||||||
void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
|
/**
|
||||||
|
* Handles this packet using the visitor pattern.
|
||||||
void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion);
|
*
|
||||||
|
* @param handler the session handler
|
||||||
|
* @return true if the packet was handled
|
||||||
|
*/
|
||||||
boolean handle(MinecraftSessionHandler handler);
|
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.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Supplier;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,122 +140,122 @@ public enum StateRegistry {
|
|||||||
|
|
||||||
HANDSHAKE {
|
HANDSHAKE {
|
||||||
{
|
{
|
||||||
serverbound.register(HandshakePacket.class, HandshakePacket::new,
|
serverbound.register(HandshakePacket.class, new HandshakePacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false));
|
map(0x00, MINECRAFT_1_7_2, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
STATUS {
|
STATUS {
|
||||||
{
|
{
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
StatusRequestPacket.class, () -> StatusRequestPacket.INSTANCE,
|
StatusRequestPacket.class, new StatusRequestPacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false));
|
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));
|
map(0x01, MINECRAFT_1_7_2, false));
|
||||||
|
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
StatusResponsePacket.class, StatusResponsePacket::new,
|
StatusResponsePacket.class, new StatusResponsePacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false));
|
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));
|
map(0x01, MINECRAFT_1_7_2, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CONFIG {
|
CONFIG {
|
||||||
{
|
{
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ClientSettingsPacket.class, ClientSettingsPacket::new,
|
ClientSettingsPacket.class, new ClientSettingsPacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_20_2, false));
|
map(0x00, MINECRAFT_1_20_2, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_20_5, false));
|
map(0x01, MINECRAFT_1_20_5, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
PluginMessagePacket.class, PluginMessagePacket::new,
|
PluginMessagePacket.class, new PluginMessagePacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_20_2, false),
|
map(0x01, MINECRAFT_1_20_2, false),
|
||||||
map(0x02, MINECRAFT_1_20_5, false));
|
map(0x02, MINECRAFT_1_20_5, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||||
map(0x02, MINECRAFT_1_20_2, false),
|
map(0x02, MINECRAFT_1_20_2, false),
|
||||||
map(0x03, MINECRAFT_1_20_5, 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(0x03, MINECRAFT_1_20_2, false),
|
||||||
map(0x04, MINECRAFT_1_20_5, false));
|
map(0x04, MINECRAFT_1_20_5, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
PingIdentifyPacket.class, PingIdentifyPacket::new,
|
PingIdentifyPacket.class, new PingIdentifyPacket.Codec(),
|
||||||
map(0x04, MINECRAFT_1_20_2, false),
|
map(0x04, MINECRAFT_1_20_2, false),
|
||||||
map(0x05, MINECRAFT_1_20_5, false));
|
map(0x05, MINECRAFT_1_20_5, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ResourcePackResponsePacket.class,
|
ResourcePackResponsePacket.class,
|
||||||
ResourcePackResponsePacket::new,
|
new ResourcePackResponsePacket.Codec(),
|
||||||
map(0x05, MINECRAFT_1_20_2, false),
|
map(0x05, MINECRAFT_1_20_2, false),
|
||||||
map(0x06, MINECRAFT_1_20_5, false));
|
map(0x06, MINECRAFT_1_20_5, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
KnownPacksPacket.class,
|
KnownPacksPacket.class,
|
||||||
KnownPacksPacket::new,
|
new KnownPacksPacket.Codec(),
|
||||||
map(0x07, MINECRAFT_1_20_5, false));
|
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));
|
map(0x08, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
CodeOfConductAcceptPacket.class,
|
CodeOfConductAcceptPacket.class,
|
||||||
() -> CodeOfConductAcceptPacket.INSTANCE,
|
new CodeOfConductAcceptPacket.Codec(),
|
||||||
map(0x09, MINECRAFT_1_21_9, false));
|
map(0x09, MINECRAFT_1_21_9, false));
|
||||||
|
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_20_5, false));
|
map(0x00, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PluginMessagePacket.class, PluginMessagePacket::new,
|
PluginMessagePacket.class, new PluginMessagePacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_20_2, false),
|
map(0x00, MINECRAFT_1_20_2, false),
|
||||||
map(0x01, MINECRAFT_1_20_5, false));
|
map(0x01, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
DisconnectPacket.class, () -> new DisconnectPacket(this),
|
DisconnectPacket.class, new DisconnectPacket.Codec(this),
|
||||||
map(0x01, MINECRAFT_1_20_2, false),
|
map(0x01, MINECRAFT_1_20_2, false),
|
||||||
map(0x02, MINECRAFT_1_20_5, false));
|
map(0x02, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||||
map(0x02, MINECRAFT_1_20_2, false),
|
map(0x02, MINECRAFT_1_20_2, false),
|
||||||
map(0x03, MINECRAFT_1_20_5, 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(0x03, MINECRAFT_1_20_2, false),
|
||||||
map(0x04, MINECRAFT_1_20_5, false));
|
map(0x04, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PingIdentifyPacket.class, PingIdentifyPacket::new,
|
PingIdentifyPacket.class, new PingIdentifyPacket.Codec(),
|
||||||
map(0x04, MINECRAFT_1_20_2, false),
|
map(0x04, MINECRAFT_1_20_2, false),
|
||||||
map(0x05, MINECRAFT_1_20_5, false));
|
map(0x05, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RegistrySyncPacket.class, RegistrySyncPacket::new,
|
RegistrySyncPacket.class, new RegistrySyncPacket.Codec(),
|
||||||
map(0x05, MINECRAFT_1_20_2, false),
|
map(0x05, MINECRAFT_1_20_2, false),
|
||||||
map(0x07, MINECRAFT_1_20_5, false));
|
map(0x07, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RemoveResourcePackPacket.class, RemoveResourcePackPacket::new,
|
RemoveResourcePackPacket.class, new RemoveResourcePackPacket.Codec(),
|
||||||
map(0x06, MINECRAFT_1_20_3, false),
|
map(0x06, MINECRAFT_1_20_3, false),
|
||||||
map(0x08, MINECRAFT_1_20_5, 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(0x06, MINECRAFT_1_20_2, false),
|
||||||
map(0x07, MINECRAFT_1_20_3, false),
|
map(0x07, MINECRAFT_1_20_3, false),
|
||||||
map(0x09, MINECRAFT_1_20_5, false));
|
map(0x09, MINECRAFT_1_20_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
ClientboundStoreCookiePacket.class, new ClientboundStoreCookiePacket.Codec(),
|
||||||
map(0x0A, MINECRAFT_1_20_5, false));
|
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));
|
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(0x07, MINECRAFT_1_20_2, false),
|
||||||
map(0x08, MINECRAFT_1_20_3, false),
|
map(0x08, MINECRAFT_1_20_3, false),
|
||||||
map(0x0C, MINECRAFT_1_20_5, 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(0x08, MINECRAFT_1_20_2, false),
|
||||||
map(0x09, MINECRAFT_1_20_3, false),
|
map(0x09, MINECRAFT_1_20_3, false),
|
||||||
map(0x0D, MINECRAFT_1_20_5, 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));
|
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));
|
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));
|
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));
|
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));
|
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));
|
map(0x13, MINECRAFT_1_21_9, false));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -264,7 +264,7 @@ public enum StateRegistry {
|
|||||||
serverbound.fallback = false;
|
serverbound.fallback = false;
|
||||||
clientbound.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(0x14, MINECRAFT_1_7_2, false),
|
||||||
map(0x01, MINECRAFT_1_9, false),
|
map(0x01, MINECRAFT_1_9, false),
|
||||||
map(0x02, MINECRAFT_1_12, false),
|
map(0x02, MINECRAFT_1_12, false),
|
||||||
@@ -281,7 +281,7 @@ public enum StateRegistry {
|
|||||||
map(0x0E, MINECRAFT_1_21_6, false));
|
map(0x0E, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
LegacyChatPacket.class,
|
LegacyChatPacket.class,
|
||||||
LegacyChatPacket::new,
|
new LegacyChatPacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_7_2, false),
|
map(0x01, MINECRAFT_1_7_2, false),
|
||||||
map(0x02, MINECRAFT_1_9, false),
|
map(0x02, MINECRAFT_1_9, false),
|
||||||
map(0x03, MINECRAFT_1_12, false),
|
map(0x03, MINECRAFT_1_12, false),
|
||||||
@@ -289,35 +289,35 @@ public enum StateRegistry {
|
|||||||
map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false));
|
map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ChatAcknowledgementPacket.class,
|
ChatAcknowledgementPacket.class,
|
||||||
ChatAcknowledgementPacket::new,
|
new ChatAcknowledgementPacket.Codec(),
|
||||||
map(0x03, MINECRAFT_1_19_3, false),
|
map(0x03, MINECRAFT_1_19_3, false),
|
||||||
map(0x04, MINECRAFT_1_21_2, false),
|
map(0x04, MINECRAFT_1_21_2, false),
|
||||||
map(0x05, MINECRAFT_1_21_6, 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(0x03, MINECRAFT_1_19, false),
|
||||||
map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, 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(0x04, MINECRAFT_1_19, false),
|
||||||
map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, 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(0x04, MINECRAFT_1_19_3, false),
|
||||||
map(0x05, MINECRAFT_1_20_5, false),
|
map(0x05, MINECRAFT_1_20_5, false),
|
||||||
map(0x06, MINECRAFT_1_21_2, false),
|
map(0x06, MINECRAFT_1_21_2, false),
|
||||||
map(0x07, MINECRAFT_1_21_6, 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(0x04, MINECRAFT_1_20_5, false),
|
||||||
map(0x05, MINECRAFT_1_21_2, false),
|
map(0x05, MINECRAFT_1_21_2, false),
|
||||||
map(0x06, MINECRAFT_1_21_6, false));
|
map(0x06, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
SessionPlayerChatPacket.class,
|
SessionPlayerChatPacket.class,
|
||||||
SessionPlayerChatPacket::new,
|
new SessionPlayerChatPacket.Codec(),
|
||||||
map(0x05, MINECRAFT_1_19_3, false),
|
map(0x05, MINECRAFT_1_19_3, false),
|
||||||
map(0x06, MINECRAFT_1_20_5, false),
|
map(0x06, MINECRAFT_1_20_5, false),
|
||||||
map(0x07, MINECRAFT_1_21_2, false),
|
map(0x07, MINECRAFT_1_21_2, false),
|
||||||
map(0x08, MINECRAFT_1_21_6, false));
|
map(0x08, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ClientSettingsPacket.class,
|
ClientSettingsPacket.class,
|
||||||
ClientSettingsPacket::new,
|
new ClientSettingsPacket.Codec(),
|
||||||
map(0x15, MINECRAFT_1_7_2, false),
|
map(0x15, MINECRAFT_1_7_2, false),
|
||||||
map(0x04, MINECRAFT_1_9, false),
|
map(0x04, MINECRAFT_1_9, false),
|
||||||
map(0x05, MINECRAFT_1_12, false),
|
map(0x05, MINECRAFT_1_12, false),
|
||||||
@@ -332,13 +332,13 @@ public enum StateRegistry {
|
|||||||
map(0x0C, MINECRAFT_1_21_2, false),
|
map(0x0C, MINECRAFT_1_21_2, false),
|
||||||
map(0x0D, MINECRAFT_1_21_6, false));
|
map(0x0D, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||||
map(0x11, MINECRAFT_1_20_5, false),
|
map(0x11, MINECRAFT_1_20_5, false),
|
||||||
map(0x13, MINECRAFT_1_21_2, false),
|
map(0x13, MINECRAFT_1_21_2, false),
|
||||||
map(0x14, MINECRAFT_1_21_6, false));
|
map(0x14, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
PluginMessagePacket.class,
|
PluginMessagePacket.class,
|
||||||
PluginMessagePacket::new,
|
new PluginMessagePacket.Codec(),
|
||||||
map(0x17, MINECRAFT_1_7_2, false),
|
map(0x17, MINECRAFT_1_7_2, false),
|
||||||
map(0x09, MINECRAFT_1_9, false),
|
map(0x09, MINECRAFT_1_9, false),
|
||||||
map(0x0A, MINECRAFT_1_12, false),
|
map(0x0A, MINECRAFT_1_12, false),
|
||||||
@@ -357,7 +357,7 @@ public enum StateRegistry {
|
|||||||
map(0x15, MINECRAFT_1_21_6, false));
|
map(0x15, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
KeepAlivePacket.class,
|
KeepAlivePacket.class,
|
||||||
KeepAlivePacket::new,
|
new KeepAlivePacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false),
|
map(0x00, MINECRAFT_1_7_2, false),
|
||||||
map(0x0B, MINECRAFT_1_9, false),
|
map(0x0B, MINECRAFT_1_9, false),
|
||||||
map(0x0C, MINECRAFT_1_12, false),
|
map(0x0C, MINECRAFT_1_12, false),
|
||||||
@@ -377,7 +377,7 @@ public enum StateRegistry {
|
|||||||
map(0x1B, MINECRAFT_1_21_6, false));
|
map(0x1B, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ResourcePackResponsePacket.class,
|
ResourcePackResponsePacket.class,
|
||||||
ResourcePackResponsePacket::new,
|
new ResourcePackResponsePacket.Codec(),
|
||||||
map(0x19, MINECRAFT_1_8, false),
|
map(0x19, MINECRAFT_1_8, false),
|
||||||
map(0x16, MINECRAFT_1_9, false),
|
map(0x16, MINECRAFT_1_9, false),
|
||||||
map(0x18, MINECRAFT_1_12, false),
|
map(0x18, MINECRAFT_1_12, false),
|
||||||
@@ -394,7 +394,7 @@ public enum StateRegistry {
|
|||||||
map(0x2F, MINECRAFT_1_21_4, false),
|
map(0x2F, MINECRAFT_1_21_4, false),
|
||||||
map(0x30, MINECRAFT_1_21_6, false));
|
map(0x30, MINECRAFT_1_21_6, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE,
|
FinishedUpdatePacket.class, new FinishedUpdatePacket.Codec(),
|
||||||
map(0x0B, MINECRAFT_1_20_2, false),
|
map(0x0B, MINECRAFT_1_20_2, false),
|
||||||
map(0x0C, MINECRAFT_1_20_5, false),
|
map(0x0C, MINECRAFT_1_20_5, false),
|
||||||
map(0x0E, MINECRAFT_1_21_2, false),
|
map(0x0E, MINECRAFT_1_21_2, false),
|
||||||
@@ -402,7 +402,7 @@ public enum StateRegistry {
|
|||||||
|
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
BossBarPacket.class,
|
BossBarPacket.class,
|
||||||
BossBarPacket::new,
|
new BossBarPacket.Codec(),
|
||||||
map(0x0C, MINECRAFT_1_9, false),
|
map(0x0C, MINECRAFT_1_9, false),
|
||||||
map(0x0D, MINECRAFT_1_15, false),
|
map(0x0D, MINECRAFT_1_15, false),
|
||||||
map(0x0C, MINECRAFT_1_16, false),
|
map(0x0C, MINECRAFT_1_16, false),
|
||||||
@@ -413,14 +413,14 @@ public enum StateRegistry {
|
|||||||
map(0x09, MINECRAFT_1_21_5, false));
|
map(0x09, MINECRAFT_1_21_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LegacyChatPacket.class,
|
LegacyChatPacket.class,
|
||||||
LegacyChatPacket::new,
|
new LegacyChatPacket.Codec(),
|
||||||
map(0x02, MINECRAFT_1_7_2, true),
|
map(0x02, MINECRAFT_1_7_2, true),
|
||||||
map(0x0F, MINECRAFT_1_9, true),
|
map(0x0F, MINECRAFT_1_9, true),
|
||||||
map(0x0E, MINECRAFT_1_13, true),
|
map(0x0E, MINECRAFT_1_13, true),
|
||||||
map(0x0F, MINECRAFT_1_15, true),
|
map(0x0F, MINECRAFT_1_15, true),
|
||||||
map(0x0E, MINECRAFT_1_16, true),
|
map(0x0E, MINECRAFT_1_16, true),
|
||||||
map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, 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(0x3A, MINECRAFT_1_7_2, false),
|
||||||
map(0x0E, MINECRAFT_1_9, false),
|
map(0x0E, MINECRAFT_1_9, false),
|
||||||
map(0x10, MINECRAFT_1_13, false),
|
map(0x10, MINECRAFT_1_13, false),
|
||||||
@@ -435,7 +435,7 @@ public enum StateRegistry {
|
|||||||
map(0x0F, MINECRAFT_1_21_5, false));
|
map(0x0F, MINECRAFT_1_21_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
AvailableCommandsPacket.class,
|
AvailableCommandsPacket.class,
|
||||||
AvailableCommandsPacket::new,
|
new AvailableCommandsPacket.Codec(),
|
||||||
map(0x11, MINECRAFT_1_13, false),
|
map(0x11, MINECRAFT_1_13, false),
|
||||||
map(0x12, MINECRAFT_1_15, false),
|
map(0x12, MINECRAFT_1_15, false),
|
||||||
map(0x11, MINECRAFT_1_16, false),
|
map(0x11, MINECRAFT_1_16, false),
|
||||||
@@ -447,11 +447,11 @@ public enum StateRegistry {
|
|||||||
map(0x11, MINECRAFT_1_20_2, false),
|
map(0x11, MINECRAFT_1_20_2, false),
|
||||||
map(0x10, MINECRAFT_1_21_5, false));
|
map(0x10, MINECRAFT_1_21_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||||
map(0x16, MINECRAFT_1_20_5, false),
|
map(0x16, MINECRAFT_1_20_5, false),
|
||||||
map(0x15, MINECRAFT_1_21_5, false));
|
map(0x15, MINECRAFT_1_21_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
|
ClientboundSoundEntityPacket.class, new ClientboundSoundEntityPacket.Codec(),
|
||||||
map(0x5D, MINECRAFT_1_19_3, true),
|
map(0x5D, MINECRAFT_1_19_3, true),
|
||||||
map(0x61, MINECRAFT_1_19_4, true),
|
map(0x61, MINECRAFT_1_19_4, true),
|
||||||
map(0x63, MINECRAFT_1_20_2, true),
|
map(0x63, MINECRAFT_1_20_2, true),
|
||||||
@@ -461,7 +461,7 @@ public enum StateRegistry {
|
|||||||
map(0x6D, MINECRAFT_1_21_5, true),
|
map(0x6D, MINECRAFT_1_21_5, true),
|
||||||
map(0x72, MINECRAFT_1_21_9, true));
|
map(0x72, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
|
ClientboundStopSoundPacket.class, new ClientboundStopSoundPacket.Codec(),
|
||||||
map(0x5F, MINECRAFT_1_19_3, true),
|
map(0x5F, MINECRAFT_1_19_3, true),
|
||||||
map(0x63, MINECRAFT_1_19_4, true),
|
map(0x63, MINECRAFT_1_19_4, true),
|
||||||
map(0x66, MINECRAFT_1_20_2, true),
|
map(0x66, MINECRAFT_1_20_2, true),
|
||||||
@@ -472,7 +472,7 @@ public enum StateRegistry {
|
|||||||
map(0x75, MINECRAFT_1_21_9, true));
|
map(0x75, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PluginMessagePacket.class,
|
PluginMessagePacket.class,
|
||||||
PluginMessagePacket::new,
|
new PluginMessagePacket.Codec(),
|
||||||
map(0x3F, MINECRAFT_1_7_2, false),
|
map(0x3F, MINECRAFT_1_7_2, false),
|
||||||
map(0x18, MINECRAFT_1_9, false),
|
map(0x18, MINECRAFT_1_9, false),
|
||||||
map(0x19, MINECRAFT_1_13, false),
|
map(0x19, MINECRAFT_1_13, false),
|
||||||
@@ -490,7 +490,7 @@ public enum StateRegistry {
|
|||||||
map(0x18, MINECRAFT_1_21_5, false));
|
map(0x18, MINECRAFT_1_21_5, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
DisconnectPacket.class,
|
DisconnectPacket.class,
|
||||||
() -> new DisconnectPacket(this),
|
new DisconnectPacket.Codec(this),
|
||||||
map(0x40, MINECRAFT_1_7_2, false),
|
map(0x40, MINECRAFT_1_7_2, false),
|
||||||
map(0x1A, MINECRAFT_1_9, false),
|
map(0x1A, MINECRAFT_1_9, false),
|
||||||
map(0x1B, MINECRAFT_1_13, false),
|
map(0x1B, MINECRAFT_1_13, false),
|
||||||
@@ -509,7 +509,7 @@ public enum StateRegistry {
|
|||||||
map(0x20, MINECRAFT_1_21_9, false));
|
map(0x20, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
KeepAlivePacket.class,
|
KeepAlivePacket.class,
|
||||||
KeepAlivePacket::new,
|
new KeepAlivePacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false),
|
map(0x00, MINECRAFT_1_7_2, false),
|
||||||
map(0x1F, MINECRAFT_1_9, false),
|
map(0x1F, MINECRAFT_1_9, false),
|
||||||
map(0x21, MINECRAFT_1_13, false),
|
map(0x21, MINECRAFT_1_13, false),
|
||||||
@@ -529,7 +529,7 @@ public enum StateRegistry {
|
|||||||
map(0x2B, MINECRAFT_1_21_9, false));
|
map(0x2B, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
JoinGamePacket.class,
|
JoinGamePacket.class,
|
||||||
JoinGamePacket::new,
|
new JoinGamePacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_7_2, false),
|
map(0x01, MINECRAFT_1_7_2, false),
|
||||||
map(0x23, MINECRAFT_1_9, false),
|
map(0x23, MINECRAFT_1_9, false),
|
||||||
map(0x25, MINECRAFT_1_13, false),
|
map(0x25, MINECRAFT_1_13, false),
|
||||||
@@ -549,7 +549,7 @@ public enum StateRegistry {
|
|||||||
map(0x30, MINECRAFT_1_21_9, false));
|
map(0x30, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RespawnPacket.class,
|
RespawnPacket.class,
|
||||||
RespawnPacket::new,
|
new RespawnPacket.Codec(),
|
||||||
map(0x07, MINECRAFT_1_7_2, true),
|
map(0x07, MINECRAFT_1_7_2, true),
|
||||||
map(0x33, MINECRAFT_1_9, true),
|
map(0x33, MINECRAFT_1_9, true),
|
||||||
map(0x34, MINECRAFT_1_12, true),
|
map(0x34, MINECRAFT_1_12, true),
|
||||||
@@ -572,7 +572,7 @@ public enum StateRegistry {
|
|||||||
map(0x50, MINECRAFT_1_21_9, true));
|
map(0x50, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
RemoveResourcePackPacket.class,
|
RemoveResourcePackPacket.class,
|
||||||
RemoveResourcePackPacket::new,
|
new RemoveResourcePackPacket.Codec(),
|
||||||
map(0x43, MINECRAFT_1_20_3, false),
|
map(0x43, MINECRAFT_1_20_3, false),
|
||||||
map(0x45, MINECRAFT_1_20_5, false),
|
map(0x45, MINECRAFT_1_20_5, false),
|
||||||
map(0x4A, MINECRAFT_1_21_2, false),
|
map(0x4A, MINECRAFT_1_21_2, false),
|
||||||
@@ -580,7 +580,7 @@ public enum StateRegistry {
|
|||||||
map(0x4E, MINECRAFT_1_21_9, false));
|
map(0x4E, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ResourcePackRequestPacket.class,
|
ResourcePackRequestPacket.class,
|
||||||
ResourcePackRequestPacket::new,
|
new ResourcePackRequestPacket.Codec(),
|
||||||
map(0x48, MINECRAFT_1_8, false),
|
map(0x48, MINECRAFT_1_8, false),
|
||||||
map(0x32, MINECRAFT_1_9, false),
|
map(0x32, MINECRAFT_1_9, false),
|
||||||
map(0x33, MINECRAFT_1_12, false),
|
map(0x33, MINECRAFT_1_12, false),
|
||||||
@@ -603,7 +603,7 @@ public enum StateRegistry {
|
|||||||
map(0x4F, MINECRAFT_1_21_9, false));
|
map(0x4F, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
HeaderAndFooterPacket.class,
|
HeaderAndFooterPacket.class,
|
||||||
HeaderAndFooterPacket::new,
|
new HeaderAndFooterPacket.Codec(),
|
||||||
map(0x47, MINECRAFT_1_8, true),
|
map(0x47, MINECRAFT_1_8, true),
|
||||||
map(0x48, MINECRAFT_1_9, true),
|
map(0x48, MINECRAFT_1_9, true),
|
||||||
map(0x47, MINECRAFT_1_9_4, true),
|
map(0x47, MINECRAFT_1_9_4, true),
|
||||||
@@ -627,7 +627,7 @@ public enum StateRegistry {
|
|||||||
map(0x78, MINECRAFT_1_21_9, true));
|
map(0x78, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LegacyTitlePacket.class,
|
LegacyTitlePacket.class,
|
||||||
LegacyTitlePacket::new,
|
new LegacyTitlePacket.Codec(),
|
||||||
map(0x45, MINECRAFT_1_8, true),
|
map(0x45, MINECRAFT_1_8, true),
|
||||||
map(0x45, MINECRAFT_1_9, true),
|
map(0x45, MINECRAFT_1_9, true),
|
||||||
map(0x47, MINECRAFT_1_12, true),
|
map(0x47, MINECRAFT_1_12, true),
|
||||||
@@ -636,7 +636,7 @@ public enum StateRegistry {
|
|||||||
map(0x4F, MINECRAFT_1_14, true),
|
map(0x4F, MINECRAFT_1_14, true),
|
||||||
map(0x50, MINECRAFT_1_15, true),
|
map(0x50, MINECRAFT_1_15, true),
|
||||||
map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, 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(0x57, MINECRAFT_1_17, true),
|
||||||
map(0x58, MINECRAFT_1_18, true),
|
map(0x58, MINECRAFT_1_18, true),
|
||||||
map(0x5B, MINECRAFT_1_19_1, true),
|
map(0x5B, MINECRAFT_1_19_1, true),
|
||||||
@@ -650,7 +650,7 @@ public enum StateRegistry {
|
|||||||
map(0x6E, MINECRAFT_1_21_9, true));
|
map(0x6E, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTextPacket.class,
|
TitleTextPacket.class,
|
||||||
TitleTextPacket::new,
|
new TitleTextPacket.Codec(),
|
||||||
map(0x59, MINECRAFT_1_17, true),
|
map(0x59, MINECRAFT_1_17, true),
|
||||||
map(0x5A, MINECRAFT_1_18, true),
|
map(0x5A, MINECRAFT_1_18, true),
|
||||||
map(0x5D, MINECRAFT_1_19_1, true),
|
map(0x5D, MINECRAFT_1_19_1, true),
|
||||||
@@ -664,7 +664,7 @@ public enum StateRegistry {
|
|||||||
map(0x70, MINECRAFT_1_21_9, true));
|
map(0x70, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleActionbarPacket.class,
|
TitleActionbarPacket.class,
|
||||||
TitleActionbarPacket::new,
|
new TitleActionbarPacket.Codec(),
|
||||||
map(0x41, MINECRAFT_1_17, true),
|
map(0x41, MINECRAFT_1_17, true),
|
||||||
map(0x40, MINECRAFT_1_19, true),
|
map(0x40, MINECRAFT_1_19, true),
|
||||||
map(0x43, MINECRAFT_1_19_1, true),
|
map(0x43, MINECRAFT_1_19_1, true),
|
||||||
@@ -678,7 +678,7 @@ public enum StateRegistry {
|
|||||||
map(0x55, MINECRAFT_1_21_9, true));
|
map(0x55, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleTimesPacket.class,
|
TitleTimesPacket.class,
|
||||||
TitleTimesPacket::new,
|
new TitleTimesPacket.Codec(),
|
||||||
map(0x5A, MINECRAFT_1_17, true),
|
map(0x5A, MINECRAFT_1_17, true),
|
||||||
map(0x5B, MINECRAFT_1_18, true),
|
map(0x5B, MINECRAFT_1_18, true),
|
||||||
map(0x5E, MINECRAFT_1_19_1, true),
|
map(0x5E, MINECRAFT_1_19_1, true),
|
||||||
@@ -692,7 +692,7 @@ public enum StateRegistry {
|
|||||||
map(0x71, MINECRAFT_1_21_9, true));
|
map(0x71, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TitleClearPacket.class,
|
TitleClearPacket.class,
|
||||||
TitleClearPacket::new,
|
new TitleClearPacket.Codec(),
|
||||||
map(0x10, MINECRAFT_1_17, true),
|
map(0x10, MINECRAFT_1_17, true),
|
||||||
map(0x0D, MINECRAFT_1_19, true),
|
map(0x0D, MINECRAFT_1_19, true),
|
||||||
map(0x0C, MINECRAFT_1_19_3, true),
|
map(0x0C, MINECRAFT_1_19_3, true),
|
||||||
@@ -701,7 +701,7 @@ public enum StateRegistry {
|
|||||||
map(0x0E, MINECRAFT_1_21_5, true));
|
map(0x0E, MINECRAFT_1_21_5, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LegacyPlayerListItemPacket.class,
|
LegacyPlayerListItemPacket.class,
|
||||||
LegacyPlayerListItemPacket::new,
|
new LegacyPlayerListItemPacket.Codec(),
|
||||||
map(0x38, MINECRAFT_1_7_2, false),
|
map(0x38, MINECRAFT_1_7_2, false),
|
||||||
map(0x2D, MINECRAFT_1_9, false),
|
map(0x2D, MINECRAFT_1_9, false),
|
||||||
map(0x2E, MINECRAFT_1_12_1, false),
|
map(0x2E, MINECRAFT_1_12_1, false),
|
||||||
@@ -713,7 +713,7 @@ public enum StateRegistry {
|
|||||||
map(0x36, MINECRAFT_1_17, false),
|
map(0x36, MINECRAFT_1_17, false),
|
||||||
map(0x34, MINECRAFT_1_19, false),
|
map(0x34, MINECRAFT_1_19, false),
|
||||||
map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, 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(0x35, MINECRAFT_1_19_3, false),
|
||||||
map(0x39, MINECRAFT_1_19_4, false),
|
map(0x39, MINECRAFT_1_19_4, false),
|
||||||
map(0x3B, MINECRAFT_1_20_2, false),
|
map(0x3B, MINECRAFT_1_20_2, false),
|
||||||
@@ -723,7 +723,7 @@ public enum StateRegistry {
|
|||||||
map(0x43, MINECRAFT_1_21_9, false));
|
map(0x43, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
UpsertPlayerInfoPacket.class,
|
UpsertPlayerInfoPacket.class,
|
||||||
UpsertPlayerInfoPacket::new,
|
new UpsertPlayerInfoPacket.Codec(),
|
||||||
map(0x36, MINECRAFT_1_19_3, false),
|
map(0x36, MINECRAFT_1_19_3, false),
|
||||||
map(0x3A, MINECRAFT_1_19_4, false),
|
map(0x3A, MINECRAFT_1_19_4, false),
|
||||||
map(0x3C, MINECRAFT_1_20_2, false),
|
map(0x3C, MINECRAFT_1_20_2, false),
|
||||||
@@ -732,14 +732,14 @@ public enum StateRegistry {
|
|||||||
map(0x3F, MINECRAFT_1_21_5, false),
|
map(0x3F, MINECRAFT_1_21_5, false),
|
||||||
map(0x44, MINECRAFT_1_21_9, false));
|
map(0x44, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new,
|
ClientboundStoreCookiePacket.class, new ClientboundStoreCookiePacket.Codec(),
|
||||||
map(0x6B, MINECRAFT_1_20_5, false),
|
map(0x6B, MINECRAFT_1_20_5, false),
|
||||||
map(0x72, MINECRAFT_1_21_2, false),
|
map(0x72, MINECRAFT_1_21_2, false),
|
||||||
map(0x71, MINECRAFT_1_21_5, false),
|
map(0x71, MINECRAFT_1_21_5, false),
|
||||||
map(0x76, MINECRAFT_1_21_9, false));
|
map(0x76, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
SystemChatPacket.class,
|
SystemChatPacket.class,
|
||||||
SystemChatPacket::new,
|
new SystemChatPacket.Codec(),
|
||||||
map(0x5F, MINECRAFT_1_19, true),
|
map(0x5F, MINECRAFT_1_19, true),
|
||||||
map(0x62, MINECRAFT_1_19_1, true),
|
map(0x62, MINECRAFT_1_19_1, true),
|
||||||
map(0x60, MINECRAFT_1_19_3, true),
|
map(0x60, MINECRAFT_1_19_3, true),
|
||||||
@@ -752,7 +752,7 @@ public enum StateRegistry {
|
|||||||
map(0x77, MINECRAFT_1_21_9, true));
|
map(0x77, MINECRAFT_1_21_9, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
PlayerChatCompletionPacket.class,
|
PlayerChatCompletionPacket.class,
|
||||||
PlayerChatCompletionPacket::new,
|
new PlayerChatCompletionPacket.Codec(),
|
||||||
map(0x15, MINECRAFT_1_19_1, true),
|
map(0x15, MINECRAFT_1_19_1, true),
|
||||||
map(0x14, MINECRAFT_1_19_3, true),
|
map(0x14, MINECRAFT_1_19_3, true),
|
||||||
map(0x16, MINECRAFT_1_19_4, true),
|
map(0x16, MINECRAFT_1_19_4, true),
|
||||||
@@ -761,7 +761,7 @@ public enum StateRegistry {
|
|||||||
map(0x17, MINECRAFT_1_21_5, true));
|
map(0x17, MINECRAFT_1_21_5, true));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ServerDataPacket.class,
|
ServerDataPacket.class,
|
||||||
ServerDataPacket::new,
|
new ServerDataPacket.Codec(),
|
||||||
map(0x3F, MINECRAFT_1_19, false),
|
map(0x3F, MINECRAFT_1_19, false),
|
||||||
map(0x42, MINECRAFT_1_19_1, false),
|
map(0x42, MINECRAFT_1_19_1, false),
|
||||||
map(0x41, MINECRAFT_1_19_3, false),
|
map(0x41, MINECRAFT_1_19_3, false),
|
||||||
@@ -774,7 +774,7 @@ public enum StateRegistry {
|
|||||||
map(0x54, MINECRAFT_1_21_9, false));
|
map(0x54, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
StartUpdatePacket.class,
|
StartUpdatePacket.class,
|
||||||
() -> StartUpdatePacket.INSTANCE,
|
new StartUpdatePacket.Codec(),
|
||||||
map(0x65, MINECRAFT_1_20_2, false),
|
map(0x65, MINECRAFT_1_20_2, false),
|
||||||
map(0x67, MINECRAFT_1_20_3, false),
|
map(0x67, MINECRAFT_1_20_3, false),
|
||||||
map(0x69, MINECRAFT_1_20_5, false),
|
map(0x69, MINECRAFT_1_20_5, false),
|
||||||
@@ -783,23 +783,23 @@ public enum StateRegistry {
|
|||||||
map(0x74, MINECRAFT_1_21_9, false));
|
map(0x74, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
BundleDelimiterPacket.class,
|
BundleDelimiterPacket.class,
|
||||||
() -> BundleDelimiterPacket.INSTANCE,
|
new BundleDelimiterPacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_19_4, false));
|
map(0x00, MINECRAFT_1_19_4, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
TransferPacket.class,
|
TransferPacket.class,
|
||||||
TransferPacket::new,
|
new TransferPacket.Codec(),
|
||||||
map(0x73, MINECRAFT_1_20_5, false),
|
map(0x73, MINECRAFT_1_20_5, false),
|
||||||
map(0x7A, MINECRAFT_1_21_2, false),
|
map(0x7A, MINECRAFT_1_21_2, false),
|
||||||
map(0x7F, MINECRAFT_1_21_9, false));
|
map(0x7F, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCustomReportDetailsPacket.class,
|
ClientboundCustomReportDetailsPacket.class,
|
||||||
ClientboundCustomReportDetailsPacket::new,
|
new ClientboundCustomReportDetailsPacket.Codec(),
|
||||||
map(0x7A, MINECRAFT_1_21, false),
|
map(0x7A, MINECRAFT_1_21, false),
|
||||||
map(0x81, MINECRAFT_1_21_2, false),
|
map(0x81, MINECRAFT_1_21_2, false),
|
||||||
map(0x86, MINECRAFT_1_21_9, false));
|
map(0x86, MINECRAFT_1_21_9, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundServerLinksPacket.class,
|
ClientboundServerLinksPacket.class,
|
||||||
ClientboundServerLinksPacket::new,
|
new ClientboundServerLinksPacket.Codec(),
|
||||||
map(0x7B, MINECRAFT_1_21, false),
|
map(0x7B, MINECRAFT_1_21, false),
|
||||||
map(0x82, MINECRAFT_1_21_2, false),
|
map(0x82, MINECRAFT_1_21_2, false),
|
||||||
map(0x87, MINECRAFT_1_21_9, false));
|
map(0x87, MINECRAFT_1_21_9, false));
|
||||||
@@ -808,39 +808,39 @@ public enum StateRegistry {
|
|||||||
LOGIN {
|
LOGIN {
|
||||||
{
|
{
|
||||||
serverbound.register(ServerLoginPacket.class,
|
serverbound.register(ServerLoginPacket.class,
|
||||||
ServerLoginPacket::new,
|
new ServerLoginPacket.Codec(),
|
||||||
map(0x00, MINECRAFT_1_7_2, false));
|
map(0x00, MINECRAFT_1_7_2, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
EncryptionResponsePacket.class, EncryptionResponsePacket::new,
|
EncryptionResponsePacket.class, new EncryptionResponsePacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_7_2, false));
|
map(0x01, MINECRAFT_1_7_2, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
LoginPluginResponsePacket.class, LoginPluginResponsePacket::new,
|
LoginPluginResponsePacket.class, new LoginPluginResponsePacket.Codec(),
|
||||||
map(0x02, MINECRAFT_1_13, false));
|
map(0x02, MINECRAFT_1_13, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
LoginAcknowledgedPacket.class, LoginAcknowledgedPacket::new,
|
LoginAcknowledgedPacket.class, new LoginAcknowledgedPacket.Codec(),
|
||||||
map(0x03, MINECRAFT_1_20_2, false));
|
map(0x03, MINECRAFT_1_20_2, false));
|
||||||
serverbound.register(
|
serverbound.register(
|
||||||
ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new,
|
ServerboundCookieResponsePacket.class, new ServerboundCookieResponsePacket.Codec(),
|
||||||
map(0x04, MINECRAFT_1_20_5, false));
|
map(0x04, MINECRAFT_1_20_5, false));
|
||||||
|
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
DisconnectPacket.class, () -> new DisconnectPacket(this),
|
DisconnectPacket.class, new DisconnectPacket.Codec(this),
|
||||||
map(0x00, MINECRAFT_1_7_2, false));
|
map(0x00, MINECRAFT_1_7_2, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
EncryptionRequestPacket.class, EncryptionRequestPacket::new,
|
EncryptionRequestPacket.class, new EncryptionRequestPacket.Codec(),
|
||||||
map(0x01, MINECRAFT_1_7_2, false));
|
map(0x01, MINECRAFT_1_7_2, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ServerLoginSuccessPacket.class, ServerLoginSuccessPacket::new,
|
ServerLoginSuccessPacket.class, new ServerLoginSuccessPacket.Codec(),
|
||||||
map(0x02, MINECRAFT_1_7_2, false));
|
map(0x02, MINECRAFT_1_7_2, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
SetCompressionPacket.class, SetCompressionPacket::new,
|
SetCompressionPacket.class, new SetCompressionPacket.Codec(),
|
||||||
map(0x03, MINECRAFT_1_8, false));
|
map(0x03, MINECRAFT_1_8, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
LoginPluginMessagePacket.class,
|
LoginPluginMessagePacket.class,
|
||||||
LoginPluginMessagePacket::new,
|
new LoginPluginMessagePacket.Codec(),
|
||||||
map(0x04, MINECRAFT_1_13, false));
|
map(0x04, MINECRAFT_1_13, false));
|
||||||
clientbound.register(
|
clientbound.register(
|
||||||
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
|
ClientboundCookieRequestPacket.class, new ClientboundCookieRequestPacket.Codec(),
|
||||||
map(0x05, MINECRAFT_1_20_5, false));
|
map(0x05, MINECRAFT_1_20_5, false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -906,7 +906,7 @@ public enum StateRegistry {
|
|||||||
return registry;
|
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) {
|
PacketMapping... mappings) {
|
||||||
if (mappings.length == 0) {
|
if (mappings.length == 0) {
|
||||||
throw new IllegalArgumentException("At least one mapping must be provided.");
|
throw new IllegalArgumentException("At least one mapping must be provided.");
|
||||||
@@ -947,7 +947,7 @@ public enum StateRegistry {
|
|||||||
"Unknown protocol version " + current.protocolVersion);
|
"Unknown protocol version " + current.protocolVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registry.packetIdToSupplier.containsKey(current.id)) {
|
if (registry.packetIdToCodec.containsKey(current.id)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Can not register class "
|
"Can not register class "
|
||||||
+ clazz.getSimpleName()
|
+ clazz.getSimpleName()
|
||||||
@@ -964,8 +964,9 @@ public enum StateRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!current.encodeOnly) {
|
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);
|
registry.packetClassToId.put(clazz, current.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -977,8 +978,11 @@ public enum StateRegistry {
|
|||||||
public class ProtocolRegistry {
|
public class ProtocolRegistry {
|
||||||
|
|
||||||
public final ProtocolVersion version;
|
public final ProtocolVersion version;
|
||||||
final IntObjectMap<Supplier<? extends MinecraftPacket>> packetIdToSupplier =
|
final IntObjectMap<PacketCodec<? extends MinecraftPacket>> packetIdToCodec =
|
||||||
new IntObjectHashMap<>(16, 0.5f);
|
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 =
|
final Object2IntMap<Class<? extends MinecraftPacket>> packetClassToId =
|
||||||
new Object2IntOpenHashMap<>(16, 0.5f);
|
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
|
* @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) {
|
public @Nullable PacketCodec<? extends MinecraftPacket> getCodec(final int id) {
|
||||||
final Supplier<? extends MinecraftPacket> supplier = this.packetIdToSupplier.get(id);
|
return this.packetIdToCodec.get(id);
|
||||||
if (supplier == null) {
|
}
|
||||||
return null;
|
|
||||||
}
|
/**
|
||||||
return supplier.get();
|
* 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));
|
out.add(readExtended16Data(in));
|
||||||
} else if (first == 0x02 && in.isReadable()) {
|
} else if (first == 0x02 && in.isReadable()) {
|
||||||
in.skipBytes(in.readableBytes());
|
in.skipBytes(in.readableBytes());
|
||||||
out.add(new LegacyHandshakePacket());
|
out.add(LegacyHandshakePacket.INSTANCE);
|
||||||
} else {
|
} else {
|
||||||
in.readerIndex(originalReaderIndex);
|
in.readerIndex(originalReaderIndex);
|
||||||
ctx.pipeline().remove(this);
|
ctx.pipeline().remove(this);
|
||||||
|
|||||||
@@ -71,18 +71,20 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
|||||||
|
|
||||||
int originalReaderIndex = buf.readerIndex();
|
int originalReaderIndex = buf.readerIndex();
|
||||||
int packetId = ProtocolUtils.readVarInt(buf);
|
int packetId = ProtocolUtils.readVarInt(buf);
|
||||||
MinecraftPacket packet = this.registry.createPacket(packetId);
|
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec =
|
||||||
if (packet == null) {
|
this.registry.getCodec(packetId);
|
||||||
|
if (codec == null) {
|
||||||
buf.readerIndex(originalReaderIndex);
|
buf.readerIndex(originalReaderIndex);
|
||||||
ctx.fireChannelRead(buf);
|
ctx.fireChannelRead(buf);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
doLengthSanityChecks(buf, packet);
|
doLengthSanityChecks(buf, codec);
|
||||||
|
|
||||||
|
MinecraftPacket packet;
|
||||||
try {
|
try {
|
||||||
packet.decode(buf, direction, registry.version);
|
packet = codec.decode(buf, direction, registry.version);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleDecodeFailure(e, packet, packetId);
|
throw handleDecodeFailure(e, codec, packetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf.isReadable()) {
|
if (buf.isReadable()) {
|
||||||
@@ -95,14 +97,16 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
|
private void doLengthSanityChecks(ByteBuf buf,
|
||||||
int expectedMinLen = packet.decodeExpectedMinLength(buf, direction, registry.version);
|
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec)
|
||||||
int expectedMaxLen = packet.decodeExpectedMaxLength(buf, direction, registry.version);
|
throws Exception {
|
||||||
|
int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, registry.version);
|
||||||
|
int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, registry.version);
|
||||||
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
|
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
|
||||||
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
|
throw handleOverflow(codec, expectedMaxLen, buf.readableBytes());
|
||||||
}
|
}
|
||||||
if (buf.readableBytes() < expectedMinLen) {
|
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) {
|
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)");
|
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||||
} else {
|
} else {
|
||||||
return DECODE_FAILED;
|
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) {
|
if (DEBUG) {
|
||||||
return new CorruptedFrameException(
|
return new CorruptedFrameException(
|
||||||
"Error decoding " + packet.getClass() + " " + getExtraConnectionDetail(packetId), cause);
|
"Error decoding " + codec.getClass() + " " + getExtraConnectionDetail(packetId), cause);
|
||||||
} else {
|
} else {
|
||||||
return DECODE_FAILED;
|
return DECODE_FAILED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.netty;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@@ -48,16 +49,31 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected void encode(ChannelHandlerContext ctx, MinecraftPacket msg, ByteBuf out) {
|
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);
|
int packetId = this.registry.getPacketId(msg);
|
||||||
ProtocolUtils.writeVarInt(out, packetId);
|
ProtocolUtils.writeVarInt(out, packetId);
|
||||||
msg.encode(out, direction, registry.version);
|
codec.encode(msg, out, direction, registry.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, MinecraftPacket msg,
|
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, MinecraftPacket msg,
|
||||||
boolean preferDirect) throws Exception {
|
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) {
|
if (hint < 0) {
|
||||||
return super.allocateBuffer(ctx, msg, preferDirect);
|
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 static io.netty.util.ByteProcessor.FIND_NON_NUL;
|
||||||
|
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
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.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
@@ -122,22 +122,21 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
final int payloadLength = length - ProtocolUtils.varIntBytes(packetId);
|
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
|
// 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;
|
throw UNKNOWN_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
|
// 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
|
// the packet if needed, so, we'll take advantage of the existing methods
|
||||||
int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version);
|
int expectedMinLen = codec.decodeExpectedMinLength(in, direction, registry.version);
|
||||||
int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version);
|
int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, registry.version);
|
||||||
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
|
||||||
throw handleOverflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleOverflow(expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
if (payloadLength < expectedMinLen) {
|
if (payloadLength < expectedMinLen) {
|
||||||
throw handleUnderflow(packet, expectedMaxLen, in.readableBytes());
|
throw handleUnderflow(expectedMaxLen, in.readableBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
in.readerIndex(index);
|
in.readerIndex(index);
|
||||||
@@ -224,18 +223,18 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
|
|||||||
return result | (tmp & 0x7F) << 14;
|
return result | (tmp & 0x7F) << 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exception handleOverflow(MinecraftPacket packet, int expected, int actual) {
|
private Exception handleOverflow(int expected, int actual) {
|
||||||
if (MinecraftDecoder.DEBUG) {
|
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)");
|
+ "big (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||||
} else {
|
} else {
|
||||||
return FRAME_DECODER_FAILED;
|
return FRAME_DECODER_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Exception handleUnderflow(MinecraftPacket packet, int expected, int actual) {
|
private Exception handleUnderflow(int expected, int actual) {
|
||||||
if (MinecraftDecoder.DEBUG) {
|
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)");
|
+ "small (expected " + expected + " bytes, got " + actual + " bytes)");
|
||||||
} else {
|
} else {
|
||||||
return FRAME_DECODER_FAILED;
|
return FRAME_DECODER_FAILED;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.velocitypowered.api.command.CommandSource;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.packet.brigadier.ArgumentPropertyRegistry;
|
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.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 Command<CommandSource> PLACEHOLDER_COMMAND = source -> 0;
|
||||||
private static final Predicate<CommandSource> PLACEHOLDER_REQUIREMENT = source -> true;
|
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_HAS_SUGGESTIONS = 0x10;
|
||||||
private static final byte FLAG_IS_RESTRICTED = 0x20;
|
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() {
|
public RootCommandNode<CommandSource> getRootNode() {
|
||||||
if (rootNode == null) {
|
|
||||||
throw new IllegalStateException("Packet not yet deserialized");
|
|
||||||
}
|
|
||||||
return rootNode;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WireNode deserializeNode(ByteBuf buf, int idx, ProtocolVersion version) {
|
public static class Codec implements PacketCodec<AvailableCommandsPacket> {
|
||||||
byte flags = buf.readByte();
|
@Override
|
||||||
int[] children = ProtocolUtils.readIntegerArray(buf);
|
public AvailableCommandsPacket decode(ByteBuf buf, Direction direction,
|
||||||
int redirectTo = -1;
|
ProtocolVersion protocolVersion) {
|
||||||
if ((flags & FLAG_IS_REDIRECT) > 0) {
|
int commands = ProtocolUtils.readVarInt(buf);
|
||||||
redirectTo = 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) {
|
@Override
|
||||||
case NODE_TYPE_ROOT:
|
public void encode(AvailableCommandsPacket packet, ByteBuf buf, Direction direction,
|
||||||
return new WireNode(idx, flags, children, redirectTo, null);
|
ProtocolVersion protocolVersion) {
|
||||||
case NODE_TYPE_LITERAL:
|
// Assign all the children an index.
|
||||||
return new WireNode(idx, flags, children, redirectTo, LiteralArgumentBuilder
|
Deque<CommandNode<CommandSource>> childrenQueue = new ArrayDeque<>(ImmutableList.of(packet.rootNode));
|
||||||
.literal(ProtocolUtils.readString(buf)));
|
Object2IntMap<CommandNode<CommandSource>> idMappings = new Object2IntLinkedOpenCustomHashMap<>(
|
||||||
case NODE_TYPE_ARGUMENT:
|
IdentityHashStrategy.instance());
|
||||||
String name = ProtocolUtils.readString(buf);
|
while (!childrenQueue.isEmpty()) {
|
||||||
ArgumentType<?> argumentType = ArgumentPropertyRegistry.deserialize(buf, version);
|
CommandNode<CommandSource> child = childrenQueue.poll();
|
||||||
|
if (!idMappings.containsKey(child)) {
|
||||||
RequiredArgumentBuilder<CommandSource, ?> argumentBuilder = RequiredArgumentBuilder
|
idMappings.put(child, idMappings.size());
|
||||||
.argument(name, argumentType);
|
childrenQueue.addAll(child.getChildren());
|
||||||
if ((flags & FLAG_HAS_SUGGESTIONS) != 0) {
|
if (child.getRedirect() != null) {
|
||||||
argumentBuilder.suggests(new ProtocolSuggestionProvider(ProtocolUtils.readString(buf)));
|
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();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import com.velocitypowered.proxy.util.collect.Enum2IntMap;
|
import com.velocitypowered.proxy.util.collect.Enum2IntMap;
|
||||||
@@ -29,7 +30,8 @@ import java.util.UUID;
|
|||||||
import net.kyori.adventure.bossbar.BossBar;
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 =
|
private static final Enum2IntMap<BossBar.Color> COLORS_TO_PROTOCOL =
|
||||||
new Enum2IntMap.Builder<>(BossBar.Color.class)
|
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_NAME = 3;
|
||||||
public static final int UPDATE_STYLE = 4;
|
public static final int UPDATE_STYLE = 4;
|
||||||
public static final int UPDATE_PROPERTIES = 5;
|
public static final int UPDATE_PROPERTIES = 5;
|
||||||
private @Nullable UUID uuid;
|
|
||||||
private int action;
|
public UUID getUuid() {
|
||||||
private @Nullable ComponentHolder name;
|
return uuid;
|
||||||
private float percent;
|
}
|
||||||
private int color;
|
|
||||||
private int overlay;
|
public int getAction() {
|
||||||
private short flags;
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
public static BossBarPacket createAddPacket(
|
public static BossBarPacket createAddPacket(
|
||||||
final UUID id,
|
final UUID id,
|
||||||
final BossBar bar,
|
final BossBar bar,
|
||||||
final ComponentHolder name
|
final ComponentHolder name
|
||||||
) {
|
) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, ADD, name, bar.progress(),
|
||||||
packet.setUuid(id);
|
COLORS_TO_PROTOCOL.get(bar.color()), OVERLAY_TO_PROTOCOL.get(bar.overlay()),
|
||||||
packet.setAction(BossBarPacket.ADD);
|
serializeFlags(bar.flags()));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BossBarPacket createRemovePacket(final UUID id, final BossBar bar) {
|
public static BossBarPacket createRemovePacket(final UUID id) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, REMOVE, null, 0, 0, 0, (short) 0);
|
||||||
packet.setUuid(id);
|
|
||||||
packet.setAction(REMOVE);
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BossBarPacket createUpdateProgressPacket(final UUID id, final BossBar bar) {
|
public static BossBarPacket createUpdateProgressPacket(final UUID id, final BossBar bar) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, UPDATE_PERCENT, null, bar.progress(), 0, 0, (short) 0);
|
||||||
packet.setUuid(id);
|
|
||||||
packet.setAction(UPDATE_PERCENT);
|
|
||||||
packet.setPercent(bar.progress());
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BossBarPacket createUpdateNamePacket(
|
public static BossBarPacket createUpdateNamePacket(
|
||||||
@@ -106,177 +96,20 @@ public class BossBarPacket implements MinecraftPacket {
|
|||||||
final BossBar bar,
|
final BossBar bar,
|
||||||
final ComponentHolder name
|
final ComponentHolder name
|
||||||
) {
|
) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, UPDATE_NAME, name, 0, 0, 0, (short) 0);
|
||||||
packet.setUuid(id);
|
|
||||||
packet.setAction(UPDATE_NAME);
|
|
||||||
packet.setName(name);
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BossBarPacket createUpdateStylePacket(final UUID id, final BossBar bar) {
|
public static BossBarPacket createUpdateStylePacket(final UUID id, final BossBar bar) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, UPDATE_STYLE, null, 0,
|
||||||
packet.setUuid(id);
|
COLORS_TO_PROTOCOL.get(bar.color()), OVERLAY_TO_PROTOCOL.get(bar.overlay()), (short) 0);
|
||||||
packet.setAction(UPDATE_STYLE);
|
|
||||||
packet.setColor(COLORS_TO_PROTOCOL.get(bar.color()));
|
|
||||||
packet.setOverlay(OVERLAY_TO_PROTOCOL.get(bar.overlay()));
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BossBarPacket createUpdatePropertiesPacket(final UUID id, final BossBar bar) {
|
public static BossBarPacket createUpdatePropertiesPacket(final UUID id, final BossBar bar) {
|
||||||
final BossBarPacket packet = new BossBarPacket();
|
return new BossBarPacket(id, UPDATE_PROPERTIES, null, 0, 0, 0, serializeFlags(bar.flags()));
|
||||||
packet.setUuid(id);
|
|
||||||
packet.setAction(UPDATE_PROPERTIES);
|
|
||||||
packet.setFlags(serializeFlags(bar.flags()));
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getUuid() {
|
private static short serializeFlags(Set<BossBar.Flag> flags) {
|
||||||
if (uuid == null) {
|
short val = 0x0;
|
||||||
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;
|
|
||||||
for (BossBar.Flag flag : flags) {
|
for (BossBar.Flag flag : flags) {
|
||||||
val |= FLAG_BITS_TO_PROTOCOL.get(flag);
|
val |= FLAG_BITS_TO_PROTOCOL.get(flag);
|
||||||
}
|
}
|
||||||
@@ -287,4 +120,86 @@ public class BossBarPacket implements MinecraftPacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
@@ -29,18 +30,21 @@ public final class BundleDelimiterPacket implements MinecraftPacket {
|
|||||||
private BundleDelimiterPacket() {
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class ClientSettingsPacket implements MinecraftPacket {
|
public final class ClientSettingsPacket implements MinecraftPacket {
|
||||||
private @Nullable String locale;
|
private final @Nullable String locale;
|
||||||
private byte viewDistance;
|
private final byte viewDistance;
|
||||||
private int chatVisibility;
|
private final int chatVisibility;
|
||||||
private boolean chatColors;
|
private final boolean chatColors;
|
||||||
private byte difficulty; // 1.7 Protocol
|
private final byte difficulty; // 1.7 Protocol
|
||||||
private short skinParts;
|
private final short skinParts;
|
||||||
private int mainHand;
|
private final int mainHand;
|
||||||
private boolean textFilteringEnabled; // Added in 1.17
|
private final boolean textFilteringEnabled; // Added in 1.17
|
||||||
private boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode
|
private final boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode
|
||||||
private int particleStatus; // Added in 1.21.2
|
private final int particleStatus; // Added in 1.21.2
|
||||||
|
|
||||||
public ClientSettingsPacket() {
|
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,
|
public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility,
|
||||||
short skinParts, int mainHand, boolean textFilteringEnabled, boolean clientListingAllowed,
|
boolean chatColors, short skinParts, int mainHand,
|
||||||
int particleStatus) {
|
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.locale = locale;
|
||||||
this.viewDistance = viewDistance;
|
this.viewDistance = viewDistance;
|
||||||
this.chatVisibility = chatVisibility;
|
this.chatVisibility = chatVisibility;
|
||||||
this.chatColors = chatColors;
|
this.chatColors = chatColors;
|
||||||
|
this.difficulty = difficulty;
|
||||||
this.skinParts = skinParts;
|
this.skinParts = skinParts;
|
||||||
this.mainHand = mainHand;
|
this.mainHand = mainHand;
|
||||||
this.textFilteringEnabled = textFilteringEnabled;
|
this.textFilteringEnabled = textFilteringEnabled;
|
||||||
@@ -55,150 +67,51 @@ public class ClientSettingsPacket implements MinecraftPacket {
|
|||||||
this.particleStatus = particleStatus;
|
this.particleStatus = particleStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLocale() {
|
public String locale() {
|
||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
throw new IllegalStateException("No locale specified");
|
throw new IllegalStateException("No locale specified");
|
||||||
}
|
}
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocale(String locale) {
|
public byte viewDistance() {
|
||||||
this.locale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getViewDistance() {
|
|
||||||
return viewDistance;
|
return viewDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setViewDistance(byte viewDistance) {
|
public int chatVisibility() {
|
||||||
this.viewDistance = viewDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getChatVisibility() {
|
|
||||||
return chatVisibility;
|
return chatVisibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChatVisibility(int chatVisibility) {
|
public boolean chatColors() {
|
||||||
this.chatVisibility = chatVisibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isChatColors() {
|
|
||||||
return chatColors;
|
return chatColors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChatColors(boolean chatColors) {
|
public byte difficulty() {
|
||||||
this.chatColors = chatColors;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getSkinParts() {
|
public short skinParts() {
|
||||||
return skinParts;
|
return skinParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSkinParts(short skinParts) {
|
public int mainHand() {
|
||||||
this.skinParts = skinParts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMainHand() {
|
|
||||||
return mainHand;
|
return mainHand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMainHand(int mainHand) {
|
public boolean textFilteringEnabled() {
|
||||||
this.mainHand = mainHand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTextFilteringEnabled() {
|
|
||||||
return textFilteringEnabled;
|
return textFilteringEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextFilteringEnabled(boolean textFilteringEnabled) {
|
public boolean clientListingAllowed() {
|
||||||
this.textFilteringEnabled = textFilteringEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isClientListingAllowed() {
|
|
||||||
return clientListingAllowed;
|
return clientListingAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClientListingAllowed(boolean clientListingAllowed) {
|
public int particleStatus() {
|
||||||
this.clientListingAllowed = clientListingAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getParticleStatus() {
|
|
||||||
return particleStatus;
|
return particleStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParticleStatus(int particleStatus) {
|
public String getLocale() {
|
||||||
this.particleStatus = particleStatus;
|
return locale();
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -227,18 +140,79 @@ public class ClientSettingsPacket implements MinecraftPacket {
|
|||||||
&& Objects.equals(locale, that.locale);
|
&& Objects.equals(locale, that.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<ClientSettingsPacket> {
|
||||||
public int hashCode() {
|
@Override
|
||||||
return Objects.hash(
|
public ClientSettingsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
locale,
|
ProtocolVersion version) {
|
||||||
viewDistance,
|
String locale = ProtocolUtils.readString(buf, 16);
|
||||||
chatVisibility,
|
byte viewDistance = buf.readByte();
|
||||||
chatColors,
|
int chatVisibility = ProtocolUtils.readVarInt(buf);
|
||||||
difficulty,
|
boolean chatColors = buf.readBoolean();
|
||||||
skinParts,
|
byte difficulty = 0;
|
||||||
mainHand,
|
|
||||||
textFilteringEnabled,
|
if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_7_6)) {
|
||||||
clientListingAllowed,
|
difficulty = buf.readByte();
|
||||||
particleStatus);
|
}
|
||||||
|
|
||||||
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
|
||||||
public class ClientboundCookieRequestPacket implements MinecraftPacket {
|
public record ClientboundCookieRequestPacket(Key key) implements MinecraftPacket {
|
||||||
|
|
||||||
private Key key;
|
|
||||||
|
|
||||||
public Key getKey() {
|
public Key getKey() {
|
||||||
return key;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import net.kyori.adventure.sound.Sound;
|
import net.kyori.adventure.sound.Sound;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class ClientboundSoundEntityPacket implements MinecraftPacket {
|
public record ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange,
|
||||||
|
int emitterEntityId) 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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sound getSound() {
|
public static class Codec implements PacketCodec<ClientboundSoundEntityPacket> {
|
||||||
return sound;
|
@Override
|
||||||
}
|
public ClientboundSoundEntityPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
|
ProtocolVersion protocolVersion) {
|
||||||
|
throw new UnsupportedOperationException("Decode is not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
public void setSound(Sound sound) {
|
@Override
|
||||||
this.sound = sound;
|
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() {
|
ProtocolUtils.writeMinimalKey(buf, packet.sound.name());
|
||||||
return fixedRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFixedRange(@Nullable Float fixedRange) {
|
buf.writeBoolean(packet.fixedRange != null);
|
||||||
this.fixedRange = fixedRange;
|
if (packet.fixedRange != null) {
|
||||||
}
|
buf.writeFloat(packet.fixedRange);
|
||||||
|
}
|
||||||
|
|
||||||
public int getEmitterEntityId() {
|
ProtocolUtils.writeSoundSource(buf, protocolVersion, packet.sound.source());
|
||||||
return emitterEntityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEmitterEntityId(int emitterEntityId) {
|
ProtocolUtils.writeVarInt(buf, packet.emitterEntityId);
|
||||||
this.emitterEntityId = 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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
@@ -28,82 +29,58 @@ import net.kyori.adventure.sound.SoundStop;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class ClientboundStopSoundPacket implements MinecraftPacket {
|
public record ClientboundStopSoundPacket(@Nullable Sound.Source source,
|
||||||
|
@Nullable Key soundName) implements MinecraftPacket {
|
||||||
private @Nullable Sound.Source source;
|
|
||||||
private @Nullable Key soundName;
|
|
||||||
|
|
||||||
public ClientboundStopSoundPacket() {}
|
|
||||||
|
|
||||||
public ClientboundStopSoundPacket(SoundStop soundStop) {
|
public ClientboundStopSoundPacket(SoundStop soundStop) {
|
||||||
this(soundStop.source(), soundStop.sound());
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
public static class Codec implements PacketCodec<ClientboundStopSoundPacket> {
|
||||||
public Sound.Source getSource() {
|
@Override
|
||||||
return source;
|
public ClientboundStopSoundPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
}
|
ProtocolVersion protocolVersion) {
|
||||||
|
int flagsBitmask = buf.readByte();
|
||||||
|
|
||||||
public void setSource(@Nullable Sound.Source source) {
|
Sound.Source source = null;
|
||||||
this.source = source;
|
if ((flagsBitmask & 1) != 0) {
|
||||||
}
|
source = ProtocolUtils.readSoundSource(buf, protocolVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
Key soundName = null;
|
||||||
public Key getSoundName() {
|
if ((flagsBitmask & 2) != 0) {
|
||||||
return soundName;
|
soundName = ProtocolUtils.readKey(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSoundName(@Nullable Key soundName) {
|
return new ClientboundStopSoundPacket(source, soundName);
|
||||||
this.soundName = 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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
|
||||||
public class ClientboundStoreCookiePacket implements MinecraftPacket {
|
public record ClientboundStoreCookiePacket(Key key, byte[] payload) 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
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;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class DialogClearPacket implements MinecraftPacket {
|
public final class DialogClearPacket implements MinecraftPacket {
|
||||||
|
|
||||||
public static final DialogClearPacket INSTANCE = new DialogClearPacket();
|
public static final DialogClearPacket INSTANCE = new DialogClearPacket();
|
||||||
|
|
||||||
private DialogClearPacket() {
|
private DialogClearPacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.nbt.BinaryTag;
|
import net.kyori.adventure.nbt.BinaryTag;
|
||||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||||
|
|
||||||
public class DialogShowPacket implements MinecraftPacket {
|
public final class DialogShowPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private final StateRegistry state;
|
private final StateRegistry state;
|
||||||
private int id;
|
private final int id;
|
||||||
private BinaryTag nbt;
|
private final BinaryTag nbt;
|
||||||
|
|
||||||
public DialogShowPacket(final StateRegistry state) {
|
public DialogShowPacket(StateRegistry state, int id, BinaryTag nbt) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
this.id = id;
|
||||||
|
this.nbt = nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public StateRegistry state() {
|
||||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
return state;
|
||||||
this.id = this.state == StateRegistry.CONFIG ? 0 : ProtocolUtils.readVarInt(buf);
|
|
||||||
if (this.id == 0) {
|
|
||||||
this.nbt = ProtocolUtils.readBinaryTag(buf, protocolVersion, BinaryTagIO.reader());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int id() {
|
||||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
return id;
|
||||||
if (this.state == StateRegistry.CONFIG) {
|
}
|
||||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
|
||||||
} else {
|
public BinaryTag nbt() {
|
||||||
ProtocolUtils.writeVarInt(buf, this.id);
|
return nbt;
|
||||||
if (this.id == 0) {
|
|
||||||
ProtocolUtils.writeBinaryTag(buf, protocolVersion, this.nbt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.text.Component;
|
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;
|
private final StateRegistry state;
|
||||||
|
|
||||||
public DisconnectPacket(StateRegistry state) {
|
public DisconnectPacket(StateRegistry state, ComponentHolder reason) {
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DisconnectPacket(StateRegistry state, ComponentHolder reason) {
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.reason = Preconditions.checkNotNull(reason, "reason");
|
this.reason = Preconditions.checkNotNull(reason, "reason");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComponentHolder getReason() {
|
public ComponentHolder reason() {
|
||||||
if (reason == null) {
|
if (reason == null) {
|
||||||
throw new IllegalStateException("No reason specified");
|
throw new IllegalStateException("No reason specified");
|
||||||
}
|
}
|
||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReason(@Nullable ComponentHolder reason) {
|
public ComponentHolder getReason() {
|
||||||
this.reason = reason;
|
return reason();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateRegistry state() {
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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");
|
Preconditions.checkNotNull(component, "component");
|
||||||
return new DisconnectPacket(state, new ComponentHolder(state == StateRegistry.LOGIN
|
return new DisconnectPacket(state, new ComponentHolder(state == StateRegistry.LOGIN
|
||||||
? ProtocolVersion.MINECRAFT_1_20_2 : version, component));
|
? 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;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class EncryptionRequestPacket implements MinecraftPacket {
|
public final class EncryptionRequestPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private String serverId = "";
|
private final String serverId;
|
||||||
private byte[] publicKey = EMPTY_BYTE_ARRAY;
|
private final byte[] publicKey;
|
||||||
private byte[] verifyToken = EMPTY_BYTE_ARRAY;
|
private final byte[] verifyToken;
|
||||||
private boolean shouldAuthenticate = true;
|
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();
|
return publicKey.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPublicKey(byte[] publicKey) {
|
public byte[] verifyToken() {
|
||||||
this.publicKey = publicKey.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getVerifyToken() {
|
|
||||||
return verifyToken.clone();
|
return verifyToken.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerifyToken(byte[] verifyToken) {
|
public boolean shouldAuthenticate() {
|
||||||
this.verifyToken = verifyToken.clone();
|
return shouldAuthenticate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPublicKey() {
|
||||||
|
return publicKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getVerifyToken() {
|
||||||
|
return verifyToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class EncryptionResponsePacket implements MinecraftPacket {
|
public final class EncryptionResponsePacket implements MinecraftPacket {
|
||||||
|
|
||||||
private static final QuietDecoderException NO_SALT = new QuietDecoderException(
|
private static final QuietDecoderException NO_SALT = new QuietDecoderException(
|
||||||
"Encryption response didn't contain salt");
|
"Encryption response didn't contain salt");
|
||||||
|
|
||||||
private byte[] sharedSecret = EMPTY_BYTE_ARRAY;
|
private final byte[] sharedSecret;
|
||||||
private byte[] verifyToken = EMPTY_BYTE_ARRAY;
|
private final byte[] verifyToken;
|
||||||
private @Nullable Long salt;
|
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();
|
return sharedSecret.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getVerifyToken() {
|
public byte[] verifyToken() {
|
||||||
return verifyToken.clone();
|
return verifyToken.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSalt() {
|
public long salt() {
|
||||||
if (salt == null) {
|
if (salt == null) {
|
||||||
throw NO_SALT;
|
throw NO_SALT;
|
||||||
}
|
}
|
||||||
return salt;
|
return salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getSharedSecret() {
|
||||||
|
return sharedSecret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getVerifyToken() {
|
||||||
|
return verifyToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSalt() {
|
||||||
|
return salt();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "EncryptionResponse{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<EncryptionResponsePacket> {
|
||||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
|
public EncryptionResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
// The length prefix always winds up being 2 bytes.
|
ProtocolVersion version) {
|
||||||
int base = 256 + 2 + 2;
|
byte[] sharedSecret;
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
byte[] verifyToken;
|
||||||
return base + 128;
|
Long salt = null;
|
||||||
}
|
|
||||||
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
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
sharedSecret = ProtocolUtils.readByteArray(buf, 128);
|
||||||
int base = decodeExpectedMaxLength(buf, direction, version);
|
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)
|
||||||
// These are "optional"
|
&& version.lessThan(ProtocolVersion.MINECRAFT_1_19_3)
|
||||||
base -= 128 + 8;
|
&& !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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
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.
|
// 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.
|
// 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 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() {
|
private final ProtocolVersion protocolVersion;
|
||||||
return 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;
|
this.protocolVersion = protocolVersion;
|
||||||
}
|
|
||||||
|
|
||||||
public String getServerAddress() {
|
|
||||||
return serverAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServerAddress(String serverAddress) {
|
|
||||||
this.serverAddress = serverAddress;
|
this.serverAddress = serverAddress;
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPort(int port) {
|
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
|
||||||
|
|
||||||
public int getNextStatus() {
|
|
||||||
return this.nextStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIntent(HandshakeIntent intent) {
|
|
||||||
this.intent = intent;
|
this.intent = intent;
|
||||||
this.nextStatus = intent.id();
|
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;
|
return this.intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProtocolVersion getProtocolVersion() {
|
||||||
|
return protocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerAddress() {
|
||||||
|
return serverAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return port();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HandshakeIntent getIntent() {
|
||||||
|
return intent();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Handshake{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<HandshakePacket> {
|
||||||
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
@Override
|
||||||
ProtocolVersion version) {
|
public HandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
return 7;
|
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
|
@Override
|
||||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
public void encode(HandshakePacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
ProtocolVersion version) {
|
ProtocolVersion ignored) {
|
||||||
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
|
ProtocolUtils.writeVarInt(buf, packet.protocolVersion.getProtocol());
|
||||||
}
|
ProtocolUtils.writeString(buf, packet.serverAddress);
|
||||||
|
buf.writeShort(packet.port);
|
||||||
|
ProtocolUtils.writeVarInt(buf, packet.nextStatus);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
ProtocolVersion version) {
|
||||||
// sizes of this packet.
|
return 7;
|
||||||
return 4 * 1024;
|
}
|
||||||
|
|
||||||
|
@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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
public class HeaderAndFooterPacket implements MinecraftPacket {
|
public record HeaderAndFooterPacket(ComponentHolder header,
|
||||||
|
ComponentHolder footer) implements MinecraftPacket {
|
||||||
|
|
||||||
private final ComponentHolder header;
|
public HeaderAndFooterPacket {
|
||||||
private final ComponentHolder footer;
|
Preconditions.checkNotNull(header, "header");
|
||||||
|
Preconditions.checkNotNull(footer, "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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,4 +50,19 @@ public class HeaderAndFooterPacket implements MinecraftPacket {
|
|||||||
ComponentHolder empty = new ComponentHolder(version, Component.empty());
|
ComponentHolder empty = new ComponentHolder(version, Component.empty());
|
||||||
return new HeaderAndFooterPacket(empty, 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.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
||||||
import com.velocitypowered.proxy.protocol.*;
|
import com.velocitypowered.proxy.protocol.*;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024);
|
||||||
private int entityId;
|
|
||||||
private short gamemode;
|
private final int entityId;
|
||||||
private int dimension;
|
private final short gamemode;
|
||||||
private long partialHashedSeed; // 1.15+
|
private final int dimension;
|
||||||
private short difficulty;
|
private final long partialHashedSeed;
|
||||||
private boolean isHardcore;
|
private final short difficulty;
|
||||||
private int maxPlayers;
|
private final boolean isHardcore;
|
||||||
private @Nullable String levelType;
|
private final int maxPlayers;
|
||||||
private int viewDistance; // 1.14+
|
private final @Nullable String levelType;
|
||||||
private boolean reducedDebugInfo;
|
private final int viewDistance;
|
||||||
private boolean showRespawnScreen;
|
private final boolean reducedDebugInfo;
|
||||||
private boolean doLimitedCrafting; // 1.20.2+
|
private final boolean showRespawnScreen;
|
||||||
private ImmutableSet<String> levelNames; // 1.16+
|
private final boolean doLimitedCrafting;
|
||||||
private CompoundBinaryTag registry; // 1.16+
|
private final ImmutableSet<String> levelNames;
|
||||||
private DimensionInfo dimensionInfo; // 1.16+
|
private final CompoundBinaryTag registry;
|
||||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
private final DimensionInfo dimensionInfo;
|
||||||
private short previousGamemode; // 1.16+
|
private final CompoundBinaryTag currentDimensionData;
|
||||||
private int simulationDistance; // 1.18+
|
private final short previousGamemode;
|
||||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
private final int simulationDistance;
|
||||||
private int portalCooldown; // 1.20+
|
private final @Nullable Pair<String, Long> lastDeathPosition;
|
||||||
private int seaLevel; // 1.21.2+
|
private final int portalCooldown;
|
||||||
private boolean enforcesSecureChat; // 1.20.5+
|
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() {
|
public int getEntityId() {
|
||||||
return entityId;
|
return entityId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEntityId(int entityId) {
|
|
||||||
this.entityId = entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getGamemode() {
|
public short getGamemode() {
|
||||||
return gamemode;
|
return gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGamemode(short gamemode) {
|
|
||||||
this.gamemode = gamemode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDimension() {
|
public int getDimension() {
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDimension(int dimension) {
|
|
||||||
this.dimension = dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPartialHashedSeed() {
|
public long getPartialHashedSeed() {
|
||||||
return partialHashedSeed;
|
return partialHashedSeed;
|
||||||
}
|
}
|
||||||
@@ -86,74 +107,38 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
return difficulty;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDifficulty(short difficulty) {
|
|
||||||
this.difficulty = difficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxPlayers() {
|
public int getMaxPlayers() {
|
||||||
return maxPlayers;
|
return maxPlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxPlayers(int maxPlayers) {
|
|
||||||
this.maxPlayers = maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable String getLevelType() {
|
public @Nullable String getLevelType() {
|
||||||
return levelType;
|
return levelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLevelType(@Nullable String levelType) {
|
|
||||||
this.levelType = levelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getViewDistance() {
|
public int getViewDistance() {
|
||||||
return viewDistance;
|
return viewDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setViewDistance(int viewDistance) {
|
|
||||||
this.viewDistance = viewDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReducedDebugInfo() {
|
public boolean isReducedDebugInfo() {
|
||||||
return reducedDebugInfo;
|
return reducedDebugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReducedDebugInfo(boolean reducedDebugInfo) {
|
|
||||||
this.reducedDebugInfo = reducedDebugInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DimensionInfo getDimensionInfo() {
|
public DimensionInfo getDimensionInfo() {
|
||||||
return dimensionInfo;
|
return dimensionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDimensionInfo(DimensionInfo dimensionInfo) {
|
|
||||||
this.dimensionInfo = dimensionInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPreviousGamemode() {
|
public short getPreviousGamemode() {
|
||||||
return previousGamemode;
|
return previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousGamemode(short previousGamemode) {
|
|
||||||
this.previousGamemode = previousGamemode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getIsHardcore() {
|
public boolean getIsHardcore() {
|
||||||
return isHardcore;
|
return isHardcore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsHardcore(boolean isHardcore) {
|
|
||||||
this.isHardcore = isHardcore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getDoLimitedCrafting() {
|
public boolean getDoLimitedCrafting() {
|
||||||
return doLimitedCrafting;
|
return doLimitedCrafting;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDoLimitedCrafting(boolean doLimitedCrafting) {
|
|
||||||
this.doLimitedCrafting = doLimitedCrafting;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompoundBinaryTag getCurrentDimensionData() {
|
public CompoundBinaryTag getCurrentDimensionData() {
|
||||||
return currentDimensionData;
|
return currentDimensionData;
|
||||||
}
|
}
|
||||||
@@ -162,46 +147,34 @@ public class JoinGamePacket implements MinecraftPacket {
|
|||||||
return simulationDistance;
|
return simulationDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSimulationDistance(int simulationDistance) {
|
|
||||||
this.simulationDistance = simulationDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pair<String, Long> getLastDeathPosition() {
|
public Pair<String, Long> getLastDeathPosition() {
|
||||||
return lastDeathPosition;
|
return lastDeathPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastDeathPosition(Pair<String, Long> lastDeathPosition) {
|
|
||||||
this.lastDeathPosition = lastDeathPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPortalCooldown() {
|
public int getPortalCooldown() {
|
||||||
return portalCooldown;
|
return portalCooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPortalCooldown(int portalCooldown) {
|
|
||||||
this.portalCooldown = portalCooldown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSeaLevel() {
|
public int getSeaLevel() {
|
||||||
return seaLevel;
|
return seaLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSeaLevel(int seaLevel) {
|
|
||||||
this.seaLevel = seaLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getEnforcesSecureChat() {
|
public boolean getEnforcesSecureChat() {
|
||||||
return this.enforcesSecureChat;
|
return this.enforcesSecureChat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnforcesSecureChat(final boolean enforcesSecureChat) {
|
|
||||||
this.enforcesSecureChat = enforcesSecureChat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompoundBinaryTag getRegistry() {
|
public CompoundBinaryTag getRegistry() {
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getShowRespawnScreen() {
|
||||||
|
return showRespawnScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableSet<String> getLevelNames() {
|
||||||
|
return levelNames;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" +
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class KeepAlivePacket implements MinecraftPacket {
|
public record KeepAlivePacket(long randomId) implements MinecraftPacket {
|
||||||
|
|
||||||
private long randomId;
|
|
||||||
|
|
||||||
public long getRandomId() {
|
public long getRandomId() {
|
||||||
return randomId;
|
return randomId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRandomId(long randomId) {
|
|
||||||
this.randomId = randomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "KeepAlive{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class LegacyHandshakePacket implements MinecraftPacket {
|
public final class LegacyHandshakePacket implements MinecraftPacket {
|
||||||
|
|
||||||
@Override
|
public static final LegacyHandshakePacket INSTANCE = new LegacyHandshakePacket();
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private LegacyHandshakePacket() {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.legacyping.LegacyMinecraftPingVersion;
|
import com.velocitypowered.proxy.protocol.packet.legacyping.LegacyMinecraftPingVersion;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class LegacyPingPacket implements MinecraftPacket {
|
public final class LegacyPingPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private final LegacyMinecraftPingVersion version;
|
private final LegacyMinecraftPingVersion version;
|
||||||
private final @Nullable InetSocketAddress vhost;
|
private final @Nullable InetSocketAddress vhost;
|
||||||
@@ -41,26 +42,38 @@ public class LegacyPingPacket implements MinecraftPacket {
|
|||||||
this.vhost = vhost;
|
this.vhost = vhost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LegacyMinecraftPingVersion getVersion() {
|
public LegacyMinecraftPingVersion version() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable InetSocketAddress getVhost() {
|
public @Nullable InetSocketAddress vhost() {
|
||||||
return vhost;
|
return vhost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public LegacyMinecraftPingVersion getVersion() {
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
return version();
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public @Nullable InetSocketAddress getVhost() {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
return vhost();
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.util.GameProfile;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -33,22 +34,20 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 ADD_PLAYER = 0;
|
||||||
public static final int UPDATE_GAMEMODE = 1;
|
public static final int UPDATE_GAMEMODE = 1;
|
||||||
public static final int UPDATE_LATENCY = 2;
|
public static final int UPDATE_LATENCY = 2;
|
||||||
public static final int UPDATE_DISPLAY_NAME = 3;
|
public static final int UPDATE_DISPLAY_NAME = 3;
|
||||||
public static final int REMOVE_PLAYER = 4;
|
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) {
|
public LegacyPlayerListItemPacket(int action, List<Item> items) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.items.addAll(items);
|
this.items = ImmutableList.copyOf(items);
|
||||||
}
|
|
||||||
|
|
||||||
public LegacyPlayerListItemPacket() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAction() {
|
public int getAction() {
|
||||||
@@ -59,131 +58,137 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket {
|
|||||||
return items;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeDisplayName(ByteBuf buf, @Nullable Component displayName,
|
public static class Codec implements PacketCodec<LegacyPlayerListItemPacket> {
|
||||||
ProtocolVersion version) {
|
@Override
|
||||||
buf.writeBoolean(displayName != null);
|
public LegacyPlayerListItemPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
if (displayName != null) {
|
ProtocolVersion version) {
|
||||||
ProtocolUtils.writeString(buf, ProtocolUtils.getJsonChatSerializer(version)
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||||
.serialize(displayName));
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class LoginAcknowledgedPacket implements MinecraftPacket {
|
public final class LoginAcknowledgedPacket implements MinecraftPacket {
|
||||||
|
|
||||||
@Override
|
public static final LoginAcknowledgedPacket INSTANCE = new LoginAcknowledgedPacket();
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
|
||||||
ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private LoginAcknowledgedPacket() {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
|
|
||||||
ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
|
|
||||||
ProtocolVersion version) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.DefaultByteBufHolder;
|
||||||
import io.netty.buffer.Unpooled;
|
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 final int id;
|
||||||
private @Nullable String channel;
|
private final String channel;
|
||||||
|
|
||||||
public LoginPluginMessagePacket() {
|
public LoginPluginMessagePacket(int id, String channel, ByteBuf data) {
|
||||||
super(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoginPluginMessagePacket(int id, @Nullable String channel, ByteBuf data) {
|
|
||||||
super(data);
|
super(data);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
@@ -47,9 +43,6 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getChannel() {
|
public String getChannel() {
|
||||||
if (channel == null) {
|
|
||||||
throw new IllegalStateException("Channel is not specified!");
|
|
||||||
}
|
|
||||||
return channel;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<LoginPluginMessagePacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
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.ByteBuf;
|
||||||
|
import io.netty.buffer.DefaultByteBufHolder;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
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 final int id;
|
||||||
private boolean success;
|
private final boolean success;
|
||||||
|
|
||||||
public LoginPluginResponsePacket() {
|
|
||||||
super(Unpooled.EMPTY_BUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoginPluginResponsePacket(int id, boolean success, @MonotonicNonNull ByteBuf buf) {
|
public LoginPluginResponsePacket(int id, boolean success, @MonotonicNonNull ByteBuf buf) {
|
||||||
super(buf);
|
super(buf);
|
||||||
@@ -42,20 +39,20 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements
|
|||||||
this.success = success;
|
this.success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int id() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(int id) {
|
public boolean success() {
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccess() {
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSuccess(boolean success) {
|
public int getId() {
|
||||||
this.success = success;
|
return id();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<LoginPluginResponsePacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class PingIdentifyPacket implements MinecraftPacket {
|
public record PingIdentifyPacket(int id) 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
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.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import io.netty.buffer.DefaultByteBufHolder;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
||||||
|
|
||||||
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() {
|
public PluginMessagePacket(String channel, ByteBuf backing) {
|
||||||
super(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginMessagePacket(String channel,
|
|
||||||
@MonotonicNonNull ByteBuf backing) {
|
|
||||||
super(backing);
|
super(backing);
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getChannel() {
|
public String getChannel() {
|
||||||
if (channel == null) {
|
|
||||||
throw new IllegalStateException("Channel is not specified.");
|
|
||||||
}
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChannel(String channel) {
|
|
||||||
this.channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PluginMessage{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
@@ -145,8 +93,41 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr
|
|||||||
return (PluginMessagePacket) super.touch(hint);
|
return (PluginMessagePacket) super.touch(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<PluginMessagePacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class RemovePlayerInfoPacket implements MinecraftPacket {
|
public record RemovePlayerInfoPacket(Collection<UUID> profilesToRemove) implements MinecraftPacket {
|
||||||
|
|
||||||
private Collection<UUID> profilesToRemove;
|
|
||||||
|
|
||||||
public RemovePlayerInfoPacket() {
|
|
||||||
this.profilesToRemove = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemovePlayerInfoPacket(Collection<UUID> profilesToRemove) {
|
|
||||||
this.profilesToRemove = profilesToRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<UUID> getProfilesToRemove() {
|
public Collection<UUID> getProfilesToRemove() {
|
||||||
return profilesToRemove;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.UUID;
|
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 @Nullable UUID getId() {
|
||||||
|
|
||||||
public RemoveResourcePackPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemoveResourcePackPacket(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
|
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
@@ -30,100 +31,47 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 final @Nullable UUID id; // 1.20.3+
|
||||||
private @MonotonicNonNull String url;
|
private final String url;
|
||||||
private @MonotonicNonNull String hash;
|
private final String hash;
|
||||||
private boolean isRequired; // 1.17+
|
private final boolean isRequired; // 1.17+
|
||||||
private @Nullable ComponentHolder prompt; // 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+
|
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() {
|
public @Nullable UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(UUID id) {
|
public String getUrl() {
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable String getUrl() {
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRequired() {
|
public boolean isRequired() {
|
||||||
return isRequired;
|
return isRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getHash() {
|
public String getHash() {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHash(String hash) {
|
|
||||||
this.hash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRequired(boolean required) {
|
|
||||||
isRequired = required;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable ComponentHolder getPrompt() {
|
public @Nullable ComponentHolder getPrompt() {
|
||||||
return prompt;
|
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() {
|
public VelocityResourcePackInfo toServerPromptedPack() {
|
||||||
final ResourcePackInfo.Builder builder =
|
final ResourcePackInfo.Builder builder =
|
||||||
new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url))
|
new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url))
|
||||||
@@ -153,4 +101,51 @@ public class ResourcePackRequestPacket implements MinecraftPacket {
|
|||||||
", prompt=" + prompt +
|
", 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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ResourcePackResponsePacket implements MinecraftPacket {
|
public record ResourcePackResponsePacket(UUID id, String hash,
|
||||||
|
Status status) implements MinecraftPacket {
|
||||||
|
|
||||||
private UUID id;
|
public UUID getId() {
|
||||||
private String hash = "";
|
return id;
|
||||||
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 String getHash() {
|
public String getHash() {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getId() {
|
public Status getStatus() {
|
||||||
return id;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,12 +48,32 @@ public class ResourcePackResponsePacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<ResourcePackResponsePacket> {
|
||||||
public String toString() {
|
@Override
|
||||||
return "ResourcePackResponsePacket{" +
|
public ResourcePackResponsePacket decode(ByteBuf buf, Direction direction,
|
||||||
"id=" + id +
|
ProtocolVersion protocolVersion) {
|
||||||
", hash='" + hash + '\'' +
|
UUID id = null;
|
||||||
", status=" + status +
|
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.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import it.unimi.dsi.fastutil.Pair;
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
@@ -28,23 +29,20 @@ import net.kyori.adventure.nbt.BinaryTagIO;
|
|||||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class RespawnPacket implements MinecraftPacket {
|
public final class RespawnPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private int dimension;
|
private final int dimension;
|
||||||
private long partialHashedSeed;
|
private final long partialHashedSeed;
|
||||||
private short difficulty;
|
private final short difficulty;
|
||||||
private short gamemode;
|
private final short gamemode;
|
||||||
private String levelType = "";
|
private final String levelType;
|
||||||
private byte dataToKeep; // 1.16+
|
private final byte dataToKeep;
|
||||||
private DimensionInfo dimensionInfo; // 1.16-1.16.1
|
private final DimensionInfo dimensionInfo;
|
||||||
private short previousGamemode; // 1.16+
|
private final short previousGamemode;
|
||||||
private CompoundBinaryTag currentDimensionData; // 1.16.2+
|
private final CompoundBinaryTag currentDimensionData;
|
||||||
private @Nullable Pair<String, Long> lastDeathPosition; // 1.19+
|
private final @Nullable Pair<String, Long> lastDeathPosition;
|
||||||
private int portalCooldown; // 1.20+
|
private final int portalCooldown;
|
||||||
private int seaLevel; // 1.21.2+
|
private final int seaLevel;
|
||||||
|
|
||||||
public RespawnPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode,
|
public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode,
|
||||||
String levelType, byte dataToKeep, DimensionInfo dimensionInfo,
|
String levelType, byte dataToKeep, DimensionInfo dimensionInfo,
|
||||||
@@ -73,84 +71,60 @@ public class RespawnPacket implements MinecraftPacket {
|
|||||||
joinGame.getPortalCooldown(), joinGame.getSeaLevel());
|
joinGame.getPortalCooldown(), joinGame.getSeaLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDimension() {
|
public static RespawnPacket fromJoinGame(JoinGamePacket joinGame, int newDimension) {
|
||||||
return dimension;
|
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) {
|
public int getDimension() {
|
||||||
this.dimension = dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getPartialHashedSeed() {
|
public long getPartialHashedSeed() {
|
||||||
return partialHashedSeed;
|
return partialHashedSeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPartialHashedSeed(long partialHashedSeed) {
|
|
||||||
this.partialHashedSeed = partialHashedSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getDifficulty() {
|
public short getDifficulty() {
|
||||||
return difficulty;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDifficulty(short difficulty) {
|
|
||||||
this.difficulty = difficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getGamemode() {
|
public short getGamemode() {
|
||||||
return gamemode;
|
return gamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGamemode(short gamemode) {
|
|
||||||
this.gamemode = gamemode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLevelType() {
|
public String getLevelType() {
|
||||||
return levelType;
|
return levelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLevelType(String levelType) {
|
|
||||||
this.levelType = levelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getDataToKeep() {
|
public byte getDataToKeep() {
|
||||||
return dataToKeep;
|
return dataToKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDataToKeep(byte dataToKeep) {
|
|
||||||
this.dataToKeep = dataToKeep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getPreviousGamemode() {
|
public short getPreviousGamemode() {
|
||||||
return previousGamemode;
|
return previousGamemode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPreviousGamemode(short previousGamemode) {
|
|
||||||
this.previousGamemode = previousGamemode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pair<String, Long> getLastDeathPosition() {
|
public Pair<String, Long> getLastDeathPosition() {
|
||||||
return lastDeathPosition;
|
return lastDeathPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastDeathPosition(Pair<String, Long> lastDeathPosition) {
|
|
||||||
this.lastDeathPosition = lastDeathPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPortalCooldown() {
|
public int getPortalCooldown() {
|
||||||
return portalCooldown;
|
return portalCooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPortalCooldown(int portalCooldown) {
|
|
||||||
this.portalCooldown = portalCooldown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSeaLevel() {
|
public int getSeaLevel() {
|
||||||
return seaLevel;
|
return seaLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSeaLevel(int seaLevel) {
|
public DimensionInfo getDimensionInfo() {
|
||||||
this.seaLevel = seaLevel;
|
return dimensionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundBinaryTag getCurrentDimensionData() {
|
||||||
|
return currentDimensionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.util.Favicon;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
@@ -29,14 +30,11 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
public class ServerDataPacket implements MinecraftPacket {
|
public final class ServerDataPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private @Nullable ComponentHolder description;
|
private final @Nullable ComponentHolder description;
|
||||||
private @Nullable Favicon favicon;
|
private final @Nullable Favicon favicon;
|
||||||
private boolean secureChatEnforced; // Added in 1.19.1 - Removed in 1.20.5
|
private final boolean secureChatEnforced; // Added in 1.19.1 - Removed in 1.20.5
|
||||||
|
|
||||||
public ServerDataPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerDataPacket(@Nullable ComponentHolder description, @Nullable Favicon favicon,
|
public ServerDataPacket(@Nullable ComponentHolder description, @Nullable Favicon favicon,
|
||||||
boolean secureChatEnforced) {
|
boolean secureChatEnforced) {
|
||||||
@@ -45,63 +43,6 @@ public class ServerDataPacket implements MinecraftPacket {
|
|||||||
this.secureChatEnforced = secureChatEnforced;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
@@ -119,12 +60,68 @@ public class ServerDataPacket implements MinecraftPacket {
|
|||||||
return secureChatEnforced;
|
return secureChatEnforced;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecureChatEnforced(boolean secureChatEnforced) {
|
public static class Codec implements PacketCodec<ServerDataPacket> {
|
||||||
this.secureChatEnforced = secureChatEnforced;
|
@Override
|
||||||
}
|
public ServerDataPacket decode(ByteBuf buf, Direction direction,
|
||||||
|
ProtocolVersion protocolVersion) {
|
||||||
|
ComponentHolder description = null;
|
||||||
|
Favicon favicon = null;
|
||||||
|
boolean secureChatEnforced = false;
|
||||||
|
|
||||||
@Override
|
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_19_4) || buf.readBoolean()) {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
description = ComponentHolder.read(buf, protocolVersion);
|
||||||
return 8 * 1024;
|
}
|
||||||
|
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;
|
package com.velocitypowered.proxy.protocol.packet;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.crypto.IdentifiedKey;
|
import com.velocitypowered.api.proxy.crypto.IdentifiedKey;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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(
|
private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException(
|
||||||
"Empty username!");
|
"Empty username!");
|
||||||
|
|
||||||
private @Nullable String username;
|
private final String username;
|
||||||
private @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3
|
private final @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3
|
||||||
private @Nullable UUID holderUuid; // Used for key revision 2
|
private final @Nullable UUID holderUuid; // Used for key revision 2
|
||||||
|
|
||||||
public ServerLoginPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey) {
|
public ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey) {
|
||||||
this.username = Preconditions.checkNotNull(username, "username");
|
this(username, playerKey, null);
|
||||||
this.playerKey = playerKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerLoginPacket(String username, @Nullable UUID holderUuid) {
|
public ServerLoginPacket(String username, @Nullable UUID holderUuid) {
|
||||||
this.username = Preconditions.checkNotNull(username, "username");
|
this(username, null, holderUuid);
|
||||||
this.holderUuid = holderUuid;
|
|
||||||
this.playerKey = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUsername() {
|
private ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey,
|
||||||
if (username == null) {
|
@Nullable UUID holderUuid) {
|
||||||
throw new IllegalStateException("No username found!");
|
this.username = username;
|
||||||
}
|
this.playerKey = playerKey;
|
||||||
|
this.holderUuid = holderUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String username() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable IdentifiedKey getPlayerKey() {
|
public String getUsername() {
|
||||||
|
return username();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable IdentifiedKey playerKey() {
|
||||||
return this.playerKey;
|
return this.playerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayerKey(IdentifiedKey playerKey) {
|
public @Nullable UUID holderUuid() {
|
||||||
this.playerKey = playerKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable UUID getHolderUuid() {
|
|
||||||
return holderUuid;
|
return holderUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ServerLogin{"
|
return "ServerLogin{"
|
||||||
+ "username='" + username + '\''
|
+ "username='" + username + '\''
|
||||||
+ "playerKey='" + playerKey + '\''
|
+ "playerKey='" + playerKey + '\''
|
||||||
+ "holderUUID='" + holderUuid + '\''
|
+ "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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.util.UuidUtils;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.util.VelocityProperties;
|
import com.velocitypowered.proxy.util.VelocityProperties;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
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 final UUID uuid;
|
||||||
private @Nullable String username;
|
private final String username;
|
||||||
private @Nullable List<GameProfile.Property> properties;
|
private final List<GameProfile.Property> properties;
|
||||||
private static final boolean strictErrorHandling = VelocityProperties
|
private static final boolean strictErrorHandling = VelocityProperties
|
||||||
.readBoolean("velocity.strictErrorHandling", true);
|
.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() {
|
public UUID getUuid() {
|
||||||
if (uuid == null) {
|
|
||||||
throw new IllegalStateException("No UUID specified!");
|
|
||||||
}
|
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUuid(UUID uuid) {
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
if (username == null) {
|
|
||||||
throw new IllegalStateException("No username specified!");
|
|
||||||
}
|
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<GameProfile.Property> getProperties() {
|
public List<GameProfile.Property> getProperties() {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperties(List<GameProfile.Property> properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ServerLoginSuccess{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<ServerLoginSuccessPacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
// We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
|
public ServerLoginSuccessPacket decode(ByteBuf buf, Direction direction,
|
||||||
// sizes of this packet.
|
ProtocolVersion version) {
|
||||||
return 4 * 1024;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class ServerboundCookieResponsePacket implements MinecraftPacket {
|
public record ServerboundCookieResponsePacket(Key key,
|
||||||
|
byte @Nullable [] payload) implements MinecraftPacket {
|
||||||
private Key key;
|
|
||||||
private byte @Nullable [] payload;
|
|
||||||
|
|
||||||
public Key getKey() {
|
public Key getKey() {
|
||||||
return key;
|
return key;
|
||||||
@@ -39,34 +38,32 @@ public class ServerboundCookieResponsePacket implements MinecraftPacket {
|
|||||||
return payload;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public ServerboundCustomClickActionPacket(ByteBuf backing) {
|
||||||
super(null);
|
super(backing);
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,7 +39,61 @@ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder im
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
public ServerboundCustomClickActionPacket copy() {
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class SetCompressionPacket implements MinecraftPacket {
|
public record SetCompressionPacket(int threshold) implements MinecraftPacket {
|
||||||
|
|
||||||
private int threshold;
|
|
||||||
|
|
||||||
public SetCompressionPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public SetCompressionPacket(int threshold) {
|
|
||||||
this.threshold = threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getThreshold() {
|
public int getThreshold() {
|
||||||
return threshold;
|
return threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThreshold(int threshold) {
|
|
||||||
this.threshold = threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SetCompression{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class StatusPingPacket implements MinecraftPacket {
|
public record StatusPingPacket(long randomId) 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<StatusPingPacket> {
|
||||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return 8;
|
public StatusPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
}
|
ProtocolVersion protocolVersion) {
|
||||||
|
return new StatusPingPacket(buf.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
public void encode(StatusPingPacket packet, ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
return 8;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
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 com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class StatusRequestPacket implements MinecraftPacket {
|
public final class StatusRequestPacket implements MinecraftPacket {
|
||||||
|
|
||||||
public static final StatusRequestPacket INSTANCE = new StatusRequestPacket();
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "StatusRequest";
|
return "StatusRequest";
|
||||||
@@ -52,8 +42,22 @@ public class StatusRequestPacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<StatusRequestPacket> {
|
||||||
public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return 0;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class StatusResponsePacket implements MinecraftPacket {
|
public final class StatusResponsePacket implements MinecraftPacket {
|
||||||
|
|
||||||
private @Nullable CharSequence status;
|
private final @Nullable CharSequence status;
|
||||||
|
|
||||||
public StatusResponsePacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusResponsePacket(CharSequence status) {
|
public StatusResponsePacket(CharSequence status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStatus() {
|
public String status() {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
throw new IllegalStateException("Status is not specified");
|
throw new IllegalStateException("Status is not specified");
|
||||||
}
|
}
|
||||||
return status.toString();
|
return status.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "StatusResponse{"
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<StatusResponsePacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
return ProtocolUtils.stringSizeHint(this.status);
|
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_8;
|
||||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 static final int VANILLA_MAX_TAB_COMPLETE_LEN = 2048;
|
||||||
|
|
||||||
private @Nullable String command;
|
private final @Nullable String command;
|
||||||
private int transactionId;
|
private final int transactionId;
|
||||||
private boolean assumeCommand;
|
private final boolean assumeCommand;
|
||||||
private boolean hasPosition;
|
private final boolean hasPosition;
|
||||||
private long position;
|
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) {
|
if (command == null) {
|
||||||
throw new IllegalStateException("Command is not specified");
|
throw new IllegalStateException("Command is not specified");
|
||||||
}
|
}
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCommand(String command) {
|
public String getCommand() {
|
||||||
this.command = command;
|
return command();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAssumeCommand() {
|
public boolean assumeCommand() {
|
||||||
return assumeCommand;
|
return assumeCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAssumeCommand(boolean assumeCommand) {
|
public boolean isAssumeCommand() {
|
||||||
this.assumeCommand = assumeCommand;
|
return assumeCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPosition() {
|
public boolean hasPosition() {
|
||||||
return hasPosition;
|
return hasPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHasPosition(boolean hasPosition) {
|
public long position() {
|
||||||
this.hasPosition = hasPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getPosition() {
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(long position) {
|
public int transactionId() {
|
||||||
this.position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTransactionId() {
|
|
||||||
return 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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@@ -30,39 +31,54 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class TabCompleteResponsePacket implements MinecraftPacket {
|
public final class TabCompleteResponsePacket implements MinecraftPacket {
|
||||||
|
|
||||||
private int transactionId;
|
private final int transactionId;
|
||||||
private int start;
|
private final int start;
|
||||||
private int length;
|
private final int length;
|
||||||
private final List<Offer> offers = new ArrayList<>();
|
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;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTransactionId(int transactionId) {
|
public int start() {
|
||||||
this.transactionId = transactionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStart() {
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStart(int start) {
|
public int length() {
|
||||||
this.start = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLength() {
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLength(int length) {
|
public List<Offer> offers() {
|
||||||
this.length = length;
|
return offers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTransactionId() {
|
||||||
|
return transactionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStart() {
|
||||||
|
return start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return length();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Offer> getOffers() {
|
public List<Offer> getOffers() {
|
||||||
return offers;
|
return offers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabCompleteResponsePacket withOffers(List<Offer> offers) {
|
||||||
|
return new TabCompleteResponsePacket(transactionId, start, length, offers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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> {
|
public static class Offer implements Comparable<Offer> {
|
||||||
|
|
||||||
private final String text;
|
private final String text;
|
||||||
|
|||||||
@@ -20,22 +20,13 @@ package com.velocitypowered.proxy.protocol.packet;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class TransferPacket implements MinecraftPacket {
|
public record TransferPacket(String host, int port) implements MinecraftPacket {
|
||||||
private String host;
|
|
||||||
private int port;
|
|
||||||
|
|
||||||
public TransferPacket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransferPacket(final String host, final int port) {
|
|
||||||
this.host = host;
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public InetSocketAddress address() {
|
public InetSocketAddress address() {
|
||||||
@@ -45,20 +36,31 @@ public class TransferPacket implements MinecraftPacket {
|
|||||||
return new InetSocketAddress(host, port);
|
return new InetSocketAddress(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public String getHost() {
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
return host;
|
||||||
this.host = ProtocolUtils.readString(buf);
|
|
||||||
this.port = ProtocolUtils.readVarInt(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int getPort() {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
return port;
|
||||||
ProtocolUtils.writeString(buf, host);
|
|
||||||
ProtocolUtils.writeVarInt(buf, port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.util.GameProfile;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.RemoteChatSession;
|
import com.velocitypowered.proxy.protocol.packet.chat.RemoteChatSession;
|
||||||
@@ -28,29 +29,18 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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 static final Action[] ALL_ACTIONS = Action.class.getEnumConstants();
|
||||||
|
|
||||||
private final EnumSet<Action> actions;
|
private final EnumSet<Action> actions;
|
||||||
private final List<Entry> entries;
|
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) {
|
public UpsertPlayerInfoPacket(EnumSet<Action> actions, List<Entry> entries) {
|
||||||
this.actions = actions;
|
this.actions = actions;
|
||||||
this.entries = entries;
|
this.entries = entries;
|
||||||
@@ -68,71 +58,60 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
|
|||||||
return this.actions.contains(action);
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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 {
|
public enum Action {
|
||||||
ADD_PLAYER((ignored, buf, info) -> { // read
|
ADD_PLAYER((ignored, buf, info) -> { // read
|
||||||
info.profile = new GameProfile(
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class ChatAcknowledgementPacket implements MinecraftPacket {
|
public record ChatAcknowledgementPacket(int offset) implements MinecraftPacket {
|
||||||
int offset;
|
|
||||||
|
|
||||||
public ChatAcknowledgementPacket(int offset) {
|
@Override
|
||||||
this.offset = offset;
|
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
|
@Override
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
public void encode(ChatAcknowledgementPacket packet, ByteBuf buf,
|
||||||
offset = ProtocolUtils.readVarInt(buf);
|
ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||||
}
|
ProtocolUtils.writeVarInt(buf, packet.offset);
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,17 @@ package com.velocitypowered.proxy.protocol.packet.chat;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class PlayerChatCompletionPacket implements MinecraftPacket {
|
public final class PlayerChatCompletionPacket implements MinecraftPacket {
|
||||||
|
|
||||||
private String[] completions;
|
private final String[] completions;
|
||||||
private Action action;
|
private final Action action;
|
||||||
|
|
||||||
public PlayerChatCompletionPacket() {
|
public PlayerChatCompletionPacket() {
|
||||||
|
this(new String[0], Action.ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerChatCompletionPacket(String[] completions, Action action) {
|
public PlayerChatCompletionPacket(String[] completions, Action action) {
|
||||||
@@ -36,36 +38,14 @@ public class PlayerChatCompletionPacket implements MinecraftPacket {
|
|||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getCompletions() {
|
public String[] completions() {
|
||||||
return completions;
|
return completions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action getAction() {
|
public Action action() {
|
||||||
return 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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
@@ -76,4 +56,21 @@ public class PlayerChatCompletionPacket implements MinecraftPacket {
|
|||||||
REMOVE,
|
REMOVE,
|
||||||
SET
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public SystemChatPacket() {
|
||||||
|
this(null, ChatType.SYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SystemChatPacket(ComponentHolder component, ChatType type) {
|
public SystemChatPacket(ComponentHolder component, ChatType type) {
|
||||||
@@ -33,48 +38,59 @@ public class SystemChatPacket implements MinecraftPacket {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComponentHolder component;
|
public ChatType type() {
|
||||||
private ChatType type;
|
|
||||||
|
|
||||||
public ChatType getType() {
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComponentHolder getComponent() {
|
public ComponentHolder component() {
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public ComponentHolder getComponent() {
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
return component();
|
||||||
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)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public ChatType getType() {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
return type();
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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;
|
package com.velocitypowered.proxy.protocol.packet.chat.keyed;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatType;
|
import com.velocitypowered.proxy.protocol.packet.chat.ChatType;
|
||||||
@@ -42,12 +41,13 @@ public class KeyedChatBuilder extends ChatBuilderV2 {
|
|||||||
@Override
|
@Override
|
||||||
public MinecraftPacket toServer() {
|
public MinecraftPacket toServer() {
|
||||||
if (message.startsWith("/")) {
|
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 {
|
} else {
|
||||||
// This will produce an error on the server, but needs to be here.
|
// This will produce an error on the server, but needs to be here.
|
||||||
KeyedPlayerChatPacket v1Chat = new KeyedPlayerChatPacket(message);
|
return new KeyedPlayerChatPacket(message, false, false, timestamp, null, null,
|
||||||
v1Chat.setExpiry(this.timestamp);
|
new com.velocitypowered.proxy.crypto.SignaturePair[0], null);
|
||||||
return v1Chat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,41 +23,43 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
|||||||
import com.velocitypowered.proxy.crypto.EncryptionUtils;
|
import com.velocitypowered.proxy.crypto.EncryptionUtils;
|
||||||
import com.velocitypowered.proxy.crypto.SignaturePair;
|
import com.velocitypowered.proxy.crypto.SignaturePair;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class KeyedPlayerChatPacket implements MinecraftPacket {
|
public final 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 static final int MAXIMUM_PREVIOUS_MESSAGE_COUNT = 5;
|
public static final int MAXIMUM_PREVIOUS_MESSAGE_COUNT = 5;
|
||||||
|
|
||||||
public static final QuietDecoderException INVALID_PREVIOUS_MESSAGES =
|
public static final QuietDecoderException INVALID_PREVIOUS_MESSAGES =
|
||||||
new 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.message = message;
|
||||||
this.unsigned = true;
|
this.signedPreview = signedPreview;
|
||||||
}
|
this.unsigned = unsigned;
|
||||||
|
|
||||||
public void setExpiry(@Nullable Instant expiry) {
|
|
||||||
this.expiry = expiry;
|
this.expiry = expiry;
|
||||||
|
this.signature = signature;
|
||||||
|
this.salt = salt;
|
||||||
|
this.previousMessages = previousMessages;
|
||||||
|
this.lastMessage = lastMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant getExpiry() {
|
public @Nullable Instant getExpiry() {
|
||||||
return expiry;
|
return expiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,82 +75,96 @@ public class KeyedPlayerChatPacket implements MinecraftPacket {
|
|||||||
return signedPreview;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.EncryptionUtils;
|
||||||
import com.velocitypowered.proxy.crypto.SignaturePair;
|
import com.velocitypowered.proxy.crypto.SignaturePair;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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_NUM_ARGUMENTS = 8;
|
||||||
private static final int MAX_LENGTH_ARGUMENTS = 16;
|
private static final int MAX_LENGTH_ARGUMENTS = 16;
|
||||||
private static final QuietDecoderException LIMITS_VIOLATION =
|
private static final QuietDecoderException LIMITS_VIOLATION =
|
||||||
new QuietDecoderException("Command arguments incorrect size");
|
new QuietDecoderException("Command arguments incorrect size");
|
||||||
|
|
||||||
private boolean unsigned = false;
|
private final boolean unsigned;
|
||||||
private String command;
|
private final String command;
|
||||||
private Instant timestamp;
|
private final Instant timestamp;
|
||||||
private long salt;
|
private final long salt;
|
||||||
private boolean signedPreview; // purely for pass through for 1.19 -> 1.19.2 - this will never be implemented
|
private final boolean signedPreview;
|
||||||
private SignaturePair[] previousMessages = new SignaturePair[0];
|
private final SignaturePair[] previousMessages;
|
||||||
private @Nullable SignaturePair lastMessage;
|
private final @Nullable SignaturePair lastMessage;
|
||||||
private Map<String, byte[]> arguments = ImmutableMap.of();
|
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() {
|
public Instant getTimestamp() {
|
||||||
return timestamp;
|
return timestamp;
|
||||||
@@ -63,116 +76,6 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
|||||||
return command;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PlayerCommand{"
|
return "PlayerCommand{"
|
||||||
@@ -190,4 +93,100 @@ public class KeyedPlayerCommandPacket implements MinecraftPacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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
|
@Override
|
||||||
public MinecraftPacket toServer() {
|
public MinecraftPacket toServer() {
|
||||||
LegacyChatPacket chat = new LegacyChatPacket();
|
return new LegacyChatPacket(message, (byte) 0, null);
|
||||||
chat.setMessage(message);
|
|
||||||
return chat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ package com.velocitypowered.proxy.protocol.packet.chat.legacy;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
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 CHAT_TYPE = (byte) 0;
|
||||||
public static final byte SYSTEM_TYPE = (byte) 1;
|
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 int MAX_SERVERBOUND_MESSAGE_LENGTH = 256;
|
||||||
public static final UUID EMPTY_SENDER = new UUID(0, 0);
|
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() {
|
public String getMessage() {
|
||||||
if (message == null) {
|
|
||||||
throw new IllegalStateException("Message is not specified");
|
|
||||||
}
|
|
||||||
return message;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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();
|
LastSeenMessages lastSeenMessages = this.lastSeenMessages != null ? this.lastSeenMessages : new LastSeenMessages();
|
||||||
if (message.startsWith("/")) {
|
if (message.startsWith("/")) {
|
||||||
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||||
UnsignedPlayerCommandPacket command = new UnsignedPlayerCommandPacket();
|
return new UnsignedPlayerCommandPacket(message.substring(1));
|
||||||
command.command = message.substring(1);
|
|
||||||
return command;
|
|
||||||
} else {
|
} else {
|
||||||
SessionPlayerCommandPacket command = new SessionPlayerCommandPacket();
|
return new SessionPlayerCommandPacket(message.substring(1), timestamp, 0L,
|
||||||
command.command = message.substring(1);
|
new SessionPlayerCommandPacket.ArgumentSignatures(), lastSeenMessages);
|
||||||
command.salt = 0L;
|
|
||||||
command.timeStamp = timestamp;
|
|
||||||
command.argumentSignatures = new SessionPlayerCommandPacket.ArgumentSignatures();
|
|
||||||
command.lastSeenMessages = lastSeenMessages;
|
|
||||||
return command;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SessionPlayerChatPacket chat = new SessionPlayerChatPacket();
|
return new SessionPlayerChatPacket(message, timestamp, 0L, false, new byte[0],
|
||||||
chat.message = message;
|
lastSeenMessages);
|
||||||
chat.signed = false;
|
|
||||||
chat.signature = new byte[0];
|
|
||||||
chat.timestamp = timestamp;
|
|
||||||
chat.salt = 0L;
|
|
||||||
chat.lastSeenMessages = lastSeenMessages;
|
|
||||||
return chat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.packet.chat.session;
|
|||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@@ -27,14 +28,21 @@ import java.time.Instant;
|
|||||||
|
|
||||||
public class SessionPlayerChatPacket implements MinecraftPacket {
|
public class SessionPlayerChatPacket implements MinecraftPacket {
|
||||||
|
|
||||||
protected String message;
|
protected final String message;
|
||||||
protected Instant timestamp;
|
protected final Instant timestamp;
|
||||||
protected long salt;
|
protected final long salt;
|
||||||
protected boolean signed;
|
protected final boolean signed;
|
||||||
protected byte[] signature;
|
protected final byte[] signature;
|
||||||
protected LastSeenMessages lastSeenMessages;
|
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() {
|
public String getMessage() {
|
||||||
@@ -61,34 +69,6 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
|||||||
return lastSeenMessages;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
@@ -101,13 +81,38 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SessionPlayerChatPacket withLastSeenMessages(LastSeenMessages lastSeenMessages) {
|
public SessionPlayerChatPacket withLastSeenMessages(LastSeenMessages lastSeenMessages) {
|
||||||
SessionPlayerChatPacket packet = new SessionPlayerChatPacket();
|
return new SessionPlayerChatPacket(message, timestamp, salt, signed, signature, lastSeenMessages);
|
||||||
packet.message = message;
|
}
|
||||||
packet.timestamp = timestamp;
|
|
||||||
packet.salt = salt;
|
public static class Codec implements PacketCodec<SessionPlayerChatPacket> {
|
||||||
packet.signed = signed;
|
@Override
|
||||||
packet.signature = signature;
|
public SessionPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||||
packet.lastSeenMessages = lastSeenMessages;
|
ProtocolVersion protocolVersion) {
|
||||||
return packet;
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
@@ -33,29 +34,19 @@ import java.util.List;
|
|||||||
|
|
||||||
public class SessionPlayerCommandPacket implements MinecraftPacket {
|
public class SessionPlayerCommandPacket implements MinecraftPacket {
|
||||||
|
|
||||||
protected String command;
|
protected final String command;
|
||||||
protected Instant timeStamp;
|
protected final Instant timeStamp;
|
||||||
protected long salt;
|
protected final long salt;
|
||||||
protected ArgumentSignatures argumentSignatures;
|
protected final ArgumentSignatures argumentSignatures;
|
||||||
protected LastSeenMessages lastSeenMessages;
|
protected final LastSeenMessages lastSeenMessages;
|
||||||
|
|
||||||
@Override
|
public SessionPlayerCommandPacket(String command, Instant timeStamp, long salt,
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
ArgumentSignatures argumentSignatures, LastSeenMessages lastSeenMessages) {
|
||||||
int cap = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5) ? 256 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE;
|
this.command = command;
|
||||||
this.command = ProtocolUtils.readString(buf, cap);
|
this.timeStamp = timeStamp;
|
||||||
this.timeStamp = Instant.ofEpochMilli(buf.readLong());
|
this.salt = salt;
|
||||||
this.salt = buf.readLong();
|
this.argumentSignatures = argumentSignatures;
|
||||||
this.argumentSignatures = new ArgumentSignatures(buf);
|
this.lastSeenMessages = lastSeenMessages;
|
||||||
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 String getCommand() {
|
public String getCommand() {
|
||||||
@@ -92,17 +83,33 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
|
|||||||
|
|
||||||
public SessionPlayerCommandPacket withLastSeenMessages(@Nullable LastSeenMessages lastSeenMessages) {
|
public SessionPlayerCommandPacket withLastSeenMessages(@Nullable LastSeenMessages lastSeenMessages) {
|
||||||
if (lastSeenMessages == null) {
|
if (lastSeenMessages == null) {
|
||||||
UnsignedPlayerCommandPacket packet = new UnsignedPlayerCommandPacket();
|
return new UnsignedPlayerCommandPacket(command);
|
||||||
packet.command = command;
|
}
|
||||||
return packet;
|
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 {
|
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.event.command.CommandExecuteEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
import java.time.Instant;
|
||||||
|
|
||||||
@Override
|
public final class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
||||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
|
||||||
this.command = ProtocolUtils.readString(buf, ProtocolUtils.DEFAULT_MAX_STRING_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public UnsignedPlayerCommandPacket(String command) {
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
super(command, Instant.EPOCH, 0L, new ArgumentSignatures(), null);
|
||||||
ProtocolUtils.writeString(buf, this.command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,6 +38,7 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isSigned() {
|
public boolean isSigned() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -56,4 +54,19 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
|
|||||||
"command='" + command + '\'' +
|
"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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
|
|
||||||
public class ActiveFeaturesPacket implements MinecraftPacket {
|
public record ActiveFeaturesPacket(Key[] activeFeatures) implements MinecraftPacket {
|
||||||
|
|
||||||
private Key[] activeFeatures;
|
|
||||||
|
|
||||||
public ActiveFeaturesPacket(Key[] activeFeatures) {
|
|
||||||
this.activeFeatures = activeFeatures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActiveFeaturesPacket() {
|
public ActiveFeaturesPacket() {
|
||||||
this.activeFeatures = new Key[0];
|
this(new Key[0]);
|
||||||
}
|
|
||||||
|
|
||||||
public void setActiveFeatures(Key[] activeFeatures) {
|
|
||||||
this.activeFeatures = activeFeatures;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Key[] getActiveFeatures() {
|
public Key[] getActiveFeatures() {
|
||||||
return activeFeatures;
|
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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ClientboundCustomReportDetailsPacket implements MinecraftPacket {
|
public record ClientboundCustomReportDetailsPacket(Map<String, String> details) implements MinecraftPacket {
|
||||||
|
|
||||||
private Map<String, String> details;
|
|
||||||
|
|
||||||
public ClientboundCustomReportDetailsPacket() {
|
public ClientboundCustomReportDetailsPacket() {
|
||||||
}
|
this(Map.of());
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -61,7 +37,28 @@ public class ClientboundCustomReportDetailsPacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getDetails() {
|
public static class Codec implements PacketCodec<ClientboundCustomReportDetailsPacket> {
|
||||||
return details;
|
@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.api.util.ServerLink;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ClientboundServerLinksPacket implements MinecraftPacket {
|
public record ClientboundServerLinksPacket(List<ServerLink> serverLinks) implements MinecraftPacket {
|
||||||
|
|
||||||
private List<ServerLink> serverLinks;
|
|
||||||
|
|
||||||
public ClientboundServerLinksPacket() {
|
public ClientboundServerLinksPacket() {
|
||||||
}
|
this(List.of());
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,10 +39,6 @@ public class ClientboundServerLinksPacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ServerLink> getServerLinks() {
|
|
||||||
return serverLinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ServerLink(int id, ComponentHolder displayName, String url) {
|
public record ServerLink(int id, ComponentHolder displayName, String url) {
|
||||||
|
|
||||||
private static ServerLink read(ByteBuf buf, ProtocolVersion version) {
|
private static ServerLink read(ByteBuf buf, ProtocolVersion version) {
|
||||||
@@ -87,4 +60,28 @@ public class ClientboundServerLinksPacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.writeString(buf, url);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class CodeOfConductAcceptPacket implements MinecraftPacket {
|
public final class CodeOfConductAcceptPacket implements MinecraftPacket {
|
||||||
|
|
||||||
public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket();
|
public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket();
|
||||||
|
|
||||||
private CodeOfConductAcceptPacket() {
|
private CodeOfConductAcceptPacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public CodeOfConductPacket(ByteBuf buf) {
|
||||||
super(null);
|
super(buf);
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -46,7 +37,61 @@ public class CodeOfConductPacket extends DeferredByteBufHolder implements Minecr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
public CodeOfConductPacket copy() {
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class FinishedUpdatePacket implements MinecraftPacket {
|
public final class FinishedUpdatePacket implements MinecraftPacket {
|
||||||
public static final FinishedUpdatePacket INSTANCE = new FinishedUpdatePacket();
|
public static final FinishedUpdatePacket INSTANCE = new FinishedUpdatePacket();
|
||||||
|
|
||||||
private 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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
import com.velocitypowered.proxy.util.except.QuietDecoderException;
|
||||||
import io.netty.buffer.ByteBuf;
|
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);
|
public KnownPacksPacket() {
|
||||||
private static final QuietDecoderException TOO_MANY_PACKS =
|
this(new KnownPack[0]);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,4 +47,37 @@ public class KnownPacksPacket implements MinecraftPacket {
|
|||||||
ProtocolUtils.writeString(buf, version);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public RegistrySyncPacket(ByteBuf backing) {
|
||||||
super(null);
|
super(backing);
|
||||||
}
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,8 +37,22 @@ public class RegistrySyncPacket extends DeferredByteBufHolder implements Minecra
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
||||||
return content().readableBytes();
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class StartUpdatePacket implements MinecraftPacket {
|
public final class StartUpdatePacket implements MinecraftPacket {
|
||||||
public static final StartUpdatePacket INSTANCE = new StartUpdatePacket();
|
public static final StartUpdatePacket INSTANCE = new StartUpdatePacket();
|
||||||
|
|
||||||
private 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
|
@Override
|
||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.util.Map;
|
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) {
|
public TagsUpdatePacket(Map<String, Map<String, int[]>> tags) {
|
||||||
this.tags = tags;
|
this.tags = ImmutableMap.copyOf(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TagsUpdatePacket() {
|
public Map<String, Map<String, int[]>> getTags() {
|
||||||
this.tags = Map.of();
|
return tags;
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,21 +45,61 @@ public class TagsUpdatePacket implements MinecraftPacket {
|
|||||||
return handler.handle(this);
|
return handler.handle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class Codec implements PacketCodec<TagsUpdatePacket> {
|
||||||
public int encodeSizeHint(Direction direction, ProtocolVersion version) {
|
@Override
|
||||||
int size = ProtocolUtils.varIntBytes(tags.size());
|
public TagsUpdatePacket decode(ByteBuf buf, Direction direction,
|
||||||
for (Map.Entry<String, Map<String, int[]>> entry : tags.entrySet()) {
|
ProtocolVersion protocolVersion) {
|
||||||
size += ProtocolUtils.stringSizeHint(entry.getKey());
|
ImmutableMap.Builder<String, Map<String, int[]>> builder = ImmutableMap.builder();
|
||||||
size += ProtocolUtils.varIntBytes(entry.getValue().size());
|
int size = ProtocolUtils.readVarInt(buf);
|
||||||
for (Map.Entry<String, int[]> innerEntry : entry.getValue().entrySet()) {
|
for (int i = 0; i < size; i++) {
|
||||||
size += ProtocolUtils.stringSizeHint(innerEntry.getKey());
|
String key = ProtocolUtils.readString(buf);
|
||||||
size += ProtocolUtils.varIntBytes(innerEntry.getValue().length);
|
|
||||||
for (int innerEntryValue : innerEntry.getValue()) {
|
int innerSize = ProtocolUtils.readVarInt(buf);
|
||||||
size += ProtocolUtils.varIntBytes(innerEntryValue);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
|
|
||||||
public abstract class GenericTitlePacket implements MinecraftPacket {
|
public abstract class GenericTitlePacket implements MinecraftPacket {
|
||||||
|
|
||||||
@@ -45,10 +43,9 @@ public abstract class GenericTitlePacket implements MinecraftPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ActionType action;
|
||||||
|
|
||||||
private ActionType action;
|
protected GenericTitlePacket(ActionType action) {
|
||||||
|
|
||||||
protected void setAction(ActionType action) {
|
|
||||||
this.action = action;
|
this.action = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,76 +57,77 @@ public abstract class GenericTitlePacket implements MinecraftPacket {
|
|||||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
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() {
|
public int getFadeIn() {
|
||||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
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() {
|
public int getStay() {
|
||||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
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() {
|
public int getFadeOut() {
|
||||||
throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType");
|
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
|
* @param version Protocol version of the target player
|
||||||
* @return GenericTitlePacket instance that follows the invoker type/version
|
* @return GenericTitlePacket instance that follows the invoker type/version
|
||||||
*/
|
*/
|
||||||
public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) {
|
public static GenericTitlePacket createClearTitlePacket(ActionType type, ProtocolVersion version) {
|
||||||
GenericTitlePacket packet = null;
|
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)) {
|
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SET_ACTION_BAR:
|
case SET_ACTION_BAR:
|
||||||
packet = new TitleActionbarPacket();
|
return new TitleActionbarPacket(component);
|
||||||
break;
|
|
||||||
case SET_SUBTITLE:
|
case SET_SUBTITLE:
|
||||||
packet = new TitleSubtitlePacket();
|
return new TitleSubtitlePacket(component);
|
||||||
break;
|
|
||||||
case SET_TIMES:
|
|
||||||
packet = new TitleTimesPacket();
|
|
||||||
break;
|
|
||||||
case SET_TITLE:
|
case SET_TITLE:
|
||||||
packet = new TitleTextPacket();
|
return new TitleTextPacket(component);
|
||||||
break;
|
|
||||||
case HIDE:
|
|
||||||
case RESET:
|
|
||||||
packet = new TitleClearPacket();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid ActionType");
|
throw new IllegalArgumentException("Invalid ActionType for component title: " + type);
|
||||||
}
|
}
|
||||||
} else {
|
} 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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class LegacyTitlePacket extends GenericTitlePacket {
|
public final class LegacyTitlePacket extends GenericTitlePacket {
|
||||||
|
|
||||||
private @Nullable ComponentHolder component;
|
private final @Nullable ComponentHolder component;
|
||||||
private int fadeIn;
|
private final int fadeIn;
|
||||||
private int stay;
|
private final int stay;
|
||||||
private int fadeOut;
|
private final int fadeOut;
|
||||||
|
|
||||||
@Override
|
public LegacyTitlePacket(ActionType action, @Nullable ComponentHolder component,
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
int fadeIn, int stay, int fadeOut) {
|
||||||
if (version.lessThan(ProtocolVersion.MINECRAFT_1_11)
|
super(action);
|
||||||
&& getAction() == ActionType.SET_ACTION_BAR) {
|
this.component = component;
|
||||||
throw new IllegalStateException("Action bars are only supported on 1.11 and newer");
|
this.fadeIn = fadeIn;
|
||||||
}
|
this.stay = stay;
|
||||||
ProtocolUtils.writeVarInt(buf, getAction().getAction(version));
|
this.fadeOut = fadeOut;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,44 +46,24 @@ public class LegacyTitlePacket extends GenericTitlePacket {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setComponent(@Nullable ComponentHolder component) {
|
|
||||||
this.component = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFadeIn() {
|
public int getFadeIn() {
|
||||||
return fadeIn;
|
return fadeIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFadeIn(int fadeIn) {
|
|
||||||
this.fadeIn = fadeIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStay() {
|
public int getStay() {
|
||||||
return stay;
|
return stay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStay(int stay) {
|
|
||||||
this.stay = stay;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFadeOut() {
|
public int getFadeOut() {
|
||||||
return fadeOut;
|
return fadeOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFadeOut(int fadeOut) {
|
|
||||||
this.fadeOut = fadeOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "GenericTitlePacket{"
|
return "LegacyTitlePacket{"
|
||||||
+ "action=" + getAction()
|
+ "action=" + getAction()
|
||||||
+ ", component='" + component + '\''
|
+ ", component='" + component + '\''
|
||||||
+ ", fadeIn=" + fadeIn
|
+ ", fadeIn=" + fadeIn
|
||||||
@@ -122,4 +76,43 @@ public class LegacyTitlePacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public TitleActionbarPacket(ComponentHolder component) {
|
||||||
setAction(ActionType.SET_TITLE);
|
super(ActionType.SET_ACTION_BAR);
|
||||||
}
|
this.component = component;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
component.write(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,15 +38,10 @@ public class TitleActionbarPacket extends GenericTitlePacket {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setComponent(ComponentHolder component) {
|
|
||||||
this.component = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TitleActionbarPacket{"
|
return "TitleActionbarPacket{"
|
||||||
+ ", component='" + component + '\''
|
+ "component='" + component + '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,4 +49,18 @@ public class TitleActionbarPacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class TitleClearPacket extends GenericTitlePacket {
|
public final class TitleClearPacket extends GenericTitlePacket {
|
||||||
|
|
||||||
public TitleClearPacket() {
|
private final boolean reset;
|
||||||
setAction(ActionType.HIDE);
|
|
||||||
|
public TitleClearPacket(boolean reset) {
|
||||||
|
super(reset ? ActionType.RESET : ActionType.HIDE);
|
||||||
|
this.reset = reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean isReset() {
|
||||||
public void setAction(ActionType action) {
|
return reset;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TitleClearPacket{"
|
return "TitleClearPacket{"
|
||||||
+ ", resetTimes=" + (getAction() == ActionType.RESET)
|
+ "resetTimes=" + reset
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,4 +47,18 @@ public class TitleClearPacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public TitleSubtitlePacket(ComponentHolder component) {
|
||||||
setAction(ActionType.SET_SUBTITLE);
|
super(ActionType.SET_SUBTITLE);
|
||||||
}
|
this.component = component;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
component.write(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,15 +38,10 @@ public class TitleSubtitlePacket extends GenericTitlePacket {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setComponent(ComponentHolder component) {
|
|
||||||
this.component = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TitleSubtitlePacket{"
|
return "TitleSubtitlePacket{"
|
||||||
+ ", component='" + component + '\''
|
+ "component='" + component + '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,4 +49,18 @@ public class TitleSubtitlePacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||||
import io.netty.buffer.ByteBuf;
|
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() {
|
public TitleTextPacket(ComponentHolder component) {
|
||||||
setAction(ActionType.SET_TITLE);
|
super(ActionType.SET_TITLE);
|
||||||
}
|
this.component = component;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
component.write(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,15 +38,10 @@ public class TitleTextPacket extends GenericTitlePacket {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setComponent(ComponentHolder component) {
|
|
||||||
this.component = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TitleTextPacket{"
|
return "TitleTextPacket{"
|
||||||
+ ", component='" + component + '\''
|
+ "component='" + component + '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,4 +49,18 @@ public class TitleTextPacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.protocol.PacketCodec;
|
||||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
public class TitleTimesPacket extends GenericTitlePacket {
|
public final class TitleTimesPacket extends GenericTitlePacket {
|
||||||
|
|
||||||
private int fadeIn;
|
private final int fadeIn;
|
||||||
private int stay;
|
private final int stay;
|
||||||
private int fadeOut;
|
private final int fadeOut;
|
||||||
|
|
||||||
public TitleTimesPacket() {
|
public TitleTimesPacket(int fadeIn, int stay, int fadeOut) {
|
||||||
setAction(ActionType.SET_TIMES);
|
super(ActionType.SET_TIMES);
|
||||||
}
|
this.fadeIn = fadeIn;
|
||||||
|
this.stay = stay;
|
||||||
@Override
|
this.fadeOut = fadeOut;
|
||||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
|
||||||
buf.writeInt(fadeIn);
|
|
||||||
buf.writeInt(stay);
|
|
||||||
buf.writeInt(fadeOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -44,35 +41,20 @@ public class TitleTimesPacket extends GenericTitlePacket {
|
|||||||
return fadeIn;
|
return fadeIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFadeIn(int fadeIn) {
|
|
||||||
this.fadeIn = fadeIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getStay() {
|
public int getStay() {
|
||||||
return stay;
|
return stay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStay(int stay) {
|
|
||||||
this.stay = stay;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFadeOut() {
|
public int getFadeOut() {
|
||||||
return fadeOut;
|
return fadeOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFadeOut(int fadeOut) {
|
|
||||||
this.fadeOut = fadeOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TitleTimesPacket{"
|
return "TitleTimesPacket{"
|
||||||
+ ", fadeIn=" + fadeIn
|
+ "fadeIn=" + fadeIn
|
||||||
+ ", stay=" + stay
|
+ ", stay=" + stay
|
||||||
+ ", fadeOut=" + fadeOut
|
+ ", fadeOut=" + fadeOut
|
||||||
+ '}';
|
+ '}';
|
||||||
@@ -82,4 +64,20 @@ public class TitleTimesPacket extends GenericTitlePacket {
|
|||||||
public boolean handle(MinecraftSessionHandler handler) {
|
public boolean handle(MinecraftSessionHandler handler) {
|
||||||
return handler.handle(this);
|
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
|
@Override
|
||||||
public void activated() {
|
public void activated() {
|
||||||
HandshakePacket handshake = new HandshakePacket();
|
String serverAddress = this.virtualHostString == null || this.virtualHostString.isEmpty()
|
||||||
handshake.setIntent(HandshakeIntent.STATUS);
|
? server.getServerInfo().getAddress().getHostString() : this.virtualHostString;
|
||||||
handshake.setServerAddress(this.virtualHostString == null || this.virtualHostString.isEmpty()
|
HandshakePacket handshake = new HandshakePacket(version, serverAddress,
|
||||||
? server.getServerInfo().getAddress().getHostString() : this.virtualHostString);
|
server.getServerInfo().getAddress().getPort(), HandshakeIntent.STATUS);
|
||||||
handshake.setPort(server.getServerInfo().getAddress().getPort());
|
|
||||||
handshake.setProtocolVersion(version);
|
|
||||||
connection.delayedWrite(handshake);
|
connection.delayedWrite(handshake);
|
||||||
|
|
||||||
connection.setActiveSessionHandler(StateRegistry.STATUS);
|
connection.setActiveSessionHandler(StateRegistry.STATUS);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class PacketRegistryTest {
|
|||||||
private StateRegistry.PacketRegistry setupRegistry() {
|
private StateRegistry.PacketRegistry setupRegistry() {
|
||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
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(0x01, MINECRAFT_1_8, null, false),
|
||||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false),
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false),
|
||||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_15, MINECRAFT_1_16, false));
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_15, MINECRAFT_1_16, false));
|
||||||
@@ -55,29 +55,30 @@ class PacketRegistryTest {
|
|||||||
@Test
|
@Test
|
||||||
void packetRegistryWorks() {
|
void packetRegistryWorks() {
|
||||||
StateRegistry.PacketRegistry registry = setupRegistry();
|
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");
|
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");
|
"Registry did not return the correct packet ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void packetRegistryLinkingWorks() {
|
void packetRegistryLinkingWorks() {
|
||||||
StateRegistry.PacketRegistry registry = setupRegistry();
|
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");
|
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_1).getPacketId(packet),
|
HandshakePacket handshakePacket = new HandshakePacket();
|
||||||
|
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12_1).getPacketId(handshakePacket),
|
||||||
"Registry did not return the correct packet ID");
|
"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");
|
"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");
|
"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");
|
"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");
|
"Registry should return null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ class PacketRegistryTest {
|
|||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||||
assertThrows(IllegalArgumentException.class,
|
assertThrows(IllegalArgumentException.class,
|
||||||
() -> registry.register(HandshakePacket.class, HandshakePacket::new));
|
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec()));
|
||||||
assertThrows(IllegalArgumentException.class,
|
assertThrows(IllegalArgumentException.class,
|
||||||
() -> registry.getProtocolRegistry(ProtocolVersion.UNKNOWN)
|
() -> registry.getProtocolRegistry(ProtocolVersion.UNKNOWN)
|
||||||
.getPacketId(new HandshakePacket()));
|
.getPacketId(new HandshakePacket()));
|
||||||
@@ -97,18 +98,18 @@ class PacketRegistryTest {
|
|||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
||||||
assertThrows(IllegalArgumentException.class,
|
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),
|
||||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false)));
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false)));
|
||||||
assertThrows(IllegalArgumentException.class,
|
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),
|
||||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false)));
|
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false)));
|
||||||
assertThrows(IllegalArgumentException.class,
|
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)));
|
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, MINECRAFT_1_8, false)));
|
||||||
assertThrows(IllegalArgumentException.class,
|
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(0x01, MINECRAFT_1_8, MINECRAFT_1_14, false),
|
||||||
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_16, null, false)));
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_16, null, false)));
|
||||||
}
|
}
|
||||||
@@ -117,13 +118,13 @@ class PacketRegistryTest {
|
|||||||
void failOnDuplicate() {
|
void failOnDuplicate() {
|
||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
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));
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false));
|
||||||
assertThrows(IllegalArgumentException.class,
|
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)));
|
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12, null, false)));
|
||||||
assertThrows(IllegalArgumentException.class,
|
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)));
|
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_13, null, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +132,7 @@ class PacketRegistryTest {
|
|||||||
void shouldNotFailWhenRegisterLatestProtocolVersion() {
|
void shouldNotFailWhenRegisterLatestProtocolVersion() {
|
||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
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(0x00, MINECRAFT_1_8, null, false),
|
||||||
new StateRegistry.PacketMapping(0x01, getLast(ProtocolVersion.SUPPORTED_VERSIONS),
|
new StateRegistry.PacketMapping(0x01, getLast(ProtocolVersion.SUPPORTED_VERSIONS),
|
||||||
null, false)));
|
null, false)));
|
||||||
@@ -141,19 +142,19 @@ class PacketRegistryTest {
|
|||||||
void registrySuppliesCorrectPacketsByProtocol() {
|
void registrySuppliesCorrectPacketsByProtocol() {
|
||||||
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
|
||||||
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
|
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(0x00, MINECRAFT_1_12, null, false),
|
||||||
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, null, false),
|
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, null, false),
|
||||||
new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, null, false));
|
new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, null, false));
|
||||||
assertEquals(HandshakePacket.class,
|
assertEquals(HandshakePacket.Codec.class,
|
||||||
registry.getProtocolRegistry(MINECRAFT_1_12).createPacket(0x00).getClass());
|
registry.getProtocolRegistry(MINECRAFT_1_12).getCodec(0x00).getClass());
|
||||||
assertEquals(HandshakePacket.class,
|
assertEquals(HandshakePacket.Codec.class,
|
||||||
registry.getProtocolRegistry(MINECRAFT_1_12_1).createPacket(0x01).getClass());
|
registry.getProtocolRegistry(MINECRAFT_1_12_1).getCodec(0x01).getClass());
|
||||||
assertEquals(HandshakePacket.class,
|
assertEquals(HandshakePacket.Codec.class,
|
||||||
registry.getProtocolRegistry(MINECRAFT_1_12_2).createPacket(0x01).getClass());
|
registry.getProtocolRegistry(MINECRAFT_1_12_2).getCodec(0x01).getClass());
|
||||||
assertEquals(HandshakePacket.class,
|
assertEquals(HandshakePacket.Codec.class,
|
||||||
registry.getProtocolRegistry(MINECRAFT_1_13).createPacket(0x02).getClass());
|
registry.getProtocolRegistry(MINECRAFT_1_13).getCodec(0x02).getClass());
|
||||||
assertEquals(HandshakePacket.class,
|
assertEquals(HandshakePacket.Codec.class,
|
||||||
registry.getProtocolRegistry(MINECRAFT_1_14_2).createPacket(0x02).getClass());
|
registry.getProtocolRegistry(MINECRAFT_1_14_2).getCodec(0x02).getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user