superb-warfare/src/main/java/com/atsuishio/superbwarfare/entity/projectile/AbstractLaserEntity.java
2024-12-01 23:25:05 +08:00

274 lines
9.2 KiB
Java

package com.atsuishio.superbwarfare.entity.projectile;
import com.atsuishio.superbwarfare.client.AnimationTicker;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.TraceableEntity;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.phys.*;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* Code based on @BobMowzie's MowziesMobs, @EEEAB's EEEABsMobs and @Mercurows's DreamaticVoyage
*/
public abstract class AbstractLaserEntity extends Entity implements TraceableEntity {
public LivingEntity caster;
public float yaw, pitch;
public float preYaw, prePitch;
public double endPosX, endPosY, endPosZ;
public double collidePosX, collidePosY, collidePosZ;
public double prevCollidePosX, prevCollidePosY, prevCollidePosZ;
public Direction blockSide = null;
public boolean on = true;
public AnimationTicker ticker = new AnimationTicker(3);
private static final EntityDataAccessor<Integer> DATA_CASTER_ID = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Float> DATA_YAW = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Float> DATA_PITCH = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.FLOAT);
private static final EntityDataAccessor<Integer> DATA_DURATION = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<Integer> DATA_COUNT_DOWN = SynchedEntityData.defineId(AbstractLaserEntity.class, EntityDataSerializers.INT);
public AbstractLaserEntity(EntityType<?> type, Level level, int countDown) {
super(type, level);
this.setCountDown(countDown);
this.noCulling = true;
}
@Override
public void tick() {
super.tick();
this.prevCollidePosX = this.collidePosX;
this.prevCollidePosY = this.collidePosY;
this.prevCollidePosZ = this.collidePosZ;
this.preYaw = this.yaw;
this.prePitch = this.pitch;
this.yaw = this.getYaw();
this.pitch = this.getPitch();
this.xo = this.getX();
this.yo = this.getY();
this.zo = this.getZ();
if (this.tickCount == 1 && this.level().isClientSide) {
this.caster = (LivingEntity) this.level().getEntity(getCasterId());
}
this.beamTick();
if ((!this.on && this.ticker.isStopped()) || (this.caster != null && !caster.isAlive())) {
this.discard();
}
this.ticker.changeTimer(this.on && this.isAccumulating());
if (this.tickCount - this.getCountDown() > this.getDuration()) {
this.on = false;
}
}
@Override
public Packet<ClientGamePacketListener> getAddEntityPacket() {
return NetworkHooks.getEntitySpawningPacket(this);
}
@Override
protected void readAdditionalSaveData(CompoundTag pCompound) {
}
@Override
protected void addAdditionalSaveData(CompoundTag pCompound) {
}
protected void beamTick() {
}
@Nullable
public LivingEntity getOwner() {
return caster;
}
@Override
public boolean isPickable() {
return super.isPickable();
}
@Override
public void push(Entity entityIn) {
}
@Override
public PushReaction getPistonPushReaction() {
return PushReaction.IGNORE;
}
@Override
protected void defineSynchedData() {
this.entityData.define(DATA_CASTER_ID, -1);
this.entityData.define(DATA_YAW, 0F);
this.entityData.define(DATA_PITCH, 0F);
this.entityData.define(DATA_DURATION, 0);
this.entityData.define(DATA_COUNT_DOWN, 0);
}
public void setCasterId(int id) {
this.entityData.set(DATA_CASTER_ID, id);
}
public int getCasterId() {
return this.entityData.get(DATA_CASTER_ID);
}
public boolean isAccumulating() {
return this.tickCount > this.getCountDown();
}
public float getYaw() {
return getEntityData().get(DATA_YAW);
}
public void setYaw(float rotAngle) {
getEntityData().set(DATA_YAW, rotAngle);
}
public float getPitch() {
return getEntityData().get(DATA_PITCH);
}
public void setPitch(float rotAngle) {
getEntityData().set(DATA_PITCH, rotAngle);
}
public int getDuration() {
return getEntityData().get(DATA_DURATION);
}
public void setDuration(int duration) {
getEntityData().set(DATA_DURATION, duration);
}
public int getCountDown() {
return getEntityData().get(DATA_COUNT_DOWN);
}
public void setCountDown(int countDown) {
getEntityData().set(DATA_COUNT_DOWN, countDown);
}
protected void calculateEndPos(double radius) {
if (level().isClientSide()) {
endPosX = getX() + radius * Math.cos(yaw) * Math.cos(pitch);
endPosZ = getZ() + radius * Math.sin(yaw) * Math.cos(pitch);
endPosY = getY() + radius * Math.sin(pitch);
} else {
endPosX = getX() + radius * Math.cos(getYaw()) * Math.cos(getPitch());
endPosZ = getZ() + radius * Math.sin(getYaw()) * Math.cos(getPitch());
endPosY = getY() + radius * Math.sin(getPitch());
}
}
public CustomHitResult raytraceEntities(Level world, Vec3 from, Vec3 to) {
CustomHitResult result = new CustomHitResult();
result.setBlockHit(world.clip(new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)));
if (result.getBlockHit() != null) {
Vec3 hitVec = result.getBlockHit().getLocation();
collidePosX = hitVec.x;
collidePosY = hitVec.y;
collidePosZ = hitVec.z;
blockSide = result.getBlockHit().getDirection();
} else {
collidePosX = endPosX;
collidePosY = endPosY;
collidePosZ = endPosZ;
blockSide = null;
}
List<LivingEntity> entities = world.getEntitiesOfClass(LivingEntity.class, new AABB(Math.min(getX(), collidePosX), Math.min(getY(), collidePosY), Math.min(getZ(), collidePosZ), Math.max(getX(), collidePosX), Math.max(getY(), collidePosY), Math.max(getZ(), collidePosZ)).inflate(1, 1, 1));
for (LivingEntity entity : entities) {
if (entity == this.caster) {
continue;
}
float pad = entity.getPickRadius() + getBaseScale();
AABB aabb = entity.getBoundingBox().inflate(pad, pad, pad);
Optional<Vec3> hit = aabb.clip(from, to);
if (aabb.contains(from)) {
result.addEntityHit(entity);
} else if (hit.isPresent()) {
result.addEntityHit(entity);
}
}
return result;
}
@Override
public boolean isAttackable() {
return false;
}
@Override
public boolean displayFireAnimation() {
return false;
}
protected void onHit(HitResult hitResult) {
HitResult.Type hitresult$type = hitResult.getType();
if (hitresult$type == HitResult.Type.ENTITY) {
this.onHitEntity((EntityHitResult) hitResult);
this.level().gameEvent(GameEvent.PROJECTILE_LAND, hitResult.getLocation(), GameEvent.Context.of(this, null));
} else if (hitresult$type == HitResult.Type.BLOCK) {
BlockHitResult blockhitresult = (BlockHitResult) hitResult;
this.onHitBlock(blockhitresult);
BlockPos blockpos = blockhitresult.getBlockPos();
this.level().gameEvent(GameEvent.PROJECTILE_LAND, blockpos, GameEvent.Context.of(this, this.level().getBlockState(blockpos)));
}
}
protected void onHitEntity(EntityHitResult result) {
}
protected void onHitBlock(BlockHitResult result) {
}
protected float getBaseScale() {
return 0.5F;
}
public static class CustomHitResult {
private BlockHitResult blockHit;
private final List<LivingEntity> entities = new ArrayList<>();
public BlockHitResult getBlockHit() {
return blockHit;
}
public List<LivingEntity> getEntities() {
return entities;
}
public void setBlockHit(HitResult rayTraceResult) {
if (rayTraceResult.getType() == HitResult.Type.BLOCK)
this.blockHit = (BlockHitResult) rayTraceResult;
}
public void addEntityHit(LivingEntity entity) {
entities.add(entity);
}
}
}