265 lines
10 KiB
Java
265 lines
10 KiB
Java
package net.minecraft.network.chat;
|
|
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonParser;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.DataResult;
|
|
import com.mojang.serialization.DynamicOps;
|
|
import com.mojang.serialization.JsonOps;
|
|
import com.mojang.serialization.Lifecycle;
|
|
import com.mojang.serialization.MapCodec;
|
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.UUID;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.UUIDUtil;
|
|
import net.minecraft.core.component.DataComponentPatch;
|
|
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.chat.HoverEvent.Action.1;
|
|
import net.minecraft.resources.RegistryOps;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.util.StringRepresentable;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class HoverEvent {
|
|
public static final Codec<HoverEvent> CODEC = Codec.withAlternative(HoverEvent.TypedHoverEvent.CODEC.codec(), HoverEvent.TypedHoverEvent.LEGACY_CODEC.codec())
|
|
.xmap(HoverEvent::new, hoverEvent -> hoverEvent.event);
|
|
private final HoverEvent.TypedHoverEvent<?> event;
|
|
|
|
public <T> HoverEvent(HoverEvent.Action<T> action, T value) {
|
|
this(new HoverEvent.TypedHoverEvent<>(action, value));
|
|
}
|
|
|
|
private HoverEvent(HoverEvent.TypedHoverEvent<?> event) {
|
|
this.event = event;
|
|
}
|
|
|
|
/**
|
|
* Gets the action to perform when this event is raised.
|
|
*/
|
|
public HoverEvent.Action<?> getAction() {
|
|
return this.event.action;
|
|
}
|
|
|
|
@Nullable
|
|
public <T> T getValue(HoverEvent.Action<T> actionType) {
|
|
return this.event.action == actionType ? actionType.cast(this.event.value) : null;
|
|
}
|
|
|
|
public boolean equals(Object object) {
|
|
if (this == object) {
|
|
return true;
|
|
} else {
|
|
return object != null && this.getClass() == object.getClass() ? ((HoverEvent)object).event.equals(this.event) : false;
|
|
}
|
|
}
|
|
|
|
public String toString() {
|
|
return this.event.toString();
|
|
}
|
|
|
|
public int hashCode() {
|
|
return this.event.hashCode();
|
|
}
|
|
|
|
public static class Action<T> implements StringRepresentable {
|
|
public static final HoverEvent.Action<Component> SHOW_TEXT = new HoverEvent.Action<>(
|
|
"show_text", true, ComponentSerialization.CODEC, (component, registryOps) -> DataResult.success(component)
|
|
);
|
|
public static final HoverEvent.Action<HoverEvent.ItemStackInfo> SHOW_ITEM = new HoverEvent.Action<>(
|
|
"show_item", true, HoverEvent.ItemStackInfo.CODEC, HoverEvent.ItemStackInfo::legacyCreate
|
|
);
|
|
public static final HoverEvent.Action<HoverEvent.EntityTooltipInfo> SHOW_ENTITY = new HoverEvent.Action<>(
|
|
"show_entity", true, HoverEvent.EntityTooltipInfo.CODEC, HoverEvent.EntityTooltipInfo::legacyCreate
|
|
);
|
|
public static final Codec<HoverEvent.Action<?>> UNSAFE_CODEC = StringRepresentable.fromValues(
|
|
() -> new HoverEvent.Action[]{SHOW_TEXT, SHOW_ITEM, SHOW_ENTITY}
|
|
);
|
|
public static final Codec<HoverEvent.Action<?>> CODEC = UNSAFE_CODEC.validate(HoverEvent.Action::filterForSerialization);
|
|
private final String name;
|
|
private final boolean allowFromServer;
|
|
final MapCodec<HoverEvent.TypedHoverEvent<T>> codec;
|
|
final MapCodec<HoverEvent.TypedHoverEvent<T>> legacyCodec;
|
|
|
|
public Action(String name, boolean allowFromServer, Codec<T> codec, HoverEvent.LegacyConverter<T> legacyConverter) {
|
|
this.name = name;
|
|
this.allowFromServer = allowFromServer;
|
|
this.codec = codec.<HoverEvent.TypedHoverEvent<T>>xmap(object -> new HoverEvent.TypedHoverEvent<>(this, (T)object), typedHoverEvent -> typedHoverEvent.value)
|
|
.fieldOf("contents");
|
|
this.legacyCodec = new 1(this, legacyConverter).fieldOf("value");
|
|
}
|
|
|
|
/**
|
|
* Indicates whether this event can be run from chat text.
|
|
*/
|
|
public boolean isAllowedFromServer() {
|
|
return this.allowFromServer;
|
|
}
|
|
|
|
@Override
|
|
public String getSerializedName() {
|
|
return this.name;
|
|
}
|
|
|
|
T cast(Object parameter) {
|
|
return (T)parameter;
|
|
}
|
|
|
|
public String toString() {
|
|
return "<action " + this.name + ">";
|
|
}
|
|
|
|
private static DataResult<HoverEvent.Action<?>> filterForSerialization(@Nullable HoverEvent.Action<?> action) {
|
|
if (action == null) {
|
|
return DataResult.error(() -> "Unknown action");
|
|
} else {
|
|
return !action.isAllowedFromServer() ? DataResult.error(() -> "Action not allowed: " + action) : DataResult.success(action, Lifecycle.stable());
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class EntityTooltipInfo {
|
|
public static final Codec<HoverEvent.EntityTooltipInfo> CODEC = RecordCodecBuilder.create(
|
|
instance -> instance.group(
|
|
BuiltInRegistries.ENTITY_TYPE.byNameCodec().fieldOf("type").forGetter(entityTooltipInfo -> entityTooltipInfo.type),
|
|
UUIDUtil.LENIENT_CODEC.fieldOf("id").forGetter(entityTooltipInfo -> entityTooltipInfo.id),
|
|
ComponentSerialization.CODEC.lenientOptionalFieldOf("name").forGetter(entityTooltipInfo -> entityTooltipInfo.name)
|
|
)
|
|
.apply(instance, HoverEvent.EntityTooltipInfo::new)
|
|
);
|
|
public final EntityType<?> type;
|
|
public final UUID id;
|
|
public final Optional<Component> name;
|
|
@Nullable
|
|
private List<Component> linesCache;
|
|
|
|
public EntityTooltipInfo(EntityType<?> type, UUID id, @Nullable Component name) {
|
|
this(type, id, Optional.ofNullable(name));
|
|
}
|
|
|
|
public EntityTooltipInfo(EntityType<?> type, UUID id, Optional<Component> name) {
|
|
this.type = type;
|
|
this.id = id;
|
|
this.name = name;
|
|
}
|
|
|
|
public static DataResult<HoverEvent.EntityTooltipInfo> legacyCreate(Component name, @Nullable RegistryOps<?> ops) {
|
|
try {
|
|
CompoundTag compoundTag = TagParser.parseTag(name.getString());
|
|
DynamicOps<JsonElement> dynamicOps = (DynamicOps<JsonElement>)(ops != null ? ops.withParent(JsonOps.INSTANCE) : JsonOps.INSTANCE);
|
|
DataResult<Component> dataResult = ComponentSerialization.CODEC.parse(dynamicOps, JsonParser.parseString(compoundTag.getString("name")));
|
|
EntityType<?> entityType = BuiltInRegistries.ENTITY_TYPE.getValue(ResourceLocation.parse(compoundTag.getString("type")));
|
|
UUID uUID = UUID.fromString(compoundTag.getString("id"));
|
|
return dataResult.map(component -> new HoverEvent.EntityTooltipInfo(entityType, uUID, component));
|
|
} catch (Exception var7) {
|
|
return DataResult.error(() -> "Failed to parse tooltip: " + var7.getMessage());
|
|
}
|
|
}
|
|
|
|
public List<Component> getTooltipLines() {
|
|
if (this.linesCache == null) {
|
|
this.linesCache = new ArrayList();
|
|
this.name.ifPresent(this.linesCache::add);
|
|
this.linesCache.add(Component.translatable("gui.entity_tooltip.type", this.type.getDescription()));
|
|
this.linesCache.add(Component.literal(this.id.toString()));
|
|
}
|
|
|
|
return this.linesCache;
|
|
}
|
|
|
|
public boolean equals(Object object) {
|
|
if (this == object) {
|
|
return true;
|
|
} else if (object != null && this.getClass() == object.getClass()) {
|
|
HoverEvent.EntityTooltipInfo entityTooltipInfo = (HoverEvent.EntityTooltipInfo)object;
|
|
return this.type.equals(entityTooltipInfo.type) && this.id.equals(entityTooltipInfo.id) && this.name.equals(entityTooltipInfo.name);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int hashCode() {
|
|
int i = this.type.hashCode();
|
|
i = 31 * i + this.id.hashCode();
|
|
return 31 * i + this.name.hashCode();
|
|
}
|
|
}
|
|
|
|
public static class ItemStackInfo {
|
|
public static final Codec<HoverEvent.ItemStackInfo> FULL_CODEC = ItemStack.CODEC.xmap(HoverEvent.ItemStackInfo::new, HoverEvent.ItemStackInfo::getItemStack);
|
|
private static final Codec<HoverEvent.ItemStackInfo> SIMPLE_CODEC = ItemStack.SIMPLE_ITEM_CODEC
|
|
.xmap(HoverEvent.ItemStackInfo::new, HoverEvent.ItemStackInfo::getItemStack);
|
|
public static final Codec<HoverEvent.ItemStackInfo> CODEC = Codec.withAlternative(FULL_CODEC, SIMPLE_CODEC);
|
|
private final Holder<Item> item;
|
|
private final int count;
|
|
private final DataComponentPatch components;
|
|
@Nullable
|
|
private ItemStack itemStack;
|
|
|
|
ItemStackInfo(Holder<Item> item, int count, DataComponentPatch components) {
|
|
this.item = item;
|
|
this.count = count;
|
|
this.components = components;
|
|
}
|
|
|
|
public ItemStackInfo(ItemStack stack) {
|
|
this(stack.getItemHolder(), stack.getCount(), stack.getComponentsPatch());
|
|
}
|
|
|
|
public boolean equals(Object object) {
|
|
if (this == object) {
|
|
return true;
|
|
} else if (object != null && this.getClass() == object.getClass()) {
|
|
HoverEvent.ItemStackInfo itemStackInfo = (HoverEvent.ItemStackInfo)object;
|
|
return this.count == itemStackInfo.count && this.item.equals(itemStackInfo.item) && this.components.equals(itemStackInfo.components);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int hashCode() {
|
|
int i = this.item.hashCode();
|
|
i = 31 * i + this.count;
|
|
return 31 * i + this.components.hashCode();
|
|
}
|
|
|
|
public ItemStack getItemStack() {
|
|
if (this.itemStack == null) {
|
|
this.itemStack = new ItemStack(this.item, this.count, this.components);
|
|
}
|
|
|
|
return this.itemStack;
|
|
}
|
|
|
|
private static DataResult<HoverEvent.ItemStackInfo> legacyCreate(Component name, @Nullable RegistryOps<?> ops) {
|
|
try {
|
|
CompoundTag compoundTag = TagParser.parseTag(name.getString());
|
|
DynamicOps<Tag> dynamicOps = (DynamicOps<Tag>)(ops != null ? ops.withParent(NbtOps.INSTANCE) : NbtOps.INSTANCE);
|
|
return ItemStack.CODEC.parse(dynamicOps, compoundTag).map(HoverEvent.ItemStackInfo::new);
|
|
} catch (CommandSyntaxException var4) {
|
|
return DataResult.error(() -> "Failed to parse item tag: " + var4.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface LegacyConverter<T> {
|
|
DataResult<T> parse(Component component, @Nullable RegistryOps<?> registryOps);
|
|
}
|
|
|
|
record TypedHoverEvent<T>(HoverEvent.Action<T> action, T value) {
|
|
public static final MapCodec<HoverEvent.TypedHoverEvent<?>> CODEC = HoverEvent.Action.CODEC
|
|
.dispatchMap("action", HoverEvent.TypedHoverEvent::action, action -> action.codec);
|
|
public static final MapCodec<HoverEvent.TypedHoverEvent<?>> LEGACY_CODEC = HoverEvent.Action.CODEC
|
|
.dispatchMap("action", HoverEvent.TypedHoverEvent::action, action -> action.legacyCodec);
|
|
}
|
|
}
|