aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-09-29 22:44:13 +0200
committernea <nea@nea.moe>2023-09-29 22:44:13 +0200
commitf89135db7e500571231721ac8d5b0ffff63469df (patch)
tree50d9f6ed963468194dcbaced0e508e120240b4f0
parent7a71e77b4cc79331b135aa95b4b8c9dbdf9e76ef (diff)
downloadfirmament-f89135db7e500571231721ac8d5b0ffff63469df.tar.gz
firmament-f89135db7e500571231721ac8d5b0ffff63469df.tar.bz2
firmament-f89135db7e500571231721ac8d5b0ffff63469df.zip
Add UUID Locking (per unique item locking that allows movement)
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinClientPlayerEntity.java3
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java13
-rw-r--r--src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt27
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt61
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/MC.kt1
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt9
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json3
7 files changed, 97 insertions, 20 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinClientPlayerEntity.java b/src/main/java/moe/nea/firmament/mixins/MixinClientPlayerEntity.java
index 21e3308..16e8fc3 100644
--- a/src/main/java/moe/nea/firmament/mixins/MixinClientPlayerEntity.java
+++ b/src/main/java/moe/nea/firmament/mixins/MixinClientPlayerEntity.java
@@ -10,6 +10,7 @@ import moe.nea.firmament.events.IsSlotProtectedEvent;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.slot.Slot;
+import net.minecraft.screen.slot.SlotActionType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -24,7 +25,7 @@ public abstract class MixinClientPlayerEntity extends PlayerEntity {
@Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true)
public void onDropSelectedItem(boolean entireStack, CallbackInfoReturnable<Boolean> cir) {
Slot fakeSlot = new Slot(getInventory(), getInventory().selectedSlot, 0, 0);
- if (IsSlotProtectedEvent.shouldBlockInteraction(fakeSlot)) {
+ if (IsSlotProtectedEvent.shouldBlockInteraction(fakeSlot, SlotActionType.THROW)) {
cir.setReturnValue(false);
}
}
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
index 84c47cb..3972ffc 100644
--- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
@@ -10,6 +10,7 @@ import moe.nea.firmament.events.*;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
@@ -63,11 +64,19 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {
@Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At("HEAD"), cancellable = true)
public void onMouseClickedSlot(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) {
- if (IsSlotProtectedEvent.shouldBlockInteraction(slot)) {
+ if (slotId == -999 && getScreenHandler() != null && actionType == SlotActionType.PICKUP) { // -999 is code for "clicked outside the main window"
+ ItemStack cursorStack = getScreenHandler().getCursorStack();
+ if (cursorStack != null && IsSlotProtectedEvent.shouldBlockInteraction(slot, SlotActionType.THROW, cursorStack)) {
+ ci.cancel();
+ return;
+ }
+ }
+ if (IsSlotProtectedEvent.shouldBlockInteraction(slot, actionType)) {
ci.cancel();
+ return;
}
if (actionType == SlotActionType.SWAP && 0 <= button && button < 9) {
- if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0))) {
+ if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0), actionType)) {
ci.cancel();
}
}
diff --git a/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt
index f1a861e..02557ab 100644
--- a/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt
+++ b/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt
@@ -6,28 +6,37 @@
package moe.nea.firmament.events
+import net.minecraft.item.ItemStack
import net.minecraft.screen.slot.Slot
+import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.Text
import moe.nea.firmament.util.CommonSoundEffects
import moe.nea.firmament.util.MC
data class IsSlotProtectedEvent(
- val slot: Slot, var isProtected: Boolean = false
+ val slot: Slot?,
+ val actionType: SlotActionType,
+ var isProtected: Boolean,
+ val itemStackOverride: ItemStack?,
) : FirmamentEvent() {
+ val itemStack get() = itemStackOverride ?: slot!!.stack
+
+ fun protect() {
+ isProtected = true
+ }
+
companion object : FirmamentEventBus<IsSlotProtectedEvent>() {
@JvmStatic
- fun shouldBlockInteraction(slot: Slot?): Boolean {
- if (slot == null) return false
- return publish(IsSlotProtectedEvent(slot)).isProtected.also {
+ @JvmOverloads
+ fun shouldBlockInteraction(slot: Slot?, action: SlotActionType, itemStackOverride: ItemStack? = null): Boolean {
+ if (slot == null && itemStackOverride == null) return false
+ val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)
+ return publish(event).isProtected.also {
if (it) {
- MC.player?.sendMessage(Text.translatable("firmament.protectitem").append(slot.stack.name))
+ MC.player?.sendMessage(Text.translatable("firmament.protectitem").append(event.itemStack.name))
CommonSoundEffects.playFailure()
}
}
}
}
-
- fun protect() {
- isProtected = true
- }
}
diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
index 76a719a..943f7dd 100644
--- a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt
@@ -3,23 +3,30 @@
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+@file:UseSerializers(DashlessUUIDSerializer::class)
package moe.nea.firmament.features.inventory
+import java.util.*
import org.lwjgl.glfw.GLFW
import kotlinx.serialization.Serializable
+import kotlinx.serialization.UseSerializers
import kotlinx.serialization.serializer
import net.minecraft.entity.player.PlayerInventory
+import net.minecraft.screen.slot.SlotActionType
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.events.IsSlotProtectedEvent
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
import moe.nea.firmament.util.CommonSoundEffects
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
+import moe.nea.firmament.util.json.DashlessUUIDSerializer
+import moe.nea.firmament.util.skyblockUUID
object SlotLocking : FirmamentFeature {
override val identifier: String
@@ -29,10 +36,15 @@ object SlotLocking : FirmamentFeature {
data class Data(
val lockedSlots: MutableSet<Int> = mutableSetOf(),
val lockedSlotsRift: MutableSet<Int> = mutableSetOf(),
+
+ val lockedUUIDs: MutableSet<UUID> = mutableSetOf(),
)
object TConfig : ManagedConfig(identifier) {
- val lock by keyBinding("lock") { GLFW.GLFW_KEY_L }
+ val lockSlot by keyBinding("lock") { GLFW.GLFW_KEY_L }
+ val lockUUID by keyBindingWithOutDefaultModifiers("lock-uuid") {
+ SavedKeyBinding(GLFW.GLFW_KEY_L, shift = true)
+ }
}
override val config: TConfig
@@ -40,6 +52,8 @@ object SlotLocking : FirmamentFeature {
object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "locked-slots", ::Data)
+ val lockedUUIDs get() = DConfig.data?.lockedUUIDs
+
val lockedSlots
get() = when (SBData.skyblockLocation) {
"rift" -> DConfig.data?.lockedSlotsRift
@@ -49,7 +63,7 @@ object SlotLocking : FirmamentFeature {
override fun onLoad() {
HandledScreenKeyPressedEvent.subscribe {
- if (!it.matches(TConfig.lock)) return@subscribe
+ if (!it.matches(TConfig.lockSlot)) return@subscribe
val inventory = MC.handledScreen ?: return@subscribe
inventory as AccessorHandledScreen
@@ -65,19 +79,56 @@ object SlotLocking : FirmamentFeature {
CommonSoundEffects.playSuccess()
}
}
+ HandledScreenKeyPressedEvent.subscribe {
+ if (!it.matches(TConfig.lockUUID)) return@subscribe
+ val inventory = MC.handledScreen ?: return@subscribe
+ inventory as AccessorHandledScreen
+
+ val slot = inventory.focusedSlot_Firmament ?: return@subscribe
+ val stack = slot.stack ?: return@subscribe
+ val uuid = stack.skyblockUUID ?: return@subscribe
+ val lockedUUIDs = lockedUUIDs ?: return@subscribe
+ if (uuid in lockedUUIDs) {
+ lockedUUIDs.remove(uuid)
+ } else {
+ lockedUUIDs.add(uuid)
+ }
+ DConfig.markDirty()
+ CommonSoundEffects.playSuccess()
+ }
+ IsSlotProtectedEvent.subscribe {
+ if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
+ it.protect()
+ }
+ }
IsSlotProtectedEvent.subscribe {
- if (it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
+ if (it.actionType == SlotActionType.SWAP
+ || it.actionType == SlotActionType.PICKUP
+ || it.actionType == SlotActionType.QUICK_MOVE
+ || it.actionType == SlotActionType.QUICK_CRAFT
+ || it.actionType == SlotActionType.CLONE
+ || it.actionType == SlotActionType.PICKUP_ALL
+ ) return@subscribe
+ val stack = it.itemStack ?: return@subscribe
+ val uuid = stack.skyblockUUID ?: return@subscribe
+ if (uuid in (lockedUUIDs ?: return@subscribe)) {
it.protect()
}
}
SlotRenderEvents.Before.subscribe {
- if (it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
+ val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
+ val isUUIDLocked = (it.slot.stack?.skyblockUUID ?: return@subscribe) in (lockedUUIDs ?: setOf())
+ if (isSlotLocked || isUUIDLocked) {
it.context.fill(
it.slot.x,
it.slot.y,
it.slot.x + 16,
it.slot.y + 16,
- 0xFFFF0000.toInt()
+ when {
+ isSlotLocked -> 0xFFFF0000.toInt()
+ isUUIDLocked -> 0xFF00FF00.toInt()
+ else -> error("Slot is locked, but not by slot or uuid")
+ }
)
}
}
diff --git a/src/main/kotlin/moe/nea/firmament/util/MC.kt b/src/main/kotlin/moe/nea/firmament/util/MC.kt
index 0c09306..e8611a6 100644
--- a/src/main/kotlin/moe/nea/firmament/util/MC.kt
+++ b/src/main/kotlin/moe/nea/firmament/util/MC.kt
@@ -13,6 +13,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
import moe.nea.firmament.events.TickEvent
+import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
object MC {
diff --git a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt b/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt
index fe2b4e5..a071107 100644
--- a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt
+++ b/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt
@@ -5,11 +5,12 @@
*/
@file:UseSerializers(DashlessUUIDSerializer::class)
+
package moe.nea.firmament.util
import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.Rarity
-import java.util.UUID
+import java.util.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
import kotlinx.serialization.decodeFromString
@@ -73,6 +74,12 @@ private val jsonparser = Json { ignoreUnknownKeys = true }
val ItemStack.extraAttributes: NbtCompound
get() = getOrCreateSubNbt("ExtraAttributes")
+val ItemStack.skyblockUUIDString: String?
+ get() = extraAttributes.getString("uuid")?.takeIf { it.isNotBlank() }
+
+val ItemStack.skyblockUUID: UUID?
+ get() = skyblockUUIDString?.let { UUID.fromString(it) }
+
val ItemStack.petData: HypixelPetInfo?
get() {
val jsonString = extraAttributes.getString("petInfo")
diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json
index fb25a39..82bfb13 100644
--- a/src/main/resources/assets/firmament/lang/en_us.json
+++ b/src/main/resources/assets/firmament/lang/en_us.json
@@ -57,8 +57,6 @@
"firmament.config.fishing-warning": "Fishing Warning",
"firmament.config.fishing-warning.display-warning": "Display a warning when you are about to hook a fish",
"firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles",
- "firmament.key.slotlocking": "Lock Slot / Slot Binding",
- "firmament.key.category": "Firmament",
"firmament.protectitem": "Firmament protected your item: ",
"firmament.recipe.forge.time": "Forging Time: %s",
"firmament.pv.skills": "Skills",
@@ -97,6 +95,7 @@
"firmament.keybinding.external": "External",
"firmament.config.slot-locking": "Slot Locking",
"firmament.config.slot-locking.lock": "Lock Slot",
+ "firmament.config.slot-locking.lock-uuid": "Lock UUID (Lock Item)",
"firmament.config.fixes.auto-sprint": "Auto Sprint",
"firmament.config.fixes.auto-sprint-keybinding": "Auto Sprint KeyBinding",
"firmament.config.fixes.auto-sprint-hud": "Sprint State Hud",