249 lines
8.7 KiB
Java
249 lines
8.7 KiB
Java
/*
|
|
* Ex Deorum
|
|
* Copyright (c) 2024 thedarkcolour
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package thedarkcolour.exdeorum.blockentity;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.util.RandomSource;
|
|
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.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.enchantment.Enchantments;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.storage.loot.LootContext;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import thedarkcolour.exdeorum.block.MechanicalHammerBlock;
|
|
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
|
|
import thedarkcolour.exdeorum.config.EConfig;
|
|
import thedarkcolour.exdeorum.data.TranslationKeys;
|
|
import thedarkcolour.exdeorum.loot.HammerLootModifier;
|
|
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
|
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
|
|
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
|
import thedarkcolour.exdeorum.tag.EItemTags;
|
|
|
|
public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity<MechanicalHammerBlockEntity> {
|
|
private static final Component TITLE = Component.translatable(TranslationKeys.MECHANICAL_HAMMER_SCREEN_TITLE);
|
|
private static final int INPUT_SLOT = 0;
|
|
private static final int HAMMER_SLOT = 1;
|
|
private static final int OUTPUT_SLOT = 2;
|
|
public static final int TOTAL_PROGRESS = 10_000_000;
|
|
// process should take 320 ticks or 10 seconds with no efficiency
|
|
private static final int PROGRESS_INTERVAL = TOTAL_PROGRESS / 200;
|
|
public static final int NOT_RUNNING = -1;
|
|
|
|
// an integer from 0 to 10,000,000 instead of a decimal number which is inaccurate and buggy
|
|
private int progress = -1;
|
|
private float efficiency;
|
|
|
|
public MechanicalHammerBlockEntity(BlockPos pos, BlockState state) {
|
|
super(EBlockEntities.MECHANICAL_HAMMER.get(), pos, state, ItemHandler::new, EConfig.SERVER.mechanicalHammerEnergyStorage.get());
|
|
}
|
|
|
|
public static boolean isValidInput(ItemStack stack) {
|
|
return RecipeUtil.getHammerRecipe(stack.getItem()) != null;
|
|
}
|
|
|
|
@Override
|
|
protected void saveAdditional(CompoundTag nbt) {
|
|
super.saveAdditional(nbt);
|
|
|
|
nbt.putInt("progress", this.progress);
|
|
}
|
|
|
|
@Override
|
|
public void load(CompoundTag nbt) {
|
|
super.load(nbt);
|
|
|
|
this.progress = nbt.getInt("progress");
|
|
onHammerChanged();
|
|
}
|
|
|
|
@Override
|
|
public Component getDisplayName() {
|
|
return TITLE;
|
|
}
|
|
|
|
@Override
|
|
public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player pPlayer) {
|
|
return new MechanicalHammerMenu(containerId, playerInventory, this);
|
|
}
|
|
|
|
@Override
|
|
protected boolean isRunning() {
|
|
return this.progress != NOT_RUNNING;
|
|
}
|
|
|
|
@Override
|
|
protected void tryStartRunning() {
|
|
var input = this.inventory.getStackInSlot(INPUT_SLOT);
|
|
|
|
if (!input.isEmpty() && !this.inventory.getStackInSlot(HAMMER_SLOT).isEmpty()) {
|
|
if (canFitResultIntoOutput(input) != null) {
|
|
this.progress = 0;
|
|
this.level.setBlock(this.worldPosition, this.getBlockState().setValue(MechanicalHammerBlock.RUNNING, true), 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private HammerRecipe canFitResultIntoOutput(ItemStack input) {
|
|
var output = this.inventory.getStackInSlot(OUTPUT_SLOT);
|
|
|
|
if (output.isEmpty() || output.getCount() < output.getMaxStackSize()) {
|
|
var recipe = RecipeUtil.getHammerRecipe(input.getItem());
|
|
|
|
if (recipe != null && (output.isEmpty() || matchesStack(recipe.result, output))) {
|
|
return recipe;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static boolean matchesStack(Item item, ItemStack stack) {
|
|
return !stack.hasTag() && item == stack.getItem();
|
|
}
|
|
|
|
@Override
|
|
protected void runMachineTick() {
|
|
var input = this.inventory.getStackInSlot(INPUT_SLOT);
|
|
|
|
if (!input.isEmpty() && !this.inventory.getStackInSlot(HAMMER_SLOT).isEmpty()) {
|
|
this.progress += PROGRESS_INTERVAL * this.efficiency;
|
|
|
|
if (this.progress >= TOTAL_PROGRESS) {
|
|
var recipe = canFitResultIntoOutput(input);
|
|
|
|
if (recipe != null) {
|
|
@SuppressWarnings("DataFlowIssue")
|
|
LootContext ctx = RecipeUtil.emptyLootContext((ServerLevel) this.level);
|
|
var resultCount = recipe.resultAmount.getInt(ctx);
|
|
resultCount += HammerLootModifier.calculateFortuneBonus(this.inventory.getStackInSlot(HAMMER_SLOT), ctx.getRandom(), resultCount == 0);
|
|
var output = this.inventory.getStackInSlot(OUTPUT_SLOT);
|
|
if (output.isEmpty()) {
|
|
this.inventory.setStackInSlot(OUTPUT_SLOT, new ItemStack(recipe.result, resultCount));
|
|
} else {
|
|
output.setCount(Math.min(output.getMaxStackSize(), resultCount + output.getCount()));
|
|
}
|
|
input.shrink(1);
|
|
damageHammer(ctx.getRandom());
|
|
|
|
setChanged();
|
|
}
|
|
|
|
this.progress = NOT_RUNNING;
|
|
}
|
|
} else {
|
|
this.level.setBlock(this.worldPosition, this.getBlockState().setValue(MechanicalHammerBlock.RUNNING, false), 3);
|
|
}
|
|
}
|
|
|
|
private void damageHammer(RandomSource rand) {
|
|
var hammer = this.inventory.getStackInSlot(HAMMER_SLOT);
|
|
|
|
if (hammer.isDamageableItem()) {
|
|
|
|
if (hammer.hurt(1, rand, null)) {
|
|
hammer.shrink(1);
|
|
|
|
if (hammer.isEmpty()) {
|
|
this.inventory.setStackInSlot(HAMMER_SLOT, ItemStack.EMPTY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void onHammerChanged() {
|
|
var hammer = this.inventory.getStackInSlot(HAMMER_SLOT);
|
|
if (hammer.isEmpty()) {
|
|
this.progress = NOT_RUNNING;
|
|
}
|
|
this.efficiency = 1f + hammer.getEnchantmentLevel(Enchantments.BLOCK_EFFICIENCY) * 0.17f;
|
|
}
|
|
|
|
@Override
|
|
protected int getEnergyConsumption() {
|
|
return EConfig.SERVER.mechanicalHammerEnergyConsumption.get();
|
|
}
|
|
|
|
// The value synced to the client for rendering the arrow in GUI
|
|
public int getGuiProgress() {
|
|
return Math.round((float)(24 * this.progress) / TOTAL_PROGRESS);
|
|
}
|
|
|
|
public void setGuiProgress(int guiProgress) {
|
|
this.progress = (guiProgress * TOTAL_PROGRESS) / 24;
|
|
}
|
|
|
|
public int getProgress() {
|
|
return this.progress;
|
|
}
|
|
|
|
public void setProgress(int progress) {
|
|
this.progress = progress;
|
|
}
|
|
|
|
private static class ItemHandler extends ItemHelper {
|
|
private final MechanicalHammerBlockEntity hammer;
|
|
|
|
public ItemHandler(MechanicalHammerBlockEntity hammer) {
|
|
super(3);
|
|
this.hammer = hammer;
|
|
}
|
|
|
|
@Override
|
|
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
|
|
if (slot == INPUT_SLOT) {
|
|
return RecipeUtil.getHammerRecipe(stack.getItem()) != null;
|
|
} else if (slot == HAMMER_SLOT) {
|
|
return stack.is(EItemTags.HAMMERS);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getSlotLimit(int slot) {
|
|
return slot == HAMMER_SLOT ? 1 : super.getSlotLimit(slot);
|
|
}
|
|
|
|
@Override
|
|
public boolean canMachineExtract(int slot) {
|
|
return slot == OUTPUT_SLOT;
|
|
}
|
|
|
|
@Override
|
|
protected void onContentsChanged(int slot) {
|
|
if (slot == HAMMER_SLOT) {
|
|
this.hammer.onHammerChanged();
|
|
} else if (slot == INPUT_SLOT) {
|
|
if (getStackInSlot(INPUT_SLOT).isEmpty()) {
|
|
this.hammer.progress = NOT_RUNNING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|