Jump to content

[1.12.2] Conditional custom json recipes


Aarilight

Recommended Posts

I want conditional recipes, which only are registered if an item is present. (So that JEI won't show them). The recipes were already custom classes, because they're for my custom "crafting table". I need to implement this support via the json recipe system (so my options are limited to things I can do inside of Factory.parse, I believe.

 

What I tried so far:

1. Returning an output of ItemStack.EMPTY (just shows up as a recipe with no output in JEI)

2. Returning null instead of a valid IRecipe in the factory (crashes, which I kinda expected)
3. Setting a slot in the recipe to an IngredientNever (basically the same thing as Choonster's) (Just shows up as an empty slot in JEI)

 

The other options I can think of:
 

1. Throw a JsonSyntaxException. The game doesn't crash if I do this, and the recipe isn't registered, but it will spam the log.

2. Figure out some way of hiding the recipes in JEI. (I've looked into this a bit but haven't found anything yet)

3. Figure out a way to deregister recipes (potentially the same way that CraftTweaker does it? I haven't looked into this yet) 

 

I'm not really too fond of these other solutions. Is there a simple solution that I'm missing? If not, do you think it would be reasonable to suggest forge to allow Factory.parse to return null and silently skip the recipe it in that case?

Edited by Aarilight
Link to comment
Share on other sites

I'm not really too fond of that solution either because it requires adding additional information to the json, things which I just want to happen by default for this recipe type.

 

Also, I phrased the initial post wrong, I said "if an item is present", I should have said "if an item in a given ore dictionary is present"

 

My current recipe factory actually supports using the first ItemStack in an ore dictionary as it's result, and I'm combining that with an ore dictionary ingredient.

I guess I might as well post my current recipe:

{
	"type": "soulus:composer_shaped",
	"time": 16,
	"pattern": [
		"eee",
		"ede",
		"eee"
	],
	"key": {
		"d": {
			"type": "forge:ore_dict",
			"ore": "dustLead"
		},
		"e": {
			"item": "soulus:ingot_endersteel"
		}
	},
	"result": {
		"type": "forge:ore_dict",
		"ore": "ingotLead",
		"count": 8
	}
}

 

Everything is implemented and works except for the issues with not being able to fail it silently.

 

If there really is no other solution I'll add in that new condition, I guess.

Edited by Aarilight
Link to comment
Share on other sites

If the recipe is for your custom crafting table, does that mean you're calling CraftingHelper.findFiles yourself to load the recipes? If so, you could check that the recipe's output is non-empty between loading and registering it.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

No, I register them with the rest of the normal recipes (via _factories.json) ... the instances simply don't match unless they're used in my crafting table.

 

The reason I do it that way is my crafting table also supports all vanilla recipes. It's an autocrafting table =P

Edited by Aarilight
Link to comment
Share on other sites

Then I think the least hackish way to handle this would probably be adding the condition to your recipes.

 

If you really don't want to do that, you could probably integrate with JEI to hide your uncraftable recipes.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I actually ended up just deregistering any recipes which were instances of my table's recipes and had an empty output. I realised that the major downside to this way was the advancement issues, and since the recipes are optional depending on mods anyway, having advancements relating to them (if I were to ever make them) wouldn't even really make sense. If I ever need to jump over that hurdle, I'll rewrite this then. Thanks for your help. =)

 

Out of curiosity, do you think a recipe factory returning null would make sense to fail silently? Cause I still think that would have been the most elegant solution... maybe I should make a forge issue/pr, but I feel like that would be a controversial change? If there would be people that disagree with a change like that I don't think my needs here are important enough to warrant it.

Link to comment
Share on other sites

57 minutes ago, Aarilight said:

Out of curiosity, do you think a recipe factory returning null would make sense to fail silently? Cause I still think that would have been the most elegant solution... maybe I should make a forge issue/pr, but I feel like that would be a controversial change? If there would be people that disagree with a change like that I don't think my needs here are important enough to warrant it.

 

It could be useful in some circumstances, but I'm not sure how many people would actually need it.

 

It probably wouldn't hurt to open an issue/PR, the worst that can happen is that it's closed because Lex/mezz don't see a wide use for it.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

A few notes: 1) You can't always trust the first oredict entry to be a valid itemstack. You may need to expand it to a random one.

2) https://github.com/MinecraftForge/MinecraftForge/blob/1.12.x/src/main/java/net/minecraftforge/common/crafting/IConditionFactory.java

 

I do Forge for free, however the servers to run it arn't free, so anything is appreciated.
Consider supporting the team on Patreon

Link to comment
Share on other sites

Here's where I get the ItemStack:

private static ItemStack getOreDictItem (JsonObject result, JsonContext context) {
    if (JsonUtils.getString(result, "type", "").equals("forge:ore_dict")) {
        String ore = JsonUtils.getString(result, "ore");
        ItemStack stack = OreDictionary.getOres(ore).stream().findAny().orElse(ItemStack.EMPTY).copy();
        stack.setCount(JsonUtils.getInt(result, "count", 1));
        int data = JsonUtils.getInt(result, "data", -1);
        if (data > -1) stack.setItemDamage(data);
        return stack;

    } else {
        return CraftingHelper.getItemStack(result, context);
    }
}

 

Would this not work for it? Should I be looping through it manually to find a valid stack? As of now I've made 8 recipes that seem to work with it, but I guess if the list could include empty item stacks I should probably do that? I would think that would be a mod bug tho, if empty stacks are being added to an ore dictionary (and should probably be reported to those mods)?

 

Also, conditions were mentioned previously in this conversation. The reason I didn't want to go for them is afaik, it requires adding additional information to each json recipe. It would have to be a recipe condition, as it's based on whether the "result" property in the json is a valid ore dictionary item. So basically, what would happen is the condition would check if the result !isEmpty(), and if it is, it would pass the condition, and then this code would be run again when the recipe is actually built.

 

Since I'm doing this additional parsing as part of the recipe, to me it makes sense to allow failing during that.

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.