/*
* This file is part of Matter Overdrive
* Copyright (c) 2015., Simeon Radivoev, All rights reserved.
*
* Matter Overdrive is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Matter Overdrive is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Matter Overdrive. If not, see <http://www.gnu.org/licenses>.
*/
package matteroverdrive.tile;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import matteroverdrive.MatterOverdrive;
import matteroverdrive.Reference;
import matteroverdrive.api.IScannable;
import matteroverdrive.api.events.anomaly.MOEventGravitationalAnomalyConsume;
import matteroverdrive.api.gravity.AnomalySuppressor;
import matteroverdrive.api.gravity.IGravitationalAnomaly;
import matteroverdrive.api.gravity.IGravityEntity;
import matteroverdrive.client.sound.GravitationalAnomalySound;
import matteroverdrive.entity.player.AndroidPlayer;
import matteroverdrive.fx.GravitationalAnomalyParticle;
import matteroverdrive.init.MatterOverdriveBioticStats;
import matteroverdrive.items.SpacetimeEqualizer;
import matteroverdrive.machines.MachineNBTCategory;
import matteroverdrive.util.MatterHelper;
import matteroverdrive.util.TimeTracker;
import matteroverdrive.util.math.MOMathHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.IFluidBlock;
import org.apache.logging.log4j.Level;
import org.lwjgl.util.vector.Vector3f;
import java.text.DecimalFormat;
import java.util.*;
/**
* Created by Simeon on 5/11/2015.
*/
public class TileEntityGravitationalAnomaly extends MOTileEntity implements IScannable, IMOTickable,IGravitationalAnomaly
{
public static boolean FALLING_BLOCKS = true;
public static boolean BLOCK_ENTETIES = true;
public static boolean VANILLA_FLUIDS = true;
public static boolean FORGE_FLUIDS = true;
public static boolean BLOCK_DESTRUCTION = true;
public static boolean GRAVITATION = true;
public static final float MAX_VOLUME = 0.5f;
public static final int BLOCK_DESTORY_DELAY = 6;
public static final int MAX_BLOCKS_PER_HARVEST = 6;
public static final int MAX_LIQUIDS_PER_HARVEST = 32;
public static final double STREHGTH_MULTIPLYER = 0.00001;
public static final double G = 6.67384;
public static final double G2 = G * 2;
public static final double C = 2.99792458;
public static final double CC = C * C;
@SideOnly(Side.CLIENT)
private GravitationalAnomalySound sound;
private TimeTracker blockDestoryTimer;
private long mass;
PriorityQueue<PositionWrapper> blocks;
List<AnomalySuppressor> supressors;
private float suppression;
private Vec3 blockPos;
private Vec3 entityPos;
private Vec3 dir;
private Vec3 intersectDir;
//region Constructors
public TileEntityGravitationalAnomaly()
{
blockDestoryTimer = new TimeTracker();
this.mass = 2048 + Math.round(Math.random() * 8192);
supressors = new ArrayList<>();
blockPos = Vec3.createVectorHelper(0,0,0);
entityPos = Vec3.createVectorHelper(0,0,0);
dir = Vec3.createVectorHelper(0,0,0);
intersectDir = Vec3.createVectorHelper(0,0,0);
}
public TileEntityGravitationalAnomaly(int mass)
{
this();
this.mass = mass;
}
//endregion
//region Updates
@Override
public void updateEntity()
{
super.updateEntity();
if (worldObj.isRemote)
{
spawnParticles(worldObj);
manageSound();
manageClientEntityGravitation(worldObj);
}
}
@Override
public void onServerTick(TickEvent.Phase phase,World world)
{
if (worldObj == null)
return;
if (phase.equals(TickEvent.Phase.END))
{
float tmpSuppression = calculateSuppression();
if (tmpSuppression != suppression)
{
suppression = tmpSuppression;
worldObj.markBlockForUpdate(xCoord,yCoord,zCoord);
}
manageEntityGravitation(worldObj, 0);
manageBlockDestory(worldObj);
}
}
//endregion
@SideOnly(Side.CLIENT)
public void spawnParticles(World world)
{
double radius = (float)getBlockBreakRange();
Vector3f point = MOMathHelper.randomSpherePoint(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5, Vec3.createVectorHelper(radius, radius, radius), world.rand);
GravitationalAnomalyParticle particle = new GravitationalAnomalyParticle(world,point.x, point.y, point.z, Vec3.createVectorHelper(xCoord + 0.5f, yCoord + 0.5f, zCoord + 0.5f));
Minecraft.getMinecraft().effectRenderer.addEffect(particle);
}
@SideOnly(Side.CLIENT)
public void manageClientEntityGravitation(World world)
{
if (!GRAVITATION)
return;
double rangeSq = getMaxRange() + 1;
rangeSq *= rangeSq;
blockPos.xCoord = xCoord + 0.5;
blockPos.yCoord = yCoord + 0.5;
blockPos.zCoord = zCoord + 0.5;
entityPos.xCoord = Minecraft.getMinecraft().thePlayer.posX;
entityPos.yCoord = Minecraft.getMinecraft().thePlayer.posY + Minecraft.getMinecraft().thePlayer.getEyeHeight()/2;
entityPos.zCoord = Minecraft.getMinecraft().thePlayer.posZ;
double distanceSq = entityPos.squareDistanceTo(blockPos);
if ( distanceSq < rangeSq)
{
if ((Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(3) != null && Minecraft.getMinecraft().thePlayer.getEquipmentInSlot(3).getItem() instanceof SpacetimeEqualizer)
|| Minecraft.getMinecraft().thePlayer.capabilities.disableDamage
|| AndroidPlayer.get(Minecraft.getMinecraft().thePlayer).isUnlocked(MatterOverdriveBioticStats.equalizer,0))
return;
double acceleration = getAcceleration(distanceSq);
dir.xCoord = blockPos.xCoord - entityPos.xCoord;
dir.yCoord = blockPos.yCoord - entityPos.yCoord;
dir.zCoord = blockPos.zCoord - entityPos.zCoord;
normalize(dir);
Minecraft.getMinecraft().thePlayer.addVelocity(dir.xCoord * acceleration,dir.yCoord * acceleration,dir.zCoord * acceleration);
Minecraft.getMinecraft().thePlayer.velocityChanged = true;
}
}
public void manageEntityGravitation(World world,float ticks)
{
if (!GRAVITATION)
return;
double range = getMaxRange() + 1;
AxisAlignedBB bb = AxisAlignedBB.getBoundingBox(xCoord - range, yCoord - range, zCoord - range, xCoord + range, yCoord + range, zCoord + range);
List entities = world.getEntitiesWithinAABB(Entity.class, bb);
blockPos.xCoord = xCoord + 0.5;
blockPos.yCoord = yCoord + 0.5;
blockPos.zCoord = zCoord + 0.5;
for (Object entityObject : entities)
{
if (entityObject instanceof Entity)
{
Entity entity = (Entity)entityObject;
if (entity instanceof IGravityEntity)
{
if (!((IGravityEntity) entity).isAffectedByAnomaly(this))
{
continue;
}
}
entityPos.xCoord = entity.posX;
entityPos.yCoord = entity.posY;
entityPos.zCoord = entity.posZ;
//pos.yCoord += entity.getEyeHeight();
double distanceSq = entityPos.squareDistanceTo(blockPos);
double acceleration = getAcceleration(distanceSq);
double eventHorizon = getEventHorizon();
dir.xCoord = blockPos.xCoord - entityPos.xCoord;
dir.yCoord = blockPos.yCoord - entityPos.yCoord;
dir.zCoord = blockPos.zCoord - entityPos.zCoord;
normalize(dir);
dir.xCoord *= acceleration;
dir.yCoord *= acceleration;
dir.zCoord *= acceleration;
if (intersectsAnomaly(entityPos,dir,blockPos,eventHorizon))
{
consume(entity);
}
if (entityObject instanceof EntityLivingBase) {
ItemStack eq = ((EntityLivingBase) entityObject).getEquipmentInSlot(3);
if (eq != null && eq.getItem() instanceof SpacetimeEqualizer)
continue;
}
entity.addVelocity(dir.xCoord, dir.yCoord, dir.zCoord);
}
}
}
boolean intersectsAnomaly(Vec3 origin,Vec3 dir,Vec3 anomaly,double radius)
{
if (origin.distanceTo(anomaly) <= radius)
{
return true;
}else
{
intersectDir.xCoord = origin.xCoord - anomaly.xCoord;
intersectDir.yCoord = origin.yCoord - anomaly.yCoord;
intersectDir.zCoord = origin.zCoord - anomaly.zCoord;
double c = intersectDir.lengthVector();
double v = intersectDir.dotProduct(dir);
double d = radius*radius - (c*c - v*v);
if (d < 0)
{
return false;
}else
{
return true;
}
}
}
//region Sounds
@SideOnly(Side.CLIENT)
public void stopSounds()
{
if (sound != null)
{
sound.stopPlaying();
FMLClientHandler.instance().getClient().getSoundHandler().stopSound(sound);
sound = null;
}
}
@SideOnly(Side.CLIENT)
public void playSounds()
{
if (sound == null)
{
sound = new GravitationalAnomalySound(new ResourceLocation(Reference.MOD_ID + ":" + "windy"),xCoord,yCoord,zCoord,0.2f,getMaxRange());
FMLClientHandler.instance().getClient().getSoundHandler().playSound(sound);
}
else if (!FMLClientHandler.instance().getClient().getSoundHandler().isSoundPlaying(sound))
{
stopSounds();
sound = new GravitationalAnomalySound(new ResourceLocation(Reference.MOD_ID + ":" + "windy"),xCoord,yCoord,zCoord,0.2f,getMaxRange());
FMLClientHandler.instance().getClient().getSoundHandler().playSound(sound);
}
}
@SideOnly(Side.CLIENT)
public void manageSound()
{
if (sound == null)
{
playSounds();
}else
{
sound.setVolume(Math.min(MAX_VOLUME,getBreakStrength(0,(float)getMaxRange()) * 0.1f));
sound.setRange(getMaxRange());
}
}
//endregion
//region Super Events
@Override
public void onAdded(World world, int x, int y, int z) {
}
@Override
public void onPlaced(World world, EntityLivingBase entityLiving) {
}
@Override
public void onDestroyed() {
}
@Override
public void onNeighborBlockChange() {
}
@Override
public void writeToDropItem(ItemStack itemStack) {
}
@Override
public void readFromPlaceItem(ItemStack itemStack) {
}
@Override
public void onScan(World world, double x, double y, double z, EntityPlayer player, ItemStack scanner) {
}
public void onChunkUnload()
{
if (worldObj.isRemote)
{
stopSounds();
}
}
@Override
protected void onAwake(Side side) {
}
@Override
public Packet getDescriptionPacket()
{
NBTTagCompound syncData = new NBTTagCompound();
writeCustomNBT(syncData, MachineNBTCategory.ALL_OPTS, false);
return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 1, syncData);
}
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
{
NBTTagCompound syncData = pkt.func_148857_g();
if(syncData != null)
{
readCustomNBT(syncData, MachineNBTCategory.ALL_OPTS);
}
}
@Override
public void invalidate()
{
super.invalidate();
if (worldObj.isRemote)
{
stopSounds();
}
}
//endregion
//region Events
private boolean onEntityConsume(Entity entity,boolean pre)
{
if (entity instanceof IGravityEntity)
{
((IGravityEntity) entity).onEntityConsumed(this);
}
if (pre)
{
MinecraftForge.EVENT_BUS.post(new MOEventGravitationalAnomalyConsume.Pre(entity,xCoord,yCoord,zCoord));
}else
{
MinecraftForge.EVENT_BUS.post(new MOEventGravitationalAnomalyConsume.Post(entity,xCoord,yCoord,zCoord));
}
return true;
}
//endregion
public void manageBlockDestory(World world)
{
if (!BLOCK_DESTRUCTION)
return;
int solidCount = 0;
int liquidCount = 0;
int range = (int) Math.floor(getBlockBreakRange());
double distance;
double eventHorizon = getEventHorizon();
int blockPosX,blockPosY,blockPosZ;
float hardness;
Block block;
blocks = new PriorityQueue<>(1,new BlockComparitor(xCoord,yCoord,zCoord));
if (blockDestoryTimer.hasDelayPassed(world,BLOCK_DESTORY_DELAY))
{
for (int x = -range; x < range;x++)
{
for (int y = -range;y < range;y++)
{
for (int z = -range;z < range;z++)
{
blockPosX = xCoord + x;
blockPosY = yCoord + y;
blockPosZ = zCoord + z;
block = getBlock(world,blockPosX,blockPosY,blockPosZ);
distance = MOMathHelper.distance(blockPosX,blockPosY,blockPosZ,xCoord,yCoord,zCoord);
hardness = block.getBlockHardness(world,blockPosX,blockPosY,blockPosZ);
if (block instanceof IFluidBlock || block instanceof BlockLiquid)
{
hardness = 1;
}
float strength = getBreakStrength((float)distance,range);
if (block != null && block != Blocks.air && distance <= range && hardness >= 0 && (distance < eventHorizon || hardness < strength))
{
blocks.add(new PositionWrapper(blockPosX,blockPosY,blockPosZ));
}
}
}
}
}
for (PositionWrapper position : blocks)
{
block = world.getBlock(position.x,position.y,position.z);
if (!cleanFlowingLiquids(block,position.x,position.y,position.z))
{
if (liquidCount < MAX_LIQUIDS_PER_HARVEST) {
if (cleanLiquids(block, position.x, position.y, position.z)) {
liquidCount++;
continue;
}
}
if (solidCount < MAX_BLOCKS_PER_HARVEST)
{
try {
distance = MOMathHelper.distance(position.x,position.y,position.z,xCoord,yCoord,zCoord);
float strength = getBreakStrength((float)distance,range);
if (brakeBlock(world, position.x, position.y, position.z, strength, eventHorizon, range)) {
solidCount++;
}
}catch (Exception e)
{
MatterOverdrive.log.log(Level.ERROR,e,"There was a problem while trying to brake block %s",block);
}
}
}
}
}
//region Consume Type Handlers
public void consume(Entity entity) {
if (!entity.isDead && onEntityConsume(entity,true)) {
boolean consumedFlag = false;
if (entity instanceof EntityItem) {
consumedFlag |= consumeEntityItem((EntityItem)entity);
} else if (entity instanceof EntityFallingBlock) {
consumedFlag |= consumeFallingBlock((EntityFallingBlock)entity);
} else if (entity instanceof EntityLivingBase)
{
consumedFlag |= consumeLivingEntity((EntityLivingBase)entity,getBreakStrength((float)entity.getDistance(xCoord,yCoord,zCoord),(float)getMaxRange()));
}
if (consumedFlag)
{
onEntityConsume(entity, false);
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
}
private boolean consumeEntityItem(EntityItem entityItem)
{
ItemStack itemStack = entityItem.getEntityItem();
if (itemStack != null) {
try {
mass = Math.addExact(mass, (long) MatterHelper.getMatterAmountFromItem(itemStack) * (long) itemStack.stackSize);
}
catch (ArithmeticException e)
{
return false;
}
entityItem.setDead();
worldObj.removeEntity(entityItem);
//Todo made the gravitational anomaly collapse on Antimatter
if (entityItem.getEntityItem().getItem().equals(Items.nether_star))
{
collapse();
}
return true;
}
return false;
}
private boolean consumeFallingBlock(EntityFallingBlock fallingBlock)
{
ItemStack itemStack = new ItemStack(fallingBlock.func_145805_f(),1,fallingBlock.field_145814_a);
if (itemStack != null) {
try {
mass = Math.addExact(mass, (long) MatterHelper.getMatterAmountFromItem(itemStack) * (long) itemStack.stackSize);
} catch (ArithmeticException e) {
return false;
}
fallingBlock.setDead();
worldObj.removeEntity(fallingBlock);
return true;
}
return false;
}
private boolean consumeLivingEntity(EntityLivingBase entity,float strength)
{
try {
mass = Math.addExact(mass,(long)Math.min(entity.getHealth(), strength));
}catch (ArithmeticException e)
{
return false;
}
if (entity.getHealth() <= strength && !(entity instanceof EntityPlayer)) {
entity.setDead();
worldObj.removeEntity(entity);
}
DamageSource damageSource = new DamageSource("blackHole");
entity.attackEntityFrom(damageSource, strength);
return true;
}
//endregion
public boolean brakeBlock(World world,int x,int y,int z,float strength,double eventHorizon,int range)
{
Block block = world.getBlock(x, y, z);
if (block == null)
return true;
float hardness = block.getBlockHardness(worldObj,x,y,z);
double distance = MOMathHelper.distance(x,y,z,xCoord,yCoord,zCoord);
if (distance <= range && hardness >= 0 && (distance < eventHorizon || hardness < strength))
{
int meta = worldObj.getBlockMetadata(x, y, z);
if (BLOCK_ENTETIES) {
if (FALLING_BLOCKS)
{
EntityFallingBlock fallingBlock = new EntityFallingBlock(world, x + 0.5, y + 0.5, z + 0.5, block, world.getBlockMetadata(x, y, z));
fallingBlock.field_145812_b = 1;
fallingBlock.noClip = true;
world.spawnEntityInWorld(fallingBlock);
}
else {
ItemStack bStack = createStackedBlock(block, meta);
if (bStack != null)
{
EntityItem item = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, bStack);
world.spawnEntityInWorld(item);
}
}
block.breakBlock(world, x, y, z, block, 0);
worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12));
world.setBlock(x, y, z, Blocks.air, 0, 10);
return true;
}else
{
int matter = 0;
if (block.canSilkHarvest(worldObj, null, x, y, z, meta)) {
matter += MatterHelper.getMatterAmountFromItem(createStackedBlock(block, meta));
} else {
for (ItemStack stack : block.getDrops(worldObj, x, y, z, meta, 0))
{
matter+= MatterHelper.getMatterAmountFromItem(stack);
}
}
worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12));
List<EntityItem> result = worldObj.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(x - 2, y - 2, z - 2, x + 3, y + 3, z + 3));
for (EntityItem entityItem : result) {
consumeEntityItem(entityItem);
}
try {
mass = Math.addExact(mass,matter);
}
catch (ArithmeticException e)
{
return false;
}
world.setBlock(x, y, z, Blocks.air, 0, 10);
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
return true;
}
}
return false;
}
//region Helper Methods
protected ItemStack createStackedBlock(Block block,int meta)
{
if (block != null) {
Item item = Item.getItemFromBlock(block);
if (item != null) {
if (item.getHasSubtypes()) {
return new ItemStack(item, 1, meta);
}
return new ItemStack(item, 1, 0);
}
}
return null;
}
public boolean cleanLiquids(Block block,int x,int y,int z)
{
if (block instanceof IFluidBlock && FORGE_FLUIDS)
{
if(((IFluidBlock) block).canDrain(worldObj,x,y,z))
{
if (FALLING_BLOCKS)
{
EntityFallingBlock fallingBlock = new EntityFallingBlock(worldObj, x + 0.5, y + 0.5, z + 0.5, block, worldObj.getBlockMetadata(x, y, z));
fallingBlock.field_145812_b = 1;
fallingBlock.noClip = true;
worldObj.spawnEntityInWorld(fallingBlock);
}
((IFluidBlock) block).drain(worldObj,x,y,z,true);
return true;
}
}else if (block instanceof BlockLiquid && VANILLA_FLUIDS)
{
if(worldObj.setBlock(x, y, z, Blocks.air, 0, 2)) {
if (FALLING_BLOCKS)
{
EntityFallingBlock fallingBlock = new EntityFallingBlock(worldObj, x + 0.5, y + 0.5, z + 0.5, block, worldObj.getBlockMetadata(x, y, z));
fallingBlock.field_145812_b = 1;
fallingBlock.noClip = true;
worldObj.spawnEntityInWorld(fallingBlock);
}
return true;
}
}
return false;
}
public boolean cleanFlowingLiquids(Block block,int x,int y,int z) {
if (VANILLA_FLUIDS) {
if (block == Blocks.flowing_water || block == Blocks.flowing_lava) {
return worldObj.setBlock(x, y, z, Blocks.air, 0, 2);
}
}
return false;
}
private Vec3 normalize(Vec3 vec3)
{
double d0 = (double) net.minecraft.util.MathHelper.sqrt_double(vec3.xCoord * vec3.xCoord + vec3.yCoord * vec3.yCoord + vec3.zCoord * vec3.zCoord);
if (d0 < 1.0E-4D)
{
vec3.xCoord = 0;
vec3.yCoord = 0;
vec3.zCoord = 0;
}else
{
vec3.xCoord = vec3.xCoord / d0;
vec3.yCoord = vec3.yCoord / d0;
vec3.zCoord = vec3.zCoord / d0;
}
return vec3;
}
//endregion
public void collapse()
{
worldObj.setBlockToAir(xCoord,yCoord,zCoord);
worldObj.createExplosion(null,xCoord,yCoord,zCoord,(float)getRealMassUnsuppressed()*2,true);
}
@Override
public void addInfo(World world, double x, double y, double z, List<String> infos)
{
DecimalFormat format = new DecimalFormat("#.##");
infos.add("Mass: " + mass);
infos.add("Range: " + format.format(getMaxRange()));
infos.add("Brake Range: " + format.format(getBlockBreakRange()));
infos.add("Horizon: " + format.format(getEventHorizon()));
infos.add("Brake Lvl: " + format.format(getBreakStrength()));
}
public void suppress(AnomalySuppressor suppressor)
{
for (AnomalySuppressor s : supressors)
{
if (s.update(suppressor))
{
return;
}
}
supressors.add(suppressor);
}
private float calculateSuppression()
{
float suppression = 1;
Iterator<AnomalySuppressor> iterator = supressors.iterator();
while (iterator.hasNext())
{
AnomalySuppressor s = iterator.next();
if (!s.isValid())
{
iterator.remove();
}
s.tick();
suppression *= s.getAmount();
}
return suppression;
}
//region NBT
@Override
public void writeCustomNBT(NBTTagCompound nbt, EnumSet<MachineNBTCategory> categories, boolean toDisk)
{
if (categories.contains(MachineNBTCategory.DATA)) {
nbt.setLong("Mass", mass);
nbt.setFloat("Suppression", suppression);
if (toDisk)
{
NBTTagList suppressors = new NBTTagList();
for (AnomalySuppressor s : this.supressors)
{
NBTTagCompound suppressorTag = new NBTTagCompound();
s.writeToNBT(suppressorTag);
suppressors.appendTag(suppressorTag);
}
nbt.setTag("suppressors", suppressors);
}
}
}
@Override
public void readCustomNBT(NBTTagCompound nbt, EnumSet<MachineNBTCategory> categories)
{
if (categories.contains(MachineNBTCategory.DATA)) {
this.supressors.clear();
mass = nbt.getLong("Mass");
suppression = nbt.getFloat("Suppression");
NBTTagList suppressors = nbt.getTagList("suppressors", Constants.NBT.TAG_COMPOUND);
for (int i = 0;i < supressors.size();i++)
{
NBTTagCompound suppressorTag = suppressors.getCompoundTagAt(i);
AnomalySuppressor s = new AnomalySuppressor(suppressorTag);
this.supressors.add(s);
}
}
}
//endregion
//region Getters and Setters
@SideOnly(Side.CLIENT)
public double getMaxRenderDistanceSquared()
{
return Math.max(Math.pow(getMaxRange(),3),2048);
}
public Block getBlock(World world,int x,int y,int z)
{
return world.getBlock(x,y,z);
}
@Override
public int getX() {
return xCoord;
}
@Override
public int getY() {
return yCoord;
}
@Override
public int getZ() {
return zCoord;
}
public double getEventHorizon()
{
return Math.max((G2 * getRealMass()) / CC,0.5);
}
public double getBlockBreakRange()
{
return getMaxRange() / 2;
}
public double getMaxRange()
{
return Math.sqrt(getRealMass()*(G/0.01));
}
public double getAcceleration(double distanceSq)
{
return G * (getRealMass() / Math.max(distanceSq,0.0001f));
}
public double getRealMass() {
return getRealMassUnsuppressed() * suppression;
}
public double getRealMassUnsuppressed()
{
return Math.log1p(Math.max(mass,0) * STREHGTH_MULTIPLYER);
}
public float getBreakStrength(float distance,float maxRange)
{
return ((float)getRealMass() * 4 * suppression) * getDistanceFalloff(distance,maxRange);
}
public float getDistanceFalloff(float distance,float maxRange)
{
return (1 - (distance / maxRange));
}
public float getBreakStrength()
{
return (float)getRealMass() * 4 * suppression;
}
//endregion
//region Sub Classes
public static class PositionWrapper
{
int x,y,z;
public PositionWrapper(int x,int y,int z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
public static class BlockComparitor implements Comparator<PositionWrapper>
{
int posX,posY,posZ;
public BlockComparitor(int x,int y,int z)
{
posX = x;
posY = y;
posZ = z;
}
@Override
public int compare(PositionWrapper o1, PositionWrapper o2)
{
return Double.compare(MOMathHelper.distanceSqured(o1.x, o1.y, o1.z, posX, posY, posZ),MOMathHelper.distanceSqured(o2.x, o2.y, o2.z, posX, posY, posZ));
}
}
//endregion
}