mirror of
https://github.com/PaperMC/Velocity.git
synced 2026-02-17 14:37:43 +01:00
Current work on migrating chat over to a registry
This commit is contained in:
@@ -318,7 +318,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
Component translated = translateMessage(message);
|
||||
|
||||
connection.write(ChatBuilder.builder(this.getProtocolVersion())
|
||||
.component(translated).forIdentity(identity).toClient());
|
||||
.component(translated).forIdentity(identity).toClient(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -332,7 +332,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
connection.write(ChatBuilder.builder(this.getProtocolVersion())
|
||||
.component(translated).forIdentity(identity)
|
||||
.setType(type == MessageType.CHAT ? ChatBuilder.ChatType.CHAT : ChatBuilder.ChatType.SYSTEM)
|
||||
.toClient());
|
||||
.toClient(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,80 +30,148 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
*/
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.format.TextFormat;
|
||||
import net.kyori.adventure.translation.Translatable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// TODO Implement
|
||||
public class ChatData {
|
||||
/*
|
||||
private static final ListBinaryTag EMPTY_LIST_TAG = ListBinaryTag.empty();
|
||||
|
||||
private static final ListBinaryTag EMPTY_LIST_TAG = ListBinaryTag.empty();
|
||||
private final String identifier;
|
||||
private final int id;
|
||||
|
||||
private final String identifier;
|
||||
private final int id;
|
||||
private final Map<>
|
||||
public ChatData(int id, String identifier) {
|
||||
this.id = id;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an entry in the registry.
|
||||
*
|
||||
* @param binaryTag the binary tag to decode.
|
||||
* @param version the version to decode for.
|
||||
* @return The decoded ChatData
|
||||
*/
|
||||
public static ChatData decodeRegistryEntry(CompoundBinaryTag binaryTag, ProtocolVersion version) {
|
||||
final String registryIdentifier = binaryTag.getString("name");
|
||||
final Integer id = binaryTag.getInt("id");
|
||||
|
||||
public static class Decoration implements Translatable {
|
||||
CompoundBinaryTag element = binaryTag.getCompound("element");
|
||||
ChatData decodedChatData = decodeElementCompound(element);
|
||||
return decodedChatData.annotateWith(id, registryIdentifier);
|
||||
}
|
||||
|
||||
private final List<String> parameters;
|
||||
private final List<TextFormat> style;
|
||||
private final String translationKey;
|
||||
private ChatData annotateWith(Integer id, String registryIdentifier) {
|
||||
return new ChatData(id, registryIdentifier);
|
||||
}
|
||||
|
||||
public List<String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
private static ChatData decodeElementCompound(CompoundBinaryTag element) {
|
||||
System.out.println(element);
|
||||
final CompoundBinaryTag chatCompund = element.getCompound("chat");
|
||||
|
||||
public List<TextFormat> getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
public Decoration(List<String> parameters, List<TextFormat> style, String translationKey) {
|
||||
this.parameters = Preconditions.checkNotNull(parameters);
|
||||
this.style = Preconditions.checkNotNull(style);
|
||||
this.translationKey = Preconditions.checkNotNull(translationKey);
|
||||
Preconditions.checkArgument(translationKey.length() > 0);
|
||||
}
|
||||
|
||||
public static Decoration decodeRegistryEntry(CompoundBinaryTag toDecode) {
|
||||
ImmutableList.Builder<String> parameters = ImmutableList.builder();
|
||||
ListBinaryTag paramList = toDecode.getList("parameters", EMPTY_LIST_TAG);
|
||||
if (paramList != EMPTY_LIST_TAG) {
|
||||
paramList.forEach(binaryTag -> parameters.add(binaryTag.toString()));
|
||||
}
|
||||
|
||||
ImmutableList.Builder<TextFormat> style = ImmutableList.builder();
|
||||
CompoundBinaryTag styleList = toDecode.getCompound("style");
|
||||
for (String key : styleList.keySet()) {
|
||||
if ("color".equals(key)) {
|
||||
NamedTextColor color = Preconditions.checkNotNull(
|
||||
NamedTextColor.NAMES.value(styleList.getString(key)));
|
||||
style.add(color);
|
||||
} else {
|
||||
// Key is a Style option instead
|
||||
TextDecoration deco = TextDecoration.NAMES.value(key);
|
||||
// This wouldn't be here if it wasn't applied, but here it goes anyway:
|
||||
byte val = styleList.getByte(key);
|
||||
if (val != 0) {
|
||||
style.add(deco);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String translationKey = toDecode.getString("translation_key");
|
||||
|
||||
return new Decoration(parameters.build(), style.build(), translationKey);
|
||||
}
|
||||
|
||||
public void encodeRegistryEntry(CompoundBinaryTag )
|
||||
Decoration chatDecoration = null;
|
||||
|
||||
final CompoundBinaryTag chatDecorationCompound = chatCompund.getCompound("decoration");
|
||||
if (chatDecorationCompound != CompoundBinaryTag.empty()) {
|
||||
chatDecoration = Decoration.decodeRegistryEntry(chatDecorationCompound);
|
||||
}
|
||||
|
||||
public static enum Priority {
|
||||
SYSTEM,
|
||||
CHAT
|
||||
return new ChatData(-1, "invalid");
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static class Decoration implements Translatable {
|
||||
|
||||
private final List<String> parameters;
|
||||
private final List<TextFormat> style;
|
||||
private final String translationKey;
|
||||
|
||||
public List<String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
*/
|
||||
|
||||
public List<TextFormat> getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String translationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Decoration with the associated data.
|
||||
* @param parameters chat params
|
||||
* @param style chat style
|
||||
* @param translationKey translation key
|
||||
*/
|
||||
public Decoration(List<String> parameters, List<TextFormat> style, String translationKey) {
|
||||
this.parameters = Preconditions.checkNotNull(parameters);
|
||||
this.style = Preconditions.checkNotNull(style);
|
||||
this.translationKey = Preconditions.checkNotNull(translationKey);
|
||||
Preconditions.checkArgument(translationKey.length() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a decoration entry.
|
||||
* @param toDecode Compound Tag to decode
|
||||
* @return the parsed Decoration entry.
|
||||
*/
|
||||
public static Decoration decodeRegistryEntry(CompoundBinaryTag toDecode) {
|
||||
ImmutableList.Builder<String> parameters = ImmutableList.builder();
|
||||
ListBinaryTag paramList = toDecode.getList("parameters", EMPTY_LIST_TAG);
|
||||
if (paramList != EMPTY_LIST_TAG) {
|
||||
paramList.forEach(binaryTag -> parameters.add(binaryTag.toString()));
|
||||
}
|
||||
|
||||
ImmutableList.Builder<TextFormat> style = ImmutableList.builder();
|
||||
CompoundBinaryTag styleList = toDecode.getCompound("style");
|
||||
for (String key : styleList.keySet()) {
|
||||
if ("color".equals(key)) {
|
||||
NamedTextColor color = Preconditions.checkNotNull(
|
||||
NamedTextColor.NAMES.value(styleList.getString(key)));
|
||||
style.add(color);
|
||||
} else {
|
||||
// Key is a Style option instead
|
||||
TextDecoration deco = TextDecoration.NAMES.value(key);
|
||||
// This wouldn't be here if it wasn't applied, but here it goes anyway:
|
||||
byte val = styleList.getByte(key);
|
||||
if (val != 0) {
|
||||
style.add(deco);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String translationKey = toDecode.getString("translation_key");
|
||||
|
||||
return new Decoration(parameters.build(), style.build(), translationKey);
|
||||
}
|
||||
|
||||
public void encodeRegistryEntry(CompoundBinaryTag compoundBinaryTag) {}
|
||||
|
||||
}
|
||||
|
||||
public static enum Priority {
|
||||
SYSTEM,
|
||||
CHAT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 com.google.common.collect.Maps;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
|
||||
import java.util.Map;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
|
||||
|
||||
public final class ChatRegistry {
|
||||
|
||||
private final Map<String, ChatData> registeredChatTypes;
|
||||
|
||||
public ChatRegistry(ImmutableList<ChatData> chatDataImmutableList) {
|
||||
registeredChatTypes = Maps.uniqueIndex(chatDataImmutableList, ChatData::getIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a CompoundTag storing a Chat Type Registry.
|
||||
*
|
||||
* @param compound The Compound to decode
|
||||
* @param version Protocol version
|
||||
* @return an ImmutableList of read ChatData
|
||||
*/
|
||||
public static ImmutableList<ChatData> fromGameData(ListBinaryTag compound, ProtocolVersion version) {
|
||||
final ImmutableList.Builder<ChatData> builder = ImmutableList.builder();
|
||||
for (BinaryTag binaryTag : compound) {
|
||||
if (binaryTag instanceof CompoundBinaryTag) {
|
||||
builder.add(ChatData.decodeRegistryEntry((CompoundBinaryTag) binaryTag, version));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public BinaryTag build() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,12 @@
|
||||
|
||||
package com.velocitypowered.proxy.protocol.packet;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||
import com.velocitypowered.proxy.connection.registry.ChatData;
|
||||
import com.velocitypowered.proxy.connection.registry.ChatRegistry;
|
||||
import com.velocitypowered.proxy.connection.registry.DimensionData;
|
||||
import com.velocitypowered.proxy.connection.registry.DimensionInfo;
|
||||
import com.velocitypowered.proxy.connection.registry.DimensionRegistry;
|
||||
@@ -32,6 +35,8 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JoinGame implements MinecraftPacket {
|
||||
|
||||
private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024);
|
||||
@@ -53,7 +58,7 @@ public class JoinGame implements MinecraftPacket {
|
||||
private CompoundBinaryTag biomeRegistry; // 1.16.2+
|
||||
private int simulationDistance; // 1.18+
|
||||
private @Nullable Pair<String, Long> lastDeathPosition;
|
||||
private CompoundBinaryTag chatTypeRegistry; // placeholder, 1.19+
|
||||
private ChatRegistry chatTypeRegistry; // placeholder, 1.19+
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
@@ -183,11 +188,11 @@ public class JoinGame implements MinecraftPacket {
|
||||
this.lastDeathPosition = lastDeathPosition;
|
||||
}
|
||||
|
||||
public CompoundBinaryTag getChatTypeRegistry() {
|
||||
public ChatRegistry getChatTypeRegistry() {
|
||||
return chatTypeRegistry;
|
||||
}
|
||||
|
||||
public void setChatTypeRegistry(CompoundBinaryTag chatTypeRegistry) {
|
||||
public void setChatTypeRegistry(ChatRegistry chatTypeRegistry) {
|
||||
this.chatTypeRegistry = chatTypeRegistry;
|
||||
}
|
||||
|
||||
@@ -274,9 +279,10 @@ public class JoinGame implements MinecraftPacket {
|
||||
.getList("value", BinaryTagTypes.COMPOUND);
|
||||
this.biomeRegistry = registryContainer.getCompound("minecraft:worldgen/biome");
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) {
|
||||
this.chatTypeRegistry = registryContainer.getCompound("minecraft:chat_type");
|
||||
final ImmutableList<ChatData> chatDataList = ChatRegistry.fromGameData(registryContainer.getCompound("minecraft:chat_type").getList("value"), version);
|
||||
this.chatTypeRegistry = new ChatRegistry(chatDataList);
|
||||
} else {
|
||||
this.chatTypeRegistry = CompoundBinaryTag.empty();
|
||||
this.chatTypeRegistry = null; // TODO: Faux registry?
|
||||
}
|
||||
} else {
|
||||
dimensionRegistryContainer = registryContainer.getList("dimension",
|
||||
@@ -387,7 +393,7 @@ public class JoinGame implements MinecraftPacket {
|
||||
registryContainer.put("minecraft:dimension_type", dimensionRegistryEntry.build());
|
||||
registryContainer.put("minecraft:worldgen/biome", biomeRegistry);
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) {
|
||||
registryContainer.put("minecraft:chat_type", chatTypeRegistry);
|
||||
registryContainer.put("minecraft:chat_type", chatTypeRegistry.build());
|
||||
}
|
||||
} else {
|
||||
registryContainer.put("dimension", encodedDimensionRegistry);
|
||||
|
||||
@@ -21,15 +21,22 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.crypto.SignedChatCommand;
|
||||
import com.velocitypowered.proxy.crypto.SignedChatMessage;
|
||||
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class ChatBuilder {
|
||||
@@ -125,10 +132,10 @@ public class ChatBuilder {
|
||||
*
|
||||
* @return The {@link MinecraftPacket} to send to the client.
|
||||
*/
|
||||
public MinecraftPacket toClient() {
|
||||
public MinecraftPacket toClient(ConnectedPlayer player) {
|
||||
// This is temporary
|
||||
UUID identity = sender == null ? (senderIdentity == null ? Identity.nil().uuid()
|
||||
: senderIdentity.uuid()) : sender.getUniqueId();
|
||||
: senderIdentity.uuid()) : sender.getUniqueId();
|
||||
Component msg = component == null ? Component.text(message) : component;
|
||||
|
||||
if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) {
|
||||
@@ -164,19 +171,45 @@ public class ChatBuilder {
|
||||
return chat;
|
||||
}
|
||||
|
||||
public static enum ChatType {
|
||||
CHAT((byte) 0),
|
||||
SYSTEM((byte) 1),
|
||||
GAME_INFO((byte) 2);
|
||||
public static class ChatType {
|
||||
public static final ChatType CHAT = new ChatType((byte) 0, Key.key("minecraft", "chat"));
|
||||
public static final ChatType SYSTEM = new ChatType((byte) 1, Key.key("minecraft", "system"));
|
||||
public static final ChatType GAME_INFO = new ChatType((byte) 2, Key.key("minecraft", "game_info"));
|
||||
|
||||
private final byte raw;
|
||||
@NonNull
|
||||
private final Key key;
|
||||
|
||||
ChatType(byte raw) {
|
||||
ChatType(byte raw, @NonNull Key key) {
|
||||
Preconditions.checkNotNull(key, "Key cannot be null!");
|
||||
this.raw = raw;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ChatType chatType = (ChatType) o;
|
||||
return raw == chatType.raw && key.equals(chatType.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(raw, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user