package net.minecraft.commands.functions; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.UnaryOperator; import net.minecraft.Util; import net.minecraft.commands.ExecutionCommandSource; import net.minecraft.commands.FunctionInstantiationException; import net.minecraft.commands.execution.UnboundEntryAction; import net.minecraft.nbt.ByteTag; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.DoubleTag; import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.LongTag; import net.minecraft.nbt.ShortTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; public class MacroFunction> implements CommandFunction { private static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("#"), decimalFormat -> { decimalFormat.setMaximumFractionDigits(15); decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.US)); }); private static final int MAX_CACHE_ENTRIES = 8; private final List parameters; private final Object2ObjectLinkedOpenHashMap, InstantiatedFunction> cache = new Object2ObjectLinkedOpenHashMap<>(8, 0.25F); private final ResourceLocation id; private final List> entries; public MacroFunction(ResourceLocation id, List> entries, List parameters) { this.id = id; this.entries = entries; this.parameters = parameters; } @Override public ResourceLocation id() { return this.id; } @Override public InstantiatedFunction instantiate(@Nullable CompoundTag arguments, CommandDispatcher dispatcher) throws FunctionInstantiationException { if (arguments == null) { throw new FunctionInstantiationException(Component.translatable("commands.function.error.missing_arguments", Component.translationArg(this.id()))); } else { List list = new ArrayList(this.parameters.size()); for (String string : this.parameters) { Tag tag = arguments.get(string); if (tag == null) { throw new FunctionInstantiationException(Component.translatable("commands.function.error.missing_argument", Component.translationArg(this.id()), string)); } list.add(stringify(tag)); } InstantiatedFunction instantiatedFunction = this.cache.getAndMoveToLast(list); if (instantiatedFunction != null) { return instantiatedFunction; } else { if (this.cache.size() >= 8) { this.cache.removeFirst(); } InstantiatedFunction instantiatedFunction2 = this.substituteAndParse(this.parameters, list, dispatcher); this.cache.put(list, instantiatedFunction2); return instantiatedFunction2; } } } private static String stringify(Tag tag) { return switch (tag) { case FloatTag(float var24) -> DECIMAL_FORMAT.format(var24); case DoubleTag(double var25) -> DECIMAL_FORMAT.format(var25); case ByteTag(byte var26) -> String.valueOf(var26); case ShortTag(short var27) -> String.valueOf(var27); case LongTag(long var28) -> String.valueOf(var28); case StringTag(String var17) -> var17; default -> tag.toString(); }; } private static void lookupValues(List arguments, IntList parameters, List output) { output.clear(); parameters.forEach(i -> output.add((String)arguments.get(i))); } private InstantiatedFunction substituteAndParse(List argumentNames, List argumentValues, CommandDispatcher dispatcher) throws FunctionInstantiationException { List> list = new ArrayList(this.entries.size()); List list2 = new ArrayList(argumentValues.size()); for (MacroFunction.Entry entry : this.entries) { lookupValues(argumentValues, entry.parameters(), list2); list.add(entry.instantiate(list2, dispatcher, this.id)); } return new PlainTextFunction<>(this.id().withPath((UnaryOperator)(string -> string + "/" + argumentNames.hashCode())), list); } interface Entry { IntList parameters(); UnboundEntryAction instantiate(List arguments, CommandDispatcher dispatcher, ResourceLocation function) throws FunctionInstantiationException; } static class MacroEntry> implements MacroFunction.Entry { private final StringTemplate template; private final IntList parameters; private final T compilationContext; public MacroEntry(StringTemplate template, IntList parameters, T compilationContext) { this.template = template; this.parameters = parameters; this.compilationContext = compilationContext; } @Override public IntList parameters() { return this.parameters; } @Override public UnboundEntryAction instantiate(List arguments, CommandDispatcher dispatcher, ResourceLocation function) throws FunctionInstantiationException { String string = this.template.substitute(arguments); try { return CommandFunction.parseCommand(dispatcher, this.compilationContext, new StringReader(string)); } catch (CommandSyntaxException var6) { throw new FunctionInstantiationException( Component.translatable("commands.function.error.parse", Component.translationArg(function), string, var6.getMessage()) ); } } } static class PlainTextEntry implements MacroFunction.Entry { private final UnboundEntryAction compiledAction; public PlainTextEntry(UnboundEntryAction compiledAction) { this.compiledAction = compiledAction; } @Override public IntList parameters() { return IntLists.emptyList(); } @Override public UnboundEntryAction instantiate(List arguments, CommandDispatcher dispatcher, ResourceLocation function) { return this.compiledAction; } } }