From 39c4725d3f0deebdcd8cd04a6b9f5df2554cbe0b Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Thu, 13 Jul 2023 01:33:08 -0700 Subject: [PATCH 1/5] ContainerPreview: EChest caching, nested locking, item frames Includes a stripped down version of the CachedContainerManager. This can be expanded on for caching more container types as in Constructor's draft PR --- .../com/lambda/mixin/gui/MixinGuiChest.java | 20 - .../com/lambda/mixin/gui/MixinGuiScreen.java | 3 - .../network/MixinNetHandlerPlayClient.java | 9 + .../mixin/player/MixinEntityPlayerSP.java | 9 + .../client/event/ForgeEventProcessor.kt | 10 + .../hudgui/elements/player/InventoryViewer.kt | 79 +--- .../managers/CachedContainerManager.kt | 134 +++++++ .../module/modules/render/ContainerPreview.kt | 376 ++++++++++++++---- .../client/util/graphics/RenderUtils2D.kt | 4 +- src/main/resources/mixins.lambda.json | 1 - 10 files changed, 483 insertions(+), 162 deletions(-) delete mode 100644 src/main/java/com/lambda/mixin/gui/MixinGuiChest.java create mode 100644 src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt diff --git a/src/main/java/com/lambda/mixin/gui/MixinGuiChest.java b/src/main/java/com/lambda/mixin/gui/MixinGuiChest.java deleted file mode 100644 index d77f398ad..000000000 --- a/src/main/java/com/lambda/mixin/gui/MixinGuiChest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.lambda.mixin.gui; - -import com.lambda.client.module.modules.render.ContainerPreview; -import net.minecraft.client.gui.inventory.GuiChest; -import net.minecraft.inventory.IInventory; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(GuiChest.class) -public class MixinGuiChest { - - @Inject(method = "", at = @At("RETURN")) - public void drawScreen(IInventory upperInv, IInventory lowerInv, CallbackInfo ci) { - if (lowerInv.getName().equals("Ender Chest")) { - ContainerPreview.INSTANCE.setEnderChest(lowerInv); - } - } -} diff --git a/src/main/java/com/lambda/mixin/gui/MixinGuiScreen.java b/src/main/java/com/lambda/mixin/gui/MixinGuiScreen.java index 7d3aa016c..2c8920a4e 100644 --- a/src/main/java/com/lambda/mixin/gui/MixinGuiScreen.java +++ b/src/main/java/com/lambda/mixin/gui/MixinGuiScreen.java @@ -1,6 +1,5 @@ package com.lambda.mixin.gui; -import com.lambda.client.module.modules.render.ContainerPreview; import com.lambda.client.module.modules.render.MapPreview; import com.lambda.client.module.modules.render.NoRender; import com.lambda.client.util.Wrapper; @@ -25,8 +24,6 @@ public void renderToolTip(ItemStack stack, int x, int y, CallbackInfo ci) { ci.cancel(); MapPreview.drawMap(stack, mapData, x, y); } - } else if (ContainerPreview.INSTANCE.isEnabled()) { - ContainerPreview.INSTANCE.renderTooltips(stack, x, y, ci); } } diff --git a/src/main/java/com/lambda/mixin/network/MixinNetHandlerPlayClient.java b/src/main/java/com/lambda/mixin/network/MixinNetHandlerPlayClient.java index 82a85b304..9bdf478de 100644 --- a/src/main/java/com/lambda/mixin/network/MixinNetHandlerPlayClient.java +++ b/src/main/java/com/lambda/mixin/network/MixinNetHandlerPlayClient.java @@ -2,9 +2,11 @@ import com.lambda.client.event.LambdaEventBus; import com.lambda.client.event.events.ChunkDataEvent; +import com.lambda.client.manager.managers.CachedContainerManager; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.network.play.server.SPacketChunkData; +import net.minecraft.network.play.server.SPacketWindowItems; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -20,4 +22,11 @@ public class MixinNetHandlerPlayClient { public void handleChunkData(SPacketChunkData packetIn, CallbackInfo ci) { LambdaEventBus.INSTANCE.post(new ChunkDataEvent(packetIn.isFullChunk(), this.world.getChunk(packetIn.getChunkX(), packetIn.getChunkZ()))); } + + @Inject(method = "handleWindowItems", at = @At(value = "RETURN")) + public void handleItems(SPacketWindowItems packetIn, CallbackInfo ci) { + if (packetIn.getWindowId() != 0) { + CachedContainerManager.updateContainerInventory(packetIn.getWindowId()); + } + } } diff --git a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java index a7a8803f0..6a615336c 100644 --- a/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java +++ b/src/main/java/com/lambda/mixin/player/MixinEntityPlayerSP.java @@ -6,6 +6,7 @@ import com.lambda.client.event.events.PlayerMoveEvent; import com.lambda.client.event.events.PushOutOfBlocksEvent; import com.lambda.client.gui.mc.LambdaGuiBeacon; +import com.lambda.client.manager.managers.CachedContainerManager; import com.lambda.client.manager.managers.MessageManager; import com.lambda.client.manager.managers.PlayerPacketManager; import com.lambda.client.module.modules.chat.PortalChat; @@ -18,6 +19,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.entity.MoverType; import net.minecraft.entity.player.EntityPlayer; @@ -68,6 +70,13 @@ public MixinEntityPlayerSP(World worldIn, GameProfile gameProfileIn) { @Shadow protected abstract void updateAutoJump(float p_189810_1_, float p_189810_2_); + @Inject(method = "closeScreen", at = @At("HEAD")) + public void onCloseScreen(CallbackInfo ci) { + if (mc.currentScreen instanceof GuiChest) { + CachedContainerManager.onGuiChestClosed(); + } + } + @Redirect(method = "onLivingUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;closeScreen()V")) public void closeScreen(EntityPlayerSP player) { if (PortalChat.INSTANCE.isDisabled()) player.closeScreen(); diff --git a/src/main/kotlin/com/lambda/client/event/ForgeEventProcessor.kt b/src/main/kotlin/com/lambda/client/event/ForgeEventProcessor.kt index 6c35b11ee..bcbb1fe7a 100644 --- a/src/main/kotlin/com/lambda/client/event/ForgeEventProcessor.kt +++ b/src/main/kotlin/com/lambda/client/event/ForgeEventProcessor.kt @@ -102,6 +102,16 @@ internal object ForgeEventProcessor { } } + @SubscribeEvent + fun onDrawScreenEvent(event: GuiScreenEvent.DrawScreenEvent) { + LambdaEventBus.post(event) + } + + @SubscribeEvent + fun onRenderTooltipEvent(event: RenderTooltipEvent.Pre) { + LambdaEventBus.post(event) + } + /** * Includes events of subclasses like ChunkEvent and GetCollisionBoxesEvent */ diff --git a/src/main/kotlin/com/lambda/client/gui/hudgui/elements/player/InventoryViewer.kt b/src/main/kotlin/com/lambda/client/gui/hudgui/elements/player/InventoryViewer.kt index cc35214c2..b397482b6 100644 --- a/src/main/kotlin/com/lambda/client/gui/hudgui/elements/player/InventoryViewer.kt +++ b/src/main/kotlin/com/lambda/client/gui/hudgui/elements/player/InventoryViewer.kt @@ -1,12 +1,10 @@ package com.lambda.client.gui.hudgui.elements.player import com.lambda.client.event.SafeClientEvent -import com.lambda.client.event.events.ConnectionEvent import com.lambda.client.event.events.PacketEvent import com.lambda.client.gui.hudgui.HudElement -import com.lambda.client.mixin.extension.windowID -import com.lambda.client.module.modules.client.ClickGUI -import com.lambda.client.module.modules.client.GuiColors +import com.lambda.client.manager.managers.CachedContainerManager +import com.lambda.client.util.color.ColorHolder import com.lambda.client.util.graphics.GlStateUtils import com.lambda.client.util.graphics.RenderUtils2D import com.lambda.client.util.graphics.VertexHelper @@ -14,15 +12,9 @@ import com.lambda.client.util.items.storageSlots import com.lambda.client.util.math.Vec2d import com.lambda.client.util.threads.runSafe import com.lambda.client.util.threads.safeListener -import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.vertex.DefaultVertexFormats -import net.minecraft.init.Blocks -import net.minecraft.inventory.ContainerChest -import net.minecraft.inventory.InventoryBasic -import net.minecraft.item.ItemStack -import net.minecraft.network.play.client.CPacketCloseWindow import net.minecraft.network.play.server.SPacketOpenWindow import net.minecraft.util.ResourceLocation import net.minecraft.util.text.TextComponentTranslation @@ -38,22 +30,21 @@ internal object InventoryViewer : HudElement( private val showIcon by setting("Show Icon", false, { !mcTexture }) private val iconScale by setting("Icon Scale", 0.5f, 0.1f..1.0f, 0.1f, { !mcTexture && showIcon }) private val background by setting("Background", true, { !mcTexture }) - private val alpha by setting("Alpha", 150, 0..255, 1, { !mcTexture }) + private val backgroundColor by setting("Background Color", ColorHolder(0, 0, 0, 150), visibility = { !mcTexture && background }) + private val outline by setting("Outline", true, visibility = { !mcTexture }) + private val outlineColor by setting("Outline Color", ColorHolder(255, 255, 255, 150), visibility = { !mcTexture && outline }) + private val outlineThickness by setting("Outline Thickness", 1.0f, 0.5f..5.0f, 0.5f, { !mcTexture && outline }) private val containerTexture = ResourceLocation("textures/gui/container/inventory.png") private val lambdaIcon = ResourceLocation("lambda/lambda_icon.png") - private var enderChestContents: MutableList = MutableList(27) { ItemStack(Blocks.AIR) } override val hudWidth: Float = 162.0f override val hudHeight: Float = 54.0f - private var openedEnderChest: Int = -1 - override fun renderHud(vertexHelper: VertexHelper) { super.renderHud(vertexHelper) runSafe { drawFrame(vertexHelper) drawFrameTexture() - checkEnderChest() drawItems() } } @@ -61,10 +52,10 @@ internal object InventoryViewer : HudElement( private fun drawFrame(vertexHelper: VertexHelper) { if (!mcTexture) { if (background) { - RenderUtils2D.drawRectFilled(vertexHelper, posEnd = Vec2d(162.0, 54.0), color = GuiColors.backGround.apply { a = alpha }) + RenderUtils2D.drawRectFilled(vertexHelper, posEnd = Vec2d(hudWidth.toDouble(), hudHeight.toDouble()), color = backgroundColor) } - if (ClickGUI.windowOutline) { - RenderUtils2D.drawRectOutline(vertexHelper, posEnd = Vec2d(162.0, 54.0), lineWidth = ClickGUI.outlineWidth, color = GuiColors.outline.apply { a = alpha }) + if (outline) { + RenderUtils2D.drawRectOutline(vertexHelper, posEnd = Vec2d(hudWidth.toDouble(), hudHeight.toDouble()), lineWidth = outlineThickness, color = outlineColor) } } } @@ -78,15 +69,15 @@ internal object InventoryViewer : HudElement( mc.renderEngine.bindTexture(containerTexture) buffer.begin(GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX) buffer.pos(0.0, 0.0, 0.0).tex(0.02734375, 0.32421875).endVertex() // (7 / 256), (83 / 256) - buffer.pos(0.0, 54.0, 0.0).tex(0.02734375, 0.53125).endVertex() // (7 / 256), (136 / 256) - buffer.pos(162.0, 0.0, 0.0).tex(0.65625, 0.32421875).endVertex() // (168 / 256), (83 / 256) - buffer.pos(162.0, 54.0, 0.0).tex(0.65625, 0.53125).endVertex() // (168 / 256), (136 / 256) + buffer.pos(0.0, hudHeight.toDouble(), 0.0).tex(0.02734375, 0.53125).endVertex() // (7 / 256), (136 / 256) + buffer.pos(hudWidth.toDouble(), 0.0, 0.0).tex(0.65625, 0.32421875).endVertex() // (168 / 256), (83 / 256) + buffer.pos(hudWidth.toDouble(), hudHeight.toDouble(), 0.0).tex(0.65625, 0.53125).endVertex() // (168 / 256), (136 / 256) tessellator.draw() } else if (showIcon) { mc.renderEngine.bindTexture(lambdaIcon) GlStateManager.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - val center = Vec2d(81.0, 27.0) + val center = Vec2d(hudWidth / 2.0, hudHeight / 2.0) val halfWidth = iconScale * 50.0 val halfHeight = iconScale * 50.0 @@ -103,10 +94,6 @@ internal object InventoryViewer : HudElement( init { - safeListener { - openedEnderChest = -1 - } - safeListener { if (it.packet !is SPacketOpenWindow) return@safeListener if (it.packet.guiId != "minecraft:container") return@safeListener @@ -114,50 +101,26 @@ internal object InventoryViewer : HudElement( if (title !is TextComponentTranslation) return@safeListener if (title.key != "container.enderchest") return@safeListener - openedEnderChest = it.packet.windowId - } - - safeListener { - if (it.packet !is CPacketCloseWindow) return@safeListener - if (it.packet.windowID != openedEnderChest) return@safeListener - - checkEnderChest() - openedEnderChest = -1 - } - } - - private fun checkEnderChest() { - val guiScreen = mc.currentScreen - - if (guiScreen !is GuiContainer) return - - val container = guiScreen.inventorySlots - - if (container is ContainerChest && container.lowerChestInventory is InventoryBasic) { - if (container.windowId == openedEnderChest) { - for (i in 0..26) enderChestContents[i] = container.inventory[i] - } } } private fun SafeClientEvent.drawItems() { if (enderChest == SlotType.ENDER_CHEST) { - for ((index, stack) in enderChestContents.withIndex()) { - if (stack.isEmpty) continue - - val slotX = index % 9 * 18 + 1 - val slotY = index / 9 * 18 + 1 - RenderUtils2D.drawItem(stack, slotX, slotY) + CachedContainerManager.getEnderChestInventory().forEachIndexed { index, stack -> + if (stack.isEmpty) return@forEachIndexed + val slotX = index % 9 * (hudWidth / 9.0) + 1 + val slotY = index / 9 * (hudWidth / 9.0) + 1 + RenderUtils2D.drawItem(stack, slotX.toInt(), slotY.toInt()) } } else { for ((index, slot) in player.storageSlots.withIndex()) { val itemStack = slot.stack if (itemStack.isEmpty) continue - val slotX = index % 9 * 18 + 1 - val slotY = index / 9 * 18 + 1 + val slotX = index % 9 * (hudWidth / 9.0) + 1 + val slotY = index / 9 * (hudWidth / 9.0) + 1 - RenderUtils2D.drawItem(itemStack, slotX, slotY) + RenderUtils2D.drawItem(itemStack, slotX.toInt(), slotY.toInt()) } } } diff --git a/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt b/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt new file mode 100644 index 000000000..a4144cd26 --- /dev/null +++ b/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt @@ -0,0 +1,134 @@ +package com.lambda.client.manager.managers + +import com.lambda.client.LambdaMod +import com.lambda.client.event.events.ConnectionEvent +import com.lambda.client.event.listener.listener +import com.lambda.client.manager.Manager +import com.lambda.client.module.modules.player.PacketLogger +import com.lambda.client.module.modules.render.ContainerPreview.cacheEnderChests +import com.lambda.client.util.FolderUtils +import com.lambda.client.util.threads.defaultScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import net.minecraft.inventory.ContainerChest +import net.minecraft.inventory.IInventory +import net.minecraft.inventory.InventoryBasic +import net.minecraft.inventory.ItemStackHelper +import net.minecraft.item.ItemStack +import net.minecraft.nbt.CompressedStreamTools +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.NonNullList +import java.io.File +import java.io.IOException +import java.nio.file.Paths + +object CachedContainerManager : Manager { + private val directory = Paths.get(FolderUtils.lambdaFolder, "cached-containers").toFile() + private var echestFile: File? = null + private var currentEnderChest: NonNullList? = null + + init { + listener { + val serverDirectory = if (mc.integratedServer != null && mc.integratedServer?.isServerRunning == true) { + mc.integratedServer?.folderName ?: run { + LambdaMod.LOG.info("Failed to get SP directory") + return@listener + } + } else { + mc.currentServerData?.serverIP?.replace(":", "_") + ?: run { + LambdaMod.LOG.info("Failed to get server directory") + return@listener + } + } + + val folder = File(directory, serverDirectory) + echestFile = folder.toPath().resolve(mc.session.profile.id.toString()).resolve("echest.nbt").toFile() + try { + if (!echestFile!!.exists()) { + if (!echestFile!!.parentFile.exists()) echestFile!!.parentFile.mkdirs() + echestFile!!.createNewFile() + } + } catch (e: IOException) { + LambdaMod.LOG.error("Failed to create ender chest file", e) + } + } + + listener { + echestFile = null + currentEnderChest = null + } + } + + fun getEnderChestInventory(): NonNullList { + echestFile?.let { eFile -> + currentEnderChest?.let { return it } + if (!cacheEnderChests) return@let + try { + CompressedStreamTools.read(eFile)?.let { nbt -> + val inventory = NonNullList.withSize(27, ItemStack.EMPTY) + ItemStackHelper.loadAllItems(nbt, inventory) + currentEnderChest = inventory + return inventory + } + } catch (e: IOException) { + currentEnderChest = NonNullList.withSize(27, ItemStack.EMPTY) + LambdaMod.LOG.warn("${PacketLogger.chatName} Failed loading echest!", e) + } + + } + return NonNullList.withSize(27, ItemStack.EMPTY) + } + + private fun saveEchest(inventory: NonNullList) { + if (!cacheEnderChests) return + val currentEchestFile = echestFile ?: return + val nonNullList = NonNullList.withSize(inventory.size, ItemStack.EMPTY) + inventory.forEachIndexed { index, itemStack -> + nonNullList[index] = itemStack + } + val nbt = NBTTagCompound() + ItemStackHelper.saveAllItems(nbt, nonNullList) + + defaultScope.launch(Dispatchers.IO) { + try { + CompressedStreamTools.write(nbt, currentEchestFile) + } catch (e: Throwable) { + LambdaMod.LOG.warn("${PacketLogger.chatName} Failed saving echest!", e) + } + } + } + + @JvmStatic + fun setEnderChestInventory(inv: IInventory) { + val inventory = NonNullList.withSize(inv.sizeInventory, ItemStack.EMPTY) + for (i in 0 until inv.sizeInventory) { + inventory[i] = inv.getStackInSlot(i) + } + currentEnderChest = inventory + saveEchest(inventory) + } + + @JvmStatic + fun updateContainerInventory(windowId: Int) { + val container = mc.player.openContainer + if (container.windowId != windowId) return + if (container !is ContainerChest) return + val chest = container.lowerChestInventory + if (chest !is InventoryBasic) return + if (chest.name.contains("Ender Chest")) + setEnderChestInventory(chest) + // we can save other container inventories here but we also need the position + } + + @JvmStatic + fun onGuiChestClosed() { + val container = mc.player.openContainer + if (container !is ContainerChest) return + val chest = container.lowerChestInventory + if (chest !is InventoryBasic) return + if (chest.name.contains("Ender Chest")) + setEnderChestInventory(chest) + // we can save other container inventories here but we also need the position + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt index 53ac4006d..27e8a744e 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt @@ -1,140 +1,360 @@ package com.lambda.client.module.modules.render -import com.lambda.client.commons.extension.ceilToInt +import com.lambda.client.commons.extension.floorToInt +import com.lambda.client.event.events.RenderOverlayEvent +import com.lambda.client.manager.managers.CachedContainerManager import com.lambda.client.module.Category import com.lambda.client.module.Module +import com.lambda.client.util.Bind import com.lambda.client.util.color.ColorHolder import com.lambda.client.util.graphics.GlStateUtils +import com.lambda.client.util.graphics.ProjectionUtils import com.lambda.client.util.graphics.RenderUtils2D import com.lambda.client.util.graphics.VertexHelper import com.lambda.client.util.graphics.font.FontRenderAdapter import com.lambda.client.util.items.block import com.lambda.client.util.math.Vec2d +import com.lambda.client.util.threads.safeListener +import net.minecraft.block.BlockEnderChest +import net.minecraft.block.BlockShulkerBox +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.ScaledResolution +import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.entity.item.EntityItemFrame +import net.minecraft.entity.player.EntityPlayer import net.minecraft.init.Blocks +import net.minecraft.inventory.Container import net.minecraft.inventory.IInventory +import net.minecraft.inventory.ItemStackHelper +import net.minecraft.inventory.Slot import net.minecraft.item.ItemShulkerBox import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.NonNullList +import net.minecraft.util.math.Vec3d +import net.minecraft.util.text.ITextComponent +import net.minecraft.util.text.TextComponentString +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.client.event.RenderTooltipEvent +import org.lwjgl.input.Keyboard import org.lwjgl.opengl.GL11.GL_LINE_LOOP import org.lwjgl.opengl.GL11.glLineWidth -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo object ContainerPreview : Module( name = "ContainerPreview", - description = "Previews shulkers and ender chests in the game GUI", + description = "Previews shulkers and ender chests in inventories or item frames", category = Category.RENDER ) { - private val useCustomFont by setting("Use Custom Font", false) + val cacheEnderChests by setting("Cache Ender Chest", true) private val backgroundColor by setting("Background Color", ColorHolder(16, 0, 16, 255)) private val borderTopColor by setting("Top Border Color", ColorHolder(144, 101, 237, 54)) private val borderBottomColor by setting("Bottom Border Color", ColorHolder(40, 0, 127, 80)) + private val previewLock by setting("Preview Lock Bind", Bind(Keyboard.KEY_LCONTROL)) + private val itemFrames by setting("Item Frames", true) - var enderChest: IInventory? = null + private const val previewWidth = 176 + private const val previewHeight = 70 + private var isMouseInPreviewGui = false + private var isPreviewTooltip = false - fun renderTooltips(itemStack: ItemStack, x: Int, y: Int, ci: CallbackInfo) { - val item = itemStack.item + private var stackContainer: GuiPreview? = null - if (item is ItemShulkerBox) { - renderShulkerBoxTooltips(itemStack, x, y, ci) - } else if (item.block == Blocks.ENDER_CHEST) { - renderEnderChestTooltips(itemStack, x, y, ci) + init { + + safeListener { + if (mc.currentScreen !is GuiContainer) return@safeListener + val gui = it.gui as GuiContainer + if (!Keyboard.isKeyDown(previewLock.key)) { + val slotUnder = gui.slotUnderMouse + if (slotUnder != null && slotUnder.hasStack && !slotUnder.stack.isEmpty && (slotUnder.stack.item is ItemShulkerBox || slotUnder.stack.item.block == Blocks.ENDER_CHEST)) { + if (stackContainer == null || stackContainer?.parentContainer != slotUnder.stack) { + val res = ScaledResolution(mc) + val resWidth = res.scaledWidth + // ensure the preview gui is on screen + val dX = gui.guiLeft + slotUnder.xPos + 16 + val previewDrawX = if (dX + previewWidth > resWidth) res.scaledWidth - previewWidth else dX + val dY = gui.guiTop + slotUnder.yPos + 8 + val previewDrawY = if (dY + previewHeight > res.scaledHeight) res.scaledHeight - previewHeight else dY + stackContainer = createPreviewGui(slotUnder.stack, getContainerContents(slotUnder.stack), previewDrawX, previewDrawY) + } + } else stackContainer = null + } + stackContainer?.drawScreen(it.mouseX, it.mouseY, it.renderPartialTicks) + } + + safeListener { + if (mc.currentScreen !is GuiContainer + || isPreviewTooltip + || !(isMouseInPreviewGui + || it.stack.item is ItemShulkerBox + || it.stack.item.block == Blocks.ENDER_CHEST)) return@safeListener + it.isCanceled = true } - } - private fun renderShulkerBoxTooltips(itemStack: ItemStack, x: Int, y: Int, ci: CallbackInfo) { - getShulkerData(itemStack)?.let { - val itemStacks = Array(27) { ItemStack.EMPTY } - val nbtTagList = it.getTagList("Items", 10) + safeListener { + if (!itemFrames) return@safeListener + mc.renderManager.pointedEntity?.let { pe -> + if (pe !is EntityItemFrame) return@safeListener + if (!(pe.displayedItem.item.block is BlockShulkerBox || pe.displayedItem.item.block is BlockEnderChest)) return@safeListener + val posX = pe.posX + (pe.facingDirection?.xOffset ?: 0) * 0.1 + val posY = pe.posY + (pe.facingDirection?.yOffset ?: 0) * 0.1 + val posZ = pe.posZ + (pe.facingDirection?.zOffset ?: 0) * 0.1 + val screenPos = ProjectionUtils.toScaledScreenPos(Vec3d(posX, posY, posZ)) + val width = 9 * 16 + val height = 3 * 16 + val newX = screenPos.x - width / 2 + val newY = screenPos.y - height / 2 - for (i in 0 until nbtTagList.tagCount()) { - val itemStackNBTTag = nbtTagList.getCompoundTagAt(i) - val slot = itemStackNBTTag.getInteger("Slot") and 255 - if (slot in itemStacks.indices) { - itemStacks[slot] = ItemStack(itemStackNBTTag) + GlStateManager.pushMatrix() + val vertexHelper = VertexHelper(GlStateUtils.useVbo()) + RenderUtils2D.drawRoundedRectFilled( + vertexHelper, + Vec2d(newX, newY), + Vec2d(newX + width, newY + height), + 1.0, + color = backgroundColor + ) + + drawRectOutline(vertexHelper, newX + 1.0, newY + 1.0, (width - 2).toDouble(), (height - 2).toDouble()) + GlStateManager.enableDepth() + + RenderHelper.enableGUIStandardItemLighting() + GlStateManager.enableRescaleNormal() + GlStateManager.enableColorMaterial() + GlStateManager.enableLighting() + val contents = if (pe.displayedItem.item.block is BlockShulkerBox && pe.displayedItem.hasTagCompound()) + getContainerContents(pe.displayedItem) + else if (pe.displayedItem.item.block is BlockEnderChest) getEnderChestData() + else null + contents?.forEachIndexed { index, itemStack -> + val x = newX + (index % 9) * 16 + val y = newY + (index / 9) * 16 + RenderUtils2D.drawItem(itemStack, x.floorToInt(), y.floorToInt()) } + GlStateManager.popMatrix() } + } + } - ci.cancel() - renderContainerAndItems(itemStack, x, y, itemStacks) + private fun createPreviewGui( + parentContainer: ItemStack, + containerContents: MutableList, + posX: Int, + posY: Int + ): GuiPreview { + return GuiPreview( + PreviewContainer(PreviewInventory(containerContents), 27), + parentContainer, + posX, + posY + ) + } + + private fun getContainerContents(stack: ItemStack): MutableList { // TODO: move somewhere else + return if (stack.item.block == Blocks.ENDER_CHEST) { + getEnderChestData() + } else { + val contents = NonNullList.withSize(27, ItemStack.EMPTY) + val compound = stack.tagCompound + if (compound != null && compound.hasKey("BlockEntityTag", 10)) { + val tags = compound.getCompoundTag("BlockEntityTag") + if (tags.hasKey("Items", 9)) ItemStackHelper.loadAllItems(tags, contents) + } + contents } } - private fun getShulkerData(stack: ItemStack): NBTTagCompound? { - val tagCompound = if (stack.item is ItemShulkerBox) stack.tagCompound else return null + private fun drawRectOutline(vertexHelper: VertexHelper, x: Double, y: Double, width: Double, height: Double) { + RenderUtils2D.prepareGl() + glLineWidth(5.0f) + + vertexHelper.begin(GL_LINE_LOOP) + vertexHelper.put(Vec2d(x, y), borderTopColor) + vertexHelper.put(Vec2d(x, y + height), borderBottomColor) + vertexHelper.put(Vec2d(x + width, y + height), borderBottomColor) + vertexHelper.put(Vec2d(x + width, y), borderTopColor) + vertexHelper.end() + + RenderUtils2D.releaseGl() + glLineWidth(1.0f) + } + + private fun getEnderChestData(): MutableList { + return CachedContainerManager.getEnderChestInventory().toMutableList() + } + + class GuiPreview(inventorySlotsIn: Container, val parentContainer: ItemStack, val posX: Int, val posY: Int) : GuiContainer(inventorySlotsIn) { + init { + this.mc = Minecraft.getMinecraft() + this.fontRenderer = this.mc.fontRenderer + this.width = mc.displayWidth + this.height = mc.displayHeight + } + + override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) { + drawPreview(posX, posY, parentContainer, inventorySlots.inventorySlots.map { it.stack }, 301) - tagCompound?.let { - val blockEntityTag = it.getCompoundTag("BlockEntityTag") - if (blockEntityTag.hasKey("Items", 9)) { - return blockEntityTag + var hoveringOver: Slot? = null + val rx = posX.toDouble() + 8 + val ry = posY.toDouble() - 5 + + for (slot in inventorySlots.inventorySlots) { + if (!slot.hasStack) continue + val px = rx + slot.xPos + val py = ry + slot.yPos + if (isPointInRegion(px.toInt(), py.toInt(), 16, 16, mouseX, mouseY)) + hoveringOver = slot } + if (hoveringOver != null) + drawHoveredItem((rx + hoveringOver.xPos).toInt(), (ry + hoveringOver.yPos).toInt(), hoveringOver) + + isMouseInPreviewGui = isPointInRegion(posX, posY, xSize, ySize, mouseX, mouseY) + + GlStateManager.disableBlend() + GlStateManager.color(1f, 1f, 1f, 1.0f) + } + + private fun drawHoveredItem(drawX: Int, drawY: Int, hoveringOver: Slot) { + GlStateManager.disableLighting() + GlStateManager.disableDepth() + GlStateManager.colorMask(true, true, true, false) + drawGradientRect( + drawX, + drawY, + drawX + 16, + drawY + 16, + -2130706433, + -2130706433) + GlStateManager.colorMask(true, true, true, true) + GlStateManager.enableDepth() + + if (hoveringOver.stack.item is ItemShulkerBox || hoveringOver.stack.item.block == Blocks.ENDER_CHEST) { + val res = ScaledResolution(mc) + // ensure the preview gui is on screen + val dX = drawX + 16 + val previewDrawX = if (dX + previewWidth > res.scaledWidth) dX - previewWidth else dX + val dY = drawY + 8 + val previewDrawY = if (dY + previewHeight > res.scaledHeight) dY - previewHeight else dY + drawPreview(previewDrawX, previewDrawY, hoveringOver.stack, getContainerContents(hoveringOver.stack), 400) + } else { + isPreviewTooltip = true + renderToolTip(hoveringOver.stack, drawX + 8, drawY + 8) + isPreviewTooltip = false + } + } + + private fun drawPreview(drawX: Int, drawY: Int, container: ItemStack, containerContents: List, z: Int) { + val depth = z.toDouble() + val x = drawX.toDouble() + val y = drawY.toDouble() + + val vertexHelper = VertexHelper(GlStateUtils.useVbo()) + GlStateManager.disableDepth() + RenderUtils2D.drawRoundedRectFilled( + vertexHelper, + Vec2d(x, y), + Vec2d(x + previewWidth, y + previewHeight), + 1.0, + color = backgroundColor + ) + drawRectOutline(vertexHelper, x + 1.0, y + 1.0, (previewWidth - 2).toDouble(), (previewHeight - 2.toFloat()).toDouble()) + FontRenderAdapter.drawString(container.displayName, (x + 4).toFloat(), (y + 2).toFloat()) + GlStateManager.enableDepth() + RenderHelper.enableGUIStandardItemLighting() + GlStateManager.enableRescaleNormal() + GlStateManager.enableColorMaterial() + GlStateManager.enableLighting() + for (slot in inventorySlots.inventorySlots) { + val px = x + 8 + slot.xPos + val py = y - 5 + slot.yPos + RenderUtils2D.drawItem(containerContents[slot.slotIndex], px.toInt(), py.toInt(), z = (depth + 1).toFloat()) + } + GlStateManager.disableLighting() + } + + override fun drawGuiContainerBackgroundLayer(partialTicks: Float, mouseX: Int, mouseY: Int) { + // do nothing } - return null } - private fun renderEnderChestTooltips(itemStack: ItemStack, x: Int, y: Int, ci: CallbackInfo) { - val itemStacks = Array(27) { ItemStack.EMPTY } - enderChest?.let { - for (i in itemStacks.indices) { - itemStacks[i] = it.getStackInSlot(i) + class PreviewContainer(val inventory: PreviewInventory, val size: Int) : Container() { + init { + for (i in 0 until size) { + addSlotToContainer(Slot(inventory, i, i % 9 * 18, (i / 9 + 1) * 18 + 1)) } } - ci.cancel() - renderContainerAndItems(itemStack, x, y, itemStacks) + override fun canInteractWith(playerIn: EntityPlayer): Boolean { + return false + } } - private fun renderContainerAndItems(stack: ItemStack, originalX: Int, originalY: Int, items: Array) { - GlStateManager.pushMatrix() - GlStateManager.translate(0.0, 0.0, 500.0) + class PreviewInventory(private val contents: MutableList) : IInventory { + override fun getName(): String { + return "Preview Inventory" + } - renderContainer(stack, originalX, originalY) - renderContainerItems(items, originalX, originalY) + override fun hasCustomName(): Boolean { + return false + } - GlStateManager.popMatrix() - } + override fun getDisplayName(): ITextComponent { + return TextComponentString("Preview Inventory") + } - private fun renderContainer(stack: ItemStack, originalX: Int, originalY: Int) { - val width = 144.coerceAtLeast(FontRenderAdapter.getStringWidth(stack.displayName).ceilToInt() + 3) - val vertexHelper = VertexHelper(GlStateUtils.useVbo()) + override fun getSizeInventory(): Int { + return contents.size + } - val x = (originalX + 12).toDouble() - val y = (originalY - 12).toDouble() - val height = FontRenderAdapter.getFontHeight(customFont = useCustomFont) + 48 + override fun isEmpty(): Boolean { + return contents.isEmpty() + } - RenderUtils2D.drawRoundedRectFilled( - vertexHelper, - Vec2d(x - 4, y - 4), - Vec2d(x + width + 4, y + height + 4), - 1.0, - color = backgroundColor - ) + override fun getStackInSlot(index: Int): ItemStack { + return contents[index] + } - drawRectOutline(vertexHelper, x, y, width, height) + override fun decrStackSize(index: Int, count: Int): ItemStack { + return ItemStack.EMPTY + } - FontRenderAdapter.drawString(stack.displayName, x.toFloat(), y.toFloat() - 2.0f, customFont = useCustomFont) - } + override fun removeStackFromSlot(index: Int): ItemStack { + return ItemStack.EMPTY + } - private fun drawRectOutline(vertexHelper: VertexHelper, x: Double, y: Double, width: Int, height: Float) { - RenderUtils2D.prepareGl() - glLineWidth(5.0f) + override fun setInventorySlotContents(index: Int, stack: ItemStack) { + this.contents[index] = stack + } - vertexHelper.begin(GL_LINE_LOOP) - vertexHelper.put(Vec2d(x - 3, y - 3), borderTopColor) - vertexHelper.put(Vec2d(x - 3, y + height + 3), borderBottomColor) - vertexHelper.put(Vec2d(x + width + 3, y + height + 3), borderBottomColor) - vertexHelper.put(Vec2d(x + width + 3, y - 3), borderTopColor) - vertexHelper.end() + override fun getInventoryStackLimit(): Int { + return 27 + } - RenderUtils2D.releaseGl() - glLineWidth(1.0f) - } + override fun markDirty() {} - private fun renderContainerItems(itemStacks: Array, originalX: Int, originalY: Int) { - for (i in itemStacks.indices) { - val x = originalX + (i % 9) * 16 + 11 - val y = originalY + (i / 9) * 16 - 2 - RenderUtils2D.drawItem(itemStacks[i], x, y) + override fun isUsableByPlayer(player: EntityPlayer): Boolean { + return false } + + override fun openInventory(player: EntityPlayer) {} + + override fun closeInventory(player: EntityPlayer) {} + + override fun isItemValidForSlot(index: Int, stack: ItemStack): Boolean { + return true + } + + override fun getField(id: Int): Int { + return 0 + } + + override fun setField(id: Int, value: Int) {} + + override fun getFieldCount(): Int { + return 0 + } + + override fun clear() {} } } diff --git a/src/main/kotlin/com/lambda/client/util/graphics/RenderUtils2D.kt b/src/main/kotlin/com/lambda/client/util/graphics/RenderUtils2D.kt index 5a86fb8c6..7c730e495 100644 --- a/src/main/kotlin/com/lambda/client/util/graphics/RenderUtils2D.kt +++ b/src/main/kotlin/com/lambda/client/util/graphics/RenderUtils2D.kt @@ -16,12 +16,12 @@ import kotlin.math.* object RenderUtils2D { val mc = Wrapper.minecraft - fun drawItem(itemStack: ItemStack, x: Int, y: Int, text: String? = null, drawOverlay: Boolean = true) { + fun drawItem(itemStack: ItemStack, x: Int, y: Int, text: String? = null, drawOverlay: Boolean = true, z: Float = 0.0f) { GlStateUtils.blend(true) GlStateUtils.depth(true) RenderHelper.enableGUIStandardItemLighting() - mc.renderItem.zLevel = 0.0f + mc.renderItem.zLevel = z mc.renderItem.renderItemAndEffectIntoGUI(itemStack, x, y) if (drawOverlay) mc.renderItem.renderItemOverlayIntoGUI(mc.fontRenderer, itemStack, x, y, text) mc.renderItem.zLevel = 0.0f diff --git a/src/main/resources/mixins.lambda.json b/src/main/resources/mixins.lambda.json index 6da5206ac..d92b2be59 100644 --- a/src/main/resources/mixins.lambda.json +++ b/src/main/resources/mixins.lambda.json @@ -42,7 +42,6 @@ "entity.MixinEntityLlama", "entity.MixinEntityPig", "gui.MixinGuiChat", - "gui.MixinGuiChest", "gui.MixinGuiContainer", "gui.MixinGuiIngameForge", "gui.MixinGuiIngameMenu", From 4118102ffb6e79c15b0f204ec1c9e96250dad43c Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Sat, 15 Jul 2023 19:34:01 -0700 Subject: [PATCH 2/5] Preview moves with mouse position if there is screen space --- .../module/modules/render/ContainerPreview.kt | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt index 27e8a744e..038c2ed90 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt @@ -66,19 +66,23 @@ object ContainerPreview : Module( if (mc.currentScreen !is GuiContainer) return@safeListener val gui = it.gui as GuiContainer if (!Keyboard.isKeyDown(previewLock.key)) { - val slotUnder = gui.slotUnderMouse - if (slotUnder != null && slotUnder.hasStack && !slotUnder.stack.isEmpty && (slotUnder.stack.item is ItemShulkerBox || slotUnder.stack.item.block == Blocks.ENDER_CHEST)) { - if (stackContainer == null || stackContainer?.parentContainer != slotUnder.stack) { + gui.slotUnderMouse?.let {slotUnder -> + if (slotUnder.hasStack && !slotUnder.stack.isEmpty && (slotUnder.stack.item is ItemShulkerBox || slotUnder.stack.item.block == Blocks.ENDER_CHEST)) { + if (stackContainer == null || stackContainer?.parentContainer != slotUnder.stack) { + stackContainer = createPreviewGui(slotUnder.stack, getContainerContents(slotUnder.stack)) + } + } else stackContainer = null + stackContainer?.let { sc -> val res = ScaledResolution(mc) - val resWidth = res.scaledWidth // ensure the preview gui is on screen - val dX = gui.guiLeft + slotUnder.xPos + 16 - val previewDrawX = if (dX + previewWidth > resWidth) res.scaledWidth - previewWidth else dX - val dY = gui.guiTop + slotUnder.yPos + 8 + val dX = it.mouseX + 8 + val previewDrawX = if (dX + previewWidth > res.scaledWidth) res.scaledWidth - previewWidth else dX + val dY = it.mouseY val previewDrawY = if (dY + previewHeight > res.scaledHeight) res.scaledHeight - previewHeight else dY - stackContainer = createPreviewGui(slotUnder.stack, getContainerContents(slotUnder.stack), previewDrawX, previewDrawY) + sc.posX = previewDrawX + sc.posY = previewDrawY } - } else stackContainer = null + } } stackContainer?.drawScreen(it.mouseX, it.mouseY, it.renderPartialTicks) } @@ -139,15 +143,11 @@ object ContainerPreview : Module( private fun createPreviewGui( parentContainer: ItemStack, - containerContents: MutableList, - posX: Int, - posY: Int + containerContents: MutableList ): GuiPreview { return GuiPreview( PreviewContainer(PreviewInventory(containerContents), 27), - parentContainer, - posX, - posY + parentContainer ) } @@ -184,7 +184,9 @@ object ContainerPreview : Module( return CachedContainerManager.getEnderChestInventory().toMutableList() } - class GuiPreview(inventorySlotsIn: Container, val parentContainer: ItemStack, val posX: Int, val posY: Int) : GuiContainer(inventorySlotsIn) { + class GuiPreview(inventorySlotsIn: Container, val parentContainer: ItemStack) : GuiContainer(inventorySlotsIn) { + var posX: Int = 0 + var posY: Int = 0 init { this.mc = Minecraft.getMinecraft() this.fontRenderer = this.mc.fontRenderer From 001dd08cd2190b5d2bbbfac173809a0a21cb3df0 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Sat, 15 Jul 2023 19:37:14 -0700 Subject: [PATCH 3/5] oopsie fix --- .../com/lambda/client/module/modules/render/ContainerPreview.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt index 038c2ed90..cd2b66a99 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt @@ -82,7 +82,7 @@ object ContainerPreview : Module( sc.posX = previewDrawX sc.posY = previewDrawY } - } + } ?: run { stackContainer = null } } stackContainer?.drawScreen(it.mouseX, it.mouseY, it.renderPartialTicks) } From 11b4e3b7aa4383cbc812bfbb49058e9849bf04ce Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Sat, 15 Jul 2023 19:44:33 -0700 Subject: [PATCH 4/5] default lock bind to shift --- .../com/lambda/client/module/modules/render/ContainerPreview.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt index cd2b66a99..6eca86520 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt @@ -50,7 +50,7 @@ object ContainerPreview : Module( private val backgroundColor by setting("Background Color", ColorHolder(16, 0, 16, 255)) private val borderTopColor by setting("Top Border Color", ColorHolder(144, 101, 237, 54)) private val borderBottomColor by setting("Bottom Border Color", ColorHolder(40, 0, 127, 80)) - private val previewLock by setting("Preview Lock Bind", Bind(Keyboard.KEY_LCONTROL)) + private val previewLock by setting("Preview Lock Bind", Bind(Keyboard.KEY_LSHIFT)) private val itemFrames by setting("Item Frames", true) private const val previewWidth = 176 From 59e2a2dae4825563e4410cefa7e0735ae58f6e5c Mon Sep 17 00:00:00 2001 From: Constructor Date: Sun, 16 Jul 2023 04:54:12 +0200 Subject: [PATCH 5/5] Clean up !! is bad --- .../managers/CachedContainerManager.kt | 15 ++++++----- .../module/modules/render/ContainerPreview.kt | 26 ++++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt b/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt index a4144cd26..7b451eda6 100644 --- a/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt +++ b/src/main/kotlin/com/lambda/client/manager/managers/CachedContainerManager.kt @@ -44,13 +44,16 @@ object CachedContainerManager : Manager { val folder = File(directory, serverDirectory) echestFile = folder.toPath().resolve(mc.session.profile.id.toString()).resolve("echest.nbt").toFile() - try { - if (!echestFile!!.exists()) { - if (!echestFile!!.parentFile.exists()) echestFile!!.parentFile.mkdirs() - echestFile!!.createNewFile() + + echestFile?.let { file -> + try { + if (!file.exists()) { + if (!file.parentFile.exists()) file.parentFile.mkdirs() + file.createNewFile() + } + } catch (e: IOException) { + LambdaMod.LOG.error("Failed to create ender chest file", e) } - } catch (e: IOException) { - LambdaMod.LOG.error("Failed to create ender chest file", e) } } diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt index 6eca86520..4c2d25a65 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/ContainerPreview.kt @@ -61,24 +61,34 @@ object ContainerPreview : Module( private var stackContainer: GuiPreview? = null init { - safeListener { if (mc.currentScreen !is GuiContainer) return@safeListener val gui = it.gui as GuiContainer + if (!Keyboard.isKeyDown(previewLock.key)) { - gui.slotUnderMouse?.let {slotUnder -> - if (slotUnder.hasStack && !slotUnder.stack.isEmpty && (slotUnder.stack.item is ItemShulkerBox || slotUnder.stack.item.block == Blocks.ENDER_CHEST)) { + gui.slotUnderMouse?.let { slotUnder -> + if (slotUnder.hasStack + && !slotUnder.stack.isEmpty + && (slotUnder.stack.item is ItemShulkerBox || slotUnder.stack.item.block == Blocks.ENDER_CHEST) + ) { if (stackContainer == null || stackContainer?.parentContainer != slotUnder.stack) { stackContainer = createPreviewGui(slotUnder.stack, getContainerContents(slotUnder.stack)) } - } else stackContainer = null + } else { + stackContainer = null + } + stackContainer?.let { sc -> val res = ScaledResolution(mc) // ensure the preview gui is on screen val dX = it.mouseX + 8 - val previewDrawX = if (dX + previewWidth > res.scaledWidth) res.scaledWidth - previewWidth else dX + val previewDrawX = if (dX + previewWidth > res.scaledWidth) { + res.scaledWidth - previewWidth + } else dX val dY = it.mouseY - val previewDrawY = if (dY + previewHeight > res.scaledHeight) res.scaledHeight - previewHeight else dY + val previewDrawY = if (dY + previewHeight > res.scaledHeight) { + res.scaledHeight - previewHeight + } else dY sc.posX = previewDrawX sc.posY = previewDrawY } @@ -100,7 +110,8 @@ object ContainerPreview : Module( if (!itemFrames) return@safeListener mc.renderManager.pointedEntity?.let { pe -> if (pe !is EntityItemFrame) return@safeListener - if (!(pe.displayedItem.item.block is BlockShulkerBox || pe.displayedItem.item.block is BlockEnderChest)) return@safeListener + if (!(pe.displayedItem.item.block is BlockShulkerBox + || pe.displayedItem.item.block is BlockEnderChest)) return@safeListener val posX = pe.posX + (pe.facingDirection?.xOffset ?: 0) * 0.1 val posY = pe.posY + (pe.facingDirection?.yOffset ?: 0) * 0.1 val posZ = pe.posZ + (pe.facingDirection?.zOffset ?: 0) * 0.1 @@ -187,6 +198,7 @@ object ContainerPreview : Module( class GuiPreview(inventorySlotsIn: Container, val parentContainer: ItemStack) : GuiContainer(inventorySlotsIn) { var posX: Int = 0 var posY: Int = 0 + init { this.mc = Minecraft.getMinecraft() this.fontRenderer = this.mc.fontRenderer