Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Recipe Logic for DiskAssemblerBlock #9

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -49,7 +51,12 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new DiskAssemblerBlockEntity(blockPos, blockState);
}


@Override
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, @NotNull BlockState blockState, @NotNull BlockEntityType<T> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
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;
import net.minecraft.world.entity.player.Inventory;
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;

Expand All @@ -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);
}
Expand All @@ -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<DiskAssemblerRecipe> 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;
Expand All @@ -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() {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -33,29 +31,26 @@ public record DiskAssemblerRecipe(
) implements Recipe<RecipeWrapper>, RecipeType<DiskAssemblerRecipe> {

@Override
public boolean matches(RecipeWrapper recipeWrapper, Level level) {
ItemStack[] mainItems = {recipeWrapper.getItem(0), recipeWrapper.getItem(1), recipeWrapper.getItem(2)};
List<Predicate<ItemStack>> toTest = Arrays.asList(diskPort, diskCasing, screws);

for (Predicate<ItemStack> 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
Expand Down
Loading