aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/moe/nea/firmament/Firmament.kt6
-rw-r--r--src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt17
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt61
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt25
-rw-r--r--src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt42
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json184
7 files changed, 237 insertions, 100 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/Firmament.kt b/src/main/kotlin/moe/nea/firmament/Firmament.kt
index 1a2739e..e4b874a 100644
--- a/src/main/kotlin/moe/nea/firmament/Firmament.kt
+++ b/src/main/kotlin/moe/nea/firmament/Firmament.kt
@@ -14,13 +14,13 @@ import io.ktor.client.plugins.compression.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.serialization.kotlinx.json.*
-import java.lang.Exception
import java.nio.file.Files
import java.nio.file.Path
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
+import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents
import net.fabricmc.loader.api.FabricLoader
import net.fabricmc.loader.api.Version
@@ -41,6 +41,7 @@ import net.minecraft.command.CommandRegistryAccess
import net.minecraft.util.Identifier
import moe.nea.firmament.commands.registerFirmamentCommand
import moe.nea.firmament.dbus.FirmamentDbusObject
+import moe.nea.firmament.events.ItemTooltipEvent
import moe.nea.firmament.events.ScreenRenderPostEvent
import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FeatureManager
@@ -133,6 +134,9 @@ object Firmament {
globalJob.cancel()
}
})
+ ItemTooltipCallback.EVENT.register { a, b, c ->
+ ItemTooltipEvent.publish(ItemTooltipEvent(a, b, c))
+ }
ScreenEvents.AFTER_INIT.register(ScreenEvents.AfterInit { client, screen, scaledWidth, scaledHeight ->
ScreenEvents.afterRender(screen)
.register(ScreenEvents.AfterRender { screen, drawContext, mouseX, mouseY, tickDelta ->
diff --git a/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt
new file mode 100644
index 0000000..ba597cd
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt
@@ -0,0 +1,17 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.events
+
+import net.minecraft.client.item.TooltipContext
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+
+data class ItemTooltipEvent(
+ val stack: ItemStack, val context: TooltipContext, val lines: MutableList<Text>
+) : FirmamentEvent() {
+ companion object : FirmamentEventBus<ItemTooltipEvent>()
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
index facb821..91f5e03 100644
--- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
@@ -14,6 +14,7 @@ import moe.nea.firmament.features.debug.DebugView
import moe.nea.firmament.features.debug.DeveloperFeatures
import moe.nea.firmament.features.fixes.Fixes
import moe.nea.firmament.features.inventory.CraftingOverlay
+import moe.nea.firmament.features.inventory.PriceData
import moe.nea.firmament.features.inventory.SaveCursorPosition
import moe.nea.firmament.features.inventory.SlotLocking
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay
@@ -48,6 +49,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
loadFeature(ChatLinks)
loadFeature(SaveCursorPosition)
loadFeature(CustomSkyBlockTextures)
+ loadFeature(PriceData)
loadFeature(Fixes)
if (Firmament.DEBUG) {
loadFeature(DeveloperFeatures)
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt
new file mode 100644
index 0000000..3ae7b00
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.inventory
+
+import net.minecraft.text.Text
+import moe.nea.firmament.events.ItemTooltipEvent
+import moe.nea.firmament.features.FirmamentFeature
+import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.repo.HypixelStaticData
+import moe.nea.firmament.util.FirmFormatters
+import moe.nea.firmament.util.skyBlockId
+
+object PriceData : FirmamentFeature {
+ override val identifier: String
+ get() = "price-data"
+
+ object TConfig : ManagedConfig(identifier) {
+ val tooltipEnabled by toggle("enable-always") { true }
+ val enableKeybinding by keyBindingWithDefaultUnbound("enable-keybind")
+ }
+
+ override val config get() = TConfig
+
+ override fun onLoad() {
+ ItemTooltipEvent.subscribe {
+ if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) {
+ return@subscribe
+ }
+ val sbId = it.stack.skyBlockId
+ val bazaarData = HypixelStaticData.bazaarData[sbId]
+ val lowestBin = HypixelStaticData.lowestBin[sbId]
+ if (bazaarData != null) {
+ it.lines.add(Text.literal(""))
+ it.lines.add(
+ Text.translatable(
+ "firmament.tooltip.bazaar.sell-order",
+ FirmFormatters.toString(bazaarData.quickStatus.sellPrice, 1)
+ )
+ )
+ it.lines.add(
+ Text.translatable(
+ "firmament.tooltip.bazaar.buy-order",
+ FirmFormatters.toString(bazaarData.quickStatus.buyPrice, 1)
+ )
+ )
+ } else if (lowestBin != null) {
+ it.lines.add(Text.literal(""))
+ it.lines.add(
+ Text.translatable(
+ "firmament.tooltip.ah.lowestbin",
+ FirmFormatters.toString(lowestBin, 1)
+ )
+ )
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
index 8743293..8e05632 100644
--- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
+++ b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt
@@ -14,22 +14,23 @@ import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
+import moe.nea.jarvis.api.Point
+import org.lwjgl.glfw.GLFW
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
+import kotlin.io.path.createDirectories
+import kotlin.io.path.readText
+import kotlin.io.path.writeText
+import kotlin.time.Duration
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.WTightScrollPanel
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil.setScreenLater
-import moe.nea.jarvis.api.Point
-import net.minecraft.client.gui.screen.Screen
-import net.minecraft.text.Text
-import kotlin.io.path.createDirectories
-import kotlin.io.path.readText
-import kotlin.io.path.writeText
-import kotlin.time.Duration
abstract class ManagedConfig(override val name: String) : ManagedConfigElement() {
@@ -110,15 +111,21 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
protected fun keyBinding(
propertyName: String,
default: () -> Int,
- ): ManagedOption<SavedKeyBinding> = keyBindingWithDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
+ ): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
- protected fun keyBindingWithDefaultModifiers(
+ protected fun keyBindingWithOutDefaultModifiers(
propertyName: String,
default: () -> SavedKeyBinding,
): ManagedOption<SavedKeyBinding> {
return option(propertyName, default, KeyBindingHandler("firmament.config.${name}.${propertyName}", this))
}
+ protected fun keyBindingWithDefaultUnbound(
+ propertyName: String,
+ ): ManagedOption<SavedKeyBinding> {
+ return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) }
+ }
+
protected fun integer(
propertyName: String,
min: Int,
diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt
index e0f0c50..606485b 100644
--- a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt
+++ b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt
@@ -6,8 +6,11 @@
package moe.nea.firmament.keybindings
-import kotlinx.serialization.Serializable
import org.lwjgl.glfw.GLFW
+import kotlinx.serialization.Serializable
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.util.InputUtil
+import moe.nea.firmament.util.MC
@Serializable
data class SavedKeyBinding(
@@ -35,6 +38,43 @@ data class SavedKeyBinding(
}
}
+ fun hasShiftDown(): Boolean {
+ return InputUtil.isKeyPressed(
+ MinecraftClient.getInstance().window.handle,
+ GLFW.GLFW_KEY_LEFT_SHIFT
+ ) || InputUtil.isKeyPressed(
+ MinecraftClient.getInstance().window.handle, GLFW.GLFW_KEY_RIGHT_SHIFT
+ )
+ }
+
+ fun hasAltDown(): Boolean {
+ return InputUtil.isKeyPressed(
+ MinecraftClient.getInstance().window.handle,
+ GLFW.GLFW_KEY_LEFT_ALT
+ ) || InputUtil.isKeyPressed(
+ MinecraftClient.getInstance().window.handle, GLFW.GLFW_KEY_RIGHT_ALT
+ )
+ }
+
+ fun isPressed(): Boolean {
+ val h = MC.window.handle
+ if (!InputUtil.isKeyPressed(h, keyCode)) return false
+
+ val ctrl = if (MinecraftClient.IS_SYSTEM_MAC) {
+ InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER)
+ } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL)
+ val shift = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SHIFT)
+ val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT)
+
+ return (ctrl == this.ctrl) &&
+ (alt == this.alt) &&
+ (shift == this.shift)
+ }
+
override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
return keyCode == this.keyCode && getMods(modifiers) == Triple(shift, ctrl, alt)
}
diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json
index 8315cef..2058c4b 100644
--- a/src/main/resources/assets/firmament/lang/en_us.json
+++ b/src/main/resources/assets/firmament/lang/en_us.json
@@ -1,91 +1,97 @@
{
- "firmament.dev.resourcerebuild.start": "Invoking gradle resource rebuild (./gradlew :processResources)",
- "firmament.dev.resourcerebuild.done": "Gradle resource rebuild done in %s",
- "firmament.config.developer": "Developer Settings",
- "firmament.config.developer.auto-rebuild": "Automatically rebuild resources",
- "firmament.price": "Checking price for %s",
- "firmament.price.bazaar": "Bazaar stats:",
- "firmament.price.bazaar.productid": "Stock id: %s",
- "firmament.price.bazaar.buy.price": "Buy Price: %s",
- "firmament.price.bazaar.buy.order": "Buy orders: %d",
- "firmament.pv.pets": "Pets",
- "firmament.debug.skyblockid": "SkyBlock ID: %s",
- "firmament.debug.skyblockid.copy": "Click to copy SkyBlock ID",
- "firmament.price.bazaar.sell.price": "Sell Price: %s",
- "firmament.price.bazaar.sell.order": "Sell orders: %d",
- "firmament.price.lowestbin": "Lowest BIN: %s",
- "firmament.repo.reload.network": "Trying to redownload the repository",
- "firmament.repo.reload.disk": "Reloading repository from disk. This may lag a bit.",
- "firmament.repo.cache": "Recaching items",
- "firmament.repo.brokenitem": "Failed to render item: %s",
- "firmanent.config.edit": "Edit",
- "firmament.config.repo": "Firmament Repo Settings",
- "firmament.config.repo.autoUpdate": "Auto Update",
- "firmament.config.repo.username": "Repo Username",
- "firmament.config.repo.username.hint": "NotEnoughUpdates",
- "firmament.config.repo.reponame": "Repo Name",
- "firmament.config.repo.reponame.hint": "NotEnoughUpdates-REPO",
- "firmament.config.repo.branch": "Repo Branch",
- "firmament.config.repo.branch.hint": "dangerous",
- "firmament.config.repo.reset": "Reset",
- "firmament.ursa.debugrequest.start": "Ursa request launched",
- "firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
- "firmament.sbinfo.nolocraw": "No locraw data available",
- "firmament.sbinfo.profile": "Current profile cutename: %s",
- "firmament.sbinfo.server": "Locraw Server: %s",
- "firmament.sbinfo.gametype": "Locraw Gametype: %s",
- "firmament.sbinfo.mode": "Locraw Mode: %s",
- "firmament.sbinfo.map": "Locraw Map: %s",
- "firmament.config.fairy-souls": "Fairy Souls",
- "firmament.config.fairy-souls.show": "Show Fairy Soul Waypoints",
- "firmament.config.fairy-souls.reset": "Reset Collected Fairy Souls",
- "firmament.config.fishing-warning": "Fishing Warning",
- "firmament.config.fishing-warning.display-warning": "Display a warning when you are about to hook a fish",
- "firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles",
- "firmament.key.slotlocking": "Lock Slot / Slot Binding",
- "firmament.key.category": "Firmament",
- "firmament.protectitem": "Firmament protected your item: ",
- "firmament.recipe.forge.time": "Forging Time: %s",
- "firmament.pv.skills": "Skills",
- "firmament.pv.skills.farming": "Farming",
- "firmament.pv.skills.foraging": "Foraging",
- "firmament.pv.skills.mining": "Mining",
- "firmament.pv.skills.alchemy": "Alchemy",
- "firmament.pv.skills.taming": "Taming",
- "firmament.pv.skills.fishing": "Fishing",
- "firmament.pv.skills.runecrafting": "Runecrafting",
- "firmament.pv.skills.carpentry": "Carpentry",
- "firmament.pv.skills.combat": "Combat",
- "firmament.pv.skills.social": "Social",
- "firmament.pv.skills.rift": "Rift",
- "firmament.pv.skills.enchanting": "Enchanting",
- "firmament.pv.skills.total": "Total Exp: %s",
- "firmament.pv.lookingup": "Looking up %s",
- "firmament.pv.noprofile": "%s has no SkyBlock profiles",
- "firmament.pv.noplayer": "%s is not a Minecraft player",
- "firmament.config.save-cursor-position.enable": "Enable",
- "firmament.config.save-cursor-position.tolerance": "Tolerance",
- "firmament.config.save-cursor-position": "Save Cursor Position",
- "firmament.config.storage-overlay": "Storage Overlay",
- "firmament.config.storage-overlay.rows": "Rows",
- "firmament.config.storage-overlay.padding": "Padding",
- "firmament.config.storage-overlay.scroll-speed": "Scroll Speed",
- "firmament.config.storage-overlay.inverse-scroll": "Invert Scroll",
- "firmament.config.storage-overlay.margin": "Margin",
- "firmament.config.chat-links": "Chat Links",
- "firmament.config.chat-links.links-enabled": "Enable Clickable Links",
- "firmament.config.chat-links.image-enabled": "Enable Image Preview",
- "firmament.config.chat-links.allow-all-hosts": "Allow all Image Hosts",
- "firmament.config.chat-links.allowed-hosts": "Allowed Image Hosts",
- "firmament.config.chat-links.position": "Chat Image Preview",
- "firmament.hud.edit": "Edit %s",
- "firmament.keybinding.external": "External",
- "firmament.config.slot-locking": "Slot Locking",
- "firmament.config.slot-locking.lock": "Lock Slot",
- "firmament.config.fixes.auto-sprint": "Auto Sprint",
- "firmament.config.custom-skyblock-textures": "Custom SkyBlock Item Textures",
- "firmament.config.custom-skyblock-textures.cache-duration": "Model Cache Duration",
- "firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures",
- "firmament.config.fixes": "Fixes",
- "firmament.config.fixes.player-skins": "Fix unsigned Player Skins"
+ "firmament.dev.resourcerebuild.start": "Invoking gradle resource rebuild (./gradlew :processResources)",
+ "firmament.dev.resourcerebuild.done": "Gradle resource rebuild done in %s",
+ "firmament.config.developer": "Developer Settings",
+ "firmament.config.developer.auto-rebuild": "Automatically rebuild resources",
+ "firmament.price": "Checking price for %s",
+ "firmament.price.bazaar": "Bazaar stats:",
+ "firmament.price.bazaar.productid": "Stock id: %s",
+ "firmament.price.bazaar.buy.price": "Buy Price: %s",
+ "firmament.price.bazaar.buy.order": "Buy orders: %d",
+ "firmament.tooltip.bazaar.sell-order": "Bazaar Sell Order: %s",
+ "firmament.tooltip.bazaar.buy-order": "Bazaar Buy Order: %s",
+ "firmament.tooltip.ah.lowestbin": "Lowest BIN: %d",
+ "firmament.pv.pets": "Pets",
+ "firmament.debug.skyblockid": "SkyBlock ID: %s",
+ "firmament.debug.skyblockid.copy": "Click to copy SkyBlock ID",
+ "firmament.price.bazaar.sell.price": "Sell Price: %s",
+ "firmament.price.bazaar.sell.order": "Sell orders: %d",
+ "firmament.price.lowestbin": "Lowest BIN: %s",
+ "firmament.repo.reload.network": "Trying to redownload the repository",
+ "firmament.repo.reload.disk": "Reloading repository from disk. This may lag a bit.",
+ "firmament.repo.cache": "Recaching items",
+ "firmament.repo.brokenitem": "Failed to render item: %s",
+ "firmanent.config.edit": "Edit",
+ "firmament.config.repo": "Firmament Repo Settings",
+ "firmament.config.repo.autoUpdate": "Auto Update",
+ "firmament.config.repo.username": "Repo Username",
+ "firmament.config.repo.username.hint": "NotEnoughUpdates",
+ "firmament.config.repo.reponame": "Repo Name",
+ "firmament.config.repo.reponame.hint": "NotEnoughUpdates-REPO",
+ "firmament.config.repo.branch": "Repo Branch",
+ "firmament.config.repo.branch.hint": "dangerous",
+ "firmament.config.repo.reset": "Reset",
+ "firmament.ursa.debugrequest.start": "Ursa request launched",
+ "firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
+ "firmament.sbinfo.nolocraw": "No locraw data available",
+ "firmament.sbinfo.profile": "Current profile cutename: %s",
+ "firmament.sbinfo.server": "Locraw Server: %s",
+ "firmament.sbinfo.gametype": "Locraw Gametype: %s",
+ "firmament.sbinfo.mode": "Locraw Mode: %s",
+ "firmament.sbinfo.map": "Locraw Map: %s",
+ "firmament.config.price-data": "Price data",
+ "firmament.config.price-data.enable-always": "Enable Item Price",
+ "firmament.config.price-data.enable-keybind": "Enable only with Keybinding",
+ "firmament.config.fairy-souls": "Fairy Souls",
+ "firmament.config.fairy-souls.show": "Show Fairy Soul Waypoints",
+ "firmament.config.fairy-souls.reset": "Reset Collected Fairy Souls",
+ "firmament.config.fishing-warning": "Fishing Warning",
+ "firmament.config.fishing-warning.display-warning": "Display a warning when you are about to hook a fish",
+ "firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles",
+ "firmament.key.slotlocking": "Lock Slot / Slot Binding",
+ "firmament.key.category": "Firmament",
+ "firmament.protectitem": "Firmament protected your item: ",
+ "firmament.recipe.forge.time": "Forging Time: %s",
+ "firmament.pv.skills": "Skills",
+ "firmament.pv.skills.farming": "Farming",
+ "firmament.pv.skills.foraging": "Foraging",
+ "firmament.pv.skills.mining": "Mining",
+ "firmament.pv.skills.alchemy": "Alchemy",
+ "firmament.pv.skills.taming": "Taming",
+ "firmament.pv.skills.fishing": "Fishing",
+ "firmament.pv.skills.runecrafting": "Runecrafting",
+ "firmament.pv.skills.carpentry": "Carpentry",
+ "firmament.pv.skills.combat": "Combat",
+ "firmament.pv.skills.social": "Social",
+ "firmament.pv.skills.rift": "Rift",
+ "firmament.pv.skills.enchanting": "Enchanting",
+ "firmament.pv.skills.total": "Total Exp: %s",
+ "firmament.pv.lookingup": "Looking up %s",
+ "firmament.pv.noprofile": "%s has no SkyBlock profiles",
+ "firmament.pv.noplayer": "%s is not a Minecraft player",
+ "firmament.config.save-cursor-position.enable": "Enable",
+ "firmament.config.save-cursor-position.tolerance": "Tolerance",
+ "firmament.config.save-cursor-position": "Save Cursor Position",
+ "firmament.config.storage-overlay": "Storage Overlay",
+ "firmament.config.storage-overlay.rows": "Rows",
+ "firmament.config.storage-overlay.padding": "Padding",
+ "firmament.config.storage-overlay.scroll-speed": "Scroll Speed",
+ "firmament.config.storage-overlay.inverse-scroll": "Invert Scroll",
+ "firmament.config.storage-overlay.margin": "Margin",
+ "firmament.config.chat-links": "Chat Links",
+ "firmament.config.chat-links.links-enabled": "Enable Clickable Links",
+ "firmament.config.chat-links.image-enabled": "Enable Image Preview",
+ "firmament.config.chat-links.allow-all-hosts": "Allow all Image Hosts",
+ "firmament.config.chat-links.allowed-hosts": "Allowed Image Hosts",
+ "firmament.config.chat-links.position": "Chat Image Preview",
+ "firmament.hud.edit": "Edit %s",
+ "firmament.keybinding.external": "External",
+ "firmament.config.slot-locking": "Slot Locking",
+ "firmament.config.slot-locking.lock": "Lock Slot",
+ "firmament.config.fixes.auto-sprint": "Auto Sprint",
+ "firmament.config.custom-skyblock-textures": "Custom SkyBlock Item Textures",
+ "firmament.config.custom-skyblock-textures.cache-duration": "Model Cache Duration",
+ "firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures",
+ "firmament.config.fixes": "Fixes",
+ "firmament.config.fixes.player-skins": "Fix unsigned Player Skins"
}