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

275 lines
11 KiB
Java
Raw Normal View History

2020-07-15 22:44:49 +00:00
package com.thebrokenrail.energonrelics.block.entity;
2020-08-04 17:06:11 +00:00
import com.thebrokenrail.energonrelics.api.block.entity.core.EnergyReceiverBlockEntity;
import com.thebrokenrail.energonrelics.api.energy.Action;
import com.thebrokenrail.energonrelics.config.HardcodedConfig;
2020-07-15 22:44:49 +00:00
import com.thebrokenrail.energonrelics.EnergonRelics;
import com.thebrokenrail.energonrelics.block.DefensiveLaserBlock;
2020-07-17 20:20:05 +00:00
import com.thebrokenrail.energonrelics.mixin.DamageSourceAccessor;
2020-07-15 22:44:49 +00:00
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntityType;
2020-07-17 00:13:45 +00:00
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
2020-07-15 22:44:49 +00:00
import net.minecraft.entity.LivingEntity;
2020-07-17 20:20:05 +00:00
import net.minecraft.entity.damage.DamageSource;
2020-07-17 00:13:45 +00:00
import net.minecraft.entity.player.PlayerEntity;
2020-07-15 22:44:49 +00:00
import net.minecraft.nbt.CompoundTag;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.hit.HitResult;
2020-07-17 01:42:15 +00:00
import net.minecraft.util.math.BlockPos;
2020-07-15 22:44:49 +00:00
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RayTraceContext;
2020-07-17 01:42:15 +00:00
import net.minecraft.world.World;
2020-07-17 00:13:45 +00:00
import net.minecraft.world.explosion.Explosion;
2020-07-15 22:44:49 +00:00
2020-07-17 00:13:45 +00:00
import java.util.Comparator;
2020-07-15 22:44:49 +00:00
import java.util.List;
2020-07-17 00:13:45 +00:00
import java.util.Objects;
2020-07-15 22:44:49 +00:00
import java.util.Optional;
import java.util.function.Predicate;
public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity {
2020-07-17 00:13:45 +00:00
private static final float ROTATION_INCREMENT = 4;
2020-07-15 22:44:49 +00:00
2020-07-22 01:23:33 +00:00
public final Rotation rotation = new Rotation();
2020-07-15 22:44:49 +00:00
2020-07-17 01:42:15 +00:00
private static Vec3d getPosVec(BlockPos pos) {
return new Vec3d(pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d);
}
2020-07-26 03:13:15 +00:00
public Vec3d getPosVec() {
2020-07-17 01:42:15 +00:00
return getPosVec(getPos());
2020-07-15 22:44:49 +00:00
}
@Override
public BlockState getCachedState() {
if (hasWorld()) {
return super.getCachedState();
} else {
return EnergonRelics.DEFENSIVE_LASER_BLOCK.getDefaultState();
}
}
2020-07-28 20:38:21 +00:00
public static class Rotation {
2020-07-15 22:44:49 +00:00
private float yaw = 0;
private float pitch = 0;
2020-07-22 01:23:33 +00:00
private static final String KEY = "Rotation";
2020-07-15 22:44:49 +00:00
2020-07-22 01:23:33 +00:00
private Rotation() {
setRaw(0f, 0f);
2020-07-15 22:44:49 +00:00
}
private void fromTag(CompoundTag tag) {
2020-07-22 01:23:33 +00:00
CompoundTag rotation = tag.getCompound(KEY);
2020-07-15 22:44:49 +00:00
setRaw(rotation.getInt("Yaw"), rotation.getInt("Pitch"));
}
private void toTag(CompoundTag tag) {
CompoundTag rotation = new CompoundTag();
rotation.putFloat("Yaw", yaw);
rotation.putFloat("Pitch", pitch);
2020-07-22 01:23:33 +00:00
tag.put(KEY, rotation);
2020-07-15 22:44:49 +00:00
}
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) {
2020-07-16 18:50:18 +00:00
this.pitch = pitch % 360;
2020-07-15 22:44:49 +00:00
}
2020-07-16 18:50:18 +00:00
public float getYaw() {
return yaw;
2020-07-15 22:44:49 +00:00
}
2020-07-16 18:50:18 +00:00
public float getPitch() {
return pitch;
2020-07-15 22:44:49 +00:00
}
2020-07-16 18:50:18 +00:00
private void change(float diffYaw, float diffPitch) {
setRaw(yaw + diffYaw, pitch + diffPitch);
2020-07-15 22:44:49 +00:00
}
2020-07-26 03:13:15 +00:00
public Vec3d getRayVector() {
2020-07-17 00:13:45 +00:00
return DefensiveLaserBlockEntity.getRayVector(yaw, pitch);
2020-07-15 22:44:49 +00:00
}
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) {
2020-07-16 18:50:18 +00:00
float yawChange = getAngleChange(yaw, targetYaw);
float pitchChange = getAngleChange(pitch, targetPitch);
2020-07-15 22:44:49 +00:00
change(yawChange, pitchChange);
}
}
2020-07-17 00:13:45 +00:00
private static Vec3d getRayVector(float yaw, float pitch) {
float pitchRad = pitch * (float) DEG2RAD;
float yawRad = yaw * (float) DEG2RAD;
float cosYaw = MathHelper.cos(yawRad);
float sinYaw = MathHelper.sin(yawRad);
float cosPitch = MathHelper.cos(pitchRad);
float sinPitch = MathHelper.sin(pitchRad);
return new Vec3d(sinYaw * cosPitch, -sinPitch, cosYaw * cosPitch);
}
2020-07-15 22:44:49 +00:00
public DefensiveLaserBlockEntity(BlockEntityType<?> type) {
super(type);
}
public static final double DEG2RAD = Math.PI / 180d;
private static final double RAD2DEG = 180d / Math.PI;
2020-07-17 00:13:45 +00:00
private float getTargetPitch(Vec3d targetPos) {
2020-07-15 22:44:49 +00:00
Vec3d pos = getPosVec();
2020-07-17 00:13:45 +00:00
double diffX = targetPos.getX() - pos.getX();
double diffY = targetPos.getY() - pos.getY();
double diffZ = targetPos.getZ() - pos.getZ();
2020-07-15 22:44:49 +00:00
double g = MathHelper.sqrt(diffX * diffX + diffZ * diffZ);
return (float) -(MathHelper.atan2(diffY, g) * RAD2DEG);
}
2020-07-17 00:13:45 +00:00
private float getTargetYaw(Vec3d targetPos) {
2020-07-15 22:44:49 +00:00
Vec3d pos = getPosVec();
2020-07-17 00:13:45 +00:00
double diffX = targetPos.getX() - pos.getX();
double diffZ = targetPos.getZ() - pos.getZ();
2020-07-22 22:57:51 +00:00
return -((float) (MathHelper.atan2(diffZ, diffX) * RAD2DEG) - 90f);
2020-07-17 00:13:45 +00:00
}
private static final int COUNTDOWN = 28;
private LivingEntity target;
private int countdown = 0;
private Predicate<LivingEntity> getTargetPredicate(boolean useCurrentRotation) {
return entity -> {
if (entity.isAlive() && (!(entity instanceof PlayerEntity) || !((PlayerEntity) entity).isCreative()) && !entity.isInvisible() && entity.getPos().distanceTo(getPosVec()) <= HardcodedConfig.DEFENSIVE_LASER_RANGE) {
2020-07-17 00:13:45 +00:00
Vec3d entityPos = entity.getPos();
Vec3d start;
if (useCurrentRotation) {
start = rotation.getRayVector().add(getPosVec());
} else {
start = getRayVector(getTargetYaw(entityPos), getTargetPitch(entityPos)).add(getPosVec());
}
HitResult result = entity.getEntityWorld().rayTrace(new RayTraceContext(start, entityPos, RayTraceContext.ShapeType.COLLIDER, RayTraceContext.FluidHandling.ANY, getDummyEntity()));
return result.getType() == HitResult.Type.MISS;
} else {
return false;
}
};
}
private List<LivingEntity> getEntities(Predicate<LivingEntity> predicate) {
return Objects.requireNonNull(getWorld()).getEntitiesByClass(LivingEntity.class, new Box(getPos()).expand(HardcodedConfig.DEFENSIVE_LASER_RANGE), predicate);
2020-07-17 00:13:45 +00:00
}
private Entity getDummyEntity() {
Vec3d posVec = getPosVec();
return new ItemEntity(getWorld(), posVec.getX(), posVec.getY(), posVec.getZ());
2020-07-15 22:44:49 +00:00
}
2020-07-17 20:20:05 +00:00
private static final DamageSource DAMAGE_SOURCE = DamageSourceAccessor.createDamageSource(EnergonRelics.NAMESPACE + ".defensive_laser").setScaledWithDifficulty().setExplosive();
2020-07-17 01:42:15 +00:00
private void fire(World world, BlockPos pos) {
List<LivingEntity> entities = getEntities(entity -> true);
Vec3d posVec = getPosVec(pos);
Vec3d collision = null;
for (LivingEntity entity : entities) {
Optional<Vec3d> optional = entity.getBoundingBox().rayTrace(posVec, posVec.add(rotation.getRayVector().multiply(HardcodedConfig.DEFENSIVE_LASER_RANGE)));
2020-07-17 01:42:15 +00:00
if (optional.isPresent()) {
Vec3d vec = optional.get();
if (collision == null || vec.distanceTo(posVec) < collision.distanceTo(posVec)) {
collision = optional.get();
}
}
}
Vec3d rotationVec = rotation.getRayVector();
Vec3d start = rotationVec.add(posVec);
Vec3d end = rotationVec.multiply(HardcodedConfig.DEFENSIVE_LASER_RANGE).add(posVec);
2020-07-17 01:42:15 +00:00
HitResult result = world.rayTrace(new RayTraceContext(start, end, RayTraceContext.ShapeType.COLLIDER, RayTraceContext.FluidHandling.ANY, getDummyEntity()));
if (result.getType() != HitResult.Type.MISS && (collision == null || result.getPos().distanceTo(posVec) < collision.distanceTo(posVec))) {
collision = result.getPos();
}
if (collision != null) {
2020-07-17 20:20:05 +00:00
world.createExplosion(null, DAMAGE_SOURCE, null, collision.getX(), collision.getY(), collision.getZ(), 2f, false, Explosion.DestructionType.NONE);
2020-07-17 01:42:15 +00:00
2020-07-17 20:20:05 +00:00
double distance = posVec.distanceTo(collision);
2020-07-17 01:42:15 +00:00
2020-07-17 20:20:05 +00:00
double multiplier = 4d;
distance = distance * multiplier;
for (int i = 0; i < distance; i++) {
Vec3d vec = rotationVec.multiply(i / multiplier).add(posVec);
((ServerWorld) world).spawnParticles(ParticleTypes.END_ROD, vec.getX(), vec.getY(), vec.getZ(), 1, 0, 0, 0, 0.4f);
}
2020-07-17 01:42:15 +00:00
}
}
2020-07-15 22:44:49 +00:00
@Override
2020-07-27 18:06:46 +00:00
protected void energyTick() {
2020-07-15 22:44:49 +00:00
assert getWorld() != null;
2020-07-24 18:02:42 +00:00
addAction(Action.createBlockStatePropertyAction(HardcodedConfig.DEFENSIVE_LASER_IDLE_ENERGY_REQUIRED, DefensiveLaserBlock.POWERED, true, false));
2020-07-15 22:44:49 +00:00
if (getCachedState().get(DefensiveLaserBlock.POWERED)) {
if (countdown > 0) {
countdown--;
}
if (countdown == 1) {
2020-07-26 03:13:15 +00:00
addAction(new Action(HardcodedConfig.DEFENSIVE_LASER_FIRE_ENERGY_REQUIRED, (world, pos, state) -> fire(world, pos), (world, pos, state) -> {}));
2020-07-15 22:44:49 +00:00
target = null;
2020-07-26 03:13:15 +00:00
} else if (countdown < 1) {
2020-07-15 22:44:49 +00:00
if (target == null) {
2020-07-17 00:13:45 +00:00
List<LivingEntity> entities = getEntities(getTargetPredicate(false));
2020-07-15 22:44:49 +00:00
if (entities.size() > 0) {
2020-07-17 00:13:45 +00:00
Vec3d posVec = getPosVec();
entities.sort(Comparator.comparingDouble(entity -> entity.getPos().distanceTo(posVec)));
2020-07-15 22:44:49 +00:00
target = entities.get(0);
}
} else {
2020-07-17 00:13:45 +00:00
if (getTargetPredicate(false).test(target)) {
Optional<Vec3d> optional = target.getBoundingBox().rayTrace(getPosVec(), getPosVec().add(rotation.getRayVector().multiply(HardcodedConfig.DEFENSIVE_LASER_RANGE)));
2020-07-17 00:13:45 +00:00
if (optional.isPresent() && getTargetPredicate(true).test(target)) {
2020-07-15 22:44:49 +00:00
countdown = COUNTDOWN;
} else {
Vec3d targetPos = target.getPos();
2020-07-17 00:13:45 +00:00
float targetYaw = getTargetYaw(targetPos);
float targetPitch = getTargetPitch(targetPos);
2020-07-15 22:44:49 +00:00
rotation.target(targetYaw, targetPitch);
}
} else {
target = null;
}
}
}
2020-07-28 20:38:21 +00:00
markDirty();
2020-07-15 22:44:49 +00:00
}
}
@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");
}
}