diff --git a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlock.java b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlock.java index 47539c8..78bbd8a 100644 --- a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlock.java +++ b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlock.java @@ -13,6 +13,8 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -49,7 +51,12 @@ protected void createBlockStateDefinition(StateDefinition.Builder BlockEntityTicker getTicker(Level level, @NotNull BlockState blockState, @NotNull BlockEntityType blockEntityType) { + return level.isClientSide ? null : ((level1, pos, state, blockEntity) -> ((DiskAssemblerBlockEntity) blockEntity).tick()); + } + @Override protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { if (player instanceof ServerPlayer serverPlayer) { diff --git a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlockEntity.java b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlockEntity.java index f7af49a..34119a5 100644 --- a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlockEntity.java +++ b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerBlockEntity.java @@ -1,11 +1,14 @@ package dev.wolfieboy09.qstorage.block.disk_assembler; +import dev.wolfieboy09.qstorage.QuantiumizedStorage; import dev.wolfieboy09.qstorage.block.AbstractEnergyBlockEntity; import dev.wolfieboy09.qstorage.registries.QSBlockEntities; +import dev.wolfieboy09.qstorage.registries.QSRecipes; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.world.MenuProvider; import net.minecraft.world.SimpleContainer; @@ -13,9 +16,13 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.block.state.BlockState; import net.neoforged.neoforge.energy.EnergyStorage; import net.neoforged.neoforge.items.ItemStackHandler; +import net.neoforged.neoforge.items.wrapper.RecipeWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +34,9 @@ public class DiskAssemblerBlockEntity extends AbstractEnergyBlockEntity implemen private int progress = 0; private int crafting_ticks = 0; private int energy_required = 0; - + private DiskAssemblerRecipe recipe = null; + private boolean isValidRecipe = false; + public DiskAssemblerBlockEntity(BlockPos pos, BlockState blockState) { super(QSBlockEntities.DISK_ASSEMBLER.get(), pos, blockState, getEnergyCapacity(), 1000, 0); } @@ -43,6 +52,95 @@ public DiskAssemblerBlockEntity(BlockPos pos, BlockState blockState) { return new DiskAssemblerMenu(id, this.getBlockPos(), playerInv, player, this.energyData); } + public void tick() { + if (this.level == null || getInputContainer().isEmpty()) return; + + // Validate the recipe + if (!this.isValidRecipe) return; + + // Check if output has space before crafting + ItemStack outputSlotStack = this.inventory.getStackInSlot(DiskAssemblerSlot.OUTPUT_SLOT); + ItemStack resultItem = this.recipe.getResultItem(this.level.registryAccess()); + + boolean outputHasSpace = outputSlotStack.isEmpty() || + (outputSlotStack.getItem() == resultItem.getItem() && + outputSlotStack.getCount() + resultItem.getCount() <= outputSlotStack.getMaxStackSize()); + + if (!outputHasSpace) return; // Exit if output slot lacks space + + // Check energy and progress crafting if energy is sufficient + boolean energySufficient = this.energyStorage.getEnergyStored() >= this.recipe.energyCost(); + int timeRequired = this.recipe.timeInTicks(); + + if (energySufficient) { + if (this.crafting_ticks < timeRequired) { + this.crafting_ticks++; + this.progress = getProgress(); + QuantiumizedStorage.LOGGER.debug("Progress: {}", this.progress); + } + + // If progress reaches 100%, complete the crafting + if (this.progress >= 100) { + // Consume energy and input items + this.energyStorage.removeEnergy(this.recipe.energyCost()); // Extract energy here upon successful crafting + consumeInputItems(); + + // Place result in output slot + if (outputSlotStack.isEmpty()) { + this.inventory.setStackInSlot(DiskAssemblerSlot.OUTPUT_SLOT, resultItem.copy()); + } else { + outputSlotStack.grow(resultItem.getCount()); + } + + // Reset crafting progress + resetProgress(); + } + } + } + + private int getProgress() { + return (int) (this.crafting_ticks / (float) this.recipe.timeInTicks() * 100); + } + + private void consumeInputItems() { + this.inventory.getStackInSlot(DiskAssemblerSlot.MAIN_SLOT_1).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.MAIN_SLOT_2).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.MAIN_SLOT_3).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.EXTRA_SLOT_1).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.EXTRA_SLOT_2).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.EXTRA_SLOT_3).shrink(1); + this.inventory.getStackInSlot(DiskAssemblerSlot.EXTRA_SLOT_4).shrink(1); + } + + protected void resetProgress() { + this.crafting_ticks = 0; + this.progress = 0; + } + + private boolean checkRecipe(){ + // Get the input items + if (this.level == null) return false; + var inputHandler = new ItemStackHandler(7); + for (int i = 0; i < 7; i++) { + inputHandler.setStackInSlot(i, this.inventory.getStackInSlot(i)); + } + RecipeWrapper input = new RecipeWrapper(inputHandler); + RecipeManager recipes = this.level.getRecipeManager(); + RecipeHolder recipeFound = recipes.getRecipeFor( + QSRecipes.DISK_ASSEMBLER_TYPE.get(), + input, + this.level + ).orElseGet(()->null); + if (recipeFound == null) return false; + DiskAssemblerRecipe recipe = recipeFound.value(); + boolean matches = recipe.matches(input, this.level); + if (!matches) return false; + ItemStack result = recipe.assemble(input, this.level.registryAccess()); + if (result.isEmpty()) return false; + this.recipe = recipe; + return true; + } + public static class DiskAssemblerSlot { public static final int MAIN_SLOT_1 = 0; public static final int MAIN_SLOT_2 = 1; @@ -58,16 +156,16 @@ public static class DiskAssemblerSlot { @Override protected void onContentsChanged(int slot) { if (slot < 7) { - resetProgress(); + boolean isValidRecipe = checkRecipe(); + if (!isValidRecipe) resetProgress(); + setIsValidRecipe(isValidRecipe); } setChanged(); } }; - - protected void resetProgress() { - if (this.progress != 0) { - this.progress = 0; - } + + private void setIsValidRecipe(boolean value){ + this.isValidRecipe = value; } public ItemStackHandler getInventory() { @@ -128,6 +226,24 @@ public SimpleContainer getOutputContainer() { container.setItem(0, inventory.getStackInSlot(inventory.getSlots() - 1)); return container; } + + private void saveRecipeToNBT(CompoundTag modData, HolderLookup.Provider registries) { + try { + if (this.recipe instanceof DiskAssemblerRecipe t) { + modData.put("recipe", DiskAssemblerRecipe.CODEC.encodeStart(NbtOps.INSTANCE, t).getOrThrow()); + } + } catch (Exception e) { + QuantiumizedStorage.LOGGER.error("Error saving recipe to NBT: {}", e.getMessage()); + } + } + + private void loadRecipeFromNBT(CompoundTag recipeTag) { + var recipe = Recipe.CODEC.parse(NbtOps.INSTANCE, recipeTag).getOrThrow(); + if (recipe instanceof DiskAssemblerRecipe diskAssemblerRecipe) { + this.recipe = diskAssemblerRecipe; + } + } + @Override public void saveExtra(CompoundTag tag, HolderLookup.Provider registries) { @@ -136,6 +252,8 @@ public void saveExtra(CompoundTag tag, HolderLookup.Provider registries) { tag.putInt("energy_required", this.energy_required); tag.putInt("crafting_ticks", this.crafting_ticks); tag.put("inventory", this.inventory.serializeNBT(registries)); + tag.putBoolean("isValidRecipe", this.isValidRecipe); + saveRecipeToNBT(tag, registries); } @Override @@ -145,6 +263,11 @@ protected void loadExtra(CompoundTag tag, HolderLookup.Provider registries) { this.energy_required = tag.getInt("energy_required"); this.crafting_ticks = tag.getInt("crafting_ticks"); this.inventory.deserializeNBT(registries, tag.getCompound("inventory")); + this.isValidRecipe = tag.getBoolean("isValidRecipe"); + // Load the recipe if it exists + if (tag.contains("recipe")) { + loadRecipeFromNBT(tag.getCompound("recipe")); + } } @Override diff --git a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerRecipe.java b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerRecipe.java index 0916c52..dc8a1fa 100644 --- a/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerRecipe.java +++ b/src/main/java/dev/wolfieboy09/qstorage/block/disk_assembler/DiskAssemblerRecipe.java @@ -17,9 +17,7 @@ import org.jetbrains.annotations.NotNull; import javax.annotation.ParametersAreNonnullByDefault; -import java.util.Arrays; import java.util.List; -import java.util.function.Predicate; @ParametersAreNonnullByDefault public record DiskAssemblerRecipe( @@ -33,29 +31,26 @@ public record DiskAssemblerRecipe( ) implements Recipe, RecipeType { @Override - public boolean matches(RecipeWrapper recipeWrapper, Level level) { - ItemStack[] mainItems = {recipeWrapper.getItem(0), recipeWrapper.getItem(1), recipeWrapper.getItem(2)}; - List> toTest = Arrays.asList(diskPort, diskCasing, screws); - - for (Predicate test : toTest) { - if (Arrays.stream(mainItems).noneMatch(test)) { - return false; - } - } - - for (int i = 3; i <= 6; i++) { - ItemStack extraItem = recipeWrapper.getItem(i); - if (extras.stream().noneMatch(extra -> extra.test(extraItem))) { - return false; + public boolean matches(RecipeWrapper input, Level level) { + boolean extrasMatch = !this.extras.isEmpty(); + for (Ingredient extra : this.extras) { + if (!extra.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.EXTRA_SLOT_1)) + && !extra.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.EXTRA_SLOT_2)) + && !extra.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.EXTRA_SLOT_3)) + && !extra.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.EXTRA_SLOT_4))) { + extrasMatch = false; } } - return true; + + return this.diskPort.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.MAIN_SLOT_1)) + && this.diskCasing.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.MAIN_SLOT_2)) + && this.screws.test(input.getItem(DiskAssemblerBlockEntity.DiskAssemblerSlot.MAIN_SLOT_3)) + && extrasMatch; } - @Override public @NotNull ItemStack assemble(RecipeWrapper recipeWrapper, HolderLookup.Provider provider) { - return this.result.copy(); + return getResultItem(provider); } @Override