package net.minecraft.advancements; import com.google.common.collect.Maps; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.Iterator; import java.util.Map; import javax.annotation.Nullable; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.util.EnumTypeAdapterFactory; import net.minecraft.util.JsonUtils; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.Style; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class AdvancementManager { private static final Logger LOGGER = LogManager.getLogger(); public static final Gson GSON = (new GsonBuilder()).registerTypeHierarchyAdapter(Advancement.Builder.class, new JsonDeserializer() { public Advancement.Builder deserialize(JsonElement p_deserialize_1_, Type p_deserialize_2_, JsonDeserializationContext p_deserialize_3_) throws JsonParseException { JsonObject jsonobject = JsonUtils.getJsonObject(p_deserialize_1_, "advancement"); return Advancement.Builder.deserialize(jsonobject, p_deserialize_3_); } }).registerTypeAdapter(AdvancementRewards.class, new AdvancementRewards.Deserializer()).registerTypeHierarchyAdapter(ITextComponent.class, new ITextComponent.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new EnumTypeAdapterFactory()).create(); private static final AdvancementList ADVANCEMENT_LIST = new AdvancementList(); /** The directory where this manager looks for custom advancement files. */ private final File advancementsDir; private boolean hasErrored; public AdvancementManager(@Nullable File advancementsDirIn) { this.advancementsDir = advancementsDirIn; this.reload(); } public void reload() { this.hasErrored = false; ADVANCEMENT_LIST.clear(); Map map = this.loadCustomAdvancements(); this.loadBuiltInAdvancements(map); this.hasErrored |= net.minecraftforge.common.ForgeHooks.loadAdvancements(map); ADVANCEMENT_LIST.loadAdvancements(map); for (Advancement advancement : ADVANCEMENT_LIST.getRoots()) { if (advancement.getDisplay() != null) { AdvancementTreeNode.layout(advancement); } } } public boolean hasErrored() { return this.hasErrored; } private Map loadCustomAdvancements() { if (this.advancementsDir == null) { return Maps.newHashMap(); } else { Map map = Maps.newHashMap(); this.advancementsDir.mkdirs(); for (File file1 : FileUtils.listFiles(this.advancementsDir, new String[] {"json"}, true)) { String s = FilenameUtils.removeExtension(this.advancementsDir.toURI().relativize(file1.toURI()).toString()); String[] astring = s.split("/", 2); if (astring.length == 2) { ResourceLocation resourcelocation = new ResourceLocation(astring[0], astring[1]); try { Advancement.Builder advancement$builder = (Advancement.Builder)JsonUtils.gsonDeserialize(GSON, FileUtils.readFileToString(file1, StandardCharsets.UTF_8), Advancement.Builder.class); if (advancement$builder == null) { LOGGER.error("Couldn't load custom advancement " + resourcelocation + " from " + file1 + " as it's empty or null"); } else { map.put(resourcelocation, advancement$builder); } } catch (IllegalArgumentException | JsonParseException jsonparseexception) { LOGGER.error("Parsing error loading custom advancement " + resourcelocation, (Throwable)jsonparseexception); this.hasErrored = true; } catch (IOException ioexception) { LOGGER.error("Couldn't read custom advancement " + resourcelocation + " from " + file1, (Throwable)ioexception); this.hasErrored = true; } } } return map; } } private void loadBuiltInAdvancements(Map map) { FileSystem filesystem = null; try { URL url = AdvancementManager.class.getResource("/assets/.mcassetsroot"); if (url != null) { URI uri = url.toURI(); Path path; if ("file".equals(uri.getScheme())) { path = Paths.get(CraftingManager.class.getResource("/assets/minecraft/advancements").toURI()); } else { if (!"jar".equals(uri.getScheme())) { LOGGER.error("Unsupported scheme " + uri + " trying to list all built-in advancements (NYI?)"); this.hasErrored = true; return; } filesystem = FileSystems.newFileSystem(uri, Collections.emptyMap()); path = filesystem.getPath("/assets/minecraft/advancements"); } Iterator iterator = Files.walk(path).iterator(); while (iterator.hasNext()) { Path path1 = iterator.next(); if ("json".equals(FilenameUtils.getExtension(path1.toString()))) { Path path2 = path.relativize(path1); String s = FilenameUtils.removeExtension(path2.toString()).replaceAll("\\\\", "/"); ResourceLocation resourcelocation = new ResourceLocation("minecraft", s); if (!map.containsKey(resourcelocation)) { BufferedReader bufferedreader = null; try { bufferedreader = Files.newBufferedReader(path1); Advancement.Builder advancement$builder = (Advancement.Builder)JsonUtils.fromJson(GSON, bufferedreader, Advancement.Builder.class); map.put(resourcelocation, advancement$builder); } catch (JsonParseException jsonparseexception) { LOGGER.error("Parsing error loading built-in advancement " + resourcelocation, (Throwable)jsonparseexception); this.hasErrored = true; } catch (IOException ioexception) { LOGGER.error("Couldn't read advancement " + resourcelocation + " from " + path1, (Throwable)ioexception); this.hasErrored = true; } finally { IOUtils.closeQuietly((Reader)bufferedreader); } } } } return; } LOGGER.error("Couldn't find .mcassetsroot"); this.hasErrored = true; } catch (IOException | URISyntaxException urisyntaxexception) { LOGGER.error("Couldn't get a list of all built-in advancement files", (Throwable)urisyntaxexception); this.hasErrored = true; return; } finally { IOUtils.closeQuietly((Closeable)filesystem); } } @Nullable public Advancement getAdvancement(ResourceLocation id) { return ADVANCEMENT_LIST.getAdvancement(id); } public Iterable getAdvancements() { return ADVANCEMENT_LIST.getAdvancements(); } }