
DoctorC
Members-
Posts
39 -
Joined
-
Last visited
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
DoctorC's Achievements

Tree Puncher (2/8)
0
Reputation
-
Okay, thanks! I've been trying out Mixins, but can't figure out how Surface Rules work, so I'll probably just wait.
-
Hello! I have implemented a custom biome, but am not sure how to change the surface of it. In the past, I used a surfacebuilder to have red sand as my top layer, but I'm not sure how to do this in 1.18. Currently, I am looking at Mixins in SurfaceRuleData (I think this is how Fabric does it). Unfortunately, this doesn't work well with Forge Registry items. How should I go about changing the surface of my biome?
-
Hmm, okay. Yeah I need to do recipes, but I'll probably just have to hard code in this specific case and have recipes as overrides. Thanks!
-
Yes, I've used the method before. Are you suggesting that I loop through every single registered block and see if it is burnable? That seems pretty laggy and I'm not even sure how to get a list of all blocks. I could yeah, but I'm not sure what you'd need to see.
-
So I would like to create a custom recipe where one of the items can be any furnace fuel. I tried using AbstractFurnaceTileEntity.getFuel() and creating an Ingredient from its keys. Unfortunately, there are a few issues with this: this method is deprecated it came up with this error on runData: "Tag minecraft:non_flammable_wood used before it was bound" it doesn't support custom furnace fuels added by other mods (I think) What would the correct way to generate a list of all furnace fuels be?
-
It works! I'm not sure about your final point about Ingredient.fromJson working already, as I used a different JSON key ('ingredientWithout' instead of 'ingredient') - so I didn't change this. Sorry to bother you again but what did you mean by 'forge:compound' earlier as a method of removing both bricks and nether bricks. I can easily do this with a custom tag, just wondering if that would be an easier way? Thanks!
-
Yep, thanks - I've fixed this. Now that I have fixed up the getItems() method, JEI has all the ingots except brick - so that respect is working great! I've done this - but unfortunately the recipe still works with brick. Here are my new files: IngredientWithout.java: package my.mod.crafting; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.tags.ITag; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; public class IngredientWithout extends Ingredient { private final Ingredient of; private final Ingredient without; protected IngredientWithout(@Nonnull ITag<Item> of, ITag<Item> without) { super(Stream.of(new Ingredient.TagList(of))); this.of = Ingredient.of(of); this.without = Ingredient.of(without); } protected IngredientWithout(@Nonnull Ingredient of, Ingredient without) { super(Arrays.stream(of.getItems()).filter((item) -> !item.isEmpty()).map(SingleItemList::new)); this.of = of; this.without = without; } public static IngredientWithout of(ITag<Item> of, ITag<Item> without) { return new IngredientWithout(of, without); } public static IngredientWithout fromJson(JsonElement jsonElement) { return new IngredientWithout(Ingredient.fromJson(jsonElement.getAsJsonObject().get("of")), Ingredient.fromJson(jsonElement.getAsJsonObject().get("without"))); } @Override public ItemStack[] getItems() { return Arrays.stream(this.of.getItems()).filter( ofItemStack -> !Arrays.stream(this.without.getItems()) .map(ItemStack::getItem) .collect(Collectors.toList()).contains(ofItemStack.getItem())) .toArray(ItemStack[]::new); } @Override public boolean test(@Nullable ItemStack p_test_1_) { if (super.test(p_test_1_)) { for (ItemStack itemStack : this.of.getItems()) { if (!this.without.test(itemStack)) return true; } } return false; } @Override public JsonElement toJson() { JsonObject jsonObject = new JsonObject(); jsonObject.add("of", this.of.toJson()); jsonObject.add("without", this.without.toJson()); return jsonObject; } } PressingRecipe.java: package my.mod.crafting.recipe; import com.google.gson.JsonObject; import my.mod.crafting.IngredientWithout; import my.mod.setup.ModRecipes; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.SingleItemRecipe; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistryEntry; import javax.annotation.Nullable; public class PressingRecipe extends SingleItemRecipe { public PressingRecipe(ResourceLocation recipeId, Ingredient ingredient, ItemStack result) { super(ModRecipes.Types.PRESSING, ModRecipes.Serialisers.PRESSING.get(), recipeId, "", ingredient, result); } @Override public boolean matches(IInventory inv, World world) { return this.ingredient.test(inv.getItem(0)); } public static class Serialiser extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<PressingRecipe> { @Override public PressingRecipe fromJson(ResourceLocation recipeId, JsonObject json) { ResourceLocation itemId = new ResourceLocation(JSONUtils.getAsString(json, "result")); int count = JSONUtils.getAsInt(json, "count", 1); ItemStack result = new ItemStack(ForgeRegistries.ITEMS.getValue(itemId), count); if (json.has("ingredientWithout")) { IngredientWithout ingredient = IngredientWithout.fromJson(json.get("ingredientWithout")); return new PressingRecipe(recipeId, ingredient, result); } else { Ingredient ingredient = Ingredient.fromJson(json.get("ingredient")); return new PressingRecipe(recipeId, ingredient, result); } } @Nullable @Override public PressingRecipe fromNetwork(ResourceLocation recipeId, PacketBuffer buffer) { Ingredient ingredient = Ingredient.fromNetwork(buffer); ItemStack result = buffer.readItem(); return new PressingRecipe(recipeId, ingredient, result); } @Override public void toNetwork(PacketBuffer buffer, PressingRecipe recipe) { recipe.ingredient.toNetwork(buffer); buffer.writeItem(recipe.result); } } }
-
Okay, so I've tried to implement this: IngredientWithout.java package my.mod.crafting; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.tags.ITag; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; public class IngredientWithout extends Ingredient { private final Ingredient of; private final Ingredient without; protected IngredientWithout(@Nonnull ITag<Item> of, ITag<Item> without) { super(Stream.of(new Ingredient.TagList(of))); this.of = Ingredient.of(of); this.without = Ingredient.of(without); } protected IngredientWithout(@Nonnull Ingredient of, Ingredient without) { super(Arrays.stream(of.getItems()).filter((item) -> !item.isEmpty()).map(SingleItemList::new)); this.of = of; this.without = without; } public static IngredientWithout of(ITag<Item> of, ITag<Item> without) { return new IngredientWithout(of, without); } public static IngredientWithout of(Ingredient of, Ingredient without) { return new IngredientWithout(of, without); } public static IngredientWithout fromJson(JsonElement jsonElement) { return new IngredientWithout(Ingredient.fromJson(jsonElement.getAsJsonObject().get("of")), Ingredient.fromJson(jsonElement.getAsJsonObject().get("without"))); } public Ingredient of() { return this.of; } public Ingredient without() { return this.without; } @Override public ItemStack[] getItems() { return Arrays.stream(this.of.getItems()).filter( item -> Arrays.asList(this.without.getItems()).contains(item)) .toArray(ItemStack[]::new); } @Override public boolean test(@Nullable ItemStack p_test_1_) { if (super.test(p_test_1_)) { for (ItemStack itemStack : this.of.getItems()) { if (!this.without.test(itemStack)) return true; } } return false; } @Override public JsonElement toJson() { JsonObject jsonObject = new JsonObject(); jsonObject.add("of", this.of.toJson()); jsonObject.add("without", this.without.toJson()); return jsonObject; } } I already have a Serialiser (as the recipe is for a custom Tile Entity), and have successfully implemented fromJson, but I'm not sure how to do fromNetwork and toNetwork as there are two ingredients: PressingRecipe.java package my.mod.crafting.recipe; import com.google.gson.JsonObject; import my.mod.crafting.IngredientWithout; import my.mod.setup.ModRecipes; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.SingleItemRecipe; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistryEntry; import javax.annotation.Nullable; public class PressingRecipe extends SingleItemRecipe { public PressingRecipe(ResourceLocation recipeId, Ingredient ingredient, ItemStack result) { super(ModRecipes.Types.PRESSING, ModRecipes.Serialisers.PRESSING.get(), recipeId, "", ingredient, result); } @Override public boolean matches(IInventory inv, World world) { return this.ingredient.test(inv.getItem(0)); } public static class Serialiser extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<PressingRecipe> { @Override public PressingRecipe fromJson(ResourceLocation recipeId, JsonObject json) { ResourceLocation itemId = new ResourceLocation(JSONUtils.getAsString(json, "result")); int count = JSONUtils.getAsInt(json, "count", 1); ItemStack result = new ItemStack(ForgeRegistries.ITEMS.getValue(itemId), count); if (json.has("ingredientWithout")) { IngredientWithout ingredient = IngredientWithout.fromJson(json.get("ingredientWithout")); return new PressingRecipe(recipeId, ingredient, result); } else { Ingredient ingredient = Ingredient.fromJson(json.get("ingredient")); return new PressingRecipe(recipeId, ingredient, result); } } @Nullable @Override public PressingRecipe fromNetwork(ResourceLocation recipeId, PacketBuffer buffer) { Ingredient of = Ingredient.fromNetwork(buffer); Ingredient without = Ingredient.fromNetwork(buffer); ItemStack result = buffer.readItem(); return new PressingRecipe(recipeId, IngredientWithout.of(of, without), result); } @Override public void toNetwork(PacketBuffer buffer, PressingRecipe recipe) { if (recipe.ingredient instanceof IngredientWithout) { ((IngredientWithout) recipe.ingredient).of().toNetwork(buffer); ((IngredientWithout) recipe.ingredient).without().toNetwork(buffer); } else { recipe.ingredient.toNetwork(buffer); } buffer.writeItem(recipe.result); } } } And this is how I implemented the recipe: PressingRecipeBuilder.builder(IngredientWithout.of(Tags.Items.INGOTS, Tags.Items.INGOTS_BRICK), ModItems.SHEET_METAL.get()) .unlockedBy("has_item", has(Tags.Items.INGOTS)) .save(consumer, mod("sheet_metal_pressing")); Unfortunately, anything from the forge:ingots tag seems to still work. This has also messed up my JEI integration (the input is blank in the JEI screen).
-
Okay, I implemented this (without the forge:compound, no idea how to do this): package my.mod.crafting; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import java.util.Arrays; import java.util.stream.Stream; public class IngredientWithout extends Ingredient { protected IngredientWithout(Stream<? extends IItemList> p_i49381_1_) { super(p_i49381_1_); } public static IngredientWithout of(Ingredient of, Ingredient without) { Stream<ItemStack> withoutItems = Arrays.stream(of.getItems()).filter(without); IngredientWithout ing = new IngredientWithout(withoutItems.filter((item) -> !item.isEmpty()).map(SingleItemList::new)); return ing.getItems().length == 0 ? new IngredientWithout(Stream.empty()) : ing; } } But it produced the same issue:
-
Sorry, I'm still not sure what you mean? I have a RegistryObject<IRecipeSerializer<PressingRecipe>> which is used for my custom recipe type. I have tried creating an Ingredient from a list of ItemStacks, generated using Tags.Items.INGOTS and removing the brick and nether brick tags (similar to as seen above) - but this produced the same error as in my original post.
-
It uses a custom recipe builder, but it's pretty similar to the furnace builders: PressingRecipeBuilder.builder(Ingredient.of(ModTags.Items.INGOTS_METAL), ModItems.SHEET_METAL.get()) .unlockedBy("has_item", has(ModTags.Items.INGOTS_METAL)) .save(consumer, mod("sheet_metal_pressing"))
-
Sorry. You said that 'I would just check at runtime if the item is in the ingots tag but not in the brick or nether brick tags'. How would I go about doing this?
-
Okay, I guess that's the only option. I'd like to have multiple recipes, so is there a good way to remove the bricks for the specific recipe instead of completely removing any support for them as an input Ingredient?
-
I think this is what you mean? ModItemTagsProvider.java package my.mod.data; import my.mod.Main; import my.mod.setup.ModTags; import net.minecraft.data.BlockTagsProvider; import net.minecraft.data.DataGenerator; import net.minecraft.data.ItemTagsProvider; import net.minecraft.item.Item; import net.minecraftforge.common.Tags; import net.minecraftforge.common.data.ExistingFileHelper; import java.util.List; public class ModItemTagsProvider extends ItemTagsProvider { public ModItemTagsProvider(DataGenerator dataGenerator, BlockTagsProvider blockTagsProvider, ExistingFileHelper existingFileHelper) { super(dataGenerator, blockTagsProvider, Main.MOD_ID, existingFileHelper); } @Override protected void addTags() { List<Item> metalIngots = Tags.Items.INGOTS.getValues(); metalIngots.removeAll(Tags.Items.INGOTS_BRICK.getValues()); metalIngots.removeAll(Tags.Items.INGOTS_NETHER_BRICK.getValues()); tag(ModTags.Items.INGOTS_METAL).add(metalIngots.toArray(new Item[0])); } } DataGenerators.java package my.mod.data; import my.mod.Main; import my.mod.data.ModBlockTagsProvider; import my.mod.data.ModItemTagsProvider; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; @EventBusSubscriber(modid = Main.MOD_ID, bus = EventBusSubscriber.Bus.MOD) public class DataGenerators { @SubscribeEvent public static void gatherData(GatherDataEvent event) { DataGenerator gen = event.getGenerator(); ExistingFileHelper fileHelper = event.getExistingFileHelper(); ModBlockTagsProvider blockTags = new ModBlockTagsProvider(gen, fileHelper); gen.addProvider(blockTags); gen.addProvider(new ModItemTagsProvider(gen, blockTags, fileHelper)); } } ModTags.java package my.mod.setup; import my.mod.Main; import net.minecraft.tags.ITag; import net.minecraft.util.ResourceLocation; import net.minecraft.item.Item; public class ModTags { public static final class Items { public static final ITag.INamedTag<Item> INGOTS_METAL = mod("metal_ingots"); private static ITag.INamedTag<Item> mod(String path) { return ItemTags.createOptional(new ResourceLocation(Main.MOD_ID, path)); } } }