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.Objects; import java.util.function.UnaryOperator; 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.Identifier; import net.minecraft.util.Util; import org.jspecify.annotations.Nullable; public class MacroFunction> implements CommandFunction { private static final DecimalFormat DECIMAL_FORMAT = Util.make( new DecimalFormat("#", DecimalFormatSymbols.getInstance(Locale.ROOT)), format -> format.setMaximumFractionDigits(15) ); private static final int MAX_CACHE_ENTRIES = 8; private final List parameters; private final Object2ObjectLinkedOpenHashMap, InstantiatedFunction> cache = new Object2ObjectLinkedOpenHashMap<>(8, 0.25F); private final Identifier id; private final List> entries; public MacroFunction(final Identifier id, final List> entries, final List parameters) { this.id = id; this.entries = entries; this.parameters = parameters; } @Override public Identifier id() { return this.id; } @Override public InstantiatedFunction instantiate(@Nullable final CompoundTag arguments, final CommandDispatcher dispatcher) throws FunctionInstantiationException { if (arguments == null) { throw new FunctionInstantiationException(Component.translatable("commands.function.error.missing_arguments", Component.translationArg(this.id()))); } else { List parameterValues = new ArrayList(this.parameters.size()); for (String argument : this.parameters) { Tag argumentValue = arguments.get(argument); if (argumentValue == null) { throw new FunctionInstantiationException(Component.translatable("commands.function.error.missing_argument", Component.translationArg(this.id()), argument)); } parameterValues.add(stringify(argumentValue)); } InstantiatedFunction cachedFunction = this.cache.getAndMoveToLast(parameterValues); if (cachedFunction != null) { return cachedFunction; } else { if (this.cache.size() >= 8) { this.cache.removeFirst(); } InstantiatedFunction function = this.substituteAndParse(this.parameters, parameterValues, dispatcher); this.cache.put(parameterValues, function); return function; } } } private static String stringify(final Tag tag) { Objects.requireNonNull(tag); return switch (tag) { case FloatTag(float var41) -> { float var25 = var41; if (true) { yield DECIMAL_FORMAT.format(var25); } byte var45 = 1; } case DoubleTag(double var39) -> { double var26 = var39; if (true) { yield DECIMAL_FORMAT.format(var26); } byte var44 = 2; } case ByteTag(byte var37) -> { byte var27 = var37; if (true) { yield String.valueOf(var27); } byte var43 = 3; } case ShortTag(short var35) -> { short var28 = var35; if (true) { yield String.valueOf(var28); } byte var42 = 4; } case LongTag(long var33) -> { long var29 = var33; if (true) { yield String.valueOf(var29); } byte var2 = 5; } case StringTag(String var17) -> var17; default -> tag.toString(); }; } private static void lookupValues(final List values, final IntList indicesToSelect, final List selectedValuesOutput) { selectedValuesOutput.clear(); indicesToSelect.forEach(index -> selectedValuesOutput.add((String)values.get(index))); } private InstantiatedFunction substituteAndParse(final List keys, final List values, final CommandDispatcher dispatcher) throws FunctionInstantiationException { List> newEntries = new ArrayList(this.entries.size()); List entryArguments = new ArrayList(values.size()); for (MacroFunction.Entry entry : this.entries) { lookupValues(values, entry.parameters(), entryArguments); newEntries.add(entry.instantiate(entryArguments, dispatcher, this.id)); } return new PlainTextFunction<>(this.id().withPath((UnaryOperator)(id -> id + "/" + keys.hashCode())), newEntries); } interface Entry { IntList parameters(); UnboundEntryAction instantiate(List substitutions, CommandDispatcher dispatcher, Identifier funtionId) throws FunctionInstantiationException; } static class MacroEntry> implements MacroFunction.Entry { private final StringTemplate template; private final IntList parameters; private final T compilationContext; public MacroEntry(final StringTemplate template, final IntList parameters, final T compilationContext) { this.template = template; this.parameters = parameters; this.compilationContext = compilationContext; } @Override public IntList parameters() { return this.parameters; } @Override public UnboundEntryAction instantiate(final List substitutions, final CommandDispatcher dispatcher, final Identifier functionId) throws FunctionInstantiationException { String command = this.template.substitute(substitutions); try { return CommandFunction.parseCommand(dispatcher, this.compilationContext, new StringReader(command)); } catch (CommandSyntaxException var6) { throw new FunctionInstantiationException( Component.translatable("commands.function.error.parse", Component.translationArg(functionId), command, var6.getMessage()) ); } } } static class PlainTextEntry implements MacroFunction.Entry { private final UnboundEntryAction compiledAction; public PlainTextEntry(final UnboundEntryAction compiledAction) { this.compiledAction = compiledAction; } @Override public IntList parameters() { return IntLists.emptyList(); } @Override public UnboundEntryAction instantiate(final List substitutions, final CommandDispatcher dispatcher, final Identifier functionId) { return this.compiledAction; } } }