@@ -168,6 +168,51 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
168168 return p
169169 }
170170
171+ private fun resetStealState (clearProgress : Boolean = false) {
172+ chestStealerCurrentSlot = - 1
173+ chestStealerLastSlot = - 1
174+
175+ if (clearProgress) {
176+ progress = null
177+ }
178+ }
179+
180+ private fun syncOpenChestState (): Boolean {
181+ val player = mc.thePlayer ? : return false
182+
183+ if (mc.currentScreen !is GuiChest ) {
184+ return false
185+ }
186+
187+ val container = player.openContainer ? : return false
188+ if (container.windowId == 0 ) {
189+ return false
190+ }
191+
192+ if (receivedId != container.windowId || stacks.isEmpty() || stacks.size != container.inventorySlots.size) {
193+ receivedId = container.windowId
194+ stacks = container.inventorySlots.map { it.stack }
195+ }
196+
197+ return true
198+ }
199+
200+ private fun canTakeStack (stack : ItemStack ): Boolean {
201+ if (hasSpaceInInventory()) {
202+ return true
203+ }
204+
205+ val mergeableCount = mc.thePlayer?.inventory?.mainInventory?.sumOf { otherStack ->
206+ otherStack?.takeIf {
207+ it.isItemEqual(stack) && ItemStack .areItemStackTagsEqual(stack, otherStack)
208+ }?.let { mergeableStack ->
209+ mergeableStack.maxStackSize - mergeableStack.stackSize
210+ } ? : 0
211+ } ? : 0
212+
213+ return mergeableCount > 0
214+ }
215+
171216 private suspend fun shouldOperate (): Boolean {
172217 while (true ) {
173218 if (! handleEvents())
@@ -179,6 +224,8 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
179224 if (mc.currentScreen !is GuiChest )
180225 return false
181226
227+ syncOpenChestState()
228+
182229 if (mc.thePlayer?.openContainer?.windowId != receivedId)
183230 return false
184231
@@ -223,6 +270,8 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
223270 if (screen !is GuiChest || ! shouldOperate())
224271 return
225272
273+ syncOpenChestState()
274+
226275 // Check if chest isn't a custom gui
227276 if (chestTitle && Blocks .chest.localizedName !in (screen.lowerChestInventory ? : return ).name)
228277 return
@@ -238,26 +287,29 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
238287 if (! shouldOperate())
239288 return
240289
241- if (! hasSpaceInInventory())
242- return
290+ val itemsToSteal = getItemsToSteal()
243291
244- var hasTaken = false
292+ if (itemsToSteal.isEmpty()) {
293+ progress = 1f
294+ delay(closeDelay.random().toLong())
245295
246- val itemsToSteal = getItemsToSteal()
296+ nextTick { SilentHotbar .resetSlot() }
297+ break
298+ }
299+
300+ var hasTaken = false
247301
248302 run scheduler@{
249303 itemsToSteal.forEachIndexed { index, (slot, stack, sortableTo) ->
250304 // Wait for NoMove or cancel click
251305 if (! shouldOperate()) {
252306 nextTick { SilentHotbar .resetSlot() }
253- chestStealerCurrentSlot = - 1
254- chestStealerLastSlot = - 1
307+ resetStealState()
255308 return
256309 }
257310
258- if (! hasSpaceInInventory()) {
259- chestStealerCurrentSlot = - 1
260- chestStealerLastSlot = - 1
311+ if (! canTakeStack(stack)) {
312+ resetStealState()
261313 return @scheduler
262314 }
263315
@@ -326,13 +378,12 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
326378 awaitTicked()
327379
328380 // Before closing the chest, check all items once more, whether server hadn't cancelled some of the actions.
329- stacks = thePlayer.openContainer.inventory
381+ stacks = thePlayer.openContainer.inventorySlots.map { it.stack }
330382 }
331383
332384 // Wait before the chest gets closed (if it gets closed out of tick loop it could throw npe)
333385 nextTick {
334- chestStealerCurrentSlot = - 1
335- chestStealerLastSlot = - 1
386+ resetStealState()
336387 thePlayer.closeScreen()
337388 progress = null
338389
@@ -443,6 +494,14 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
443494 return itemsToSteal
444495 }
445496
497+ override fun onDisable () {
498+ receivedId = null
499+ stacks = emptyList()
500+ currentContainerPos = null
501+ SilentHotbar .resetSlot(this )
502+ resetStealState(clearProgress = true )
503+ }
504+
446505 private fun sortBasedOnOptimumPath (itemsToSteal : MutableList <ItemTakeRecord >) {
447506 for (i in itemsToSteal.indices) {
448507 var nextIndex = i
@@ -493,19 +552,22 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
493552 val onPacket = handler<PacketEvent > { event ->
494553 when (val packet = event.packet) {
495554 is S2DPacketOpenWindow -> {
496- receivedId = null
497- progress = null
555+ resetStealState(clearProgress = true )
556+ currentContainerPos = null
498557
499- if (furnace && packet.windowTitle.unformattedText.lowercase().contains(" furnace" )) {
500- receivedId = packet.windowId
501- stacks = emptyList()
558+ receivedId = when {
559+ packet.guiId == " minecraft:chest" || packet.guiId == " minecraft:container" -> packet.windowId
560+ furnace && packet.windowTitle.unformattedText.lowercase().contains(" furnace" ) -> packet.windowId
561+ else -> null
502562 }
563+ stacks = emptyList()
503564 }
504565
505566 is C0DPacketCloseWindow , is S2EPacketCloseWindow -> {
506567 receivedId = null
507- progress = null
568+ stacks = emptyList()
508569 currentContainerPos = null
570+ resetStealState(clearProgress = true )
509571 }
510572
511573 is S30PacketWindowItems -> {
@@ -516,7 +578,7 @@ object ChestStealer : Module("ChestStealer", Category.OTHER, Category.SubCategor
516578 return @handler
517579
518580 if (receivedId != packetWindowId) {
519- debug(" Chest opened with ${stacks .size} items" )
581+ debug(" Chest opened with ${packet.itemStacks .size} items" )
520582 }
521583
522584 receivedId = packetWindowId
0 commit comments