Refactor source layout

Introduce compat source sets and move all kotlin sources to the main directory

[no changelog]
This commit is contained in:
Linnea Gräf
2024-08-28 19:04:24 +02:00
parent a690630816
commit d2f240ff0c
251 changed files with 295 additions and 38 deletions

View File

@@ -0,0 +1,85 @@
package moe.nea.firmament.features.inventory.buttons
import com.mojang.brigadier.StringReader
import me.shedaniel.math.Dimension
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import kotlinx.serialization.Serializable
import net.minecraft.client.gui.DrawContext
import net.minecraft.command.CommandRegistryAccess
import net.minecraft.command.argument.ItemStackArgumentType
import net.minecraft.item.ItemStack
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.memoize
@Serializable
data class InventoryButton(
var x: Int,
var y: Int,
var anchorRight: Boolean,
var anchorBottom: Boolean,
var icon: String? = "",
var command: String? = "",
) {
companion object {
val itemStackParser by lazy {
ItemStackArgumentType.itemStack(CommandRegistryAccess.of(MC.defaultRegistries,
FeatureFlags.VANILLA_FEATURES))
}
val dimensions = Dimension(18, 18)
val getItemForName = ::getItemForName0.memoize(1024)
fun getItemForName0(icon: String): ItemStack {
val repoItem = RepoManager.getNEUItem(SkyblockId(icon))
var itemStack = repoItem.asItemStack(idHint = SkyblockId(icon))
if (repoItem == null) {
val giveSyntaxItem = if (icon.startsWith("/give") || icon.startsWith("give"))
icon.split(" ", limit = 3).getOrNull(2) ?: icon
else icon
val componentItem =
runCatching {
itemStackParser.parse(StringReader(giveSyntaxItem)).createStack(1, false)
}.getOrNull()
if (componentItem != null)
itemStack = componentItem
}
return itemStack
}
}
fun render(context: DrawContext) {
context.drawSprite(
0,
0,
0,
dimensions.width,
dimensions.height,
MC.guiAtlasManager.getSprite(Identifier.of("firmament:inventory_button_background"))
)
context.drawItem(getItem(), 1, 1)
}
fun isValid() = !icon.isNullOrBlank() && !command.isNullOrBlank()
fun getPosition(guiRect: Rectangle): Point {
return Point(
(if (anchorRight) guiRect.maxX else guiRect.minX) + x,
(if (anchorBottom) guiRect.maxY else guiRect.minY) + y,
)
}
fun getBounds(guiRect: Rectangle): Rectangle {
return Rectangle(getPosition(guiRect), dimensions)
}
fun getItem(): ItemStack {
return getItemForName(icon ?: "")
}
}

View File

@@ -0,0 +1,184 @@
package moe.nea.firmament.features.inventory.buttons
import io.github.notenoughupdates.moulconfig.common.IItemStack
import io.github.notenoughupdates.moulconfig.platform.ModernItemStack
import io.github.notenoughupdates.moulconfig.xml.Bind
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import org.lwjgl.glfw.GLFW
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.util.InputUtil
import net.minecraft.text.Text
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec2f
import moe.nea.firmament.util.ClipboardUtils
import moe.nea.firmament.util.FragmentGuiScreen
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MoulConfigUtils
class InventoryButtonEditor(
val lastGuiRect: Rectangle,
) : FragmentGuiScreen() {
inner class Editor(val originalButton: InventoryButton) {
@field:Bind
var command: String = originalButton.command ?: ""
@field:Bind
var icon: String = originalButton.icon ?: ""
@Bind
fun getItemIcon(): IItemStack {
save()
return ModernItemStack.of(InventoryButton.getItemForName(icon))
}
@Bind
fun delete() {
buttons.removeIf { it === originalButton }
popup = null
}
fun save() {
originalButton.icon = icon
originalButton.command = command
}
}
var buttons: MutableList<InventoryButton> =
InventoryButtons.DConfig.data.buttons.map { it.copy() }.toMutableList()
override fun close() {
InventoryButtons.DConfig.data.buttons = buttons
InventoryButtons.DConfig.markDirty()
super.close()
}
override fun init() {
super.init()
addDrawableChild(
ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.load-preset")) {
val t = ClipboardUtils.getTextContents()
val newButtons = InventoryButtonTemplates.loadTemplate(t)
if (newButtons != null)
buttons = newButtons.toMutableList()
}
.position(lastGuiRect.minX + 10, lastGuiRect.minY + 35)
.width(lastGuiRect.width - 20)
.build()
)
addDrawableChild(
ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.save-preset")) {
ClipboardUtils.setTextContent(InventoryButtonTemplates.saveTemplate(buttons))
}
.position(lastGuiRect.minX + 10, lastGuiRect.minY + 60)
.width(lastGuiRect.width - 20)
.build()
)
}
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
super.render(context, mouseX, mouseY, delta)
context.matrices.push()
context.matrices.translate(0f, 0f, -10f)
context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1)
context.setShaderColor(1f, 1f, 1f, 1f)
context.matrices.pop()
for (button in buttons) {
val buttonPosition = button.getBounds(lastGuiRect)
context.matrices.push()
context.matrices.translate(buttonPosition.minX.toFloat(), buttonPosition.minY.toFloat(), 0F)
button.render(context)
context.matrices.pop()
}
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
if (super.keyPressed(keyCode, scanCode, modifiers)) return true
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
close()
return true
}
return false
}
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (super.mouseReleased(mouseX, mouseY, button)) return true
val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) }
if (clickedButton != null && !justPerformedAClickAction) {
createPopup(MoulConfigUtils.loadGui("button_editor_fragment", Editor(clickedButton)), Point(mouseX, mouseY))
return true
}
justPerformedAClickAction = false
lastDraggedButton = null
return false
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) return true
if (initialDragMousePosition.distanceSquared(Vec2f(mouseX.toFloat(), mouseY.toFloat())) >= 4 * 4) {
initialDragMousePosition = Vec2f(-10F, -10F)
lastDraggedButton?.let { dragging ->
justPerformedAClickAction = true
val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mouseX.toInt(), mouseY.toInt())
?: return true
dragging.x = offsetX
dragging.y = offsetY
dragging.anchorRight = anchorRight
dragging.anchorBottom = anchorBottom
}
}
return false
}
var lastDraggedButton: InventoryButton? = null
var justPerformedAClickAction = false
var initialDragMousePosition = Vec2f(-10F, -10F)
data class AnchoredCoords(
val anchorRight: Boolean,
val anchorBottom: Boolean,
val offsetX: Int,
val offsetY: Int,
)
fun getCoordsForMouse(mx: Int, my: Int): AnchoredCoords? {
if (lastGuiRect.contains(mx, my) || lastGuiRect.contains(
Point(
mx + InventoryButton.dimensions.width,
my + InventoryButton.dimensions.height,
)
)
) return null
val anchorRight = mx > lastGuiRect.maxX
val anchorBottom = my > lastGuiRect.maxY
var offsetX = mx - if (anchorRight) lastGuiRect.maxX else lastGuiRect.minX
var offsetY = my - if (anchorBottom) lastGuiRect.maxY else lastGuiRect.minY
if (InputUtil.isKeyPressed(MC.window.handle, InputUtil.GLFW_KEY_LEFT_SHIFT)) {
offsetX = MathHelper.floor(offsetX / 20F) * 20
offsetY = MathHelper.floor(offsetY / 20F) * 20
}
return AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (super.mouseClicked(mouseX, mouseY, button)) return true
val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) }
if (clickedButton != null) {
lastDraggedButton = clickedButton
initialDragMousePosition = Vec2f(mouseX.toFloat(), mouseY.toFloat())
return true
}
val mx = mouseX.toInt()
val my = mouseY.toInt()
val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mx, my) ?: return true
buttons.add(InventoryButton(offsetX, offsetY, anchorRight, anchorBottom, null, null))
justPerformedAClickAction = true
return true
}
}

View File

@@ -0,0 +1,35 @@
package moe.nea.firmament.features.inventory.buttons
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.TemplateUtil
object InventoryButtonTemplates {
val legacyPrefix = "NEUBUTTONS/"
val modernPrefix = "MAYBEONEDAYIWILLHAVEMYOWNFORMAT"
fun loadTemplate(t: String): List<InventoryButton>? {
val buttons = TemplateUtil.maybeDecodeTemplate<List<String>>(legacyPrefix, t) ?: return null
return buttons.mapNotNull {
try {
Firmament.json.decodeFromString<InventoryButton>(it).also {
if (it.icon?.startsWith("extra:") == true || it.command?.any { it.isLowerCase() } == true) {
MC.sendChat(Text.translatable("firmament.inventory-buttons.import-failed"))
}
}
} catch (e: Exception) {
null
}
}
}
fun saveTemplate(buttons: List<InventoryButton>): String {
return TemplateUtil.encodeTemplate(legacyPrefix, buttons.map { Firmament.json.encodeToString(it) })
}
}

View File

@@ -0,0 +1,88 @@
package moe.nea.firmament.features.inventory.buttons
import me.shedaniel.math.Rectangle
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenClickEvent
import moe.nea.firmament.events.HandledScreenForegroundEvent
import moe.nea.firmament.events.HandledScreenPushREIEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.data.DataHolder
import moe.nea.firmament.util.getRectangle
object InventoryButtons : FirmamentFeature {
override val identifier: String
get() = "inventory-buttons"
object TConfig : ManagedConfig(identifier) {
val _openEditor by button("open-editor") {
openEditor()
}
}
object DConfig : DataHolder<Data>(serializer(), identifier, ::Data)
@Serializable
data class Data(
var buttons: MutableList<InventoryButton> = mutableListOf()
)
override val config: ManagedConfig
get() = TConfig
fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() }
@Subscribe
fun onRectangles(it: HandledScreenPushREIEvent) {
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds)
it.block(buttonBounds)
}
}
@Subscribe
fun onClickScreen(it: HandledScreenClickEvent) {
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds)
if (buttonBounds.contains(it.mouseX, it.mouseY)) {
MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */)
break
}
}
}
@Subscribe
fun onRenderForeground(it: HandledScreenForegroundEvent) {
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds)
it.context.matrices.push()
it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F)
button.render(it.context)
it.context.matrices.pop()
}
lastRectangle = bounds
}
var lastRectangle: Rectangle? = null
fun openEditor() {
ScreenUtil.setScreenLater(
InventoryButtonEditor(
lastRectangle ?: Rectangle(
MC.window.scaledWidth / 2 - 100,
MC.window.scaledHeight / 2 - 100,
200, 200,
)
)
)
}
}