CrackedScreen Posted October 8, 2022 Posted October 8, 2022 (edited) I'm trying to disable crafting recipes based on config file values. Currently using datagen for crafting recipes, and ICondition seems to have changed compared to the older IConditionFactory. Edited October 26, 2022 by CrackedScreen Marked thread as solved. Quote
ChampionAsh5357 Posted October 9, 2022 Posted October 9, 2022 You would need to make your own condition that checks the value. Note that when the config refreshes, you'll need to refresh the datapacks as well. You can learn how to make a custom condition on the docs. Quote
CrackedScreen Posted October 17, 2022 Author Posted October 17, 2022 (edited) Late reply, but tried implementing ICondition and copying some code over from ModLoadedCondition: Reveal hidden contents public class RecipeCondition implements ICondition { private static final ResourceLocation NAME = new ResourceLocation(MusketMod.MOD_ID, "recipe_enabled"); private final boolean loaded; public RecipeCondition(Boolean loaded) { this.loaded = loaded; } public ResourceLocation getID() { return NAME; } @Override public boolean test(IContext context) { return ICondition.super.test(context); } @Override public boolean test() { return false; } public static class Serializer implements IConditionSerializer<RecipeCondition> { public static final RecipeCondition.Serializer INSTANCE = new RecipeCondition.Serializer(); @Override public void write(JsonObject json, RecipeCondition value) { json.addProperty("recipe_enabled", value.loaded); } @Override public RecipeCondition read(JsonObject json) { return new RecipeCondition(GsonHelper.getAsBoolean(json, "recipe_enabled")); } @Override public ResourceLocation getID() { return RecipeCondition.NAME; } } } Getting an error for including the test() method since it is marked as deprecated, but forge still requires it to be implemented. Using Forge 1.18.2-40.1.51, if I'm missing anything let me know. EDIT: The mod will still compile and run fine since this isn't actually an error, but will need to know how to pass existing datagen recipes through the serializer since forge does not come with any functional examples by itself. Would still appreciate an answer on how to get rid of the deprecated method in case I am missing something obvious. Edited October 17, 2022 by CrackedScreen Changed post. Quote
ChampionAsh5357 Posted October 17, 2022 Posted October 17, 2022 On 10/17/2022 at 4:14 AM, CrackedScreen said: The mod will still compile and run fine since this isn't actually an error, but will need to know how to pass existing datagen recipes through the serializer since forge does not come with any functional examples by itself. Expand I give you, a Forge provided functional example: https://github.com/MinecraftForge/MinecraftForge/blob/1.19.x/src/test/java/net/minecraftforge/debug/DataGeneratorTest.java#L165-L204 On 10/17/2022 at 4:14 AM, CrackedScreen said: Would still appreciate an answer on how to get rid of the deprecated method in case I am missing something obvious. Expand Essentially, the method is removed in 1.19 due to the context parameter addition. However, changing how the method is implemented would induce a breaking change. As such, older versions need to have it implemented until they update to the next version. Quote
CrackedScreen Posted October 17, 2022 Author Posted October 17, 2022 (edited) Used the following to create the recipe: Reveal hidden contents ResourceLocation ID = new ResourceLocation(MOD_ID, moddedItem.toString()); ConditionalRecipe.builder().addCondition( new RecipeCondition(Config.ENABLED_CRAFTING.get()) ).addRecipe( ShapedRecipeBuilder.shaped(moddedItem, amount) // .define ingredients here ).build(consumer, ID); Condition/Serializer class: Reveal hidden contents public class RecipeCondition implements ICondition { private static final ResourceLocation NAME = new ResourceLocation(MOD_ID, "recipe_enabled"); private final boolean loaded; public RecipeCondition(Boolean loaded) { this.loaded = loaded; } public ResourceLocation getID() { return NAME; } @Override public boolean test(IContext context) { return loaded; } @Override public boolean test() { return false; } public static class Serializer implements IConditionSerializer<RecipeCondition> { public static final Serializer INSTANCE = new Serializer(); @Override public void write(JsonObject json, RecipeCondition value) { json.addProperty("recipe_enabled", value.loaded); } @Override public RecipeCondition read(JsonObject json) { return new RecipeCondition(GsonHelper.getAsBoolean(json, "recipe_enabled")); } @Override public ResourceLocation getID() { return RecipeCondition.NAME; } } } Registered the serializer class in RegistryEvents class: Reveal hidden contents @SubscribeEvent public void registerSerializers(RegistryEvent.Register<RecipeSerializer<?>> event) { CraftingHelper.register(RecipeCondition.Serializer.INSTANCE); } Currently getting an "Unknown condition type" error when using the runData task which likely means the condition wasn't registered correctly, but don't know how this is the case. Reveal hidden contents Caused by: com.google.gson.JsonSyntaxException: Unknown condition type: mod_id:recipe_enabled Edited October 17, 2022 by CrackedScreen Changed text Quote
ChampionAsh5357 Posted October 18, 2022 Posted October 18, 2022 How are you listening to the register event? If using EventBusSubscriber, the method needs to be static. Quote
CrackedScreen Posted October 18, 2022 Author Posted October 18, 2022 The register event works fine after setting the method to static, though now it seems that changing the config file values inside of the save folder doesn't have any effect on whether the recipe is active or not. Code is still same as above. Quote
ChampionAsh5357 Posted October 18, 2022 Posted October 18, 2022 That makes sense, you cache the static value of the boolean. You should not need any parameters and just check in test if the config value is loaded. Then, you need to resave the config and reload the datapack, because the condition won't be checked if the datapack isn't reloaded. Quote
CrackedScreen Posted October 18, 2022 Author Posted October 18, 2022 (edited) I've already tried pulling the value directly from configs, this does not change the result. Reveal hidden contents public class RecipeCondition implements ICondition { public static final RecipeCondition INSTANCE = new RecipeCondition(); private static final ResourceLocation NAME = new ResourceLocation(MOD_ID, "recipe_enabled"); public RecipeCondition() { } public ResourceLocation getID() { return NAME; } @Override public boolean test(IContext context) { return Config.ENABLED_CRAFTING.get(); } @Override public boolean test() { return false; } public static class Serializer implements IConditionSerializer<RecipeCondition> { public static final Serializer INSTANCE = new Serializer(); @Override public void write(JsonObject json, RecipeCondition value) { json.addProperty("recipe_enabled", Config.ENABLED_CRAFTING.get()); } @Override public RecipeCondition read(JsonObject json) { return RecipeCondition.INSTANCE; } @Override public ResourceLocation getID() { return RecipeCondition.NAME; } } } The recipes aren't being loaded as the serializer is returning null after using /reload, the problem is likely the read() method but I'm not sure what it should return since the examples provided by forge return a new condition with constructor. Would also prefer to reload datapacks from code whenever the world/server is loaded, if possible. Edited October 18, 2022 by CrackedScreen Quote
ChampionAsh5357 Posted October 18, 2022 Posted October 18, 2022 On 10/18/2022 at 4:32 PM, CrackedScreen said: The recipes aren't being loaded as the serializer is returning null after using /reload Expand That would mean the serializer is null. On 10/18/2022 at 4:32 PM, CrackedScreen said: the problem is likely the read() method but I'm not sure what it should return since the examples provided by forge return a new condition with constructor Expand Not really an issue with read, though you don't need to write anything and the single boolean test needs to return the config value as well. On 10/18/2022 at 4:32 PM, CrackedScreen said: Would also prefer to reload datapacks from code whenever the world/server is loaded, if possible. Expand You can look at the `ReloadCommand` to learn how to do this, but it should generally be avoided unless the cached config value changes. Quote
CrackedScreen Posted October 18, 2022 Author Posted October 18, 2022 (edited) On 10/18/2022 at 5:32 PM, ChampionAsh5357 said: That would mean the serializer is null. Expand You'll have to elaborate on why this is the case since I don't see any immediate issues. I created the condition almost the exact same way the builtin forge conditions are. Edit: The recipes are disabled if the config value is set to false, but only after manually reloading. Will need a fix for the serializer issue and best practices for forcing a reload upon entering a world if the serializer fix doesn't correct this behavior. Edited October 18, 2022 by CrackedScreen Update Quote
ChampionAsh5357 Posted October 18, 2022 Posted October 18, 2022 On 10/18/2022 at 9:20 PM, CrackedScreen said: You'll have to elaborate on why this is the case since I don't see any immediate issues. Expand I wouldn't know the reasoning. There's no inclination in the code provided that there would be an issue. The only thing I can think of is the event listener where you register things, which you would need to show the entire class for. Anything else might result from a separate issue. Quote
CrackedScreen Posted October 18, 2022 Author Posted October 18, 2022 Registry class: Reveal hidden contents @Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) public static class RegistryEvents { @SubscribeEvent public static void registerSerializers(RegistryEvent.Register<RecipeSerializer<?>> event) { CraftingHelper.register(RecipeCondition.Serializer.INSTANCE); } } I could try registering this outside of event bus in a non-static context. Quote
ChampionAsh5357 Posted October 19, 2022 Posted October 19, 2022 Ah, you need to provide your modid to the event bus subscriber. Quote
CrackedScreen Posted October 19, 2022 Author Posted October 19, 2022 (edited) Adding modid = MOD_ID to my event bus subscriber didn't have any effect. The serializer only has the null issue when the config value is set to false for some reason, if I return true/false directly in the condition class or leave the config value as true there aren't any issues with loading/blocking the recipe. Edited October 19, 2022 by CrackedScreen Quote
ChampionAsh5357 Posted October 19, 2022 Posted October 19, 2022 On 10/19/2022 at 2:47 PM, CrackedScreen said: The serializer only has the null issue when the config value is set to false for some reason, if I return true/false directly in the condition class or leave the config value as true there aren't any issues with loading/blocking the recipe. Expand Ah, so it's a defaulting issue. Well, the way to fix that is to either give your config a default, or to cache the value into a boolean and change the boolean when the config is loaded and reloaded using (ConfigEvent$Loading and ConfigEvent$Reloading). Quote
CrackedScreen Posted October 19, 2022 Author Posted October 19, 2022 (edited) The test value that I'm using already has a default value set: Reveal hidden contents public static ForgeConfigSpec.BooleanValue ENABLED_CRAFTING; public static void registerConfig() { ForgeConfigSpec.Builder CONFIG_BUILDER = new ForgeConfigSpec.Builder(); ENABLED_CRAFTING = CONFIG_BUILDER .define("Test value", true); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, CONFIG_BUILDER.build()); } Will look into using booleans, but I may have tried this + reloading before with no success using something similar: Reveal hidden contents @SubscribeEvent public static void onConfigLoad(ModConfigEvent.Loading event) { ((CommentedFileConfig)event.getConfig().getConfigData()).load(); } Edited October 19, 2022 by CrackedScreen Quote
ChampionAsh5357 Posted October 22, 2022 Posted October 22, 2022 On 10/19/2022 at 6:45 PM, CrackedScreen said: ((CommentedFileConfig)event.getConfig().getConfigData()).load(); Expand Yeah, that looks like it may cause a infinite loop. The events are called because the data has finished loading and reloading and are now within the config values. These are for if you want to know when those values are changed. Quote
CrackedScreen Posted October 26, 2022 Author Posted October 26, 2022 Managed to fix this by creating different conditions for each recipe and reusing the same serializer. Apparently it isn't possible to return different values with the same condition, and the "null issue" is forge working as intended according to here: https://github.com/P3pp3rF1y/Reliquary/issues/529 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.