This repository has been archived on 2023-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
EnergonRelics/src/main/java/com/thebrokenrail/energonrelics/block/entity/DefensiveLaserBlockEntity.java

210 lines
7.5 KiB
Java

package com.thebrokenrail.energonrelics.block.entity;
import com.thebrokenrail.energonrelics.Config;
import com.thebrokenrail.energonrelics.EnergonRelics;
import com.thebrokenrail.energonrelics.block.DefensiveLaserBlock;
import com.thebrokenrail.energonrelics.energy.core.EnergyReceiverBlockEntity;
import com.thebrokenrail.energonrelics.energy.core.util.Action;
import com.thebrokenrail.energonrelics.util.MissingCaseException;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity {
private static final float MAX_PITCH = 0;
private static final float MIN_PITCH = -70;
private static final float ROTATION_INCREMENT = 2;
private static final int COUNTDOWN = 6;
public final Rotation rotation = new Rotation(0, 0, "Rotation");
private LivingEntity target;
private int countdown = 0;
private final Predicate<LivingEntity> predicate = entity -> {
if (entity.getBlockPos().isWithinDistance(getPos(), Config.DEFENSIVE_LASER_RANGE)) {
Vec3d start = getPosVec().add(rotation.getRayVector());
Vec3d end = entity.getPos();
HitResult result = entity.getEntityWorld().rayTrace(new RayTraceContext(start, end, RayTraceContext.ShapeType.COLLIDER, RayTraceContext.FluidHandling.ANY, entity));
return result.getType() == HitResult.Type.MISS;
} else {
return false;
}
};
private Vec3d getPosVec() {
return new Vec3d(getPos().getX() + 0.5d, getPos().getY() + 0.5d, getPos().getZ() + 0.5d);
}
@Override
public BlockState getCachedState() {
if (hasWorld()) {
return super.getCachedState();
} else {
return EnergonRelics.DEFENSIVE_LASER_BLOCK.getDefaultState();
}
}
public class Rotation {
private float yaw = 0;
private float pitch = 0;
private final String key;
private Rotation(float yaw, float pitch, String key) {
setRaw(yaw, pitch);
this.key = key;
}
private void fromTag(CompoundTag tag) {
CompoundTag rotation = tag.getCompound(key);
setRaw(rotation.getInt("Yaw"), rotation.getInt("Pitch"));
}
private void toTag(CompoundTag tag) {
CompoundTag rotation = new CompoundTag();
rotation.putFloat("Yaw", yaw);
rotation.putFloat("Pitch", pitch);
tag.put(key, rotation);
}
private void setRaw(float yaw, float pitch) {
setYaw(yaw);
setPitch(pitch);
}
private void setYaw(float yaw) {
this.yaw = yaw % 360;
}
private void setPitch(float pitch) {
this.pitch = pitch % 360;
}
public float getYaw() {
return yaw;
}
public float getPitch() {
return pitch;
}
private void change(float diffYaw, float diffPitch) {
setRaw(yaw + diffYaw, pitch + diffPitch);
markDirty();
}
private Vec3d getRayVector() {
float pitch = this.pitch * (float) DEG2RAD;
float yaw = this.yaw * (float) DEG2RAD;
float cosYaw = MathHelper.cos(yaw);
float sinYaw = MathHelper.sin(yaw);
float cosPitch = MathHelper.cos(pitch);
float sinPitch = MathHelper.sin(pitch);
return new Vec3d(sinYaw * cosPitch, -sinPitch, cosYaw * cosPitch);
}
private float getAngleChange(float from, float to) {
float diff = MathHelper.subtractAngles(from, to);
return MathHelper.clamp(diff, -ROTATION_INCREMENT, ROTATION_INCREMENT);
}
private void target(float targetYaw, float targetPitch) {
float yawChange = getAngleChange(yaw, targetYaw);
float pitchChange = getAngleChange(pitch, targetPitch);
change(yawChange, pitchChange);
}
}
public DefensiveLaserBlockEntity(BlockEntityType<?> type) {
super(type);
}
public static final double DEG2RAD = Math.PI / 180d;
private static final double RAD2DEG = 180d / Math.PI;
private float getTargetPitch(double x, double y, double z) {
Vec3d pos = getPosVec();
double diffX = x - pos.getX();
double diffY = y - pos.getY();
double diffZ = z - pos.getZ();
double g = MathHelper.sqrt(diffX * diffX + diffZ * diffZ);
return (float) -(MathHelper.atan2(diffY, g) * RAD2DEG);
}
private float getTargetYaw(double x, double z) {
Vec3d pos = getPosVec();
double diffX = x - pos.getX();
double diffZ = z - pos.getZ();
return (float) (MathHelper.atan2(diffZ, diffX) * RAD2DEG) - 90.0F;
}
@Override
protected void tickEnergy() {
assert getWorld() != null;
Vec3d vec = rotation.getRayVector().add(getPosVec());
((ServerWorld) getWorld()).spawnParticles(ParticleTypes.END_ROD, vec.getX(), vec.getY(), vec.getZ(), 1, 0, 0, 0, 0);
addAction(Action.createBlockStatePropertyAction(Config.DEFENSIVE_LASER_IDLE_ENERGY_REQUIRED, DefensiveLaserBlock.POWERED, true, false));
if (getCachedState().get(DefensiveLaserBlock.POWERED)) {
if (countdown > 0) {
countdown--;
}
if (countdown == 1) {
// Fire!
target = null;
} else if (countdown < 1) {
if (target == null) {
List<LivingEntity> entities = getWorld().getEntities(LivingEntity.class, new Box(getPos()).expand(Config.DEFENSIVE_LASER_RANGE), predicate);
if (entities.size() > 0) {
Collections.shuffle(entities);
target = entities.get(0);
}
} else {
if (predicate.test(target)) {
Optional<Vec3d> optional = target.getBoundingBox().rayTrace(getPosVec(), getPosVec().add(rotation.getRayVector().multiply(Config.DEFENSIVE_LASER_RANGE)));
if (optional.isPresent()) {
countdown = COUNTDOWN;
} else {
Vec3d targetPos = target.getPos();
float targetYaw = getTargetYaw(targetPos.getX(), targetPos.getZ());
float targetPitch = getTargetPitch(targetPos.getX(), targetPos.getY(), targetPos.getZ());
rotation.target(targetYaw, targetPitch);
}
} else {
target = null;
}
}
}
}
}
@Override
public CompoundTag toTag(CompoundTag tag) {
super.toTag(tag);
rotation.toTag(tag);
tag.putInt("Countdown", countdown);
return tag;
}
@Override
public void fromTag(BlockState state, CompoundTag tag) {
super.fromTag(state, tag);
rotation.fromTag(tag);
countdown = tag.getInt("Countdown");
}
}