253 lines
10 KiB
Java
253 lines
10 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.google.common.collect.ImmutableList
|
|
* com.google.common.collect.ImmutableList$Builder
|
|
* com.mojang.brigadier.exceptions.CommandSyntaxException
|
|
* com.mojang.datafixers.kinds.App
|
|
* com.mojang.datafixers.kinds.Applicative
|
|
* com.mojang.datafixers.util.Either
|
|
* com.mojang.serialization.Codec
|
|
* com.mojang.serialization.DataResult
|
|
* com.mojang.serialization.MapCodec
|
|
* com.mojang.serialization.codecs.RecordCodecBuilder
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.network.chat.contents;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.mojang.datafixers.kinds.App;
|
|
import com.mojang.datafixers.kinds.Applicative;
|
|
import com.mojang.datafixers.util.Either;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.DataResult;
|
|
import com.mojang.serialization.MapCodec;
|
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.function.Consumer;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.locale.Language;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.ComponentContents;
|
|
import net.minecraft.network.chat.ComponentSerialization;
|
|
import net.minecraft.network.chat.ComponentUtils;
|
|
import net.minecraft.network.chat.FormattedText;
|
|
import net.minecraft.network.chat.MutableComponent;
|
|
import net.minecraft.network.chat.Style;
|
|
import net.minecraft.network.chat.contents.TranslatableFormatException;
|
|
import net.minecraft.util.ExtraCodecs;
|
|
import net.minecraft.world.entity.Entity;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public class TranslatableContents
|
|
implements ComponentContents {
|
|
public static final Object[] NO_ARGS = new Object[0];
|
|
private static final Codec<Object> PRIMITIVE_ARG_CODEC = ExtraCodecs.JAVA.validate(TranslatableContents::filterAllowedArguments);
|
|
private static final Codec<Object> ARG_CODEC = Codec.either(PRIMITIVE_ARG_CODEC, ComponentSerialization.CODEC).xmap(e -> e.map(o -> o, component -> Objects.requireNonNullElse(component.tryCollapseToString(), component)), o -> {
|
|
Either either;
|
|
if (o instanceof Component) {
|
|
Component c = (Component)o;
|
|
either = Either.right((Object)c);
|
|
} else {
|
|
either = Either.left((Object)o);
|
|
}
|
|
return either;
|
|
});
|
|
public static final MapCodec<TranslatableContents> MAP_CODEC = RecordCodecBuilder.mapCodec(i -> i.group((App)Codec.STRING.fieldOf("translate").forGetter(o -> o.key), (App)Codec.STRING.lenientOptionalFieldOf("fallback").forGetter(o -> Optional.ofNullable(o.fallback)), (App)ARG_CODEC.listOf().optionalFieldOf("with").forGetter(o -> TranslatableContents.adjustArgs(o.args))).apply((Applicative)i, TranslatableContents::create));
|
|
private static final FormattedText TEXT_PERCENT = FormattedText.of("%");
|
|
private static final FormattedText TEXT_NULL = FormattedText.of("null");
|
|
private final String key;
|
|
private final @Nullable String fallback;
|
|
private final Object[] args;
|
|
private @Nullable Language decomposedWith;
|
|
private List<FormattedText> decomposedParts = ImmutableList.of();
|
|
private static final Pattern FORMAT_PATTERN = Pattern.compile("%(?:(\\d+)\\$)?([A-Za-z%]|$)");
|
|
|
|
private static DataResult<Object> filterAllowedArguments(@Nullable Object result) {
|
|
if (!TranslatableContents.isAllowedPrimitiveArgument(result)) {
|
|
return DataResult.error(() -> "This value needs to be parsed as component");
|
|
}
|
|
return DataResult.success((Object)result);
|
|
}
|
|
|
|
public static boolean isAllowedPrimitiveArgument(@Nullable Object object) {
|
|
return object instanceof Number || object instanceof Boolean || object instanceof String;
|
|
}
|
|
|
|
private static Optional<List<Object>> adjustArgs(Object[] args) {
|
|
return args.length == 0 ? Optional.empty() : Optional.of(Arrays.asList(args));
|
|
}
|
|
|
|
private static Object[] adjustArgs(Optional<List<Object>> args) {
|
|
return args.map(a -> a.isEmpty() ? NO_ARGS : a.toArray()).orElse(NO_ARGS);
|
|
}
|
|
|
|
private static TranslatableContents create(String key, Optional<String> fallback, Optional<List<Object>> args) {
|
|
return new TranslatableContents(key, fallback.orElse(null), TranslatableContents.adjustArgs(args));
|
|
}
|
|
|
|
public TranslatableContents(String key, @Nullable String fallback, Object[] args) {
|
|
this.key = key;
|
|
this.fallback = fallback;
|
|
this.args = args;
|
|
}
|
|
|
|
public MapCodec<TranslatableContents> codec() {
|
|
return MAP_CODEC;
|
|
}
|
|
|
|
private void decompose() {
|
|
Language currentLanguage = Language.getInstance();
|
|
if (currentLanguage == this.decomposedWith) {
|
|
return;
|
|
}
|
|
this.decomposedWith = currentLanguage;
|
|
String format = this.fallback != null ? currentLanguage.getOrDefault(this.key, this.fallback) : currentLanguage.getOrDefault(this.key);
|
|
try {
|
|
ImmutableList.Builder parts = ImmutableList.builder();
|
|
this.decomposeTemplate(format, arg_0 -> ((ImmutableList.Builder)parts).add(arg_0));
|
|
this.decomposedParts = parts.build();
|
|
}
|
|
catch (TranslatableFormatException e) {
|
|
this.decomposedParts = ImmutableList.of((Object)FormattedText.of(format));
|
|
}
|
|
}
|
|
|
|
private void decomposeTemplate(String template, Consumer<FormattedText> decomposedParts) {
|
|
Matcher matcher = FORMAT_PATTERN.matcher(template);
|
|
try {
|
|
int replacementIndex = 0;
|
|
int current = 0;
|
|
while (matcher.find(current)) {
|
|
int start = matcher.start();
|
|
int end = matcher.end();
|
|
if (start > current) {
|
|
String prefix = template.substring(current, start);
|
|
if (prefix.indexOf(37) != -1) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
decomposedParts.accept(FormattedText.of(prefix));
|
|
}
|
|
String formatType = matcher.group(2);
|
|
String formatString = template.substring(start, end);
|
|
if ("%".equals(formatType) && "%%".equals(formatString)) {
|
|
decomposedParts.accept(TEXT_PERCENT);
|
|
} else if ("s".equals(formatType)) {
|
|
String possiblePositionIndex = matcher.group(1);
|
|
int index = possiblePositionIndex != null ? Integer.parseInt(possiblePositionIndex) - 1 : replacementIndex++;
|
|
decomposedParts.accept(this.getArgument(index));
|
|
} else {
|
|
throw new TranslatableFormatException(this, "Unsupported format: '" + formatString + "'");
|
|
}
|
|
current = end;
|
|
}
|
|
if (current < template.length()) {
|
|
String tail = template.substring(current);
|
|
if (tail.indexOf(37) != -1) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
decomposedParts.accept(FormattedText.of(tail));
|
|
}
|
|
}
|
|
catch (IllegalArgumentException e) {
|
|
throw new TranslatableFormatException(this, (Throwable)e);
|
|
}
|
|
}
|
|
|
|
private FormattedText getArgument(int index) {
|
|
if (index < 0 || index >= this.args.length) {
|
|
throw new TranslatableFormatException(this, index);
|
|
}
|
|
Object arg = this.args[index];
|
|
if (arg instanceof Component) {
|
|
Component componentArg = (Component)arg;
|
|
return componentArg;
|
|
}
|
|
return arg == null ? TEXT_NULL : FormattedText.of(arg.toString());
|
|
}
|
|
|
|
@Override
|
|
public <T> Optional<T> visit(FormattedText.StyledContentConsumer<T> output, Style currentStyle) {
|
|
this.decompose();
|
|
for (FormattedText part : this.decomposedParts) {
|
|
Optional<T> result = part.visit(output, currentStyle);
|
|
if (!result.isPresent()) continue;
|
|
return result;
|
|
}
|
|
return Optional.empty();
|
|
}
|
|
|
|
@Override
|
|
public <T> Optional<T> visit(FormattedText.ContentConsumer<T> output) {
|
|
this.decompose();
|
|
for (FormattedText part : this.decomposedParts) {
|
|
Optional<T> result = part.visit(output);
|
|
if (!result.isPresent()) continue;
|
|
return result;
|
|
}
|
|
return Optional.empty();
|
|
}
|
|
|
|
@Override
|
|
public MutableComponent resolve(@Nullable CommandSourceStack source, @Nullable Entity entity, int recursionDepth) throws CommandSyntaxException {
|
|
Object[] argsCopy = new Object[this.args.length];
|
|
for (int i = 0; i < argsCopy.length; ++i) {
|
|
Object param = this.args[i];
|
|
if (param instanceof Component) {
|
|
Component component = (Component)param;
|
|
argsCopy[i] = ComponentUtils.updateForEntity(source, component, entity, recursionDepth);
|
|
continue;
|
|
}
|
|
argsCopy[i] = param;
|
|
}
|
|
return MutableComponent.create(new TranslatableContents(this.key, this.fallback, argsCopy));
|
|
}
|
|
|
|
/*
|
|
* Enabled force condition propagation
|
|
* Lifted jumps to return sites
|
|
*/
|
|
public boolean equals(Object o) {
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (!(o instanceof TranslatableContents)) return false;
|
|
TranslatableContents that = (TranslatableContents)o;
|
|
if (!Objects.equals(this.key, that.key)) return false;
|
|
if (!Objects.equals(this.fallback, that.fallback)) return false;
|
|
if (!Arrays.equals(this.args, that.args)) return false;
|
|
return true;
|
|
}
|
|
|
|
public int hashCode() {
|
|
int result = Objects.hashCode(this.key);
|
|
result = 31 * result + Objects.hashCode(this.fallback);
|
|
result = 31 * result + Arrays.hashCode(this.args);
|
|
return result;
|
|
}
|
|
|
|
public String toString() {
|
|
return "translation{key='" + this.key + "'" + (String)(this.fallback != null ? ", fallback='" + this.fallback + "'" : "") + ", args=" + Arrays.toString(this.args) + "}";
|
|
}
|
|
|
|
public String getKey() {
|
|
return this.key;
|
|
}
|
|
|
|
public @Nullable String getFallback() {
|
|
return this.fallback;
|
|
}
|
|
|
|
public Object[] getArgs() {
|
|
return this.args;
|
|
}
|
|
}
|
|
|