Skip to content

Commit a9202c2

Browse files
committed
better anti desync measures
1 parent 4ff5cdd commit a9202c2

File tree

3 files changed

+103
-34
lines changed

3 files changed

+103
-34
lines changed

src/main/java/com/lambda/mixin/network/ClientPlayNetworkHandlerMixin.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
import com.lambda.event.EventFlow;
2121
import com.lambda.event.events.InventoryEvent;
2222
import com.lambda.event.events.WorldEvent;
23+
import com.lambda.interaction.request.inventory.InventoryManager;
2324
import com.lambda.module.modules.movement.Velocity;
2425
import com.lambda.module.modules.render.NoRender;
26+
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
27+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
2528
import net.minecraft.client.network.ClientPlayNetworkHandler;
2629
import net.minecraft.client.network.PlayerListEntry;
2730
import net.minecraft.network.packet.s2c.play.*;
@@ -103,4 +106,14 @@ public boolean onServerMetadata(ClientPlayNetworkHandler clientPlayNetworkHandle
103106
void injectVelocity(ExplosionS2CPacket packet, CallbackInfo ci) {
104107
if (Velocity.getExplosion() && Velocity.INSTANCE.isEnabled()) ci.cancel();
105108
}
109+
110+
@WrapMethod(method = "onScreenHandlerSlotUpdate")
111+
private void wrapOnScreenHandlerSlotUpdate(ScreenHandlerSlotUpdateS2CPacket packet, Operation<Void> original) {
112+
InventoryManager.onSlotUpdate(packet, original);
113+
}
114+
115+
@WrapMethod(method = "onInventory")
116+
private void wrapOnInventory(InventoryS2CPacket packet, Operation<Void> original) {
117+
InventoryManager.onInventoryUpdate(packet, original);
118+
}
106119
}

src/main/kotlin/com/lambda/context/AutomationConfig.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ object AutomationConfig : Configurable(LambdaConfig), Automated {
6060
override val eatConfig = EatSettings(this, Group.Eat)
6161

6262
val avoidDesync by setting("Avoid Desync", true, "Cancels incoming inventory update packets if they match previous actions").group(Group.Debug)
63-
val maxDesyncCache by setting("Max Desync Cache", 10, 1..30, 1, "Maximum cached previous inventory actions")
64-
val desyncTimeout by setting("Desync Timeout", 10, 1..30, 1, unit = " ticks", description = "Time to store previous inventory actions before dropping the cache").group(Group.Debug)
63+
val maxDesyncCache by setting("Max Desync Cache", 10, 1..30, 1, "Maximum cached previous inventory actions") { avoidDesync }.group(Group.Debug)
64+
val desyncTimeout by setting("Desync Timeout", 10, 1..30, 1, unit = " ticks", description = "Time to store previous inventory actions before dropping the cache") { avoidDesync }.group(Group.Debug)
6565
val showAllEntries by setting("Show All Entries", false, "Show all entries in the task tree").group(Group.Debug)
6666
val shrinkFactor by setting("Shrink Factor", 0.001, 0.0..1.0, 0.001).group(Group.Debug)
6767
val ignoreItemDropWarnings by setting("Ignore Drop Warnings", false, "Hides the item drop warnings from the break manager").group(Group.Debug)

src/main/kotlin/com/lambda/interaction/request/inventory/InventoryManager.kt

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,22 @@ import com.lambda.context.AutomationConfig
2222
import com.lambda.context.AutomationConfig.avoidDesync
2323
import com.lambda.context.SafeContext
2424
import com.lambda.event.EventFlow.post
25-
import com.lambda.event.events.PacketEvent
2625
import com.lambda.event.events.TickEvent
2726
import com.lambda.event.events.UpdateManagerEvent
2827
import com.lambda.event.listener.SafeListener.Companion.listen
2928
import com.lambda.interaction.request.Logger
3029
import com.lambda.interaction.request.RequestHandler
3130
import com.lambda.interaction.request.placing.PlaceManager
3231
import com.lambda.module.hud.ManagerDebugLoggers.inventoryManagerLogger
33-
import com.lambda.util.Communication.info
32+
import com.lambda.threading.runSafe
3433
import com.lambda.util.collections.LimitedDecayQueue
3534
import com.lambda.util.item.ItemStackUtils.equal
35+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation
36+
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen
3637
import net.minecraft.item.ItemStack
3738
import net.minecraft.network.packet.s2c.play.InventoryS2CPacket
39+
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket
40+
import net.minecraft.screen.PlayerScreenHandler
3841
import net.minecraft.screen.ScreenHandler
3942
import net.minecraft.screen.slot.Slot
4043

@@ -69,33 +72,8 @@ object InventoryManager : RequestHandler<InventoryRequest>(
6972
override fun load(): String {
7073
super.load()
7174

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-
9475
listen<TickEvent.Post>(priority = Int.MIN_VALUE) {
95-
if (avoidDesync) {
96-
alteredSlots.addAll(gatherInventoryChanges())
97-
slots = getStacks(player.currentScreenHandler.slots)
98-
}
76+
if (avoidDesync) indexInventoryChanges()
9977
if (++secondCounter >= 20) {
10078
secondCounter = 0
10179
actionsThisSecond = 0
@@ -122,6 +100,7 @@ object InventoryManager : RequestHandler<InventoryRequest>(
122100
while (iterator.hasNext()) {
123101
if (actionsThisSecond + 1 > maxActionsThisSecond && !request.mustPerform) break
124102
iterator.next()()
103+
if (avoidDesync) indexInventoryChanges()
125104
actionsThisTick++
126105
actionsThisSecond++
127106
iterator.remove()
@@ -141,14 +120,91 @@ object InventoryManager : RequestHandler<InventoryRequest>(
141120
maxActionsThisSecond = request.inventoryConfig.actionsPerSecond
142121
}
143122

144-
private fun SafeContext.gatherInventoryChanges() =
145-
if (player.currentScreenHandler !== screenHandler) emptyList()
146-
else screenHandler?.slots
147-
?.filter { it.stack != slots[it.id] }
123+
private fun SafeContext.indexInventoryChanges() {
124+
if (player.currentScreenHandler !== screenHandler) return
125+
val changes = screenHandler?.slots
126+
?.filter { !it.stack.equal(slots[it.id]) }
148127
?.map { Pair(it.id, Pair(slots[it.id], it.stack.copy())) }
149128
?: emptyList()
129+
alteredSlots.addAll(changes)
130+
slots = getStacks(player.currentScreenHandler.slots)
131+
}
150132

151133
private fun getStacks(slots: Collection<Slot>) = slots.map { it.stack.copy() }
152134

135+
/**
136+
* A modified version of the [net.minecraft.client.network.ClientPlayNetworkHandler.onInventory] method
137+
*/
138+
@JvmStatic
139+
fun onInventoryUpdate(packet: InventoryS2CPacket, original: Operation<Void>){
140+
runSafe {
141+
if (!mc.isOnThread || !avoidDesync) {
142+
original.call(packet)
143+
return
144+
}
145+
screenHandler = player.currentScreenHandler
146+
val packetScreenHandler =
147+
when (packet.syncId) {
148+
0 -> player.playerScreenHandler
149+
screenHandler?.syncId -> player.currentScreenHandler
150+
else -> return@runSafe
151+
}
152+
val alteredContents = mutableListOf<ItemStack>()
153+
packet.contents.forEachIndexed { index, incomingStack ->
154+
val matches = alteredSlots.removeIf { cached ->
155+
incomingStack.equal(cached.second.second)
156+
}
157+
if (matches) alteredContents.add(packetScreenHandler.slots[index].stack)
158+
else alteredContents.add(incomingStack)
159+
}
160+
packetScreenHandler.updateSlotStacks(packet.revision(), alteredContents, packet.cursorStack())
161+
return
162+
}
163+
original.call(packet)
164+
}
165+
166+
/**
167+
* A modified version of the vanilla [net.minecraft.client.network.ClientPlayNetworkHandler.onScreenHandlerSlotUpdate] method
168+
*/
169+
@JvmStatic
170+
fun onSlotUpdate(packet: ScreenHandlerSlotUpdateS2CPacket, original: Operation<Void>) {
171+
runSafe {
172+
screenHandler = player.currentScreenHandler
173+
if (!mc.isOnThread || !avoidDesync) {
174+
original.call(packet)
175+
return
176+
}
177+
val itemStack = packet.stack
178+
mc.tutorialManager.onSlotUpdate(itemStack)
179+
180+
val bl = (mc.currentScreen as? CreativeInventoryScreen)?.let {
181+
!it.isInventoryTabSelected
182+
} ?: false
183+
184+
val matches = alteredSlots.removeIf {
185+
it.first == packet.slot && it.second.second.equal(itemStack)
186+
}
187+
188+
if (packet.syncId == 0) {
189+
if (PlayerScreenHandler.isInHotbar(packet.slot) && !itemStack.isEmpty) {
190+
val itemStack2 = screenHandler?.getSlot(packet.slot)?.stack ?: return
191+
if (itemStack2.isEmpty || itemStack2.count < itemStack.count) {
192+
itemStack.bobbingAnimationTime = 5
193+
}
194+
}
195+
196+
if (!matches) player.playerScreenHandler.setStackInSlot(packet.slot, packet.revision, itemStack)
197+
} else if (packet.syncId == player.currentScreenHandler.syncId && (packet.syncId != 0 || !bl))
198+
if (!matches) player.currentScreenHandler.setStackInSlot(packet.slot, packet.revision, itemStack)
199+
200+
if (mc.currentScreen is CreativeInventoryScreen) {
201+
player.playerScreenHandler.setReceivedStack(packet.slot, itemStack)
202+
player.playerScreenHandler.sendContentUpdates()
203+
}
204+
return
205+
}
206+
original.call(packet)
207+
}
208+
153209
override fun preEvent() = UpdateManagerEvent.Inventory.post()
154210
}

0 commit comments

Comments
 (0)