package com.infinityraider.agricraft.tiles.irrigation; import com.infinityraider.agricraft.api.irrigation.IConnectable; import com.infinityraider.agricraft.api.irrigation.IIrrigationComponent; import com.infinityraider.agricraft.api.irrigation.IrrigationConnectionType; import com.infinityraider.agricraft.blocks.irrigation.BlockWaterChannel; import com.infinityraider.agricraft.reference.AgriCraftConfig; import com.infinityraider.agricraft.reference.Constants; import com.infinityraider.agricraft.renderers.particles.LiquidSprayFX; import com.infinityraider.agricraft.utility.BaseIcons; import com.infinityraider.infinitylib.block.tile.TileEntityBase; import net.minecraft.block.Block; import net.minecraft.block.BlockFarmland; import net.minecraft.block.IGrowable; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraftforge.common.IPlantable; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import com.infinityraider.agricraft.reference.AgriNBT; import com.infinityraider.infinitylib.utility.WorldHelper; import com.infinityraider.agricraft.utility.BlockRange; public class TileEntitySprinkler extends TileEntityBase implements ITickable, IIrrigationComponent { public static final int BUFFER_CAP = 100; public static final int RADIUS = 3; public static final int HEIGHT = 5; private int buffer = 0; private int counter = 0; private float angle = 0.0F; private boolean active = false; private final BlockRange range; public TileEntitySprinkler() { this.range = new BlockRange(this.getPos().add(-RADIUS, 1, -RADIUS), this.getPos().add(RADIUS, HEIGHT, RADIUS)); } /** * Retrieves the current angle of the sprinkler head. * * @return The sprinkler head angle. */ public float getAngle() { return angle; } //this saves the data on the tile entity @Override public void writeTileNBT(NBTTagCompound tag) { if (this.counter > 0) { tag.setInteger(AgriNBT.LEVEL, this.counter); } tag.setBoolean(AgriNBT.ACTIVE, active); } //this loads the saved data for the tile entity @Override public void readTileNBT(NBTTagCompound tag) { if (tag.hasKey(AgriNBT.LEVEL)) { this.counter = tag.getInteger(AgriNBT.LEVEL); } else { this.counter = 0; } if (tag.hasKey(AgriNBT.ACTIVE)) { this.active = tag.getBoolean(AgriNBT.ACTIVE); } else { this.active = false; } } //checks if the sprinkler is CONNECTED to an irrigation channel public boolean isConnected() { return this.worldObj != null && this.worldObj.getBlockState(getPos().add(0, 1, 0)).getBlock() instanceof BlockWaterChannel; } @Override public void update() { if (!worldObj.isRemote && this.isActive()) { this.counter = (counter + 1) % AgriCraftConfig.sprinklerGrowthIntervalTicks; this.buffer -= 10; this.range.stream().forEach(p -> this.irrigate(p, false)); } else if (this.active) { this.renderLiquidSpray(); } } @Override public boolean canConnectTo(EnumFacing side, IConnectable component) { return side.equals(EnumFacing.UP) && component instanceof TileEntityChannel; } @Override public boolean canAcceptFluid(int y, int amount, boolean partial) { if (buffer + amount <= BUFFER_CAP) { return true; } else { return partial; } } @Override public int acceptFluid(int y, int amount, boolean partial) { if (canAcceptFluid(y, amount, partial)) { this.buffer += amount; if (this.buffer > BUFFER_CAP) { amount = this.buffer - BUFFER_CAP; this.buffer = BUFFER_CAP; } else { amount = 0; } } return amount; } @Override public int getFluidAmount(int y) { return this.buffer; } @Override public int getCapacity() { return BUFFER_CAP; } @Override public void setFluidLevel(int lvl) { // This can be skipped... Shhh! } @Override public void syncFluidLevel() { // This can be skipped... Shhh! } @Override public int getFluidHeight() { return this.buffer; } @Override public float getFluidHeight(int lvl) { return (this.buffer * 16.0f / BUFFER_CAP); } @Override public IrrigationConnectionType getConnectionType(EnumFacing side) { if (side == EnumFacing.UP) { return IrrigationConnectionType.PRIMARY; } else { return IrrigationConnectionType.NONE; } } public boolean canSprinkle() { return WorldHelper .getTile(worldObj, pos.add(0, 1, 0), TileEntityChannel.class) .filter(c -> c.getFluidAmount(0) > AgriCraftConfig.sprinklerRatePerHalfSecond) .isPresent(); } private boolean isActive() { boolean newState = this.canSprinkle(); if (newState != this.active) { this.active = newState; this.markForUpdate(); } return this.active; } /** * Depending on the block type either irrigates farmland or forces plant * GROWTH (based on chance) */ private void irrigate(BlockPos pos, boolean farmlandOnly) { IBlockState state = this.getWorld().getBlockState(pos); Block block = state.getBlock(); if (block instanceof BlockFarmland && block.getMetaFromState(state) < 7) { // irrigate farmland int flag = counter == 0 ? 2 : 6; worldObj.setBlockState(pos, block.getStateFromMeta(7), flag); } else if (!farmlandOnly && ((block instanceof IPlantable) || (block instanceof IGrowable))) { // X1 chance to force GROWTH tick on plant every Y1 ticks if (counter == 0 && worldObj.rand.nextDouble() <= AgriCraftConfig.sprinklerGrowthChancePercent) { block.updateTick(this.getWorld(), pos, state, worldObj.rand); } } } @SideOnly(Side.CLIENT) public TextureAtlasSprite getChannelIcon() { // Fetch the Icon using the handy world helper class. return WorldHelper .getTile(worldObj, pos.add(0, 1, 0), TileEntityChannel.class) .map(c -> c.getIcon()) .orElse(BaseIcons.OAK_PLANKS.getIcon()); } @SideOnly(Side.CLIENT) private void renderLiquidSpray() { if (AgriCraftConfig.disableParticles) { return; } this.angle = (this.angle + 5F) % 360; int particleSetting = Minecraft.getMinecraft().gameSettings.particleSetting; //0 = all, 1 = decreased; 2 = minimal; counter = (counter + 1) % (particleSetting + 1); if (counter == 0) { for (int i = 0; i < 4; i++) { float alpha = -(this.angle + 90 * i) * ((float) Math.PI) / 180; double xOffset = (4 * Constants.UNIT) * Math.cos(alpha); double zOffset = (4 * Constants.UNIT) * Math.sin(alpha); float radius = 0.3F; for (int j = 0; j <= 4; j++) { float beta = -j * ((float) Math.PI) / (8.0F); Vec3d vector = new Vec3d(radius * Math.cos(alpha), radius * Math.sin(beta), radius * Math.sin(alpha)); this.spawnLiquidSpray(xOffset * (4 - j) / 4, zOffset * (4 - j) / 4, vector); } } } } @SideOnly(Side.CLIENT) private void spawnLiquidSpray(double xOffset, double zOffset, Vec3d vector) { LiquidSprayFX liquidSpray = new LiquidSprayFX(this.worldObj, this.xCoord() + 0.5F + xOffset, this.yCoord() + 8 * Constants.UNIT, this.zCoord() + 0.5F + zOffset, 0.3F, 0.7F, vector); Minecraft.getMinecraft().effectRenderer.addEffect(liquidSpray); } }