package openblocks.common.tileentity; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemDye; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.IFluidHandler; import openblocks.Config; import openblocks.OpenBlocks; import openblocks.client.gui.GuiSprinkler; import openblocks.common.container.ContainerSprinkler; import openmods.api.IHasGui; import openmods.api.INeighbourAwareTile; import openmods.api.ISurfaceAttachment; import openmods.fakeplayer.FakePlayerPool; import openmods.fakeplayer.FakePlayerPool.PlayerUser; import openmods.fakeplayer.OpenModsFakePlayer; import openmods.include.IncludeInterface; import openmods.include.IncludeOverride; import openmods.inventory.GenericInventory; import openmods.inventory.IInventoryProvider; import openmods.inventory.TileEntityInventory; import openmods.inventory.legacy.ItemDistribution; import openmods.liquids.GenericFluidHandler; import openmods.sync.SyncableFlags; import openmods.sync.SyncableTank; import openmods.tileentity.SyncedTileEntity; public class TileEntitySprinkler extends SyncedTileEntity implements ISurfaceAttachment, IInventoryProvider, IHasGui, INeighbourAwareTile { private static final ItemStack BONEMEAL = new ItemStack(Items.dye, 1, 15); private static final Random RANDOM = new Random(); private static final double[] SPRINKER_DELTA = new double[] { 0.2, 0.25, 0.5 }; private static final int[] SPRINKER_MOD = new int[] { 1, 5, 20 }; private boolean hasBonemeal = false; private boolean needsTankUpdate; public enum Flags { enabled } private SyncableFlags flags; private SyncableTank tank; public int ticks; private final GenericInventory inventory = registerInventoryCallback(new TileEntityInventory(this, "sprinkler", true, 9) { @Override public boolean isItemValidForSlot(int i, ItemStack itemstack) { return itemstack != null && itemstack.isItemEqual(BONEMEAL); } }); @IncludeInterface private final IFluidHandler tankWrapper = new GenericFluidHandler.Drain(tank); @Override protected void createSyncedFields() { flags = SyncableFlags.create(Flags.values().length); tank = new SyncableTank(Config.sprinklerInternalTank, FluidRegistry.WATER, OpenBlocks.Fluids.xpJuice); } private static int selectFromRange(int range) { return RANDOM.nextInt(2 * range + 1) - range; } private void attemptFertilize() { if (!(worldObj instanceof WorldServer)) return; final int fertilizerChance = hasBonemeal? Config.sprinklerBonemealFertizizeChance : Config.sprinklerFertilizeChance; if (RANDOM.nextDouble() < 1.0 / fertilizerChance) { FakePlayerPool.instance.executeOnPlayer((WorldServer)worldObj, new PlayerUser() { @Override public void usePlayer(OpenModsFakePlayer fakePlayer) { final int x = selectFromRange(Config.sprinklerEffectiveRange) + xCoord; final int z = selectFromRange(Config.sprinklerEffectiveRange) + zCoord; for (int i = -1; i <= 1; i++) { int y = yCoord + i; if (ItemDye.applyBonemeal(BONEMEAL.copy(), worldObj, x, y, z, fakePlayer)) break; } } }); } } @Override public Object getServerGui(EntityPlayer player) { return new ContainerSprinkler(player.inventory, this); } @Override public Object getClientGui(EntityPlayer player) { return new GuiSprinkler(new ContainerSprinkler(player.inventory, this)); } @Override public boolean canOpenGui(EntityPlayer player) { return true; } private static final double SPRAY_SIDE_SCATTER = Math.toRadians(25); private void sprayParticles() { if (tank.getFluidAmount() > 0) { // 0 = All, 1 = Decreased, 2 = Minimal final int particleSetting = OpenBlocks.proxy.getParticleSettings(); if (particleSetting > 2) return; final int fillFactor = SPRINKER_MOD[particleSetting]; if ((ticks % fillFactor) != 0) return; final ForgeDirection blockYawRotation = getOrientation().north(); final double nozzleAngle = getSprayDirection(); final double sprayForwardVelocity = Math.sin(Math.toRadians(nozzleAngle * 25)); final double forwardVelocityX = sprayForwardVelocity * blockYawRotation.offsetZ / -2; final double forwardVelocityZ = sprayForwardVelocity * blockYawRotation.offsetX / 2; final double sprinklerDelta = SPRINKER_DELTA[particleSetting]; double outletPosition = -0.5; while (outletPosition <= 0.5) { final double spraySideVelocity = Math.sin(SPRAY_SIDE_SCATTER * (RANDOM.nextDouble() - 0.5)); final double sideVelocityX = spraySideVelocity * blockYawRotation.offsetX; final double sideVelocityZ = spraySideVelocity * blockYawRotation.offsetZ; Vec3 vec = Vec3.createVectorHelper( forwardVelocityX + sideVelocityX, 0.35, forwardVelocityZ + sideVelocityZ); OpenBlocks.proxy.spawnLiquidSpray(worldObj, tank.getFluid().getFluid(), xCoord + 0.5 + (outletPosition * 0.6 * blockYawRotation.offsetX), yCoord + 0.2, zCoord + 0.5 + (outletPosition * 0.6 * blockYawRotation.offsetZ), 0.3f, 0.7f, vec); outletPosition += sprinklerDelta; } } } @Override public void updateEntity() { super.updateEntity(); if (!worldObj.isRemote) { if (tank.getFluidAmount() <= 0) { if (needsTankUpdate) { tank.updateNeighbours(worldObj, getPosition()); needsTankUpdate = false; } tank.fillFromSide(worldObj, getPosition(), ForgeDirection.DOWN); } if (ticks % Config.sprinklerBonemealConsumeRate == 0) { hasBonemeal = ItemDistribution.consumeFirstInventoryItem(inventory, BONEMEAL); } if (ticks % Config.sprinklerWaterConsumeRate == 0) { setEnabled(tank.drain(1, true) != null); sync(); } } ticks++; // simplified this action because only one of these will execute // depending on worldObj.isRemote if (isEnabled()) { if (worldObj.isRemote) sprayParticles(); else attemptFertilize(); } } private void setEnabled(boolean b) { flags.set(Flags.enabled, b); } private boolean isEnabled() { return flags.get(Flags.enabled); } @Override public ForgeDirection getSurfaceDirection() { return ForgeDirection.DOWN; } /** * Get spray direction of Sprinkler particles * * @return float from -1f to 1f indicating the direction, left to right of the particles */ public float getSprayDirection() { if (isEnabled()) { return MathHelper.sin(ticks * 0.02f); } return 0; } @IncludeOverride public boolean canDrain(ForgeDirection from, Fluid fluid) { return false; } @Override @IncludeInterface public IInventory getInventory() { return inventory; } @Override public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); inventory.writeToNBT(tag); } @Override public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); inventory.readFromNBT(tag); } @Override public void validate() { super.validate(); this.needsTankUpdate = true; } @Override public void onNeighbourChanged(Block block) { this.needsTankUpdate = true; } }