From b9fc16ad17ff2abd8cd149684ef7411d95cb0f10 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 24 Feb 2024 10:51:35 +0800 Subject: [PATCH 1/4] MCFunctionLoadEvent Add a new function for the modder to add their mcFunctions. -usually for the result for advancements. -enable modder register it by codes. (means serializing is not needed) --- .../advancements/FunctionManager.java.patch | 18 ++ .../net/minecraftforge/common/ForgeHooks.java | 9 +- .../event/MCFunctionLoadEvent.java | 180 ++++++++++++++++++ .../net/minecraftforge/fml/common/Loader.java | 3 + 4 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch create mode 100644 src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java diff --git a/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch b/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch new file mode 100644 index 000000000..8c44893b5 --- /dev/null +++ b/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch @@ -0,0 +1,18 @@ +--- before/net/minecraft/advancements/FunctionManager.java ++++ after/net/minecraft/advancements/FunctionManager.java +@@ -14,6 +14,7 @@ + import net.minecraft.util.ITickable; + import net.minecraft.util.ResourceLocation; + import net.minecraft.world.World; ++import net.minecraftforge.common.ForgeHooks; + import org.apache.commons.io.FileUtils; + import org.apache.commons.io.FilenameUtils; + import org.apache.logging.log4j.LogManager; +@@ -182,6 +183,7 @@ + } + } + } ++ ForgeHooks.onMCFunctionLoad(this); + + if (!this.field_193070_d.isEmpty()) + { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index d3422f3a8..af4bfae5e 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -44,6 +44,7 @@ import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementManager; +import net.minecraft.advancements.FunctionManager; import net.minecraft.block.Block; import net.minecraft.block.BlockFarmland; import net.minecraft.block.BlockLiquid; @@ -119,10 +120,7 @@ import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.common.util.BlockSnapshot; -import net.minecraftforge.event.AnvilUpdateEvent; -import net.minecraftforge.event.DifficultyChangeEvent; -import net.minecraftforge.event.ForgeEventFactory; -import net.minecraftforge.event.ServerChatEvent; +import net.minecraftforge.event.*; import net.minecraftforge.event.entity.EntityTravelToDimensionEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent; @@ -1402,6 +1400,9 @@ private static boolean loadAdvancements(Map recipes, List display, boolean isGuiOpen, boolean isFilteringCraftable) { diff --git a/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java b/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java new file mode 100644 index 000000000..2e6e95213 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java @@ -0,0 +1,180 @@ +package net.minecraftforge.event; + + +import com.google.common.collect.Lists; +import com.google.common.io.ByteSource; +import com.google.common.io.LineProcessor; +import net.minecraft.advancements.FunctionManager; +import net.minecraft.command.FunctionObject; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLLog; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.eventhandler.Event; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.IOException; +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.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class MCFunctionLoadEvent extends Event { + public final FunctionManager functionManager; + public final Map functions; + public MCFunctionLoadEvent(FunctionManager manager){ + this.functionManager=manager; + functions = ObfuscationReflectionHelper.getPrivateValue(FunctionManager.class,manager,"field_193070_d","functions"); + } + public HashMap loadAndRegisterFor(String modid){ + HashMap map = new HashMap<>(); + ModContainer container = Loader.getLoadedMod(modid); + Loader.instance().setActiveModContainer(container); + findFiles(container, "assets/" + container.getModId() + "/functions",null, + (root, file) -> { + String relative = root.relativize(file).toString(); + if (!"mcfunction".equals(FilenameUtils.getExtension(file.toString())) || relative.startsWith("_")) + return true; + String name = FilenameUtils.removeExtension(relative).replaceAll("\\\\", "/"); + ResourceLocation key = new ResourceLocation(container.getModId(), name); + try { + + FunctionObject functionObject = FunctionObject.create( + functionManager, + getByteSource(file).asCharSource(StandardCharsets.UTF_8) + .readLines(new LineProcessor<>() { + final List result = Lists.newArrayList(); + + @Override + public boolean processLine(String line) { + result.add(line); + return true; + } + + @Override + public List getResult() { + return result; + } + }) + ); + map.put(key, functionObject); + return true; + } catch (IOException e) { + FMLLog.log.error("Couldn't read function {} from {}", key, file, e); + return false; + } + },true, true); + functions.putAll(map); + Loader.instance().setActiveModContainer(null); + return map; + } + public void register(ResourceLocation resourceLocation, FunctionObject functionObject){ + functions.put(resourceLocation, functionObject); + } + @Nullable + public FunctionObject unregister(ResourceLocation resourceLocation){ + return functions.remove(resourceLocation); + } + public HashMap unregisterAll(Collection collection){ + HashMap hashMap = new HashMap<>(); + for(ResourceLocation resourceLocation:collection){ + hashMap.put(resourceLocation, unregister(resourceLocation)); + } + return hashMap; + } + private static boolean findFiles(ModContainer mod, String base, Function preprocessor, BiFunction processor, + boolean defaultUnfoundRoot, boolean visitAllFiles) + { + + File source = mod.getSource(); + + if ("minecraft".equals(mod.getModId())) + { + return true; + } + + FileSystem fs = null; + boolean success = true; + + try + { + Path root = null; + + if (source.isFile()) + { + try + { + fs = FileSystems.newFileSystem(source.toPath(), (ClassLoader)null); + root = fs.getPath("/" + base); + } + catch (IOException e) + { + FMLLog.log.error("Error loading FileSystem from jar: ", e); + return false; + } + } + else if (source.isDirectory()) + { + root = source.toPath().resolve(base); + } + + if (root == null || !Files.exists(root)) + return defaultUnfoundRoot; + + if (preprocessor != null) + { + Boolean cont = preprocessor.apply(root); + if (cont == null || !cont) + return false; + } + + if (processor != null) + { + Iterator itr; + try + { + itr = Files.walk(root).iterator(); + } + catch (IOException e) + { + FMLLog.log.error("Error iterating filesystem for: {}", mod.getModId(), e); + return false; + } + + while (itr.hasNext()) + { + Boolean cont = processor.apply(root, itr.next()); + + if (visitAllFiles) + { + success &= cont != null && cont; + } + else if (cont == null || !cont) + { + return false; + } + } + } + } + finally + { + IOUtils.closeQuietly(fs); + } + + return success; + } + private static ByteSource getByteSource(Path path) throws IOException { + return ByteSource.wrap(IOUtils.toByteArray(Files.newBufferedReader(path))); + } + public static FunctionObject singleFunction(FunctionObject.Entry entry){ + return new FunctionObject(new FunctionObject.Entry[]{entry}); + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/Loader.java b/src/main/java/net/minecraftforge/fml/common/Loader.java index 6bb30c25d..94e855d4c 100644 --- a/src/main/java/net/minecraftforge/fml/common/Loader.java +++ b/src/main/java/net/minecraftforge/fml/common/Loader.java @@ -689,6 +689,9 @@ public static boolean isModLoaded(String modname) { return instance().namedMods.containsKey(modname) && instance().modController.getModState(instance.namedMods.get(modname))!=ModState.DISABLED; } + public static ModContainer getLoadedMod(String modname){ + return instance().namedMods.get(modname); + } public File getConfigDir() { From a64e820e5e8ee88ce83e7e6728920046b9b9c67c Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 24 Feb 2024 13:24:23 +0800 Subject: [PATCH 2/4] fix import and add Java-doc --- .../advancements/FunctionManager.java.patch | 12 +---- .../command/FunctionObject.java.patch | 11 ++++ .../net/minecraftforge/common/ForgeHooks.java | 5 +- .../event/MCFunctionLoadEvent.java | 50 +++++++++++++++++-- 4 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 patches/minecraft/net/minecraft/command/FunctionObject.java.patch diff --git a/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch b/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch index 8c44893b5..af3602189 100644 --- a/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch +++ b/patches/minecraft/net/minecraft/advancements/FunctionManager.java.patch @@ -1,18 +1,10 @@ --- before/net/minecraft/advancements/FunctionManager.java +++ after/net/minecraft/advancements/FunctionManager.java -@@ -14,6 +14,7 @@ - import net.minecraft.util.ITickable; - import net.minecraft.util.ResourceLocation; - import net.minecraft.world.World; -+import net.minecraftforge.common.ForgeHooks; - import org.apache.commons.io.FileUtils; - import org.apache.commons.io.FilenameUtils; - import org.apache.logging.log4j.LogManager; -@@ -182,6 +183,7 @@ +@@ -182,6 +182,7 @@ } } } -+ ForgeHooks.onMCFunctionLoad(this); ++ net.minecraftforge.common.ForgeHooks.onMCFunctionLoad(this, this.field_193070_d); if (!this.field_193070_d.isEmpty()) { diff --git a/patches/minecraft/net/minecraft/command/FunctionObject.java.patch b/patches/minecraft/net/minecraft/command/FunctionObject.java.patch new file mode 100644 index 000000000..e14d34f7b --- /dev/null +++ b/patches/minecraft/net/minecraft/command/FunctionObject.java.patch @@ -0,0 +1,11 @@ +--- before/net/minecraft/command/FunctionObject.java ++++ after/net/minecraft/command/FunctionObject.java +@@ -104,7 +104,7 @@ + { + private final String field_193525_a; + +- public CommandEntry(String p_i47534_1_) ++ public CommandEntry(String p_i47534_1_) + { + this.field_193525_a = p_i47534_1_; + } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index af4bfae5e..bb67aefe0 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -52,6 +52,7 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.command.FunctionObject; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; @@ -1400,8 +1401,8 @@ private static boolean loadAdvancements(Map functionsIn){ + MinecraftForge.EVENT_BUS.post(new MCFunctionLoadEvent(manager, functionsIn)); } public static void sendRecipeBook(NetHandlerPlayServer connection, State state, List recipes, List display, boolean isGuiOpen, boolean isFilteringCraftable) diff --git a/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java b/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java index 2e6e95213..5124f28df 100644 --- a/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java +++ b/src/main/java/net/minecraftforge/event/MCFunctionLoadEvent.java @@ -7,10 +7,14 @@ import net.minecraft.advancements.FunctionManager; import net.minecraft.command.FunctionObject; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.EnumDifficulty; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; @@ -18,6 +22,7 @@ import javax.annotation.Nullable; import java.io.File; import java.io.IOException; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -27,13 +32,35 @@ import java.util.function.BiFunction; import java.util.function.Function; +/** + * MCFunctionLoadEvent is fired when {@link FunctionObject} `.mcfunction` be loaded and registered
+ *
+ * This event is fired via the {@link ForgeHooks#onMCFunctionLoad(FunctionManager, Map)}.
+ *
+ * This event is not {@link Cancelable}.
+ *
+ * This event does not have a result. {@link HasResult}
+ *
+ * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + **/ public class MCFunctionLoadEvent extends Event { public final FunctionManager functionManager; public final Map functions; - public MCFunctionLoadEvent(FunctionManager manager){ - this.functionManager=manager; - functions = ObfuscationReflectionHelper.getPrivateValue(FunctionManager.class,manager,"field_193070_d","functions"); + + /** + * @param manager the instance of {@link FunctionManager} , which is the owner of Functions. + * @param functionsIn the instance of {@link FunctionObject} map. It is a registry. + */ + public MCFunctionLoadEvent(FunctionManager manager, Map functionsIn){ + this.functionManager = manager; + this.functions = functionsIn; } + + /** + * It will scan the `.mcfunction` file at `assets//functions` and it's child folds, to load {@link FunctionObject} and register it, using the path as the register name. + * @param modid the modID + * @return the loaded {@link FunctionObject} + */ public HashMap loadAndRegisterFor(String modid){ HashMap map = new HashMap<>(); ModContainer container = Loader.getLoadedMod(modid); @@ -76,13 +103,28 @@ public List getResult() { Loader.instance().setActiveModContainer(null); return map; } + + /** + * @param resourceLocation the register name + * @param functionObject the function + */ public void register(ResourceLocation resourceLocation, FunctionObject functionObject){ functions.put(resourceLocation, functionObject); } + + /** + * @param resourceLocation the register name + * @return the function + */ @Nullable public FunctionObject unregister(ResourceLocation resourceLocation){ return functions.remove(resourceLocation); } + + /** + * @param collection the register names + * @return the unregistered {@link FunctionObject} + */ public HashMap unregisterAll(Collection collection){ HashMap hashMap = new HashMap<>(); for(ResourceLocation resourceLocation:collection){ @@ -172,7 +214,7 @@ else if (cont == null || !cont) return success; } private static ByteSource getByteSource(Path path) throws IOException { - return ByteSource.wrap(IOUtils.toByteArray(Files.newBufferedReader(path))); + return ByteSource.wrap(IOUtils.toByteArray(Files.newBufferedReader(path), StandardCharsets.UTF_8)); } public static FunctionObject singleFunction(FunctionObject.Entry entry){ return new FunctionObject(new FunctionObject.Entry[]{entry}); From 3b79c41b918d2ef83568126803a455c08a8d6181 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 24 Feb 2024 13:27:24 +0800 Subject: [PATCH 3/4] Delete FunctionObject.java.patch --- .../net/minecraft/command/FunctionObject.java.patch | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 patches/minecraft/net/minecraft/command/FunctionObject.java.patch diff --git a/patches/minecraft/net/minecraft/command/FunctionObject.java.patch b/patches/minecraft/net/minecraft/command/FunctionObject.java.patch deleted file mode 100644 index e14d34f7b..000000000 --- a/patches/minecraft/net/minecraft/command/FunctionObject.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- before/net/minecraft/command/FunctionObject.java -+++ after/net/minecraft/command/FunctionObject.java -@@ -104,7 +104,7 @@ - { - private final String field_193525_a; - -- public CommandEntry(String p_i47534_1_) -+ public CommandEntry(String p_i47534_1_) - { - this.field_193525_a = p_i47534_1_; - } From e960d24bf982e7d2a5d3e9937251e3991edaa6ce Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 26 Oct 2024 20:27:44 +0800 Subject: [PATCH 4/4] fix import --- src/main/java/net/minecraftforge/common/ForgeHooks.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index bb67aefe0..445804a70 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -121,7 +121,11 @@ import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.common.util.BlockSnapshot; -import net.minecraftforge.event.*; +import net.minecraftforge.event.AnvilUpdateEvent; +import net.minecraftforge.event.DifficultyChangeEvent; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.event.MCFunctionLoadEvent; +import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.event.entity.EntityTravelToDimensionEvent; import net.minecraftforge.event.entity.item.ItemTossEvent; import net.minecraftforge.event.entity.living.LivingAttackEvent;