package net.minecraft.data.structures; import com.google.common.collect.Lists; import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; import com.google.common.hash.HashingOutputStream; import com.mojang.logging.LogUtils; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import net.minecraft.Util; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; public class SnbtToNbt implements DataProvider { private static final Logger LOGGER = LogUtils.getLogger(); private final PackOutput output; private final Iterable inputFolders; private final List filters = Lists.newArrayList(); public SnbtToNbt(PackOutput output, Iterable inputFolders) { this.output = output; this.inputFolders = inputFolders; } public SnbtToNbt addFilter(SnbtToNbt.Filter filter) { this.filters.add(filter); return this; } private CompoundTag applyFilters(String fileName, CompoundTag tag) { CompoundTag compoundTag = tag; for (SnbtToNbt.Filter filter : this.filters) { compoundTag = filter.apply(fileName, compoundTag); } return compoundTag; } @Override public CompletableFuture run(CachedOutput output) { Path path = this.output.getOutputFolder(); List> list = Lists.>newArrayList(); for (Path path2 : this.inputFolders) { list.add( CompletableFuture.supplyAsync( () -> { try { Stream stream = Files.walk(path2); CompletableFuture var5x; try { var5x = CompletableFuture.allOf( (CompletableFuture[])stream.filter(pathxx -> pathxx.toString().endsWith(".snbt")).map(path3 -> CompletableFuture.runAsync(() -> { SnbtToNbt.TaskResult taskResult = this.readStructure(path3, this.getName(path2, path3)); this.storeStructureIfChanged(output, taskResult, path); }, Util.backgroundExecutor().forName("SnbtToNbt"))).toArray(CompletableFuture[]::new) ); } catch (Throwable var8) { if (stream != null) { try { stream.close(); } catch (Throwable var7) { var8.addSuppressed(var7); } } throw var8; } if (stream != null) { stream.close(); } return var5x; } catch (Exception var9) { throw new RuntimeException("Failed to read structure input directory, aborting", var9); } }, Util.backgroundExecutor().forName("SnbtToNbt") ) .thenCompose(completableFuture -> completableFuture) ); } return Util.sequenceFailFast(list); } @Override public final String getName() { return "SNBT -> NBT"; } /** * Gets the name of the given SNBT file, based on its path and the input directory. The result does not have the ".snbt" extension. */ private String getName(Path inputFolder, Path file) { String string = inputFolder.relativize(file).toString().replaceAll("\\\\", "/"); return string.substring(0, string.length() - ".snbt".length()); } private SnbtToNbt.TaskResult readStructure(Path filePath, String fileName) { try { BufferedReader bufferedReader = Files.newBufferedReader(filePath); SnbtToNbt.TaskResult var10; try { String string = IOUtils.toString(bufferedReader); CompoundTag compoundTag = this.applyFilters(fileName, NbtUtils.snbtToStructure(string)); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); HashingOutputStream hashingOutputStream = new HashingOutputStream(Hashing.sha1(), byteArrayOutputStream); NbtIo.writeCompressed(compoundTag, hashingOutputStream); byte[] bs = byteArrayOutputStream.toByteArray(); HashCode hashCode = hashingOutputStream.hash(); var10 = new SnbtToNbt.TaskResult(fileName, bs, hashCode); } catch (Throwable var12) { if (bufferedReader != null) { try { bufferedReader.close(); } catch (Throwable var11) { var12.addSuppressed(var11); } } throw var12; } if (bufferedReader != null) { bufferedReader.close(); } return var10; } catch (Throwable var13) { throw new SnbtToNbt.StructureConversionException(filePath, var13); } } private void storeStructureIfChanged(CachedOutput output, SnbtToNbt.TaskResult taskResult, Path directoryPath) { Path path = directoryPath.resolve(taskResult.name + ".nbt"); try { output.writeIfNeeded(path, taskResult.payload, taskResult.hash); } catch (IOException var6) { LOGGER.error("Couldn't write structure {} at {}", taskResult.name, path, var6); } } @FunctionalInterface public interface Filter { CompoundTag apply(String structureLocationPath, CompoundTag tag); } /** * Wraps exceptions thrown while reading structures to include the path of the structure in the exception message. */ static class StructureConversionException extends RuntimeException { public StructureConversionException(Path path, Throwable cause) { super(path.toAbsolutePath().toString(), cause); } } record TaskResult(String name, byte[] payload, HashCode hash) { } }