TextComponentHoverAndClickEventFix.java

net.minecraft.util.datafix.fixes.TextComponentHoverAndClickEventFix

信息

  • 全限定名:net.minecraft.util.datafix.fixes.TextComponentHoverAndClickEventFix
  • 类型:public class
  • 包:net.minecraft.util.datafix.fixes
  • 源码路径:src/main/java/net/minecraft/util/datafix/fixes/TextComponentHoverAndClickEventFix.java
  • 起始行号:L21
  • 继承:DataFix
  • 职责:

    TODO

字段/常量

内部类/嵌套类型

构造器

public TextComponentHoverAndClickEventFix(Schema outputSchema) @ L22

  • 构造器名:TextComponentHoverAndClickEventFix
  • 源码定位:L22
  • 修饰符:public

参数:

  • outputSchema: Schema

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected TypeRewriteRule makeRule() @ L26

  • 方法名:makeRule
  • 源码定位:L26
  • 返回类型:TypeRewriteRule
  • 修饰符:protected

参数:

说明:

TODO

private <C1,C2,H extends Pair<String,?>> TypeRewriteRule createFixer(Type<C1> oldRawTextComponentType, Type<C2> newTextComponentType, Type<H> hoverEventType) @ L36

  • 方法名:createFixer
  • 源码定位:L36
  • 返回类型:<C1,C2,H extends Pair<String,?>> TypeRewriteRule
  • 修饰符:private

参数:

  • oldRawTextComponentType: Type
  • newTextComponentType: Type
  • hoverEventType: Type

说明:

TODO

private static Dynamic<?> fixTextComponent(Dynamic<?> dynamic) @ L81

  • 方法名:fixTextComponent
  • 源码定位:L81
  • 返回类型:Dynamic<?>
  • 修饰符:private static

参数:

  • dynamic: Dynamic<?>

说明:

TODO

private static Dynamic<?> copyFields(Dynamic<?> target, Dynamic<?> source, String... fields) @ L86

  • 方法名:copyFields
  • 源码定位:L86
  • 返回类型:Dynamic<?>
  • 修饰符:private static

参数:

  • target: Dynamic<?>
  • source: Dynamic<?>
  • fields: String…

说明:

TODO

private static Dynamic<?> fixHoverEvent(Dynamic<?> dynamic) @ L94

  • 方法名:fixHoverEvent
  • 源码定位:L94
  • 返回类型:Dynamic<?>
  • 修饰符:private static

参数:

  • dynamic: Dynamic<?>

说明:

TODO

private static <T> Dynamic<T> fixClickEvent(Dynamic<T> dynamic) @ L114

  • 方法名:fixClickEvent
  • 源码定位:L114
  • 返回类型: Dynamic
  • 修饰符:private static

参数:

  • dynamic: Dynamic

说明:

TODO

private static Integer parseOldPage(Dynamic<?> value) @ L135

  • 方法名:parseOldPage
  • 源码定位:L135
  • 返回类型:Integer
  • 修饰符:private static

参数:

  • value: Dynamic<?>

说明:

TODO

private static boolean validateUri(String uri) @ L148

  • 方法名:validateUri
  • 源码定位:L148
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • uri: String

说明:

TODO

private static boolean validateChat(String string) @ L163

  • 方法名:validateChat
  • 源码定位:L163
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • string: String

说明:

TODO

代码

public class TextComponentHoverAndClickEventFix extends DataFix {
    public TextComponentHoverAndClickEventFix(Schema outputSchema) {
        super(outputSchema, true);
    }
 
    @Override
    protected TypeRewriteRule makeRule() {
        Type<? extends Pair<String, ?>> hoverEventType = (Type<? extends Pair<String, ?>>)this.getInputSchema()
            .getType(References.TEXT_COMPONENT)
            .findFieldType("hoverEvent");
        return this.createFixer(
            this.getInputSchema().getTypeRaw(References.TEXT_COMPONENT), this.getOutputSchema().getType(References.TEXT_COMPONENT), hoverEventType
        );
    }
 
    private <C1, C2, H extends Pair<String, ?>> TypeRewriteRule createFixer(
        Type<C1> oldRawTextComponentType, Type<C2> newTextComponentType, Type<H> hoverEventType
    ) {
        Type<Pair<String, Either<Either<String, List<C1>>, Pair<Either<List<C1>, Unit>, Pair<Either<C1, Unit>, Pair<Either<H, Unit>, Dynamic<?>>>>>>> oldTextComponentType = DSL.named(
            References.TEXT_COMPONENT.typeName(),
            DSL.or(
                DSL.or(DSL.string(), DSL.list(oldRawTextComponentType)),
                DSL.and(
                    DSL.optional(DSL.field("extra", DSL.list(oldRawTextComponentType))),
                    DSL.optional(DSL.field("separator", oldRawTextComponentType)),
                    DSL.optional(DSL.field("hoverEvent", hoverEventType)),
                    DSL.remainderType()
                )
            )
        );
        if (!oldTextComponentType.equals(this.getInputSchema().getType(References.TEXT_COMPONENT))) {
            throw new IllegalStateException(
                "Text component type did not match, expected " + oldTextComponentType + " but got " + this.getInputSchema().getType(References.TEXT_COMPONENT)
            );
        } else {
            Type<?> patchedInputType = ExtraDataFixUtils.patchSubType(oldTextComponentType, oldTextComponentType, newTextComponentType);
            return this.fixTypeEverywhere(
                "TextComponentHoverAndClickEventFix",
                oldTextComponentType,
                newTextComponentType,
                ops -> textComponent -> {
                    boolean hasHoverOrClick = textComponent.getSecond().map(simple -> false, full -> {
                        Pair<Either<H, Unit>, Dynamic<?>> hoverAndRemainder = full.getSecond().getSecond();
                        boolean hasHover = hoverAndRemainder.getFirst().left().isPresent();
                        boolean hasClick = hoverAndRemainder.getSecond().get("clickEvent").result().isPresent();
                        return hasHover || hasClick;
                    });
                    return (C2)(!hasHoverOrClick
                        ? textComponent
                        : Util.writeAndReadTypedOrThrow(
                                ExtraDataFixUtils.cast(patchedInputType, textComponent, ops),
                                newTextComponentType,
                                TextComponentHoverAndClickEventFix::fixTextComponent
                            )
                            .getValue());
                }
            );
        }
    }
 
    private static Dynamic<?> fixTextComponent(Dynamic<?> dynamic) {
        return dynamic.renameAndFixField("hoverEvent", "hover_event", TextComponentHoverAndClickEventFix::fixHoverEvent)
            .renameAndFixField("clickEvent", "click_event", TextComponentHoverAndClickEventFix::fixClickEvent);
    }
 
    private static Dynamic<?> copyFields(Dynamic<?> target, Dynamic<?> source, String... fields) {
        for (String field : fields) {
            target = Dynamic.copyField(source, field, target, field);
        }
 
        return target;
    }
 
    private static Dynamic<?> fixHoverEvent(Dynamic<?> dynamic) {
        String action = dynamic.get("action").asString("");
 
        return switch (action) {
            case "show_text" -> dynamic.renameField("contents", "value");
            case "show_item" -> {
                Dynamic<?> contents = dynamic.get("contents").orElseEmptyMap();
                Optional<String> simpleId = contents.asString().result();
                yield simpleId.isPresent()
                    ? dynamic.renameField("contents", "id")
                    : copyFields(dynamic.remove("contents"), contents, "id", "count", "components");
            }
            case "show_entity" -> {
                Dynamic<?> contents = dynamic.get("contents").orElseEmptyMap();
                yield copyFields(dynamic.remove("contents"), contents, "id", "type", "name").renameField("id", "uuid").renameField("type", "id");
            }
            default -> dynamic;
        };
    }
 
    private static <T> @Nullable Dynamic<T> fixClickEvent(Dynamic<T> dynamic) {
        String action = dynamic.get("action").asString("");
        String value = dynamic.get("value").asString("");
 
        return switch (action) {
            case "open_url" -> !validateUri(value) ? null : dynamic.renameField("value", "url");
            case "open_file" -> dynamic.renameField("value", "path");
            case "run_command", "suggest_command" -> !validateChat(value) ? null : dynamic.renameField("value", "command");
            case "change_page" -> {
                Integer oldPage = dynamic.get("value").result().map(TextComponentHoverAndClickEventFix::parseOldPage).orElse(null);
                if (oldPage == null) {
                    yield null;
                } else {
                    int page = Math.max(oldPage, 1);
                    yield dynamic.remove("value").set("page", dynamic.createInt(page));
                }
            }
            default -> dynamic;
        };
    }
 
    private static @Nullable Integer parseOldPage(Dynamic<?> value) {
        Optional<Number> numberValue = value.asNumber().result();
        if (numberValue.isPresent()) {
            return numberValue.get().intValue();
        } else {
            try {
                return Integer.parseInt(value.asString(""));
            } catch (Exception var3) {
                return null;
            }
        }
    }
 
    private static boolean validateUri(String uri) {
        try {
            URI parsedUri = new URI(uri);
            String scheme = parsedUri.getScheme();
            if (scheme == null) {
                return false;
            } else {
                String protocol = scheme.toLowerCase(Locale.ROOT);
                return "http".equals(protocol) || "https".equals(protocol);
            }
        } catch (URISyntaxException var4) {
            return false;
        }
    }
 
    private static boolean validateChat(String string) {
        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            if (c == 167 || c < ' ' || c == 127) {
                return false;
            }
        }
 
        return true;
    }
}

引用的其他类

  • PropertyDispatch

    • 引用位置: 参数/返回值
  • Schema

    • 引用位置: 参数
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.writeAndReadTypedOrThrow()
  • ExtraDataFixUtils

    • 引用位置: 方法调用
    • 关联成员: ExtraDataFixUtils.cast(), ExtraDataFixUtils.patchSubType()
  • ResolvableProfile

    • 引用位置: 参数/方法调用/返回值
    • 关联成员: Dynamic.copyField()