diff --git a/src/main/java/me/alexdevs/solstice/modules/admin/commands/SmiteCommand.java b/src/main/java/me/alexdevs/solstice/modules/admin/commands/SmiteCommand.java index 0f00172..e3a3168 100644 --- a/src/main/java/me/alexdevs/solstice/modules/admin/commands/SmiteCommand.java +++ b/src/main/java/me/alexdevs/solstice/modules/admin/commands/SmiteCommand.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import me.alexdevs.solstice.api.module.ModCommand; +import me.alexdevs.solstice.util.Raycast; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.argument.EntityArgumentType; @@ -13,6 +14,10 @@ import net.minecraft.entity.SpawnReason; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; import java.util.List; @@ -22,6 +27,7 @@ public class SmiteCommand extends ModCommand { public static final EntityType entityType = EntityType.LIGHTNING_BOLT; public static final int maxTimes = 1024; + public static final int maxDistance = 512; public SmiteCommand(CommandDispatcher dispatcher, CommandRegistryAccess commandRegistry, CommandManager.RegistrationEnvironment environment) { super(dispatcher, commandRegistry, environment); @@ -36,7 +42,8 @@ public List getNames() { public LiteralArgumentBuilder command(String name) { return literal(name) .requires(require(2)) - .then(argument("target", EntityArgumentType.players()) + .executes(this::executePos) + .then(argument("target", EntityArgumentType.entities()) .executes(context -> execute(context, 1) ) @@ -46,21 +53,45 @@ public LiteralArgumentBuilder command(String name) { ))); } + private int executePos(CommandContext context) throws CommandSyntaxException { + var player = context.getSource().getPlayerOrThrow(); + + var result = Raycast.cast(player, maxDistance); + if(result.getType() == HitResult.Type.MISS) { + return 0; + } + + summon(player.getServerWorld(), result.getBlockPos().up()); + + return 1; + } + private int execute(CommandContext context, int times) throws CommandSyntaxException { - var targets = EntityArgumentType.getPlayers(context, "target"); + var player = context.getSource().getPlayerOrThrow(); + var targets = EntityArgumentType.getEntities(context, "target"); + var timesToSummon = targets.size() * times; + if (timesToSummon > maxTimes) { + times = maxTimes / targets.size(); + if (times == 0) + times = 1; + } for (var i = 0; i < times; i++) { targets.forEach(target -> - entityType.create( - target.getServerWorld(), - null, - (entity) -> target.getWorld().spawnEntity(entity), - target.getBlockPos(), - SpawnReason.COMMAND, - false, - false) + summon(player.getServerWorld(), target.getBlockPos()) ); } return targets.size(); } + + private void summon(ServerWorld world, BlockPos pos) { + entityType.create( + world, + null, + world::spawnEntity, + pos, + SpawnReason.COMMAND, + false, + false); + } } diff --git a/src/main/java/me/alexdevs/solstice/util/Raycast.java b/src/main/java/me/alexdevs/solstice/util/Raycast.java new file mode 100644 index 0000000..fc817b2 --- /dev/null +++ b/src/main/java/me/alexdevs/solstice/util/Raycast.java @@ -0,0 +1,51 @@ +package me.alexdevs.solstice.util; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; + +public class Raycast { + public static BlockHitResult cast(ServerPlayerEntity player, double maxDistance) { + var world = player.getServerWorld(); + var eyePos = player.getEyePos(); + var rotVec = player.getRotationVector(); + + var raycastEnd = eyePos.add(rotVec.multiply(maxDistance)); + + var rcContext = new RaycastContext( + eyePos, + raycastEnd, + RaycastContext.ShapeType.OUTLINE, + RaycastContext.FluidHandling.NONE, + player + ); + + return world.raycast(rcContext); + } + + public static BlockPos getBlockPos(ServerPlayerEntity player, double maxDistance) { + var result = cast(player, maxDistance); + if(result.getType() == BlockHitResult.Type.BLOCK) { + return result.getBlockPos(); + } + return null; + } + + public static Vec3d getEntityPos(ServerPlayerEntity player, double maxDistance) { + var result = cast(player, maxDistance); + if(result.getType() == BlockHitResult.Type.ENTITY) { + return result.getPos(); + } + return null; + } + + public static Vec3d getPos(ServerPlayerEntity player, double maxDistance) { + var result = cast(player, maxDistance); + if(result.getType() != BlockHitResult.Type.MISS) { + return result.getPos(); + } + return null; + } +}