diff --git a/src/main/kotlin/nl/enjarai/doabarrelroll/compat/flightassistant/DaBRThrustComputer.kt b/src/main/kotlin/nl/enjarai/doabarrelroll/compat/flightassistant/DaBRThrustComputer.kt index b05c498..d53dc11 100644 --- a/src/main/kotlin/nl/enjarai/doabarrelroll/compat/flightassistant/DaBRThrustComputer.kt +++ b/src/main/kotlin/nl/enjarai/doabarrelroll/compat/flightassistant/DaBRThrustComputer.kt @@ -32,7 +32,7 @@ class DaBRThrustComputer(computers: ComputerView) : Computer(computers), ThrustS } override fun calculateThrustForSpeed(targetSpeed: Float): Float { - return targetSpeed / (ModConfig.INSTANCE.maxThrust * 20.0).toFloat().coerceIn(-1.0f..1.0f) + return (targetSpeed / (ModConfig.INSTANCE.maxThrust * 20.0).toFloat()).coerceIn(-1.0f..1.0f) } override fun tick() { diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/api/util/extensions/CollectionExtensions.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/api/util/extensions/CollectionExtensions.kt index 1a51a01..91c6d43 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/api/util/extensions/CollectionExtensions.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/api/util/extensions/CollectionExtensions.kt @@ -30,3 +30,13 @@ fun List.getHighestPriority(): List { fun List.filterNonFaulted(): List { return this.filter { it !is Computer || !it.faulted} } + +fun > T.clearAndAdd(element: E) { + this.clear() + this.add(element) +} + +fun > T.clearAndAdd(vararg elements: E) { + this.clear() + this.addAll(elements) +} diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/AutopilotLogicComputer.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/AutopilotLogicComputer.kt index 6890498..fd0e2e8 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/AutopilotLogicComputer.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/AutopilotLogicComputer.kt @@ -1,5 +1,6 @@ package ru.octol1ttle.flightassistant.impl.computer.autoflight +import kotlin.math.abs import net.minecraft.text.Text import net.minecraft.util.Identifier import ru.octol1ttle.flightassistant.FlightAssistant @@ -8,29 +9,41 @@ import ru.octol1ttle.flightassistant.api.computer.Computer import ru.octol1ttle.flightassistant.api.computer.ComputerView class AutopilotLogicComputer(computers: ComputerView) : Computer(computers) { - var thrustMode: ThrustMode = ThrustMode(ThrustMode.Type.SelectedSpeed, 15.0f) + var thrustMode: ThrustMode = ThrustMode(ThrustMode.Type.SelectedSpeed, 0.0f) var verticalMode: VerticalMode = VerticalMode(VerticalMode.Type.SelectedPitch, 0.0f) var lateralMode: LateralMode = LateralMode(LateralMode.Type.SelectedHeading, 360.0f) - fun computeThrust(): ControlInput { + fun computeThrust(): ControlInput? { return when (thrustMode.type) { ThrustMode.Type.SelectedSpeed -> ControlInput( computers.thrust.calculateThrustForSpeed(thrustMode.speed) ?: 0.0f, ControlInput.Priority.NORMAL, - Text.translatable("mode.flightassistant.thrust.selected_speed"), + Text.translatable("mode.flightassistant.thrust.selected_speed", thrustMode.speed.toInt()), identifier = ID ) - ThrustMode.Type.VerticalTarget -> TODO() + ThrustMode.Type.VerticalTarget -> + if (!verticalMode.isAltitude()) null + else { + val useClimbThrust: Boolean = abs(verticalMode.pitchOrAltitude - (computers.data.altitude + computers.data.velocity.y * 20)) < 5.0f + ControlInput( + if (useClimbThrust) thrustMode.climbThrust!! else thrustMode.descendThrust!!, + ControlInput.Priority.NORMAL, + if (useClimbThrust) Text.translatable("mode.flightassistant.thrust.climb") else + if (thrustMode.descendThrust!! != 0.0f) Text.translatable("mode.flightassistant.thrust.descend") + else Text.translatable("mode.flightassistant.thrust.idle"), + identifier = ID + ) + } ThrustMode.Type.WaypointThrust -> TODO() } } - fun computePitch(active: Boolean): ControlInput { + fun computePitch(active: Boolean): ControlInput? { TODO() } - fun computeHeading(active: Boolean): ControlInput { + fun computeHeading(active: Boolean): ControlInput? { TODO() } @@ -40,7 +53,7 @@ class AutopilotLogicComputer(computers: ComputerView) : Computer(computers) { override fun reset() { } - class ThrustMode(var type: Type, var speed: Float) { + class ThrustMode(var type: Type, var speed: Float, var climbThrust: Float? = null, var descendThrust: Float? = null) { enum class Type { SelectedSpeed, VerticalTarget, @@ -54,6 +67,10 @@ class AutopilotLogicComputer(computers: ComputerView) : Computer(computers) { SelectedAltitude, WaypointAltitude } + + fun isAltitude(): Boolean { + return type == Type.SelectedAltitude || type == Type.WaypointAltitude + } } class LateralMode(var type: Type, var heading: Float? = null, var x: Double? = null, var z: Double? = null) { diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/ThrustComputer.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/ThrustComputer.kt index aa36410..1551d42 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/ThrustComputer.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/computer/autoflight/ThrustComputer.kt @@ -94,7 +94,7 @@ class ThrustComputer(computers: ComputerView) : Computer(computers) { fun setTarget(target: Float, input: ControlInput? = null) { val oldThrust: Float = current - if (oldThrust != target) { + if (oldThrust != target || input == null) { current = target ThrustChangeCallback.EVENT.invoker().onThrustChange(oldThrust, current, input) lastChangeAutomatic = input != null diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/display/AutomationModesDisplay.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/display/AutomationModesDisplay.kt index 4b68046..f0de5ed 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/impl/display/AutomationModesDisplay.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/impl/display/AutomationModesDisplay.kt @@ -13,6 +13,7 @@ import ru.octol1ttle.flightassistant.api.display.HudFrame import ru.octol1ttle.flightassistant.api.util.FATickCounter import ru.octol1ttle.flightassistant.api.util.extensions.* import ru.octol1ttle.flightassistant.config.FAConfig +import ru.octol1ttle.flightassistant.impl.computer.autoflight.AutopilotLogicComputer class AutomationModesDisplay(computers: ComputerView) : Display(computers) { private val thrustDisplay: ModeDisplay = ModeDisplay(1) { toPair(computers.thrust.activeInput) } @@ -24,7 +25,8 @@ class AutomationModesDisplay(computers: ComputerView) : Display(computers) { text.appendWithSeparation(Text.translatable("short.flightassistant.flight_directors")) } if (computers.automations.autoThrust) { - text.appendWithSeparation(Text.translatable("short.flightassistant.auto_thrust")) + val autoThrustText = Text.translatable("short.flightassistant.auto_thrust") + text.appendWithSeparation(if (computers.thrust.activeInput?.identifier == AutopilotLogicComputer.ID) autoThrustText else autoThrustText.styled { it.withColor(advisoryColor) }) } if (computers.automations.autopilot) { text.appendWithSeparation(Text.translatable("short.flightassistant.autopilot")) diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/screen/AutoFlightScreen.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/screen/AutoFlightScreen.kt index 0ff4009..535e393 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/screen/AutoFlightScreen.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/screen/AutoFlightScreen.kt @@ -1,6 +1,7 @@ package ru.octol1ttle.flightassistant.screen import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.Element import net.minecraft.text.Text import net.minecraft.util.Formatting import ru.octol1ttle.flightassistant.api.computer.ComputerView @@ -28,7 +29,16 @@ class AutoFlightScreen : FABaseScreen(Text.translatable("menu.flightassistant.au computers.automations.setAutoPilot(!computers.automations.autopilot, true) }.position(this.centerX + 5, this.centerY + 80).width(95).build()) - this.addDrawableChild(ThrustModeWidget(computers)) + this.addDrawableChild(ThrustModeWidget(computers, 0, this.height / 3, this.width / 3)) + } + + override fun close() { + super.close() + for (child: Element in children()) { + if (child is AutoCloseable) { + child.close() + } + } } override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { diff --git a/src/main/kotlin/ru/octol1ttle/flightassistant/screen/widgets/autoflight/ThrustModeWidget.kt b/src/main/kotlin/ru/octol1ttle/flightassistant/screen/widgets/autoflight/ThrustModeWidget.kt index 3a94741..dad33d4 100644 --- a/src/main/kotlin/ru/octol1ttle/flightassistant/screen/widgets/autoflight/ThrustModeWidget.kt +++ b/src/main/kotlin/ru/octol1ttle/flightassistant/screen/widgets/autoflight/ThrustModeWidget.kt @@ -1,43 +1,114 @@ package ru.octol1ttle.flightassistant.screen.widgets.autoflight -import java.util.ArrayList import java.util.EnumMap +import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.Element import net.minecraft.client.gui.widget.ButtonWidget import net.minecraft.client.gui.widget.TextFieldWidget +import net.minecraft.client.gui.widget.TextWidget import net.minecraft.text.Text import ru.octol1ttle.flightassistant.FlightAssistant.mc import ru.octol1ttle.flightassistant.api.computer.ComputerView +import ru.octol1ttle.flightassistant.api.util.extensions.clearAndAdd import ru.octol1ttle.flightassistant.impl.computer.autoflight.AutopilotLogicComputer import ru.octol1ttle.flightassistant.screen.widgets.AbstractParentWidget -class ThrustModeWidget(val computers: ComputerView) : AbstractParentWidget() { - private val buttons: EnumMap = EnumMap(AutopilotLogicComputer.ThrustMode.Type::class.java) - private val textFields: EnumMap> = EnumMap(AutopilotLogicComputer.ThrustMode.Type::class.java) +// TODO: fix dimensions +class ThrustModeWidget(val computers: ComputerView, val x: Int, val y: Int, val width: Int) : AbstractParentWidget(), AutoCloseable { + private val title: TextWidget = TextWidget( + x, y, width, 20, Text.translatable("menu.flightassistant.autoflight.thrust"), mc.textRenderer + ) + private var newType: AutopilotLogicComputer.ThrustMode.Type = computers.autopilot.thrustMode.type init { - buttons[AutopilotLogicComputer.ThrustMode.Type.SelectedSpeed] = ButtonWidget.builder( + initSelectedSpeed() + initVerticalTarget() + + buttons[AutopilotLogicComputer.ThrustMode.Type.WaypointThrust] = ButtonWidget.builder( + Text.translatable("menu.flightassistant.autoflight.thrust.waypoint_thrust") + ) { newType = AutopilotLogicComputer.ThrustMode.Type.WaypointThrust } + .dimensions(x, y + 20, width / 3 - 5, 15).build() + } + + private fun initSelectedSpeed() { + val type = AutopilotLogicComputer.ThrustMode.Type.SelectedSpeed + + buttons[type] = ButtonWidget.builder( Text.translatable("menu.flightassistant.autoflight.thrust.selected_speed") - ) { computers.autopilot.thrustMode.type = AutopilotLogicComputer.ThrustMode.Type.SelectedSpeed }.build() - textFields[AutopilotLogicComputer.ThrustMode.Type.SelectedSpeed] = TextFieldWidget( - mc.textRenderer, TODO() + ) { newType = type } + .dimensions(x, y + 20, (width - 15) / 3, 15).build() + val targetSpeedWidget = TextFieldWidget( + mc.textRenderer, x + width / 4, y + 40, width / 2, 15, textFields[type]?.singleOrNull(), Text.empty() ) + targetSpeedWidget.setPlaceholder(Text.translatable("menu.flightassistant.autoflight.thrust.selected_speed.target")) + targetSpeedWidget.setTextPredicate { + val i: Int? = it.toIntOrNull() + it.isEmpty() || i != null && i > 0 + } + textFields.computeIfAbsent(type) { ArrayList() }.clearAndAdd(targetSpeedWidget) + } + private fun initVerticalTarget() { + val type = AutopilotLogicComputer.ThrustMode.Type.VerticalTarget - buttons[AutopilotLogicComputer.ThrustMode.Type.VerticalTarget] = ButtonWidget.builder( + buttons[type] = ButtonWidget.builder( Text.translatable("menu.flightassistant.autoflight.thrust.vertical_target") - ) { computers.autopilot.thrustMode.type = AutopilotLogicComputer.ThrustMode.Type.VerticalTarget }.build() - buttons[AutopilotLogicComputer.ThrustMode.Type.WaypointThrust] = ButtonWidget.builder( - Text.translatable("menu.flightassistant.autoflight.thrust.waypoint_thrust") - ) { computers.autopilot.thrustMode.type = AutopilotLogicComputer.ThrustMode.Type.WaypointThrust }.build() + ) { newType = type } + .dimensions(x + (width - 15) / 3, y + 20, (width - 15) / 3, 15).build() + + val climbThrustWidget = TextFieldWidget( + mc.textRenderer, x, y + 40, (width - 10) / 2, 15, textFields[type]?.firstOrNull(), Text.empty() + ) + climbThrustWidget.setPlaceholder(Text.translatable("menu.flightassistant.autoflight.thrust.vertical_target.climb_thrust")) + climbThrustWidget.setTextPredicate { + val i: Int? = it.toIntOrNull() + it.isEmpty() || i != null && i in 0..100 + } + + val descendThrustWidget = TextFieldWidget( + mc.textRenderer, x + width / 2, y + 40, (width - 10) / 2, 15, textFields[type]?.firstOrNull(), Text.empty() + ) + descendThrustWidget.setPlaceholder(Text.translatable("menu.flightassistant.autoflight.thrust.vertical_target.descend_thrust")) + descendThrustWidget.setTextPredicate { + val i: Int? = it.toIntOrNull() + it.isEmpty() || i != null && i in 0..100 + } + + textFields.computeIfAbsent(type) { ArrayList() }.clearAndAdd(climbThrustWidget, descendThrustWidget) } override fun children(): MutableList { val list = ArrayList() + list.add(title) list.addAll(buttons.values) textFields[computers.autopilot.thrustMode.type]?.let { list.addAll(it) } return list } + + override fun close() { + computers.autopilot.thrustMode.type = newType + when (val type: AutopilotLogicComputer.ThrustMode.Type = computers.autopilot.thrustMode.type) { + AutopilotLogicComputer.ThrustMode.Type.SelectedSpeed -> computers.autopilot.thrustMode.speed = textFields[type]!!.single().text.toFloatOrNull() ?: 0.0f + AutopilotLogicComputer.ThrustMode.Type.VerticalTarget -> { + computers.autopilot.thrustMode.climbThrust = (textFields[type]!!.first().text.toIntOrNull() ?: 0) / 100.0f + computers.autopilot.thrustMode.descendThrust = (textFields[type]!![1].text.toIntOrNull() ?: 0) / 100.0f + } + else -> Unit + } + } + + override fun render(context: DrawContext?, mouseX: Int, mouseY: Int, delta: Float) { + for (button in buttons) { + button.value.active = computers.autopilot.thrustMode.type != button.key + } + + super.render(context, mouseX, mouseY, delta) + } + + companion object { + private val buttons: EnumMap = EnumMap(AutopilotLogicComputer.ThrustMode.Type::class.java) + private val textFields: EnumMap> = EnumMap(AutopilotLogicComputer.ThrustMode.Type::class.java) + } } diff --git a/src/main/resources/assets/flightassistant/lang/en_us.yml b/src/main/resources/assets/flightassistant/lang/en_us.yml index 51c2600..b2ecedb 100644 --- a/src/main/resources/assets/flightassistant/lang/en_us.yml +++ b/src/main/resources/assets/flightassistant/lang/en_us.yml @@ -207,7 +207,7 @@ menu.flightassistant: flightassistant:flight_path: Flight path display flightassistant:heading: Heading display flightassistant:radar_altitude: Radar altitude display - flightassistant:speed: Speed + flightassistant:speed: Speed display flightassistant:velocity_components: G/S & V/S display computer: flightassistant:air_data: Air data computer @@ -231,9 +231,15 @@ menu.flightassistant: auto_thrust: Auto thrust autopilot: Autopilot thrust: - selected_speed: SPD - vertical_target: VERT - waypoint_thrust: F/PLN + .: Thrust + selected_speed: + .: SPEED + target: Target speed + vertical_target: + .: VERT + climb_thrust: Climb thrust + descend_thrust: Descend thrust + waypoint_thrust: F/PLAN mode.flightassistant: thrust: @@ -241,8 +247,11 @@ mode.flightassistant: manual_toga: MAN TOGA locked: THR LK %s locked_toga: TOGA LK + idle: THR IDLE toga: THR TOGA selected_speed: SPD %s + climb: THR CLB + descend: THR DES pitch: void_protection: VOID PROT void_escape: VOID ESC diff --git a/src/main/resources/assets/flightassistant/lang/ru_ru.yml b/src/main/resources/assets/flightassistant/lang/ru_ru.yml index eb10516..4addada 100644 --- a/src/main/resources/assets/flightassistant/lang/ru_ru.yml +++ b/src/main/resources/assets/flightassistant/lang/ru_ru.yml @@ -234,9 +234,16 @@ menu.flightassistant: flight_directors: Указатели полёта auto_thrust: Автомат тяги autopilot: Автопилот - speed: Скорость - pitch: Высота - heading: Курс + thrust: + .: Тяга + selected_speed: + .: СКОР + target: Целевая скор. + vertical_target: + .: ВЕРТ + climb_thrust: Тяга набора + descend_thrust: Тяга снижения + waypoint_thrust: ПЛАН/П mode.flightassistant: thrust: @@ -244,8 +251,11 @@ mode.flightassistant: manual_toga: РУЧН ВЗЛЕТН locked: БЛОК ТЯГА %s locked_toga: БЛОК ВЗЛЕТН + idle: ТЯГА МАЛ toga: ТЯГА ВЗЛЕТН - speed: СКОР %s + selected_speed: СКОР %s + climb: ТЯГА НАБОР + descend: ТЯГА СНИЖ pitch: void_protection: ПУСТ ЗАЩ void_escape: ПУСТ ВЫХОД