forked from kaboom-fabric/extras
Experimental spidey command
This commit is contained in:
parent
ed103d8a1e
commit
50974d6ecc
3 changed files with 381 additions and 1 deletions
|
@ -31,7 +31,7 @@ public class Extras implements ModInitializer {
|
|||
CommandServerInfo.register(dispatcher);
|
||||
// CommandSkin.register(dispatcher);
|
||||
CommandSpawn.register(dispatcher);
|
||||
// CommandSpidey.register(dispatcher);
|
||||
CommandSpidey.register(dispatcher);
|
||||
// CommandTellraw.register(dispatcher);
|
||||
// CommandUsername.register(dispatcher);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package land.chipmunk.kaboomfabric.extras.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import land.chipmunk.kaboomfabric.extras.modules.block.BlockIterator;
|
||||
|
||||
public abstract class CommandSpidey {
|
||||
public static void register (CommandDispatcher dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("spidey")
|
||||
.requires(source -> source.hasPermissionLevel(2))
|
||||
// .executes(CommandSpidey::spideyCommand)
|
||||
);
|
||||
}
|
||||
|
||||
public static int spideyCommand (CommandContext<ServerCommandSource> context) throws CommandSyntaxException {
|
||||
final ServerCommandSource source = context.getSource();
|
||||
final Entity entity = source.getEntityOrThrow();
|
||||
final ServerWorld world = source.getWorld();
|
||||
|
||||
final Vec3d start = entity.getEyePos();
|
||||
final Vec3d direction = Vec3d.fromPolar(entity.getYaw(), entity.getPitch());
|
||||
final int yOffset = 0;
|
||||
final int distance = 50;
|
||||
|
||||
final BlockIterator iterator = new BlockIterator(start, direction, yOffset, distance);
|
||||
|
||||
final BlockState cobweb = Registries.BLOCK.get(new Identifier("minecraft", "cobweb")).getDefaultState();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
BlockPos pos = iterator.next();
|
||||
if (!world.isInBuildLimit(pos) || !world.getBlockState(pos).isAir()) break;
|
||||
|
||||
if (world.getBlockState(pos).hasBlockEntity()) world.removeBlockEntity(pos);
|
||||
world.setBlockState(pos, cobweb);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
package land.chipmunk.kaboomfabric.extras.modules.block;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import net.minecraft.entity.Entity;
|
||||
// import net.minecraft.world.World;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
/**
|
||||
* This class performs ray tracing and iterates along blocks on a line
|
||||
Ported from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse/src/main/java/org/bukkit/util/BlockIterator.java
|
||||
*/
|
||||
public class BlockIterator implements Iterator<BlockPos> {
|
||||
// private final World world;
|
||||
private final int maxDistance;
|
||||
|
||||
private static final int gridSize = 1 << 24;
|
||||
|
||||
private boolean end = false;
|
||||
|
||||
private BlockPos[] blockQueue = new BlockPos[3];
|
||||
private int currentBlock = 0;
|
||||
private int currentDistance = 0;
|
||||
private int maxDistanceInt;
|
||||
|
||||
private int secondError;
|
||||
private int thirdError;
|
||||
|
||||
private int secondStep;
|
||||
private int thirdStep;
|
||||
|
||||
private Direction mainFace;
|
||||
private Direction secondFace;
|
||||
private Direction thirdFace;
|
||||
|
||||
/**
|
||||
* Constructs the BlockIterator.
|
||||
* <p>
|
||||
* This considers all blocks as 1x1x1 in size.
|
||||
*
|
||||
* @param world The world to use for tracing
|
||||
* @param start A Vector giving the initial location for the trace
|
||||
* @param direction A Vector pointing in the direction for the trace
|
||||
* @param yOffset The trace begins vertically offset from the start vector
|
||||
* by this value
|
||||
* @param maxDistance This is the maximum distance in blocks for the
|
||||
* trace. Setting this value above 140 may lead to problems with
|
||||
* unloaded chunks. A value of 0 indicates no limit
|
||||
*
|
||||
*/
|
||||
public BlockIterator(Vec3d start, Vec3d direction, double yOffset, int maxDistance) {
|
||||
// Preconditions.checkArgument(world != null, "world must not be null");
|
||||
// Preconditions.checkArgument(start != null, "start must not be null");
|
||||
// Preconditions.checkArgument(direction != null, "direction must not be null");
|
||||
// Preconditions.checkArgument(!direction.isZero(), "direction must have at least one non-zero component");
|
||||
|
||||
// this.world = world;
|
||||
this.maxDistance = maxDistance;
|
||||
|
||||
Vec3d startClone = new Vec3d(start.getX(), start.getY() + yOffset, start.getZ());
|
||||
|
||||
currentDistance = 0;
|
||||
|
||||
double mainDirection = 0;
|
||||
double secondDirection = 0;
|
||||
double thirdDirection = 0;
|
||||
double mainPosition = 0;
|
||||
double secondPosition = 0;
|
||||
double thirdPosition = 0;
|
||||
|
||||
BlockPos startBlock = new BlockPos(floor(startClone.getX()), floor(startClone.getY()), floor(startClone.getZ()));
|
||||
|
||||
if (getXLength(direction) > mainDirection) {
|
||||
mainFace = getXFace(direction);
|
||||
mainDirection = getXLength(direction);
|
||||
mainPosition = getXPosition(direction, startClone, startBlock);
|
||||
|
||||
secondFace = getYFace(direction);
|
||||
secondDirection = getYLength(direction);
|
||||
secondPosition = getYPosition(direction, startClone, startBlock);
|
||||
|
||||
thirdFace = getZFace(direction);
|
||||
thirdDirection = getZLength(direction);
|
||||
thirdPosition = getZPosition(direction, startClone, startBlock);
|
||||
}
|
||||
if (getYLength(direction) > mainDirection) {
|
||||
mainFace = getYFace(direction);
|
||||
mainDirection = getYLength(direction);
|
||||
mainPosition = getYPosition(direction, startClone, startBlock);
|
||||
|
||||
secondFace = getZFace(direction);
|
||||
secondDirection = getZLength(direction);
|
||||
secondPosition = getZPosition(direction, startClone, startBlock);
|
||||
|
||||
thirdFace = getXFace(direction);
|
||||
thirdDirection = getXLength(direction);
|
||||
thirdPosition = getXPosition(direction, startClone, startBlock);
|
||||
}
|
||||
if (getZLength(direction) > mainDirection) {
|
||||
mainFace = getZFace(direction);
|
||||
mainDirection = getZLength(direction);
|
||||
mainPosition = getZPosition(direction, startClone, startBlock);
|
||||
|
||||
secondFace = getXFace(direction);
|
||||
secondDirection = getXLength(direction);
|
||||
secondPosition = getXPosition(direction, startClone, startBlock);
|
||||
|
||||
thirdFace = getYFace(direction);
|
||||
thirdDirection = getYLength(direction);
|
||||
thirdPosition = getYPosition(direction, startClone, startBlock);
|
||||
}
|
||||
|
||||
// trace line backwards to find intercept with plane perpendicular to the main axis
|
||||
|
||||
double d = mainPosition / mainDirection; // how far to hit face behind
|
||||
double secondd = secondPosition - secondDirection * d;
|
||||
double thirdd = thirdPosition - thirdDirection * d;
|
||||
|
||||
// Guarantee that the ray will pass though the start block.
|
||||
// It is possible that it would miss due to rounding
|
||||
// This should only move the ray by 1 grid position
|
||||
secondError = floor(secondd * gridSize);
|
||||
secondStep = round(secondDirection / mainDirection * gridSize);
|
||||
thirdError = floor(thirdd * gridSize);
|
||||
thirdStep = round(thirdDirection / mainDirection * gridSize);
|
||||
|
||||
if (secondError + secondStep <= 0) {
|
||||
secondError = -secondStep + 1;
|
||||
}
|
||||
|
||||
if (thirdError + thirdStep <= 0) {
|
||||
thirdError = -thirdStep + 1;
|
||||
}
|
||||
|
||||
BlockPos lastBlock;
|
||||
|
||||
lastBlock = startBlock.add(mainFace.getOpposite().getVector());
|
||||
|
||||
if (secondError < 0) {
|
||||
secondError += gridSize;
|
||||
lastBlock = lastBlock.add(secondFace.getOpposite().getVector());
|
||||
}
|
||||
|
||||
if (thirdError < 0) {
|
||||
thirdError += gridSize;
|
||||
lastBlock = lastBlock.add(thirdFace.getOpposite().getVector());
|
||||
}
|
||||
|
||||
// This means that when the variables are positive, it means that the coord=1 boundary has been crossed
|
||||
secondError -= gridSize;
|
||||
thirdError -= gridSize;
|
||||
|
||||
blockQueue[0] = lastBlock;
|
||||
currentBlock = -1;
|
||||
|
||||
scan();
|
||||
|
||||
boolean startBlockFound = false;
|
||||
|
||||
for (int cnt = currentBlock; cnt >= 0; cnt--) {
|
||||
if (blockEquals(blockQueue[cnt], startBlock)) {
|
||||
currentBlock = cnt;
|
||||
startBlockFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!startBlockFound) {
|
||||
throw new IllegalStateException("Start block missed in BlockIterator");
|
||||
}
|
||||
|
||||
// Calculate the number of planes passed to give max distance
|
||||
maxDistanceInt = round(maxDistance / (Math.sqrt(mainDirection * mainDirection + secondDirection * secondDirection + thirdDirection * thirdDirection) / mainDirection));
|
||||
}
|
||||
|
||||
private boolean blockEquals(BlockPos a, BlockPos b) {
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
private Direction getXFace(Vec3d direction) {
|
||||
return ((direction.getX() > 0) ? Direction.EAST : Direction.WEST);
|
||||
}
|
||||
|
||||
private Direction getYFace(Vec3d direction) {
|
||||
return ((direction.getY() > 0) ? Direction.UP : Direction.DOWN);
|
||||
}
|
||||
|
||||
private Direction getZFace(Vec3d direction) {
|
||||
return ((direction.getZ() > 0) ? Direction.SOUTH : Direction.NORTH);
|
||||
}
|
||||
|
||||
private double getXLength(Vec3d direction) {
|
||||
return Math.abs(direction.getX());
|
||||
}
|
||||
|
||||
private double getYLength(Vec3d direction) {
|
||||
return Math.abs(direction.getY());
|
||||
}
|
||||
|
||||
private double getZLength(Vec3d direction) {
|
||||
return Math.abs(direction.getZ());
|
||||
}
|
||||
|
||||
private double getPosition(double direction, double position, int blockPosition) {
|
||||
return direction > 0 ? (position - blockPosition) : (blockPosition + 1 - position);
|
||||
}
|
||||
|
||||
private double getXPosition(Vec3d direction, Vec3d position, BlockPos block) {
|
||||
return getPosition(direction.getX(), position.getX(), block.getX());
|
||||
}
|
||||
|
||||
private double getYPosition(Vec3d direction, Vec3d position, BlockPos block) {
|
||||
return getPosition(direction.getY(), position.getY(), block.getY());
|
||||
}
|
||||
|
||||
private double getZPosition(Vec3d direction, Vec3d position, BlockPos block) {
|
||||
return getPosition(direction.getZ(), position.getZ(), block.getZ());
|
||||
}
|
||||
|
||||
public BlockIterator(Entity entity, int maxDistance) {
|
||||
this(entity.getPos(), Vec3d.fromPolar(entity.getYaw(), entity.getPitch()), entity.getEyeHeight(entity.getPose()), maxDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the BlockIterator.
|
||||
* <p>
|
||||
* This considers all blocks as 1x1x1 in size.
|
||||
*
|
||||
* @param entity Information from the entity is used to set up the trace
|
||||
*/
|
||||
|
||||
public BlockIterator(Entity entity) {
|
||||
this(entity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the iteration has more elements
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
scan();
|
||||
return currentBlock != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next Block in the trace
|
||||
*
|
||||
* @return the next Block in the trace
|
||||
*/
|
||||
@Override
|
||||
public BlockPos next() throws NoSuchElementException {
|
||||
scan();
|
||||
if (currentBlock <= -1) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return blockQueue[currentBlock--];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("[BlockIterator] doesn't support block removal");
|
||||
}
|
||||
|
||||
private void scan() {
|
||||
if (currentBlock >= 0) {
|
||||
return;
|
||||
}
|
||||
if (maxDistance != 0 && currentDistance > maxDistanceInt) {
|
||||
end = true;
|
||||
return;
|
||||
}
|
||||
if (end) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentDistance++;
|
||||
|
||||
secondError += secondStep;
|
||||
thirdError += thirdStep;
|
||||
|
||||
if (secondError > 0 && thirdError > 0) {
|
||||
blockQueue[2] = blockQueue[0].add(mainFace.getVector());
|
||||
if (((long) secondStep) * ((long) thirdError) < ((long) thirdStep) * ((long) secondError)) {
|
||||
blockQueue[1] = blockQueue[2].add(secondFace.getVector());
|
||||
blockQueue[0] = blockQueue[1].add(thirdFace.getVector());
|
||||
} else {
|
||||
blockQueue[1] = blockQueue[2].add(thirdFace.getVector());
|
||||
blockQueue[0] = blockQueue[1].add(secondFace.getVector());
|
||||
}
|
||||
thirdError -= gridSize;
|
||||
secondError -= gridSize;
|
||||
currentBlock = 2;
|
||||
return;
|
||||
} else if (secondError > 0) {
|
||||
blockQueue[1] = blockQueue[0].add(mainFace.getVector());
|
||||
blockQueue[0] = blockQueue[1].add(secondFace.getVector());
|
||||
secondError -= gridSize;
|
||||
currentBlock = 1;
|
||||
return;
|
||||
} else if (thirdError > 0) {
|
||||
blockQueue[1] = blockQueue[0].add(mainFace.getVector());
|
||||
blockQueue[0] = blockQueue[1].add(thirdFace.getVector());
|
||||
thirdError -= gridSize;
|
||||
currentBlock = 1;
|
||||
return;
|
||||
} else {
|
||||
blockQueue[0] = blockQueue[0].add(mainFace.getVector());
|
||||
currentBlock = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse/src/main/java/org/bukkit/util/NumberConversions.java
|
||||
// This may eventually be moved to a separate file
|
||||
|
||||
private static int floor(double num) {
|
||||
final int floor = (int) num;
|
||||
return floor == num ? floor : floor - (int) (Double.doubleToRawLongBits(num) >>> 63);
|
||||
}
|
||||
|
||||
private static int round(double num) {
|
||||
return floor(num + 0.5d);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue