Skip to content

Commit

Permalink
Begin adding pump block / entity
Browse files Browse the repository at this point in the history
  • Loading branch information
Rearth committed Mar 11, 2024
1 parent 1ee3b79 commit 4524f0d
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// 1.20.4 2024-03-11T15:36:48.2448916 Oritech/Model Definitions
// 1.20.4 2024-03-11T21:29:26.0904898 Oritech/Model Definitions
3d6f377b938592ac22aca17bd64561a6579ad217 assets\oritech\blockstates\grinder_block.json
8ede0997449fd1c3f65a07df184768a843b473ed assets\oritech\models\item\centrifuge_block.json
90e28b721796ff7ee21c8eefe4525f03a251d2fb assets\oritech\models\block\machine_extender.json
Expand All @@ -7,11 +7,13 @@ e6f197ee5ac22cd68bc502a86d40b65bfe40884a assets\oritech\models\item\target_desig
53f76976c5fe0593fa89a4b835dde07c96b07067 assets\oritech\blockstates\centrifuge_block.json
95eae9b13fb2835f15057d2fd4d9550192064ca4 assets\oritech\models\item\grinder_block.json
3ceff0ef4325bb269831205626285bc857c60de8 assets\oritech\models\item\destroyer_block.json
829faf2dfb04c9aea2dd6c971037fbfdaa9aa389 assets\oritech\models\item\pump_block.json
964457f56e25b66dfef2160c8618bcaba2b640aa assets\oritech\blockstates\pulverizer_block.json
001d7907def5667f14bbdce07c9d6198efa45e71 assets\oritech\blockstates\laser_arm_block.json
e4497bad8afbd4f4b4e830d892284a05718b06dd assets\oritech\models\block\machine_core_basic.json
505d30e3b61ee0ba1f2616e1226689e2cdb7ab58 assets\oritech\models\block\addon_indicator_block.json
a5651b8d4a27308b40c404f7cd3abcf9769b64b6 assets\oritech\models\item\machine_core_basic.json
c3174dc9e04055bae724425eb8b2c2894297bf70 assets\oritech\blockstates\pump_block.json
e109fcba8a22fe480b127c3f8972d80bf3821f51 assets\oritech\blockstates\basic_generator_block.json
2f7dfa17792770a034a13f117e6b8b1942b459e4 assets\oritech\models\block\placer_block.json
ee822d455f99c8c53c789fdb744979f678ca2729 assets\oritech\blockstates\fertilizer_block.json
Expand All @@ -38,6 +40,7 @@ c641d411ad252487b93d779cee9028b9ee920281 assets\oritech\blockstates\machine_core
a5afa0ba8780ec08bd0a9284bc08e0c681fe7158 assets\oritech\blockstates\block_placer_head.json
f29468ff950a191567ab35557334666099ccd7cc assets\oritech\blockstates\assembler_block.json
5054284e6d5fe0785ac93bdda5101c47337953cf assets\oritech\models\item\machine_frame_block.json
56c7ceb5cc86d67913ad95cb4ae5ec192aed926f assets\oritech\models\block\pump_block.json
1b9cd3719105dc1e03398de41f2cab37337816fe assets\oritech\blockstates\machine_core_good.json
3810f72943d88c81d3ab6b4329d437911c859621 assets\oritech\blockstates\powered_furnace_block.json
5462a2453fcdd2f8b99129894aec60f282d29ca9 assets\oritech\models\item\pulverizer_block.json
Expand Down
7 changes: 7 additions & 0 deletions src/main/generated/assets/oritech/blockstates/pump_block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "oritech:block/pump_block"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "oritech:block/pump_block"
}
}
3 changes: 3 additions & 0 deletions src/main/generated/assets/oritech/models/item/pump_block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"parent": "oritech:block/pump_block"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package rearth.oritech.block.blocks.machines.interaction;

import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import rearth.oritech.block.entity.machines.interaction.LaserArmBlockEntity;
import rearth.oritech.block.entity.machines.interaction.PumpBlockEntity;
import rearth.oritech.network.NetworkContent;
import rearth.oritech.util.MultiblockMachineController;

public class PumpBlock extends Block implements BlockEntityProvider {

public PumpBlock(Settings settings) {
super(settings);
}

// @Override
// public BlockRenderType getRenderType(BlockState state) {
// return BlockRenderType.ENTITYBLOCK_ANIMATED;
// }

@Nullable
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new PumpBlockEntity(pos, state);
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
return (world1, pos, state1, blockEntity) -> {
if (blockEntity instanceof BlockEntityTicker ticker)
ticker.tick(world1, pos, state1, blockEntity);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package rearth.oritech.block.entity.machines.interaction;

import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import rearth.oritech.init.BlockContent;
import rearth.oritech.init.BlockEntitiesContent;
import rearth.oritech.util.FluidProvider;

import java.util.*;
import java.util.stream.Collectors;

// todo add energy storage / usage
public class PumpBlockEntity extends BlockEntity implements BlockEntityTicker<PumpBlockEntity>, FluidProvider {

private static final int MAX_SEARCH_COUNT = 10000;

private boolean initialized = false;
private boolean toolheadLowered = false;
private boolean searchActive = false;
private BlockPos toolheadPosition;
private FloodFillSearch searchInstance;
private Deque<BlockPos> pendingLiquidPositions;

private final SingleVariantStorage<FluidVariant> fluidStorage = new SingleVariantStorage<>() {
@Override
protected FluidVariant getBlankVariant() {
return FluidVariant.blank();
}

@Override
protected long getCapacity(FluidVariant variant) {
return (16 * FluidConstants.BUCKET);
}

@Override
protected void onFinalCommit() {
super.onFinalCommit();
PumpBlockEntity.this.markDirty();
}
};

public PumpBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntitiesContent.PUMP_BLOCK, pos, state);
}

@Override
protected void writeNbt(NbtCompound nbt) {
super.writeNbt(nbt);
nbt.putBoolean("initialized", initialized);
nbt.put("fluidVariant", fluidStorage.variant.toNbt());
nbt.putLong("amount", fluidStorage.amount);
nbt.putLongArray("pendingTargets", pendingLiquidPositions.stream().mapToLong(BlockPos::asLong).toArray());
}

@Override
public void readNbt(NbtCompound nbt) {
super.readNbt(nbt);
initialized = nbt.getBoolean("initialized");
fluidStorage.variant = FluidVariant.fromNbt(nbt.getCompound("fluidVariant"));
fluidStorage.amount = nbt.getLong("amount");
pendingLiquidPositions = Arrays.stream(nbt.getLongArray("pendingTargets")).mapToObj(BlockPos::fromLong).collect(Collectors.toCollection(ArrayDeque::new));
}

@Override
public void tick(World world, BlockPos pos, BlockState state, PumpBlockEntity blockEntity) {
if (world.isClient) return;

if (!initialized) {
progressStartup();
return;
}

if (world.getTime() % 10 == 0) {

if (pendingLiquidPositions.isEmpty() || tankIsFull()) return;

var targetBlock = pendingLiquidPositions.peekLast();

if (!world.getBlockState(targetBlock).isLiquid()) {
pendingLiquidPositions.pollLast();
return;
}

var targetState = world.getFluidState(targetBlock);
if (!targetState.getFluid().matchesType(Fluids.WATER)) {
drainSourceBlock(targetBlock);
pendingLiquidPositions.pollLast();
System.out.println("pumped and removed block: " + targetState.getFluid());
}

addLiquidToTank(targetState);
this.markDirty();
}

}

private boolean tankIsFull() {
return fluidStorage.amount > fluidStorage.getCapacity() - FluidConstants.BUCKET;
}

private void addLiquidToTank(FluidState targetState) {
try (var tx = Transaction.openOuter()) {
var amountInserted = fluidStorage.insert(FluidVariant.of(targetState.getFluid()), FluidConstants.BUCKET, tx);
tx.commit();
}
}

private void drainSourceBlock(BlockPos targetBlock) {
world.setBlockState(targetBlock, Blocks.AIR.getDefaultState());
}

private void progressStartup() {

// startup sequence is:
// move down until no longer in air
// check if target is liquid
// if liquid is water, consider as infinite
// if liquid, start flood fill to find all liquid blocks. Add all found blocks to queue so that it can be soaked up in reverse
// search all neighbors per tick
// if more than 10000 blocks are found, consider as infinite and stop search
// mark startup as completed

if (toolheadPosition == null) {
toolheadPosition = pos;
}

if (!toolheadLowered) {

if (world.getTime() % 10 != 0)
moveToolheadDown();

return;
}

if (searchActive) {
if (searchInstance.nextGeneration()) {
finishSearch();
searchActive = false;
}
}
}

private void moveToolheadDown() {
toolheadLowered = checkToolheadEnd(toolheadPosition);
if (toolheadLowered) {
startLiquidSearch(toolheadPosition.down());
return;
}

toolheadPosition = toolheadPosition.down();
world.setBlockState(toolheadPosition, BlockContent.BANANA_BLOCK.getDefaultState());
}

private boolean checkToolheadEnd(BlockPos newPosition) {

var posBelow = newPosition.down();
var stateBelow = world.getBlockState(posBelow);
var blockBelow = stateBelow.getBlock();

return !(blockBelow.equals(Blocks.AIR) || blockBelow.equals(BlockContent.BANANA_BLOCK));
}

private void startLiquidSearch(BlockPos start) {

var state = world.getFluidState(start);
if (!state.isStill()) return;

searchInstance = new FloodFillSearch(start, world);
searchActive = true;

System.out.println("starting search at: " + start + " " + state.getFluid() + " " + state.isStill());
}

private void finishSearch() {
System.out.println("search finished, found: " + searchInstance.foundTargets.size());
pendingLiquidPositions = searchInstance.foundTargets;
initialized = true;
searchInstance = null;
}

@Override
public Storage<FluidVariant> getFluidStorage(Direction direction) {
return fluidStorage;
}

private static class FloodFillSearch {

final HashSet<BlockPos> checkedPositions = new HashSet<>();
final HashSet<BlockPos> nextTargets = new HashSet<>();
final Deque<BlockPos> foundTargets = new ArrayDeque<>();
final World world;

public FloodFillSearch(BlockPos startPosition, World world) {
this.world = world;
nextTargets.add(startPosition);
}

// returns true when done
@SuppressWarnings("unchecked")
public boolean nextGeneration() {

var currentGeneration = (HashSet<BlockPos>) nextTargets.clone();

var earlyStop = false;

for (var target : currentGeneration) {
if (isValidTarget(target)) {
foundTargets.addLast(target);
addNeighborsToQueue(target);
if (checkForEarlyStop(target)) earlyStop = true;
}

checkedPositions.add(target);
nextTargets.remove(target);
}

if (cutoffSearch() || earlyStop) nextTargets.clear();

return nextTargets.isEmpty();
}

private boolean checkForEarlyStop(BlockPos target) {
return world.getFluidState(target).getFluid().matchesType(Fluids.WATER);
}

private boolean cutoffSearch() {
return foundTargets.size() >= MAX_SEARCH_COUNT;
}

private boolean isValidTarget(BlockPos target) {
var state = world.getFluidState(target);
return state.isStill();
}

private void addNeighborsToQueue(BlockPos self) {

for (var neighbor : getNeighbors(self)) {
if (checkedPositions.contains(neighbor)) continue;
nextTargets.add(neighbor);
}

}

// returns all neighboring positions except up
private List<BlockPos> getNeighbors(BlockPos pos) {
return List.of(pos.down(), pos.north(), pos.east(), pos.south(), pos.west());
}

}
}
1 change: 1 addition & 0 deletions src/main/java/rearth/oritech/init/BlockContent.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class BlockContent implements BlockRegistryContainer {
public static final Block PLACER_BLOCK = new PlacerBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
public static final Block DESTROYER_BLOCK = new DestroyerBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
public static final Block FERTILIZER_BLOCK = new FertilizerBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
public static final Block PUMP_BLOCK = new PumpBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());

public static final Block MACHINE_CORE_BASIC = new MachineCoreBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque(), 1);
public static final Block MACHINE_CORE_GOOD = new MachineCoreBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque(), 6);
Expand Down
Loading

0 comments on commit 4524f0d

Please sign in to comment.