1818package com.lambda.interaction.request.inventory
1919
2020import com.lambda.context.AutomatedSafeContext
21+ import com.lambda.context.AutomationConfig
22+ import com.lambda.context.AutomationConfig.avoidDesync
2123import com.lambda.context.SafeContext
2224import com.lambda.event.EventFlow.post
25+ import com.lambda.event.events.PacketEvent
2326import com.lambda.event.events.TickEvent
2427import com.lambda.event.events.UpdateManagerEvent
2528import com.lambda.event.listener.SafeListener.Companion.listen
2629import com.lambda.interaction.request.Logger
2730import com.lambda.interaction.request.RequestHandler
28- import com.lambda.interaction.request.inventory.InventoryManager.activeRequest
29- import com.lambda.interaction.request.inventory.InventoryManager.processRequest
3031import com.lambda.interaction.request.placing.PlaceManager
3132import com.lambda.module.hud.ManagerDebugLoggers.inventoryManagerLogger
32- import com.lambda.threading.runSafeAutomated
33+ import com.lambda.util.Communication.info
34+ import com.lambda.util.collections.LimitedDecayQueue
35+ import com.lambda.util.item.ItemStackUtils.equal
36+ import net.minecraft.item.ItemStack
37+ import net.minecraft.network.packet.s2c.play.InventoryS2CPacket
38+ import net.minecraft.screen.ScreenHandler
39+ import net.minecraft.screen.slot.Slot
3340
3441object InventoryManager : RequestHandler<InventoryRequest>(
3542 1 ,
3643 TickEvent .Pre ,
3744 TickEvent .Input .Pre ,
3845 TickEvent .Input .Post ,
39- TickEvent .Player .Post ,
40- onOpen = { activeRequest?.let { it.runSafeAutomated { processRequest(it) } } }
46+ TickEvent .Player .Post
4147), Logger {
42- private var activeRequest: InventoryRequest ? = null
4348 private var actions = mutableListOf<SafeContext .() - > Unit > ()
4449
50+ private var slots = listOf<ItemStack >()
51+ private var alteredSlots = LimitedDecayQueue <Pair <Int , Pair <ItemStack , ItemStack >>>(
52+ AutomationConfig .maxDesyncCache, AutomationConfig .desyncTimeout * 50L
53+ )
54+
55+ private var screenHandler: ScreenHandler ? = null
56+ set(value) {
57+ if (value != null && field != = value)
58+ slots = getStacks(value.slots)
59+ field = value
60+ }
61+
4562 private var maxActionsThisSecond = 0
4663 private var actionsThisSecond = 0
4764 private var secondCounter = 0
@@ -52,36 +69,55 @@ object InventoryManager : RequestHandler<InventoryRequest>(
5269 override fun load (): String {
5370 super .load()
5471
72+ listen<PacketEvent .Receive .Pre >(priority = Int .MIN_VALUE ) { event ->
73+ if (! avoidDesync) return @listen
74+ val packet = event.packet as ? InventoryS2CPacket ? : return @listen
75+ screenHandler = player.currentScreenHandler
76+ val packetScreenHandler =
77+ if (packet.syncId == 0 ) player.playerScreenHandler
78+ else player.currentScreenHandler
79+ event.cancel()
80+ val alteredContents = mutableListOf<ItemStack >()
81+ packet.contents.forEachIndexed { index, incomingStack ->
82+ val matches = alteredSlots.removeIf { cached ->
83+ incomingStack.equal(cached.second.second)
84+ }
85+ if (matches) alteredContents.add(packetScreenHandler.slots[index].stack)
86+ else alteredContents.add(incomingStack)
87+ if (matches) info(matches.toString())
88+ }
89+ mc.executeSync {
90+ packetScreenHandler.updateSlotStacks(packet.revision(), alteredContents, packet.cursorStack())
91+ }
92+ }
93+
5594 listen<TickEvent .Post >(priority = Int .MIN_VALUE ) {
95+ if (avoidDesync) {
96+ alteredSlots.addAll(gatherInventoryChanges())
97+ slots = getStacks(player.currentScreenHandler.slots)
98+ }
5699 if (++ secondCounter >= 20 ) {
57100 secondCounter = 0
58101 actionsThisSecond = 0
59102 }
60103 actionsThisTick = 0
61- activeRequest = null
62104 actions.clear()
63105 }
64106
65107 return " Loaded Inventory Manager"
66108 }
67109
68110 override fun AutomatedSafeContext.handleRequest (request : InventoryRequest ) {
69- if (activeRequest != null ) return
70111 if (request.actions.size >= request.inventoryConfig.actionsPerSecond - actionsThisSecond &&
71112 ! request.settleForLess &&
72113 ! request.mustPerform) return
73- activeRequest = request
74- processRequest(request)
75- if (actionsThisTick > 0 ) activeThisTick = true
76- }
114+ if (tickStage !in inventoryConfig.tickStageMask) return
77115
78- private fun AutomatedSafeContext.processRequest (request : InventoryRequest ) {
79116 if (request.fresh) populateFrom(request)
80117
81- if (tickStage !in inventoryConfig.tickStageMask) return
82-
83118 PlaceManager .logger.debug(" Processing request" , request)
84119
120+ screenHandler = player.currentScreenHandler
85121 val iterator = actions.iterator()
86122 while (iterator.hasNext()) {
87123 if (actionsThisSecond + 1 > maxActionsThisSecond && ! request.mustPerform) break
@@ -92,13 +128,11 @@ object InventoryManager : RequestHandler<InventoryRequest>(
92128 }
93129
94130 if (actions.isEmpty()) {
95- activeRequest?.let { request ->
96- logger.debug(" Clearing active request" , activeRequest)
97- request.done = true
98- request.onComplete?.invoke(this )
99- activeRequest = null
100- }
131+ request.done = true
132+ request.onComplete?.invoke(this )
101133 }
134+
135+ if (actionsThisTick > 0 ) activeThisTick = true
102136 }
103137
104138 private fun populateFrom (request : InventoryRequest ) {
@@ -107,5 +141,14 @@ object InventoryManager : RequestHandler<InventoryRequest>(
107141 maxActionsThisSecond = request.inventoryConfig.actionsPerSecond
108142 }
109143
144+ private fun SafeContext.gatherInventoryChanges () =
145+ if (player.currentScreenHandler != = screenHandler) emptyList()
146+ else screenHandler?.slots
147+ ?.filter { it.stack != slots[it.id] }
148+ ?.map { Pair (it.id, Pair (slots[it.id], it.stack.copy())) }
149+ ? : emptyList()
150+
151+ private fun getStacks (slots : Collection <Slot >) = slots.map { it.stack.copy() }
152+
110153 override fun preEvent () = UpdateManagerEvent .Inventory .post()
111154}
0 commit comments