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}; } }