geforkt von Mirrors/Velocity
WIP 1.20.3
Dieser Commit ist enthalten in:
Ursprung
a6d90105ec
Commit
814b53f12c
@ -63,7 +63,8 @@ public enum ProtocolVersion {
|
||||
MINECRAFT_1_19_3(761, "1.19.3"),
|
||||
MINECRAFT_1_19_4(762, "1.19.4"),
|
||||
MINECRAFT_1_20(763, "1.20", "1.20.1"),
|
||||
MINECRAFT_1_20_2(764, "1.20.2");
|
||||
MINECRAFT_1_20_2(764, "1.20.2"),
|
||||
MINECRAFT_1_20_3(765, "1.20.3");
|
||||
|
||||
private static final int SNAPSHOT_BIT = 30;
|
||||
|
||||
|
@ -19,6 +19,8 @@ import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.api.util.ModInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
@ -236,6 +238,7 @@ public interface Player extends
|
||||
* @return the applied resource pack or null if none.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
ResourcePackInfo getAppliedResourcePack();
|
||||
|
||||
/**
|
||||
@ -246,8 +249,26 @@ public interface Player extends
|
||||
* @return the pending resource pack or null if none
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
ResourcePackInfo getPendingResourcePack();
|
||||
|
||||
/**
|
||||
* Gets the {@link ResourcePackInfo} of the currently applied
|
||||
* resource-packs.
|
||||
*
|
||||
* @return collection of the applied resource packs.
|
||||
*/
|
||||
Collection<ResourcePackInfo> getAppliedResourcePacks();
|
||||
|
||||
/**
|
||||
* Gets the {@link ResourcePackInfo} of the resource packs
|
||||
* the user is currently downloading or is currently
|
||||
* prompted to install.
|
||||
*
|
||||
* @return collection of the pending resource packs
|
||||
*/
|
||||
Collection<ResourcePackInfo> getPendingResourcePacks();
|
||||
|
||||
/**
|
||||
* <strong>Note that this method does not send a plugin message to the server the player
|
||||
* is connected to.</strong> You should only use this method if you are trying to communicate
|
||||
|
@ -10,11 +10,20 @@ package com.velocitypowered.api.proxy.player;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents the information for a resource pack to apply that can be sent to the client.
|
||||
*/
|
||||
public interface ResourcePackInfo {
|
||||
|
||||
/**
|
||||
* Gets the id of this resource-pack.
|
||||
*
|
||||
* @return the id of the resource-pack
|
||||
*/
|
||||
UUID getId();
|
||||
|
||||
/**
|
||||
* Gets the link the resource-pack can be found at.
|
||||
*
|
||||
@ -96,6 +105,13 @@ public interface ResourcePackInfo {
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
/**
|
||||
* Sets the id of the resource pack.
|
||||
*
|
||||
* @param id the id the resource-pack
|
||||
*/
|
||||
Builder setId(UUID id);
|
||||
|
||||
/**
|
||||
* Sets the resource-pack as required to play on the network.
|
||||
* This feature was introduced in 1.17.
|
||||
|
@ -37,6 +37,7 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.PingIdentify;
|
||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemoveResourcePack;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.Respawn;
|
||||
@ -248,6 +249,10 @@ public interface MinecraftSessionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean handle(RemoveResourcePack packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean handle(ResourcePackResponse packet) {
|
||||
return false;
|
||||
}
|
||||
|
@ -49,11 +49,13 @@ import com.velocitypowered.proxy.protocol.packet.KeepAlive;
|
||||
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem;
|
||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemoveResourcePack;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerData;
|
||||
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.protocol.packet.config.StartUpdate;
|
||||
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@ -167,7 +169,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
public boolean handle(ResourcePackRequest packet) {
|
||||
ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(
|
||||
Preconditions.checkNotNull(packet.getUrl()))
|
||||
.setPrompt(packet.getPrompt())
|
||||
.setId(packet.getId())
|
||||
.setPrompt(packet.getPrompt() == null ? null : packet.getPrompt().getComponent())
|
||||
.setShouldForce(packet.isRequired())
|
||||
.setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER);
|
||||
|
||||
@ -213,6 +216,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(RemoveResourcePack packet) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(PluginMessage packet) {
|
||||
if (bungeecordMessageResponder.process(packet)) {
|
||||
@ -304,7 +312,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
ping -> server.getEventManager()
|
||||
.fire(new ProxyPingEvent(this.serverConn.getPlayer(), ping)),
|
||||
playerConnection.eventLoop()).thenAcceptAsync(pingEvent -> this.playerConnection.write(
|
||||
new ServerData(pingEvent.getPing().getDescriptionComponent(),
|
||||
new ServerData(new ComponentHolder(this.serverConn.ensureConnected().getProtocolVersion(),
|
||||
pingEvent.getPing().getDescriptionComponent()),
|
||||
pingEvent.getPing().getFavicon().orElse(null), packet.isSecureChatEnforced())),
|
||||
playerConnection.eventLoop());
|
||||
return true;
|
||||
|
@ -68,6 +68,7 @@ import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatQueue;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ChatType;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderFactory;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat;
|
||||
import com.velocitypowered.proxy.protocol.packet.config.StartUpdate;
|
||||
@ -84,6 +85,7 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -1015,22 +1017,36 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
request.setHash("");
|
||||
}
|
||||
request.setRequired(queued.getShouldForce());
|
||||
request.setPrompt(queued.getPrompt());
|
||||
request.setPrompt(queued.getPrompt() == null ? null : new ComponentHolder(getProtocolVersion(), queued.getPrompt()));
|
||||
|
||||
connection.write(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public @Nullable ResourcePackInfo getAppliedResourcePack() {
|
||||
//TODO which resource pack should be returned here?
|
||||
return appliedResourcePack;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public @Nullable ResourcePackInfo getPendingResourcePack() {
|
||||
//TODO which resource pack should be returned here?
|
||||
return pendingResourcePack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourcePackInfo> getAppliedResourcePacks() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourcePackInfo> getPendingResourcePacks() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the applied resource pack field.
|
||||
*/
|
||||
@ -1089,6 +1105,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
* Gives an indication about the previous resource pack responses.
|
||||
*/
|
||||
public @Nullable Boolean getPreviousResourceResponse() {
|
||||
//TODO can probably be removed
|
||||
return previousResourceResponse;
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,14 @@ import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Implements {@link ResourcePackInfo}.
|
||||
*/
|
||||
public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
|
||||
private final UUID id;
|
||||
private final String url;
|
||||
private final @Nullable byte[] hash;
|
||||
private final boolean shouldForce;
|
||||
@ -34,8 +37,9 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
private final Origin origin;
|
||||
private Origin originalOrigin;
|
||||
|
||||
private VelocityResourcePackInfo(String url, @Nullable byte[] hash, boolean shouldForce,
|
||||
private VelocityResourcePackInfo(UUID id, String url, @Nullable byte[] hash, boolean shouldForce,
|
||||
@Nullable Component prompt, Origin origin) {
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.hash = hash;
|
||||
this.shouldForce = shouldForce;
|
||||
@ -44,6 +48,11 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
this.originalOrigin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return url;
|
||||
@ -81,6 +90,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new BuilderImpl(url)
|
||||
.setId(id)
|
||||
.setShouldForce(shouldForce)
|
||||
.setHash(hash)
|
||||
.setPrompt(prompt);
|
||||
@ -89,6 +99,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
@Override
|
||||
public Builder asBuilder(String newUrl) {
|
||||
return new BuilderImpl(newUrl)
|
||||
.setId(id)
|
||||
.setShouldForce(shouldForce)
|
||||
.setHash(hash)
|
||||
.setPrompt(prompt);
|
||||
@ -99,6 +110,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
*/
|
||||
public static final class BuilderImpl implements ResourcePackInfo.Builder {
|
||||
|
||||
private UUID id;
|
||||
private final String url;
|
||||
private boolean shouldForce;
|
||||
private @Nullable byte[] hash;
|
||||
@ -109,6 +121,12 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
this.url = Preconditions.checkNotNull(url, "url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl setId(UUID id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuilderImpl setShouldForce(boolean shouldForce) {
|
||||
this.shouldForce = shouldForce;
|
||||
@ -134,7 +152,7 @@ public final class VelocityResourcePackInfo implements ResourcePackInfo {
|
||||
|
||||
@Override
|
||||
public ResourcePackInfo build() {
|
||||
return new VelocityResourcePackInfo(url, hash, shouldForce, prompt, origin);
|
||||
return new VelocityResourcePackInfo(id, url, hash, shouldForce, prompt, origin);
|
||||
}
|
||||
|
||||
public BuilderImpl setOrigin(Origin origin) {
|
||||
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2023 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.connection.registry;
|
||||
|
||||
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.config.RegistrySync;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Holds the registry data that is sent
|
||||
* to the client during the config stage.
|
||||
*/
|
||||
public class ClientConfigData {
|
||||
|
||||
private final @Nullable VelocityResourcePackInfo resourcePackInfo;
|
||||
private final DataTag tag;
|
||||
private final RegistrySync registry;
|
||||
private final Key[] features;
|
||||
private final String brand;
|
||||
|
||||
private ClientConfigData(@Nullable VelocityResourcePackInfo resourcePackInfo, DataTag tag,
|
||||
RegistrySync registry, Key[] features, String brand) {
|
||||
this.resourcePackInfo = resourcePackInfo;
|
||||
this.tag = tag;
|
||||
this.registry = registry;
|
||||
this.features = features;
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
public RegistrySync getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public DataTag getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public Key[] getFeatures() {
|
||||
return features;
|
||||
}
|
||||
|
||||
public @Nullable VelocityResourcePackInfo getResourcePackInfo() {
|
||||
return resourcePackInfo;
|
||||
}
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
*
|
||||
* @return ClientConfigData.Builder
|
||||
*/
|
||||
public static ClientConfigData.Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for ClientConfigData.
|
||||
*/
|
||||
public static class Builder {
|
||||
private VelocityResourcePackInfo resourcePackInfo;
|
||||
private DataTag tag;
|
||||
private RegistrySync registry;
|
||||
private Key[] features;
|
||||
private String brand;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the builder.
|
||||
*/
|
||||
public void clear() {
|
||||
this.resourcePackInfo = null;
|
||||
this.tag = null;
|
||||
this.registry = null;
|
||||
this.features = null;
|
||||
this.brand = null;
|
||||
}
|
||||
|
||||
public Builder resourcePack(@Nullable VelocityResourcePackInfo resourcePackInfo) {
|
||||
this.resourcePackInfo = resourcePackInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dataTag(DataTag tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder registry(RegistrySync registry) {
|
||||
this.registry = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder features(Key[] features) {
|
||||
this.features = features;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder brand(String brand) {
|
||||
this.brand = brand;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientConfigData build() {
|
||||
return new ClientConfigData(resourcePackInfo, tag, registry, features, brand);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2023 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.connection.registry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.key.Keyed;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a data tag.
|
||||
*/
|
||||
public class DataTag {
|
||||
private final ImmutableList<DataTag.Set> entrySets;
|
||||
|
||||
public DataTag(ImmutableList<DataTag.Set> entrySets) {
|
||||
this.entrySets = entrySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry sets.
|
||||
*
|
||||
* @return List of entry sets
|
||||
*/
|
||||
public List<Set> getEntrySets() {
|
||||
return entrySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a data tag set.
|
||||
*/
|
||||
public static class Set implements Keyed {
|
||||
|
||||
private final Key key;
|
||||
private final ImmutableList<Entry> entries;
|
||||
|
||||
public Set(Key key, ImmutableList<Entry> entries) {
|
||||
this.key = key;
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entries.
|
||||
*
|
||||
* @return List of entries
|
||||
*/
|
||||
public List<Entry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Key key() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a data tag entry.
|
||||
*/
|
||||
public static class Entry implements Keyed {
|
||||
|
||||
private final Key key;
|
||||
private final int[] elements;
|
||||
|
||||
public Entry(Key key, int[] elements) {
|
||||
this.key = key;
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
public int[] getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Key key() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,15 +34,16 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.BinaryTagType;
|
||||
import net.kyori.adventure.nbt.BinaryTagTypes;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
@ -64,6 +65,11 @@ public enum ProtocolUtils {
|
||||
.build();
|
||||
|
||||
public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB
|
||||
private static final BinaryTagType<? extends BinaryTag>[] BINARY_TAG_TYPES = new BinaryTagType[] {
|
||||
BinaryTagTypes.END, BinaryTagTypes.BYTE, BinaryTagTypes.SHORT, BinaryTagTypes.INT,
|
||||
BinaryTagTypes.LONG, BinaryTagTypes.FLOAT, BinaryTagTypes.DOUBLE,
|
||||
BinaryTagTypes.BYTE_ARRAY, BinaryTagTypes.STRING, BinaryTagTypes.LIST,
|
||||
BinaryTagTypes.COMPOUND, BinaryTagTypes.INT_ARRAY, BinaryTagTypes.LONG_ARRAY};
|
||||
private static final QuietDecoderException BAD_VARINT_CACHED =
|
||||
new QuietDecoderException("Bad VarInt decoded");
|
||||
private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33];
|
||||
@ -367,29 +373,53 @@ public enum ProtocolUtils {
|
||||
* Reads a {@link net.kyori.adventure.nbt.CompoundBinaryTag} from the {@code buf}.
|
||||
*
|
||||
* @param buf the buffer to read from
|
||||
* @param reader the NBT reader to use
|
||||
* @param reader the {@link BinaryTagIO.Reader} to use
|
||||
* @return {@link net.kyori.adventure.nbt.CompoundBinaryTag} the CompoundTag from the buffer
|
||||
*/
|
||||
public static CompoundBinaryTag readCompoundTag(ByteBuf buf, BinaryTagIO.Reader reader) {
|
||||
public static CompoundBinaryTag readCompoundTag(ByteBuf buf, ProtocolVersion version, BinaryTagIO.Reader reader) {
|
||||
BinaryTag binaryTag = readBinaryTag(buf, version, reader);
|
||||
if (binaryTag.type() != BinaryTagTypes.COMPOUND) {
|
||||
throw new DecoderException("Expected root tag to be CompoundTag, but is " + binaryTag.getClass().getSimpleName());
|
||||
}
|
||||
return (CompoundBinaryTag) binaryTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a {@link net.kyori.adventure.nbt.BinaryTag} from the {@code buf}.
|
||||
*
|
||||
* @param buf the buffer to read from
|
||||
* @param reader the {@link BinaryTagIO.Reader} to use
|
||||
* @return {@link net.kyori.adventure.nbt.BinaryTag} the BinaryTag from the buffer
|
||||
*/
|
||||
public static BinaryTag readBinaryTag(ByteBuf buf, ProtocolVersion version, BinaryTagIO.Reader reader) {
|
||||
BinaryTagType<?> type = BINARY_TAG_TYPES[buf.readByte()];
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) {
|
||||
buf.skipBytes(buf.readUnsignedShort());
|
||||
}
|
||||
try {
|
||||
return reader.read((DataInput) new ByteBufInputStream(buf));
|
||||
return type.read(new ByteBufInputStream(buf));
|
||||
} catch (IOException thrown) {
|
||||
throw new DecoderException(
|
||||
"Unable to parse NBT CompoundTag, full error: " + thrown.getMessage());
|
||||
throw new DecoderException("Unable to parse BinaryTag, full error: " + thrown.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a CompoundTag to the {@code buf}.
|
||||
* Writes a {@link net.kyori.adventure.nbt.BinaryTag} to the {@code buf}.
|
||||
*
|
||||
* @param buf the buffer to write to
|
||||
* @param compoundTag the CompoundTag to write
|
||||
* @param buf the buffer to write to
|
||||
* @param tag the BinaryTag to write
|
||||
*/
|
||||
public static void writeCompoundTag(ByteBuf buf, CompoundBinaryTag compoundTag) {
|
||||
public static <T extends BinaryTag> void writeBinaryTag(ByteBuf buf, ProtocolVersion version, T tag) {
|
||||
BinaryTagType<T> type = (BinaryTagType<T>) tag.type();
|
||||
buf.writeByte(type.id());
|
||||
try {
|
||||
BinaryTagIO.writer().write(compoundTag, (DataOutput) new ByteBufOutputStream(buf));
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) {
|
||||
// Empty name
|
||||
buf.writeShort(0);
|
||||
}
|
||||
type.write(tag, new ByteBufOutputStream(buf));
|
||||
} catch (IOException e) {
|
||||
throw new EncoderException("Unable to encode NBT CompoundTag");
|
||||
throw new EncoderException("Unable to encode BinaryTag");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_1;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_3;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_2;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_3;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
|
||||
@ -62,6 +63,7 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.PingIdentify;
|
||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemoveResourcePack;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest;
|
||||
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.Respawn;
|
||||
@ -154,10 +156,16 @@ public enum StateRegistry {
|
||||
clientbound.register(
|
||||
RegistrySync.class, RegistrySync::new, map(0x05, MINECRAFT_1_20_2, false));
|
||||
clientbound.register(
|
||||
ResourcePackRequest.class, ResourcePackRequest::new, map(0x06, MINECRAFT_1_20_2, false));
|
||||
clientbound.register(
|
||||
ActiveFeatures.class, ActiveFeatures::new, map(0x07, MINECRAFT_1_20_2, false));
|
||||
clientbound.register(TagsUpdate.class, TagsUpdate::new, map(0x08, MINECRAFT_1_20_2, false));
|
||||
RemoveResourcePack.class, RemoveResourcePack::new, map(0x06, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new,
|
||||
map(0x06, MINECRAFT_1_20_2, false),
|
||||
map(0x07, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(ActiveFeatures.class, ActiveFeatures::new,
|
||||
map(0x07, MINECRAFT_1_20_2, false),
|
||||
map(0x08, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(TagsUpdate.class, TagsUpdate::new,
|
||||
map(0x08, MINECRAFT_1_20_2, false),
|
||||
map(0x09, MINECRAFT_1_20_3, false));
|
||||
}
|
||||
},
|
||||
PLAY {
|
||||
@ -228,7 +236,8 @@ public enum StateRegistry {
|
||||
map(0x0D, MINECRAFT_1_19_1, false),
|
||||
map(0x0C, MINECRAFT_1_19_3, false),
|
||||
map(0x0D, MINECRAFT_1_19_4, false),
|
||||
map(0x0F, MINECRAFT_1_20_2, false));
|
||||
map(0x0F, MINECRAFT_1_20_2, false),
|
||||
map(0x10, MINECRAFT_1_20_3, false));
|
||||
serverbound.register(
|
||||
KeepAlive.class,
|
||||
KeepAlive::new,
|
||||
@ -244,7 +253,8 @@ public enum StateRegistry {
|
||||
map(0x12, MINECRAFT_1_19_1, false),
|
||||
map(0x11, MINECRAFT_1_19_3, false),
|
||||
map(0x12, MINECRAFT_1_19_4, false),
|
||||
map(0x14, MINECRAFT_1_20_2, false));
|
||||
map(0x14, MINECRAFT_1_20_2, false),
|
||||
map(0x15, MINECRAFT_1_20_3, false));
|
||||
serverbound.register(
|
||||
ResourcePackResponse.class,
|
||||
ResourcePackResponse::new,
|
||||
@ -257,7 +267,8 @@ public enum StateRegistry {
|
||||
map(0x21, MINECRAFT_1_16_2, false),
|
||||
map(0x23, MINECRAFT_1_19, false),
|
||||
map(0x24, MINECRAFT_1_19_1, false),
|
||||
map(0x27, MINECRAFT_1_20_2, false));
|
||||
map(0x27, MINECRAFT_1_20_2, false),
|
||||
map(0x28, MINECRAFT_1_20_3, false));
|
||||
serverbound.register(
|
||||
FinishedUpdate.class, FinishedUpdate::new, map(0x0B, MINECRAFT_1_20_2, false));
|
||||
|
||||
@ -385,7 +396,10 @@ public enum StateRegistry {
|
||||
map(0x3E, MINECRAFT_1_19_1, true),
|
||||
map(0x3D, MINECRAFT_1_19_3, true),
|
||||
map(0x41, MINECRAFT_1_19_4, true),
|
||||
map(0x43, MINECRAFT_1_20_2, true));
|
||||
map(0x43, MINECRAFT_1_20_2, true),
|
||||
map(0x45, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
RemoveResourcePack.class, RemoveResourcePack::new, map(0x43, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(
|
||||
ResourcePackRequest.class,
|
||||
ResourcePackRequest::new,
|
||||
@ -403,7 +417,8 @@ public enum StateRegistry {
|
||||
map(0x3D, MINECRAFT_1_19_1, false),
|
||||
map(0x3C, MINECRAFT_1_19_3, false),
|
||||
map(0x40, MINECRAFT_1_19_4, false),
|
||||
map(0x42, MINECRAFT_1_20_2, false));
|
||||
map(0x42, MINECRAFT_1_20_2, false),
|
||||
map(0x44, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(
|
||||
HeaderAndFooter.class,
|
||||
HeaderAndFooter::new,
|
||||
@ -422,7 +437,8 @@ public enum StateRegistry {
|
||||
map(0x63, MINECRAFT_1_19_1, true),
|
||||
map(0x61, MINECRAFT_1_19_3, true),
|
||||
map(0x65, MINECRAFT_1_19_4, true),
|
||||
map(0x68, MINECRAFT_1_20_2, true));
|
||||
map(0x68, MINECRAFT_1_20_2, true),
|
||||
map(0x6A, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
LegacyTitlePacket.class,
|
||||
LegacyTitlePacket::new,
|
||||
@ -440,7 +456,8 @@ public enum StateRegistry {
|
||||
map(0x5B, MINECRAFT_1_19_1, true),
|
||||
map(0x59, MINECRAFT_1_19_3, true),
|
||||
map(0x5D, MINECRAFT_1_19_4, true),
|
||||
map(0x5F, MINECRAFT_1_20_2, true));
|
||||
map(0x5F, MINECRAFT_1_20_2, true),
|
||||
map(0x61, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
TitleTextPacket.class,
|
||||
TitleTextPacket::new,
|
||||
@ -449,7 +466,8 @@ public enum StateRegistry {
|
||||
map(0x5D, MINECRAFT_1_19_1, true),
|
||||
map(0x5B, MINECRAFT_1_19_3, true),
|
||||
map(0x5F, MINECRAFT_1_19_4, true),
|
||||
map(0x61, MINECRAFT_1_20_2, true));
|
||||
map(0x61, MINECRAFT_1_20_2, true),
|
||||
map(0x63, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
TitleActionbarPacket.class,
|
||||
TitleActionbarPacket::new,
|
||||
@ -458,7 +476,8 @@ public enum StateRegistry {
|
||||
map(0x43, MINECRAFT_1_19_1, true),
|
||||
map(0x42, MINECRAFT_1_19_3, true),
|
||||
map(0x46, MINECRAFT_1_19_4, true),
|
||||
map(0x48, MINECRAFT_1_20_2, true));
|
||||
map(0x48, MINECRAFT_1_20_2, true),
|
||||
map(0x4A, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
TitleTimesPacket.class,
|
||||
TitleTimesPacket::new,
|
||||
@ -467,7 +486,8 @@ public enum StateRegistry {
|
||||
map(0x5E, MINECRAFT_1_19_1, true),
|
||||
map(0x5C, MINECRAFT_1_19_3, true),
|
||||
map(0x60, MINECRAFT_1_19_4, true),
|
||||
map(0x62, MINECRAFT_1_20_2, true));
|
||||
map(0x62, MINECRAFT_1_20_2, true),
|
||||
map(0x64, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
TitleClearPacket.class,
|
||||
TitleClearPacket::new,
|
||||
@ -507,7 +527,8 @@ public enum StateRegistry {
|
||||
map(0x62, MINECRAFT_1_19_1, true),
|
||||
map(0x60, MINECRAFT_1_19_3, true),
|
||||
map(0x64, MINECRAFT_1_19_4, true),
|
||||
map(0x67, MINECRAFT_1_20_2, true));
|
||||
map(0x67, MINECRAFT_1_20_2, true),
|
||||
map(0x69, MINECRAFT_1_20_3, true));
|
||||
clientbound.register(
|
||||
PlayerChatCompletion.class,
|
||||
PlayerChatCompletion::new,
|
||||
@ -522,8 +543,13 @@ public enum StateRegistry {
|
||||
map(0x42, MINECRAFT_1_19_1, false),
|
||||
map(0x41, MINECRAFT_1_19_3, false),
|
||||
map(0x45, MINECRAFT_1_19_4, false),
|
||||
map(0x47, MINECRAFT_1_20_2, false));
|
||||
clientbound.register(StartUpdate.class, StartUpdate::new, map(0x65, MINECRAFT_1_20_2, false));
|
||||
map(0x47, MINECRAFT_1_20_2, false),
|
||||
map(0x49, MINECRAFT_1_20_3, false));
|
||||
clientbound.register(
|
||||
StartUpdate.class,
|
||||
StartUpdate::new,
|
||||
map(0x65, MINECRAFT_1_20_2, false),
|
||||
map(0x67, MINECRAFT_1_20_3, false));
|
||||
}
|
||||
},
|
||||
LOGIN {
|
||||
|
@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.UUID;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@ -35,7 +36,7 @@ public class BossBar implements MinecraftPacket {
|
||||
public static final int UPDATE_PROPERTIES = 5;
|
||||
private @Nullable UUID uuid;
|
||||
private int action;
|
||||
private @Nullable String name;
|
||||
private @Nullable ComponentHolder name;
|
||||
private float percent;
|
||||
private int color;
|
||||
private int overlay;
|
||||
@ -60,11 +61,11 @@ public class BossBar implements MinecraftPacket {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
public @Nullable ComponentHolder getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
public void setName(ComponentHolder name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ -119,7 +120,7 @@ public class BossBar implements MinecraftPacket {
|
||||
this.action = ProtocolUtils.readVarInt(buf);
|
||||
switch (action) {
|
||||
case ADD:
|
||||
this.name = ProtocolUtils.readString(buf);
|
||||
this.name = ComponentHolder.read(buf, version);
|
||||
this.percent = buf.readFloat();
|
||||
this.color = ProtocolUtils.readVarInt(buf);
|
||||
this.overlay = ProtocolUtils.readVarInt(buf);
|
||||
@ -131,7 +132,7 @@ public class BossBar implements MinecraftPacket {
|
||||
this.percent = buf.readFloat();
|
||||
break;
|
||||
case UPDATE_NAME:
|
||||
this.name = ProtocolUtils.readString(buf);
|
||||
this.name = ComponentHolder.read(buf, version);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
this.color = ProtocolUtils.readVarInt(buf);
|
||||
@ -157,7 +158,7 @@ public class BossBar implements MinecraftPacket {
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, name);
|
||||
name.write(buf, version);
|
||||
buf.writeFloat(percent);
|
||||
ProtocolUtils.writeVarInt(buf, color);
|
||||
ProtocolUtils.writeVarInt(buf, overlay);
|
||||
@ -172,7 +173,7 @@ public class BossBar implements MinecraftPacket {
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("No name specified!");
|
||||
}
|
||||
ProtocolUtils.writeString(buf, name);
|
||||
name.write(buf, version);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
ProtocolUtils.writeVarInt(buf, color);
|
||||
|
@ -17,39 +17,36 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import static com.velocitypowered.proxy.protocol.ProtocolUtils.writeString;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
public class HeaderAndFooter implements MinecraftPacket {
|
||||
|
||||
private static final String EMPTY_COMPONENT = "{\"translate\":\"\"}";
|
||||
private static final HeaderAndFooter RESET = new HeaderAndFooter();
|
||||
|
||||
private final String header;
|
||||
private final String footer;
|
||||
private final ComponentHolder header;
|
||||
private final ComponentHolder footer;
|
||||
|
||||
public HeaderAndFooter() {
|
||||
this(EMPTY_COMPONENT, EMPTY_COMPONENT);
|
||||
this(ComponentHolder.EMPTY, ComponentHolder.EMPTY);
|
||||
}
|
||||
|
||||
public HeaderAndFooter(String header, String footer) {
|
||||
public HeaderAndFooter(ComponentHolder header, ComponentHolder footer) {
|
||||
this.header = Preconditions.checkNotNull(header, "header");
|
||||
this.footer = Preconditions.checkNotNull(footer, "footer");
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
public ComponentHolder getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public String getFooter() {
|
||||
public ComponentHolder getFooter() {
|
||||
return footer;
|
||||
}
|
||||
|
||||
@ -60,8 +57,8 @@ public class HeaderAndFooter implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
|
||||
writeString(buf, header);
|
||||
writeString(buf, footer);
|
||||
header.write(buf, version);
|
||||
footer.write(buf, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,8 +68,8 @@ public class HeaderAndFooter implements MinecraftPacket {
|
||||
|
||||
public static HeaderAndFooter create(Component header,
|
||||
Component footer, ProtocolVersion protocolVersion) {
|
||||
GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(protocolVersion);
|
||||
return new HeaderAndFooter(serializer.serialize(header), serializer.serialize(footer));
|
||||
return new HeaderAndFooter(new ComponentHolder(protocolVersion, header),
|
||||
new ComponentHolder(protocolVersion, footer));
|
||||
}
|
||||
|
||||
public static HeaderAndFooter reset() {
|
||||
|
@ -255,12 +255,12 @@ public class JoinGame implements MinecraftPacket {
|
||||
this.previousGamemode = buf.readByte();
|
||||
|
||||
this.levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf));
|
||||
this.registry = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
this.registry = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
String dimensionIdentifier;
|
||||
String levelName = null;
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0
|
||||
&& version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) {
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER);
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, JOINGAME_READER);
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
@ -390,10 +390,10 @@ public class JoinGame implements MinecraftPacket {
|
||||
buf.writeByte(previousGamemode);
|
||||
|
||||
ProtocolUtils.writeStringArray(buf, levelNames.toArray(String[]::new));
|
||||
ProtocolUtils.writeCompoundTag(buf, this.registry);
|
||||
ProtocolUtils.writeBinaryTag(buf, version, this.registry);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0
|
||||
&& version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) {
|
||||
ProtocolUtils.writeCompoundTag(buf, currentDimensionData);
|
||||
ProtocolUtils.writeBinaryTag(buf, version, currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018-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.packet;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class RemoveResourcePack implements MinecraftPacket {
|
||||
|
||||
private UUID id;
|
||||
|
||||
public RemoveResourcePack() {
|
||||
}
|
||||
|
||||
public RemoveResourcePack(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
this.id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeUuid(buf, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MinecraftSessionHandler handler) {
|
||||
return handler.handle(this);
|
||||
}
|
||||
}
|
@ -25,24 +25,33 @@ import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ResourcePackRequest implements MinecraftPacket {
|
||||
|
||||
private @MonotonicNonNull UUID id; // 1.20.3+
|
||||
private @MonotonicNonNull String url;
|
||||
private @MonotonicNonNull String hash;
|
||||
private boolean isRequired; // 1.17+
|
||||
private @Nullable Component prompt; // 1.17+
|
||||
private @Nullable ComponentHolder prompt; // 1.17+
|
||||
|
||||
private static final Pattern PLAUSIBLE_SHA1_HASH = Pattern.compile("^[a-z0-9]{40}$"); // 1.20.2+
|
||||
|
||||
public @Nullable UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public @Nullable String getUrl() {
|
||||
return url;
|
||||
}
|
||||
@ -67,22 +76,25 @@ public class ResourcePackRequest implements MinecraftPacket {
|
||||
isRequired = required;
|
||||
}
|
||||
|
||||
public @Nullable Component getPrompt() {
|
||||
public @Nullable ComponentHolder getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
public void setPrompt(Component prompt) {
|
||||
public void setPrompt(ComponentHolder prompt) {
|
||||
this.prompt = prompt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) {
|
||||
this.id = ProtocolUtils.readUuid(buf);
|
||||
}
|
||||
this.url = ProtocolUtils.readString(buf);
|
||||
this.hash = ProtocolUtils.readString(buf);
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) {
|
||||
this.isRequired = buf.readBoolean();
|
||||
if (buf.readBoolean()) {
|
||||
this.prompt = GsonComponentSerializer.gson().deserialize(ProtocolUtils.readString(buf));
|
||||
this.prompt = ComponentHolder.read(buf, protocolVersion);
|
||||
} else {
|
||||
this.prompt = null;
|
||||
}
|
||||
@ -91,6 +103,12 @@ public class ResourcePackRequest implements MinecraftPacket {
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) {
|
||||
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!");
|
||||
}
|
||||
@ -100,7 +118,7 @@ public class ResourcePackRequest implements MinecraftPacket {
|
||||
buf.writeBoolean(isRequired);
|
||||
if (prompt != null) {
|
||||
buf.writeBoolean(true);
|
||||
ProtocolUtils.writeString(buf, GsonComponentSerializer.gson().serialize(prompt));
|
||||
prompt.write(buf, protocolVersion);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
}
|
||||
@ -109,7 +127,8 @@ public class ResourcePackRequest implements MinecraftPacket {
|
||||
|
||||
public VelocityResourcePackInfo toServerPromptedPack() {
|
||||
ResourcePackInfo.Builder builder =
|
||||
new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)).setPrompt(prompt)
|
||||
new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url))
|
||||
.setId(id).setPrompt(prompt == null ? null : prompt.getComponent())
|
||||
.setShouldForce(isRequired).setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER);
|
||||
|
||||
if (hash != null && !hash.isEmpty()) {
|
||||
|
@ -165,7 +165,7 @@ public class Respawn implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0
|
||||
&& version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) {
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader());
|
||||
this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, version, BinaryTagIO.reader());
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
} else {
|
||||
dimensionIdentifier = ProtocolUtils.readString(buf);
|
||||
@ -210,7 +210,7 @@ public class Respawn implements MinecraftPacket {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0
|
||||
&& version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) {
|
||||
ProtocolUtils.writeCompoundTag(buf, currentDimensionData);
|
||||
ProtocolUtils.writeBinaryTag(buf, version, currentDimensionData);
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());
|
||||
|
@ -22,23 +22,23 @@ import com.velocitypowered.api.util.Favicon;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public class ServerData implements MinecraftPacket {
|
||||
|
||||
private @Nullable Component description;
|
||||
private @Nullable ComponentHolder description;
|
||||
private @Nullable Favicon favicon;
|
||||
private boolean secureChatEnforced; // Added in 1.19.1
|
||||
|
||||
public ServerData() {
|
||||
}
|
||||
|
||||
public ServerData(@Nullable Component description, @Nullable Favicon favicon,
|
||||
boolean secureChatEnforced) {
|
||||
public ServerData(@Nullable ComponentHolder description, @Nullable Favicon favicon,
|
||||
boolean secureChatEnforced) {
|
||||
this.description = description;
|
||||
this.favicon = favicon;
|
||||
this.secureChatEnforced = secureChatEnforced;
|
||||
@ -48,8 +48,7 @@ public class ServerData implements MinecraftPacket {
|
||||
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
|
||||
ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19_4) >= 0 || buf.readBoolean()) {
|
||||
this.description = ProtocolUtils.getJsonChatSerializer(protocolVersion)
|
||||
.deserialize(ProtocolUtils.readString(buf));
|
||||
this.description = ComponentHolder.read(buf, protocolVersion);
|
||||
}
|
||||
if (buf.readBoolean()) {
|
||||
String iconBase64;
|
||||
@ -77,10 +76,7 @@ public class ServerData implements MinecraftPacket {
|
||||
buf.writeBoolean(hasDescription);
|
||||
}
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19_4) >= 0 || hasDescription) {
|
||||
ProtocolUtils.writeString(
|
||||
buf,
|
||||
ProtocolUtils.getJsonChatSerializer(protocolVersion).serialize(this.description)
|
||||
);
|
||||
this.description.write(buf, protocolVersion);
|
||||
}
|
||||
|
||||
boolean hasFavicon = this.favicon != null;
|
||||
@ -108,7 +104,7 @@ public class ServerData implements MinecraftPacket {
|
||||
return handler.handle(this);
|
||||
}
|
||||
|
||||
public @Nullable Component getDescription() {
|
||||
public @Nullable ComponentHolder getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
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.RemoteChatSession;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.ArrayList;
|
||||
@ -31,7 +32,6 @@ import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class UpsertPlayerInfo implements MinecraftPacket {
|
||||
@ -179,16 +179,14 @@ public class UpsertPlayerInfo implements MinecraftPacket {
|
||||
}),
|
||||
UPDATE_DISPLAY_NAME((version, buf, info) -> { // read
|
||||
if (buf.readBoolean()) {
|
||||
info.displayName = ProtocolUtils.getJsonChatSerializer(version)
|
||||
.deserialize(ProtocolUtils.readString(buf));
|
||||
info.displayName = ComponentHolder.read(buf, version);
|
||||
} else {
|
||||
info.displayName = null;
|
||||
}
|
||||
}, (version, buf, info) -> { // write
|
||||
buf.writeBoolean(info.displayName != null);
|
||||
if (info.displayName != null) {
|
||||
ProtocolUtils.writeString(buf, ProtocolUtils.getJsonChatSerializer(version)
|
||||
.serialize(info.displayName));
|
||||
info.displayName.write(buf, version);
|
||||
}
|
||||
});
|
||||
|
||||
@ -219,7 +217,7 @@ public class UpsertPlayerInfo implements MinecraftPacket {
|
||||
private int latency;
|
||||
private int gameMode;
|
||||
@Nullable
|
||||
private Component displayName;
|
||||
private ComponentHolder displayName;
|
||||
@Nullable
|
||||
private RemoteChatSession chatSession;
|
||||
|
||||
@ -248,7 +246,7 @@ public class UpsertPlayerInfo implements MinecraftPacket {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Component getDisplayName() {
|
||||
public ComponentHolder getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@ -273,7 +271,7 @@ public class UpsertPlayerInfo implements MinecraftPacket {
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
public void setDisplayName(@Nullable Component displayName) {
|
||||
public void setDisplayName(@Nullable ComponentHolder displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
package com.velocitypowered.proxy.protocol.packet.chat;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.StringBinaryTag;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
public class ComponentHolder {
|
||||
|
||||
public static ComponentHolder EMPTY = new ComponentHolder(null, Component.empty());
|
||||
static {
|
||||
EMPTY.json = "{\"text\":\"\"}";
|
||||
EMPTY.binaryTag = StringBinaryTag.stringBinaryTag("");
|
||||
}
|
||||
|
||||
private final ProtocolVersion version;
|
||||
private @MonotonicNonNull Component component;
|
||||
private @MonotonicNonNull String json;
|
||||
private @MonotonicNonNull BinaryTag binaryTag;
|
||||
|
||||
public ComponentHolder(ProtocolVersion version, Component component) {
|
||||
this.version = version;
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public ComponentHolder(ProtocolVersion version, String json) {
|
||||
this.version = version;
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public ComponentHolder(ProtocolVersion version, BinaryTag binaryTag) {
|
||||
this.version = version;
|
||||
this.binaryTag = binaryTag;
|
||||
}
|
||||
|
||||
public Component getComponent() {
|
||||
if (component == null) {
|
||||
if (json != null) {
|
||||
component = ProtocolUtils.getJsonChatSerializer(version).deserialize(json);
|
||||
} else if (binaryTag != null) {
|
||||
//TODO component = deserialize(binaryTag);
|
||||
throw new UnsupportedOperationException("binary tag -> component not implemented yet");
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
public String getJson() {
|
||||
if (json == null) {
|
||||
json = ProtocolUtils.getJsonChatSerializer(version).serialize(getComponent());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
public BinaryTag getBinaryTag() {
|
||||
if (binaryTag == null) {
|
||||
//TODO binaryTag = serialize(getComponent());
|
||||
throw new UnsupportedOperationException("component -> binary tag not implemented yet");
|
||||
}
|
||||
return binaryTag;
|
||||
}
|
||||
|
||||
public static ComponentHolder read(ByteBuf buf, ProtocolVersion version) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) {
|
||||
return new ComponentHolder(version, ProtocolUtils.readBinaryTag(buf, version, BinaryTagIO.reader()));
|
||||
} else {
|
||||
return new ComponentHolder(version, ProtocolUtils.readString(buf));
|
||||
}
|
||||
}
|
||||
|
||||
public void write(ByteBuf buf, ProtocolVersion version) {
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_3) >= 0) {
|
||||
ProtocolUtils.writeBinaryTag(buf, version, getBinaryTag());
|
||||
} else {
|
||||
ProtocolUtils.writeString(buf, getJson());
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
|
||||
package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo;
|
||||
@ -27,6 +28,8 @@ import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo;
|
||||
*/
|
||||
public interface InternalTabList extends TabList {
|
||||
|
||||
Player getPlayer();
|
||||
|
||||
default void processLegacy(LegacyPlayerListItem packet) {
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,11 @@ public class KeyedVelocityTabList implements InternalTabList {
|
||||
this.connection = player.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setHeaderAndFooter(Component header, Component footer) {
|
||||
|
@ -19,6 +19,7 @@ package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.player.ChatSession;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
@ -27,6 +28,7 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.console.VelocityConsole;
|
||||
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.RemoteChatSession;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -64,6 +66,11 @@ public class VelocityTabList implements InternalTabList {
|
||||
this.entries = Maps.newHashMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeaderAndFooter(Component header, Component footer) {
|
||||
Preconditions.checkNotNull(header, "header");
|
||||
@ -103,7 +110,8 @@ public class VelocityTabList implements InternalTabList {
|
||||
if (!Objects.equals(previousEntry.getDisplayNameComponent().orElse(null),
|
||||
entry.getDisplayNameComponent().orElse(null))) {
|
||||
actions.add(UpsertPlayerInfo.Action.UPDATE_DISPLAY_NAME);
|
||||
playerInfoEntry.setDisplayName(entry.getDisplayNameComponent().get());
|
||||
playerInfoEntry.setDisplayName(new ComponentHolder(player.getProtocolVersion(),
|
||||
entry.getDisplayNameComponent().get()));
|
||||
}
|
||||
if (!Objects.equals(previousEntry.getLatency(), entry.getLatency())) {
|
||||
actions.add(UpsertPlayerInfo.Action.UPDATE_LATENCY);
|
||||
@ -132,7 +140,8 @@ public class VelocityTabList implements InternalTabList {
|
||||
playerInfoEntry.setProfile(entry.getProfile());
|
||||
if (entry.getDisplayNameComponent().isPresent()) {
|
||||
actions.add(UpsertPlayerInfo.Action.UPDATE_DISPLAY_NAME);
|
||||
playerInfoEntry.setDisplayName(entry.getDisplayNameComponent().get());
|
||||
playerInfoEntry.setDisplayName(new ComponentHolder(player.getProtocolVersion(),
|
||||
entry.getDisplayNameComponent().get()));
|
||||
}
|
||||
if (entry.getChatSession() != null) {
|
||||
actions.add(UpsertPlayerInfo.Action.INITIALIZE_CHAT);
|
||||
@ -243,7 +252,7 @@ public class VelocityTabList implements InternalTabList {
|
||||
currentEntry.setLatencyWithoutUpdate(entry.getLatency());
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfo.Action.UPDATE_DISPLAY_NAME)) {
|
||||
currentEntry.setDisplayNameWithoutUpdate(entry.getDisplayName());
|
||||
currentEntry.setDisplayNameWithoutUpdate(entry.getDisplayName().getComponent());
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfo.Action.INITIALIZE_CHAT)) {
|
||||
currentEntry.setChatSession(entry.getChatSession());
|
||||
|
@ -23,6 +23,8 @@ import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@ -78,7 +80,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
||||
public TabListEntry setDisplayName(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
UpsertPlayerInfo.Entry upsertEntry = this.tabList.createRawEntry(this);
|
||||
upsertEntry.setDisplayName(displayName);
|
||||
upsertEntry.setDisplayName(new ComponentHolder(this.tabList.getPlayer().getProtocolVersion(), displayName));
|
||||
this.tabList.emitActionRaw(UpsertPlayerInfo.Action.UPDATE_DISPLAY_NAME, upsertEntry);
|
||||
return this;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ package com.velocitypowered.proxy.util.bossbar;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.util.collect.Enum2IntMap;
|
||||
import com.velocitypowered.proxy.util.concurrent.Once;
|
||||
import java.util.Collections;
|
||||
@ -212,8 +212,7 @@ public class AdventureBossBarManager implements BossBar.Listener {
|
||||
.proxy.protocol.packet.BossBar();
|
||||
packet.setUuid(this.id);
|
||||
packet.setAction(com.velocitypowered.proxy.protocol.packet.BossBar.ADD);
|
||||
packet.setName(ProtocolUtils.getJsonChatSerializer(player.getProtocolVersion())
|
||||
.serialize(player.translateMessage(bar.name())));
|
||||
packet.setName(new ComponentHolder(player.getProtocolVersion(), player.translateMessage(bar.name())));
|
||||
packet.setColor(COLORS_TO_PROTOCOL.get(bar.color()));
|
||||
packet.setOverlay(OVERLAY_TO_PROTOCOL.get(bar.overlay()));
|
||||
packet.setPercent(bar.progress());
|
||||
@ -247,7 +246,7 @@ public class AdventureBossBarManager implements BossBar.Listener {
|
||||
.proxy.protocol.packet.BossBar();
|
||||
packet.setUuid(this.id);
|
||||
packet.setAction(com.velocitypowered.proxy.protocol.packet.BossBar.UPDATE_NAME);
|
||||
packet.setName(ProtocolUtils.getJsonChatSerializer(version).serialize(name));
|
||||
packet.setName(new ComponentHolder(version, name));
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren