[WIP] Remove LibGUI

This commit is contained in:
Linnea Gräf
2024-07-01 03:42:51 +02:00
parent dff1f9c0e2
commit 5ee4b8d925
44 changed files with 439 additions and 1141 deletions

View File

@@ -122,11 +122,9 @@ dependencies {
modImplementation(libs.fabric.loader)
modImplementation(libs.fabric.kotlin)
modImplementation(libs.modmenu)
modImplementation(libs.libgui)
modImplementation(libs.moulconfig)
modImplementation(libs.manninghamMills)
modCompileOnly(libs.explosiveenhancement)
include(libs.libgui)
include(libs.manninghamMills)
include(libs.moulconfig)

View File

@@ -44,7 +44,6 @@ moulconfig = { module = "org.notenoughupdates.moulconfig:modern", version.ref =
repoparser = { module = "moe.nea:neurepoparser", version.ref = "neurepoparser" }
dbus_java_core = { module = "com.github.hypfvieh:dbus-java-core", version.ref = "dbus_java" }
dbus_java_unixsocket = { module = "com.github.hypfvieh:dbus-java-transport-native-unixsocket", version.ref = "dbus_java" }
libgui = { module = "io.github.cottonmc:LibGui", version.ref = "libgui" }
mixinextras = { module = "io.github.llamalad7:mixinextras-fabric", version.ref = "mixinextras" }
jarvis_api = { module = "moe.nea.jarvis:jarvis-api", version.ref = "jarvis" }
jarvis_fabric = { module = "moe.nea.jarvis:jarvis-fabric", version.ref = "jarvis" }

View File

@@ -20,7 +20,6 @@ import moe.nea.firmament.features.world.FairySouls
import moe.nea.firmament.gui.config.AllConfigsGui
import moe.nea.firmament.gui.config.BooleanHandler
import moe.nea.firmament.gui.config.ManagedOption
import moe.nea.firmament.gui.profileviewer.ProfileViewer
import moe.nea.firmament.repo.HypixelStaticData
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.FirmFormatters
@@ -28,7 +27,6 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.unformattedString
fun firmamentCommand() = literal("firmament") {
@@ -127,19 +125,6 @@ fun firmamentCommand() = literal("firmament") {
}
}
}
thenLiteral("pv") {
thenExecute {
ProfileViewer.onCommand(source, MC.player!!.name.unformattedString)
}
thenArgument("name", string()) { name ->
suggestsList {
MC.world?.players?.filter { it.uuid?.version() == 4 }?.map { it.name.unformattedString } ?: listOf()
}
thenExecute {
ProfileViewer.onCommand(source, get(name))
}
}
}
thenLiteral("price") {
thenArgument("item", string()) { item ->
suggestsList { RepoManager.neuRepo.items.items.keys }
@@ -155,7 +140,7 @@ fun firmamentCommand() = literal("firmament") {
source.sendFeedback(
Text.stringifiedTranslatable(
"firmament.price.bazaar.buy.price",
FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1)
FirmFormatters.formatCommas(bazaarData.quickStatus.buyPrice, 1)
)
)
source.sendFeedback(
@@ -167,7 +152,7 @@ fun firmamentCommand() = literal("firmament") {
source.sendFeedback(
Text.stringifiedTranslatable(
"firmament.price.bazaar.sell.price",
FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1)
FirmFormatters.formatCommas(bazaarData.quickStatus.sellPrice, 1)
)
)
source.sendFeedback(
@@ -182,7 +167,7 @@ fun firmamentCommand() = literal("firmament") {
source.sendFeedback(
Text.stringifiedTranslatable(
"firmament.price.lowestbin",
FirmFormatters.formatCurrency(lowestBin, 1)
FirmFormatters.formatCommas(lowestBin, 1)
)
)
}

View File

@@ -6,12 +6,6 @@
package moe.nea.firmament.features.debug
import io.github.cottonmc.cotton.gui.client.CottonHud
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WDynamicLabel
import io.github.cottonmc.cotton.gui.widget.data.Axis
import java.util.stream.Collectors
import kotlin.time.Duration.Companion.seconds
import moe.nea.firmament.Firmament
import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature
@@ -36,23 +30,7 @@ object DebugView : FirmamentFeature {
}
fun recalculateDebugWidget() {
storedVariables.entries.removeIf { it.value.timer.passedTime() > 1.seconds }
debugWidget.streamChildren().collect(Collectors.toList()).forEach {
debugWidget.remove(it)
}
storedVariables.entries.forEach {
debugWidget.add(WDynamicLabel({ "${it.key}: ${it.value.obj}" }))
}
debugWidget.layout()
if (storedVariables.isNotEmpty()) {
CottonHud.add(debugWidget, 20, 20)
} else {
CottonHud.remove(debugWidget)
}
}
val debugWidget = WBox(Axis.VERTICAL)
override fun onLoad() {
TickEvent.subscribe {

View File

@@ -1,58 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.features.debug
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.Axis
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlin.reflect.KProperty1
import net.minecraft.text.Text
import moe.nea.firmament.gui.WSpacer
class ObjectRenderer(val box: WBox) {
var indent = 0
fun beginObject() {
indent++
}
fun endObject() {
indent--
}
fun emit(label: String, widget: WWidget) {
WSpacer(WBox(Axis.VERTICAL).also {
it.add(WWidget())
it.add(widget)
}, indent * 18)
}
fun <T : Any?> getDebuggingView(label: String, obj: T) {
if (obj == null) {
emit(label, WLabel(Text.literal("§cnull")))
return
}
if (obj is String) {
emit(label, WLabel(Text.literal(Json.encodeToString(obj))))
}
getObject(label, obj)
}
fun <T : Any> getObject(label: String, obj: T) {
emit(label, WLabel(Text.literal(obj::class.simpleName ?: "<unknown>")))
beginObject()
for (prop in obj::class.members.filterIsInstance<KProperty1<T, *>>()) {
val child = prop.get(obj)
getDebuggingView(prop.name, child)
}
endObject()
}
}

View File

@@ -39,17 +39,17 @@ object PriceData : FirmamentFeature {
it.lines.add(Text.literal(""))
it.lines.add(
Text.stringifiedTranslatable("firmament.tooltip.bazaar.sell-order",
FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1))
FirmFormatters.formatCommas(bazaarData.quickStatus.sellPrice, 1))
)
it.lines.add(
Text.stringifiedTranslatable("firmament.tooltip.bazaar.buy-order",
FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1))
FirmFormatters.formatCommas(bazaarData.quickStatus.buyPrice, 1))
)
} else if (lowestBin != null) {
it.lines.add(Text.literal(""))
it.lines.add(
Text.stringifiedTranslatable("firmament.tooltip.ah.lowestbin",
FirmFormatters.formatCurrency(lowestBin, 1))
FirmFormatters.formatCommas(lowestBin, 1))
)
}
}

View File

@@ -18,7 +18,7 @@ import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.gui.hud.MoulConfigHud
import moe.nea.firmament.util.BazaarPriceStrategy
import moe.nea.firmament.util.FirmFormatters.formatCurrency
import moe.nea.firmament.util.FirmFormatters.formatCommas
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
import moe.nea.firmament.util.formattedString
@@ -99,11 +99,11 @@ object PristineProfitTracker : FirmamentFeature {
if (collectionPerSecond == null || moneyPerSecond == null) return
ProfitHud.collectionCurrent = collectionPerSecond
ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection",
formatCurrency(collectionPerSecond * SECONDS_PER_HOUR,
formatCommas(collectionPerSecond * SECONDS_PER_HOUR,
1)).formattedString()
ProfitHud.moneyCurrent = moneyPerSecond
ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money",
formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1))
formatCommas(moneyPerSecond * SECONDS_PER_HOUR, 1))
.formattedString()
val data = DConfig.data
if (data != null) {

View File

@@ -7,8 +7,6 @@
package moe.nea.firmament.gui
import com.mojang.blaze3d.systems.RenderSystem
import io.github.cottonmc.cotton.gui.client.ScreenDrawing
import io.github.cottonmc.cotton.gui.widget.data.Texture
import io.github.notenoughupdates.moulconfig.common.MyResourceLocation
import io.github.notenoughupdates.moulconfig.common.RenderContext
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
@@ -33,6 +31,24 @@ class BarComponent(
return 8
}
data class Texture(
val identifier: Identifier,
val u1: Float, val v1: Float,
val u2: Float, val v2: Float,
) {
fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) {
context.drawTexturedQuad(
identifier,
x, y, x + width, x + height, 0,
u1, u2, v1, v2,
color.red / 255F,
color.green / 255F,
color.blue / 255F,
color.alpha / 255F,
)
}
}
companion object {
val resource = Firmament.identifier("textures/gui/bar.png")
val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F)
@@ -51,20 +67,21 @@ class BarComponent(
sectionEnd: Double
) {
if (sectionEnd < progress.get() && width == 4) {
ScreenDrawing.texturedRect(context, x, y, 4, 8, texture, fillColor.color)
texture.draw(context, x, y, 4, 8, fillColor)
return
}
if (sectionStart > progress.get() && width == 4) {
ScreenDrawing.texturedRect(context, x, y, 4, 8, texture, emptyColor.color)
texture.draw(context, x, y, 4, 8, emptyColor)
return
}
val increasePerPixel = (sectionEnd - sectionStart) / width
var valueAtPixel = sectionStart
for (i in (0 until width)) {
ScreenDrawing.texturedRect(
val newTex =
Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2)
newTex.draw(
context, x + i, y, 1, 8,
texture.image, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2,
if (valueAtPixel < progress.get()) fillColor.color else emptyColor.color
if (valueAtPixel < progress.get()) fillColor else emptyColor
)
valueAtPixel += increasePerPixel
}

View File

@@ -15,14 +15,15 @@ import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
class FirmButtonComponent(
open class FirmButtonComponent(
child: GuiComponent,
val isEnabled: GetSetter<Boolean> = GetSetter.constant(true),
val action: Runnable,
val isEnabled: GetSetter<Boolean> = GetSetter.constant(true)
) : PanelComponent(child) {
/* TODO: make use of vanillas built in nine slicer */
val hoveredBg = NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_highlighted.png"))
val hoveredBg =
NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_highlighted.png"))
.cornerSize(5)
.cornerUv(5 / 200F, 5 / 20F)
.mode(NinePatch.Mode.STRETCHING)
@@ -32,7 +33,13 @@ class FirmButtonComponent(
.cornerUv(5 / 200F, 5 / 20F)
.mode(NinePatch.Mode.STRETCHING)
.build()
val disabledBg = NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_disabled.png"))
val disabledBg =
NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_disabled.png"))
.cornerSize(5)
.cornerUv(5 / 200F, 5 / 20F)
.mode(NinePatch.Mode.STRETCHING)
.build()
val activeBg = NinePatch.builder(MyResourceLocation("firmament", "textures/gui/sprites/widget/button_active.png"))
.cornerSize(5)
.cornerUv(5 / 200F, 5 / 20F)
.mode(NinePatch.Mode.STRETCHING)
@@ -59,12 +66,15 @@ class FirmButtonComponent(
return false
}
open fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> =
if (!isEnabled.get()) disabledBg
else if (context.isHovered || isClicking) hoveredBg
else unhoveredBg
override fun render(context: GuiImmediateContext) {
context.renderContext.pushMatrix()
context.renderContext.drawNinePatch(
if (!isEnabled.get()) disabledBg
else if (context.isHovered || isClicking) hoveredBg
else unhoveredBg,
getBackground(context),
0f, 0f, context.width, context.height
)
context.renderContext.translate(insets.toFloat(), insets.toFloat(), 0f)

View File

@@ -14,20 +14,20 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter
import java.util.function.BiFunction
class FixedComponent(
val fixedWidth: GetSetter<Int>,
val fixedHeight: GetSetter<Int>,
val fixedWidth: GetSetter<Int>?,
val fixedHeight: GetSetter<Int>?,
val component: GuiComponent,
) : GuiComponent() {
override fun getWidth(): Int = fixedWidth.get()
override fun getWidth(): Int = fixedWidth?.get() ?: component.width
override fun getHeight(): Int = fixedHeight.get()
override fun getHeight(): Int = fixedHeight?.get() ?: component.height
override fun <T : Any?> foldChildren(initial: T, visitor: BiFunction<GuiComponent, T, T>): T {
return visitor.apply(component, initial)
}
fun fixContext(context: GuiImmediateContext): GuiImmediateContext =
context.translated(0, 0, fixedWidth.get(), fixedHeight.get())
context.translated(0, 0, width, height)
override fun render(context: GuiImmediateContext) {
component.render(fixContext(context))

View File

@@ -1,79 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import com.mojang.blaze3d.systems.RenderSystem
import io.github.cottonmc.cotton.gui.client.ScreenDrawing
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.Texture
import me.shedaniel.math.Color
import net.minecraft.client.gui.DrawContext
import moe.nea.firmament.Firmament
open class WBar(
var progress: Double,
var total: Double,
val fillColor: Color,
val emptyColor: Color = fillColor.darker(2.0),
) : WWidget() {
companion object {
val resource = Firmament.identifier("textures/gui/bar.png")
val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F)
val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F)
val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F)
val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F)
}
override fun canResize(): Boolean {
return true
}
private fun drawSection(
context: DrawContext,
texture: Texture,
x: Int,
y: Int,
width: Int,
sectionStart: Double,
sectionEnd: Double
) {
if (sectionEnd < progress && width == 4) {
ScreenDrawing.texturedRect(context, x, y, 4, 8, texture, fillColor.color)
return
}
if (sectionStart > progress && width == 4) {
ScreenDrawing.texturedRect(context, x, y, 4, 8, texture, emptyColor.color)
return
}
val increasePerPixel = (sectionEnd - sectionStart / 4)
var valueAtPixel = sectionStart
for (i in (0 until width)) {
ScreenDrawing.texturedRect(
context, x + i, y, 1, 8,
texture.image, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2,
if (valueAtPixel < progress) fillColor.color else emptyColor.color
)
valueAtPixel += increasePerPixel
}
}
override fun paint(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int) {
var i = 0
while (i < width - 4) {
drawSection(
context,
if (i == 0) left else middle,
x + i, y,
(width - (i + 4)).coerceAtMost(4),
i * total / width, (i + 4) * total / width
)
i += 4
}
drawSection(context, right, x + width - 4, y, 4, (width - 4) * total / width, total)
RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
}
}

View File

@@ -1,40 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import io.github.cottonmc.cotton.gui.widget.WPanel
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.Axis
data class WCenteringPanel(
val child: WWidget,
val axis: Axis,
) : WPanel() {
init {
child.parent = this
}
override fun setSize(x: Int, y: Int) {
super.setSize(x, y)
if (!child.canResize()) return
if (axis == Axis.HORIZONTAL) {
child.setSize(child.width, y)
} else {
child.setSize(x, child.height)
}
}
override fun layout() {
super.layout()
child.setLocation(
axis.choose((child.width + width) / 2, child.x),
axis.choose(child.y, (child.height + height) / 2),
)
}
}

View File

@@ -1,32 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import io.github.cottonmc.cotton.gui.widget.WPanel
import io.github.cottonmc.cotton.gui.widget.WWidget
class WFixedPanel() : WPanel() {
var child: WWidget
set(value) {
children.clear()
setSize(0, 0)
value.parent = this
children.add(value)
}
get() = children.single()
constructor(child: WWidget) : this() {
this.child = child
}
override fun layout() {
setSize(0, 0)
super.layout()
}
override fun canResize(): Boolean = false
}

View File

@@ -1,25 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import io.github.cottonmc.cotton.gui.widget.WPanel
import io.github.cottonmc.cotton.gui.widget.WWidget
class WSpacer(val child: WWidget, val spaceLeft: Int) : WPanel() {
init {
children.add(child)
child.setLocation(spaceLeft, 0)
}
override fun getWidth(): Int {
return child.width + spaceLeft
}
override fun getHeight(): Int {
return child.height
}
}

View File

@@ -1,29 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import io.github.cottonmc.cotton.gui.widget.WPanel
import io.github.cottonmc.cotton.gui.widget.WPanelWithInsets
import io.github.cottonmc.cotton.gui.widget.WWidget
class WSplitPanel(val left: WWidget, val right: WWidget) : WPanelWithInsets() {
init {
left.parent = this
right.parent = this
children.add(left)
children.add(right)
}
override fun layout() {
expandToFit(left, insets)
expandToFit(right, insets)
(left as? WPanel)?.layout()
(right as? WPanel)?.layout()
left.setLocation(insets.left, insets.top)
right.setLocation(width - insets.right - right.width, insets.top)
}
}

View File

@@ -1,18 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import io.github.cottonmc.cotton.gui.widget.WPanel
import io.github.cottonmc.cotton.gui.widget.WScrollPanel
import io.github.cottonmc.cotton.gui.widget.WWidget
class WTightScrollPanel(val widget: WWidget, val margin: Int = 3) : WScrollPanel(widget) {
override fun setSize(x: Int, y: Int) {
(widget as? WPanel)?.layout()
super.setSize(widget.width + 8 + margin, y)
}
}

View File

@@ -1,39 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui
import com.mojang.blaze3d.systems.RenderSystem
import io.github.cottonmc.cotton.gui.client.BackgroundPainter
import io.github.cottonmc.cotton.gui.widget.TooltipBuilder
import io.github.cottonmc.cotton.gui.widget.WWidget
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.item.TooltipType
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import moe.nea.firmament.util.MC
open class WTitledItem(var stack: ItemStack, val countString: Text = Text.empty()) : WWidget() {
var backgroundPainter: BackgroundPainter = BackgroundPainter.SLOT
override fun canResize(): Boolean = true
override fun paint(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int) {
backgroundPainter.paintBackground(context, x, y, this)
context.matrices.push()
context.matrices.translate(x.toFloat(), y.toFloat(), 0F)
context.matrices.scale(width / 18F, height / 18F, 1F)
RenderSystem.enableDepthTest()
context.drawItemWithoutEntity(stack, 18 / 2 - 8, 18 / 2 - 8)
context.matrices.translate(0F, 0F, 200F)
context.drawText(MC.font, countString, 19 - 2 - MC.font.getWidth(countString), 6 + 3, 0xFFFFFF, true)
context.matrices.pop()
}
override fun addTooltip(tooltip: TooltipBuilder) {
tooltip.add(*stack.getTooltip(null, null, TooltipType.BASIC).toTypedArray())
}
}

View File

@@ -6,7 +6,9 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WToggleButton
import io.github.notenoughupdates.moulconfig.gui.component.CenterComponent
import io.github.notenoughupdates.moulconfig.gui.component.SwitchComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.boolean
@@ -24,13 +26,16 @@ class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Bo
override fun emitGuiElements(opt: ManagedOption<Boolean>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow(
opt.labelText,
WToggleButton(opt.labelText).apply {
guiAppender.onReload { toggle = opt.value }
setOnToggle {
opt.value = it
CenterComponent(SwitchComponent(object : GetSetter<Boolean> {
override fun get(): Boolean {
return opt.get()
}
override fun set(newValue: Boolean) {
opt.set(newValue)
config.save()
}
}
)
}, 200)
))
}
}

View File

@@ -6,9 +6,9 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WButton
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import kotlinx.serialization.json.JsonElement
import net.minecraft.text.Text
import moe.nea.firmament.gui.FirmButtonComponent
class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : ManagedConfig.OptionHandler<Unit> {
override fun toJson(element: Unit): JsonElement? {
@@ -19,12 +19,10 @@ class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : Manage
override fun emitGuiElements(opt: ManagedOption<Unit>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow(
Text.translatable("firmament.config.${config.name}.${opt.propertyName}"),
WButton(Text.translatable("firmament.config.${config.name}.${opt.propertyName}")).apply {
setOnClick {
runnable()
}
},
opt.labelText,
FirmButtonComponent(
TextComponent(opt.labelText.string),
action = runnable),
)
}
}

View File

@@ -6,18 +6,16 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WSlider
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
import java.util.function.IntConsumer
import io.github.notenoughupdates.moulconfig.common.IMinecraft
import io.github.notenoughupdates.moulconfig.gui.component.RowComponent
import io.github.notenoughupdates.moulconfig.gui.component.SliderComponent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.long
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.DurationUnit
import kotlin.time.toDuration
import net.minecraft.text.Text
@@ -34,22 +32,31 @@ class DurationHandler(val config: ManagedConfig, val min: Duration, val max: Dur
}
override fun emitGuiElements(opt: ManagedOption<Duration>, guiAppender: GuiAppender) {
val label =
WLabel(Text.literal(FirmFormatters.formatTimespan(opt.value))).setVerticalAlignment(VerticalAlignment.CENTER)
guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also {
it.add(label, 40, 18)
it.add(WSlider(min.inWholeMilliseconds.toInt(), max.inWholeMilliseconds.toInt(), Axis.HORIZONTAL).apply {
valueChangeListener = IntConsumer {
opt.value = it.milliseconds
label.text = Text.literal(FirmFormatters.formatTimespan(opt.value))
config.save()
guiAppender.appendLabeledRow(
opt.labelText,
RowComponent(
TextComponent(IMinecraft.instance.defaultFontRenderer,
{ FirmFormatters.formatTimespan(opt.value) },
40,
TextComponent.TextAlignment.CENTER,
true,
false),
SliderComponent(
object : GetSetter<Float> {
override fun get(): Float {
return opt.value.toDouble(DurationUnit.SECONDS).toFloat()
}
guiAppender.onReload {
value = opt.value.inWholeMilliseconds.toInt()
label.text = Text.literal(FirmFormatters.formatTimespan(opt.value))
override fun set(newValue: Float) {
opt.value = newValue.toDouble().toDuration(DurationUnit.SECONDS)
}
}, 130, 18)
})
},
min.toDouble(DurationUnit.SECONDS).toFloat(),
max.toDouble(DurationUnit.SECONDS).toFloat(),
0.1F,
130
)
))
}
}

View File

@@ -6,37 +6,39 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import io.github.notenoughupdates.moulconfig.gui.component.RowComponent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.Text
import moe.nea.firmament.gui.WSplitPanel
import moe.nea.firmament.gui.FixedComponent
class GuiAppender(val width: Int, val screenAccessor: () -> Screen) {
val panel = WBox(Axis.VERTICAL).also {
it.setSize(width, 200)
}
val panel = mutableListOf<GuiComponent>()
internal val reloadables = mutableListOf<(() -> Unit)>()
fun onReload(reloadable: () -> Unit) {
reloadables.add(reloadable)
}
fun appendLabeledRow(label: Text, right: WWidget) {
fun appendLabeledRow(label: Text, right: GuiComponent) {
appendSplitRow(
WLabel(label).setVerticalAlignment(VerticalAlignment.CENTER),
TextComponent(label.string),
right
)
}
fun appendSplitRow(left: WWidget, right: WWidget) {
appendFullRow(WSplitPanel(left.also { it.setSize(width / 2, 18) }, right.also { it.setSize(width / 2, 18) }))
fun appendSplitRow(left: GuiComponent, right: GuiComponent) {
// TODO: make this more dynamic
// i could just make a component that allows for using half the available size
appendFullRow(RowComponent(
FixedComponent(GetSetter.constant(width / 2), null, left),
FixedComponent(GetSetter.constant(width / 2), null, right),
))
}
fun appendFullRow(widget: WWidget) {
panel.add(widget, width, 18)
fun appendFullRow(widget: GuiComponent) {
panel.add(widget)
}
}

View File

@@ -6,13 +6,14 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WButton
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import moe.nea.firmament.gui.FirmButtonComponent
import moe.nea.firmament.jarvis.JarvisIntegration
import moe.nea.firmament.util.MC
@@ -27,14 +28,16 @@ class HudMetaHandler(val config: ManagedConfig, val label: MutableText, val widt
}
override fun emitGuiElements(opt: ManagedOption<HudMeta>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow(opt.labelText, WButton(Text.stringifiedTranslatable("firmament.hud.edit", label))
.also {
it.setOnClick {
guiAppender.appendLabeledRow(
opt.labelText,
FirmButtonComponent(
TextComponent(
Text.stringifiedTranslatable("firmament.hud.edit", label).string),
) {
MC.screen = JarvisIntegration.jarvis.getHudEditor(
guiAppender.screenAccessor.invoke(),
listOf(opt.value)
)
}
})
}
}

View File

@@ -6,17 +6,16 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WLabel
import io.github.cottonmc.cotton.gui.widget.WSlider
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
import java.util.function.IntConsumer
import io.github.notenoughupdates.moulconfig.common.IMinecraft
import io.github.notenoughupdates.moulconfig.gui.component.RowComponent
import io.github.notenoughupdates.moulconfig.gui.component.SliderComponent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonPrimitive
import net.minecraft.text.Text
import moe.nea.firmament.util.FirmFormatters
class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> {
override fun toJson(element: Int): JsonElement? {
@@ -28,22 +27,32 @@ class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : Ma
}
override fun emitGuiElements(opt: ManagedOption<Int>, guiAppender: GuiAppender) {
val label =
WLabel(Text.literal(opt.value.toString())).setVerticalAlignment(VerticalAlignment.CENTER)
guiAppender.appendLabeledRow(opt.labelText, WBox(Axis.HORIZONTAL).also {
it.add(label, 40, 18)
it.add(WSlider(min, max, Axis.HORIZONTAL).apply {
valueChangeListener = IntConsumer {
opt.value = it
label.text = Text.literal(opt.value.toString())
config.save()
guiAppender.appendLabeledRow(
opt.labelText,
RowComponent(
TextComponent(IMinecraft.instance.defaultFontRenderer,
{ FirmFormatters.formatCommas(opt.value, 0) },
40,
TextComponent.TextAlignment.CENTER,
true,
false),
SliderComponent(
object : GetSetter<Float> {
override fun get(): Float {
return opt.value.toFloat()
}
guiAppender.onReload {
value = opt.value
label.text = Text.literal(opt.value.toString())
override fun set(newValue: Float) {
opt.value = newValue.toInt()
}
}, 130, 18)
})
},
min.toFloat(),
max.toFloat(),
0.1F,
130
)
))
}
}

View File

@@ -6,8 +6,12 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WButton
import io.github.cottonmc.cotton.gui.widget.data.InputResult
import io.github.notenoughupdates.moulconfig.common.IMinecraft
import io.github.notenoughupdates.moulconfig.common.MyResourceLocation
import io.github.notenoughupdates.moulconfig.deps.libninepatch.NinePatch
import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext
import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import org.lwjgl.glfw.GLFW
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
@@ -16,6 +20,7 @@ import kotlinx.serialization.json.encodeToJsonElement
import net.minecraft.client.util.InputUtil
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.gui.FirmButtonComponent
import moe.nea.firmament.keybindings.FirmamentKeyBindings
import moe.nea.firmament.keybindings.SavedKeyBinding
@@ -36,61 +41,8 @@ class KeyBindingHandler(name: String, val managedConfig: ManagedConfig) : Manage
var editing = false
var lastPressed = 0
var lastPressedNonModifier = 0
var updateButton: (() -> Unit)? = null
val button = object : WButton() {
override fun onKeyPressed(ch: Int, key: Int, modifiers: Int): InputResult {
if (!editing) {
return super.onKeyPressed(ch, key, modifiers)
}
if (ch == GLFW.GLFW_KEY_ESCAPE) {
lastPressedNonModifier = 0
editing = false
lastPressed = 0
opt.value = SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN)
updateButton!!()
return InputResult.PROCESSED
}
if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
|| ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
|| ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
) {
lastPressed = ch
} else {
opt.value = SavedKeyBinding(
ch, modifiers
)
editing = false
lastPressed = 0
lastPressedNonModifier = 0
}
updateButton!!()
return InputResult.PROCESSED
}
override fun onFocusLost() {
super.onFocusLost()
lastPressedNonModifier = 0
editing = false
lastPressed = 0
updateButton!!()
}
override fun onKeyReleased(ch: Int, key: Int, modifiers: Int): InputResult {
if (!editing)
return super.onKeyReleased(ch, key, modifiers)
if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
opt.value = SavedKeyBinding(
ch, modifiers
)
editing = false
lastPressed = 0
lastPressedNonModifier = 0
}
updateButton!!()
return InputResult.PROCESSED
}
}
var label: String = ""
var button: FirmButtonComponent? = null
fun updateLabel() {
val stroke = Text.literal("")
if (opt.value.shift) {
@@ -105,16 +57,89 @@ class KeyBindingHandler(name: String, val managedConfig: ManagedConfig) : Manage
stroke.append(InputUtil.Type.KEYSYM.createFromCode(opt.value.keyCode).localizedText)
if (editing)
stroke.styled { it.withColor(Formatting.YELLOW) }
button.setLabel(stroke)
label = (stroke).string
managedConfig.save()
}
updateButton = ::updateLabel
updateButton()
button.setOnClick {
button = object : FirmButtonComponent(
TextComponent(
IMinecraft.instance.defaultFontRenderer,
{ label },
130,
TextComponent.TextAlignment.LEFT,
false,
false
), action = {
if (editing) {
button!!.blur()
} else {
editing = true
button.requestFocus()
updateButton()
button!!.requestFocus()
updateLabel()
}
}) {
override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean {
if (event is KeyboardEvent.KeyPressed) {
if (event.pressed) onKeyPressed(event.keycode, SavedKeyBinding.getModInt())
else onKeyReleased(event.keycode, SavedKeyBinding.getModInt())
}
return super.keyboardEvent(event, context)
}
override fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> {
if (editing) return activeBg
return super.getBackground(context)
}
fun onKeyPressed(ch: Int, modifiers: Int): Boolean {
if (!editing) {
return false
}
if (ch == GLFW.GLFW_KEY_ESCAPE) {
lastPressedNonModifier = 0
editing = false
lastPressed = 0
opt.value = SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN)
updateLabel()
return true
}
if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
|| ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
|| ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
) {
lastPressed = ch
} else {
opt.value = SavedKeyBinding(
ch, modifiers
)
editing = false
lastPressed = 0
lastPressedNonModifier = 0
}
updateLabel()
return true
}
override fun onLostFocus() {
lastPressedNonModifier = 0
editing = false
lastPressed = 0
updateLabel()
}
fun onKeyReleased(ch: Int, modifiers: Int): Boolean {
if (!editing)
return false
if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
opt.value = SavedKeyBinding(ch, modifiers)
editing = false
lastPressed = 0
lastPressedNonModifier = 0
}
updateLabel()
return true
}
}
updateLabel()
guiAppender.appendLabeledRow(opt.labelText, button)
}

View File

@@ -6,17 +6,17 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.client.CottonClientScreen
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WButton
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 io.github.notenoughupdates.moulconfig.gui.CloseEventListener
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import io.github.notenoughupdates.moulconfig.gui.GuiContext
import io.github.notenoughupdates.moulconfig.gui.component.CenterComponent
import io.github.notenoughupdates.moulconfig.gui.component.ColumnComponent
import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent
import io.github.notenoughupdates.moulconfig.gui.component.RowComponent
import io.github.notenoughupdates.moulconfig.gui.component.ScrollPanelComponent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
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
@@ -27,9 +27,8 @@ 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.gui.FirmButtonComponent
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil.setScreenLater
abstract class ManagedConfig(override val name: String) : ManagedConfigElement() {
@@ -150,15 +149,12 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
val labelText = Text.translatable("firmament.config.${name}")
fun getConfigEditor(parent: Screen? = null): CottonClientScreen {
val lwgd = LightweightGuiDescription()
fun getConfigEditor(parent: Screen? = null): Screen {
var screen: Screen? = null
val guiapp = GuiAppender(400) { requireNotNull(screen) { "Screen Accessor called too early" } }
latestGuiAppender = guiapp
guiapp.panel.insets = Insets.ROOT_PANEL
guiapp.appendFullRow(WBox(Axis.HORIZONTAL).also {
it.add(WButton(Text.literal("")).also {
it.setOnClick {
guiapp.appendFullRow(RowComponent(
FirmButtonComponent(TextComponent("")) {
if (parent != null) {
save()
setScreenLater(parent)
@@ -166,27 +162,15 @@ abstract class ManagedConfig(override val name: String) : ManagedConfigElement()
AllConfigsGui.showAllGuis()
}
}
})
it.add(WLabel(labelText).also {
it.verticalAlignment = VerticalAlignment.CENTER
})
})
))
sortedOptions.forEach { it.appendToGui(guiapp) }
guiapp.reloadables.forEach { it() }
lwgd.setRootPanel(WTightScrollPanel(guiapp.panel).also {
it.setSize(400, 300)
})
screen =
object : CottonClientScreen(lwgd) {
override fun init() {
latestGuiAppender = guiapp
super.init()
}
val component = CenterComponent(PanelComponent(ScrollPanelComponent(400, 300, ColumnComponent(guiapp.panel)), 10, PanelComponent.DefaultBackgroundRenderer.VANILLA))
screen = object : GuiComponentWrapper(GuiContext(component)) {
override fun close() {
latestGuiAppender = null
save()
MC.screen = parent
if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) {
client!!.setScreen(parent)
}
}
}
return screen

View File

@@ -6,6 +6,7 @@
package moe.nea.firmament.gui.config
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlin.properties.ReadWriteProperty
@@ -18,7 +19,14 @@ class ManagedOption<T : Any>(
val propertyName: String,
val default: () -> T,
val handler: ManagedConfig.OptionHandler<T>
) : ReadWriteProperty<Any?, T> {
) : ReadWriteProperty<Any?, T>, GetSetter<T> {
override fun set(newValue: T) {
this.value = newValue
}
override fun get(): T {
return this.value
}
val rawLabelText = "firmament.config.${element.name}.${propertyName}"
val labelText = Text.translatable(rawLabelText)

View File

@@ -6,7 +6,8 @@
package moe.nea.firmament.gui.config
import io.github.cottonmc.cotton.gui.widget.WTextField
import io.github.notenoughupdates.moulconfig.gui.component.TextFieldComponent
import io.github.notenoughupdates.moulconfig.observer.GetSetter
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonPrimitive
@@ -24,15 +25,16 @@ class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Str
override fun emitGuiElements(opt: ManagedOption<String>, guiAppender: GuiAppender) {
guiAppender.appendLabeledRow(
opt.labelText,
WTextField(opt.labelText).apply {
maxLength = 1000
suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "")
guiAppender.onReload { text = opt.value }
setChangedListener {
opt.value = it
TextFieldComponent(
object : GetSetter<String> by opt {
override fun set(newValue: String) {
opt.set(newValue)
config.save()
}
}
},
130,
suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "").string
),
)
}
}

View File

@@ -6,11 +6,12 @@
package moe.nea.firmament.gui.hud
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import io.github.notenoughupdates.moulconfig.gui.GuiContext
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SynchronousResourceReloader
import moe.nea.firmament.events.FinalizeResourceManagerEvent
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.gui.config.HudMeta
import moe.nea.firmament.util.MC
@@ -21,17 +22,18 @@ abstract class MoulConfigHud(
val hudMeta: HudMeta,
) {
companion object {
private val componentWrapper = object : GuiComponentWrapper(GuiContext(TextComponent("§cERROR"))) {
private val componentWrapper by lazy {
object : GuiComponentWrapper(GuiContext(TextComponent("§cERROR"))) {
init {
this.client = MC.instance
}
}
}
}
private var fragment: GuiContext? = null
fun forceInit() {
}
open fun shouldRender(): Boolean {
@@ -53,12 +55,14 @@ abstract class MoulConfigHud(
fragment!!.root.render(renderContextTranslated)
it.context.matrices.pop()
}
FinalizeResourceManagerEvent.subscribe {
MC.resourceManager.registerReloader(object : SynchronousResourceReloader {
override fun reload(manager: ResourceManager?) {
fragment = null
}
})
}
}
fun loadFragment() {
fragment = MoulConfigUtils.loadGui(name, this)

View File

@@ -1,110 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.profileviewer
import io.github.cottonmc.cotton.gui.client.BackgroundPainter
import io.github.cottonmc.cotton.gui.widget.WBox
import io.github.cottonmc.cotton.gui.widget.WGridPanel
import io.github.cottonmc.cotton.gui.widget.WText
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment
import io.github.cottonmc.cotton.gui.widget.data.InputResult
import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
import io.github.cottonmc.cotton.gui.widget.icon.Icon
import io.github.cottonmc.cotton.gui.widget.icon.ItemIcon
import io.github.moulberry.repo.data.Rarity
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.gui.WTightScrollPanel
import moe.nea.firmament.gui.WTitledItem
import moe.nea.firmament.rei.PetData
import moe.nea.firmament.rei.SBItemStack
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.FirmFormatters
object PetsPage : ProfilePage {
private fun petOverview(profileViewer: ProfileViewer, choosePet: (ItemStack) -> Unit) = WGridPanel().also { panel ->
panel.insets = Insets.ROOT_PANEL
panel.add(WText(Text.literal(profileViewer.account.getDisplayName(profileViewer.primaryName))), 0, 0, 6, 1)
panel.add((WTightScrollPanel(WGridPanel().also { it ->
it.setGaps(8, 8)
for ((i, pet) in profileViewer.member.pets.map {
SBItemStack(it.itemId, PetData(it.tier, it.type.name, it.exp))
}.sortedWith(
Comparator.comparing<SBItemStack?, Rarity?> { it.petData!!.rarity }.reversed()
.thenDescending(Comparator.comparing { it.petData!!.levelData.currentLevel })
.thenDescending(Comparator.comparing { it.petData!!.petId })
).withIndex()) {
val stack = pet.asItemStack()
it.add(object : WTitledItem(stack) {
override fun onClick(x: Int, y: Int, button: Int): InputResult {
choosePet(stack)
return InputResult.PROCESSED
}
}, i % 9, i / 9, 1, 1)
}
it.layout()
})), 0, 1, 12, 8)
petStats(profileViewer).withIndex().forEach { (i, it) ->
panel.add(it, 0, 10 + i, 8, 1)
}
}
private fun petStats(profileViewer: ProfileViewer): List<WWidget> {
val petScore = profileViewer.member.pets.groupBy { it.type }
.map { it.value.maxBy { it.tier } }
.sumOf { RepoManager.neuRepo.constants.bonuses.getPetValue(it.tier) }
return listOf(
WText(
Text.literal("Pet Score: ").styled { it.withColor(Formatting.AQUA) }
.append(Text.literal("$petScore").styled { it.withColor(Formatting.GOLD) })
),
WText(
Text.literal("Magic Find: ").styled { it.withColor(Formatting.AQUA) }
.append(
Text.literal(
FirmFormatters.formatCurrency(
RepoManager.neuRepo.constants.bonuses.getPetRewards(
petScore
)["magic_find"] ?: 0.0F, 1
)
)
.styled { it.withColor(Formatting.GOLD) })
)
)
}
override fun getElements(profileViewer: ProfileViewer): WWidget {
return WBox(Axis.HORIZONTAL).also {
it.insets = Insets.ROOT_PANEL
val item = WTitledItem(ItemStack.EMPTY)
item.backgroundPainter = BackgroundPainter.VANILLA
it.add(WBox(Axis.VERTICAL).also { box ->
box.add(petOverview(profileViewer) { item.stack = it })
})
val b = WBox(Axis.VERTICAL).also { box ->
box.verticalAlignment = VerticalAlignment.CENTER
box.horizontalAlignment = HorizontalAlignment.CENTER
box.add(item, 128, 128)
}
it.add(b)
it.layout()
b.setSize(b.width + 20, it.height)
}
}
override val icon: Icon
get() = ItemIcon(Items.BONE)
override val text: Text
get() = Text.translatable("firmament.pv.pets")
}

View File

@@ -1,17 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.profileviewer
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.icon.Icon
import net.minecraft.text.Text
interface ProfilePage {
fun getElements(profileViewer: ProfileViewer): WWidget
val icon: Icon
val text: Text
}

View File

@@ -1,77 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.profileviewer
import io.github.cottonmc.cotton.gui.client.CottonClientScreen
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription
import io.github.cottonmc.cotton.gui.widget.WTabPanel
import moe.nea.firmament.Firmament
import moe.nea.firmament.apis.Member
import moe.nea.firmament.apis.PlayerData
import moe.nea.firmament.apis.Profile
import moe.nea.firmament.apis.Routes
import moe.nea.firmament.util.ScreenUtil
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.minecraft.text.Text
import java.util.*
class ProfileViewer(
val primaryPlayer: UUID,
val playerNames: Map<UUID, String>,
val accountData: Map<UUID, PlayerData>,
val profile: Profile,
) : LightweightGuiDescription() {
val member: Member = profile.members[primaryPlayer] ?: error("Primary player not in profile")
val primaryName: String = playerNames[primaryPlayer] ?: error("Primary player has no name")
val account: PlayerData = accountData[primaryPlayer] ?: error("Primary player has no data")
init {
val panel = WTabPanel().also { rootPanel = it }
panel.backgroundPainter
listOf<ProfilePage>(SkillPage, PetsPage)
.forEach { page ->
panel.add(page.getElements(this)) {
it.icon(page.icon)
it.tooltip(page.text)
}
}
}
companion object {
suspend fun onCommand(source: FabricClientCommandSource, name: String) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.pv.lookingup", name))
try {
val uuid = Routes.getUUIDForPlayerName(name)
if (uuid == null) {
source.sendError(Text.stringifiedTranslatable("firmament.pv.noplayer", name))
return
}
val name = Routes.getPlayerNameForUUID(uuid) ?: name
val names = mapOf(uuid to (name))
val data = Routes.getAccountData(uuid)
if (data == null) {
source.sendError(Text.stringifiedTranslatable("firmament.pv.noprofile", name))
return
}
val accountData = mapOf(data.uuid to data)
val profiles = Routes.getProfiles(uuid)
val profile = profiles?.profiles?.find { it.selected }
if (profile == null) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.pv.noprofile", name))
return
}
ScreenUtil.setScreenLater(CottonClientScreen(ProfileViewer(uuid, names, accountData, profile)))
} catch (e: Exception) {
Firmament.logger.error("Error loading profile data for $name", e)
source.sendError(Text.stringifiedTranslatable("firmament.pv.badprofile", name, e.message))
}
}
}
}

View File

@@ -1,71 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.profileviewer
import com.mojang.brigadier.StringReader
import io.github.cottonmc.cotton.gui.client.CottonClientScreen
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription
import io.github.cottonmc.cotton.gui.widget.WGridPanel
import io.github.cottonmc.cotton.gui.widget.WText
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
import moe.nea.lisp.LispData
import moe.nea.lisp.LispExecutionContext
import moe.nea.lisp.LispParser
import moe.nea.lisp.bind.AutoBinder
import moe.nea.lisp.bind.LispBinding
import moe.nea.lisp.bind.UnmapForeignObject
import net.minecraft.command.argument.ItemStringReader
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import moe.nea.firmament.gui.WTitledItem
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.item.setCustomName
import moe.nea.firmament.util.modifyLore
class ProfileViewerLibrary {
@LispBinding("mk-item")
fun makeItem(itemType: String, title: String, vararg lore: String): LispData.ForeignObject<ItemStack> {
val item = ItemStringReader(MC.defaultRegistries).consume(StringReader(itemType))
val itemStack = ItemStack(item.item.value())
itemStack.applyComponentsFrom(item.components)
itemStack.modifyLore { lore.map { Text.literal(it) } }
itemStack.setCustomName(Text.literal(title))
return LispData.ForeignObject(itemStack)
}
@LispBinding("def-page")
fun defPage(name: String, @UnmapForeignObject icon: ItemStack) {
pages.add(Pair(name, icon))
}
val pages = mutableListOf<Pair<String, ItemStack>>()
val coreEnvironment = LispExecutionContext()
fun run() {
val t = coreEnvironment.genBindings()
val ab = AutoBinder()
ab.bindTo(this, t)
val prog = LispParser.parse(
"testfile.lisp", """
(def-page "Test" (mk-item "minecraft:tnt" "§aThis is a test page" "§aMore text"))
(def-page "Skills" (mk-item "minecraft:diamond_sword" "§aThis is a test page" "§aMore text"))
""".trimIndent()
)
coreEnvironment.executeProgram(t, prog)
val light = LightweightGuiDescription()
val root = light.rootPanel as WGridPanel
root.setGaps(8, 8)
pages.forEachIndexed { i, (name, item) ->
root.add(WTitledItem(item), 0, i)
root.add(WText(Text.literal(name)).also { it.verticalAlignment = VerticalAlignment.CENTER }, 1, i, 6, 1)
}
ScreenUtil.setScreenLater(CottonClientScreen(light))
}
}

View File

@@ -1,146 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.gui.profileviewer
import io.github.cottonmc.cotton.gui.widget.*
import io.github.cottonmc.cotton.gui.widget.data.Axis
import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment
import io.github.cottonmc.cotton.gui.widget.data.Insets
import io.github.cottonmc.cotton.gui.widget.icon.Icon
import io.github.cottonmc.cotton.gui.widget.icon.ItemIcon
import moe.nea.firmament.apis.*
import moe.nea.firmament.gui.WBar
import moe.nea.firmament.gui.WFixedPanel
import moe.nea.firmament.gui.WTitledItem
import moe.nea.firmament.hud.horizontal
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.rei.SBItemEntryDefinition
import moe.nea.firmament.repo.HypixelStaticData
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.modifyLore
import moe.nea.firmament.util.toShedaniel
import moe.nea.firmament.util.toTextColor
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.text.Style
import net.minecraft.text.Text
import net.minecraft.util.DyeColor
import net.minecraft.util.Formatting
import moe.nea.firmament.util.item.setCustomName
object SkillPage : ProfilePage {
private fun skillBar(profileViewer: ProfileViewer, skill: Skill): WBar {
val leveling = RepoManager.neuRepo.constants.leveling
val exp = skill.accessor.get(profileViewer.member)
val maxLevel = skill.getMaximumLevel(leveling)
val level = skill.getLadder(leveling)
.runningFold(0.0) { a, b -> a + b }
.filter { it <= exp }.size
.coerceAtMost(maxLevel)
return object : WBar(
level.toDouble(), maxLevel.toDouble(),
skill.color.toShedaniel(), skill.color.toShedaniel().darker(2.0)
) {
override fun addTooltip(tooltip: TooltipBuilder) {
tooltip.add(Text.literal("$level/$maxLevel"))
tooltip.add(Text.stringifiedTranslatable("firmament.pv.skills.total", FirmFormatters.formatCurrency(exp, 1)))
}
}
}
private fun collectionItem(type: CollectionType, info: CollectionInfo, color: DyeColor, profile: Profile): WWidget {
val collectionCount = profile.members.values.sumOf { it.collection[type] ?: 0 }
val unlockedTiers = info.tiers.count { it.amountRequired <= collectionCount }
return WTitledItem(
SBItemEntryDefinition.getEntry(type.skyblockId).asItemEntry().value.copy()
.also {
it.setCustomName(
Text.literal(info.name).fillStyle(
Style.EMPTY.withItalic(false).withBold(true)
.withColor(color.toTextColor())
)
)
it.modifyLore { old ->
listOf(
Text.literal("${info.name} Collection: $collectionCount / ${info.tiers.last().amountRequired}"),
Text.literal("Tiers unlocked: $unlockedTiers / ${info.tiers.size}")
).map {
it.fillStyle(
Style.EMPTY.withItalic(false).withColor(Formatting.GRAY)
)
}
}
}, countString = Text.literal("$unlockedTiers").styled {
if (unlockedTiers == info.maxTiers)
it.withColor(Formatting.YELLOW)
else it
}
)
}
private fun collectionPanel(profileViewer: ProfileViewer): WTabPanel {
return WTabPanel().also {
val data = HypixelStaticData.collectionData
val panels = mutableListOf<WPanel>()
for ((collectionKind, collections) in data.entries) {
val skillT = CollectionCategory.values().find { it.name == collectionKind }
val color = skillT?.color ?: DyeColor.WHITE
val icon = skillT?.icon?.let { RepoManager.getNEUItem(it).asItemStack() } ?: ItemStack(Items.ITEM_FRAME)
val panel = WBox(Axis.HORIZONTAL).also {
it.horizontalAlignment = HorizontalAlignment.CENTER
it.add(WFixedPanel(WGridPanel().also {
it.insets = Insets.ROOT_PANEL
it.setGaps(2, 2)
var x = 0
var y = 0
for (item in collections.items) {
it.add(collectionItem(item.key, item.value, color, profileViewer.profile), x, y, 1, 1)
x++
if (x == 5) {
x = 0
y++
}
}
}))
}
panels.add(panel)
it.add(panel) {
it.tooltip(
Text.translatable("firmament.pv.skills.${collectionKind.lowercase()}")
.styled { it.withColor(color.toTextColor()) })
it.icon(ItemIcon(icon))
}
}
it.layout()
val tabWidth = it.width
panels.forEach { it.setSize(tabWidth - Insets.ROOT_PANEL.horizontal, it.height) }
}
}
override fun getElements(profileViewer: ProfileViewer): WWidget {
return WBox(Axis.HORIZONTAL).also {
it.insets = Insets.ROOT_PANEL
it.add(WGridPanel().also {
it.add(WText(Text.literal(profileViewer.account.getDisplayName(profileViewer.primaryName))), 0, 0, 8, 1)
for ((i, skill) in Skill.values().withIndex()) {
it.add(WText(Text.translatable("firmament.pv.skills.${skill.name.lowercase()}")), 0, i + 1, 4, 1)
it.add(skillBar(profileViewer, skill), 4, i + 1, 4, 1)
}
})
it.add(collectionPanel(profileViewer))
}
}
override val icon: Icon
get() = ItemIcon(ItemStack(Items.IRON_SWORD))
override val text: Text
get() = Text.translatable("firmament.pv.skills")
}

View File

@@ -1,69 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package moe.nea.firmament.hud
import io.github.cottonmc.cotton.gui.client.ScreenDrawing
import io.github.cottonmc.cotton.gui.widget.WWidget
import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment
import io.github.cottonmc.cotton.gui.widget.data.Insets
import kotlin.math.roundToInt
import kotlin.math.sin
import net.minecraft.client.gui.DrawContext
val Insets.vertical get() = bottom + top
val Insets.horizontal get() = left + right
class ProgressBar(
var label: String,
var total: Int?, // If total is null, then make it a bouncy rectangle
var progress: Int = 0,
) : WWidget() {
var insets: Insets = Insets(7)
override fun canResize(): Boolean = true
fun reportProgress(label: String, progress: Int, total: Int?) {
synchronized(this) {
this.label = label
this.progress = progress
this.total = total
}
}
override fun paint(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int) {
ScreenDrawing.coloredRect(context, x, y, width, height, 0xFF808080.toInt())
val (l, prog) = synchronized(this) {
label to (progress to total)
}
val (p, t) = prog
if (t == null) {
ScreenDrawing.coloredRect(
context,
(x + (1 + sin(System.currentTimeMillis().toDouble() / 1000)) * width * 3 / 4 / 2).roundToInt(),
y,
width / 4,
height,
0xFF00FF00.toInt()
)
} else {
ScreenDrawing.coloredRect(context, x, y, width * p / t, height, 0xFF00FF00.toInt())
}
ScreenDrawing.drawString(
context,
if (t != null) "$l ($p/$t)" else l,
HorizontalAlignment.CENTER,
x + insets.left,
y + insets.top,
width - insets.horizontal,
height - insets.vertical,
)
}
}

View File

@@ -6,11 +6,11 @@
package moe.nea.firmament.keybindings
import org.lwjgl.glfw.GLFW
import kotlinx.serialization.Serializable
import moe.nea.firmament.util.MC
import net.minecraft.client.MinecraftClient
import net.minecraft.client.util.InputUtil
import org.lwjgl.glfw.GLFW
import moe.nea.firmament.util.MC
@Serializable
data class SavedKeyBinding(
@@ -38,6 +38,24 @@ data class SavedKeyBinding(
modifiers and GLFW.GLFW_MOD_ALT != 0
)
}
fun getModInt(): Int {
val h = MC.window.handle
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)
var mods = 0
if (ctrl) mods = mods or GLFW.GLFW_MOD_CONTROL
if (shift) mods = mods or GLFW.GLFW_MOD_SHIFT
if (alt) mods = mods or GLFW.GLFW_MOD_ALT
return mods
}
}
fun isPressed(atLeast: Boolean = false): Boolean {

View File

@@ -79,10 +79,10 @@ data class SBItemStack(
) {
val stats = petInfo.interpolatedStatsAtLevel(level) ?: return
stats.otherNumbers.forEachIndexed { index, it ->
replacementData[index.toString()] = FirmFormatters.formatCurrency(it, 1)
replacementData[index.toString()] = FirmFormatters.formatCommas(it, 1)
}
stats.statNumbers.forEach { (t, u) ->
replacementData[t] = FirmFormatters.formatCurrency(u, 1)
replacementData[t] = FirmFormatters.formatCommas(u, 1)
}
}

View File

@@ -8,12 +8,12 @@
package moe.nea.firmament.repo
import com.mojang.serialization.Dynamic
import io.github.cottonmc.cotton.gui.client.CottonHud
import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUItem
import io.github.notenoughupdates.moulconfig.xml.Bind
import java.text.NumberFormat
import java.util.*
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import org.apache.logging.log4j.LogManager
import kotlinx.coroutines.Job
@@ -32,6 +32,9 @@ import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtOps
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.config.HudMeta
import moe.nea.firmament.gui.config.HudPosition
import moe.nea.firmament.gui.hud.MoulConfigHud
import moe.nea.firmament.util.LegacyTagParser
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
@@ -135,6 +138,30 @@ object ItemCache : IReloadable {
fun NEUItem.getIdentifier() = skyblockId.identifier
var job: Job? = null
object ReloadProgressHud : MoulConfigHud(
"repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) {
var isEnabled = false
override fun shouldRender(): Boolean {
return isEnabled
}
@get:Bind("current")
var current: Double = 0.0
@get:Bind("label")
var label: String = ""
@get:Bind("max")
var max: Double = 0.0
fun reportProgress(label: String, current: Int, max: Int) {
this.label = label
this.current = current.toDouble()
this.max = max.toDouble()
}
}
override fun reload(repository: NEURepository) {
val j = job
@@ -147,18 +174,18 @@ object ItemCache : IReloadable {
job = Firmament.coroutineScope.launch {
val items = repository.items?.items
if (items == null) {
CottonHud.remove(RepoManager.progressBar)
ReloadProgressHud.isEnabled = false
return@launch
}
val recacheItems = I18n.translate("firmament.repo.cache")
RepoManager.progressBar.reportProgress(recacheItems, 0, items.size)
CottonHud.add(RepoManager.progressBar)
ReloadProgressHud.reportProgress(recacheItems, 0, items.size)
ReloadProgressHud.isEnabled = true
var i = 0
items.values.forEach {
it.asItemStack() // Rebuild cache
RepoManager.progressBar.reportProgress(recacheItems, i++, items.size)
ReloadProgressHud.reportProgress(recacheItems, i++, items.size)
}
CottonHud.remove(RepoManager.progressBar)
ReloadProgressHud.isEnabled = false
}
}

View File

@@ -6,7 +6,6 @@
package moe.nea.firmament.repo
import io.github.cottonmc.cotton.gui.client.CottonHud
import io.github.moulberry.repo.NEURecipeCache
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.NEURepositoryException
@@ -21,7 +20,6 @@ import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.hud.ProgressBar
import moe.nea.firmament.rei.PetData
import moe.nea.firmament.util.MinecraftDispatcher
import moe.nea.firmament.util.SkyblockId
@@ -54,12 +52,6 @@ object RepoManager {
var recentlyFailedToUpdateItemList = false
val progressBar by lazy {
ProgressBar("", null, 0).also {
it.setSize(180, 22)
}
}
val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
registerReloadListener(ItemCache)
registerReloadListener(ExpLadders)
@@ -98,14 +90,13 @@ object RepoManager {
fun launchAsyncUpdate(force: Boolean = false) {
Firmament.coroutineScope.launch {
progressBar.reportProgress("Downloading", 0, null)
CottonHud.add(progressBar)
ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar
ItemCache.ReloadProgressHud.isEnabled = true
try {
RepoDownloadManager.downloadUpdate(force)
progressBar.reportProgress("Download complete", 1, 1)
ItemCache.ReloadProgressHud.reportProgress("Download complete", 1, 1)
} finally {
CottonHud.remove(progressBar)
ItemCache.ReloadProgressHud.isEnabled = false
}
reload()
}
@@ -113,14 +104,14 @@ object RepoManager {
fun reload() {
try {
progressBar.reportProgress("Reloading from Disk", 0, null)
CottonHud.add(progressBar)
ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", 0, -1) // TODO: replace with a proper boundy bar
ItemCache.ReloadProgressHud.isEnabled = true
neuRepo.reload()
} catch (exc: NEURepositoryException) {
MinecraftClient.getInstance().player?.sendMessage(
Text.literal("Failed to reload repository. This will result in some mod features not working.")
)
CottonHud.remove(progressBar)
ItemCache.ReloadProgressHud.isEnabled = false
exc.printStackTrace()
}
}

View File

@@ -11,21 +11,22 @@ import kotlin.math.absoluteValue
import kotlin.time.Duration
object FirmFormatters {
fun formatCurrency(long: Long, segments: Int = 3): String {
fun formatCommas(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments)
fun formatCommas(long: Long, segments: Int = 3): String {
val α = long / 1000
if (α != 0L) {
return formatCurrency(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
return formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0')
}
return long.toString()
}
fun formatCurrency(float: Float, fractionalDigits: Int): String = formatCurrency(float.toDouble(), fractionalDigits)
fun formatCurrency(double: Double, fractionalDigits: Int): String {
fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits)
fun formatCommas(double: Double, fractionalDigits: Int): String {
val long = double.toLong()
val δ = (double - long).absoluteValue
val μ = pow(10, fractionalDigits)
val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0')
return formatCurrency(long) + (if (digits.isEmpty()) "" else ".$digits")
return formatCommas(long) + (if (digits.isEmpty()) "" else ".$digits")
}
fun formatDistance(distance: Double): String {
@@ -34,8 +35,29 @@ object FirmFormatters {
return "%dm".format(distance.toInt())
}
fun formatTimespan(duration: Duration): String {
return duration.toString()
fun formatTimespan(duration: Duration, millis: Boolean = false): String {
if (duration.isInfinite()) {
return if (duration.isPositive()) ""
else "-∞"
}
val sb = StringBuilder()
if (duration.isNegative()) sb.append("-")
duration.toComponents { days, hours, minutes, seconds, nanoseconds ->
if (days > 0) {
sb.append(days).append("d")
}
if (hours > 0) {
sb.append(hours).append("h")
}
if (minutes > 0) {
sb.append(minutes).append("m")
}
sb.append(seconds).append("s")
if (millis) {
sb.append(nanoseconds / 1_000_000).append("ms")
}
}
return sb.toString()
}
}

View File

@@ -77,9 +77,9 @@ object MoulConfigUtils {
override fun createInstance(context: XMLContext<*>, element: Element): FirmButtonComponent {
return FirmButtonComponent(
context.getChildFragment(element),
context.getMethodFromAttribute(element, QName("onClick")),
context.getPropertyFromAttribute(element, QName("enabled"), Boolean::class.java)
?: GetSetter.constant(true)
?: GetSetter.constant(true),
context.getMethodFromAttribute(element, QName("onClick")),
)
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<Root xmlns="http://notenoughupdates.org/moulconfig" xmlns:firm="http://firmament.nea.moe/moulconfig">
<Row>
<firm:Bar progress="@current" total="@max" emptyColor="#30ff30" fillColor="#30aa30"/>
<Text text="@label"/>
</Row>
</Root>

View File

@@ -97,6 +97,7 @@
"firmament.config.waypoints": "Waypoints",
"firmament.config.waypoints.temp-waypoint-duration": "Temporary Waypoint Duration",
"firmament.config.waypoints.show-index": "Show ordered waypoint indexes",
"firmament.config.waypoints.skip-to-nearest": "Allow skipping waypoints",
"firmament.recipe.forge.time": "Forging Time: %s",
"firmament.recipe.mobs.drops": "§e§lDrop Chance: %s",
"firmament.recipe.mobs.name": "§8[§7Lv %d§8] §c%s",

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -15,3 +15,4 @@ accessible field net/minecraft/entity/passive/AbstractHorseEntity items Lnet/min
accessible field net/minecraft/entity/passive/AbstractHorseEntity SADDLED_FLAG I
accessible field net/minecraft/entity/passive/AbstractHorseEntity HORSE_FLAGS Lnet/minecraft/entity/data/TrackedData;
accessible method net/minecraft/resource/NamespaceResourceManager loadMetadata (Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/metadata/ResourceMetadata;
accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Lnet/minecraft/util/Identifier;IIIIIFFFFFFFF)V