Skip to content

Commit

Permalink
refactor: refactor inventory handling of block entities and menus
Browse files Browse the repository at this point in the history
  • Loading branch information
Elenterius committed Oct 13, 2024
1 parent 7a47262 commit 747d96f
Show file tree
Hide file tree
Showing 67 changed files with 1,223 additions and 1,224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jetbrains.annotations.ApiStatus;

import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;

@ApiStatus.Experimental
public final class Nutrients {
Expand All @@ -19,6 +20,7 @@ public final class Nutrients {
private static final Object2IntMap<Item> REPAIR_VALUES = new Object2IntArrayMap<>();

public static final IntUnaryOperator RAW_MEAT_NUTRITION_MODIFIER = nutrition -> nutrition > 0 ? Mth.ceil(3.75d * Math.exp(0.215d * nutrition)) : 0;
public static final Predicate<ItemStack> FUEL_PREDICATE = Nutrients::isValidFuel;

static {
registerFuel(ModItems.NUTRIENT_PASTE.get(), 3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState new
updateNeighbors(level, pos);
}
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof MachineBlockEntity<?, ?, ?> machine) {
if (blockEntity instanceof MachineBlockEntity<?, ?> machine) {
machine.dropAllInvContents(level, pos);
}
if (Boolean.TRUE.equals(state.getValue(CRAFTING))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import com.github.elenterius.biomancy.crafting.state.CraftingState;
import com.github.elenterius.biomancy.crafting.state.RecipeCraftingStateData;
import com.github.elenterius.biomancy.init.ModBlockProperties;
import com.github.elenterius.biomancy.inventory.InventoryHandler;
import com.github.elenterius.biomancy.util.PlayerInteractionPredicate;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
import net.minecraft.world.Nameable;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
Expand All @@ -21,7 +22,7 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;

public abstract class MachineBlockEntity<R extends ProcessingRecipe<C>, C extends Container, S extends RecipeCraftingStateData<R, C>> extends BlockEntity implements Nameable {
public abstract class MachineBlockEntity<R extends ProcessingRecipe, S extends RecipeCraftingStateData<R>> extends BlockEntity implements Nameable, PlayerInteractionPredicate {

protected final int tickOffset = BiomancyMod.GLOBAL_RANDOM.nextInt(20);
protected int ticks = tickOffset;
Expand All @@ -30,27 +31,33 @@ protected MachineBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState s
super(type, pos, state);
}

public static <R extends ProcessingRecipe<C>, C extends Container, S extends RecipeCraftingStateData<R, C>> void serverTick(Level level, BlockPos pos, BlockState state, MachineBlockEntity<R, C, S> entity) {
public static <R extends ProcessingRecipe, S extends RecipeCraftingStateData<R>> void serverTick(Level level, BlockPos pos, BlockState state, MachineBlockEntity<R, S> entity) {
entity.serverTick((ServerLevel) level);
}

public boolean canPlayerOpenInv(Player player) {
@Override
public boolean canPlayerInteract(Player player) {
if (isRemoved()) return false;
if (level == null || level.getBlockEntity(worldPosition) != this) return false;
return player.distanceToSqr(Vec3.atCenterOf(worldPosition)) < 8d * 8d;
}

protected void onInventoryChanged() {
if (level != null && !level.isClientSide) setChanged();
}

public int getTicks() {
return ticks - tickOffset;
}

protected abstract S getStateData();

protected abstract C getInputInventory();
protected abstract InventoryHandler getInputInventory();

protected abstract IFuelHandler getFuelHandler();

public int getFuelCost(R recipeToCraft) {
return getFuelHandler().getFuelCost(recipeToCraft.getCraftingCostNutrients(getInputInventory()));
return getFuelHandler().getFuelCost(recipeToCraft.getCraftingCostNutrients(getInputInventory().getRecipeWrapper()));
}

public abstract ItemStack getStackInFuelSlot();
Expand Down Expand Up @@ -111,7 +118,7 @@ protected void serverTick(final ServerLevel level) {
if (hasEnoughFuel(craftingGoal)) { //make sure there is enough fuel to craft the recipe
state.setCraftingState(CraftingState.IN_PROGRESS);
state.clear(); //safeguard, shouldn't be needed
state.setCraftingGoalRecipe(craftingGoal, getInputInventory()); // this also sets the time required for crafting
state.setCraftingGoalRecipe(craftingGoal, getInputInventory().getRecipeWrapper()); // this also sets the time required for crafting
}
} else if (!state.isCraftingCanceled()) { // something is being crafted, check that the crafting goals match
R prevCraftingGoal = state.getCraftingGoalRecipe(level).orElse(null);
Expand Down Expand Up @@ -163,7 +170,7 @@ else if (state.getCraftingState() == CraftingState.NONE) {

private ItemStack getItemToCraft(ServerLevel level, R craftingGoal) {
if (craftingGoal.isSpecial()) {
return craftingGoal.assemble(getInputInventory(), level.registryAccess());
return craftingGoal.assemble(getInputInventory().getRecipeWrapper(), level.registryAccess());
}
return craftingGoal.getResultItem(level.registryAccess());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.elenterius.biomancy.block.base;

import com.github.elenterius.biomancy.util.PlayerInteractionPredicate;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
Expand All @@ -14,15 +15,17 @@
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;

public abstract class SimpleContainerBlockEntity extends BlockEntity implements MenuProvider, Nameable {
public abstract class SimpleContainerBlockEntity extends BlockEntity implements MenuProvider, PlayerInteractionPredicate, Nameable {

protected Component name;

protected SimpleContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}

public boolean canPlayerOpenContainer(Player player) {
@Override
public boolean canPlayerInteract(Player player) {
if (isRemoved()) return false;
if (level == null || level.getBlockEntity(worldPosition) != this) return false;
return player.distanceToSqr(Vec3.atCenterOf(worldPosition)) < 8d * 8d;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource

@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (level.getBlockEntity(pos) instanceof BioForgeBlockEntity bioForge && bioForge.canPlayerOpenInv(player)) {
if (level.getBlockEntity(pos) instanceof BioForgeBlockEntity bioForge && bioForge.canPlayerInteract(player)) {
if (!level.isClientSide) {
NetworkHooks.openScreen((ServerPlayer) player, bioForge, buffer -> buffer.writeBlockPos(pos));
SoundUtil.broadcastBlockSound((ServerLevel) level, pos, ModSoundEvents.UI_BIO_FORGE_OPEN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import com.github.elenterius.biomancy.BiomancyMod;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModCapabilities;
import com.github.elenterius.biomancy.inventory.BehavioralInventory;
import com.github.elenterius.biomancy.inventory.itemhandler.HandlerBehaviors;
import com.github.elenterius.biomancy.inventory.InventoryHandler;
import com.github.elenterius.biomancy.inventory.InventoryHandlers;
import com.github.elenterius.biomancy.inventory.ItemHandlerUtil;
import com.github.elenterius.biomancy.menu.BioForgeMenu;
import com.github.elenterius.biomancy.styles.TextComponentUtil;
import com.github.elenterius.biomancy.util.PlayerInteractionPredicate;
import com.github.elenterius.biomancy.util.fuel.FluidFuelConsumerHandler;
import com.github.elenterius.biomancy.util.fuel.FuelHandler;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
Expand All @@ -16,13 +18,11 @@
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.Nameable;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
Expand All @@ -45,15 +45,17 @@
import javax.annotation.Nonnull;
import java.util.Objects;

public class BioForgeBlockEntity extends BlockEntity implements MenuProvider, Nameable, GeoBlockEntity {
public class BioForgeBlockEntity extends BlockEntity implements MenuProvider, PlayerInteractionPredicate, Nameable, GeoBlockEntity {

public static final int FUEL_SLOTS = 1;
public static final int MAX_FUEL = 1_000;
static final int OPENERS_CHANGE_EVENT = 1;

protected final int tickOffset = BiomancyMod.GLOBAL_RANDOM.nextInt(20);

private final BioForgeStateData stateData;
private final FuelHandler fuelHandler;
private final BehavioralInventory<?> fuelInventory;
private final InventoryHandler fuelInventory;

private final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {

Expand Down Expand Up @@ -82,7 +84,9 @@ protected boolean isOwnContainer(Player player) {
return false;
}
};

private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);

protected int ticks = tickOffset;
private boolean playWorkingAnimation = false;
private int nearbyTimer = -10;
Expand All @@ -91,9 +95,7 @@ protected boolean isOwnContainer(Player player) {

public BioForgeBlockEntity(BlockPos worldPosition, BlockState blockState) {
super(ModBlockEntities.BIO_FORGE.get(), worldPosition, blockState);
fuelInventory = BehavioralInventory.createServerContents(FUEL_SLOTS, HandlerBehaviors::filterFuel, this::canPlayerOpenInv, this::setChanged);
fuelInventory.setOpenInventoryConsumer(this::startOpen);
fuelInventory.setCloseInventoryConsumer(this::stopOpen);
fuelInventory = InventoryHandlers.filterFuel(FUEL_SLOTS, this::onInventoryChanged);

fuelHandler = FuelHandler.createNutrientFuelHandler(MAX_FUEL, this::setChanged);
stateData = new BioForgeStateData(fuelHandler);
Expand All @@ -117,17 +119,22 @@ public boolean triggerEvent(int id, int type) {
return super.triggerEvent(id, type);
}

public boolean canPlayerOpenInv(Player player) {
@Override
public boolean canPlayerInteract(Player player) {
if (level == null || level.getBlockEntity(worldPosition) != this) return false;
return player.distanceToSqr(Vec3.atCenterOf(worldPosition)) < 8d * 8d;
}

private void startOpen(Player player) {
protected void onInventoryChanged() {
if (level != null && !level.isClientSide) setChanged();
}

public void startOpen(Player player) {
if (remove || player.isSpectator()) return;
openersCounter.incrementOpeners(player, Objects.requireNonNull(getLevel()), getBlockPos(), getBlockState());
}

private void stopOpen(Player player) {
public void stopOpen(Player player) {
if (remove || player.isSpectator()) return;
openersCounter.decrementOpeners(player, Objects.requireNonNull(getLevel()), getBlockPos(), getBlockState());
}
Expand All @@ -140,7 +147,11 @@ public void recheckOpen() {
@Nullable
@Override
public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) {
return BioForgeMenu.createServerMenu(containerId, playerInventory, fuelInventory, stateData, ContainerLevelAccess.create(level, getBlockPos()));
return BioForgeMenu.createServerMenu(containerId, playerInventory, this);
}

public InventoryHandler getFuelInventory() {
return fuelInventory;
}

public BioForgeStateData getStateData() {
Expand Down Expand Up @@ -176,11 +187,11 @@ public int getMaxFuelAmount() {
}

public ItemStack getStackInFuelSlot() {
return fuelInventory.getItem(0);
return fuelInventory.getStackInSlot(0);
}

public void setStackInFuelSlot(ItemStack stack) {
fuelInventory.setItem(0, stack);
fuelInventory.setStackInSlot(0, stack);
}

@Override
Expand All @@ -198,7 +209,7 @@ public void load(CompoundTag tag) {
}

public void dropAllInvContents(Level level, BlockPos pos) {
Containers.dropContents(level, pos, fuelInventory);
ItemHandlerUtil.dropContents(level, pos, fuelInventory);
}

@Nonnull
Expand All @@ -207,7 +218,7 @@ public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable Direction
if (remove) return super.getCapability(cap, side);

if (cap == ModCapabilities.ITEM_HANDLER && side != null && side.getAxis().isHorizontal()) {
return fuelInventory.getOptionalItemHandler().cast();
return fuelInventory.getLazyOptional().cast();
}

if (cap == ModCapabilities.FLUID_HANDLER) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, Block

@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (level.getBlockEntity(pos) instanceof BioLabBlockEntity bioLab && bioLab.canPlayerOpenInv(player)) {
if (level.getBlockEntity(pos) instanceof BioLabBlockEntity bioLab && bioLab.canPlayerInteract(player)) {
if (!level.isClientSide) {
NetworkHooks.openScreen((ServerPlayer) player, bioLab, buffer -> buffer.writeBlockPos(pos));
SoundUtil.broadcastBlockSound((ServerLevel) level, pos, ModSoundEvents.UI_BIO_LAB_OPEN);
Expand Down
Loading

0 comments on commit 747d96f

Please sign in to comment.