Added Block Breaker and Block Placer Machine. Huge thanks to SimonFlapse

* Added advancements crafting data for block breaker and placer

(From 7a31de7b869e67697f85aeca9f0a5099c6bc7d62)
Added Block Breaker Machine (#2871)

* Added a new machine that can break blocks in front of it

(From e56a51da2b0c4e144cdf70ebff53d7097e81b5ce)
Added Block Placer Machine

* Added a new machine that can place blocks in front of it

(From e80de2ec82e0a14f161137e4b147bb455a839e3d)
Added Block Breaker and Placer recipe

(From dccdf76eacb8ceb7075897170e098bc346b8b4db)
Break blocks instead of removing + Refactoring
This commit is contained in:
Simon 2022-04-02 09:47:36 +02:00 committed by GitHub
parent c8ca8a5aa3
commit 7f2912009b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1543 additions and 10 deletions

View file

@ -66,7 +66,7 @@ import java.util.Optional;
/**
* Created by modmuss50 on 04/11/2016.
*/
public class MachineBaseBlockEntity extends BlockEntity implements BlockEntityTicker<MachineBaseBlockEntity>, IUpgradeable, IUpgradeHandler, IListInfoProvider, Inventory, SidedInventory {
public class MachineBaseBlockEntity extends BlockEntity implements BlockEntityTicker<MachineBaseBlockEntity>, IUpgradeable, IUpgradeHandler, IListInfoProvider, Inventory, SidedInventory, RedstoneConfigurable {
public RebornInventory<MachineBaseBlockEntity> upgradeInventory = new RebornInventory<>(getUpgradeSlotCount(), "upgrades", 1, this, (slotID, stack, face, direction, blockEntity) -> true);
private SlotConfiguration slotConfiguration;
@ -518,6 +518,7 @@ public class MachineBaseBlockEntity extends BlockEntity implements BlockEntityTi
return redstoneConfiguration;
}
@Override
public boolean isActive(RedstoneConfiguration.Element element) {
return redstoneConfiguration.isActive(element);
}

View file

@ -0,0 +1,5 @@
package reborncore.common.blockentity;
public interface RedstoneConfigurable {
boolean isActive(RedstoneConfiguration.Element element);
}

View file

@ -40,8 +40,8 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import reborncore.api.blockentity.IMachineGuiHandler;
import reborncore.common.screen.BuiltScreenHandlerProvider;
import reborncore.common.screen.BuiltScreenHandler;
import reborncore.common.screen.BuiltScreenHandlerProvider;
import techreborn.blockentity.data.DataDrivenBEProvider;
import techreborn.blockentity.generator.PlasmaGeneratorBlockEntity;
import techreborn.blockentity.generator.SolarPanelBlockEntity;
@ -54,6 +54,8 @@ import techreborn.blockentity.machine.iron.IronAlloyFurnaceBlockEntity;
import techreborn.blockentity.machine.iron.IronFurnaceBlockEntity;
import techreborn.blockentity.machine.misc.ChargeOMatBlockEntity;
import techreborn.blockentity.machine.multiblock.*;
import techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity;
import techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity;
import techreborn.blockentity.machine.tier1.*;
import techreborn.blockentity.machine.tier3.ChunkLoaderBlockEntity;
import techreborn.blockentity.machine.tier3.IndustrialCentrifugeBlockEntity;
@ -118,6 +120,8 @@ public final class GuiType<T extends BlockEntity> implements IMachineGuiHandler
public static final GuiType<FluidReplicatorBlockEntity> FLUID_REPLICATOR = register("fluid_replicator");
public static final GuiType<PlayerDetectorBlockEntity> PLAYER_DETECTOR = register("player_detector");
public static final GuiType<DataDrivenBEProvider.DataDrivenBlockEntity> DATA_DRIVEN = register("data_driven");
public static final GuiType<BlockBreakerBlockEntity> BLOCK_BREAKER = register("block_breaker");
public static final GuiType<BlockPlacerBlockEntity> BLOCK_PLACER = register("block_placer");
private static <T extends BlockEntity> GuiType<T> register(String id) {
return register(new Identifier("techreborn", id));

View file

@ -0,0 +1,96 @@
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
import reborncore.client.screen.builder.ScreenHandlerBuilder;
import reborncore.common.blockentity.MachineBaseBlockEntity;
import reborncore.common.recipes.RecipeCrafter;
import reborncore.common.screen.BuiltScreenHandler;
import reborncore.common.screen.BuiltScreenHandlerProvider;
import techreborn.blockentity.machine.GenericMachineBlockEntity;
public class AbstractBlockBlockEntity extends GenericMachineBlockEntity implements BuiltScreenHandlerProvider, BlockProcessable {
private final int ENERGY_SLOT = 0;
private final int INPUT_SLOT = 1;
protected BlockProcessor processor;
/**
* @param blockEntityType
* @param pos
* @param state
* @param name {@link String} Name for a {@link BlockEntity}.
* @param maxInput {@code int} Maximum energy input, value in EU
* @param maxEnergy {@code int} Maximum energy buffer, value in EU
* @param toolDrop {@link Block} Block to drop with wrench
* @param energySlot {@code int} Energy slot to use to charge machine from battery
*/
public AbstractBlockBlockEntity(BlockEntityType<?> blockEntityType, BlockPos pos, BlockState state, String name, int maxInput, int maxEnergy, Block toolDrop, int energySlot) {
super(blockEntityType, pos, state, name, maxInput, maxEnergy, toolDrop, energySlot);
}
// BuiltScreenHandlerProvider
@Override
public BuiltScreenHandler createScreenHandler(int syncID, PlayerEntity player) {
BlockEntityScreenHandlerBuilder builder = new ScreenHandlerBuilder("blockplacer")
.player(player.getInventory())
.inventory()
.hotbar()
.addInventory()
.blockEntity(this)
.energySlot(ENERGY_SLOT, 8 , 72).syncEnergyValue()
.slot(INPUT_SLOT, 80, 60);
processor.syncNbt(builder);
return builder.addInventory().create(this, syncID);
}
@Override
public void tick(World world, BlockPos pos, BlockState state, MachineBaseBlockEntity blockEntity) {
super.tick(world, pos, state, blockEntity);
if (world == null || world.isClient) {
return;
}
processor.onTick(world, BlockProcessorUtils.getFrontBlockPosition(blockEntity, pos));
}
@Override
public void writeNbt(NbtCompound tag) {
super.writeNbt(tag);
processor.writeNbt(tag);
}
@Override
public void readNbt(NbtCompound tag) {
super.readNbt(tag);
processor.readNbt(tag);
}
public BlockProcessor getProcessor() {
return processor;
}
//BlockBreakerProcessable
@Override
public boolean consumeEnergy(int amount) {
return tryUseExact(getEuPerTick(amount));
}
//BlockBreakerProcessable
@Override
public void playSound() {
if (RecipeCrafter.soundHandler != null) {
RecipeCrafter.soundHandler.playSound(false, this);
}
}
}

View file

@ -0,0 +1,80 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
import reborncore.client.screen.builder.ScreenHandlerBuilder;
import reborncore.common.screen.BuiltScreenHandler;
import reborncore.common.screen.BuiltScreenHandlerProvider;
import reborncore.common.util.RebornInventory;
import techreborn.blockentity.machine.tier0.block.blockbreaker.BlockBreakerProcessor;
import techreborn.config.TechRebornConfig;
import techreborn.init.TRBlockEntities;
import techreborn.init.TRContent;
/**
* <b>A machine that can break the block physically located in front of it</b>
* <br>
* May not break blocks with hardness < 0, may not break blocks that has no item.
* Shares most functionality with other GenericMachineBlockEntities, however does not make use of the {@code RecipeCrafter}
*
* @author SimonFlapse
*/
public class BlockBreakerBlockEntity extends AbstractBlockBlockEntity implements BuiltScreenHandlerProvider, BlockProcessable {
public static final int ENERGY_SLOT = 0;
public static final int OUTPUT_SLOT = 1;
public static final int FAKE_INPUT_SLOT = 2;
public BlockBreakerBlockEntity(BlockPos pos, BlockState state) {
super(TRBlockEntities.BLOCK_BREAKER, pos, state, "Block Breaker", TechRebornConfig.blockBreakerMaxInput, TechRebornConfig.blockBreakerMaxEnergy, TRContent.Machine.BLOCK_BREAKER.block, ENERGY_SLOT);
processor = new BlockBreakerProcessor(this, OUTPUT_SLOT, FAKE_INPUT_SLOT, TechRebornConfig.blockBreakerBaseBreakTime, TechRebornConfig.blockBreakerEnergyPerTick);
inventory = new RebornInventory<>(3, "BlockBreakerBlockEntity", 64, this);
}
// BuiltScreenHandlerProvider
@Override
public BuiltScreenHandler createScreenHandler(int syncID, PlayerEntity player) {
BlockEntityScreenHandlerBuilder builder = new ScreenHandlerBuilder("blockbreaker")
.player(player.getInventory())
.inventory()
.hotbar()
.addInventory()
.blockEntity(this)
.energySlot(ENERGY_SLOT, 8 , 72).syncEnergyValue()
.outputSlot(OUTPUT_SLOT, 80, 60);
processor.syncNbt(builder);
return builder.addInventory().create(this, syncID);
}
public BlockBreakerProcessor getProcessor() {
return (BlockBreakerProcessor) this.processor;
}
}

View file

@ -0,0 +1,80 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
import reborncore.client.screen.builder.ScreenHandlerBuilder;
import reborncore.common.screen.BuiltScreenHandler;
import reborncore.common.screen.BuiltScreenHandlerProvider;
import reborncore.common.util.RebornInventory;
import techreborn.blockentity.machine.tier0.block.blockplacer.BlockPlacerProcessor;
import techreborn.config.TechRebornConfig;
import techreborn.init.TRBlockEntities;
import techreborn.init.TRContent;
/**
* <b>A machine that can break place blocks in front of it</b>
* <br>
* May not place blocks with hardness < 0.
* Shares most functionality with other GenericMachineBlockEntities, however does not make use of the {@code RecipeCrafter}
*
* @author SimonFlapse
*/
public class BlockPlacerBlockEntity extends AbstractBlockBlockEntity implements BuiltScreenHandlerProvider, BlockProcessable {
public static final int ENERGY_SLOT = 0;
public static final int INPUT_SLOT = 1;
public static final int FAKE_OUTPUT_SLOT = 2;
public BlockPlacerBlockEntity(BlockPos pos, BlockState state) {
super(TRBlockEntities.BLOCK_PLACER, pos, state, "Block Placer", TechRebornConfig.blockPlacerMaxInput, TechRebornConfig.blockPlacerMaxEnergy, TRContent.Machine.BLOCK_PLACER.block, ENERGY_SLOT);
processor = new BlockPlacerProcessor(this, INPUT_SLOT, FAKE_OUTPUT_SLOT, TechRebornConfig.blockPlacerBaseBreakTime, TechRebornConfig.blockPlacerEnergyPerTick);
inventory = new RebornInventory<>(3, "BlockPlacerBlockEntity", 64, this);
}
// BuiltScreenHandlerProvider
@Override
public BuiltScreenHandler createScreenHandler(int syncID, PlayerEntity player) {
BlockEntityScreenHandlerBuilder builder = new ScreenHandlerBuilder("blockplacer")
.player(player.getInventory())
.inventory()
.hotbar()
.addInventory()
.blockEntity(this)
.energySlot(ENERGY_SLOT, 8 , 72).syncEnergyValue()
.slot(INPUT_SLOT, 80, 60);
processor.syncNbt(builder);
return builder.addInventory().create(this, syncID);
}
public BlockPlacerProcessor getProcessor() {
return (BlockPlacerProcessor) this.processor;
}
}

View file

@ -0,0 +1,31 @@
package techreborn.blockentity.machine.tier0.block;
import reborncore.api.blockentity.InventoryProvider;
import reborncore.common.blockentity.RedstoneConfigurable;
import reborncore.common.recipes.IUpgradeHandler;
/**
* <b>Aggregated interface for use with BlockEntities that have a processor attached</b>
* <br>
* Example of a processor {@link techreborn.blockentity.machine.tier0.block.blockplacer.BlockPlacerProcessor}
*
* @author SimonFlapse
*/
public interface BlockProcessable extends IUpgradeHandler, RedstoneConfigurable, InventoryProvider {
/**
* <b>Consume some amount of Energy</b>
* <br>
* Must only return true if it successfully consumed energy.
* Must not consume energy if only partial fulfilled
*
* @param amount {@code int} amount of energy to consume
* @return if the energy could be consumed
*/
boolean consumeEnergy(int amount);
/**
* <b>Play a sound to the Minecraft world</b>
*/
void playSound();
}

View file

@ -0,0 +1,23 @@
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
public interface BlockProcessor {
ProcessingStatus onTick(World world, BlockPos positionInFront);
ProcessingStatus getStatusEnum();
int getCurrentTickTime();
int getTickTime();
void readNbt(NbtCompound tag);
void writeNbt(NbtCompound tag);
BlockEntityScreenHandlerBuilder syncNbt(BlockEntityScreenHandlerBuilder builder);
default int getProgress() {
return (int) (((double) getCurrentTickTime() / (double) getTickTime()) * 100);
}
}

View file

@ -0,0 +1,69 @@
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import reborncore.common.blockentity.MachineBaseBlockEntity;
/**
* <b>Common utilities for BlockProcessors</b>
* <br>
* Only exposes static methods
*
* @author SimonFlapse
*/
public class BlockProcessorUtils {
private BlockProcessorUtils() {};
/**
* <b>Get the hardness to break of a block</b>
* @param world {@link World} the world where the blockInFront is in
* @param blockInFront {@link BlockState} the block from which to get the hardness
* @param positionInFront {@link BlockPos} the position of the block from which to get the hardness
* @return the hardness to break of the supplied {@link BlockState}
*/
public static float getHardness(World world, BlockState blockInFront, BlockPos positionInFront) {
float hardness = blockInFront.getHardness(world, positionInFront);
return hardness;
}
/**
* <b>Get processing time adjusted to the hardness of a block and the overclocking speed</b>
* <br>
* Minimum value is 1 tick
* @param processable {@link BlockProcessable} the machine from which to get the speed multiplier of
* @param baseTickTime {@code int} the base processing time in ticks
* @param hardness {@code float} the hardness of the processed block
* @return time to process a block in ticks given the hardness, speed multiplier and base processing time
*/
public static int getProcessTimeWithHardness(BlockProcessable processable, int baseTickTime, float hardness) {
int placeTime = (int) (baseTickTime * hardness * (1.0 - processable.getSpeedMultiplier()));
return Math.max(placeTime, 1);
}
/**
* <b>Play a sound in a regular interval of 20 ticks</b>
* <br>
* Prevents spamming a new sound every tick, instead only allowing for a sound to be played every 20 tick.
* @param processable {@link BlockProcessable} the machine which should play the sound
* @param currentTick {@code int} the current tick of the processing
*/
public static void playSound(BlockProcessable processable, int currentTick) {
if (currentTick == 1 || currentTick % 20 == 0) {
processable.playSound();
}
}
/**
* <b>Get the position of the block in front of the blockEntity</b>
* <br>
* @param blockEntity
* @param pos
* @return
*/
public static BlockPos getFrontBlockPosition(MachineBaseBlockEntity blockEntity, BlockPos pos) {
return pos.offset(blockEntity.getFacing() == null? Direction.NORTH : blockEntity.getFacing());
}
}

View file

@ -0,0 +1,50 @@
package techreborn.blockentity.machine.tier0.block;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
/**
* <b>Interface describing different statuses of a Processing Machine</b>
* <br>
* Used to define {@link TranslatableText} for UI elements based on the positive, neutral or negative status of a machine
*
* @author SimonFlapse
*/
public interface ProcessingStatus {
/**
* <b>The status state described as a translatable text</b>
*
* @return The translatable text for displaying in a UI
*/
Text getText();
/**
* <b>The processing status with current progress formatted</b>
* <br>
* May not always use the passed progress value
*
* @param progress {@code int} the current progress as an integer between 0 and 100. Displayed as a percentage (Eg. 75%)
* @return The translatable text for displaying in a UI
*/
Text getProgressText(int progress);
/**
* <b>The color to be used for the status text</b>
* <br>
* Used to help describe the implication of a status effect
* e.g red for critical status, blue for informational status or green for positive status
*
* @return the color represented as an integer
*/
int getColor();
/**
* <b>Integer representation of a status</b>
* <br>
* Similar to, or fully based on {@link Enum#ordinal()}
*
* @return an integer corresponding to the status code
* @see Enum#ordinal()
*/
int getStatusCode();
}

View file

@ -0,0 +1,61 @@
package techreborn.blockentity.machine.tier0.block.blockbreaker;
import net.minecraft.nbt.NbtCompound;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
/**
* <b>Class handling Nbt values of the Block Breaker</b>
* <br>
* Inherited by the {@link BlockBreakerProcessor} for keeping its values in sync when saving/loading a map
*
* @author SimonFlapse
* @see BlockBreakerProcessor
*/
class BlockBreakerNbt {
protected int breakTime;
protected int currentBreakTime;
protected ProcessingStatus status = BlockBreakerStatus.IDLE;
public void writeNbt(NbtCompound tag) {
tag.putInt("breakTime", this.breakTime);
tag.putInt("currentBreakTime", this.currentBreakTime);
tag.putInt("blockBreakerStatus", getStatus());
}
public void readNbt(NbtCompound tag) {
this.breakTime = tag.getInt("breakTime");
this.currentBreakTime = tag.getInt("currentBreakTime");
setStatus(tag.getInt("blockBreakerStatus"));
}
public BlockEntityScreenHandlerBuilder syncNbt(BlockEntityScreenHandlerBuilder builder) {
return builder.sync(this::getBreakTime, this::setBreakTime)
.sync(this::getCurrentBreakTime, this::setCurrentBreakTime)
.sync(this::getStatus, this::setStatus);
}
protected int getBreakTime() {
return breakTime;
}
protected void setBreakTime(int breakTime) {
this.breakTime = breakTime;
}
protected int getCurrentBreakTime() {
return currentBreakTime;
}
protected void setCurrentBreakTime(int currentBreakTime) {
this.currentBreakTime = currentBreakTime;
}
protected int getStatus() {
return status.getStatusCode();
}
protected void setStatus(int status) {
this.status = BlockBreakerStatus.values()[status];
}
}

View file

@ -0,0 +1,224 @@
package techreborn.blockentity.machine.tier0.block.blockbreaker;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import reborncore.common.blockentity.RedstoneConfiguration;
import techreborn.blockentity.machine.tier0.block.BlockProcessable;
import techreborn.blockentity.machine.tier0.block.BlockProcessor;
import techreborn.blockentity.machine.tier0.block.BlockProcessorUtils;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
import java.util.UUID;
/**
* <b>Class handling the process of breaking a block</b>
* <br>
* The main purpose of this class is to implement the {@link #onTick(World, BlockPos)}.
* This method defines the logic for breaking a block
*
* @author SimonFlapse
* @see techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity
*/
public class BlockBreakerProcessor extends BlockBreakerNbt implements BlockProcessor {
private UUID processorId = UUID.randomUUID();
private BlockProcessable processable;
private int outputSlot;
private int fakeInputSlot;
private int baseBreakTime;
private int baseCostToBreak;
public BlockBreakerProcessor(BlockProcessable processable, int outputSlot, int fakeInputSlot, int baseBreakTime, int baseCostToBreak) {
this.processable = processable;
this.outputSlot = outputSlot;
this.fakeInputSlot = fakeInputSlot;
this.baseBreakTime = baseBreakTime;
this.baseCostToBreak = baseCostToBreak;
}
@Override
public ProcessingStatus getStatusEnum() {
return status;
}
public ProcessingStatus onTick(World world, BlockPos positionInFront) {
handleBlockBreakingProgressReset(world, positionInFront);
if (!ensureRedstoneEnabled()) return status;
if (!handleInterrupted()) return status;
ItemStack outputItemStack = processable.getInventory().getStack(outputSlot);
BlockState blockInFront = world.getBlockState(positionInFront);
if (!handleBlockInFrontRemoved(blockInFront)) return status;
Item currentBreakingItem = processable.getInventory().getStack(fakeInputSlot).getItem();
ItemStack item = blockInFront.getBlock().asItem().getDefaultStack().copy();
ItemStack fakeItem = item.copy();
if (fakeItem.isOf(Items.AIR)) {
currentBreakingItem = null;
}
processable.getInventory().setStack(fakeInputSlot, fakeItem);
float hardness = BlockProcessorUtils.getHardness(world, blockInFront, positionInFront);
if (!ensureBlockCanBeBroken(blockInFront, fakeItem, hardness)) return status;
this.breakTime = BlockProcessorUtils.getProcessTimeWithHardness(processable, baseBreakTime, hardness);
if (!ensureBlockNotReplaced(currentBreakingItem, item)) return status;
if (!ensureBlockFitInOutput(outputItemStack, item)) return status;
if (!increaseBreakTime(world, positionInFront)) return status;
BlockProcessorUtils.playSound(processable, currentBreakTime);
breakBlock(world, positionInFront, outputItemStack, item);
status = BlockBreakerStatus.PROCESSING;
return status;
}
private boolean ensureRedstoneEnabled() {
if (!processable.isActive(RedstoneConfiguration.RECIPE_PROCESSING)) {
return breakControlFlow(BlockBreakerStatus.IDLE_PAUSED);
}
return true;
}
private void handleBlockBreakingProgressReset(World world, BlockPos pos) {
//Resets the BlockBreakingProgress, otherwise the progress will be buggy when a new block has been placed
if (currentBreakTime == 0) {
setBlockBreakingProgress(world, pos, -1);
}
}
private boolean handleInterrupted() {
//Persists the last status message until the currentBreakTime is back to 0
//Set the currentBreakTime to less than 0 for as many ticks as you want a message to persist.
//The machine processing is halted while persisting messages.
if (currentBreakTime < 0) {
this.currentBreakTime++;
return false;
}
return true;
}
private boolean handleBlockInFrontRemoved(BlockState blockInFront) {
//Makes sure that if the block in front is removed, the processing resets
if (blockInFront.isOf(Blocks.AIR)) {
processable.getInventory().setStack(fakeInputSlot, ItemStack.EMPTY);
resetProcessing(0);
}
return true;
}
private boolean ensureBlockCanBeBroken(BlockState blockInFront, ItemStack fakeItem, float hardness) {
//Resets time if there is no block
//If breaking the block returns no output, skip breaking it
//Blocks with a hardness below 0 are unbreakable
if (blockInFront.isAir() || fakeItem.isEmpty() || hardness < 0) {
return breakControlFlow(BlockBreakerStatus.IDLE);
}
return true;
}
private boolean ensureBlockNotReplaced(Item currentBreakingItem, ItemStack item) {
//Ensures that a piston cannot be abused to push in another block without resetting the progress
if (currentBreakingItem != null && !ItemStack.EMPTY.isOf(currentBreakingItem) && !item.isOf(currentBreakingItem)) {
return breakControlFlow(BlockBreakerStatus.INTERRUPTED);
}
return true;
}
private boolean ensureBlockFitInOutput(ItemStack currentStack, ItemStack item) {
//Ensures that the block is the same as the one currently in the output slot
if (!currentStack.isOf(ItemStack.EMPTY.getItem()) && !currentStack.isOf(item.getItem())) {
return breakControlFlow(BlockBreakerStatus.OUTPUT_BLOCKED);
}
//Ensure that output slot can fit the block
if (currentStack.getMaxCount() < currentStack.getCount() + item.getCount()) {
return breakControlFlow(BlockBreakerStatus.OUTPUT_FULL);
}
return true;
}
private boolean increaseBreakTime(World world, BlockPos blockPos) {
//if (!tryUseExact(getEuPerTick(baseCostToBreak))) {
if (!processable.consumeEnergy(baseCostToBreak)) {
return breakControlFlow(BlockBreakerStatus.NO_ENERGY);
}
setBlockBreakingProgress(world, blockPos);
this.currentBreakTime++;
return true;
}
private void breakBlock(World world, BlockPos positionInFront, ItemStack currentStack, ItemStack item) {
if (currentBreakTime >= breakTime) {
world.breakBlock(positionInFront, false);
resetProcessing(0);
if (currentStack.isOf(ItemStack.EMPTY.getItem())) {
processable.getInventory().setStack(outputSlot, item);
} else {
int currentCount = currentStack.getCount();
currentStack.setCount(currentCount + item.getCount());
}
}
}
private void resetProcessing(int tick) {
this.currentBreakTime = tick;
breakTime = baseBreakTime;
}
private void setBlockBreakingProgress(World world, BlockPos blockPos) {
setBlockBreakingProgress(world, blockPos, getProgress() / 10);
}
private void setBlockBreakingProgress(World world, BlockPos blockPos, int breakingProgress) {
world.setBlockBreakingInfo(processorId.hashCode(), blockPos, breakingProgress);
}
@Override
public int getCurrentTickTime() {
return this.getCurrentBreakTime();
}
@Override
public int getTickTime() {
return this.getBreakTime();
}
private boolean breakControlFlow(ProcessingStatus status) {
resetProcessing(-20);
this.status = status;
return false;
}
}

View file

@ -0,0 +1,60 @@
package techreborn.blockentity.machine.tier0.block.blockbreaker;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import reborncore.common.util.Color;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
/**
* An enumeration of different statuses the Block Breaker can have
*
* Includes {@code TranslatableText} describing the status along with a text color
*
* @author SimonFlapse
*/
enum BlockBreakerStatus implements ProcessingStatus {
IDLE(new TranslatableText("gui.techreborn.block_breaker.idle"), Color.BLUE),
IDLE_PAUSED(new TranslatableText("gui.techreborn.block.idle_redstone"), Color.BLUE),
OUTPUT_FULL(new TranslatableText("gui.techreborn.block.output_full"), Color.RED),
NO_ENERGY(new TranslatableText("gui.techreborn.block.no_energy"), Color.RED),
INTERRUPTED(new TranslatableText("gui.techreborn.block.interrupted"), Color.RED),
OUTPUT_BLOCKED(new TranslatableText("gui.techreborn.block.output_blocked"), Color.RED),
PROCESSING(new TranslatableText("gui.techreborn.block_breaker.processing"), Color.GREEN);
private final Text text;
private final int color;
BlockBreakerStatus(Text text, Color color) {
this.text = text;
this.color = color.getColor();
}
@Override
public Text getText() {
return text;
}
@Override
public Text getProgressText(int progress) {
progress = Math.max(progress, 0);
if (this == PROCESSING) {
return new TranslatableText("gui.techreborn.block.progress.active", new LiteralText("" + progress + "%"));
} else if (this == IDLE || this == INTERRUPTED) {
return new TranslatableText("gui.techreborn.block.progress.stopped");
}
return new TranslatableText("gui.techreborn.block.progress.paused", new LiteralText("" + progress + "%"));
}
@Override
public int getColor() {
return color;
}
@Override
public int getStatusCode() {
return this.ordinal();
}
}

View file

@ -0,0 +1,61 @@
package techreborn.blockentity.machine.tier0.block.blockplacer;
import net.minecraft.nbt.NbtCompound;
import reborncore.client.screen.builder.BlockEntityScreenHandlerBuilder;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
/**
* <b>Class handling Nbt values of the Block Placer</b>
* <br>
* Inherited by the {@link BlockPlacerProcessor} for keeping its values in sync when saving/loading a map
*
* @author SimonFlapse
* @see BlockPlacerProcessor
*/
class BlockPlacerNbt {
protected int placeTime;
protected int currentPlaceTime;
protected ProcessingStatus status = BlockPlacerStatus.IDLE;
public void writeNbt(NbtCompound tag) {
tag.putInt("placeTime", this.placeTime);
tag.putInt("currentPlaceTime", this.currentPlaceTime);
tag.putInt("blockPlacerStatus", getStatus());
}
public void readNbt(NbtCompound tag) {
this.placeTime = tag.getInt("placeTime");
this.currentPlaceTime = tag.getInt("currentPlaceTime");
setStatus(tag.getInt("blockPlacerStatus"));
}
public BlockEntityScreenHandlerBuilder syncNbt(BlockEntityScreenHandlerBuilder builder) {
return builder.sync(this::getPlaceTime, this::setPlaceTime)
.sync(this::getCurrentPlaceTime, this::setCurrentPlaceTime)
.sync(this::getStatus, this::setStatus);
}
protected int getPlaceTime() {
return placeTime;
}
protected void setPlaceTime(int placeTime) {
this.placeTime = placeTime;
}
protected int getCurrentPlaceTime() {
return currentPlaceTime;
}
protected void setCurrentPlaceTime(int currentPlaceTime) {
this.currentPlaceTime = currentPlaceTime;
}
protected int getStatus() {
return status.getStatusCode();
}
protected void setStatus(int status) {
this.status = BlockPlacerStatus.values()[status];
}
}

View file

@ -0,0 +1,199 @@
package techreborn.blockentity.machine.tier0.block.blockplacer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import reborncore.common.blockentity.RedstoneConfiguration;
import techreborn.blockentity.machine.tier0.block.BlockProcessable;
import techreborn.blockentity.machine.tier0.block.BlockProcessor;
import techreborn.blockentity.machine.tier0.block.BlockProcessorUtils;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
/**
* <b>Class handling the process of placing a block</b>
* <br>
* The main purpose of this class is to implement the {@link #onTick(World, BlockPos)}.
* This method defines the logic for placing a block
*
* @author SimonFlapse
* @see techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity
*/
public class BlockPlacerProcessor extends BlockPlacerNbt implements BlockProcessor {
private BlockProcessable processable;
private int inputSlot;
private int fakeOutputSlot;
private int basePlaceTime;
private int baseCostToPlace;
public BlockPlacerProcessor(BlockProcessable processable, int inputSlot, int fakeOutputSlot, int basePlaceTime, int baseCostToPlace) {
this.processable = processable;
this.inputSlot = inputSlot;
this.fakeOutputSlot = fakeOutputSlot;
this.basePlaceTime = basePlaceTime;
this.baseCostToPlace = baseCostToPlace;
}
public ProcessingStatus getStatusEnum() {
return status;
}
@Override
public int getCurrentTickTime() {
return getCurrentPlaceTime();
}
@Override
public int getTickTime() {
return getPlaceTime();
}
public ProcessingStatus onTick(World world, BlockPos positionInFront) {
if (!ensureRedstoneEnabled()) return status;
if (!handleInterrupted()) return status;
ItemStack inputItemStack = processable.getInventory().getStack(inputSlot);
if (!handleInputSlotEmptied(inputItemStack)) return status;
BlockState blockInFront = world.getBlockState(positionInFront);
if (!ensureEnoughItemsToPlace(inputItemStack)) return status;
if (!ensureBlockCanBePlaced(blockInFront, inputItemStack, 1)) return status;
Item currentPlacingItem = processable.getInventory().getStack(fakeOutputSlot).getItem();
ItemStack fakeItem = inputItemStack.copy();
if (fakeItem.isOf(Items.AIR)) {
currentPlacingItem = null;
}
processable.getInventory().setStack(fakeOutputSlot, fakeItem);
BlockState resultingBlockState = Block.getBlockFromItem(inputItemStack.getItem()).getDefaultState();
float hardness = BlockProcessorUtils.getHardness(world, resultingBlockState, positionInFront);
this.placeTime = BlockProcessorUtils.getProcessTimeWithHardness(processable, basePlaceTime, hardness);
if (!ensureItemNotReplaced(currentPlacingItem, inputItemStack)) return status;
if (!increasePlaceTime()) return status;
BlockProcessorUtils.playSound(processable, currentPlaceTime);
placeBlock(world, positionInFront, inputItemStack);
status = BlockPlacerStatus.PROCESSING;
return status;
}
private boolean ensureRedstoneEnabled() {
if (!processable.isActive(RedstoneConfiguration.RECIPE_PROCESSING)) {
return breakControlFlow(BlockPlacerStatus.IDLE_PAUSED);
}
return true;
}
private boolean handleInterrupted() {
//Persists the last status message until the currentPlaceTime is back to 0
//Set the currentPlaceTime to less than 0 for as many ticks as you want a message to persist.
//The machine processing is halted while persisting messages.
if (currentPlaceTime < 0) {
this.currentPlaceTime++;
return false;
}
return true;
}
private boolean handleInputSlotEmptied(ItemStack inputStack) {
//Makes sure that if the input slot is emptied, the processing resets
if (inputStack.isOf(ItemStack.EMPTY.getItem())) {
processable.getInventory().setStack(fakeOutputSlot, ItemStack.EMPTY);
resetProcessing(0);
}
return true;
}
private boolean ensureEnoughItemsToPlace(ItemStack currentStack) {
//Ensure that we have enough items in the input to place
if (currentStack.getCount() <= 0) {
return breakControlFlow(BlockPlacerStatus.IDLE);
}
return true;
}
private boolean ensureBlockCanBePlaced(BlockState blockInFront, ItemStack fakeItem, float hardness) {
//Checks if the block can be placed
//Items for which the default BlockState is an air block should not be placed, that will just destroy the item
//Blocks with hardness below 0 can not be broken, and thus should not be placed
BlockState blockState = Block.getBlockFromItem(fakeItem.getItem()).getDefaultState();
if (blockState.isAir() || hardness < 0) {
return breakControlFlow(BlockPlacerStatus.IDLE);
}
//Checks if output is blocked
if (!blockInFront.isAir()) {
return breakControlFlow(BlockPlacerStatus.OUTPUT_BLOCKED);
}
return true;
}
private boolean ensureItemNotReplaced(Item currentPlacingItem, ItemStack item) {
//Ensures that a smart replace of item, will cause the processing to restart
if (currentPlacingItem != null && !ItemStack.EMPTY.isOf(currentPlacingItem) && !item.isOf(currentPlacingItem)) {
return breakControlFlow(BlockPlacerStatus.INTERRUPTED);
}
return true;
}
private boolean increasePlaceTime() {
if (!processable.consumeEnergy(baseCostToPlace)) {
return breakControlFlow(BlockPlacerStatus.NO_ENERGY);
}
this.currentPlaceTime++;
return true;
}
private void placeBlock(World world, BlockPos positionInFront, ItemStack currentStack) {
if (currentPlaceTime >= placeTime) {
ItemStack itemStack = processable.getInventory().getStack(inputSlot);
world.setBlockState(positionInFront, Block.getBlockFromItem(currentStack.getItem()).getDefaultState());
itemStack.setCount(itemStack.getCount() - 1);
resetProcessing(0);
}
}
private void resetProcessing(int tick) {
this.currentPlaceTime = tick;
this.placeTime = basePlaceTime;
this.processable.getInventory().setStack(fakeOutputSlot, ItemStack.EMPTY);
}
private boolean breakControlFlow(ProcessingStatus status) {
resetProcessing(-20);
this.status = status;
return false;
}
}

View file

@ -0,0 +1,59 @@
package techreborn.blockentity.machine.tier0.block.blockplacer;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import reborncore.common.util.Color;
import techreborn.blockentity.machine.tier0.block.ProcessingStatus;
/**
* An enumeration of different statuses the Block Placer can have
*
* Includes {@code TranslatableText} describing the status along with a text color
*
* @author SimonFlapse
*/
enum BlockPlacerStatus implements ProcessingStatus {
IDLE(new TranslatableText("gui.techreborn.block_placer.idle"), Color.BLUE),
IDLE_PAUSED(new TranslatableText("gui.techreborn.block.idle_redstone"), Color.BLUE),
NO_ENERGY(new TranslatableText("gui.techreborn.block.no_energy"), Color.RED),
INTERRUPTED(new TranslatableText("gui.techreborn.block.interrupted"), Color.RED),
OUTPUT_BLOCKED(new TranslatableText("gui.techreborn.block.output_blocked"), Color.RED),
PROCESSING(new TranslatableText("gui.techreborn.block_placer.processing"), Color.GREEN);
private final Text text;
private final int color;
BlockPlacerStatus(Text text, Color color) {
this.text = text;
this.color = color.getColor();
}
@Override
public Text getText() {
return text;
}
@Override
public Text getProgressText(int progress) {
progress = Math.max(progress, 0);
if (this == PROCESSING) {
return new TranslatableText("gui.techreborn.block.progress.active", new LiteralText("" + progress + "%"));
} else if (this == IDLE || this == INTERRUPTED) {
return new TranslatableText("gui.techreborn.block.progress.stopped");
} else {
return new TranslatableText("gui.techreborn.block.progress.paused", new LiteralText("" + progress + "%"));
}
}
@Override
public int getColor() {
return color;
}
@Override
public int getStatusCode() {
return this.ordinal();
}
}

View file

@ -31,7 +31,6 @@ import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.Identifier;
import techreborn.blockentity.GuiType;
import techreborn.blockentity.data.DataDrivenBEProvider;
import techreborn.client.gui.DataDrivenGui;
import techreborn.blockentity.generator.PlasmaGeneratorBlockEntity;
import techreborn.blockentity.generator.SolarPanelBlockEntity;
import techreborn.blockentity.generator.advanced.DieselGeneratorBlockEntity;
@ -43,6 +42,8 @@ import techreborn.blockentity.machine.iron.IronAlloyFurnaceBlockEntity;
import techreborn.blockentity.machine.iron.IronFurnaceBlockEntity;
import techreborn.blockentity.machine.misc.ChargeOMatBlockEntity;
import techreborn.blockentity.machine.multiblock.*;
import techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity;
import techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity;
import techreborn.blockentity.machine.tier1.*;
import techreborn.blockentity.machine.tier3.ChunkLoaderBlockEntity;
import techreborn.blockentity.machine.tier3.IndustrialCentrifugeBlockEntity;
@ -110,6 +111,8 @@ public class ClientGuiType<T extends BlockEntity> {
public static final ClientGuiType<FluidReplicatorBlockEntity> FLUID_REPLICATOR = register(GuiType.FLUID_REPLICATOR, GuiFluidReplicator::new);
public static final ClientGuiType<PlayerDetectorBlockEntity> PLAYER_DETECTOR = register(GuiType.PLAYER_DETECTOR, GuiPlayerDetector::new);
public static final ClientGuiType<DataDrivenBEProvider.DataDrivenBlockEntity> DATA_DRIVEN = register(GuiType.DATA_DRIVEN, DataDrivenGui::new);
public static final ClientGuiType<BlockBreakerBlockEntity> BLOCK_BREAKER = register(GuiType.BLOCK_BREAKER, GuiBlockBreaker::new);
public static final ClientGuiType<BlockPlacerBlockEntity> BLOCK_PLACER = register(GuiType.BLOCK_PLACER, GuiBlockPlacer::new);
private static <T extends BlockEntity> ClientGuiType<T> register(GuiType<T> type, GuiFactory<T> factory) {
return new ClientGuiType<>(type, factory);

View file

@ -0,0 +1,68 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.client.gui;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import reborncore.client.gui.builder.GuiBase;
import reborncore.common.screen.BuiltScreenHandler;
import techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity;
import techreborn.blockentity.machine.tier0.block.blockbreaker.BlockBreakerProcessor;
public class GuiBlockBreaker extends GuiBase<BuiltScreenHandler> {
BlockBreakerBlockEntity blockEntity;
public GuiBlockBreaker(int syncID, final PlayerEntity player, final BlockBreakerBlockEntity blockEntity) {
super(player, blockEntity, blockEntity.createScreenHandler(syncID, player));
this.blockEntity = blockEntity;
}
@Override
protected void drawBackground(MatrixStack matrixStack, final float f, final int mouseX, final int mouseY) {
super.drawBackground(matrixStack, f, mouseX, mouseY);
final Layer layer = Layer.BACKGROUND;
BlockBreakerProcessor processor = blockEntity.getProcessor();
drawSlot(matrixStack, 8, 72, layer);
drawCentredText(matrixStack, blockEntity.getProcessor().getStatusEnum().getText(), 25, processor.getStatusEnum().getColor(), layer);
drawCentredText(matrixStack, processor.getStatusEnum().getProgressText(processor.getProgress()), 40, processor.getStatusEnum().getColor(), layer);
drawOutputSlot(matrixStack, 80, 60, layer);
builder.drawJEIButton(matrixStack, this, 158, 5, layer);
}
@Override
protected void drawForeground(MatrixStack matrixStack, final int mouseX, final int mouseY) {
super.drawForeground(matrixStack, mouseX, mouseY);
final Layer layer = Layer.FOREGROUND;
builder.drawMultiEnergyBar(matrixStack, this, 9, 19, (int) blockEntity.getEnergy(), (int) blockEntity.getMaxStoredPower(), mouseX, mouseY, 0, layer);
}
}

View file

@ -0,0 +1,68 @@
/*
* This file is part of TechReborn, licensed under the MIT License (MIT).
*
* Copyright (c) 2020 TechReborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package techreborn.client.gui;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import reborncore.client.gui.builder.GuiBase;
import reborncore.common.screen.BuiltScreenHandler;
import techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity;
import techreborn.blockentity.machine.tier0.block.blockplacer.BlockPlacerProcessor;
public class GuiBlockPlacer extends GuiBase<BuiltScreenHandler> {
BlockPlacerBlockEntity blockEntity;
public GuiBlockPlacer(int syncID, final PlayerEntity player, final BlockPlacerBlockEntity blockEntity) {
super(player, blockEntity, blockEntity.createScreenHandler(syncID, player));
this.blockEntity = blockEntity;
}
@Override
protected void drawBackground(MatrixStack matrixStack, final float f, final int mouseX, final int mouseY) {
super.drawBackground(matrixStack, f, mouseX, mouseY);
final Layer layer = Layer.BACKGROUND;
BlockPlacerProcessor processor = blockEntity.getProcessor();
drawSlot(matrixStack, 8, 72, layer);
drawCentredText(matrixStack, blockEntity.getProcessor().getStatusEnum().getText(), 25, processor.getStatusEnum().getColor(), layer);
drawCentredText(matrixStack, processor.getStatusEnum().getProgressText(processor.getProgress()), 40, processor.getStatusEnum().getColor(), layer);
drawSlot(matrixStack, 80, 60, layer);
builder.drawJEIButton(matrixStack, this, 158, 5, layer);
}
@Override
protected void drawForeground(MatrixStack matrixStack, final int mouseX, final int mouseY) {
super.drawForeground(matrixStack, mouseX, mouseY);
final Layer layer = Layer.FOREGROUND;
builder.drawMultiEnergyBar(matrixStack, this, 9, 19, (int) blockEntity.getEnergy(), (int) blockEntity.getMaxStoredPower(), mouseX, mouseY, 0, layer);
}
}

View file

@ -555,6 +555,30 @@ public class TechRebornConfig {
@Config(config = "machines", category = "drain", key = "TicksUntilNextDrainAttempt", comment = "How many ticks should go between two drain attempts. 0 or negative will disable drain.")
public static int ticksUntilNextDrainAttempt = 10;
@Config(config = "machines", category = "block_breaker", key = "BlockBreakerMaxInput", comment = "Block Breaker Max Input (Energy per tick)")
public static int blockBreakerMaxInput = 32;
@Config(config = "machines", category = "block_breaker", key = "BlockBreakerMaxEnergy", comment = "Block Breaker Max Energy")
public static int blockBreakerMaxEnergy = 1_000;
@Config(config = "machines", category = "block_breaker", key = "BlockBreakerEnergyPerTick", comment = "Block Breaker Energy usage Per Tick")
public static int blockBreakerEnergyPerTick = 5;
@Config(config = "machines", category = "block_breaker", key = "BlockBreakerBaseBreakTime", comment = "How many ticks a block of hardness 1 requires to be broken")
public static int blockBreakerBaseBreakTime = 100;
@Config(config = "machines", category = "block_placer", key = "BlockPlacerMaxInput", comment = "Block Placer Max Input (Energy per tick)")
public static int blockPlacerMaxInput = 32;
@Config(config = "machines", category = "block_placer", key = "BlockPlacerMaxEnergy", comment = "Block Placer Max Energy")
public static int blockPlacerMaxEnergy = 1_000;
@Config(config = "machines", category = "block_placer", key = "BlockPlacerEnergyPerTick", comment = "Block Placer Energy usage Per Tick")
public static int blockPlacerEnergyPerTick = 5;
@Config(config = "machines", category = "block_placer", key = "BlockPlacerBaseBreakTime", comment = "How many ticks a block of hardness 1 requires to be placed")
public static int blockPlacerBaseBreakTime = 100;
// Misc
@Config(config = "misc", category = "general", key = "IC2TransformersStyle", comment = "Input from dots side, output from other sides, like in IC2.")
public static boolean IC2TransformersStyle = true;

View file

@ -54,6 +54,7 @@ public class ModSounds {
if (world == null) {
return;
}
world.playSound(null, blockEntity.getPos().getX(), blockEntity.getPos().getY(),
blockEntity.getPos().getZ(), ModSounds.MACHINE_RUN, SoundCategory.BLOCKS, TechRebornConfig.machineSoundVolume, 1F);
}

View file

@ -51,6 +51,8 @@ import techreborn.blockentity.machine.misc.ChargeOMatBlockEntity;
import techreborn.blockentity.machine.misc.DrainBlockEntity;
import techreborn.blockentity.machine.multiblock.*;
import techreborn.blockentity.machine.multiblock.casing.MachineCasingBlockEntity;
import techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity;
import techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity;
import techreborn.blockentity.machine.tier1.*;
import techreborn.blockentity.machine.tier3.ChunkLoaderBlockEntity;
import techreborn.blockentity.machine.tier3.IndustrialCentrifugeBlockEntity;
@ -138,6 +140,8 @@ public class TRBlockEntities {
public static final BlockEntityType<SolidCanningMachineBlockEntity> SOLID_CANNING_MACHINE = register(SolidCanningMachineBlockEntity::new, "solid_canning_machine", TRContent.Machine.SOLID_CANNING_MACHINE);
public static final BlockEntityType<WireMillBlockEntity> WIRE_MILL = register(WireMillBlockEntity::new, "wire_mill", TRContent.Machine.WIRE_MILL);
public static final BlockEntityType<GreenhouseControllerBlockEntity> GREENHOUSE_CONTROLLER = register(GreenhouseControllerBlockEntity::new, "greenhouse_controller", TRContent.Machine.GREENHOUSE_CONTROLLER);
public static final BlockEntityType<BlockBreakerBlockEntity> BLOCK_BREAKER = register(BlockBreakerBlockEntity::new, "block_breaker", TRContent.Machine.BLOCK_BREAKER);
public static final BlockEntityType<BlockPlacerBlockEntity> BLOCK_PLACER = register(BlockPlacerBlockEntity::new, "block_placer", TRContent.Machine.BLOCK_PLACER);
public static <T extends BlockEntity> BlockEntityType<T> register(BiFunction<BlockPos, BlockState, T> supplier, String name, ItemConvertible... items) {
return register(supplier, name, Arrays.stream(items).map(itemConvertible -> Block.getBlockFromItem(itemConvertible.asItem())).toArray(Block[]::new));

View file

@ -47,8 +47,8 @@ import reborncore.common.fluid.FluidValue;
import reborncore.common.misc.TagConvertible;
import reborncore.common.powerSystem.PowerAcceptorBlockEntity;
import reborncore.common.powerSystem.RcEnergyTier;
import techreborn.TechReborn;
import techreborn.blockentity.GuiType;
import techreborn.blockentity.generator.LightningRodBlockEntity;
import techreborn.blockentity.generator.PlasmaGeneratorBlockEntity;
import techreborn.blockentity.generator.advanced.*;
@ -58,6 +58,8 @@ import techreborn.blockentity.generator.basic.WindMillBlockEntity;
import techreborn.blockentity.machine.misc.ChargeOMatBlockEntity;
import techreborn.blockentity.machine.misc.DrainBlockEntity;
import techreborn.blockentity.machine.multiblock.*;
import techreborn.blockentity.machine.tier0.block.BlockBreakerBlockEntity;
import techreborn.blockentity.machine.tier0.block.BlockPlacerBlockEntity;
import techreborn.blockentity.machine.tier1.*;
import techreborn.blockentity.machine.tier3.ChunkLoaderBlockEntity;
import techreborn.blockentity.machine.tier3.IndustrialCentrifugeBlockEntity;
@ -83,7 +85,6 @@ import techreborn.blocks.transformers.BlockEVTransformer;
import techreborn.blocks.transformers.BlockHVTransformer;
import techreborn.blocks.transformers.BlockLVTransformer;
import techreborn.blocks.transformers.BlockMVTransformer;
import techreborn.blockentity.GuiType;
import techreborn.config.TechRebornConfig;
import techreborn.entities.EntityNukePrimed;
import techreborn.events.ModRegistry;
@ -95,7 +96,6 @@ import techreborn.world.OreDistribution;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -684,6 +684,8 @@ public class TRContent {
SOLID_CANNING_MACHINE(new GenericMachineBlock(GuiType.SOLID_CANNING_MACHINE, SolidCanningMachineBlockEntity::new)),
WIRE_MILL(new GenericMachineBlock(GuiType.WIRE_MILL, WireMillBlockEntity::new)),
GREENHOUSE_CONTROLLER(new GenericMachineBlock(GuiType.GREENHOUSE_CONTROLLER, GreenhouseControllerBlockEntity::new)),
BLOCK_BREAKER(new GenericMachineBlock(GuiType.BLOCK_BREAKER, BlockBreakerBlockEntity::new)),
BLOCK_PLACER(new GenericMachineBlock(GuiType.BLOCK_PLACER, BlockPlacerBlockEntity::new)),
DIESEL_GENERATOR(new GenericGeneratorBlock(GuiType.DIESEL_GENERATOR, DieselGeneratorBlockEntity::new)),
DRAGON_EGG_SYPHON(new GenericGeneratorBlock(null, DragonEggSyphonBlockEntity::new)),

View file

@ -0,0 +1,12 @@
{
"variants": {
"facing=north,active=false": { "model": "techreborn:block/machines/tier0_machines/block_breaker" },
"facing=south,active=false": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 180 },
"facing=west,active=false": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 270 },
"facing=east,active=false": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 90 },
"facing=north,active=true": { "model": "techreborn:block/machines/tier0_machines/block_breaker" },
"facing=south,active=true": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 180 },
"facing=west,active=true": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 270 },
"facing=east,active=true": { "model": "techreborn:block/machines/tier0_machines/block_breaker", "y": 90 }
}
}

View file

@ -0,0 +1,12 @@
{
"variants": {
"facing=north,active=false": { "model": "techreborn:block/machines/tier0_machines/block_placer" },
"facing=south,active=false": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 180 },
"facing=west,active=false": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 270 },
"facing=east,active=false": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 90 },
"facing=north,active=true": { "model": "techreborn:block/machines/tier0_machines/block_placer" },
"facing=south,active=true": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 180 },
"facing=west,active=true": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 270 },
"facing=east,active=true": { "model": "techreborn:block/machines/tier0_machines/block_placer", "y": 90 }
}
}

View file

@ -91,6 +91,8 @@
"block.techreborn.solid_canning_machine": "Solid Canning Machine",
"block.techreborn.wire_mill": "Wire Mill",
"block.techreborn.greenhouse_controller": "Greenhouse controller",
"block.techreborn.block_breaker": "Block Breaker",
"block.techreborn.block_placer": "Block Placer",
"_comment1": "Blocks",
"block.techreborn.rubber_log": "Rubber Log",
@ -829,6 +831,8 @@
"techreborn.message.info.block.techreborn.charge_o_mat": "Charges up to 6 items simultaneously",
"techreborn.message.info.block.techreborn.chunk_loader": "Keeps chunks loaded, allows machines to run when you're not nearby",
"techreborn.message.info.block.techreborn.drain": "Pulls any fluid directly above it, pairs nicely with a tank unit underneath",
"techreborn.message.info.block.techreborn.block_breaker": "Breaks any block directly in front of it",
"techreborn.message.info.block.techreborn.block_placer": "Places blocks from its inventory directly in front of it",
"keys.techreborn.category": "TechReborn Category",
"keys.techreborn.config": "Config",
@ -857,8 +861,6 @@
"_comment20": "Death Messages",
"death.attack.shock": "%s was electrocuted",
"death.attack.shock.player": "%s was electrocuted trying to outrun %s",
"death.attack.fusion": "%s suffered from acute radiation sickness",
"death.attack.fusion.player": "%s suffered from acute radiation sickness trying to outrun %s",
"_comment21": "Entities",
"entity.nuke": "Nuke",
@ -1085,8 +1087,24 @@
"gui.techreborn.tank.amount": "Fluid Amount:",
"gui.techreborn.storage.store": "Storing:",
"gui.techreborn.storage.amount": "Amount:",
"gui.techreborn.fusion.norecipe": "No recipe",
"gui.techreborn.fusion.charging": "Charging",
"gui.techreborn.fusion.chargingdetailed": "Charging (%s)",
"gui.techreborn.fusion.crafting": "Crafting"
"gui.techreborn.fusion.chargingdetailed": "Charging (%s)",
"gui.techreborn.fusion.crafting": "Crafting",
"gui.techreborn.block_breaker.idle": "Nothing to break",
"gui.techreborn.block_breaker.processing": "Breaking block",
"gui.techreborn.block_placer.idle": "Nothing to place",
"gui.techreborn.block_placer.processing": "Placing block",
"gui.techreborn.block.idle_redstone": "Processing paused by redstone",
"gui.techreborn.block.output_full": "Output is full",
"gui.techreborn.block.no_energy": "Not enough energy",
"gui.techreborn.block.interrupted": "Interrupted",
"gui.techreborn.block.output_blocked": "Output blocked",
"gui.techreborn.block.progress.active": "Progress: (%s)",
"gui.techreborn.block.progress.stopped": "Idle (Stopped)",
"gui.techreborn.block.progress.paused": "Idle (%s)"
}

View file

@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "techreborn:block/machines/tier0_machines/machine_top",
"front": "techreborn:block/machines/tier0_machines/block_breaker_front",
"side": "techreborn:block/machines/tier0_machines/machine_side"
}
}

View file

@ -0,0 +1,8 @@
{
"parent": "minecraft:block/orientable",
"textures": {
"top": "techreborn:block/machines/tier0_machines/machine_top",
"front": "techreborn:block/machines/tier0_machines/block_placer_front",
"side": "techreborn:block/machines/tier0_machines/machine_side"
}
}

View file

@ -0,0 +1,3 @@
{
"parent": "techreborn:block/machines/tier0_machines/block_breaker"
}

View file

@ -0,0 +1,3 @@
{
"parent": "techreborn:block/machines/tier0_machines/block_placer"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

View file

@ -0,0 +1,54 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"techreborn:crafting_table/machine/block_breaker"
]
},
"criteria": {
"has_sticky_piston": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["minecraft:sticky_piston"]
}
]
}
},
"has_refined_iron_plate": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["techreborn:refined_iron_plate"]
}
]
}
},
"has_hopper": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["minecraft:hopper"]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "techreborn:crafting_table/machine/block_breaker"
}
}
},
"requirements": [
[
"has_sticky_piston",
"has_refined_iron_plate",
"has_hopper",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,54 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"techreborn:crafting_table/machine/block_placer"
]
},
"criteria": {
"has_piston": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["minecraft:piston"]
}
]
}
},
"has_refined_iron_plate": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["techreborn:refined_iron_plate"]
}
]
}
},
"has_hopper": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": ["minecraft:hopper"]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "techreborn:crafting_table/machine/block_placer"
}
}
},
"requirements": [
[
"has_piston",
"has_refined_iron_plate",
"has_hopper",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "techreborn:block_breaker"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "techreborn:block_placer"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,25 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"PCP",
"PHP",
"PXP"
],
"key": {
"P": {
"item": "techreborn:refined_iron_plate"
},
"C": {
"item": "techreborn:electronic_circuit"
},
"H": {
"item": "minecraft:hopper"
},
"X": {
"item": "minecraft:sticky_piston"
}
},
"result": {
"item": "techreborn:block_breaker"
}
}

View file

@ -0,0 +1,25 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"PCP",
"PHP",
"PXP"
],
"key": {
"P": {
"item": "techreborn:refined_iron_plate"
},
"C": {
"item": "techreborn:electronic_circuit"
},
"H": {
"item": "minecraft:hopper"
},
"X": {
"item": "minecraft:piston"
}
},
"result": {
"item": "techreborn:block_placer"
}
}