feat: allow skull:texturehash items for neu buttons

This commit is contained in:
Linnea Gräf
2025-06-07 23:05:41 +02:00
parent 120fba3bbc
commit 1f24736e0c
4 changed files with 109 additions and 82 deletions

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.features.inventory.buttons
import com.mojang.brigadier.StringReader
@@ -18,69 +16,86 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.collections.memoize
import moe.nea.firmament.util.mc.arbitraryUUID
import moe.nea.firmament.util.mc.createSkullItem
import moe.nea.firmament.util.render.drawGuiTexture
@Serializable
data class InventoryButton(
var x: Int,
var y: Int,
var anchorRight: Boolean,
var anchorBottom: Boolean,
var icon: String? = "",
var command: String? = "",
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
}
}
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) {
when {
icon.startsWith("skull:") -> {
itemStack = createSkullItem(
arbitraryUUID,
"https://textures.minecraft.net/texture/${icon.substring("skull:".length)}"
)
}
fun render(context: DrawContext) {
context.drawGuiTexture(
0,
0,
0,
dimensions.width,
dimensions.height,
Identifier.of("firmament:inventory_button_background")
)
context.drawItem(getItem(), 1, 1)
}
else -> {
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 isValid() = !icon.isNullOrBlank() && !command.isNullOrBlank()
fun render(context: DrawContext) {
context.drawGuiTexture(
0,
0,
0,
dimensions.width,
dimensions.height,
Identifier.of("firmament:inventory_button_background")
)
context.drawItem(getItem(), 1, 1)
}
fun getPosition(guiRect: Rectangle): Point {
return Point(
(if (anchorRight) guiRect.maxX else guiRect.minX) + x,
(if (anchorBottom) guiRect.maxY else guiRect.minY) + y,
)
}
fun isValid() = !icon.isNullOrBlank() && !command.isNullOrBlank()
fun getBounds(guiRect: Rectangle): Rectangle {
return Rectangle(getPosition(guiRect), dimensions)
}
fun getPosition(guiRect: Rectangle): Point {
return Point(
(if (anchorRight) guiRect.maxX else guiRect.minX) + x,
(if (anchorBottom) guiRect.maxY else guiRect.minY) + y,
)
}
fun getItem(): ItemStack {
return getItemForName(icon ?: "")
}
fun getBounds(guiRect: Rectangle): Rectangle {
return Rectangle(getPosition(guiRect), dimensions)
}
fun getItem(): ItemStack {
return getItemForName(icon ?: "")
}
}

View File

@@ -1,7 +1,9 @@
package moe.nea.firmament.features.inventory.buttons
import io.github.notenoughupdates.moulconfig.common.IItemStack
import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent
import io.github.notenoughupdates.moulconfig.platform.ModernItemStack
import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext
import io.github.notenoughupdates.moulconfig.xml.Bind
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
@@ -57,7 +59,10 @@ class InventoryButtonEditor(
}
override fun resize(client: MinecraftClient, width: Int, height: Int) {
lastGuiRect.move(MC.window.scaledWidth / 2 - lastGuiRect.width / 2, MC.window.scaledHeight / 2 - lastGuiRect.height / 2)
lastGuiRect.move(
MC.window.scaledWidth / 2 - lastGuiRect.width / 2,
MC.window.scaledHeight / 2 - lastGuiRect.height / 2
)
super.resize(client, width, height)
}
@@ -89,14 +94,20 @@ class InventoryButtonEditor(
val movedButtons = mutableListOf<InventoryButton>()
for (button in buttons) {
if ((!button.anchorBottom && !button.anchorRight && button.x > 0 && button.y > 0)) {
MC.sendChat(tr("firmament.inventory-buttons.button-moved",
"One of your imported buttons intersects with the inventory and has been moved to the top left."))
movedButtons.add(button.copy(
x = 0,
y = -InventoryButton.dimensions.width,
anchorRight = false,
anchorBottom = false
))
MC.sendChat(
tr(
"firmament.inventory-buttons.button-moved",
"One of your imported buttons intersects with the inventory and has been moved to the top left."
)
)
movedButtons.add(
button.copy(
x = 0,
y = -InventoryButton.dimensions.width,
anchorRight = false,
anchorBottom = false
)
)
} else {
newButtons.add(button)
}
@@ -105,9 +116,11 @@ class InventoryButtonEditor(
val zeroRect = Rectangle(0, 0, 1, 1)
for (movedButton in movedButtons) {
fun getPosition(button: InventoryButton, index: Int) =
button.copy(x = (index % 10) * InventoryButton.dimensions.width,
y = (index / 10) * -InventoryButton.dimensions.height,
anchorRight = false, anchorBottom = false)
button.copy(
x = (index % 10) * InventoryButton.dimensions.width,
y = (index / 10) * -InventoryButton.dimensions.height,
anchorRight = false, anchorBottom = false
)
while (true) {
val newPos = getPosition(movedButton, i++)
val newBounds = newPos.getBounds(zeroRect)
@@ -131,7 +144,12 @@ class InventoryButtonEditor(
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)
PanelComponent.DefaultBackgroundRenderer.VANILLA
.render(
ModernRenderContext(context),
lastGuiRect.minX, lastGuiRect.minY,
lastGuiRect.width, lastGuiRect.height,
)
context.matrices.pop()
for (button in buttons) {
val buttonPosition = button.getBounds(lastGuiRect)
@@ -193,14 +211,6 @@ class InventoryButtonEditor(
)
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
@@ -209,7 +219,10 @@ class InventoryButtonEditor(
offsetX = MathHelper.floor(offsetX / 20F) * 20
offsetY = MathHelper.floor(offsetY / 20F) * 20
}
return AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY)
val rect = InventoryButton(offsetX, offsetY, anchorRight, anchorBottom).getBounds(lastGuiRect)
if (rect.intersects(lastGuiRect)) return null
val anchoredCoords = AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY)
return anchoredCoords
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {

View File

@@ -11,7 +11,7 @@ import net.minecraft.item.Items
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.mc.setEncodedSkullOwner
import moe.nea.firmament.util.mc.zeroUUID
import moe.nea.firmament.util.mc.arbitraryUUID
object ModifyEquipment : EntityModifier {
val names = mapOf(
@@ -36,7 +36,7 @@ object ModifyEquipment : EntityModifier {
if (split.size != 2) return SBItemStack(SkyblockId(item)).asImmutableItemStack()
val (type, data) = split
return when (type) {
"SKULL" -> ItemStack(Items.PLAYER_HEAD).also { it.setEncodedSkullOwner(zeroUUID, data) }
"SKULL" -> ItemStack(Items.PLAYER_HEAD).also { it.setEncodedSkullOwner(arbitraryUUID, data) }
"LEATHER_LEGGINGS" -> coloredLeatherArmor(Items.LEATHER_LEGGINGS, data)
"LEATHER_BOOTS" -> coloredLeatherArmor(Items.LEATHER_BOOTS, data)
"LEATHER_HELMET" -> coloredLeatherArmor(Items.LEATHER_HELMET, data)

View File

@@ -10,7 +10,6 @@ import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.encodeToString
import net.minecraft.component.DataComponentTypes
import net.minecraft.component.type.ProfileComponent
import net.minecraft.item.ItemStack
@@ -51,7 +50,7 @@ fun ItemStack.setEncodedSkullOwner(uuid: UUID, encodedData: String) {
this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile))
}
val zeroUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1")
val arbitraryUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1")
fun createSkullItem(uuid: UUID, url: String) = ItemStack(Items.PLAYER_HEAD)
.also { it.setSkullOwner(uuid, url) }