feat: Add /dh command

This commit is contained in:
Linnea Gräf
2024-12-23 23:02:08 +01:00
parent 22bc3adbae
commit 656958937f
7 changed files with 167 additions and 84 deletions

View File

@@ -51,7 +51,7 @@ public class FirmKeybindsInVanillaControlsPatch {
var config = FirmamentKeyBindings.INSTANCE.getKeyBindings().get(binding); var config = FirmamentKeyBindings.INSTANCE.getKeyBindings().get(binding);
if (config == null) return; if (config == null) return;
resetButton.active = false; resetButton.active = false;
editButton.setMessage(Text.translatable("firmament.keybinding.external", config.value.format())); editButton.setMessage(Text.translatable("firmament.keybinding.external", config.getValue().format()));
ci.cancel(); ci.cancel();
} }

View File

@@ -0,0 +1,17 @@
package moe.nea.firmament.mixins;
import moe.nea.firmament.features.chat.QuickCommands;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayNetworkHandler.class)
public class SaveOriginalCommandTreePacket {
@Inject(method = "onCommandTree", at = @At(value = "RETURN"))
private void saveUnmodifiedCommandTree(CommandTreeS2CPacket packet, CallbackInfo ci) {
QuickCommands.INSTANCE.setLastReceivedTreePacket(packet);
}
}

View File

@@ -1,8 +1,12 @@
package moe.nea.firmament.features.chat package moe.nea.firmament.features.chat
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.context.CommandContext
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.fabricmc.fabric.impl.command.client.ClientCommandInternals
import net.minecraft.command.CommandRegistryAccess
import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.DefaultSource import moe.nea.firmament.commands.DefaultSource
@@ -12,89 +16,139 @@ import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.gui.config.ManagedOption
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.grey
import moe.nea.firmament.util.tr
object QuickCommands : FirmamentFeature { object QuickCommands : FirmamentFeature {
override val identifier: String override val identifier: String
get() = "quick-commands" get() = "quick-commands"
fun removePartialPrefix(text: String, prefix: String): String? { object TConfig : ManagedConfig("quick-commands", Category.CHAT) {
var lf: String? = null val enableJoin by toggle("join") { true }
for (i in 1..prefix.length) { val enableDh by toggle("dh") { true }
if (text.startsWith(prefix.substring(0, i))) { override fun onChange(option: ManagedOption<*>) {
lf = text.substring(i) reloadCommands()
} }
} }
return lf
}
val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL") fun reloadCommands() {
val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN") val lastPacket = lastReceivedTreePacket ?: return
val network = MC.networkHandler ?: return
val fallback = ClientCommandInternals.getActiveDispatcher()
try {
val dispatcher = CommandDispatcher<FabricClientCommandSource>()
ClientCommandInternals.setActiveDispatcher(dispatcher)
ClientCommandRegistrationCallback.EVENT.invoker()
.register(dispatcher, CommandRegistryAccess.of(network.combinedDynamicRegistries,
network.enabledFeatures))
ClientCommandInternals.finalizeInit()
network.onCommandTree(lastPacket)
} catch (ex: Exception) {
ClientCommandInternals.setActiveDispatcher(fallback)
throw ex
}
}
@Subscribe
fun onCommands(it: CommandEvent) {
it.register("join") {
thenArgument("what", RestArgumentType) { what ->
thenExecute {
val what = this[what]
if (!SBData.isOnSkyblock) {
MC.sendCommand("join $what")
return@thenExecute
}
val joinName = getNameForFloor(what.replace(" ", "").lowercase())
if (joinName == null) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
} else {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success",
joinName))
MC.sendCommand("joininstance $joinName")
}
}
}
thenExecute {
source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain"))
}
}
}
fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? { fun removePartialPrefix(text: String, prefix: String): String? {
val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier") var lf: String? = null
if (kuudraLevel != null) { for (i in 1..prefix.length) {
val l = kuudraLevel.toIntOrNull()?.let { it - 1 } ?: kuudraLevelNames.indexOfFirst { if (text.startsWith(prefix.substring(0, i))) {
it.startsWith( lf = text.substring(i)
kuudraLevel, }
true }
) return lf
} }
if (l !in kuudraLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra", var lastReceivedTreePacket: CommandTreeS2CPacket? = null
kuudraLevel))
return null val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL")
} val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN")
return "KUUDRA_${kuudraLevelNames[l]}"
} @Subscribe
val masterLevel = removePartialPrefix(w, "master") fun registerDh(event: CommandEvent) {
val normalLevel = if (!TConfig.enableDh) return
removePartialPrefix(w, "floor") ?: removePartialPrefix(w, "catacombs") ?: removePartialPrefix(w, "dungeons") event.register("dh") {
val dungeonLevel = masterLevel ?: normalLevel thenExecute {
if (dungeonLevel != null) { MC.sendCommand("warp dhub")
val l = dungeonLevel.toIntOrNull()?.let { it - 1 } ?: dungeonLevelNames.indexOfFirst { }
it.startsWith( }
dungeonLevel, event.register("dn") {
true thenExecute {
) MC.sendChat(tr("firmament.quickwarp.deez-nutz", "Warping to... Deez Nuts!").grey())
} MC.sendCommand("warp dhub")
if (masterLevel == null && (l == -1 || null != removePartialPrefix(w, "entrance"))) { }
return "CATACOMBS_ENTRANCE" }
} }
if (l !in dungeonLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs", @Subscribe
kuudraLevel)) fun registerJoin(it: CommandEvent) {
return null if (!TConfig.enableJoin) return
} it.register("join") {
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}" thenArgument("what", RestArgumentType) { what ->
} thenExecute {
return null val what = this[what]
} if (!SBData.isOnSkyblock) {
MC.sendCommand("join $what")
return@thenExecute
}
val joinName = getNameForFloor(what.replace(" ", "").lowercase())
if (joinName == null) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
} else {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success",
joinName))
MC.sendCommand("joininstance $joinName")
}
}
}
thenExecute {
source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain"))
}
}
}
fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? {
val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier")
if (kuudraLevel != null) {
val l = kuudraLevel.toIntOrNull()?.let { it - 1 } ?: kuudraLevelNames.indexOfFirst {
it.startsWith(
kuudraLevel,
true
)
}
if (l !in kuudraLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra",
kuudraLevel))
return null
}
return "KUUDRA_${kuudraLevelNames[l]}"
}
val masterLevel = removePartialPrefix(w, "master")
val normalLevel =
removePartialPrefix(w, "floor") ?: removePartialPrefix(w, "catacombs") ?: removePartialPrefix(w, "dungeons")
val dungeonLevel = masterLevel ?: normalLevel
if (dungeonLevel != null) {
val l = dungeonLevel.toIntOrNull()?.let { it - 1 } ?: dungeonLevelNames.indexOfFirst {
it.startsWith(
dungeonLevel,
true
)
}
if (masterLevel == null && (l == -1 || null != removePartialPrefix(w, "entrance"))) {
return "CATACOMBS_ENTRANCE"
}
if (l !in dungeonLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs",
kuudraLevel))
return null
}
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}"
}
return null
}
} }

View File

@@ -15,7 +15,6 @@ import org.lwjgl.glfw.GLFW
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlin.enums.enumEntries
import kotlin.io.path.createDirectories import kotlin.io.path.createDirectories
import kotlin.io.path.readText import kotlin.io.path.readText
import kotlin.io.path.writeText import kotlin.io.path.writeText
@@ -135,7 +134,7 @@ abstract class ManagedConfig(
return StringIdentifiable.createCodec { x() } return StringIdentifiable.createCodec { x() }
} }
// TODO: wait on https://youtrack.jetbrains.com/issue/KT-73434 // TODO: wait on https://youtrack.jetbrains.com/issue/KT-73434
// protected inline fun <reified E> choice( // protected inline fun <reified E> choice(
// propertyName: String, // propertyName: String,
// noinline default: () -> E // noinline default: () -> E
@@ -148,6 +147,8 @@ abstract class ManagedConfig(
// default // default
// ) // )
// } // }
open fun onChange(option: ManagedOption<*>) {
}
protected fun duration( protected fun duration(
propertyName: String, propertyName: String,

View File

@@ -6,7 +6,6 @@ import kotlinx.serialization.json.JsonObject
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.ErrorUtil
class ManagedOption<T : Any>( class ManagedOption<T : Any>(
@@ -28,7 +27,13 @@ class ManagedOption<T : Any>(
val descriptionTranslationKey = "firmament.config.${element.name}.${propertyName}.description" val descriptionTranslationKey = "firmament.config.${element.name}.${propertyName}.description"
val labelDescription: Text = Text.translatable(descriptionTranslationKey) val labelDescription: Text = Text.translatable(descriptionTranslationKey)
lateinit var value: T private var actualValue: T? = null
var value: T
get() = actualValue ?: error("Lateinit variable not initialized")
set(value) {
actualValue = value
element.onChange(this)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value this.value = value

View File

@@ -3,6 +3,7 @@ accessible class net/minecraft/client/render/RenderLayer$MultiPhase
accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
accessible class net/minecraft/client/font/TextRenderer$Drawer accessible class net/minecraft/client/font/TextRenderer$Drawer
accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator; accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;
accessible field net/minecraft/client/network/ClientPlayNetworkHandler combinedDynamicRegistries Lnet/minecraft/registry/DynamicRegistryManager$Immutable;
accessible field net/minecraft/client/render/item/HeldItemRenderer itemRenderer Lnet/minecraft/client/render/item/ItemRenderer; accessible field net/minecraft/client/render/item/HeldItemRenderer itemRenderer Lnet/minecraft/client/render/item/ItemRenderer;
accessible field net/minecraft/client/render/item/ItemModels missingModelSupplier Ljava/util/function/Supplier; accessible field net/minecraft/client/render/item/ItemModels missingModelSupplier Ljava/util/function/Supplier;

View File

@@ -180,6 +180,11 @@
"firmament.config.pristine-profit.position.description": "Edit the pristine profit hud location.", "firmament.config.pristine-profit.position.description": "Edit the pristine profit hud location.",
"firmament.config.pristine-profit.timeout": "Timeout (0 = disabled)", "firmament.config.pristine-profit.timeout": "Timeout (0 = disabled)",
"firmament.config.pristine-profit.timeout.description": "Track the profit you make from pristine gemstones while mining. Set to 0 seconds to disable the HUD.", "firmament.config.pristine-profit.timeout.description": "Track the profit you make from pristine gemstones while mining. Set to 0 seconds to disable the HUD.",
"firmament.config.quick-commands": "Quick Commands",
"firmament.config.quick-commands.dh": "Enable /dh",
"firmament.config.quick-commands.dh.description": "Warps you to the dungeon hub.",
"firmament.config.quick-commands.join": "Enable /join",
"firmament.config.quick-commands.join.description": "Join various types of instances like dungeons using short hands like /join f1, /join k1, /join m7",
"firmament.config.repo": "Firmament Repo Settings", "firmament.config.repo": "Firmament Repo Settings",
"firmament.config.repo.autoUpdate": "Auto Update", "firmament.config.repo.autoUpdate": "Auto Update",
"firmament.config.repo.autoUpdate.description": "Automatically download new items for the item list on every startup.", "firmament.config.repo.autoUpdate.description": "Automatically download new items for the item list on every startup.",