diff --git a/src/main/java/com/thebrokenrail/energonrelics/block/DefensiveLaserBlock.java b/src/main/java/com/thebrokenrail/energonrelics/block/DefensiveLaserBlock.java index c1554a8..e0d7f54 100644 --- a/src/main/java/com/thebrokenrail/energonrelics/block/DefensiveLaserBlock.java +++ b/src/main/java/com/thebrokenrail/energonrelics/block/DefensiveLaserBlock.java @@ -9,11 +9,11 @@ import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Material; +import net.minecraft.block.MaterialColor; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; import net.minecraft.client.render.block.entity.BlockEntityRenderer; -import net.minecraft.sound.BlockSoundGroup; import net.minecraft.state.StateManager; import net.minecraft.state.property.BooleanProperty; import net.minecraft.state.property.Properties; @@ -26,7 +26,7 @@ public class DefensiveLaserBlock extends EnergyProviderBlock { public static final BooleanProperty POWERED = Properties.POWERED; public DefensiveLaserBlock() { - super(FabricBlockSettings.of(Material.GLASS).sounds(BlockSoundGroup.GLASS).nonOpaque().strength(0.3f).allowsSpawning((state, world, pos, type) -> false).solidBlock((state, world, pos) -> false).suffocates((state, world, pos) -> false)); + super(FabricBlockSettings.of(Material.GLASS, MaterialColor.BLACK).requiresTool().strength(50.0F, 1200.0F).nonOpaque().allowsSpawning((state, world, pos, type) -> false).solidBlock((state, world, pos) -> false).suffocates((state, world, pos) -> false)); setDefaultState(getDefaultState().with(POWERED, false)); } diff --git a/src/main/java/com/thebrokenrail/energonrelics/block/entity/DefensiveLaserBlockEntity.java b/src/main/java/com/thebrokenrail/energonrelics/block/entity/DefensiveLaserBlockEntity.java index 41bce9f..1dc1afb 100644 --- a/src/main/java/com/thebrokenrail/energonrelics/block/entity/DefensiveLaserBlockEntity.java +++ b/src/main/java/com/thebrokenrail/energonrelics/block/entity/DefensiveLaserBlockEntity.java @@ -5,47 +5,32 @@ 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.Entity; +import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; 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 net.minecraft.world.explosion.Explosion; -import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.Objects; 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; + private static final float ROTATION_INCREMENT = 4; public final Rotation rotation = new Rotation(0, 0, "Rotation"); - private LivingEntity target; - private int countdown = 0; - - private final Predicate 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); @@ -109,13 +94,7 @@ public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity { } 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); + return DefensiveLaserBlockEntity.getRayVector(yaw, pitch); } private float getAngleChange(float from, float to) { @@ -130,6 +109,16 @@ public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity { } } + 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); + } + public DefensiveLaserBlockEntity(BlockEntityType type) { super(type); } @@ -137,51 +126,124 @@ public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity { 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) { + private float getTargetPitch(Vec3d targetPos) { Vec3d pos = getPosVec(); - double diffX = x - pos.getX(); - double diffY = y - pos.getY(); - double diffZ = z - pos.getZ(); + double diffX = targetPos.getX() - pos.getX(); + double diffY = targetPos.getY() - pos.getY(); + double diffZ = targetPos.getZ() - pos.getZ(); double g = MathHelper.sqrt(diffX * diffX + diffZ * diffZ); return (float) -(MathHelper.atan2(diffY, g) * RAD2DEG); } - private float getTargetYaw(double x, double z) { + private float getTargetYaw(Vec3d targetPos) { Vec3d pos = getPosVec(); - double diffX = x - pos.getX(); - double diffZ = z - pos.getZ(); - return (float) (MathHelper.atan2(diffZ, diffX) * RAD2DEG) - 90.0F; + double diffX = targetPos.getX() - pos.getX(); + double diffZ = targetPos.getZ() - pos.getZ(); + return -((float) (MathHelper.atan2(diffZ, diffX) * RAD2DEG) - 90.0F); + } + + private static final int COUNTDOWN = 28; + + private LivingEntity target; + private int countdown = 0; + + private boolean firing = false; + + private Predicate getTargetPredicate(boolean useCurrentRotation) { + return entity -> { + if (entity.isAlive() && (!(entity instanceof PlayerEntity) || !((PlayerEntity) entity).isCreative()) && !entity.isInvisible() && entity.getPos().distanceTo(getPosVec()) <= Config.DEFENSIVE_LASER_RANGE) { + 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 getEntities(Predicate predicate) { + return Objects.requireNonNull(getWorld()).getEntities(LivingEntity.class, new Box(getPos()).expand(Config.DEFENSIVE_LASER_RANGE), predicate); + } + + private Entity getDummyEntity() { + Vec3d posVec = getPosVec(); + return new ItemEntity(getWorld(), posVec.getX(), posVec.getY(), posVec.getZ()); } @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! + addAction(new Action(Config.DEFENSIVE_LASER_FIRE_ENERGY_REQUIRED, (world, pos, state) -> { + firing = false; + + List entities = getEntities(entity -> true); + Vec3d posVec = getPosVec(); + Vec3d collision = null; + for (LivingEntity entity : entities) { + Optional optional = entity.getBoundingBox().rayTrace(getPosVec(), getPosVec().add(rotation.getRayVector().multiply(Config.DEFENSIVE_LASER_RANGE))); + 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(Config.DEFENSIVE_LASER_RANGE).add(posVec); + 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(); + } + + double distance; + if (collision != null) { + world.createExplosion(null, collision.getX(), collision.getY(), collision.getZ(), 4, Explosion.DestructionType.NONE); + + distance = posVec.distanceTo(collision); + } else { + distance = Config.DEFENSIVE_LASER_RANGE; + } + + double multiplier = 6d; + distance = distance * multiplier; + for (int i = 0; i < distance; i++) { + Vec3d vec = rotationVec.multiply(i / multiplier).add(posVec); + ((ServerWorld) getWorld()).spawnParticles(ParticleTypes.END_ROD, vec.getX(), vec.getY(), vec.getZ(), 1, 0, 0, 0, 1); + } + }, (world, pos, state) -> firing = false)); target = null; - } else if (countdown < 1) { + firing = true; + } else if (countdown < 1 && !firing) { if (target == null) { - List entities = getWorld().getEntities(LivingEntity.class, new Box(getPos()).expand(Config.DEFENSIVE_LASER_RANGE), predicate); + List entities = getEntities(getTargetPredicate(false)); if (entities.size() > 0) { - Collections.shuffle(entities); + Vec3d posVec = getPosVec(); + entities.sort(Comparator.comparingDouble(entity -> entity.getPos().distanceTo(posVec))); target = entities.get(0); } } else { - if (predicate.test(target)) { + if (getTargetPredicate(false).test(target)) { Optional optional = target.getBoundingBox().rayTrace(getPosVec(), getPosVec().add(rotation.getRayVector().multiply(Config.DEFENSIVE_LASER_RANGE))); - if (optional.isPresent()) { + if (optional.isPresent() && getTargetPredicate(true).test(target)) { countdown = COUNTDOWN; } else { Vec3d targetPos = target.getPos(); - float targetYaw = getTargetYaw(targetPos.getX(), targetPos.getZ()); - float targetPitch = getTargetPitch(targetPos.getX(), targetPos.getY(), targetPos.getZ()); + float targetYaw = getTargetYaw(targetPos); + float targetPitch = getTargetPitch(targetPos); rotation.target(targetYaw, targetPitch); } } else { @@ -205,5 +267,6 @@ public class DefensiveLaserBlockEntity extends EnergyReceiverBlockEntity { super.fromTag(state, tag); rotation.fromTag(tag); countdown = tag.getInt("Countdown"); + firing = false; } } diff --git a/src/main/java/com/thebrokenrail/energonrelics/client/render/DefensiveLaserBlockEntityRenderer.java b/src/main/java/com/thebrokenrail/energonrelics/client/render/DefensiveLaserBlockEntityRenderer.java index e0b1b13..5e7655d 100644 --- a/src/main/java/com/thebrokenrail/energonrelics/client/render/DefensiveLaserBlockEntityRenderer.java +++ b/src/main/java/com/thebrokenrail/energonrelics/client/render/DefensiveLaserBlockEntityRenderer.java @@ -6,8 +6,6 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; -import net.minecraft.client.render.entity.feature.HeadFeatureRenderer; -import net.minecraft.client.render.entity.feature.ShulkerHeadFeatureRenderer; import net.minecraft.client.render.model.json.ModelTransformation; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.Vector3f; diff --git a/src/main/resources/assets/energonrelics/models/block/defensive_laser.json b/src/main/resources/assets/energonrelics/models/block/defensive_laser.json index 58541e8..2fc3d31 100644 --- a/src/main/resources/assets/energonrelics/models/block/defensive_laser.json +++ b/src/main/resources/assets/energonrelics/models/block/defensive_laser.json @@ -1,6 +1,6 @@ { "parent": "minecraft:block/cube_all", "textures": { - "all": "energonrelics:block/defensive_laser_base" + "all": "energonrelics:block/defensive_laser" } } diff --git a/src/main/resources/assets/energonrelics/textures/block/defensive_laser.png b/src/main/resources/assets/energonrelics/textures/block/defensive_laser.png new file mode 100644 index 0000000..a2f869f Binary files /dev/null and b/src/main/resources/assets/energonrelics/textures/block/defensive_laser.png differ diff --git a/src/main/resources/data/energonrelics/recipes/defensive_laser.json b/src/main/resources/data/energonrelics/recipes/defensive_laser.json new file mode 100644 index 0000000..3a19518 --- /dev/null +++ b/src/main/resources/data/energonrelics/recipes/defensive_laser.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "#G#", + "GLG", + "#G#" + ], + "key": { + "#": { + "item": "minecraft:obsidian" + }, + "G": { + "item": "minecraft:glass" + }, + "L": { + "item": "energonrelics:defensive_laser_core" + } + }, + "result": { + "item": "energonrelics:defensive_laser", + "count": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/data/energonrelics/recipes/defensive_laser_core.json b/src/main/resources/data/energonrelics/recipes/defensive_laser_core.json new file mode 100644 index 0000000..349ff79 --- /dev/null +++ b/src/main/resources/data/energonrelics/recipes/defensive_laser_core.json @@ -0,0 +1,23 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "#I#", + "IGI", + "#I#" + ], + "key": { + "#": { + "item": "energonrelics:circuit_board" + }, + "I": { + "item": "minecraft:gold_ingot" + }, + "G": { + "item": "minecraft:gunpowder" + } + }, + "result": { + "item": "energonrelics:defensive_laser_core", + "count": 1 + } +} \ No newline at end of file