feat: Allow dropping protected items in dungeons
This commit is contained in:
@@ -4,8 +4,11 @@ package moe.nea.firmament.mixins;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import moe.nea.firmament.events.*;
|
||||
import moe.nea.firmament.events.HandledScreenClickEvent;
|
||||
import moe.nea.firmament.events.HandledScreenForegroundEvent;
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent;
|
||||
import moe.nea.firmament.events.IsSlotProtectedEvent;
|
||||
import moe.nea.firmament.events.SlotRenderEvents;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
@@ -22,9 +25,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@Mixin(value = HandledScreen.class, priority = 990)
|
||||
public abstract class MixinHandledScreen<T extends ScreenHandler> {
|
||||
@@ -74,17 +74,17 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {
|
||||
public void onMouseClickedSlot(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) {
|
||||
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)) {
|
||||
if (cursorStack != null && IsSlotProtectedEvent.shouldBlockInteraction(slot, SlotActionType.THROW, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE, cursorStack)) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(slot, actionType)) {
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(slot, actionType, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE)) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
if (actionType == SlotActionType.SWAP && 0 <= button && button < 9) {
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0), actionType)) {
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(new Slot(playerInventory, button, 0, 0), actionType, IsSlotProtectedEvent.MoveOrigin.INVENTORY_MOVE)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract class PlayerDropEventPatch 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, SlotActionType.THROW)) {
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(fakeSlot, SlotActionType.THROW, IsSlotProtectedEvent.MoveOrigin.DROP_FROM_HOTBAR)) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
package moe.nea.firmament.events
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
@@ -14,12 +12,14 @@ data class IsSlotProtectedEvent(
|
||||
val actionType: SlotActionType,
|
||||
var isProtected: Boolean,
|
||||
val itemStackOverride: ItemStack?,
|
||||
val origin: MoveOrigin,
|
||||
var silent: Boolean = false,
|
||||
) : FirmamentEvent() {
|
||||
val itemStack get() = itemStackOverride ?: slot!!.stack
|
||||
|
||||
fun protect() {
|
||||
isProtected = true
|
||||
silent = false
|
||||
}
|
||||
|
||||
fun protectSilent() {
|
||||
@@ -29,12 +29,22 @@ data class IsSlotProtectedEvent(
|
||||
isProtected = true
|
||||
}
|
||||
|
||||
enum class MoveOrigin {
|
||||
DROP_FROM_HOTBAR,
|
||||
SALVAGE,
|
||||
INVENTORY_MOVE
|
||||
;
|
||||
}
|
||||
companion object : FirmamentEventBus<IsSlotProtectedEvent>() {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun shouldBlockInteraction(slot: Slot?, action: SlotActionType, itemStackOverride: ItemStack? = null): Boolean {
|
||||
fun shouldBlockInteraction(
|
||||
slot: Slot?, action: SlotActionType,
|
||||
origin: MoveOrigin,
|
||||
itemStackOverride: ItemStack? = null,
|
||||
): Boolean {
|
||||
if (slot == null && itemStackOverride == null) return false
|
||||
val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)
|
||||
val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride, origin)
|
||||
publish(event)
|
||||
if (event.isProtected && !event.silent) {
|
||||
MC.sendChat(Text.translatable("firmament.protectitem").append(event.itemStack.name))
|
||||
|
||||
@@ -45,10 +45,6 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
||||
|
||||
private var hasAutoloaded = false
|
||||
|
||||
init {
|
||||
autoload()
|
||||
}
|
||||
|
||||
fun autoload() {
|
||||
synchronized(this) {
|
||||
if (hasAutoloaded) return
|
||||
|
||||
@@ -15,6 +15,7 @@ import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.FeaturesInitializedEvent
|
||||
import moe.nea.firmament.events.HandledScreenForegroundEvent
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||
import moe.nea.firmament.events.HandledScreenKeyReleasedEvent
|
||||
@@ -37,6 +38,7 @@ import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.render.GuiRenderLayers
|
||||
import moe.nea.firmament.util.render.drawLine
|
||||
import moe.nea.firmament.util.skyblock.DungeonUtil
|
||||
import moe.nea.firmament.util.skyblockUUID
|
||||
import moe.nea.firmament.util.unformattedString
|
||||
|
||||
@@ -60,6 +62,7 @@ object SlotLocking : FirmamentFeature {
|
||||
val slotBind by keyBinding("bind") { GLFW.GLFW_KEY_L }
|
||||
val slotBindRequireShift by toggle("require-quick-move") { true }
|
||||
val slotRenderLines by choice("bind-render") { SlotRenderLinesMode.ONLY_BOXES }
|
||||
val allowDroppingInDungeons by toggle("drop-in-dungeons") { true }
|
||||
}
|
||||
|
||||
enum class SlotRenderLinesMode : StringIdentifiable {
|
||||
@@ -120,7 +123,11 @@ object SlotLocking : FirmamentFeature {
|
||||
var anyBlocked = false
|
||||
for (i in 0 until event.slot.index) {
|
||||
val stack = inv.getStack(i)
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack))
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(null,
|
||||
SlotActionType.THROW,
|
||||
IsSlotProtectedEvent.MoveOrigin.SALVAGE,
|
||||
stack)
|
||||
)
|
||||
anyBlocked = true
|
||||
}
|
||||
if (anyBlocked) {
|
||||
@@ -155,6 +162,19 @@ object SlotLocking : FirmamentFeature {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onEvent(event: FeaturesInitializedEvent) {
|
||||
IsSlotProtectedEvent.subscribe(receivesCancelled = true, "SlotLocking:unlockInDungeons") {
|
||||
if (it.isProtected
|
||||
&& it.origin == IsSlotProtectedEvent.MoveOrigin.DROP_FROM_HOTBAR
|
||||
&& DungeonUtil.isInActiveDungeon
|
||||
&& TConfig.allowDroppingInDungeons
|
||||
) {
|
||||
it.isProtected = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onQuickMoveBoundSlot(it: IsSlotProtectedEvent) {
|
||||
val boundSlots = DConfig.data?.boundSlots ?: mapOf()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
package moe.nea.firmament.util
|
||||
|
||||
import java.util.*
|
||||
import java.util.Optional
|
||||
import net.minecraft.client.gui.hud.InGameHud
|
||||
import net.minecraft.scoreboard.ScoreboardDisplaySlot
|
||||
import net.minecraft.scoreboard.Team
|
||||
@@ -10,8 +8,20 @@ import net.minecraft.text.StringVisitable
|
||||
import net.minecraft.text.Style
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Formatting
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
|
||||
fun getScoreboardLines(): List<Text> {
|
||||
object ScoreboardUtil {
|
||||
var scoreboardLines: List<Text> = listOf()
|
||||
var simplifiedScoreboardLines: List<String> = listOf()
|
||||
|
||||
@Subscribe
|
||||
fun onTick(event: TickEvent) {
|
||||
scoreboardLines = getScoreboardLinesUncached()
|
||||
simplifiedScoreboardLines = scoreboardLines.map { it.unformattedString }
|
||||
}
|
||||
|
||||
private fun getScoreboardLinesUncached(): List<Text> {
|
||||
val scoreboard = MC.player?.scoreboard ?: return listOf()
|
||||
val activeObjective = scoreboard.getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR) ?: return listOf()
|
||||
return scoreboard.getScoreboardEntries(activeObjective)
|
||||
@@ -23,7 +33,7 @@ fun getScoreboardLines(): List<Text> {
|
||||
Team.decorateName(team, text)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Text.formattedString(): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
@@ -36,6 +36,7 @@ private constructor(
|
||||
val RIFT = forMode("rift")
|
||||
val MINESHAFT = forMode("mineshaft")
|
||||
val GARDEN = forMode("garden")
|
||||
val DUNGEON = forMode("dungeon")
|
||||
}
|
||||
|
||||
val userFriendlyName
|
||||
|
||||
33
src/main/kotlin/util/skyblock/DungeonUtil.kt
Normal file
33
src/main/kotlin/util/skyblock/DungeonUtil.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
package moe.nea.firmament.util.skyblock
|
||||
|
||||
import moe.nea.firmament.util.SBData
|
||||
import moe.nea.firmament.util.ScoreboardUtil
|
||||
import moe.nea.firmament.util.SkyBlockIsland
|
||||
import moe.nea.firmament.util.TIME_PATTERN
|
||||
|
||||
object DungeonUtil {
|
||||
val isInDungeonIsland get() = SBData.skyblockLocation == SkyBlockIsland.DUNGEON
|
||||
private val timeElapsedRegex = "Time Elapsed: $TIME_PATTERN".toRegex()
|
||||
val isInActiveDungeon get() = isInDungeonIsland && ScoreboardUtil.simplifiedScoreboardLines.any { it.matches(
|
||||
timeElapsedRegex) }
|
||||
|
||||
/*Title:
|
||||
|
||||
§f§lSKYBLOCK§B§L CO-OP
|
||||
|
||||
' Late Spring 7th'
|
||||
' §75:20am'
|
||||
' §7⏣ §cThe Catacombs §7(M3)'
|
||||
' §7♲ §7Ironman'
|
||||
' '
|
||||
'Keys: §c■ §c✗ §8■ §a1x'
|
||||
'Time Elapsed: §a46s'
|
||||
'Cleared: §660% §8(105)'
|
||||
' '
|
||||
'§e[B] §b151_Dragon §e2,062§c❤'
|
||||
'§e[A] §6Lennart0312 §a17,165§c'
|
||||
'§e[T] §b187i §a14,581§c❤'
|
||||
'§e[H] §bFlameeke §a8,998§c❤'
|
||||
' '
|
||||
'§ewww.hypixel.net'*/
|
||||
}
|
||||
@@ -231,6 +231,8 @@
|
||||
"firmament.config.slot-locking.bind-render.choice.only_boxes": "Only boxes",
|
||||
"firmament.config.slot-locking.bind-render.description": "Disable rendering of the slot binding lines (or all of the slot binding rendering), unless the relevant slot is being hovered.",
|
||||
"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.description": "Allow dropping items in dungeons, to use your dungeon ultimate abilities.",
|
||||
"firmament.config.slot-locking.lock": "Lock Slot",
|
||||
"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.",
|
||||
|
||||
Reference in New Issue
Block a user