Added Custom Recipe Support

This commit is contained in:
IM23a-cernik
2025-05-29 23:08:45 +02:00
parent 5b801b134b
commit 720d53fb97
6 changed files with 212 additions and 14 deletions
@@ -7,6 +7,7 @@ import net.krituximon.stalinium.item.ModCreativeModeTabs;
import net.krituximon.stalinium.item.ModItems;
import net.krituximon.stalinium.particle.BloodParticle;
import net.krituximon.stalinium.particle.ModParticles;
import net.krituximon.stalinium.recipe.ModRecipes;
import net.krituximon.stalinium.screen.ModMenuTypes;
import net.krituximon.stalinium.screen.custom.StaliniumPressScreen;
import net.krituximon.stalinium.sound.ModSounds;
@@ -57,6 +58,7 @@ public class Stalinium
ModParticles.register(modEventBus);
ModCreativeModeTabs.register(modEventBus);
PlayerLogEvents.register();
ModRecipes.register(modEventBus);
// Register ourselves for server and other game events we are interested in.
// Note that this is necessary if and only if we want *this* class (Stalinium) to respond directly to events.
@@ -1,6 +1,9 @@
package net.krituximon.stalinium.block.entity;
import net.krituximon.stalinium.item.ModItems;
import net.krituximon.stalinium.recipe.ModRecipes;
import net.krituximon.stalinium.recipe.StaliniumPressRecipe;
import net.krituximon.stalinium.recipe.StaliniumPressRecipeInput;
import net.krituximon.stalinium.screen.custom.StaliniumPressMenu;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
@@ -18,6 +21,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@@ -25,6 +29,7 @@ import net.neoforged.neoforge.items.ItemStackHandler;
import org.jetbrains.annotations.Nullable;
import javax.swing.plaf.basic.BasicComboBoxUI;
import java.util.Optional;
public class StaliniumPressBlockEntity extends BlockEntity implements MenuProvider {
public final ItemStackHandler itemHandler = new ItemStackHandler(4) {
@@ -37,10 +42,10 @@ public class StaliniumPressBlockEntity extends BlockEntity implements MenuProvid
}
};
public static final int INPUT_SLOT = 0;
public static final int REDSTONE_FUEL_SLOT = 1;
public static final int LAVA_FUEL_SLOT = 2;
public static final int OUTPUT_SLOT = 3;
public static final int INPUT_SLOT = 0;
public static final int REDSTONE_FUEL_SLOT = 1;
public static final int LAVA_FUEL_SLOT = 2;
public static final int OUTPUT_SLOT = 3;
protected final ContainerData data;
private int progress = 0;
@@ -127,11 +132,12 @@ public class StaliniumPressBlockEntity extends BlockEntity implements MenuProvid
}
private void craftItem() {
itemHandler.extractItem(INPUT_SLOT, 9, false);
Optional<RecipeHolder<StaliniumPressRecipe>> recipe = getCurrentRecipe();
itemHandler.extractItem(INPUT_SLOT, 9, false);
itemHandler.extractItem(REDSTONE_FUEL_SLOT, 1, false);
itemHandler.extractItem(LAVA_FUEL_SLOT, 1, false);
itemHandler.extractItem(LAVA_FUEL_SLOT, 1, false);
itemHandler.setStackInSlot(LAVA_FUEL_SLOT, new ItemStack(Items.BUCKET, 1));
ItemStack out = new ItemStack(ModItems.STALINIUM_INGOT.get(), 1);
ItemStack out = recipe.get().value().output();
itemHandler.setStackInSlot(
OUTPUT_SLOT,
new ItemStack(
@@ -155,17 +161,22 @@ public class StaliniumPressBlockEntity extends BlockEntity implements MenuProvid
}
private boolean hasRecipe() {
ItemStack in = itemHandler.getStackInSlot(INPUT_SLOT);
ItemStack red = itemHandler.getStackInSlot(REDSTONE_FUEL_SLOT);
ItemStack lava = itemHandler.getStackInSlot(LAVA_FUEL_SLOT);
Optional<RecipeHolder<StaliniumPressRecipe>> recipe = getCurrentRecipe();
if (recipe.isEmpty()) return false;
if (in.getItem() != ModItems.STALINIUM_NUGGET.get() || in.getCount() < 9) return false;
if (red.getItem() != Items.REDSTONE_BLOCK || red.getCount() < 1) return false;
if (lava.getItem()!= Items.LAVA_BUCKET || lava.getCount()< 1) return false;
ItemStack out = new ItemStack(ModItems.STALINIUM_INGOT.get(), 1);
ItemStack out = recipe.get().value().output();
return canInsertItemIntoOutputSlot(out) && canInsertAmountIntoOutputSlot(out.getCount());
}
private Optional<RecipeHolder<StaliniumPressRecipe>> getCurrentRecipe() {
return this.level.getRecipeManager()
.getRecipeFor(ModRecipes.STALINIUM_PRESS_TYPE.get(), new StaliniumPressRecipeInput(
itemHandler.getStackInSlot(INPUT_SLOT),
itemHandler.getStackInSlot(REDSTONE_FUEL_SLOT),
itemHandler.getStackInSlot(LAVA_FUEL_SLOT)
), level);
}
private boolean canInsertItemIntoOutputSlot(ItemStack output) {
return itemHandler.getStackInSlot(OUTPUT_SLOT).isEmpty() ||
itemHandler.getStackInSlot(OUTPUT_SLOT).getItem() == output.getItem();
@@ -0,0 +1,31 @@
package net.krituximon.stalinium.recipe;
import net.krituximon.stalinium.Stalinium;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
public class ModRecipes {
public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS =
DeferredRegister.create(Registries.RECIPE_SERIALIZER, Stalinium.MODID);
public static final DeferredRegister<RecipeType<?>> TYPES =
DeferredRegister.create(Registries.RECIPE_TYPE, Stalinium.MODID);
public static final DeferredHolder<RecipeSerializer<?>, RecipeSerializer<StaliniumPressRecipe>> STALINIUM_PRESS_SERIALIZER =
SERIALIZERS.register("stalinium_press", StaliniumPressRecipe.Serializer::new);
public static final DeferredHolder<RecipeType<?>, RecipeType<StaliniumPressRecipe>> STALINIUM_PRESS_TYPE =
TYPES.register("stalinium_press", () -> new RecipeType<StaliniumPressRecipe>() {
@Override
public String toString() {
return "stalinium_press";
}
});
public static void register(IEventBus eventBus) {
SERIALIZERS.register(eventBus);
TYPES.register(eventBus);
}
}
@@ -0,0 +1,115 @@
package net.krituximon.stalinium.recipe;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
/**
* power ingredient in slot 0
* nugget ingredient in slot 1
* fuel ingredient in slot 2
*/
public record StaliniumPressRecipe(NonNullList<Ingredient> ingredients,
ItemStack output) implements Recipe<StaliniumPressRecipeInput> {
/* --------------------------------------------------------------------- */
/* Convenience accessors referenced by the codec */
/* --------------------------------------------------------------------- */
public Ingredient power() {
return ingredients.get(0);
}
public Ingredient nugget() {
return ingredients.get(1);
}
public Ingredient fuel() {
return ingredients.get(2);
}
/* --------------------------------------------------------------------- */
/* Recipe implementation */
/* --------------------------------------------------------------------- */
@Override
public boolean matches(StaliniumPressRecipeInput input, Level level) {
if (level.isClientSide()) return false;
if (ingredients.size() != 3) return false; // malformed recipe JSON
return power().test(input.power())
&& nugget().test(input.nugget())
&& fuel().test(input.fuel());
}
@Override
public ItemStack assemble(StaliniumPressRecipeInput input, HolderLookup.Provider provider) {
return output.copy();
}
@Override
public boolean canCraftInDimensions(int w, int h) {
return true;
}
@Override
public ItemStack getResultItem(HolderLookup.Provider prov) {
return output;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ModRecipes.STALINIUM_PRESS_SERIALIZER.get();
}
@Override
public RecipeType<?> getType() {
return ModRecipes.STALINIUM_PRESS_TYPE.get();
}
/* --------------------------------------------------------------------- */
/* Serializer */
/* --------------------------------------------------------------------- */
public static class Serializer implements RecipeSerializer<StaliniumPressRecipe> {
/* ---------- Codec used for JSON files ---------- */
public static final MapCodec<StaliniumPressRecipe> CODEC =
RecordCodecBuilder.mapCodec(inst -> inst.group(
Ingredient.CODEC_NONEMPTY.fieldOf("nugget").forGetter(StaliniumPressRecipe::nugget),
Ingredient.CODEC_NONEMPTY.fieldOf("power").forGetter(StaliniumPressRecipe::power),
Ingredient.CODEC_NONEMPTY.fieldOf("fuel").forGetter(StaliniumPressRecipe::fuel),
ItemStack.CODEC.fieldOf("result").forGetter(StaliniumPressRecipe::output)
).apply(inst, (p, n, f, res) -> {
NonNullList<Ingredient> list = NonNullList.of(Ingredient.EMPTY, p, n, f);
return new StaliniumPressRecipe(list, res);
}));
/* ---------- Codec used for network sync ---------- */
private static final StreamCodec<RegistryFriendlyByteBuf, StaliniumPressRecipe> STREAM_CODEC =
StreamCodec.composite(
Ingredient.CONTENTS_STREAM_CODEC, StaliniumPressRecipe::power,
Ingredient.CONTENTS_STREAM_CODEC, StaliniumPressRecipe::nugget,
Ingredient.CONTENTS_STREAM_CODEC, StaliniumPressRecipe::fuel,
ItemStack.STREAM_CODEC, StaliniumPressRecipe::output,
(p, n, f, res) -> {
NonNullList<Ingredient> list = NonNullList.of(Ingredient.EMPTY, p, n, f);
return new StaliniumPressRecipe(list, res);
}
);
@Override
public MapCodec<StaliniumPressRecipe> codec() {
return CODEC;
}
@Override
public StreamCodec<RegistryFriendlyByteBuf, StaliniumPressRecipe> streamCodec() {
return STREAM_CODEC;
}
}
}
@@ -0,0 +1,24 @@
package net.krituximon.stalinium.recipe;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeInput;
public record StaliniumPressRecipeInput(ItemStack power, ItemStack nugget, ItemStack fuel) implements RecipeInput {
@Override
public ItemStack getItem(int i) {
ItemStack var10000 = null;
switch (i) {
case 1 -> var10000 = power;
case 0 -> var10000 = nugget;
case 2 -> var10000 = fuel;
default -> throw new IllegalArgumentException("Recipe does not contain slot " + i);
}
return var10000;
}
@Override
public int size() {
return 3;
}
}