Add edit backpacks button to /firm storage

This commit is contained in:
Linnea Gräf
2024-10-16 19:24:24 +02:00
parent 854ec336cc
commit 7de0e8e7e0
11 changed files with 473 additions and 301 deletions

View File

@@ -1,7 +1,9 @@
@file:OptIn(ExperimentalContracts::class)
package moe.nea.firmament.features.inventory.storageoverlay package moe.nea.firmament.features.inventory.storageoverlay
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
import net.minecraft.screen.GenericContainerScreenHandler import net.minecraft.screen.GenericContainerScreenHandler
@@ -39,6 +41,9 @@ sealed interface StorageBackingHandle {
* selection screen. * selection screen.
*/ */
fun fromScreen(screen: Screen?): StorageBackingHandle? { fun fromScreen(screen: Screen?): StorageBackingHandle? {
contract {
returnsNotNull() implies (screen != null)
}
if (screen == null) return null if (screen == null) return null
if (screen !is GenericContainerScreen) return null if (screen !is GenericContainerScreen) return null
val title = screen.title.unformattedString val title = screen.title.unformattedString

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.features.inventory.storageoverlay package moe.nea.firmament.features.inventory.storageoverlay
import java.util.SortedMap import java.util.SortedMap
@@ -97,6 +95,7 @@ object StorageOverlay : FirmamentFeature {
return return
} }
screen ?: return screen ?: return
if (storageOverlayScreen?.isExiting == true) return
screen.customGui = StorageOverlayCustom( screen.customGui = StorageOverlayCustom(
currentHandler ?: return, currentHandler ?: return,
screen, screen,

View File

@@ -80,6 +80,7 @@ class StorageOverlayCustom(
screen.screenHandler.slots.take(screen.screenHandler.rows * 9).drop(9), screen.screenHandler.slots.take(screen.screenHandler.rows * 9).drop(9),
Point((screen as AccessorHandledScreen).x_Firmament, screen.y_Firmament)) Point((screen as AccessorHandledScreen).x_Firmament, screen.y_Firmament))
overview.drawScrollBar(drawContext) overview.drawScrollBar(drawContext)
overview.drawControls(drawContext, mouseX, mouseY)
} }
override fun moveSlot(slot: Slot) { override fun moveSlot(slot: Slot) {

View File

@@ -1,14 +1,26 @@
package moe.nea.firmament.features.inventory.storageoverlay package moe.nea.firmament.features.inventory.storageoverlay
import io.github.notenoughupdates.moulconfig.gui.GuiContext
import io.github.notenoughupdates.moulconfig.gui.MouseEvent
import io.github.notenoughupdates.moulconfig.gui.component.ColumnComponent
import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent
import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
import me.shedaniel.math.Point import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle import me.shedaniel.math.Rectangle
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.gui.EmptyComponent
import moe.nea.firmament.gui.FirmButtonComponent
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MoulConfigUtils.adopt
import moe.nea.firmament.util.MoulConfigUtils.clickMCComponentInPlace
import moe.nea.firmament.util.MoulConfigUtils.drawMCComponentInPlace
import moe.nea.firmament.util.assertTrueOr import moe.nea.firmament.util.assertTrueOr
import moe.nea.firmament.util.customgui.customGui
class StorageOverlayScreen : Screen(Text.literal("")) { class StorageOverlayScreen : Screen(Text.literal("")) {
@@ -24,6 +36,9 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
val MAIN_INVENTORY_Y = 9 val MAIN_INVENTORY_Y = 9
val SCROLL_BAR_WIDTH = 8 val SCROLL_BAR_WIDTH = 8
val SCROLL_BAR_HEIGHT = 16 val SCROLL_BAR_HEIGHT = 16
val CONTROL_WIDTH = 70
val CONTROL_BACKGROUND_WIDTH = CONTROL_WIDTH + PLAYER_Y_INSET
val CONTROL_HEIGHT = 100
} }
var isExiting: Boolean = false var isExiting: Boolean = false
@@ -39,6 +54,8 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
val y = height / 2 - (overviewHeight + PLAYER_HEIGHT) / 2 val y = height / 2 - (overviewHeight + PLAYER_HEIGHT) / 2
val playerX = width / 2 - PLAYER_WIDTH / 2 val playerX = width / 2 - PLAYER_WIDTH / 2
val playerY = y + overviewHeight - PLAYER_Y_INSET val playerY = y + overviewHeight - PLAYER_Y_INSET
val controlX = x - CONTROL_WIDTH
val controlY = y + overviewHeight / 2 - CONTROL_HEIGHT / 2
val totalWidth = overviewWidth val totalWidth = overviewWidth
val totalHeight = overviewHeight - PLAYER_Y_INSET + PLAYER_HEIGHT val totalHeight = overviewHeight - PLAYER_Y_INSET + PLAYER_HEIGHT
} }
@@ -74,6 +91,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
val slotRowSprite = Identifier.of("firmament:storageoverlay/storage_row") val slotRowSprite = Identifier.of("firmament:storageoverlay/storage_row")
val scrollbarBackground = Identifier.of("firmament:storageoverlay/scroll_bar_background") val scrollbarBackground = Identifier.of("firmament:storageoverlay/scroll_bar_background")
val scrollbarKnob = Identifier.of("firmament:storageoverlay/scroll_bar_knob") val scrollbarKnob = Identifier.of("firmament:storageoverlay/scroll_bar_knob")
val controllerBackground = Identifier.of("firmament:storageoverlay/storage_controls")
override fun close() { override fun close() {
isExiting = true isExiting = true
@@ -86,6 +104,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
drawPages(context, mouseX, mouseY, delta, null, null, Point()) drawPages(context, mouseX, mouseY, delta, null, null, Point())
drawScrollBar(context) drawScrollBar(context)
drawPlayerInventory(context, mouseX, mouseY, delta) drawPlayerInventory(context, mouseX, mouseY, delta)
drawControls(context, mouseX, mouseY)
} }
fun getScrollbarPercentage(): Float { fun getScrollbarPercentage(): Float {
@@ -106,6 +125,39 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
) )
} }
fun editPages() {
isExiting = true
val hs = MC.screen as? HandledScreen<*>
if (StorageBackingHandle.fromScreen(hs) is StorageBackingHandle.Overview) {
hs.customGui = null
} else {
MC.sendCommand("storage")
}
}
val guiContext = GuiContext(EmptyComponent())
private val knobStub = EmptyComponent()
val editButton = PanelComponent(ColumnComponent(FirmButtonComponent(TextComponent("Edit"), action = ::editPages)),
8, PanelComponent.DefaultBackgroundRenderer.TRANSPARENT)
init {
guiContext.adopt(editButton)
guiContext.adopt(knobStub)
}
fun drawControls(context: DrawContext, mouseX: Int, mouseY: Int) {
context.drawGuiTexture(
controllerBackground,
measurements.controlX,
measurements.controlY,
CONTROL_BACKGROUND_WIDTH, CONTROL_HEIGHT)
context.drawMCComponentInPlace(
editButton,
measurements.controlX, measurements.controlY,
CONTROL_WIDTH, CONTROL_HEIGHT,
mouseX, mouseY)
}
fun drawBackgrounds(context: DrawContext) { fun drawBackgrounds(context: DrawContext) {
context.drawGuiTexture(upperBackgroundSprite, context.drawGuiTexture(upperBackgroundSprite,
measurements.x, measurements.x,
@@ -182,7 +234,10 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
context.disableScissor() context.disableScissor()
} }
var knobGrabbed = false
var knobGrabbed: Boolean
get() = guiContext.focusedElement == knobStub
set(value) = knobStub.setFocus(value)
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
return mouseClicked(mouseX, mouseY, button, null) return mouseClicked(mouseX, mouseY, button, null)
@@ -193,6 +248,12 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
knobGrabbed = false knobGrabbed = false
return true return true
} }
if (clickMCComponentInPlace(editButton,
measurements.controlX, measurements.controlY,
CONTROL_WIDTH, CONTROL_HEIGHT,
mouseX.toInt(), mouseY.toInt(),
MouseEvent.Click(button, false))
) return true
return super.mouseReleased(mouseX, mouseY, button) return super.mouseReleased(mouseX, mouseY, button)
} }
@@ -226,6 +287,12 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
knobGrabbed = true knobGrabbed = true
return true return true
} }
if (clickMCComponentInPlace(editButton,
measurements.controlX, measurements.controlY,
CONTROL_WIDTH, CONTROL_HEIGHT,
mouseX.toInt(), mouseY.toInt(),
MouseEvent.Click(button, true))
) return true
return false return false
} }
@@ -309,6 +376,10 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
Rectangle(measurements.playerX, Rectangle(measurements.playerX,
measurements.playerY, measurements.playerY,
PLAYER_WIDTH, PLAYER_WIDTH,
PLAYER_HEIGHT)) PLAYER_HEIGHT),
Rectangle(measurements.controlX,
measurements.controlY,
CONTROL_WIDTH,
CONTROL_HEIGHT))
} }
} }

View File

@@ -0,0 +1,17 @@
package moe.nea.firmament.gui
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext
class EmptyComponent : GuiComponent() {
override fun getWidth(): Int {
return 0
}
override fun getHeight(): Int {
return 0
}
override fun render(context: GuiImmediateContext) {
}
}

View File

@@ -1,12 +1,15 @@
package moe.nea.firmament.util package moe.nea.firmament.util
import io.github.notenoughupdates.moulconfig.common.IMinecraft
import io.github.notenoughupdates.moulconfig.common.MyResourceLocation import io.github.notenoughupdates.moulconfig.common.MyResourceLocation
import io.github.notenoughupdates.moulconfig.gui.CloseEventListener import io.github.notenoughupdates.moulconfig.gui.CloseEventListener
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import io.github.notenoughupdates.moulconfig.gui.GuiContext import io.github.notenoughupdates.moulconfig.gui.GuiContext
import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext
import io.github.notenoughupdates.moulconfig.gui.MouseEvent
import io.github.notenoughupdates.moulconfig.observer.GetSetter import io.github.notenoughupdates.moulconfig.observer.GetSetter
import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext
import io.github.notenoughupdates.moulconfig.xml.ChildCount import io.github.notenoughupdates.moulconfig.xml.ChildCount
import io.github.notenoughupdates.moulconfig.xml.XMLContext import io.github.notenoughupdates.moulconfig.xml.XMLContext
import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader
@@ -19,6 +22,7 @@ import me.shedaniel.math.Color
import org.w3c.dom.Element import org.w3c.dom.Element
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import moe.nea.firmament.gui.BarComponent import moe.nea.firmament.gui.BarComponent
import moe.nea.firmament.gui.FirmButtonComponent import moe.nea.firmament.gui.FirmButtonComponent
@@ -26,6 +30,7 @@ import moe.nea.firmament.gui.FirmHoverComponent
import moe.nea.firmament.gui.FixedComponent import moe.nea.firmament.gui.FixedComponent
import moe.nea.firmament.gui.ImageComponent import moe.nea.firmament.gui.ImageComponent
import moe.nea.firmament.gui.TickComponent import moe.nea.firmament.gui.TickComponent
import moe.nea.firmament.util.render.isUntranslatedGuiDrawContext
object MoulConfigUtils { object MoulConfigUtils {
val firmUrl = "http://firmament.nea.moe/moulconfig" val firmUrl = "http://firmament.nea.moe/moulconfig"
@@ -74,7 +79,9 @@ object MoulConfigUtils {
override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent { override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent {
return FirmHoverComponent( return FirmHoverComponent(
context.getChildFragment(element), context.getChildFragment(element),
context.getPropertyFromAttribute(element, QName("lines"), List::class.java) as Supplier<List<String>>, context.getPropertyFromAttribute(element,
QName("lines"),
List::class.java) as Supplier<List<String>>,
context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds), context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds),
) )
} }
@@ -224,6 +231,52 @@ object MoulConfigUtils {
} }
} }
// TODO: move this utility into moulconfig (also rework guicontext into an interface so i can make this mesh better into vanilla)
fun GuiContext.adopt(element: GuiComponent) = element.foldRecursive(Unit, { comp, unit -> comp.context = this })
fun clickMCComponentInPlace(
component: GuiComponent,
x: Int,
y: Int,
w: Int,
h: Int,
mouseX: Int, mouseY: Int,
mouseEvent: MouseEvent
): Boolean {
val immContext = createInPlaceFullContext(null, mouseX, mouseY)
return component.mouseEvent(mouseEvent, immContext.translated(x, y, w, h))
}
fun createInPlaceFullContext(drawContext: DrawContext?, mouseX: Int, mouseY: Int): GuiImmediateContext {
assert(drawContext?.isUntranslatedGuiDrawContext() != false)
val context = drawContext?.let(::ModernRenderContext)
?: IMinecraft.instance.provideTopLevelRenderContext()
val immContext = GuiImmediateContext(context,
0, 0, 0, 0,
mouseX, mouseY,
mouseX, mouseY,
mouseX.toFloat(),
mouseY.toFloat())
return immContext
}
fun DrawContext.drawMCComponentInPlace(
component: GuiComponent,
x: Int,
y: Int,
w: Int,
h: Int,
mouseX: Int,
mouseY: Int
) {
val immContext = createInPlaceFullContext(this, mouseX, mouseY)
matrices.push()
matrices.translate(x.toFloat(), y.toFloat(), 0F)
component.render(immContext.translated(x, y, w, h))
matrices.pop()
}
fun loadGui(name: String, bindTo: Any): GuiContext { fun loadGui(name: String, bindTo: Any): GuiContext {
return GuiContext(universe.load(bindTo, MyResourceLocation("firmament", "gui/$name.xml"))) return GuiContext(universe.load(bindTo, MyResourceLocation("firmament", "gui/$name.xml")))
} }

View File

@@ -1,11 +1,18 @@
@file:OptIn(ExperimentalContracts::class)
package moe.nea.firmament.util package moe.nea.firmament.util
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/** /**
* Less aggressive version of `require(obj != null)`, which fails in devenv but continues at runtime. * Less aggressive version of `require(obj != null)`, which fails in devenv but continues at runtime.
*/ */
inline fun <T : Any> assertNotNullOr(obj: T?, message: String? = null, block: () -> T): T { inline fun <T : Any> assertNotNullOr(obj: T?, message: String? = null, block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
if (message == null) if (message == null)
assert(obj != null) assert(obj != null)
else else
@@ -18,6 +25,9 @@ inline fun <T : Any> assertNotNullOr(obj: T?, message: String? = null, block: ()
* Less aggressive version of `require(condition)`, which fails in devenv but continues at runtime. * Less aggressive version of `require(condition)`, which fails in devenv but continues at runtime.
*/ */
inline fun assertTrueOr(condition: Boolean, block: () -> Unit) { inline fun assertTrueOr(condition: Boolean, block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
assert(condition) assert(condition)
if (!condition) block() if (!condition) block()
} }

View File

@@ -0,0 +1,8 @@
package moe.nea.firmament.util.render
import org.joml.Matrix4f
import net.minecraft.client.gui.DrawContext
fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {
return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0
}

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.util package moe.nea.firmament.util
import java.math.BigInteger import java.math.BigInteger

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,10 @@
{
"gui": {
"scaling": {
"type": "nine_slice",
"width": 91,
"height": 184,
"border": 7
}
}
}