|
|
|
|
@@ -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);
|
|
|
|
|
}
|
|
|
|
|
|