NaturesAura/src/main/java/de/ellpeck/naturesaura/blocks/tiles/BlockEntitySpring.java
2024-03-10 11:29:12 +01:00

200 lines
7.2 KiB
Java

package de.ellpeck.naturesaura.blocks.tiles;
import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB;
import net.neoforged.neoforge.common.FarmlandWaterManager;
import net.neoforged.neoforge.common.ticket.AABBTicket;
import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.fluids.IFluidTank;
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
public class BlockEntitySpring extends BlockEntityImpl implements ITickableBlockEntity {
public final IFluidHandler tank = new InfiniteTank();
private AABBTicket waterTicket;
public BlockEntitySpring(BlockPos pos, BlockState state) {
super(ModBlockEntities.SPRING, pos, state);
}
@Override
public void onLoad() {
super.onLoad();
if (!this.level.isClientSide) {
// add a ticket to water crops
var area = new AABB(this.worldPosition).inflate(5, 1, 5);
this.waterTicket = FarmlandWaterManager.addAABBTicket(this.level, area);
}
}
@Override
public void setRemoved() {
super.setRemoved();
if (!this.level.isClientSide && this.waterTicket != null && this.waterTicket.isValid()) {
this.waterTicket.invalidate();
this.waterTicket = null;
}
}
@Override
public void tick() {
if (this.level.isClientSide || this.level.getGameTime() % 35 != 0)
return;
// fill cauldrons
var up = this.worldPosition.above();
var upState = this.level.getBlockState(up);
if (upState.hasProperty(BlockStateProperties.LEVEL_CAULDRON)) {
int level = upState.getValue(BlockStateProperties.LEVEL_CAULDRON);
if (level < 3 && this.tryConsumeAura(2500)) {
this.level.setBlockAndUpdate(up, upState.setValue(BlockStateProperties.LEVEL_CAULDRON, level + 1));
this.level.playSound(null, up, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 1, 1);
return;
}
}
// wet sponges
var spongeRadius = 2;
for (var x = -spongeRadius; x <= spongeRadius; x++) {
for (var y = -spongeRadius; y <= spongeRadius; y++) {
for (var z = -spongeRadius; z <= spongeRadius; z++) {
var pos = this.worldPosition.offset(x, y, z);
var state = this.level.getBlockState(pos);
if (state.getBlock() == Blocks.SPONGE && this.tryConsumeAura(2500)) {
this.level.setBlock(pos, Blocks.WET_SPONGE.defaultBlockState(), 2);
this.level.levelEvent(2001, pos, Block.getId(Blocks.WATER.defaultBlockState()));
return;
}
}
}
}
// generate obsidian
for (var dir : Direction.Plane.HORIZONTAL) {
var side = this.worldPosition.relative(dir);
if (this.isLava(side, true) && this.tryConsumeAura(1500)) {
this.level.setBlockAndUpdate(side, EventHooks.fireFluidPlaceBlockEvent(this.level, side, side, Blocks.OBSIDIAN.defaultBlockState()));
this.level.levelEvent(1501, side, 0);
return;
}
}
// generate stone
var twoUp = this.worldPosition.above(2);
if (this.isLava(twoUp, false) && (this.level.getBlockState(up).isAir() || this.isLava(up, false)) && this.tryConsumeAura(150)) {
this.level.setBlockAndUpdate(up, EventHooks.fireFluidPlaceBlockEvent(this.level, up, twoUp, Blocks.STONE.defaultBlockState()));
this.level.levelEvent(1501, up, 0);
return;
}
// generate cobblestone
for (var dir : Direction.Plane.HORIZONTAL) {
var twoSide = this.worldPosition.relative(dir, 2);
var side = this.worldPosition.relative(dir);
if (this.isLava(twoSide, false) && (this.level.getBlockState(side).isAir() || this.isLava(side, false)) && this.tryConsumeAura(100)) {
this.level.setBlockAndUpdate(side, EventHooks.fireFluidPlaceBlockEvent(this.level, side, twoSide, Blocks.COBBLESTONE.defaultBlockState()));
this.level.levelEvent(1501, side, 0);
return;
}
}
}
@Override
public boolean allowsLowerLimiter() {
return true;
}
public boolean tryConsumeAura(int amount) {
if (!this.canUseRightNow(amount))
return false;
var pos = IAuraChunk.getHighestSpot(this.level, this.worldPosition, 35, this.worldPosition);
IAuraChunk.getAuraChunk(this.level, pos).drainAura(pos, amount);
return true;
}
private boolean isLava(BlockPos offset, boolean source) {
var state = this.level.getFluidState(offset);
return (!source || state.isSource()) && state.is(FluidTags.LAVA);
}
private class InfiniteTank implements IFluidTank, IFluidHandler {
@Override
public FluidStack getFluid() {
return new FluidStack(Fluids.WATER, 1000);
}
@Override
public int getFluidAmount() {
return 1000;
}
@Override
public int getCapacity() {
return 1000;
}
@Override
public boolean isFluidValid(FluidStack stack) {
return stack.getFluid().defaultFluidState().is(FluidTags.WATER);
}
@Override
public int fill(FluidStack resource, IFluidHandler.FluidAction action) {
return 0;
}
@Override
public FluidStack drain(int maxDrain, IFluidHandler.FluidAction action) {
var drain = Math.min(maxDrain, 1000);
var auraUsed = Mth.ceil(drain / 2F);
if (!BlockEntitySpring.this.canUseRightNow(auraUsed))
return FluidStack.EMPTY;
if (action.execute())
BlockEntitySpring.this.tryConsumeAura(auraUsed);
return new FluidStack(Fluids.WATER, drain);
}
@Override
public FluidStack drain(FluidStack resource, IFluidHandler.FluidAction action) {
if (this.isFluidValid(resource))
return this.drain(resource.getAmount(), action);
return FluidStack.EMPTY;
}
@Override
public int getTanks() {
return 1;
}
@Override
public FluidStack getFluidInTank(int tank) {
return this.getFluid();
}
@Override
public int getTankCapacity(int tank) {
return this.getCapacity();
}
@Override
public boolean isFluidValid(int tank, FluidStack stack) {
return this.isFluidValid(stack);
}
}
}