/**
* This class was created by <Vazkii>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [Jan 26, 2014, 5:09:12 PM (GMT)]
*/
package vazkii.botania.common.entity;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
import com.google.common.base.Optional;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import vazkii.botania.api.BotaniaAPI;
import vazkii.botania.api.internal.IManaBurst;
import vazkii.botania.api.internal.VanillaPacketDispatcher;
import vazkii.botania.api.mana.IClientManaHandler;
import vazkii.botania.api.mana.ILensEffect;
import vazkii.botania.api.mana.IManaCollector;
import vazkii.botania.api.mana.IManaCollisionGhost;
import vazkii.botania.api.mana.IManaReceiver;
import vazkii.botania.api.mana.IManaSpreader;
import vazkii.botania.api.mana.IManaTrigger;
import vazkii.botania.api.mana.IPingable;
import vazkii.botania.api.mana.IThrottledPacket;
import vazkii.botania.common.Botania;
import vazkii.botania.common.core.handler.ConfigHandler;
import vazkii.botania.common.core.helper.Vector3;
import vazkii.botania.common.item.equipment.bauble.ItemTinyPlanet;
public class EntityManaBurst extends EntityThrowable implements IManaBurst {
private static final String TAG_TICKS_EXISTED = "ticksExisted";
private static final String TAG_COLOR = "color";
private static final String TAG_MANA = "mana";
private static final String TAG_STARTING_MANA = "startingMana";
private static final String TAG_MIN_MANA_LOSS = "minManaLoss";
private static final String TAG_TICK_MANA_LOSS = "manaLossTick";
private static final String TAG_SPREADER_X = "spreaderX";
private static final String TAG_SPREADER_Y = "spreaderY";
private static final String TAG_SPREADER_Z = "spreaderZ";
private static final String TAG_GRAVITY = "gravity";
private static final String TAG_LENS_STACK = "lensStack";
private static final String TAG_LAST_MOTION_X = "lastMotionX";
private static final String TAG_LAST_MOTION_Y = "lastMotionY";
private static final String TAG_LAST_MOTION_Z = "lastMotionZ";
private static final String TAG_HAS_SHOOTER = "hasShooter";
private static final String TAG_SHOOTER_UUID_MOST = "shooterUUIDMost";
private static final String TAG_SHOOTER_UUID_LEAST = "shooterUUIDLeast";
private static final DataParameter<Integer> COLOR = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.VARINT);
private static final DataParameter<Integer> MANA = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.VARINT);
private static final DataParameter<Integer> START_MANA = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.VARINT);
private static final DataParameter<Integer> MIN_MANA_LOSS = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.VARINT);
private static final DataParameter<Float> MANA_LOSS_PER_TICK = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.FLOAT);
private static final DataParameter<Float> GRAVITY = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.FLOAT);
private static final DataParameter<BlockPos> SOURCE_COORDS = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.BLOCK_POS);
private static final DataParameter<ItemStack> SOURCE_LENS = EntityDataManager.createKey(EntityManaBurst.class, DataSerializers.OPTIONAL_ITEM_STACK);
float accumulatedManaLoss = 0;
boolean fake = false;
final Set<BlockPos> alreadyCollidedAt = new HashSet<>();
boolean fullManaLastTick = true;
UUID shooterIdentity = null;
int _ticksExisted = 0;
boolean scanBeam = false;
public final List<PositionProperties> propsList = new ArrayList<>();
public EntityManaBurst(World world) {
super(world);
setSize(0F, 0F);
}
@Override
protected void entityInit() {
super.entityInit();
dataManager.register(COLOR, 0);
dataManager.register(MANA, 0);
dataManager.register(START_MANA, 0);
dataManager.register(MIN_MANA_LOSS, 0);
dataManager.register(MANA_LOSS_PER_TICK, 0F);
dataManager.register(GRAVITY, 0F);
dataManager.register(SOURCE_COORDS, BlockPos.ORIGIN);
dataManager.register(SOURCE_LENS, ItemStack.EMPTY);
}
public EntityManaBurst(IManaSpreader spreader, boolean fake) {
this(((TileEntity)spreader).getWorld());
TileEntity tile = (TileEntity) spreader;
this.fake = fake;
setBurstSourceCoords(tile.getPos());
setLocationAndAngles(tile.getPos().getX() + 0.5, tile.getPos().getY() + 0.5, tile.getPos().getZ() + 0.5, 0, 0);
rotationYaw = -(spreader.getRotationX() + 90F);
rotationPitch = spreader.getRotationY();
float f = 0.4F;
double mx = MathHelper.sin(rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(rotationPitch / 180.0F * (float) Math.PI) * f / 2D;
double mz = -(MathHelper.cos(rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(rotationPitch / 180.0F * (float) Math.PI) * f) / 2D;
double my = MathHelper.sin(rotationPitch / 180.0F * (float) Math.PI) * f / 2D;
setMotion(mx, my, mz);
}
public EntityManaBurst(EntityPlayer player) {
this(player.world);
setBurstSourceCoords(new BlockPos(0, -1, 0));
setLocationAndAngles(player.posX, player.posY + player.getEyeHeight(), player.posZ, player.rotationYaw + 180, -player.rotationPitch);
posX -= MathHelper.cos((rotationYaw + 180) / 180.0F * (float) Math.PI) * 0.16F;
posY -= 0.10000000149011612D;
posZ -= MathHelper.sin((rotationYaw + 180) / 180.0F * (float) Math.PI) * 0.16F;
setPosition(posX, posY, posZ);
float f = 0.4F;
double mx = MathHelper.sin(rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(rotationPitch / 180.0F * (float) Math.PI) * f / 2D;
double mz = -(MathHelper.cos(rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(rotationPitch / 180.0F * (float) Math.PI) * f) / 2D;
double my = MathHelper.sin(rotationPitch / 180.0F * (float) Math.PI) * f / 2D;
setMotion(mx, my, mz);
}
// Copy of EntityThrowable.onUpdate. Relevant edits indicated.
private void superUpdate() {
lastTickPosX = posX;
lastTickPosY = posY;
lastTickPosZ = posZ;
// super.onUpdate(); Botania - inline supersuperclass's onUpdate
{
if (!world.isRemote)
{
setFlag(6, isGlowing());
}
onEntityUpdate();
}
if (throwableShake > 0)
{
--throwableShake;
}
// Botania - remove inGround check and its else branch. Bursts are never inGround.
Vec3d vec3d = new Vec3d(posX, posY, posZ);
Vec3d vec3d1 = new Vec3d(posX + motionX, posY + motionY, posZ + motionZ);
RayTraceResult raytraceresult = world.rayTraceBlocks(vec3d, vec3d1);
vec3d = new Vec3d(posX, posY, posZ);
vec3d1 = new Vec3d(posX + motionX, posY + motionY, posZ + motionZ);
if (raytraceresult != null)
{
vec3d1 = new Vec3d(raytraceresult.hitVec.xCoord, raytraceresult.hitVec.yCoord, raytraceresult.hitVec.zCoord);
}
if(!world.isRemote) { // Botania - only do entity colliding on server
Entity entity = null;
List<Entity> list = world.getEntitiesWithinAABBExcludingEntity(this, getEntityBoundingBox().addCoord(motionX, motionY, motionZ).expandXyz(1.0D));
double d0 = 0.0D;
for (int i = 0; i < list.size(); ++i)
{
Entity entity1 = list.get(i);
if (entity1.canBeCollidedWith())
{
if (entity1 == ignoreEntity)
{
}
else if (ticksExisted < 2 && ignoreEntity == null)
{
ignoreEntity = entity1;
}
else
{
AxisAlignedBB axisalignedbb = entity1.getEntityBoundingBox().expandXyz(0.30000001192092896D);
RayTraceResult raytraceresult1 = axisalignedbb.calculateIntercept(vec3d, vec3d1);
if (raytraceresult1 != null)
{
double d1 = vec3d.squareDistanceTo(raytraceresult1.hitVec);
if (d1 < d0 || d0 == 0.0D)
{
entity = entity1;
d0 = d1;
}
}
}
}
}
if (ignoreEntity != null)
{
/*if (flag)
{
this.ignoreTime = 2;
}
else if (this.ignoreTime-- <= 0)
{
this.ignoreEntity = null;
}*/
}
if (entity != null)
{
raytraceresult = new RayTraceResult(entity);
}
} // End wrap - only do entity colliding on server
if (raytraceresult != null)
{
if (raytraceresult.typeOfHit == RayTraceResult.Type.BLOCK && world.getBlockState(raytraceresult.getBlockPos()).getBlock() == Blocks.PORTAL)
{
setPortal(raytraceresult.getBlockPos());
}
else
{
onImpact(raytraceresult);
}
}
posX += motionX;
posY += motionY;
posZ += motionZ;
float f = MathHelper.sqrt(motionX * motionX + motionZ * motionZ);
rotationYaw = (float)(MathHelper.atan2(motionX, motionZ) * (180D / Math.PI));
for (rotationPitch = (float)(MathHelper.atan2(motionY, f) * (180D / Math.PI)); rotationPitch - prevRotationPitch < -180.0F; prevRotationPitch -= 360.0F)
{
;
}
while (rotationPitch - prevRotationPitch >= 180.0F)
{
prevRotationPitch += 360.0F;
}
while (rotationYaw - prevRotationYaw < -180.0F)
{
prevRotationYaw -= 360.0F;
}
while (rotationYaw - prevRotationYaw >= 180.0F)
{
prevRotationYaw += 360.0F;
}
rotationPitch = prevRotationPitch + (rotationPitch - prevRotationPitch) * 0.2F;
rotationYaw = prevRotationYaw + (rotationYaw - prevRotationYaw) * 0.2F;
float f2 = getGravityVelocity();
if (isInWater())
{
for (int j = 0; j < 4; ++j)
{
float f3 = 0.25F;
world.spawnParticle(EnumParticleTypes.WATER_BUBBLE, posX - motionX * f3, posY - motionY * f3, posZ - motionZ * f3, motionX, motionY, motionZ, new int[0]);
}
}
// Botania - don't apply drag
// this.motionX *= (double)f1;
// this.motionY *= (double)f1;
// this.motionZ *= (double)f1;
motionY -= f2;
setPosition(posX, posY, posZ);
}
@Override
public void onUpdate() {
setTicksExisted(getTicksExisted() + 1);
superUpdate();
if(!fake && !isDead)
ping();
ILensEffect lens = getLensInstance();
if(lens != null)
lens.updateBurst(this, getSourceLens());
int mana = getMana();
if(getTicksExisted() >= getMinManaLoss()) {
accumulatedManaLoss += getManaLossPerTick();
int loss = (int) accumulatedManaLoss;
setMana(mana - loss);
accumulatedManaLoss -= loss;
if(getMana() <= 0)
setDead();
}
particles();
setMotion(motionX, motionY, motionZ);
fullManaLastTick = getMana() == getStartingMana();
if(scanBeam) {
PositionProperties props = new PositionProperties(this);
if(propsList.isEmpty())
propsList.add(props);
else {
PositionProperties lastProps = propsList.get(propsList.size() - 1);
if(!props.coordsEqual(lastProps))
propsList.add(props);
}
}
}
@Override
@SideOnly(Side.CLIENT)
public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport) {
setPosition(x, y, z);
setRotation(yaw, pitch);
}
@Override
public boolean handleWaterMovement() {
return false;
}
private TileEntity collidedTile = null;
private boolean noParticles = false;
public TileEntity getCollidedTile(boolean noParticles) {
this.noParticles = noParticles;
while(!isDead)
onUpdate();
if(fake)
incrementFakeParticleTick();
return collidedTile;
}
@Override
public void writeEntityToNBT(NBTTagCompound par1nbtTagCompound) {
super.writeEntityToNBT(par1nbtTagCompound);
par1nbtTagCompound.setInteger(TAG_TICKS_EXISTED, getTicksExisted());
par1nbtTagCompound.setInteger(TAG_COLOR, getColor());
par1nbtTagCompound.setInteger(TAG_MANA, getMana());
par1nbtTagCompound.setInteger(TAG_STARTING_MANA, getStartingMana());
par1nbtTagCompound.setInteger(TAG_MIN_MANA_LOSS, getMinManaLoss());
par1nbtTagCompound.setFloat(TAG_TICK_MANA_LOSS, getManaLossPerTick());
par1nbtTagCompound.setFloat(TAG_GRAVITY, getGravity());
ItemStack stack = getSourceLens();
NBTTagCompound lensCmp = new NBTTagCompound();
if(!stack.isEmpty())
lensCmp = stack.writeToNBT(lensCmp);
par1nbtTagCompound.setTag(TAG_LENS_STACK, lensCmp);
BlockPos coords = getBurstSourceBlockPos();
par1nbtTagCompound.setInteger(TAG_SPREADER_X, coords.getX());
par1nbtTagCompound.setInteger(TAG_SPREADER_Y, coords.getY());
par1nbtTagCompound.setInteger(TAG_SPREADER_Z, coords.getZ());
par1nbtTagCompound.setDouble(TAG_LAST_MOTION_X, motionX);
par1nbtTagCompound.setDouble(TAG_LAST_MOTION_Y, motionY);
par1nbtTagCompound.setDouble(TAG_LAST_MOTION_Z, motionZ);
UUID identity = getShooterUUID();
boolean hasShooter = identity != null;
par1nbtTagCompound.setBoolean(TAG_HAS_SHOOTER, hasShooter);
if(hasShooter) {
par1nbtTagCompound.setLong(TAG_SHOOTER_UUID_MOST, identity.getMostSignificantBits());
par1nbtTagCompound.setLong(TAG_SHOOTER_UUID_LEAST, identity.getLeastSignificantBits());
}
}
@Override
public void readEntityFromNBT(NBTTagCompound par1nbtTagCompound) {
super.readEntityFromNBT(par1nbtTagCompound);
setTicksExisted(par1nbtTagCompound.getInteger(TAG_TICKS_EXISTED));
setColor(par1nbtTagCompound.getInteger(TAG_COLOR));
setMana(par1nbtTagCompound.getInteger(TAG_MANA));
setStartingMana(par1nbtTagCompound.getInteger(TAG_STARTING_MANA));
setMinManaLoss(par1nbtTagCompound.getInteger(TAG_MIN_MANA_LOSS));
setManaLossPerTick(par1nbtTagCompound.getFloat(TAG_TICK_MANA_LOSS));
setGravity(par1nbtTagCompound.getFloat(TAG_GRAVITY));
NBTTagCompound lensCmp = par1nbtTagCompound.getCompoundTag(TAG_LENS_STACK);
ItemStack stack = new ItemStack(lensCmp);
if(!stack.isEmpty())
setSourceLens(stack);
else setSourceLens(ItemStack.EMPTY);
int x = par1nbtTagCompound.getInteger(TAG_SPREADER_X);
int y = par1nbtTagCompound.getInteger(TAG_SPREADER_Y);
int z = par1nbtTagCompound.getInteger(TAG_SPREADER_Z);
setBurstSourceCoords(new BlockPos(x, y, z));
double lastMotionX = par1nbtTagCompound.getDouble(TAG_LAST_MOTION_X);
double lastMotionY = par1nbtTagCompound.getDouble(TAG_LAST_MOTION_Y);
double lastMotionZ = par1nbtTagCompound.getDouble(TAG_LAST_MOTION_Z);
setMotion(lastMotionX, lastMotionY, lastMotionZ);
boolean hasShooter = par1nbtTagCompound.getBoolean(TAG_HAS_SHOOTER);
if(hasShooter) {
long most = par1nbtTagCompound.getLong(TAG_SHOOTER_UUID_MOST);
long least = par1nbtTagCompound.getLong(TAG_SHOOTER_UUID_LEAST);
UUID identity = getShooterUUID();
if(identity == null || most != identity.getMostSignificantBits() || least != identity.getLeastSignificantBits())
shooterIdentity = new UUID(most, least);
}
}
public void particles() {
if(isDead || !world.isRemote)
return;
ILensEffect lens = getLensInstance();
if(lens != null && !lens.doParticles(this, getSourceLens()))
return;
Color color = new Color(getColor());
float r = color.getRed() / 255F;
float g = color.getGreen() / 255F;
float b = color.getBlue() / 255F;
int mana = getMana();
int maxMana = getStartingMana();
float osize = (float) mana / (float) maxMana;
float size = osize;
if(fake) {
if(getMana() == getStartingMana())
size = 2F;
else if(fullManaLastTick)
size = 4F;
if(!noParticles && shouldDoFakeParticles())
Botania.proxy.sparkleFX(posX, posY, posZ, r, g, b, 0.4F * size, 1, true);
} else {
boolean monocle = Botania.proxy.isClientPlayerWearingMonocle();
if(monocle)
Botania.proxy.setWispFXDepthTest(false);
if(ConfigHandler.subtlePowerSystem)
Botania.proxy.wispFX(posX, posY, posZ, r, g, b, 0.1F * size, (float) (Math.random() - 0.5F) * 0.02F, (float) (Math.random() - 0.5F) * 0.02F, (float) (Math.random() - 0.5F) * 0.01F);
else {
float or = r;
float og = g;
float ob = b;
double luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b; // Standard relative luminance calculation
double savedPosX = posX;
double savedPosY = posY;
double savedPosZ = posZ;
Vector3 currentPos = Vector3.fromEntity(this);
Vector3 oldPos = new Vector3(prevPosX, prevPosY, prevPosZ);
Vector3 diffVec = oldPos.subtract(currentPos);
Vector3 diffVecNorm = diffVec.normalize();
double distance = 0.095;
do {
if (luminance < 0.1) {
r = or + (float) Math.random() * 0.125F;
g = og + (float) Math.random() * 0.125F;
b = ob + (float) Math.random() * 0.125F;
}
size = osize + ((float) Math.random() - 0.5F) * 0.065F + (float) Math.sin(new Random(entityUniqueID.getMostSignificantBits()).nextInt(9001)) * 0.4F;
Botania.proxy.wispFX(posX, posY, posZ, r, g, b, 0.2F * size, (float) -motionX * 0.01F, (float) -motionY * 0.01F, (float) -motionZ * 0.01F);
posX += diffVecNorm.x * distance;
posY += diffVecNorm.y * distance;
posZ += diffVecNorm.z * distance;
currentPos = Vector3.fromEntity(this);
diffVec = oldPos.subtract(currentPos);
if(getEntityData().hasKey(ItemTinyPlanet.TAG_ORBIT))
break;
} while(Math.abs(diffVec.mag()) > distance);
Botania.proxy.wispFX(posX, posY, posZ, or, og, ob, 0.1F * size, (float) (Math.random() - 0.5F) * 0.06F, (float) (Math.random() - 0.5F) * 0.06F, (float) (Math.random() - 0.5F) * 0.06F);
posX = savedPosX;
posY = savedPosY;
posZ = savedPosZ;
}
if(monocle)
Botania.proxy.setWispFXDepthTest(true);
}
}
@Override
protected void onImpact(@Nonnull RayTraceResult rtr) {
boolean collided = false;
boolean dead = false;
if(rtr.entityHit == null) {
TileEntity tile = world.getTileEntity(rtr.getBlockPos());
IBlockState state = world.getBlockState(rtr.getBlockPos());
Block block = state.getBlock();
if(block instanceof IManaCollisionGhost && ((IManaCollisionGhost) block).isGhost(state, world, rtr.getBlockPos()) && !(block instanceof IManaTrigger) || block instanceof BlockBush || block instanceof BlockLeaves)
return;
if(BotaniaAPI.internalHandler.isBuildcraftPipe(tile))
return;
BlockPos coords = getBurstSourceBlockPos();
if(tile != null && !tile.getPos().equals(coords))
collidedTile = tile;
if(tile == null || !tile.getPos().equals(coords)) {
if(!fake && !noParticles && (!world.isRemote || tile instanceof IClientManaHandler) && tile != null && tile instanceof IManaReceiver && ((IManaReceiver) tile).canRecieveManaFromBursts())
onRecieverImpact((IManaReceiver) tile, tile.getPos());
if(block instanceof IManaTrigger)
((IManaTrigger) block).onBurstCollision(this, world, rtr.getBlockPos());
boolean ghost = block instanceof IManaCollisionGhost;
dead = !ghost;
if(ghost)
return;
}
collided = true;
}
ILensEffect lens = getLensInstance();
if(lens != null)
dead = lens.collideBurst(this, rtr, collidedTile != null && collidedTile instanceof IManaReceiver && ((IManaReceiver) collidedTile).canRecieveManaFromBursts(), dead, getSourceLens());
if(collided && !hasAlreadyCollidedAt(rtr.getBlockPos()))
alreadyCollidedAt.add(rtr.getBlockPos());
if(dead && !isDead) {
if(!fake) {
Color color = new Color(getColor());
float r = color.getRed() / 255F;
float g = color.getGreen() / 255F;
float b = color.getBlue() / 255F;
int mana = getMana();
int maxMana = getStartingMana();
float size = (float) mana / (float) maxMana;
if(!ConfigHandler.subtlePowerSystem)
for(int i = 0; i < 4; i++)
Botania.proxy.wispFX(posX, posY, posZ, r, g, b, 0.15F * size, (float) (Math.random() - 0.5F) * 0.04F, (float) (Math.random() - 0.5F) * 0.04F, (float) (Math.random() - 0.5F) * 0.04F);
Botania.proxy.sparkleFX((float) posX, (float) posY, (float) posZ, r, g, b, 4, 2);
}
setDead();
}
}
private void onRecieverImpact(IManaReceiver tile, BlockPos pos) {
ILensEffect lens = getLensInstance();
int mana = getMana();
if(lens != null) {
ItemStack stack = getSourceLens();
mana = lens.getManaToTransfer(this, this, stack, tile);
}
if(tile instanceof IManaCollector)
mana *= ((IManaCollector) tile).getManaYieldMultiplier(this);
tile.recieveMana(mana);
if(tile instanceof IThrottledPacket)
((IThrottledPacket) tile).markDispatchable();
else VanillaPacketDispatcher.dispatchTEToNearbyPlayers(world, pos);
}
@Override
public void setDead() {
super.setDead();
if(!fake) {
TileEntity tile = getShooter();
if(tile != null && tile instanceof IManaSpreader)
((IManaSpreader) tile).setCanShoot(true);
} else setDeathTicksForFakeParticle();
}
private TileEntity getShooter() {
return world.getTileEntity(getBurstSourceBlockPos());
}
@Override
protected float getGravityVelocity() {
return getGravity();
}
@Override
public boolean isFake() {
return fake;
}
@Override
public void setFake(boolean fake) {
this.fake = fake;
}
public void setScanBeam() {
scanBeam = true;
}
@Override
public int getColor() {
return dataManager.get(COLOR);
}
@Override
public void setColor(int color) {
dataManager.set(COLOR, color);
}
@Override
public int getMana() {
return dataManager.get(MANA);
}
@Override
public void setMana(int mana) {
dataManager.set(MANA, mana);
}
@Override
public int getStartingMana() {
return dataManager.get(START_MANA);
}
@Override
public void setStartingMana(int mana) {
dataManager.set(START_MANA, mana);
}
@Override
public int getMinManaLoss() {
return dataManager.get(MIN_MANA_LOSS);
}
@Override
public void setMinManaLoss(int minManaLoss) {
dataManager.set(MIN_MANA_LOSS, minManaLoss);
}
@Override
public float getManaLossPerTick() {
return dataManager.get(MANA_LOSS_PER_TICK);
}
@Override
public void setManaLossPerTick(float mana) {
dataManager.set(MANA_LOSS_PER_TICK, mana);
}
@Override
public float getGravity() {
return dataManager.get(GRAVITY);
}
@Override
public void setGravity(float gravity) {
dataManager.set(GRAVITY, gravity);
}
@Override
public BlockPos getBurstSourceBlockPos() {
return dataManager.get(SOURCE_COORDS);
}
@Override
public void setBurstSourceCoords(BlockPos pos) {
dataManager.set(SOURCE_COORDS, pos);
}
@Override
public ItemStack getSourceLens() {
return dataManager.get(SOURCE_LENS);
}
@Override
public void setSourceLens(ItemStack lens) {
dataManager.set(SOURCE_LENS, lens);
}
@Override
public int getTicksExisted() {
return _ticksExisted;
}
public void setTicksExisted(int ticks) {
_ticksExisted = ticks;
}
private ILensEffect getLensInstance() {
ItemStack lens = getSourceLens();
if(!lens.isEmpty() && lens.getItem() instanceof ILensEffect)
return (ILensEffect) lens.getItem();
return null;
}
@Override
public void setMotion(double x, double y, double z) {
motionX = x;
motionY = y;
motionZ = z;
}
@Override
public boolean hasAlreadyCollidedAt(BlockPos pos) {
return alreadyCollidedAt.contains(pos);
}
@Override
public void setCollidedAt(BlockPos pos) {
if(!hasAlreadyCollidedAt(pos))
alreadyCollidedAt.add(pos.toImmutable());
}
@Override
public void setShooterUUID(UUID uuid) {
shooterIdentity = uuid;
}
@Override
public UUID getShooterUUID() {
return shooterIdentity;
}
@Override
public void ping() {
TileEntity tile = getShooter();
if(tile != null && tile instanceof IPingable)
((IPingable) tile).pingback(this, getShooterUUID());
}
protected boolean shouldDoFakeParticles() {
if (ConfigHandler.staticWandBeam)
return true;
TileEntity tile = getShooter();
return tile != null
&& tile instanceof IManaSpreader
&& (getMana() != getStartingMana() && fullManaLastTick
|| Math.abs(((IManaSpreader) tile).getBurstParticleTick() - getTicksExisted()) < 4);
}
private void incrementFakeParticleTick() {
TileEntity tile = getShooter();
if(tile != null && tile instanceof IManaSpreader) {
IManaSpreader spreader = (IManaSpreader) tile;
spreader.setBurstParticleTick(spreader.getBurstParticleTick()+2);
if(spreader.getLastBurstDeathTick() != -1 && spreader.getBurstParticleTick() > spreader.getLastBurstDeathTick())
spreader.setBurstParticleTick(0);
}
}
private void setDeathTicksForFakeParticle() {
BlockPos coords = getBurstSourceBlockPos();
TileEntity tile = world.getTileEntity(coords);
if(tile != null && tile instanceof IManaSpreader)
((IManaSpreader) tile).setLastBurstDeathTick(getTicksExisted());
}
public static class PositionProperties {
public final BlockPos coords;
public final IBlockState state;
public boolean invalid = false;
public PositionProperties(Entity entity) {
int x = MathHelper.floor(entity.posX);
int y = MathHelper.floor(entity.posY);
int z = MathHelper.floor(entity.posZ);
coords = new BlockPos(x, y, z);
state = entity.world.getBlockState(coords);
}
public boolean coordsEqual(PositionProperties props) {
return coords.equals(props.coords);
}
public boolean contentsEqual(World world) {
if(!world.isBlockLoaded(coords)) {
invalid = true;
return false;
}
return world.getBlockState(coords) == state;
}
@Override
public int hashCode() {
return Objects.hash(coords, state);
}
@Override
public boolean equals(Object o) {
return o instanceof PositionProperties
&& ((PositionProperties) o).state == state
&& ((PositionProperties) o).coords.equals(coords);
}
}
}