diff --git a/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererInvoker.java b/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererAccessor.java similarity index 92% rename from src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererInvoker.java rename to src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererAccessor.java index 2f2acf55..374d50f9 100644 --- a/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererInvoker.java +++ b/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/BeaconBlockEntityRendererAccessor.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(BeaconBlockEntityRenderer.class) -public interface BeaconBlockEntityRendererInvoker { +public interface BeaconBlockEntityRendererAccessor { @Invoker static void invokeRenderBeam( MatrixStack matrices, diff --git a/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/PlayerInventoryAccessor.java b/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/PlayerInventoryAccessor.java index d6886b4c..c25f425d 100644 --- a/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/PlayerInventoryAccessor.java +++ b/src/main/java/me/nobaboy/nobaaddons/mixins/accessors/PlayerInventoryAccessor.java @@ -1,7 +1,8 @@ package me.nobaboy.nobaaddons.mixins.accessors; //? if >=1.21.5 { -/*import net.minecraft.entity.player.PlayerInventory; +/*import net.minecraft.entity.EntityEquipment; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.collection.DefaultedList; import org.spongepowered.asm.mixin.Mixin; @@ -9,7 +10,7 @@ @Mixin(PlayerInventory.class) public interface PlayerInventoryAccessor { - @Accessor - DefaultedList getMain(); + @Accessor DefaultedList getMain(); + @Accessor EntityEquipment getEquipment(); } *///?} diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/NobaAddons.kt b/src/main/kotlin/me/nobaboy/nobaaddons/NobaAddons.kt index 2086f94f..5b2e76fb 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/NobaAddons.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/NobaAddons.kt @@ -62,5 +62,4 @@ object NobaAddons : ClientModInitializer { NobaAddonsApis NobaAddonsModules } - } \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/api/InventoryAPI.kt b/src/main/kotlin/me/nobaboy/nobaaddons/api/InventoryAPI.kt index 8a61bed3..ab3426d1 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/api/InventoryAPI.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/api/InventoryAPI.kt @@ -1,69 +1,25 @@ package me.nobaboy.nobaaddons.api -//? if >=1.21.5 { -/*import me.nobaboy.nobaaddons.mixins.accessors.PlayerInventoryAccessor -*///?} - -import me.nobaboy.nobaaddons.api.skyblock.SkyBlockAPI -import me.nobaboy.nobaaddons.config.NobaConfig import me.nobaboy.nobaaddons.data.InventoryData import me.nobaboy.nobaaddons.events.impl.client.InventoryEvents import me.nobaboy.nobaaddons.events.impl.client.PacketEvents -import me.nobaboy.nobaaddons.events.impl.client.TickEvents -import me.nobaboy.nobaaddons.events.impl.client.WorldEvents import me.nobaboy.nobaaddons.utils.MCUtils -import me.nobaboy.nobaaddons.utils.TextUtils.buildLiteral -import me.nobaboy.nobaaddons.utils.Timestamp import me.nobaboy.nobaaddons.utils.annotations.ApiModule import net.minecraft.client.gui.screen.ChatScreen -import net.minecraft.entity.player.PlayerInventory import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket import net.minecraft.network.packet.s2c.play.CloseScreenS2CPacket import net.minecraft.network.packet.s2c.play.InventoryS2CPacket import net.minecraft.network.packet.s2c.play.OpenScreenS2CPacket import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket -import net.minecraft.text.Text -import net.minecraft.util.Formatting -import java.util.concurrent.ConcurrentHashMap @ApiModule object InventoryAPI { - private val MERCHANT_COUNT = Regex("x\\d+") - private const val SKYBLOCK_MENU_SLOT = 8 - + private var currentScreen: Screen? = null private var currentInventory: InventoryData? = null - private var currentWindow: Window? = null - - private var inventorySuppressTime = Timestamp.distantPast() - private var previousItemCounts: Map? = null - val itemLog = ConcurrentHashMap() - - private fun shouldSuppressItemLogUpdate(): Boolean = inventorySuppressTime.elapsedSeconds() < 2 init { - TickEvents.every(5, this::onQuarterSecond) PacketEvents.SEND.register(this::onPacketSend) PacketEvents.POST_RECEIVE.register(this::onPacketReceive) - WorldEvents.LOAD.register { debounceItemLog() } - } - - private fun onQuarterSecond(event: TickEvents.Tick) { - val player = event.client.player - if(!SkyBlockAPI.inSkyBlock || player == null) { - previousItemCounts = null - itemLog.clear() - return - } - - if(event.client.currentScreen == null) { - val current = player.inventory.itemNamesToCount() - previousItemCounts?.takeIf { !shouldSuppressItemLogUpdate() }?.let { updateItemLog(it, current) } - previousItemCounts = current - } - - itemLog.entries.removeIf { (_, diff) -> - diff.timestamp.elapsedSeconds() > NobaConfig.inventory.itemPickupLog.timeoutSeconds - } } private fun onPacketSend(event: PacketEvents.Send) { @@ -82,11 +38,11 @@ object InventoryAPI { } private fun onScreenOpen(packet: OpenScreenS2CPacket) { - currentWindow = Window(packet.syncId, packet.name.string) + currentScreen = Screen(packet.syncId, packet.name.string) } private fun onInventory(packet: InventoryS2CPacket) { - if(packet.syncId != currentWindow?.id) return + if(packet.syncId != currentScreen?.id) return val slotCount = packet.contents.size - 36 val items = packet.contents @@ -96,22 +52,19 @@ object InventoryAPI { .associate { it.index to it.value } .toMutableMap() - currentInventory = InventoryData(currentWindow!!.id, currentWindow!!.title, slotCount, items).also(::ready) + currentInventory = InventoryData(currentScreen!!.id, currentScreen!!.title, slotCount, items).also(::ready) } private fun onSlotUpdate(packet: ScreenHandlerSlotUpdateS2CPacket) { - if(packet.syncId != currentWindow?.id) { - InventoryEvents.SLOT_UPDATE.dispatch(InventoryEvents.SlotUpdate(packet.stack, packet.slot)) - return - } + if(packet.syncId != currentScreen?.id) return - val inventory = currentInventory ?: return + val currentInventory = currentInventory ?: return val slot = packet.slot - if(slot >= inventory.slotCount) return - packet.stack?.let { inventory.items[slot] = it } + if(slot >= currentInventory.slotCount) return + currentInventory.items[slot] = packet.stack - InventoryEvents.UPDATE.dispatch(InventoryEvents.Update(inventory)) + InventoryEvents.UPDATE.dispatch(InventoryEvents.Update(currentInventory)) } private fun ready(inventory: InventoryData) { @@ -119,78 +72,10 @@ object InventoryAPI { InventoryEvents.UPDATE.dispatch(InventoryEvents.Update(inventory)) } - private fun debounceItemLog() { - previousItemCounts = null - inventorySuppressTime = Timestamp.now() - } - private fun close(sameName: Boolean = false) { if(MCUtils.client.currentScreen is ChatScreen) return InventoryEvents.CLOSE.dispatch(InventoryEvents.Close(sameName)) } - private fun updateItemLog(previous: Map, current: Map) { - // this MUST be annotated, as the kotlin compiler can't figure out the typing automatically from getOrPut, - // despite the fact that intellij doesn't throw any warnings. - val diffs = buildMap { - for(item in (previous.keys + current.keys)) { - val previousCount = previous[item] ?: 0 - val currentCount = current[item] ?: 0 - if(previousCount == currentCount) continue - getOrPut(item) { ItemDiff(item) }.change += currentCount - previousCount - } - } - - for((name, diff) in diffs) { - if(diff.change == 0) continue - val logDiff = itemLog.getOrPut(name) { ItemDiff(name) } - logDiff.change += diff.change - logDiff.timestamp = Timestamp.now() - } - } - - private fun Text.removeMerchantCount(): Text { - if(siblings.size <= 1) return this - val last = siblings.last() - // celeste — Today at 01:19 - // i have reworded this comment like 10 times now - // i cannot figure out a way to properly express how much i hate having to do this - if(last.string.matches(MERCHANT_COUNT) && last.style.color?.rgb == Formatting.DARK_GRAY.colorValue!!) { - val copy = copy() - copy.siblings.removeLast() - val name = copy.siblings.removeLast() - val content = name.string.removeSuffix(" ") - copy.append(buildLiteral(content) { style = name.style }) - return copy - } - return this - } - - private fun PlayerInventory.itemNamesToCount(): Map = buildMap { - //? if >=1.21.5 { - /*val main = (this@itemNamesToCount as PlayerInventoryAccessor).main - *///?} - - for(slot in 0 until main.size) { - if(slot == SKYBLOCK_MENU_SLOT) { - continue - } - - val item = main[slot] - if(item.isEmpty) continue - val name = item.name.removeMerchantCount() - - merge(name, item.count, Int::plus) - } - // TODO fix for 1.21.5 -// offHand.firstOrNull()?.let { merge(name, it.count, Int::plus) } - } - - data class Window(val id: Int, val title: String) - - data class ItemDiff( - val name: Text, - var change: Int = 0, - var timestamp: Timestamp = Timestamp.now(), - ) -} + private data class Screen(val id: Int, val title: String) +} \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/PetAPI.kt b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/PetAPI.kt index 78f9c02e..95a5a3e7 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/PetAPI.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/PetAPI.kt @@ -56,9 +56,7 @@ object PetAPI { event.inventory.items.values.forEach { itemStack -> val pet = getPetData(itemStack) ?: return@forEach - if(!pet.active) return@forEach - - changePet(pet) + if(pet.active) changePet(pet) } } @@ -67,7 +65,7 @@ object PetAPI { if(event.button != GLFW.GLFW_MOUSE_BUTTON_1) return if(event.actionType != SlotActionType.PICKUP) return - getPetData(event.itemStack)?.let { changePet(it) } + getPetData(event.stack)?.let { changePet(it) } } private fun onChatMessage(event: ChatMessageEvents.Chat) { diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/hoppity/HoppityAPI.kt b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/hoppity/HoppityAPI.kt index e2895ba9..6a2df1b3 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/hoppity/HoppityAPI.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/hoppity/HoppityAPI.kt @@ -17,7 +17,7 @@ object HoppityAPI { val inRelevantIsland: Boolean get() = unsupportedIslands.none { it.inIsland() } val hasLocatorInHand: Boolean get() = MCUtils.player?.mainHandStack?.skyBlockId == LOCATOR - val hasLocatorInHotbar: Boolean get() = InventoryUtils.getItemsInHotbar().any { it.skyBlockId == LOCATOR } + val hasLocatorInHotbar: Boolean get() = InventoryUtils.getHotbarItems().any { it.skyBlockId == LOCATOR } private val unsupportedIslands = listOf( SkyBlockIsland.PRIVATE_ISLAND, diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/mythological/DianaAPI.kt b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/mythological/DianaAPI.kt index 6c704cb1..53963bf0 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/mythological/DianaAPI.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/api/skyblock/events/mythological/DianaAPI.kt @@ -14,6 +14,6 @@ object DianaAPI { val isActive: Boolean get() = SkyBlockIsland.HUB.inIsland() && isRitualActive && hasSpadeInHotbar private val isRitualActive: Boolean get() = MayorPerk.MYTHOLOGICAL_RITUAL.isActive() - private val hasSpadeInHotbar: Boolean get() = InventoryUtils.getItemsInHotbar().any { it.skyBlockId == SPADE } + private val hasSpadeInHotbar: Boolean get() = InventoryUtils.getHotbarItems().any { it.skyBlockId == SPADE } fun hasSpadeInHand(player: PlayerEntity): Boolean = player.mainHandStack.skyBlockId == SPADE } \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/config/categories/InventoryCategory.kt b/src/main/kotlin/me/nobaboy/nobaaddons/config/categories/InventoryCategory.kt index e1c10a94..0d58574e 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/config/categories/InventoryCategory.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/config/categories/InventoryCategory.kt @@ -204,6 +204,12 @@ object InventoryCategory { name = CommonText.Config.ENABLED booleanController() } + add({ inventory.itemPickupLog::compactLines }) { + name = tr("nobaaddons.config.inventory.itemPickupLog.compactLines", "Compact Lines") + descriptionText = tr("nobaaddons.config.inventory.itemPickupLog.compactLines.tooltip", "Shows a single line with the total difference, instead of displaying the added/removed item counts separately") + require { option(enabled) } + booleanController() + } add({ inventory.itemPickupLog::timeoutSeconds }) { name = tr("nobaaddons.config.inventory.itemPickupLog.timeout", "Expire After") require { option(enabled) } diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/config/configs/InventoryConfig.kt b/src/main/kotlin/me/nobaboy/nobaaddons/config/configs/InventoryConfig.kt index fb2119f4..7aa4e784 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/config/configs/InventoryConfig.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/config/configs/InventoryConfig.kt @@ -53,6 +53,7 @@ class InventoryConfig { class ItemPickupLog { var enabled = false + var compactLines = true var timeoutSeconds = 5 } } \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/events/impl/client/InventoryEvents.kt b/src/main/kotlin/me/nobaboy/nobaaddons/events/impl/client/InventoryEvents.kt index 57548f24..7a921851 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/events/impl/client/InventoryEvents.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/events/impl/client/InventoryEvents.kt @@ -37,6 +37,6 @@ object InventoryEvents { data class Open(val inventory: InventoryData) : Event data class Close(val sameName: Boolean) : Event data class Update(val inventory: InventoryData) : Event - data class SlotUpdate(val itemStack: ItemStack, val slot: Int) : Event - data class SlotClick(val itemStack: ItemStack, val button: Int, val slot: Int, val actionType: SlotActionType) : Event + data class SlotUpdate(val stack: ItemStack, val slot: Int) : Event + data class SlotClick(val stack: ItemStack, val button: Int, val slot: Int, val actionType: SlotActionType) : Event } diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/features/events/mythological/AnnounceRareDrops.kt b/src/main/kotlin/me/nobaboy/nobaaddons/features/events/mythological/AnnounceRareDrops.kt index 0e41662d..a201ceaf 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/features/events/mythological/AnnounceRareDrops.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/features/events/mythological/AnnounceRareDrops.kt @@ -1,5 +1,7 @@ package me.nobaboy.nobaaddons.features.events.mythological +import me.nobaboy.nobaaddons.api.skyblock.events.mythological.DianaAPI +import me.nobaboy.nobaaddons.config.NobaConfig import me.nobaboy.nobaaddons.events.impl.client.InventoryEvents import me.nobaboy.nobaaddons.utils.TextUtils.buildText import me.nobaboy.nobaaddons.utils.TimedSet @@ -13,6 +15,9 @@ import kotlin.time.Duration.Companion.seconds @Module object AnnounceRareDrops { + private val config get() = NobaConfig.events.mythological + private val enabled: Boolean get() = config.announceRareDrops && DianaAPI.isActive + private val uuidCache = TimedSet(10.seconds) private val rareDrops = listOf( @@ -27,8 +32,10 @@ object AnnounceRareDrops { } private fun onSlotUpdate(event: InventoryEvents.SlotUpdate) { - val itemStack = event.itemStack - val item = itemStack.asSkyBlockItem ?: return + if(!enabled) return + + val stack = event.stack + val item = stack.asSkyBlockItem ?: return if(item.id !in rareDrops) return item.timestamp?.let { if(it.elapsedSince() > 3.seconds) return } ?: return @@ -40,7 +47,7 @@ object AnnounceRareDrops { val text = buildText { append(tr("nobaaddons.chat.rareDrop", "RARE DROP!").formatted(Formatting.GOLD, Formatting.BOLD)) append(" ") - append(itemStack.name) + append(stack.name) } ChatUtils.addMessage(text, prefix = false) diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/features/inventory/ItemPickupLog.kt b/src/main/kotlin/me/nobaboy/nobaaddons/features/inventory/ItemPickupLog.kt index 3078cfcd..28eb845e 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/features/inventory/ItemPickupLog.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/features/inventory/ItemPickupLog.kt @@ -1,28 +1,178 @@ package me.nobaboy.nobaaddons.features.inventory -import me.nobaboy.nobaaddons.api.InventoryAPI +//? if >=1.21.5 { +/*import me.nobaboy.nobaaddons.mixins.accessors.PlayerInventoryAccessor +import net.minecraft.entity.EquipmentSlot +*///?} + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap +import me.nobaboy.nobaaddons.api.skyblock.SkyBlockAPI import me.nobaboy.nobaaddons.config.NobaConfig import me.nobaboy.nobaaddons.config.UISettings +import me.nobaboy.nobaaddons.events.impl.client.TickEvents +import me.nobaboy.nobaaddons.events.impl.skyblock.SkyBlockEvents import me.nobaboy.nobaaddons.ui.TextHudElement import me.nobaboy.nobaaddons.ui.UIManager +import me.nobaboy.nobaaddons.utils.NumberUtils.addSeparators +import me.nobaboy.nobaaddons.utils.TextUtils.buildLiteral import me.nobaboy.nobaaddons.utils.TextUtils.buildText import me.nobaboy.nobaaddons.utils.TextUtils.green import me.nobaboy.nobaaddons.utils.TextUtils.literal import me.nobaboy.nobaaddons.utils.TextUtils.red +import me.nobaboy.nobaaddons.utils.Timestamp import me.nobaboy.nobaaddons.utils.tr import me.owdding.ktmodules.Module import net.minecraft.client.gui.DrawContext +import net.minecraft.entity.player.PlayerInventory import net.minecraft.text.Text -import kotlin.math.abs +import net.minecraft.util.Formatting +import kotlin.time.Duration.Companion.seconds @Module object ItemPickupLog { + private val MERCHANT_COUNT = Regex("x\\d+") + private const val SKYBLOCK_MENU_SLOT = 8 + private val config get() = NobaConfig.inventory.itemPickupLog + private val enabled: Boolean get() = config.enabled && SkyBlockAPI.inSkyBlock + + private val items = Object2ObjectArrayMap() + private val itemLog = Object2ObjectArrayMap() + + private var suppressTime = Timestamp.distantPast() init { + SkyBlockEvents.ISLAND_CHANGE.register { reset() } + TickEvents.TICK.register(this::onTick) UIManager.add(PickupLogHudElement) } + private fun onTick(event: TickEvents.Tick) { + if(!enabled) return + + itemLog.values.removeIf { it.expired } + + if(event.client.currentScreen != null) return + val player = event.client.player ?: return + + val newItems = player.inventory.nameToCount() + val oldItems = mutableMapOf().apply { putAll(items) } + items.clear() + + newItems.forEach { (name, count) -> + items[name] = items.getOrDefault(name, 0) + count + } + + // ignore item changes for ~2s when switching servers, as your inventory is + // initially empty when loading in + if(suppressTime.elapsedSince() < 2.seconds) return + detectItemChanges(items, oldItems) + } + + @Suppress("SameParameterValue") // this is intentional because I feel like it's easier to read + private fun detectItemChanges(current: Map, previous: Map) { + val names = current.keys + previous.keys + + for(name in names) { + val delta = (current[name] ?: 0) - (previous[name] ?: 0) + if(delta == 0) continue + + val entry = itemLog.getOrPut(name) { ItemEntry() } + if(delta > 0) entry.added += delta else entry.removed += -delta + entry.timestamp = Timestamp.now() + } + } + + private fun PlayerInventory.nameToCount(): Map = buildMap { + //? if >=1.21.5 { + /*val main = (this@nameToCount as PlayerInventoryAccessor).main + val equipment = (this@nameToCount as PlayerInventoryAccessor).equipment + *///?} + + main.forEachIndexed { slot, stack -> + if(slot == SKYBLOCK_MENU_SLOT || stack.isEmpty) return@forEachIndexed + + val name = stack.name.removeMerchantCount() + merge(name, stack.count, Int::plus) + } + + //? if >=1.21.5 { + /*equipment.get(EquipmentSlot.OFFHAND) + *///?} else { + offHand.firstOrNull() + //?} + ?.takeIf { !it.isEmpty } + ?.let { merge(it.name, it.count, Int::plus) } + } + + private fun Text.removeMerchantCount(): Text { + if(siblings.size <= 1) return this + val last = siblings.last() + + // celeste — Today at 01:19 + // i have reworded this comment like 10 times now + // i cannot figure out a way to properly express how much i hate having to do this + if(last.string.matches(MERCHANT_COUNT) && last.style.color?.rgb == Formatting.DARK_GRAY.colorValue!!) { + val copy = copy() + copy.siblings.removeLast() + val name = copy.siblings.removeLast() + val content = name.string.removeSuffix(" ") + copy.append(buildLiteral(content) { style = name.style }) + return copy + } + + return this + } + + private fun compileCompactLines( + added: Map, + removed: Map, + ): List = buildList { + val names = added.keys + removed.keys + + names.forEach { name -> + val delta = (added[name]?.added ?: 0) - (removed[name]?.removed ?: 0) + if(delta == 0) return@forEach + + add(buildText { + val symbol = if(delta > 0) "+" else "" + literal("$symbol${delta.addSeparators()}x ") { + if(delta > 0) green() else red() + } + append(name) + }) + } + } + + private fun compileSplitLines( + added: Map, + removed: Map, + ): List = buildList { + val names = added.keys + removed.keys + + names.forEach { name -> + added[name]?.let { entry -> + add(buildText { + literal("+${entry.added.addSeparators()}x ") { green() } + append(name) + }) + } + + removed[name]?.let { entry -> + add(buildText { + literal("-${entry.removed.addSeparators()}x ") { red() } + append(name) + }) + } + } + } + + private fun reset() { + items.clear() + itemLog.clear() + suppressTime = Timestamp.now() + } + private object PickupLogHudElement : TextHudElement(UISettings.itemPickupLog) { override val name: Text = tr("nobaaddons.ui.itemPickupLog", "Item Pickup Log") override val size: Pair = 125 to 175 @@ -31,16 +181,27 @@ object ItemPickupLog { override val maxScale: Float = 1f override fun renderText(context: DrawContext) { - renderLines(context, InventoryAPI.itemLog.filter { (_, diff) -> diff.change != 0 }.map { (name, diff) -> - buildText { - if(diff.change < 0) { - literal("- ${abs(diff.change)}x ") { red() } - } else { - literal("+ ${diff.change}x ") { green() } - } - append(name) - } - }) + val itemLog = itemLog.clone() + + val added = itemLog.filterValues { it.added > 0 } + val removed = itemLog.filterValues { it.removed > 0 } + + val lines = if(config.compactLines) { + compileCompactLines(added, removed) + } else { + compileSplitLines(added, removed) + } + + renderLines(context, lines) } } + + private data class ItemEntry( + var added: Int = 0, + var removed: Int = 0, + var timestamp: Timestamp = Timestamp.now(), + ) { + val expired: Boolean + get() = timestamp.elapsedSince() > config.timeoutSeconds.seconds + } } \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/utils/InventoryUtils.kt b/src/main/kotlin/me/nobaboy/nobaaddons/utils/InventoryUtils.kt index 0985b049..7549da70 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/utils/InventoryUtils.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/utils/InventoryUtils.kt @@ -10,6 +10,9 @@ import net.minecraft.item.ItemStack object InventoryUtils { fun openInventoryName(): String? = (MCUtils.client.currentScreen as? GenericContainerScreen)?.title?.string + fun getInventoryItems(): List = getInventoryItemsOrNull().orEmpty() + fun getHotbarItems(): List = getInventoryItemsOrNull()?.slice(0..8).orEmpty() + fun getInventoryItemsOrNull(): List? { //? if >=1.21.5 { /*return (MCUtils.player?.inventory as? PlayerInventoryAccessor)?.main @@ -17,7 +20,4 @@ object InventoryUtils { return MCUtils.player?.inventory?.main //?} } - fun getInventoryItems(): List = getInventoryItemsOrNull()?.filterNotNull().orEmpty() - - fun getItemsInHotbar(): List = getInventoryItemsOrNull()?.slice(0..8)?.filterNotNull().orEmpty() } \ No newline at end of file diff --git a/src/main/kotlin/me/nobaboy/nobaaddons/utils/render/RenderUtils.kt b/src/main/kotlin/me/nobaboy/nobaaddons/utils/render/RenderUtils.kt index 8d6ed072..5fced00b 100644 --- a/src/main/kotlin/me/nobaboy/nobaaddons/utils/render/RenderUtils.kt +++ b/src/main/kotlin/me/nobaboy/nobaaddons/utils/render/RenderUtils.kt @@ -15,7 +15,7 @@ import com.mojang.blaze3d.systems.RenderSystem import org.lwjgl.opengl.GL11 //?} -import me.nobaboy.nobaaddons.mixins.accessors.BeaconBlockEntityRendererInvoker +import me.nobaboy.nobaaddons.mixins.accessors.BeaconBlockEntityRendererAccessor import me.nobaboy.nobaaddons.utils.MCUtils import me.nobaboy.nobaaddons.utils.NobaColor import me.nobaboy.nobaaddons.utils.NobaVec @@ -245,7 +245,7 @@ object RenderUtils { matrices.push() matrices.translate(x, y, z) - BeaconBlockEntityRendererInvoker.invokeRenderBeam( + BeaconBlockEntityRendererAccessor.invokeRenderBeam( matrices, context.consumers(), //? if >=1.21.5 {