package net.minecraft.server; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.ImmutableMap.Builder; import com.mojang.brigadier.CommandDispatcher; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import java.io.BufferedReader; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.Executor; import net.minecraft.commands.CommandSource; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.functions.CommandFunction; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.CommonComponents; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.tags.TagLoader; import net.minecraft.tags.TagLoader.EntryWithSource; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.slf4j.Logger; public class ServerFunctionLibrary implements PreparableReloadListener { private static final Logger LOGGER = LogUtils.getLogger(); public static final ResourceKey>> TYPE_KEY = ResourceKey.createRegistryKey( ResourceLocation.withDefaultNamespace("function") ); private static final FileToIdConverter LISTER = new FileToIdConverter(Registries.elementsDirPath(TYPE_KEY), ".mcfunction"); private volatile Map> functions = ImmutableMap.of(); private final TagLoader> tagsLoader = new TagLoader<>( (resourceLocation, bl) -> this.getFunction(resourceLocation), Registries.tagsDirPath(TYPE_KEY) ); private volatile Map>> tags = Map.of(); private final int functionCompilationLevel; private final CommandDispatcher dispatcher; public Optional> getFunction(ResourceLocation location) { return Optional.ofNullable((CommandFunction)this.functions.get(location)); } public Map> getFunctions() { return this.functions; } public List> getTag(ResourceLocation location) { return (List>)this.tags.getOrDefault(location, List.of()); } public Iterable getAvailableTags() { return this.tags.keySet(); } public ServerFunctionLibrary(int functionCompilationLevel, CommandDispatcher dispatcher) { this.functionCompilationLevel = functionCompilationLevel; this.dispatcher = dispatcher; } @Override public CompletableFuture reload( PreparableReloadListener.PreparationBarrier preparationBarrier, ResourceManager resourceManager, Executor executor, Executor executor2 ) { CompletableFuture>> completableFuture = CompletableFuture.supplyAsync( () -> this.tagsLoader.load(resourceManager), executor ); CompletableFuture>>> completableFuture2 = CompletableFuture.supplyAsync( () -> LISTER.listMatchingResources(resourceManager), executor ) .thenCompose( map -> { Map>> map2 = Maps.>>newHashMap(); CommandSourceStack commandSourceStack = new CommandSourceStack( CommandSource.NULL, Vec3.ZERO, Vec2.ZERO, null, this.functionCompilationLevel, "", CommonComponents.EMPTY, null, null ); for (Entry entry : map.entrySet()) { ResourceLocation resourceLocation = (ResourceLocation)entry.getKey(); ResourceLocation resourceLocation2 = LISTER.fileToId(resourceLocation); map2.put(resourceLocation2, CompletableFuture.supplyAsync(() -> { List list = readLines((Resource)entry.getValue()); return CommandFunction.fromLines(resourceLocation2, this.dispatcher, commandSourceStack, list); }, executor)); } CompletableFuture[] completableFutures = (CompletableFuture[])map2.values().toArray(new CompletableFuture[0]); return CompletableFuture.allOf(completableFutures).handle((void_, throwable) -> map2); } ); return completableFuture.thenCombine(completableFuture2, Pair::of) .thenCompose(preparationBarrier::wait) .thenAcceptAsync( pair -> { Map>> map = (Map>>)pair.getSecond(); Builder> builder = ImmutableMap.builder(); map.forEach((resourceLocation, completableFuturex) -> completableFuturex.handle((commandFunction, throwable) -> { if (throwable != null) { LOGGER.error("Failed to load function {}", resourceLocation, throwable); } else { builder.put(resourceLocation, commandFunction); } return null; }).join()); this.functions = builder.build(); this.tags = this.tagsLoader.build((Map>)pair.getFirst()); }, executor2 ); } private static List readLines(Resource resource) { try { BufferedReader bufferedReader = resource.openAsReader(); List var2; try { var2 = bufferedReader.lines().toList(); } catch (Throwable var5) { if (bufferedReader != null) { try { bufferedReader.close(); } catch (Throwable var4) { var5.addSuppressed(var4); } } throw var5; } if (bufferedReader != null) { bufferedReader.close(); } return var2; } catch (IOException var6) { throw new CompletionException(var6); } } }