2025-08-31 12:08:19 +02:00

337 lines
12 KiB
Java

package com.hbm.entity.projectile;
import java.util.List;
import com.hbm.handler.threading.PacketThreading;
import com.hbm.items.weapon.sedna.BulletConfig;
import com.hbm.packet.toclient.AuxParticlePacketNT;
import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
public class EntityBulletBeamBase extends Entity implements IEntityAdditionalSpawnData {
public EntityLivingBase thrower;
public BulletConfig config;
public float damage;
public double headingX;
public double headingY;
public double headingZ;
public double beamLength;
public EntityBulletBeamBase(World world) {
super(world);
this.ignoreFrustumCheck = true;
this.renderDistanceWeight = 10.0D;
this.setSize(0.5F, 0.5F);
this.isImmuneToFire = true;
}
public EntityLivingBase getThrower() { return this.thrower; }
public EntityBulletBeamBase(EntityLivingBase entity, BulletConfig config, float baseDamage) {
this(entity.worldObj);
this.thrower = entity;
this.setBulletConfig(config);
this.damage = baseDamage * this.config.damageMult;
}
public EntityBulletBeamBase(EntityLivingBase entity, BulletConfig config, float baseDamage, float angularInaccuracy, double sideOffset, double heightOffset, double frontOffset) {
this(entity.worldObj);
this.thrower = entity;
this.setBulletConfig(config);
this.damage = baseDamage * this.config.damageMult;
this.setLocationAndAngles(thrower.posX, thrower.posY + thrower.getEyeHeight(), thrower.posZ, thrower.rotationYaw + (float) rand.nextGaussian() * angularInaccuracy, thrower.rotationPitch + (float) rand.nextGaussian() * angularInaccuracy);
Vec3 offset = Vec3.createVectorHelper(sideOffset, heightOffset, frontOffset);
offset.rotateAroundX(-this.rotationPitch / 180F * (float) Math.PI);
offset.rotateAroundY(-this.rotationYaw / 180F * (float) Math.PI);
this.posX += offset.xCoord;
this.posY += offset.yCoord;
this.posZ += offset.zCoord;
this.setPosition(this.posX, this.posY, this.posZ);
this.headingX = (double) (-MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
this.headingZ = (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
this.headingY = (double) (-MathHelper.sin((this.rotationPitch) / 180.0F * (float) Math.PI));
double range = 250D;
this.headingX *= range;
this.headingY *= range;
this.headingZ *= range;
performHitscan();
}
public void setRotationsFromVector(Vec3 delta) {
this.rotationPitch = (float) (-Math.asin(delta.yCoord / delta.lengthVector()) * 180D / Math.PI);
this.rotationYaw = (float) (-Math.atan2(delta.xCoord, delta.zCoord) * 180D / Math.PI);
this.headingX = (double) (-MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
this.headingZ = (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
this.headingY = (double) (-MathHelper.sin((this.rotationPitch) / 180.0F * (float) Math.PI));
}
public void performHitscanExternal(double range) {
this.headingX *= range;
this.headingY *= range;
this.headingZ *= range;
performHitscan();
}
@Override
protected void entityInit() {
this.dataWatcher.addObject(3, Integer.valueOf(0));
}
public void setBulletConfig(BulletConfig config) {
this.config = config;
this.dataWatcher.updateObject(3, config.id);
}
public BulletConfig getBulletConfig() {
int id = this.dataWatcher.getWatchableObjectInt(3);
if(id < 0 || id > BulletConfig.configs.size()) return null;
return BulletConfig.configs.get(id);
}
@Override
public void onUpdate() {
if(config == null) config = this.getBulletConfig();
if(config == null){
this.setDead();
return;
}
if(config.onUpdate != null) config.onUpdate.accept(this);
super.onUpdate();
if(!worldObj.isRemote && this.ticksExisted > config.expires) this.setDead();
}
protected void performHitscan() {
Vec3 pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
Vec3 nextPos = Vec3.createVectorHelper(this.posX + this.headingX, this.posY + this.headingY, this.posZ + this.headingZ);
MovingObjectPosition mop = null;
if(!this.isSpectral()) mop = this.worldObj.func_147447_a(pos, nextPos, false, true, false);
pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
nextPos = Vec3.createVectorHelper(this.posX + this.headingX, this.posY + this.headingY, this.posZ + this.headingZ);
if(mop != null) {
nextPos = Vec3.createVectorHelper(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
}
if(!this.worldObj.isRemote && this.doesImpactEntities()) {
Entity hitEntity = null;
List<Entity> list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.headingX, this.headingY, this.headingZ).expand(1.0D, 1.0D, 1.0D));
double nearest = 0.0D;
MovingObjectPosition nonPenImpact = null;
MovingObjectPosition coinHit = null;
double closestCoin = 0;
EntityCoin hitCoin = null;
for(Entity entity : list) {
if(entity.isDead) continue;
if(entity instanceof EntityCoin) {
double hitbox = 0.3F;
AxisAlignedBB aabb = entity.boundingBox.expand(hitbox, hitbox, hitbox);
MovingObjectPosition hitMop = aabb.calculateIntercept(pos, nextPos);
if(hitMop != null) {
double dist = pos.distanceTo(hitMop.hitVec);
if(closestCoin == 0 || dist < closestCoin) {
closestCoin = dist;
hitCoin = (EntityCoin) entity;
coinHit = hitMop;
}
}
}
}
for(int j = 0; j < list.size(); ++j) {
Entity entity = (Entity) list.get(j);
if(entity.canBeCollidedWith() && entity != thrower && entity.isEntityAlive()) {
double hitbox = 0.3F;
AxisAlignedBB aabb = entity.boundingBox.expand(hitbox, hitbox, hitbox);
MovingObjectPosition hitMop = aabb.calculateIntercept(pos, nextPos);
if(hitMop != null) {
double dist = pos.distanceTo(hitMop.hitVec);
// if penetration is enabled, run impact for all intersecting entities
if(this.doesPenetrate()) {
if(hitCoin == null || dist < closestCoin) {
this.onImpact(new MovingObjectPosition(entity, hitMop.hitVec));
}
} else {
if(dist < nearest || nearest == 0.0D) {
hitEntity = entity;
nearest = dist;
nonPenImpact = hitMop;
}
}
}
}
}
// if not, only run it for the closest MOP
if(!this.doesPenetrate() && hitEntity != null) {
mop = new MovingObjectPosition(hitEntity, nonPenImpact.hitVec);
}
if(hitCoin != null) {
Vec3 vec = Vec3.createVectorHelper(coinHit.hitVec.xCoord - posX, coinHit.hitVec.yCoord - posY, coinHit.hitVec.zCoord - posZ);
this.beamLength = vec.lengthVector();
double range = 50;
List<Entity> targets = worldObj.getEntitiesWithinAABB(Entity.class, AxisAlignedBB.getBoundingBox(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord).expand(range, range, range));
Entity nearestCoin = null;
Entity nearestPlayer = null;
Entity nearestMob = null;
Entity nearestOther = null;
double coinDist = 0;
double playerDist = 0;
double mobDist = 0;
double otherDist = 0;
hitCoin.setDead();
// well i mean we could just uuse a single var for all variants and then overwrite stuff
// when we run into things with higher priority. however i can't be assed fuck off
for(Entity entity : targets) {
if(entity == this.getThrower()) continue;
if(entity.isDead) continue;
double dist = entity.getDistanceToEntity(hitCoin);
if(dist > range) continue;
if(entity instanceof EntityCoin) {
if(coinDist == 0 || dist < coinDist) {
coinDist = dist;
nearestCoin = entity;
}
} else if(entity instanceof EntityPlayer) {
if(playerDist == 0 || dist < playerDist) {
playerDist = dist;
nearestPlayer = entity;
}
} else if(entity instanceof EntityMob) {
if(mobDist == 0 || dist < mobDist) {
mobDist = dist;
nearestMob = entity;
}
} else if(entity instanceof EntityLivingBase) {
if(otherDist == 0 || dist < otherDist) {
otherDist = dist;
nearestOther = entity;
}
}
}
// ternary of shame
Entity target = nearestCoin != null ? nearestCoin :
nearestPlayer != null ? nearestPlayer :
nearestMob != null ? nearestMob :
nearestOther != null ? nearestOther : null;
if(target != null) {
EntityBulletBeamBase newBeam = new EntityBulletBeamBase(hitCoin.getThrower() != null ? hitCoin.getThrower() : this.thrower, this.config, this.damage * 1.25F);
newBeam.setPosition(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord);
Vec3 delta = Vec3.createVectorHelper(target.posX - newBeam.posX, (target.posY + target.height / 2D) - newBeam.posY, target.posZ - newBeam.posZ);
newBeam.setRotationsFromVector(delta);
newBeam.performHitscanExternal(delta.lengthVector());
worldObj.spawnEntityInWorld(newBeam);
} else {
EntityBulletBeamBase newBeam = new EntityBulletBeamBase(hitCoin.getThrower() != null ? hitCoin.getThrower() : this.thrower, this.config, this.damage * 1.25F);
newBeam.setPosition(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord);
newBeam.setRotationsFromVector(Vec3.createVectorHelper(rand.nextGaussian() * 0.5, -1, rand.nextGaussian() * 0.5));
newBeam.performHitscanExternal(100);
worldObj.spawnEntityInWorld(newBeam);
}
NBTTagCompound data = new NBTTagCompound();
data.setString("type", "vanillaExt");
data.setString("mode", "largeexplode");
data.setFloat("size", 1.5F);
data.setByte("count", (byte)1);
PacketThreading.createAllAroundThreadedPacket(new AuxParticlePacketNT(data, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord), new TargetPoint(worldObj.provider.dimensionId, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord, 100));
return;
}
}
if(mop != null) {
if(mop.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && this.worldObj.getBlock(mop.blockX, mop.blockY, mop.blockZ) == Blocks.portal) {
this.setInPortal();
} else {
this.onImpact(mop);
}
Vec3 vec = Vec3.createVectorHelper(mop.hitVec.xCoord - posX, mop.hitVec.yCoord - posY, mop.hitVec.zCoord - posZ);
this.beamLength = vec.lengthVector();
} else {
Vec3 vec = Vec3.createVectorHelper(nextPos.xCoord - posX, nextPos.yCoord - posY, nextPos.zCoord - posZ);
this.beamLength = vec.lengthVector();
}
}
protected void onImpact(MovingObjectPosition mop) {
if(!worldObj.isRemote) {
if(this.config.onImpactBeam != null) this.config.onImpactBeam.accept(this, mop);
}
}
public boolean doesImpactEntities() { return this.config.impactsEntities; }
public boolean doesPenetrate() { return this.config.doesPenetrate; }
public boolean isSpectral() { return this.config.isSpectral; }
@Override @SideOnly(Side.CLIENT) public float getShadowSize() { return 0.0F; }
@Override protected void writeEntityToNBT(NBTTagCompound nbt) { }
@Override public boolean writeToNBTOptional(NBTTagCompound nbt) { return false; }
@Override public void readEntityFromNBT(NBTTagCompound nbt) { this.setDead(); }
@Override public void writeSpawnData(ByteBuf buf) {
buf.writeDouble(beamLength);
buf.writeFloat(rotationYaw);
buf.writeFloat(rotationPitch);
}
@Override public void readSpawnData(ByteBuf buf) {
this.beamLength = buf.readDouble();
this.rotationYaw = buf.readFloat();
this.rotationPitch = buf.readFloat();
}
@Override @SideOnly(Side.CLIENT) public boolean canRenderOnFire() { return false; }
}