feat: Add huntrap locker

This commit is contained in:
Linnea Gräf
2025-07-06 22:07:47 +02:00
parent 86176d5afc
commit b40ae8a455
4 changed files with 60 additions and 17 deletions

View File

@@ -173,7 +173,10 @@ class LegacyItemExporter private constructor(var itemStack: ItemStack) {
} }
private fun copyColour() { private fun copyColour() {
if (!itemStack.isIn(ItemTags.DYEABLE)) return if (!itemStack.isIn(ItemTags.DYEABLE)) {
itemStack.remove(DataComponentTypes.DYED_COLOR)
return
}
val leatherTint = itemStack.componentChanges.get(DataComponentTypes.DYED_COLOR)?.getOrNull() ?: return val leatherTint = itemStack.componentChanges.get(DataComponentTypes.DYED_COLOR)?.getOrNull() ?: return
legacyNbt.getOrPutCompound("display").put("color", NbtInt.of(leatherTint.rgb)) legacyNbt.getOrPutCompound("display").put("color", NbtInt.of(leatherTint.rgb))
} }

View File

@@ -4,7 +4,6 @@ package moe.nea.firmament.features.inventory
import java.util.UUID import java.util.UUID
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import util.render.CustomRenderLayers
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
@@ -19,9 +18,8 @@ import kotlinx.serialization.json.int
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderLayers
import net.minecraft.client.render.TexturedRenderLayers
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.screen.GenericContainerScreenHandler import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType import net.minecraft.screen.slot.SlotActionType
@@ -44,14 +42,20 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.SkyBlockIsland import moe.nea.firmament.util.SkyBlockIsland
import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.data.ProfileSpecificDataHolder
import moe.nea.firmament.util.extraAttributes
import moe.nea.firmament.util.json.DashlessUUIDSerializer import moe.nea.firmament.util.json.DashlessUUIDSerializer
import moe.nea.firmament.util.lime
import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex
import moe.nea.firmament.util.mc.SlotUtils.swapWithHotBar import moe.nea.firmament.util.mc.SlotUtils.swapWithHotBar
import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.red
import moe.nea.firmament.util.render.drawLine import moe.nea.firmament.util.render.drawLine
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.DungeonUtil import moe.nea.firmament.util.skyblock.DungeonUtil
import moe.nea.firmament.util.skyblock.SkyBlockItems
import moe.nea.firmament.util.skyblockUUID import moe.nea.firmament.util.skyblockUUID
import moe.nea.firmament.util.tr
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString
object SlotLocking : FirmamentFeature { object SlotLocking : FirmamentFeature {
@@ -132,6 +136,7 @@ object SlotLocking : FirmamentFeature {
val slotBindRequireShift by toggle("require-quick-move") { true } val slotBindRequireShift by toggle("require-quick-move") { true }
val slotRenderLines by choice("bind-render") { SlotRenderLinesMode.ONLY_BOXES } val slotRenderLines by choice("bind-render") { SlotRenderLinesMode.ONLY_BOXES }
val allowMultiBinding by toggle("multi-bind") { true } // TODO: filter based on this option val allowMultiBinding by toggle("multi-bind") { true } // TODO: filter based on this option
val protectAllHuntingBoxes by toggle("hunting-box") { false }
val allowDroppingInDungeons by toggle("drop-in-dungeons") { true } val allowDroppingInDungeons by toggle("drop-in-dungeons") { true }
} }
@@ -193,10 +198,12 @@ object SlotLocking : FirmamentFeature {
var anyBlocked = false var anyBlocked = false
for (i in 0 until event.slot.index) { for (i in 0 until event.slot.index) {
val stack = inv.getStack(i) val stack = inv.getStack(i)
if (IsSlotProtectedEvent.shouldBlockInteraction(null, if (IsSlotProtectedEvent.shouldBlockInteraction(
SlotActionType.THROW, null,
IsSlotProtectedEvent.MoveOrigin.SALVAGE, SlotActionType.THROW,
stack) IsSlotProtectedEvent.MoveOrigin.SALVAGE,
stack
)
) )
anyBlocked = true anyBlocked = true
} }
@@ -219,12 +226,20 @@ object SlotLocking : FirmamentFeature {
&& doesNotDeleteItem && doesNotDeleteItem
) return ) return
val stack = event.itemStack ?: return val stack = event.itemStack ?: return
if (TConfig.protectAllHuntingBoxes && (stack.isHuntingBox())) {
event.protect()
return
}
val uuid = stack.skyblockUUID ?: return val uuid = stack.skyblockUUID ?: return
if (uuid in (lockedUUIDs ?: return)) { if (uuid in (lockedUUIDs ?: return)) {
event.protect() event.protect()
} }
} }
fun ItemStack.isHuntingBox(): Boolean {
return skyBlockId == SkyBlockItems.HUNTING_TOOLKIT || extraAttributes.get("tool_kit") != null
}
@Subscribe @Subscribe
fun onProtectSlot(it: IsSlotProtectedEvent) { fun onProtectSlot(it: IsSlotProtectedEvent) {
if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) { if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
@@ -271,6 +286,21 @@ object SlotLocking : FirmamentFeature {
val slot = inventory.focusedSlot_Firmament ?: return val slot = inventory.focusedSlot_Firmament ?: return
val stack = slot.stack ?: return val stack = slot.stack ?: return
if (stack.isHuntingBox()) {
MC.sendChat(
tr(
"firmament.slot-locking.hunting-box-unbindable-hint",
"The hunting box cannot be UUID bound reliably. It changes its own UUID frequently when switching tools. "
).red().append(
tr(
"firmament.slot-locking.hunting-box-unbindable-hint.solution",
"Use the Firmament config option for locking all hunting boxes instead."
).lime()
)
)
CommonSoundEffects.playFailure()
return
}
val uuid = stack.skyblockUUID ?: return val uuid = stack.skyblockUUID ?: return
val lockedUUIDs = lockedUUIDs ?: return val lockedUUIDs = lockedUUIDs ?: return
if (uuid in lockedUUIDs) { if (uuid in lockedUUIDs) {
@@ -350,12 +380,16 @@ object SlotLocking : FirmamentFeature {
hotX + sx, hotY + sy, hotX + sx, hotY + sy,
color(anyHovered) color(anyHovered)
) )
event.context.drawBorder(hotbarSlot.x + sx, event.context.drawBorder(
hotbarSlot.y + sy, hotbarSlot.x + sx,
16, 16, color(hotbarSlot in highlitSlots).color) hotbarSlot.y + sy,
event.context.drawBorder(inventorySlot.x + sx, 16, 16, color(hotbarSlot in highlitSlots).color
inventorySlot.y + sy, )
16, 16, color(inventorySlot in highlitSlots).color) event.context.drawBorder(
inventorySlot.x + sx,
inventorySlot.y + sy,
16, 16, color(inventorySlot in highlitSlots).color
)
} }
} }
@@ -383,9 +417,11 @@ object SlotLocking : FirmamentFeature {
hovX + sx, hovY + sy, hovX + sx, hovY + sy,
me.shedaniel.math.Color.ofOpaque(0x00FF00) me.shedaniel.math.Color.ofOpaque(0x00FF00)
) )
event.context.drawBorder(hoveredSlot.x + sx, event.context.drawBorder(
hoveredSlot.y + sy, hoveredSlot.x + sx,
16, 16, 0xFF00FF00u.toInt()) hoveredSlot.y + sy,
16, 16, 0xFF00FF00u.toInt()
)
} }
} }

View File

@@ -19,4 +19,5 @@ object SkyBlockItems {
val BONE_BOOMERANG = SkyblockId("BONE_BOOMERANG") val BONE_BOOMERANG = SkyblockId("BONE_BOOMERANG")
val STARRED_BONE_BOOMERANG = SkyblockId("STARRED_BONE_BOOMERANG") val STARRED_BONE_BOOMERANG = SkyblockId("STARRED_BONE_BOOMERANG")
val TRIBAL_SPEAR = SkyblockId("TRIBAL_SPEAR") val TRIBAL_SPEAR = SkyblockId("TRIBAL_SPEAR")
val HUNTING_TOOLKIT = SkyblockId("HUNTING_TOOLKIT")
} }

View File

@@ -266,6 +266,7 @@
"firmament.config.power-user.export-npc-location.description": "Export the NPC's location to the repo data", "firmament.config.power-user.export-npc-location.description": "Export the NPC's location to the repo data",
"firmament.config.power-user.export-recipe": "Export Recipe Data", "firmament.config.power-user.export-recipe": "Export Recipe Data",
"firmament.config.power-user.export-recipe.description": "Export Recipe Data to the repo data", "firmament.config.power-user.export-recipe.description": "Export Recipe Data to the repo data",
"firmament.config.power-user.highlight-non-overlay.description": "Highlight items missing in overlay",
"firmament.config.power-user.show-item-id": "Show SkyBlock Ids", "firmament.config.power-user.show-item-id": "Show SkyBlock Ids",
"firmament.config.power-user.show-item-id.description": "Show the SkyBlock id of items underneath them.", "firmament.config.power-user.show-item-id.description": "Show the SkyBlock id of items underneath them.",
"firmament.config.price-data": "Price Data", "firmament.config.price-data": "Price Data",
@@ -337,6 +338,8 @@
"firmament.config.slot-locking.bind.description": "Bind a hotbar slot to another slot. This allows quick switching between the slots by shift clicking on either slot.", "firmament.config.slot-locking.bind.description": "Bind a hotbar slot to another slot. This allows quick switching between the slots by shift clicking on either slot.",
"firmament.config.slot-locking.drop-in-dungeons": "Allow Dungeon Abilities", "firmament.config.slot-locking.drop-in-dungeons": "Allow Dungeon Abilities",
"firmament.config.slot-locking.drop-in-dungeons.description": "Allow dropping items in dungeons, to use your dungeon ultimate abilities.", "firmament.config.slot-locking.drop-in-dungeons.description": "Allow dropping items in dungeons, to use your dungeon ultimate abilities.",
"firmament.config.slot-locking.hunting-box": "Protect Hunting Box",
"firmament.config.slot-locking.hunting-box.description": "The Hunting Box frequently changes its UUID, and as such cannot be reliably protected using UUID locking. Instead this option can be used to block from dropping any Hunting Box.",
"firmament.config.slot-locking.lock": "Lock Slot", "firmament.config.slot-locking.lock": "Lock Slot",
"firmament.config.slot-locking.lock-uuid": "Lock UUID (Lock Item)", "firmament.config.slot-locking.lock-uuid": "Lock UUID (Lock Item)",
"firmament.config.slot-locking.lock-uuid.description": "Lock a SkyBlock item by it's UUID. This blocks a specific item from being dropped/sold, but still allows moving it around.", "firmament.config.slot-locking.lock-uuid.description": "Lock a SkyBlock item by it's UUID. This blocks a specific item from being dropped/sold, but still allows moving it around.",