From 1734f002a7096a0e4bf11973cc52ca40d62a87fe Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Fri, 24 Apr 2026 01:01:06 +0200 Subject: [PATCH 1/4] Add shulker content preview to the item render --- .../lambda/mixin/render/DrawContextMixin.java | 17 ++++ .../module/modules/render/ContainerPreview.kt | 94 ++++++++++++++++++- .../com/lambda/util/item/ItemStackUtils.kt | 4 + .../kotlin/com/lambda/util/item/ItemUtils.kt | 20 ++++ 4 files changed, 133 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/DrawContextMixin.java b/src/main/java/com/lambda/mixin/render/DrawContextMixin.java index e3ec9410a..b0097a37c 100644 --- a/src/main/java/com/lambda/mixin/render/DrawContextMixin.java +++ b/src/main/java/com/lambda/mixin/render/DrawContextMixin.java @@ -22,14 +22,17 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.render.state.GuiRenderState; import net.minecraft.client.render.MapRenderState; import net.minecraft.component.DataComponentTypes; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.tooltip.TooltipData; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; import org.joml.Matrix3x2fStack; import org.spongepowered.asm.mixin.Final; @@ -48,6 +51,10 @@ public abstract class DrawContextMixin { @Shadow @Final MinecraftClient client; + @Unique boolean adjustSize = false; + @Shadow + @Final + public GuiRenderState state; @Unique private final MapRenderState mapRenderState = new MapRenderState(); @@ -95,4 +102,14 @@ private void onDrawTooltip(TextRenderer textRenderer, List text, Optional< ContainerPreview.renderShulkerTooltip((DrawContext)(Object)this, textRenderer, x, y); } } + + @Inject(method = "drawItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;III)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/state/GuiRenderState;addItem(Lnet/minecraft/client/gui/render/state/ItemGuiElementRenderState;)V" + , shift = At.Shift.AFTER + ) + ) + private void onDrawItem(LivingEntity entity, World world, ItemStack stack, int x, int y, int seed, CallbackInfo ci) { + if (!ContainerPreview.INSTANCE.isEnabled()) return; + ContainerPreview.drawOnItem((DrawContext) (Object) this, state, entity, world, stack, x, y, seed); + } } diff --git a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt index d92f54960..6dd812ebd 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -25,15 +25,25 @@ import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import com.lambda.util.InputUtils.isSatisfied import com.lambda.util.KeyCode +import com.lambda.util.item.ItemStackUtils.bundleContents import com.lambda.util.item.ItemStackUtils.shulkerBoxContents +import com.lambda.util.item.ItemUtils.bundles import com.lambda.util.item.ItemUtils.shulkerBoxes +import com.lambda.util.text.buildText +import com.lambda.util.text.literal import net.minecraft.block.ShulkerBoxBlock import net.minecraft.client.font.TextRenderer -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.tooltip.TooltipComponent import net.minecraft.client.gl.RenderPipelines +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.render.state.GuiRenderState +import net.minecraft.client.gui.render.state.ItemGuiElementRenderState +import net.minecraft.client.gui.render.state.TextGuiElementRenderState import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.client.gui.tooltip.TooltipComponent +import net.minecraft.client.render.item.KeyedItemRenderState +import net.minecraft.entity.LivingEntity import net.minecraft.item.BlockItem +import net.minecraft.item.ItemDisplayContext import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.item.tooltip.TooltipData @@ -41,6 +51,9 @@ import net.minecraft.screen.slot.Slot import net.minecraft.util.Colors import net.minecraft.util.DyeColor import net.minecraft.util.Identifier +import net.minecraft.world.World +import org.joml.Matrix3x2f + object ContainerPreview : Module( name = "ContainerPreview", @@ -50,6 +63,11 @@ object ContainerPreview : Module( private val lockKey by setting("Lock Key", Bind(KeyCode.LeftShift.code, 0, -1), "Key to lock the tooltip in place for item interaction") private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color") + private val previewItem by setting("Preview Item", true, "Show a preview of the most common item in a shulker on the shulker item") + private val previewItemScale by setting("Preview Item Scale", 13f, 1f..32f, 0.1f, "Scale of the item icons on a shulker item") { previewItem } + private val previewItemXOffset by setting("Preview Item X Offset", 0f, -32f..32f, 0.1f, "X Offset of the item icons on a shulker item") { previewItem } + private val previewItemYOffset by setting("Preview Item Y Offset", 0f, -32f..32f, 0.1f, "Y Offset of the item icons on a shulker item") { previewItem } + private val background = Identifier.ofVanilla("textures/gui/container/shulker_box.png") private var lockedSlot: Slot? = null @@ -65,6 +83,14 @@ object ContainerPreview : Module( var isRenderingSubTooltip: Boolean = false private set + // Cache for shulker box contents summery + // Cache size is limited to 200 entries + val shulkerCache = object : LinkedHashMap(16, 0.75f, true) { + override fun removeEldestEntry(eldest: MutableMap.MutableEntry): Boolean { + return size > 200 + } + } + private const val ROWS = 3 private const val COLS = 9 private const val SLOT_SIZE = 18 @@ -325,6 +351,27 @@ object ContainerPreview : Module( return null } + private fun getPreviewItemForContainer(container: ItemStack): ContainerPreviewInfo { + val hash = container.hashCode() + + return shulkerCache.computeIfAbsent(hash) { + val contents = container.shulkerBoxContents + container.bundleContents + if (contents.isEmpty()) return@computeIfAbsent ContainerPreviewInfo(null, false) + + val group = contents.filter { stack -> stack.item != Items.AIR } + .groupBy { stack -> stack.item } + .map { (item, stacks) -> + stacks.first() to stacks.sumOf { it.count } + } + val unique = group.size + val mostCommon = group.maxByOrNull { (_, count) -> count }?.let { (stack, count) -> + stack.copyWithCount(count.coerceAtMost(stack.maxCount)) + } + + ContainerPreviewInfo(mostCommon, unique > 1) + } + } + @JvmStatic fun isShulkerBox(stack: ItemStack) = stack.item in shulkerBoxes @@ -334,9 +381,52 @@ object ContainerPreview : Module( @JvmStatic fun isPreviewableContainer(stack: ItemStack) = isShulkerBox(stack) || isEnderChest(stack) + @JvmStatic + fun isBundle(stack: ItemStack) = stack.item in bundles + + @JvmStatic + fun drawOnItem(drawContext: DrawContext, state: GuiRenderState, entity: LivingEntity?, world: World?, stack: ItemStack, x: Int, y: Int, seed: Int) { + if (!previewItem) return + if (!isShulkerBox(stack) && !isBundle(stack)) return + val preview = getPreviewItemForContainer(stack) + if (preview.stack == null) return + + // Apply scaling + val scale = previewItemScale / 16.0f + val itemMatrix = Matrix3x2f(drawContext.matrices) + + // Required to center the icon correctly, due to how the item gets centered by the renderer + val shift = 8 * (1 - scale) // 0 at scale 1.0, 8 at scale 0.0 + + val newScreenX = ((x + previewItemXOffset + shift) / scale).toInt() + val newScreenY = ((y + previewItemYOffset + shift) / scale).toInt() + + itemMatrix.scale(scale, scale) + + val keyedItemRenderState = KeyedItemRenderState(); + mc.itemModelManager.clearAndUpdate(keyedItemRenderState, preview.stack, ItemDisplayContext.GUI, world, entity, seed); + + state.addItem( + ItemGuiElementRenderState( + preview.stack.item.name.toString(), itemMatrix, keyedItemRenderState, newScreenX, newScreenY, drawContext.scissorStack.peekLast() + ) + ) + if (preview.hasMore) { + state.addText( + TextGuiElementRenderState( + mc.textRenderer, buildText { + literal("+") + }.asOrderedText(), itemMatrix, newScreenX + 14, newScreenY - 2, -1, Integer.MIN_VALUE, true, false, drawContext.scissorStack.peekLast() + ) + ) + } + } + open class ContainerComponent(val stack: ItemStack) : TooltipData, TooltipComponent { override fun drawItems(textRenderer: TextRenderer, x: Int, y: Int, width: Int, height: Int, context: DrawContext) {} override fun getHeight(textRenderer: TextRenderer): Int = 0 override fun getWidth(textRenderer: TextRenderer): Int = 0 } + + data class ContainerPreviewInfo(val stack: ItemStack?, val hasMore: Boolean) } diff --git a/src/main/kotlin/com/lambda/util/item/ItemStackUtils.kt b/src/main/kotlin/com/lambda/util/item/ItemStackUtils.kt index dd7fe6204..9e39a0cbd 100644 --- a/src/main/kotlin/com/lambda/util/item/ItemStackUtils.kt +++ b/src/main/kotlin/com/lambda/util/item/ItemStackUtils.kt @@ -115,6 +115,10 @@ object ItemStackUtils { stack.components.get(DataComponentTypes.CONTAINER)?.stream()?.toList() ?: emptyList() } + val ItemStack.bundleContents: List by cacheable { stack -> + stack.components.get(DataComponentTypes.BUNDLE_CONTENTS)?.stream()?.toList() ?: emptyList() + } + /** * Checks if the given item stacks are equal, including the item count and NBT. */ diff --git a/src/main/kotlin/com/lambda/util/item/ItemUtils.kt b/src/main/kotlin/com/lambda/util/item/ItemUtils.kt index 823b41941..dbc7c8806 100644 --- a/src/main/kotlin/com/lambda/util/item/ItemUtils.kt +++ b/src/main/kotlin/com/lambda/util/item/ItemUtils.kt @@ -97,6 +97,26 @@ object ItemUtils { Items.BLACK_SHULKER_BOX, ) + val bundles = setOf( + Items.BUNDLE, + Items.WHITE_BUNDLE, + Items.ORANGE_BUNDLE, + Items.MAGENTA_BUNDLE, + Items.LIGHT_BLUE_BUNDLE, + Items.YELLOW_BUNDLE, + Items.LIME_BUNDLE, + Items.PINK_BUNDLE, + Items.GRAY_BUNDLE, + Items.LIGHT_GRAY_BUNDLE, + Items.CYAN_BUNDLE, + Items.PURPLE_BUNDLE, + Items.BLUE_BUNDLE, + Items.BROWN_BUNDLE, + Items.GREEN_BUNDLE, + Items.RED_BUNDLE, + Items.BLACK_BUNDLE + ) + val chests = setOf( Items.CHEST, Items.TRAPPED_CHEST, From 130aa638b7c55f67ab88aa53bcef02a42fb6ae48 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Fri, 24 Apr 2026 22:43:37 +0200 Subject: [PATCH 2/4] Add weighted item counting when selecting a preview item on containers Clarify other code and code cleanup --- .../module/modules/render/ContainerPreview.kt | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt index 6dd812ebd..1d568b0bd 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -23,8 +23,10 @@ import com.lambda.interaction.material.container.containers.EnderChestContainer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +import com.lambda.util.Describable import com.lambda.util.InputUtils.isSatisfied import com.lambda.util.KeyCode +import com.lambda.util.NamedEnum import com.lambda.util.item.ItemStackUtils.bundleContents import com.lambda.util.item.ItemStackUtils.shulkerBoxContents import com.lambda.util.item.ItemUtils.bundles @@ -53,6 +55,7 @@ import net.minecraft.util.DyeColor import net.minecraft.util.Identifier import net.minecraft.world.World import org.joml.Matrix3x2f +import kotlin.math.max object ContainerPreview : Module( @@ -60,13 +63,17 @@ object ContainerPreview : Module( description = "Renders shulker box contents visually in tooltips", tag = ModuleTag.RENDER, ) { - private val lockKey by setting("Lock Key", Bind(KeyCode.LeftShift.code, 0, -1), "Key to lock the tooltip in place for item interaction") - private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color") - - private val previewItem by setting("Preview Item", true, "Show a preview of the most common item in a shulker on the shulker item") - private val previewItemScale by setting("Preview Item Scale", 13f, 1f..32f, 0.1f, "Scale of the item icons on a shulker item") { previewItem } - private val previewItemXOffset by setting("Preview Item X Offset", 0f, -32f..32f, 0.1f, "X Offset of the item icons on a shulker item") { previewItem } - private val previewItemYOffset by setting("Preview Item Y Offset", 0f, -32f..32f, 0.1f, "Y Offset of the item icons on a shulker item") { previewItem } + private val lockKey by setting("Lock Key", Bind(KeyCode.LeftShift.code, 0, -1), "Key to lock the tooltip in place for item interaction").group(Group.ContainerTooltip) + private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color").group(Group.ContainerTooltip) + + private val contentPreview by setting("Content Preview", true, "Show a preview of the most common item in a container on the container item in inventories").group(Group.ContentPreview) + private val previewItemScale by setting("Preview Item Scale", 13f, 1f..32f, 0.1f, "Scale of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) + private val previewItemXOffset by setting("Preview Item X Offset", 0f, -32f..32f, 0.1f, "X Offset of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) + private val previewItemYOffset by setting("Preview Item Y Offset", 0f, -32f..32f, 0.1f, "Y Offset of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) + private val previewItemWeightedCount by setting("Preview weighted count", true, description = "Count items for preview in containers relative to max stack size", visibility = { contentPreview }).group(Group.ContentPreview) + .onValueChange { _, _ -> + containerCache.clear() + } private val background = Identifier.ofVanilla("textures/gui/container/shulker_box.png") @@ -83,9 +90,8 @@ object ContainerPreview : Module( var isRenderingSubTooltip: Boolean = false private set - // Cache for shulker box contents summery - // Cache size is limited to 200 entries - val shulkerCache = object : LinkedHashMap(16, 0.75f, true) { + // Cache for container contents summary // Cache size is limited to 200 entries + val containerCache = object : LinkedHashMap(16, 0.75f, true) { override fun removeEldestEntry(eldest: MutableMap.MutableEntry): Boolean { return size > 200 } @@ -354,18 +360,19 @@ object ContainerPreview : Module( private fun getPreviewItemForContainer(container: ItemStack): ContainerPreviewInfo { val hash = container.hashCode() - return shulkerCache.computeIfAbsent(hash) { + return containerCache.computeIfAbsent(hash) { val contents = container.shulkerBoxContents + container.bundleContents if (contents.isEmpty()) return@computeIfAbsent ContainerPreviewInfo(null, false) val group = contents.filter { stack -> stack.item != Items.AIR } .groupBy { stack -> stack.item } .map { (item, stacks) -> - stacks.first() to stacks.sumOf { it.count } + val stackWeight = if (previewItemWeightedCount) 64f / item.maxCount else 1f + stacks.first() to (stacks.sumOf { it.count } * stackWeight) } val unique = group.size - val mostCommon = group.maxByOrNull { (_, count) -> count }?.let { (stack, count) -> - stack.copyWithCount(count.coerceAtMost(stack.maxCount)) + val mostCommon = group.maxByOrNull { (_, weightedCount) -> weightedCount }?.let { (stack, count) -> + stack.copyWithCount(max(1, count.toInt().coerceAtMost(stack.maxCount))) } ContainerPreviewInfo(mostCommon, unique > 1) @@ -386,7 +393,7 @@ object ContainerPreview : Module( @JvmStatic fun drawOnItem(drawContext: DrawContext, state: GuiRenderState, entity: LivingEntity?, world: World?, stack: ItemStack, x: Int, y: Int, seed: Int) { - if (!previewItem) return + if (!contentPreview) return if (!isShulkerBox(stack) && !isBundle(stack)) return val preview = getPreviewItemForContainer(stack) if (preview.stack == null) return @@ -422,6 +429,11 @@ object ContainerPreview : Module( } } + enum class Group(override val displayName: String, override val description: String) : NamedEnum, Describable { + ContentPreview("Preview", "Settings related to the item preview rendered on container items in inventories"), + ContainerTooltip("Container", "Settings related to container tooltip previews") + } + open class ContainerComponent(val stack: ItemStack) : TooltipData, TooltipComponent { override fun drawItems(textRenderer: TextRenderer, x: Int, y: Int, width: Int, height: Int, context: DrawContext) {} override fun getHeight(textRenderer: TextRenderer): Int = 0 From 1c5dfeede706395f989585b8331ebc2e348927fd Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Fri, 24 Apr 2026 22:44:22 +0200 Subject: [PATCH 3/4] Remove unnecessary semicolons --- .../com/lambda/module/modules/render/ContainerPreview.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt index 1d568b0bd..d52204e83 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -410,8 +410,8 @@ object ContainerPreview : Module( itemMatrix.scale(scale, scale) - val keyedItemRenderState = KeyedItemRenderState(); - mc.itemModelManager.clearAndUpdate(keyedItemRenderState, preview.stack, ItemDisplayContext.GUI, world, entity, seed); + val keyedItemRenderState = KeyedItemRenderState() + mc.itemModelManager.clearAndUpdate(keyedItemRenderState, preview.stack, ItemDisplayContext.GUI, world, entity, seed) state.addItem( ItemGuiElementRenderState( From 9539205482257f9009689b83db6acf3f83ca19b3 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sat, 25 Apr 2026 15:04:38 +0200 Subject: [PATCH 4/4] Code nits --- .../com/lambda/mixin/render/DrawContextMixin.java | 6 +----- .../module/modules/render/ContainerPreview.kt | 14 +++++++------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/DrawContextMixin.java b/src/main/java/com/lambda/mixin/render/DrawContextMixin.java index b0097a37c..c5280aae9 100644 --- a/src/main/java/com/lambda/mixin/render/DrawContextMixin.java +++ b/src/main/java/com/lambda/mixin/render/DrawContextMixin.java @@ -103,11 +103,7 @@ private void onDrawTooltip(TextRenderer textRenderer, List text, Optional< } } - @Inject(method = "drawItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;III)V", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/state/GuiRenderState;addItem(Lnet/minecraft/client/gui/render/state/ItemGuiElementRenderState;)V" - , shift = At.Shift.AFTER - ) - ) + @Inject(method = "drawItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/render/state/GuiRenderState;addItem(Lnet/minecraft/client/gui/render/state/ItemGuiElementRenderState;)V", shift = At.Shift.AFTER)) private void onDrawItem(LivingEntity entity, World world, ItemStack stack, int x, int y, int seed, CallbackInfo ci) { if (!ContainerPreview.INSTANCE.isEnabled()) return; ContainerPreview.drawOnItem((DrawContext) (Object) this, state, entity, world, stack, x, y, seed); diff --git a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt index d52204e83..58e4521ee 100644 --- a/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/module/modules/render/ContainerPreview.kt @@ -67,10 +67,10 @@ object ContainerPreview : Module( private val colorTint by setting("Color Tint", true, "Tint the background with the shulker box color").group(Group.ContainerTooltip) private val contentPreview by setting("Content Preview", true, "Show a preview of the most common item in a container on the container item in inventories").group(Group.ContentPreview) - private val previewItemScale by setting("Preview Item Scale", 13f, 1f..32f, 0.1f, "Scale of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) - private val previewItemXOffset by setting("Preview Item X Offset", 0f, -32f..32f, 0.1f, "X Offset of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) - private val previewItemYOffset by setting("Preview Item Y Offset", 0f, -32f..32f, 0.1f, "Y Offset of the item icons on a container item", visibility = { contentPreview }).group(Group.ContentPreview) - private val previewItemWeightedCount by setting("Preview weighted count", true, description = "Count items for preview in containers relative to max stack size", visibility = { contentPreview }).group(Group.ContentPreview) + private val previewItemScale by setting("Item Scale", 13f, 1f..32f, 0.1f, "Scale of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) + private val previewItemXOffset by setting("Item X Offset", 0f, -32f..32f, 0.1f, "X offset of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) + private val previewItemYOffset by setting("Item Y Offset", 0f, -32f..32f, 0.1f, "Y offset of the item icons on a container item") { contentPreview }.group(Group.ContentPreview) + private val previewItemWeightedCount by setting("Weighted Count", true, description = "Count items for preview in containers relative to max stack size") { contentPreview }.group(Group.ContentPreview) .onValueChange { _, _ -> containerCache.clear() } @@ -361,15 +361,15 @@ object ContainerPreview : Module( val hash = container.hashCode() return containerCache.computeIfAbsent(hash) { - val contents = container.shulkerBoxContents + container.bundleContents + val contents = container.shulkerBoxContents + container.bundleContents if (contents.isEmpty()) return@computeIfAbsent ContainerPreviewInfo(null, false) val group = contents.filter { stack -> stack.item != Items.AIR } .groupBy { stack -> stack.item } .map { (item, stacks) -> val stackWeight = if (previewItemWeightedCount) 64f / item.maxCount else 1f - stacks.first() to (stacks.sumOf { it.count } * stackWeight) - } + stacks.first() to (stacks.sumOf { it.count } * stackWeight) + } val unique = group.size val mostCommon = group.maxByOrNull { (_, weightedCount) -> weightedCount }?.let { (stack, count) -> stack.copyWithCount(max(1, count.toInt().coerceAtMost(stack.maxCount)))