diff --git a/src/main/java/net/torocraft/flighthud/FlightComputer.java b/src/main/java/net/torocraft/flighthud/FlightComputer.java index 567e7d5e..90578531 100644 --- a/src/main/java/net/torocraft/flighthud/FlightComputer.java +++ b/src/main/java/net/torocraft/flighthud/FlightComputer.java @@ -102,7 +102,7 @@ public BlockPos findGround(MinecraftClient client) { private int computeGroundLevel(MinecraftClient client) { BlockPos ground = findGround(client); - return ground == null ? -50 : ground.getY(); + return ground == null ? Math.min(client.player.getBlockY() + 4, -50) : ground.getY(); } private float computeDistanceFromGround(float altitude, diff --git a/src/main/java/net/torocraft/flighthud/FlightSafetyMonitor.java b/src/main/java/net/torocraft/flighthud/FlightSafetyMonitor.java index f1738e7b..eb597bb9 100644 --- a/src/main/java/net/torocraft/flighthud/FlightSafetyMonitor.java +++ b/src/main/java/net/torocraft/flighthud/FlightSafetyMonitor.java @@ -1,7 +1,9 @@ package net.torocraft.flighthud; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.List; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.FireworkRocketItem; import net.minecraft.item.ItemStack; @@ -14,8 +16,6 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.RaycastContext; -import java.util.List; - import static net.torocraft.flighthud.AutoFlightManager.changeLookDirection; import static net.torocraft.flighthud.AutoFlightManager.deltaTime; import static net.torocraft.flighthud.FlightHud.CONFIG_SETTINGS; @@ -43,15 +43,18 @@ public class FlightSafetyMonitor { public static boolean flightProtectionsEnabled = true; public static boolean thrustSet = true; + public static boolean havePassengersDismounted = false; public static long lastFireworkActivationTimeMs = 0; public static int fireworkCount = Integer.MAX_VALUE; public static boolean thrustLocked = false; + private static int lastPassengers = 0; public static void update(MinecraftClient mc, FlightComputer computer) { if (CONFIG == null || mc.world == null || mc.player == null || !mc.player.isFallFlying()) { flightProtectionsEnabled = thrustSet = true; - thrustLocked = false; + thrustLocked = havePassengersDismounted = false; + lastPassengers = 0; return; } maximumSafePitch = updateMaximumSafePitch(computer); @@ -76,15 +79,25 @@ else if (secondsUntilGroundImpact <= lampThreshold || secondsUntilTerrainImpact updateUnsafeFireworks(mc.player); fireworkCount = countSafeFireworks(mc.player); + havePassengersDismounted = updatePassengersDismounted(mc); + if (flightProtectionsEnabled) { // Make corrections to flight path to ensure safety - if (computer.distanceFromGround > 2 && computer.pitch > maximumSafePitch) - changeLookDirection(mc.player, Math.max(0, computer.pitch - maximumSafePitch) * AutoFlightManager.deltaTime, 0); + float delta = deltaTime / Math.min(1, secondsUntilGroundImpact); + if (computer.distanceFromGround > 3 && computer.pitch > maximumSafePitch) + changeLookDirection(mc.player, Math.max(0, computer.pitch - maximumSafePitch) * delta, 0); else if (secondsUntilGroundImpact <= correctThreshold) - changeLookDirection(mc.player, Math.min(0, computer.pitch) * (AutoFlightManager.deltaTime / Math.min(1, secondsUntilGroundImpact)), 0); + changeLookDirection(mc.player, Math.min(0, computer.pitch) * delta, 0); } } + private static boolean updatePassengersDismounted(MinecraftClient mc) { + int currentPassengers = (int) mc.player.getPassengerList().stream().flatMap(Entity::streamSelfAndPassengers).count(); + boolean b = currentPassengers < lastPassengers; + lastPassengers = currentPassengers; + return b; + } + private static void updateUnsafeFireworks(PlayerEntity player) { unsafeFireworkHands.clear(); if (!CONFIG_SETTINGS.unsafeFireworksAlert) return; @@ -112,15 +125,15 @@ private static boolean updateElytraLow(FlightComputer computer) { } private static boolean updateStallStatus(FlightComputer computer) { - return computer.pitch > 0 && computer.distanceFromGround > 2 && computer.airSpeed.length() <= 1.0f; + return computer.pitch > 0 && computer.distanceFromGround > 3 && computer.velocity.horizontalLength() < -computer.velocity.y; } private static float updateMaximumSafePitch(FlightComputer computer) { - return (float) (computer.airSpeed.length() * 3f); + return isStalling && computer.velocityPerSecond.y <= -10 ? 0.0f : computer.speed * 3; } private static float updateUnsafeSinkrate(FlightComputer computer) { - if (!CONFIG_SETTINGS.gpws || isStalling || computer.distanceFromGround <= 2 || computer.velocityPerSecond.y > -10) + if (!CONFIG_SETTINGS.gpws || isStalling || computer.distanceFromGround <= 3 || computer.velocityPerSecond.y > -10) return Float.MAX_VALUE; return (float) (computer.distanceFromGround / -computer.velocityPerSecond.y); } diff --git a/src/main/java/net/torocraft/flighthud/HudComponent.java b/src/main/java/net/torocraft/flighthud/HudComponent.java index 17593125..6ff703b7 100644 --- a/src/main/java/net/torocraft/flighthud/HudComponent.java +++ b/src/main/java/net/torocraft/flighthud/HudComponent.java @@ -1,5 +1,6 @@ package net.torocraft.flighthud; +import java.util.function.Consumer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -7,8 +8,6 @@ import net.minecraft.util.math.RotationAxis; import net.torocraft.flighthud.config.HudConfig; -import java.util.function.Consumer; - public abstract class HudComponent { public static HudConfig CONFIG; @@ -60,11 +59,11 @@ public static void drawVerticalLine(DrawContext context, float x, float y1, floa y2 - CONFIG.halfThickness, color); } - public static void drawBox(DrawContext context, float x, float y, float w) { - drawHorizontalLine(context, x, x + w, y, CONFIG.color); - drawHorizontalLine(context, x, x + w, y + 10, CONFIG.color); - drawVerticalLine(context, x, y, y + 10, CONFIG.color); - drawVerticalLine(context, x + w, y, y + 10, CONFIG.color); + public static void drawBox(DrawContext context, float x, float y, float w, int color) { + drawHorizontalLine(context, x, x + w, y, color); + drawHorizontalLine(context, x, x + w, y + 10, color); + drawVerticalLine(context, x, y, y + 10, color); + drawVerticalLine(context, x + w, y, y + 10, color); } public static void drawTextHighlight(TextRenderer renderer, DrawContext context, float x, float y, String text, int color) { diff --git a/src/main/java/net/torocraft/flighthud/alerts/PassengerDismountedAlert.java b/src/main/java/net/torocraft/flighthud/alerts/PassengerDismountedAlert.java new file mode 100644 index 00000000..e8e1a85f --- /dev/null +++ b/src/main/java/net/torocraft/flighthud/alerts/PassengerDismountedAlert.java @@ -0,0 +1,17 @@ +package net.torocraft.flighthud.alerts; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.torocraft.flighthud.FlightSafetyMonitor; + +public class PassengerDismountedAlert extends Alert { + @Override + public boolean shouldActivate() { + return FlightSafetyMonitor.havePassengersDismounted; + } + + @Override + public int drawText(MinecraftClient mc, DrawContext context, float x, float y, boolean highlight) { + return drawWarning(mc, context, x, y, highlight, "PAX DISMOUNTED"); + } +} \ No newline at end of file diff --git a/src/main/java/net/torocraft/flighthud/components/AltitudeIndicator.java b/src/main/java/net/torocraft/flighthud/components/AltitudeIndicator.java index 0c0b344d..7ca083f5 100644 --- a/src/main/java/net/torocraft/flighthud/components/AltitudeIndicator.java +++ b/src/main/java/net/torocraft/flighthud/components/AltitudeIndicator.java @@ -34,15 +34,16 @@ public void render(DrawContext context, MinecraftClient mc) { } if (CONFIG.altitude_showReadout) { - drawFont(mc, context, String.format("%.0f", computer.altitude), xAltText, dim.yMid - 3, computer.altitude <= -50 ? CONFIG.alertColor : CONFIG.color); - drawBox(context, xAltText - 2, dim.yMid - 4.5f, 28); + int color = computer.altitude <= -50 ? CONFIG.alertColor : CONFIG.color; + drawFont(mc, context, String.format("%.0f", computer.altitude), xAltText, dim.yMid - 3, color); + drawBox(context, xAltText - 2, dim.yMid - 4.5f, 28, color); } if (CONFIG.altitude_showHeight) { drawFont(mc, context, "G", xAltText - 10, bottom + 3); String heightText = String.format("%d", i(computer.distanceFromGround)); drawFont(mc, context, heightText, xAltText, bottom + 3); - drawBox(context, xAltText - 2, bottom + 1.5f, 28); + drawBox(context, xAltText - 2, bottom + 1.5f, 28, CONFIG.color); } if (CONFIG.altitude_showScale) { diff --git a/src/main/java/net/torocraft/flighthud/components/ElytraHealthIndicator.java b/src/main/java/net/torocraft/flighthud/components/ElytraHealthIndicator.java index e7b072c3..edbfd7af 100644 --- a/src/main/java/net/torocraft/flighthud/components/ElytraHealthIndicator.java +++ b/src/main/java/net/torocraft/flighthud/components/ElytraHealthIndicator.java @@ -24,9 +24,10 @@ public void render(DrawContext context, MinecraftClient mc) { float y = dim.hScreen * CONFIG.elytra_y; if (CONFIG.elytra_showHealth && computer.elytraHealth != null) { - drawBox(context, x - 3.5f, y - 1.5f, 30); - drawFont(mc, context, "E", x - 10, y); - drawFont(mc, context, String.format("%d", i(computer.elytraHealth)) + "%", x, y, computer.elytraHealth <= CONFIG_SETTINGS.lowElytraHealthAlarmThreshold ? CONFIG.alertColor : CONFIG.color); + int color = computer.elytraHealth <= CONFIG_SETTINGS.lowElytraHealthAlarmThreshold ? CONFIG.alertColor : CONFIG.color; + drawBox(context, x - 3.5f, y - 1.5f, 30, color); + drawFont(mc, context, "E", x - 10, y, color); + drawFont(mc, context, String.format("%d", i(computer.elytraHealth)) + "%", x, y, color); } } } diff --git a/src/main/java/net/torocraft/flighthud/components/FlightStatusIndicator.java b/src/main/java/net/torocraft/flighthud/components/FlightStatusIndicator.java index faa1426a..19d12fe7 100644 --- a/src/main/java/net/torocraft/flighthud/components/FlightStatusIndicator.java +++ b/src/main/java/net/torocraft/flighthud/components/FlightStatusIndicator.java @@ -1,6 +1,8 @@ package net.torocraft.flighthud.components; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.util.ArrayList; +import java.util.List; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.sound.SoundManager; @@ -22,18 +24,18 @@ import net.torocraft.flighthud.alerts.LowElytraHealthAlert; import net.torocraft.flighthud.alerts.LowFireworksAlert; import net.torocraft.flighthud.alerts.NoFireworksAlert; +import net.torocraft.flighthud.alerts.PassengerDismountedAlert; import net.torocraft.flighthud.alerts.ThrustLockedAlert; import net.torocraft.flighthud.alerts.UnsafeFireworksAlert; -import java.util.ArrayList; -import java.util.List; - +import static net.torocraft.flighthud.AutoFlightManager.deltaTime; import static net.torocraft.flighthud.AutoFlightManager.lastUpdateTimeMs; import static net.torocraft.flighthud.FlightHud.CONFIG_SETTINGS; public class FlightStatusIndicator extends HudComponent { public static final SoundEvent ALERT = SoundEvent.of(new Identifier("flighthud:alert")); public static final SoundEvent STICK_SHAKER = SoundEvent.of(new Identifier("flighthud:stick_shaker")); + public static final SoundEvent STALL_WARNING = SoundEvent.of(new Identifier("flighthud:stall_warning")); public static final SoundEvent SINKRATE = SoundEvent.of(new Identifier("flighthud:sinkrate")); public static final SoundEvent TERRAIN = SoundEvent.of(new Identifier("flighthud:terrain")); public static final SoundEvent PULL_UP = SoundEvent.of(new Identifier("flighthud:pull_up")); @@ -44,6 +46,7 @@ public class FlightStatusIndicator extends HudComponent { new LowElytraHealthAlert(), new LowFireworksAlert(), new NoFireworksAlert(), new UnsafeFireworksAlert(), new FireworkActivationFailureAlert(), + new PassengerDismountedAlert() }; public static final List activeAlerts = new ArrayList<>(); private static long lastHighlightTimeMs = 0L; @@ -53,6 +56,7 @@ public class FlightStatusIndicator extends HudComponent { private final FlightComputer computer; public boolean highlight = true; private boolean lastAutopilotState = false; + private AlertSoundInstance stickShakerInstance; public FlightStatusIndicator(FlightComputer computer, Dimensions dim) { this.dim = dim; @@ -148,10 +152,16 @@ public void drawCenteredWarning(MinecraftClient mc, DrawContext context, float w } public void tryStopEvents(PlayerEntity player, SoundManager manager) { - if (!activeEvents.isEmpty() && !player.isFallFlying()) { - for (SoundEvent event : activeEvents) - manager.stopSounds(event.getId(), SoundCategory.MASTER); - activeEvents.clear(); + if (!player.isFallFlying()) { + if (!activeEvents.isEmpty()) { + for (SoundEvent event : activeEvents) + manager.stopSounds(event.getId(), SoundCategory.MASTER); + activeEvents.clear(); + } + if (stickShakerInstance != null) { + manager.stop(stickShakerInstance); + stickShakerInstance = null; + } } activeAlerts.removeIf(alert -> !alert.shouldActivate()); } @@ -173,10 +183,17 @@ private void tryPlayStickShaker(MinecraftClient mc, DrawContext context) { stickShakerInstance.setVolume(stickShakerInstance.getVolume() + deltaTime * 2.0f); } + + if (computer.velocityPerSecond.y <= -10) { + playOnce(mc, STALL_WARNING, 1.0f, true); + } else + stopEvent(mc, STALL_WARNING); drawCenteredWarning(mc, context, dim.wScreen, dim.hScreen / 2 + 10, highlight, "STALL"); return; } + stopEvent(mc, STALL_WARNING); + if (stickShakerInstance == null) { return; } diff --git a/src/main/java/net/torocraft/flighthud/components/HeadingIndicator.java b/src/main/java/net/torocraft/flighthud/components/HeadingIndicator.java index a80c1149..4bd8aff1 100644 --- a/src/main/java/net/torocraft/flighthud/components/HeadingIndicator.java +++ b/src/main/java/net/torocraft/flighthud/components/HeadingIndicator.java @@ -28,7 +28,7 @@ public void render(DrawContext context, MinecraftClient mc) { if (CONFIG.heading_showReadout) { drawFont(mc, context, String.format("%03d", i(wrapHeading(computer.heading))), dim.xMid - 8, yText); - drawBox(context, dim.xMid - 15, yText - 1.5f, 30); + drawBox(context, dim.xMid - 15, yText - 1.5f, 30, CONFIG.color); } if (CONFIG.heading_showScale) { diff --git a/src/main/java/net/torocraft/flighthud/components/SpeedIndicator.java b/src/main/java/net/torocraft/flighthud/components/SpeedIndicator.java index cc44e340..85916e9c 100644 --- a/src/main/java/net/torocraft/flighthud/components/SpeedIndicator.java +++ b/src/main/java/net/torocraft/flighthud/components/SpeedIndicator.java @@ -32,12 +32,13 @@ public void render(DrawContext context, MinecraftClient mc) { float xSpeedText = left - 5; if (CONFIG.speed_showReadout) { - drawRightAlignedFont(mc, context, String.format("%.2f", computer.speed), xSpeedText, dim.yMid - 3, isStalling ? CONFIG.alertColor : CONFIG.color); + int color = isStalling ? CONFIG.alertColor : CONFIG.color; + drawRightAlignedFont(mc, context, String.format("%.2f", computer.speed), xSpeedText, dim.yMid - 3, color); + drawBox(context, xSpeedText - 29.5f, dim.yMid - 4.5f, 30, color); float frameWidth = dim.rFrame - dim.lFrame; drawFont(mc, context, String.format("G/S: %.2f", computer.velocityPerSecond.horizontalLength()), dim.lFrame + frameWidth * 0.25f, dim.hScreen * 0.8f, CONFIG.color); drawFont(mc, context, String.format("V/S: %.2f", computer.velocityPerSecond.y), dim.lFrame + frameWidth * 0.75f - 7, dim.hScreen * 0.8f, computer.velocityPerSecond.y <= -10.0f ? CONFIG.alertColor : CONFIG.color); - drawBox(context, xSpeedText - 29.5f, dim.yMid - 4.5f, 30); } diff --git a/src/main/resources/assets/flighthud/sounds.json b/src/main/resources/assets/flighthud/sounds.json index 814c5a43..0d159459 100644 --- a/src/main/resources/assets/flighthud/sounds.json +++ b/src/main/resources/assets/flighthud/sounds.json @@ -9,6 +9,11 @@ "flighthud:stick_shaker" ] }, + "stall_warning": { + "sounds": [ + "flighthud:stall_warning" + ] + }, "sinkrate": { "sounds": [ "flighthud:sinkrate" diff --git a/src/main/resources/assets/flighthud/sounds/stall_warning.ogg b/src/main/resources/assets/flighthud/sounds/stall_warning.ogg new file mode 100644 index 00000000..e69de29b