Co-authored-by: Bjarne Koll <git@lynxplay.dev>
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Co-authored-by: MiniDigger | Martin <admin@minidigger.dev>
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Co-authored-by: Shane Freeder <theboyetronic@gmail.com>
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
Co-authored-by: Tamion <70228790+notTamion@users.noreply.github.com>
Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com>
This commit is contained in:
Nassim Jahnke
2025-04-12 17:26:44 +02:00
parent 0767902699
commit f00727c57e
2092 changed files with 50551 additions and 48729 deletions

View File

@@ -1,24 +1,18 @@
package io.papermc.paper.adventure;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.BlockNBTComponent;
import net.kyori.adventure.text.Component;
@@ -40,14 +34,9 @@ import net.kyori.adventure.text.format.ShadowColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.minecraft.commands.arguments.selector.SelectorPattern;
import net.minecraft.core.UUIDUtil;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.TagParser;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.network.chat.contents.KeybindContents;
@@ -55,7 +44,6 @@ import net.minecraft.network.chat.contents.ScoreContents;
import net.minecraft.network.chat.contents.TranslatableContents;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.RegistryOps;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.item.Item;
@@ -76,7 +64,7 @@ import static net.kyori.adventure.text.TranslationArgument.numeric;
@DefaultQualifier(NonNull.class)
public final class AdventureCodecs {
public static final Codec<Component> COMPONENT_CODEC = recursive("adventure Component", AdventureCodecs::createCodec);
public static final Codec<Component> COMPONENT_CODEC = recursive("adventure Component", AdventureCodecs::createCodec);
public static final StreamCodec<RegistryFriendlyByteBuf, Component> STREAM_COMPONENT_CODEC = ByteBufCodecs.fromCodecWithRegistriesTrusted(COMPONENT_CODEC);
static final Codec<ShadowColor> SHADOW_COLOR_CODEC = ExtraCodecs.ARGB_COLOR_CODEC.xmap(ShadowColor::shadowColor, ShadowColor::value);
@@ -101,102 +89,92 @@ public final class AdventureCodecs {
return Key.parseable(s) ? DataResult.success(Key.key(s)) : DataResult.error(() -> "Cannot convert " + s + " to adventure Key");
}, Key::asString);
static final Codec<ClickEvent.Action> CLICK_EVENT_ACTION_CODEC = Codec.STRING.comapFlatMap(s -> {
final ClickEvent.@Nullable Action value = ClickEvent.Action.NAMES.value(s);
return value != null ? DataResult.success(value) : DataResult.error(() -> "Cannot convert " + s + " to adventure ClickEvent$Action");
}, ClickEvent.Action.NAMES::keyOrThrow);
static final Codec<ClickEvent> CLICK_EVENT_CODEC = RecordCodecBuilder.create((instance) -> {
return instance.group(
CLICK_EVENT_ACTION_CODEC.fieldOf("action").forGetter(ClickEvent::action),
Codec.STRING.fieldOf("value").forGetter(ClickEvent::value)
).apply(instance, ClickEvent::clickEvent);
/*
* Click
*/
static final MapCodec<ClickEvent> OPEN_URL_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.UNTRUSTED_URI.fieldOf("url").forGetter(a -> URI.create(!a.value().contains("://") ? "https://" + a.value() : a.value()))
).apply(instance, (url) -> ClickEvent.openUrl(url.toString())));
static final MapCodec<ClickEvent> OPEN_FILE_CODEC = mapCodec((instance) -> instance.group(
Codec.STRING.fieldOf("path").forGetter(ClickEvent::value)
).apply(instance, ClickEvent::openFile));
static final MapCodec<ClickEvent> RUN_COMMAND_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
).apply(instance, ClickEvent::runCommand));
static final MapCodec<ClickEvent> SUGGEST_COMMAND_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.CHAT_STRING.fieldOf("command").forGetter(ClickEvent::value)
).apply(instance, ClickEvent::suggestCommand));
static final MapCodec<ClickEvent> CHANGE_PAGE_CODEC = mapCodec((instance) -> instance.group(
ExtraCodecs.POSITIVE_INT.fieldOf("page").forGetter(a -> Integer.parseInt(a.value()))
).apply(instance, ClickEvent::changePage));
static final MapCodec<ClickEvent> COPY_TO_CLIPBOARD_CODEC = mapCodec((instance) -> instance.group(
Codec.STRING.fieldOf("value").forGetter(ClickEvent::value)
).apply(instance, ClickEvent::copyToClipboard));
static final ClickEventType OPEN_URL_CLICK_EVENT_TYPE = new ClickEventType(OPEN_URL_CODEC, "open_url");
static final ClickEventType OPEN_FILE_CLICK_EVENT_TYPE = new ClickEventType(OPEN_FILE_CODEC, "open_file");
static final ClickEventType RUN_COMMAND_CLICK_EVENT_TYPE = new ClickEventType(RUN_COMMAND_CODEC, "run_command");
static final ClickEventType SUGGEST_COMMAND_CLICK_EVENT_TYPE = new ClickEventType(SUGGEST_COMMAND_CODEC, "suggest_command");
static final ClickEventType CHANGE_PAGE_CLICK_EVENT_TYPE = new ClickEventType(CHANGE_PAGE_CODEC, "change_page");
static final ClickEventType COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE = new ClickEventType(COPY_TO_CLIPBOARD_CODEC, "copy_to_clipboard");
static final Codec<ClickEventType> CLICK_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new ClickEventType[]{OPEN_URL_CLICK_EVENT_TYPE, OPEN_FILE_CLICK_EVENT_TYPE, RUN_COMMAND_CLICK_EVENT_TYPE, SUGGEST_COMMAND_CLICK_EVENT_TYPE, CHANGE_PAGE_CLICK_EVENT_TYPE, COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE});
record ClickEventType(MapCodec<ClickEvent> codec, String id) implements StringRepresentable {
@Override
public String getSerializedName() {
return this.id;
}
}
private static final Function<ClickEvent, ClickEventType> GET_CLICK_EVENT_TYPE = he -> {
if (he.action() == ClickEvent.Action.OPEN_URL) {
return OPEN_URL_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.OPEN_FILE) {
return OPEN_FILE_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.RUN_COMMAND) {
return RUN_COMMAND_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.SUGGEST_COMMAND) {
return SUGGEST_COMMAND_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.CHANGE_PAGE) {
return CHANGE_PAGE_CLICK_EVENT_TYPE;
} else if (he.action() == ClickEvent.Action.COPY_TO_CLIPBOARD) {
return COPY_TO_CLIPBOARD_CLICK_EVENT_TYPE;
} else {
throw new IllegalStateException();
}
};
static final Codec<ClickEvent> CLICK_EVENT_CODEC = CLICK_EVENT_TYPE_CODEC.dispatch("action", GET_CLICK_EVENT_TYPE, ClickEventType::codec);
/*
* HOVER
*/
static final MapCodec<HoverEvent<Component>> SHOW_TEXT_CODEC = mapCodec((instance) -> instance.group(
COMPONENT_CODEC.fieldOf("value").forGetter(HoverEvent::value)
).apply(instance, HoverEvent::showText));
static final MapCodec<HoverEvent<HoverEvent.ShowEntity>> SHOW_ENTITY_CODEC = mapCodec((instance) -> instance.group(
KEY_CODEC.fieldOf("id").forGetter(a -> a.value().type()),
UUIDUtil.LENIENT_CODEC.fieldOf("uuid").forGetter(a -> a.value().id()),
COMPONENT_CODEC.lenientOptionalFieldOf("name").forGetter(a -> Optional.ofNullable(a.value().name()))
).apply(instance, (key, uuid, component) -> HoverEvent.showEntity(key, uuid, component.orElse(null))));
static final MapCodec<HoverEvent<HoverEvent.ShowItem>> SHOW_ITEM_CODEC = net.minecraft.network.chat.HoverEvent.ShowItem.CODEC.xmap(internal -> {
@Subst("key") final String typeKey = internal.item().getItemHolder().unwrapKey().orElseThrow().location().toString();
return HoverEvent.showItem(Key.key(typeKey), internal.item().getCount(), PaperAdventure.asAdventure(internal.item().getComponentsPatch()));
}, adventure -> {
final Item itemType = BuiltInRegistries.ITEM.getValue(PaperAdventure.asVanilla(adventure.value().item()));
final Map<Key, DataComponentValue> dataComponentsMap = adventure.value().dataComponents();
final ItemStack stack = new ItemStack(BuiltInRegistries.ITEM.wrapAsHolder(itemType), adventure.value().count(), PaperAdventure.asVanilla(dataComponentsMap));
return new net.minecraft.network.chat.HoverEvent.ShowItem(stack);
});
static Codec<HoverEvent.ShowEntity> showEntityCodec(final Codec<Component> componentCodec) {
return RecordCodecBuilder.create((instance) -> {
return instance.group(
KEY_CODEC.fieldOf("type").forGetter(HoverEvent.ShowEntity::type),
UUIDUtil.LENIENT_CODEC.fieldOf("id").forGetter(HoverEvent.ShowEntity::id),
componentCodec.lenientOptionalFieldOf("name").forGetter(he -> Optional.ofNullable(he.name()))
).apply(instance, (key, uuid, component) -> {
return HoverEvent.ShowEntity.showEntity(key, uuid, component.orElse(null));
});
});
}
static final HoverEventType<HoverEvent.ShowEntity> SHOW_ENTITY_HOVER_EVENT_TYPE = new HoverEventType<>(SHOW_ENTITY_CODEC, "show_entity");
static final HoverEventType<HoverEvent.ShowItem> SHOW_ITEM_HOVER_EVENT_TYPE = new HoverEventType<>(SHOW_ITEM_CODEC, "show_item");
static final HoverEventType<Component> SHOW_TEXT_HOVER_EVENT_TYPE = new HoverEventType<>(SHOW_TEXT_CODEC, "show_text");
static final Codec<HoverEventType<?>> HOVER_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new HoverEventType<?>[]{SHOW_ENTITY_HOVER_EVENT_TYPE, SHOW_ITEM_HOVER_EVENT_TYPE, SHOW_TEXT_HOVER_EVENT_TYPE});
static Codec<HoverEvent.ShowItem> showItemCodec(final Codec<Component> componentCodec) {
return net.minecraft.network.chat.HoverEvent.ItemStackInfo.CODEC.xmap(isi -> {
@Subst("key") final String typeKey = isi.item.unwrapKey().orElseThrow().location().toString();
return HoverEvent.ShowItem.showItem(Key.key(typeKey), isi.count, PaperAdventure.asAdventure(isi.getItemStack().getComponentsPatch()));
}, si -> {
final Item itemType = BuiltInRegistries.ITEM.getValue(PaperAdventure.asVanilla(si.item()));
final Map<Key, DataComponentValue> dataComponentsMap = si.dataComponents();
final ItemStack stack = new ItemStack(BuiltInRegistries.ITEM.wrapAsHolder(itemType), si.count(), PaperAdventure.asVanilla(dataComponentsMap));
return new net.minecraft.network.chat.HoverEvent.ItemStackInfo(stack);
});
}
static final HoverEventType<HoverEvent.ShowEntity> SHOW_ENTITY_HOVER_EVENT_TYPE = new HoverEventType<>(AdventureCodecs::showEntityCodec, HoverEvent.Action.SHOW_ENTITY, "show_entity", AdventureCodecs::legacyDeserializeEntity);
static final HoverEventType<HoverEvent.ShowItem> SHOW_ITEM_HOVER_EVENT_TYPE = new HoverEventType<>(AdventureCodecs::showItemCodec, HoverEvent.Action.SHOW_ITEM, "show_item", AdventureCodecs::legacyDeserializeItem);
static final HoverEventType<Component> SHOW_TEXT_HOVER_EVENT_TYPE = new HoverEventType<>(identity(), HoverEvent.Action.SHOW_TEXT, "show_text", (component, registryOps, codec) -> DataResult.success(component));
static final Codec<HoverEventType<?>> HOVER_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new HoverEventType<?>[]{ SHOW_ENTITY_HOVER_EVENT_TYPE, SHOW_ITEM_HOVER_EVENT_TYPE, SHOW_TEXT_HOVER_EVENT_TYPE });
static DataResult<HoverEvent.ShowEntity> legacyDeserializeEntity(final Component component, final @Nullable RegistryOps<?> ops, final Codec<Component> componentCodec) {
try {
final CompoundTag tag = TagParser.parseTag(PlainTextComponentSerializer.plainText().serialize(component));
final DynamicOps<JsonElement> dynamicOps = ops != null ? ops.withParent(JsonOps.INSTANCE) : JsonOps.INSTANCE;
final DataResult<Component> entityNameResult = componentCodec.parse(dynamicOps, JsonParser.parseString(tag.getString("name")));
@Subst("key") final String keyString = tag.getString("type");
final UUID entityUUID = UUID.fromString(tag.getString("id"));
return entityNameResult.map(name -> HoverEvent.ShowEntity.showEntity(Key.key(keyString), entityUUID, name));
} catch (final Exception ex) {
return DataResult.error(() -> "Failed to parse tooltip: " + ex.getMessage());
}
}
static DataResult<HoverEvent.ShowItem> legacyDeserializeItem(final Component component, final @Nullable RegistryOps<?> ops, final Codec<Component> componentCodec) {
try {
final CompoundTag tag = TagParser.parseTag(PlainTextComponentSerializer.plainText().serialize(component));
final DynamicOps<Tag> dynamicOps = ops != null ? ops.withParent(NbtOps.INSTANCE) : NbtOps.INSTANCE;
final DataResult<ItemStack> stackResult = ItemStack.CODEC.parse(dynamicOps, tag);
return stackResult.map(stack -> {
@Subst("key:value") final String location = stack.getItemHolder().unwrapKey().orElseThrow().location().toString();
return HoverEvent.ShowItem.showItem(Key.key(location), stack.getCount(), PaperAdventure.asAdventure(stack.getComponentsPatch()));
});
} catch (final CommandSyntaxException ex) {
return DataResult.error(() -> "Failed to parse item tag: " + ex.getMessage());
}
}
@FunctionalInterface
interface LegacyDeserializer<T> {
DataResult<T> apply(Component component, @Nullable RegistryOps<?> ops, Codec<Component> componentCodec);
}
record HoverEventType<V>(Function<Codec<Component>, MapCodec<HoverEvent<V>>> codec, String id, Function<Codec<Component>, MapCodec<HoverEvent<V>>> legacyCodec) implements StringRepresentable {
HoverEventType(final Function<Codec<Component>, Codec<V>> contentCodec, final HoverEvent.Action<V> action, final String id, final LegacyDeserializer<V> legacyDeserializer) {
this(cc -> contentCodec.apply(cc).xmap(v -> HoverEvent.hoverEvent(action, v), HoverEvent::value).fieldOf("contents"),
id,
codec -> (new Codec<HoverEvent<V>>() {
public <D> DataResult<Pair<HoverEvent<V>, D>> decode(final DynamicOps<D> dynamicOps, final D object) {
return codec.decode(dynamicOps, object).flatMap(pair -> {
final DataResult<V> dataResult;
if (dynamicOps instanceof final RegistryOps<D> registryOps) {
dataResult = legacyDeserializer.apply(pair.getFirst(), registryOps, codec);
} else {
dataResult = legacyDeserializer.apply(pair.getFirst(), null, codec);
}
return dataResult.map(value -> Pair.of(HoverEvent.hoverEvent(action, value), pair.getSecond()));
});
}
public <D> DataResult<D> encode(final HoverEvent<V> hoverEvent, final DynamicOps<D> dynamicOps, final D object) {
return DataResult.error(() -> "Can't encode in legacy format");
}
}).fieldOf("value")
);
}
record HoverEventType<V>(MapCodec<HoverEvent<V>> codec, String id) implements StringRepresentable {
@Override
public String getSerializedName() {
return this.id;
@@ -214,11 +192,12 @@ public final class AdventureCodecs {
throw new IllegalStateException();
}
};
static final Codec<HoverEvent<?>> HOVER_EVENT_CODEC = Codec.withAlternative(
HOVER_EVENT_TYPE_CODEC.<HoverEvent<?>>dispatchMap("action", GET_HOVER_EVENT_TYPE, het -> het.codec.apply(COMPONENT_CODEC)).codec(),
HOVER_EVENT_TYPE_CODEC.<HoverEvent<?>>dispatchMap("action", GET_HOVER_EVENT_TYPE, het -> het.legacyCodec.apply(COMPONENT_CODEC)).codec()
);
static final Codec<HoverEvent<?>> HOVER_EVENT_CODEC = HOVER_EVENT_TYPE_CODEC.dispatch("action", GET_HOVER_EVENT_TYPE, HoverEventType::codec);
/*
* Style
*/
public static final MapCodec<Style> STYLE_MAP_CODEC = mapCodec((instance) -> {
return instance.group(
TEXT_COLOR_CODEC.optionalFieldOf("color").forGetter(nullableGetter(Style::color)),
@@ -228,8 +207,8 @@ public final class AdventureCodecs {
Codec.BOOL.optionalFieldOf("underlined").forGetter(decorationGetter(TextDecoration.UNDERLINED)),
Codec.BOOL.optionalFieldOf("strikethrough").forGetter(decorationGetter(TextDecoration.STRIKETHROUGH)),
Codec.BOOL.optionalFieldOf("obfuscated").forGetter(decorationGetter(TextDecoration.OBFUSCATED)),
CLICK_EVENT_CODEC.optionalFieldOf("clickEvent").forGetter(nullableGetter(Style::clickEvent)),
HOVER_EVENT_CODEC.optionalFieldOf("hoverEvent").forGetter(nullableGetter(Style::hoverEvent)),
CLICK_EVENT_CODEC.optionalFieldOf("click_event").forGetter(nullableGetter(Style::clickEvent)),
HOVER_EVENT_CODEC.optionalFieldOf("hover_event").forGetter(nullableGetter(Style::hoverEvent)),
Codec.STRING.optionalFieldOf("insertion").forGetter(nullableGetter(Style::insertion)),
KEY_CODEC.optionalFieldOf("font").forGetter(nullableGetter(Style::font))
).apply(instance, (textColor, shadowColor, bold, italic, underlined, strikethrough, obfuscated, clickEvent, hoverEvent, insertion, font) -> {
@@ -248,6 +227,10 @@ public final class AdventureCodecs {
});
});
});
/*
* Misc
*/
static Consumer<Boolean> styleBooleanConsumer(final Style.Builder builder, final TextDecoration decoration) {
return b -> builder.decoration(decoration, b);
}

View File

@@ -81,34 +81,34 @@ public final class ChatProcessor {
final boolean listenersOnSyncEvent = canYouHearMe(PlayerChatEvent.getHandlerList());
if (listenersOnAsyncEvent || listenersOnSyncEvent) {
final CraftPlayer player = this.player.getBukkitEntity();
final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server));
this.post(ae);
final AsyncPlayerChatEvent asyncChatEvent = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server));
this.post(asyncChatEvent);
if (listenersOnSyncEvent) {
final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients());
se.setCancelled(ae.isCancelled()); // propagate cancelled state
this.queueIfAsyncOrRunImmediately(new Waitable<Void>() {
final PlayerChatEvent chatEvent = new PlayerChatEvent(player, asyncChatEvent.getMessage(), asyncChatEvent.getFormat(), asyncChatEvent.getRecipients());
chatEvent.setCancelled(asyncChatEvent.isCancelled()); // propagate cancelled state
this.queueIfAsyncOrRunImmediately(new Waitable<>() {
@Override
protected Void evaluate() {
ChatProcessor.this.post(se);
ChatProcessor.this.post(chatEvent);
return null;
}
});
this.readLegacyModifications(se.getMessage(), se.getFormat(), se.getPlayer());
this.readLegacyModifications(chatEvent.getMessage(), chatEvent.getFormat(), chatEvent.getPlayer());
this.processModern(
this.modernRenderer(se.getFormat()),
this.viewersFromLegacy(se.getRecipients()),
this.modernMessage(se.getMessage()),
se.getPlayer(),
se.isCancelled()
this.modernRenderer(chatEvent.getFormat()),
this.viewersFromLegacy(chatEvent.getRecipients()),
this.modernMessage(chatEvent.getMessage()),
chatEvent.getPlayer(),
chatEvent.isCancelled()
);
} else {
this.readLegacyModifications(ae.getMessage(), ae.getFormat(), ae.getPlayer());
this.readLegacyModifications(asyncChatEvent.getMessage(), asyncChatEvent.getFormat(), asyncChatEvent.getPlayer());
this.processModern(
this.modernRenderer(ae.getFormat()),
this.viewersFromLegacy(ae.getRecipients()),
this.modernMessage(ae.getMessage()),
ae.getPlayer(),
ae.isCancelled()
this.modernRenderer(asyncChatEvent.getFormat()),
this.viewersFromLegacy(asyncChatEvent.getRecipients()),
this.modernMessage(asyncChatEvent.getMessage()),
asyncChatEvent.getPlayer(),
asyncChatEvent.isCancelled()
);
}
} else {
@@ -151,14 +151,14 @@ public final class ChatProcessor {
this.post(ae);
final boolean listenersOnSyncEvent = canYouHearMe(ChatEvent.getHandlerList());
if (listenersOnSyncEvent) {
this.queueIfAsyncOrRunImmediately(new Waitable<Void>() {
this.queueIfAsyncOrRunImmediately(new Waitable<>() {
@Override
protected Void evaluate() {
final ChatEvent se = new ChatEvent(player, ae.viewers(), ae.renderer(), ae.message(), ChatProcessor.this.paper$originalMessage/*, ae.usePreviewComponent()*/, signedMessage);
se.setCancelled(ae.isCancelled()); // propagate cancelled state
ChatProcessor.this.post(se);
ChatProcessor.this.readModernModifications(se, renderer);
ChatProcessor.this.complete(se);
final ChatEvent chatEvent = new ChatEvent(player, ae.viewers(), ae.renderer(), ae.message(), ChatProcessor.this.paper$originalMessage/*, ae.usePreviewComponent()*/, signedMessage);
chatEvent.setCancelled(ae.isCancelled()); // propagate cancelled state
ChatProcessor.this.post(chatEvent);
ChatProcessor.this.readModernModifications(chatEvent, renderer);
ChatProcessor.this.complete(chatEvent);
return null;
}
});

View File

@@ -1,6 +1,5 @@
package io.papermc.paper.adventure;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.serialization.JavaOps;
import io.netty.util.AttributeKey;
@@ -134,7 +133,7 @@ public final class PaperAdventure {
public static final Codec<Tag, String, CommandSyntaxException, RuntimeException> NBT_CODEC = new Codec<>() {
@Override
public @NotNull Tag decode(final @NotNull String encoded) throws CommandSyntaxException {
return new TagParser(new StringReader(encoded)).readValue();
return TagParser.parseCompoundFully(encoded);
}
@Override

View File

@@ -17,7 +17,7 @@ import org.intellij.lang.annotations.Subst;
final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer {
public static final NBTLegacyHoverEventSerializer INSTANCE = new NBTLegacyHoverEventSerializer();
private static final Codec<CompoundTag, String, CommandSyntaxException, RuntimeException> SNBT_CODEC = Codec.codec(TagParser::parseTag, Tag::toString);
private static final Codec<CompoundTag, String, CommandSyntaxException, RuntimeException> SNBT_CODEC = Codec.codec(TagParser::parseCompoundFully, Tag::toString);
static final String ITEM_TYPE = "id";
static final String ITEM_COUNT = "Count";
@@ -35,11 +35,11 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try {
final CompoundTag contents = SNBT_CODEC.decode(raw);
final CompoundTag tag = contents.getCompound(ITEM_TAG);
@Subst("key") final String keyString = contents.getString(ITEM_TYPE);
final CompoundTag tag = contents.getCompoundOrEmpty(ITEM_TAG);
@Subst("key") final String keyString = contents.getStringOr(ITEM_TYPE, "");
return HoverEvent.ShowItem.showItem(
Key.key(keyString),
contents.contains(ITEM_COUNT) ? contents.getByte(ITEM_COUNT) : 1,
contents.getByteOr(ITEM_COUNT, (byte) 1),
tag.isEmpty() ? null : BinaryTagHolder.encode(tag, SNBT_CODEC)
);
} catch (final CommandSyntaxException ex) {
@@ -52,11 +52,11 @@ final class NBTLegacyHoverEventSerializer implements LegacyHoverEventSerializer
final String raw = PlainTextComponentSerializer.plainText().serialize(input);
try {
final CompoundTag contents = SNBT_CODEC.decode(raw);
@Subst("key") final String keyString = contents.getString(ENTITY_TYPE);
@Subst("key") final String keyString = contents.getStringOr(ENTITY_TYPE, "");
return HoverEvent.ShowEntity.showEntity(
Key.key(keyString),
UUID.fromString(contents.getString(ENTITY_ID)),
componentCodec.decode(contents.getString(ENTITY_NAME))
UUID.fromString(contents.getStringOr(ENTITY_ID, "")),
componentCodec.decode(contents.getStringOr(ENTITY_NAME, ""))
);
} catch (final CommandSyntaxException ex) {
throw new IOException(ex);