Virtual stick cursor steered through the gun reticle, server-side virtual pilot using measured control responses, client cursor/camera handling with look-ahead, free look and scroll zoom. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YVREx3uo7nz1FEhzveWTUh
102 lines
4.2 KiB
Java
102 lines
4.2 KiB
Java
package dev.lumareth.improvedAerodynamics.flight;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
|
|
/**
|
|
* The frame cursor aim steers in, in ship coordinates: forward is the boresight (what Warium's gun reticle points
|
|
* along, from the HUD block in front of the seat, else the way the seat faces), up is the ship's up axis and right
|
|
* completes it. Server and client both build it from the same block data, so a cursor sent as components in this
|
|
* frame means the same on both.
|
|
*
|
|
* @param nodePos the Vehicle Control Node the seat is linked to
|
|
*/
|
|
public record AimBasis(BlockPos seatPos, BlockPos nodePos, double[] forward, double[] right, double[] up) {
|
|
|
|
/**
|
|
* @param entityPos block position of the seat entity. Warium's control seat block is at that position or just
|
|
* below it.
|
|
* @return null if there is no seat block linked to a control node there
|
|
*/
|
|
public static AimBasis of(Level level, BlockPos entityPos) {
|
|
for (BlockPos pos : new BlockPos[]{entityPos, entityPos.below()}) {
|
|
BlockEntity seat = level.getBlockEntity(pos);
|
|
if (seat == null || !seat.getPersistentData().contains("ControlX")) {
|
|
continue;
|
|
}
|
|
CompoundTag tag = seat.getPersistentData();
|
|
BlockPos nodePos = BlockPos.containing(tag.getDouble("ControlX"), tag.getDouble("ControlY"), tag.getDouble("ControlZ"));
|
|
return new AimBasis(pos, nodePos, null, null, null).withAxes(level, pos, nodePos);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private AimBasis withAxes(Level level, BlockPos seatPos, BlockPos nodePos) {
|
|
BlockState state = level.getBlockState(seatPos);
|
|
Direction facing = Direction.NORTH;
|
|
Property<?> property = state.getBlock().getStateDefinition().getProperty("facing");
|
|
if (property instanceof DirectionProperty directionProperty) {
|
|
facing = state.getValue(directionProperty);
|
|
}
|
|
double fx = facing.getStepX();
|
|
double fy = facing.getStepY();
|
|
double fz = facing.getStepZ();
|
|
|
|
// Warium's gun reticle: the HUD block in front of the seat holds the aim vector of its guns
|
|
BlockEntity hud = level.getBlockEntity(seatPos.relative(facing));
|
|
if (hud != null && hud.getPersistentData().contains("Pitch")) {
|
|
CompoundTag hudTag = hud.getPersistentData();
|
|
double bx = hudTag.getDouble("X") + facing.getStepX();
|
|
double by = hudTag.getDouble("Pitch");
|
|
double bz = hudTag.getDouble("Z") + facing.getStepZ();
|
|
if (bx * bx + by * by + bz * bz > 1.0E-6) {
|
|
fx = bx;
|
|
fy = by;
|
|
fz = bz;
|
|
}
|
|
}
|
|
double length = Math.sqrt(fx * fx + fy * fy + fz * fz);
|
|
if (length < 1.0E-6) {
|
|
fx = 0.0;
|
|
fy = 0.0;
|
|
fz = -1.0;
|
|
length = 1.0;
|
|
}
|
|
fx /= length;
|
|
fy /= length;
|
|
fz /= length;
|
|
|
|
// right = forward x up(0,1,0)
|
|
double rx = -fz;
|
|
double ry = 0.0;
|
|
double rz = fx;
|
|
double rl = Math.sqrt(rx * rx + rz * rz);
|
|
if (rl < 1.0E-6) {
|
|
rx = 1.0;
|
|
rz = 0.0;
|
|
rl = 1.0;
|
|
}
|
|
rx /= rl;
|
|
rz /= rl;
|
|
// up = right x forward
|
|
double ux = ry * fz - rz * fy;
|
|
double uy = rz * fx - rx * fz;
|
|
double uz = rx * fy - ry * fx;
|
|
return new AimBasis(seatPos, nodePos, new double[]{fx, fy, fz}, new double[]{rx, ry, rz}, new double[]{ux, uy, uz});
|
|
}
|
|
|
|
/** Ship-space direction of a cursor given by its components along forward, right and up. */
|
|
public double[] toShip(double cf, double cr, double cu) {
|
|
return new double[]{
|
|
forward[0] * cf + right[0] * cr + up[0] * cu,
|
|
forward[1] * cf + right[1] * cr + up[1] * cu,
|
|
forward[2] * cf + right[2] * cr + up[2] * cu};
|
|
}
|
|
}
|