Skip to content

Commit

Permalink
[LEGACY] Inventory Management Rework (#1347)
Browse files Browse the repository at this point in the history
* [LEGACY] Inventory management rework beta

Recoded AutoArmor, InventoryCleaner and ChestStealer using coroutines.
* they are executed sequentially from a coroutine in ModuleManager
* added temporary modules CoroutineStealer, CoroutineArmorer, CoroutineCleaner to category Beta
* order of execution: Stealer, Armorer, Cleaner
* all modules clicks are scheduled to ticks from the coroutine, this prevents flags
* it is possible to send multiple clicks in a tick, therefore delays are as precise as they can be when averaged, previously these clicks were scheduled from a render loop but that was fps dependent, coroutines are fps independent and as precise as possible

CoroutineStealer:
* can steal to target sorting slots
* compares items in chests with items in inventory and even equipped armor (no duplicates hopefully)
* after stealing is finished, it checks all items in chest again and if any of actions failed, steals remaining items
* proper start and close delay using coroutines

CoroutineArmorer:
* using CoroutineArmorComparator
* first correct 1.8.9 best armor calculation (LB had 1.9 calculations before)
* for these calculations to be as good as possible, it finds all armor combinations and sorts them by average defense factor of the whole set
* when swapping armor pieces, it doesn't just drop the worse one and equip the better one, instead, it grabs the better one, drags and swaps it with equipped one and drops the equipped one
* this way there is no time of having no armor piece equipped
* proper start and close delay using coroutines
* can autoclose inventory, if invopen is enabled

CoroutineCleaner:
* using cleaning and sorting system from my InventoryManager script
* better useful block comparison, no interactable blocks, half blocks, stairs, flowers and so on
* no item duplicates, items are compared with their stats, durability, enchantment count, ... if both are equally good, the one that is sorted or lower in inventory wins
* sorting targets allow duplicates for blocks, pearls, etc, but not for swords, tools, ...
* added sorting target to Fire (lava, flint n' steel, ...)

TickScheduler:
* added object TickScheduler to each module
* used as a bridge to TickedActions
* has features like .schedule(), .scheduleClick(), +=, in, ...
* added optional allowDuplicates argument to TickedActions
* replaced usage of TickedActions to TickScheduler
* modified TickedActions accordingly

DelayTimer:
* new timer that is initialised with 2 arguments (min delay value, max delay value)
* every time it gets reset a random delay gets chosen
* it gets checked with .hasTimePassed() with no arguments
* used in Scaffold

ItemUtils:
* code cleanup
* ItemStack.enchantments - map of all enchantments and levels, used in ItemStack.enchantmentCount, ItemStack.enchantmentSum, ItemStack.getEnchantmentLevel()
* ItemStack.totalDurability = ItemStack.durability * unbreaking level

Minor improvements:
* made variable in Ambience private
* InventoryUtils.hasSpaceHotbar() -> hasSpaceInHotbar()
* BlockUtils improvements regarding block filtering
* increased maximal ClickGUI fade speed
* removed unnecessary ; at line ends
* added InventoryUtils.hasSpaceInInventory()
* replaced some .count() with .size
* Iterable.shuffled(shuffle: Boolean) - shuffling based on boolean, if false, does not shuffle, used in inventory managment rework
* changed refill to onTick, made it use CLICK_TIMER
* CLICK_TIMER gets reset on every window click now (but its pretty useless because of this rework)
* replaced some for loops with repeat loops for better readability
* run block simplification

* removed arbitrary comment

* added missing state checks

* improvements

* added sorting target: "Potion"
* added ItemStack.isSplashPotion(), replaced use of ItemPotion.isSplashPotion(stack.metadata) with it
* removed some commented out lines
* fixed stack trace printing

* MovementUtils improvements

* fixed possible NPEs
* simplified code

* More improvements

CoroutineArmorer:
* improved delayedSlotSwitch: if disabled: schedules all clicks to next tick to equip 4 items at once, bypasses everything except Vulcan, Matrix, if enabled: schedules slot change and click per tick

CoroutineUtils:
* added waitUntil(condition) - suspends the thread with a while loop until the condition is met, used in coroutine modules

TickScheduler:
* added scheduleAndSuspend(vararg actions) - for scheduling multiple actions to be executed 1 per tick

TickedActions:
* fixed a bug: if you had an action scheduled to an id "x", you couldn't schedule another action to id "x" from it without allowing duplicates

Other:
* improved comments
* fixed a possible NPE
* moved modules to beta category package

* Bigger improvements

CoroutineArmorer:
* made smart armor piece swapping stable and toggleable (https://youtu.be/5QyAOE9KY0I)

CoroutineCleaner:
* added MaxBlockStacks, determines how many slots can be occupied by blocks (https://youtu.be/v2VYRbvb_mA)
* removed separate sorting delay, just one delay is enough
* fixed possible sorting / isUseful / comparison issue
* stacks that were in target sorting slots had advantage even when sorting was disabled

CoroutineStealer:
* refactored TakeRandomized to RandomSlot

Other:
* refactored ItemDelay to MinItemAge
* refactored ItemStack.hasItemDelayPassed to hasItemAgePassed
* included delay() straight into click() and therefore simplified code
* reordered values
* added more comments

* Armorer hotfix + todo

* Major stability and compatibility improvements

Fixed major issue of waitUntil { TickScheduler.isEmpty() } not working at all because of the way how duplicated actions got managed.
* caused inventory desyncs, dropping whole armor sets and so on
* had to rollback TickedActions to how they were previously

CoroutineArmorer:
* fixed DelayedSlotSwitch still flagging on Vulcan
* made armor equipping instant again
* improved compatibility with CoroutineCleaner regarding inventory / simulated inventory management and closing
* improved code

CoroutineCleaner:
* improved compatibility with CoroutineArmorer, only executes if CoroutineArmorer finished first (if InvOpen was enabled, it would drop garbage and close the inventory, without Armorer equipping armor pieces before that)

More comments

* Highlight useful items on ground

Added HighlightUseful option to CoroutineCleaner
* renders green esp boxes for useful items that are dropped on ground
* integrated into ItemESP, uses its settings, when ItemESP is disabled it only renders useful items, otherwise it renders useful items with green color
* had to make item comparison compatible with dropped items on ground
* compares dropped items with inventory items + dropped items, if 2 dropped items are equally good it compares their squared distances

Fixed ItemStack.totalDurability not working correctly

Improved code of ESP modules

* MaxFoodStacks and better comparisons

Added MaxFoodStacks
* compares food by total saturation sum of the stack

Now also compares dropped blocks and food items between themselves when highlighting.

* Stack compacting and fixes

CoroutineCleaner:
* added CompactStacks option

InventoryUtils:
* added InventoryUtils.isFirstInventoryClick - fixed start delays in coroutine modules with it

Fixed possible NPE.
Fixed AutoClose possibly closing too soon, if your delay settings were in sync with tick loop.

* Resolved conflicts

* Added setters to serverSlot and serverOpenInventory

Simplified inventory, hotbar slot management in modules with these.

* The Big Bang Update

Added util InventoryManager:
* stores shared values of Armorer, Cleaner, InventoryMove, Refill, ... (NoMoveClicks and its options, for Armorer and Cleaner also start, close delay, autoclose, ...) - these values are shared between modules
* handles inventory management actions one by one
* if player is violating nomove or invopen, no inventory requiring actions even start waiting for nomove, because that could block hotbar equipping from doing its stuff
* properly fixed unwanted autoclosing

CoroutineCleaner:
* added LimitStackCounts that needs to be enabled for MaxBlockStacks and such to work
* renamed CompactStacks to MergeStacks
* fixed stack merging and also improved it by ignoring stack limits when checking what to merge, temporarily set max merging delay to 100
* whitelisted eggs and snowballs, added a sorting category for them called "Throwable"

CoroutineStealer:
* now cooperates with autoarmor to equip armor pieces even while still inside a chest
* fixed incorrectly assumed item swapping logic which could have problems when inventory was full
* if inventory is full, garbage items or items that occupy hotbar sorting slot are now moved to chest to free up inventory space
* fixed progress bar being shown in chests that were ignored because of their title or such
* fixed progress bar first appearing after start delay elapsed

InventoryMove:
* added value SilentlyCloseAndReopen - if player violates nomove check and inventory is open, close inventory and reopen it when still
* added value reopenOnClick - only reopen inventory, before a click
* renamed value Undetectable to NotInChests - if you invmove when a chest is open on Polar, the chest gets closed instantly
* improved code

TickedActions:
* fixed scheduling - nested schedules now aren't flagged as duplicates or cleared before ever being called
* added TickedActions.size(module) and TickScheduler.size

Fixed InventoryUtils getting into unescaped loops and freezing game by adding backing fields.
* improved server inventory closing detection by checking if server sent a packet to open a different window

Sprint:
* added value Inventory - stops you from sprinting when serverOpenInventory == true, needed to bypass Vulcan for example

MovementUtils:
* added serverOnGround, serverX, serverY, serverZ - used serverOnGround to improve NoMove checks for ground
* fixed hasMotion that got broken in previous commit

EventManager:
* simplified code
* improved performance by not sorting by priority every event call

Added comments.

Refactored some util packages and moved some utils around.

* Finishing touches

Improved coroutine modules
* Now they only work if gamemode is survival or adventure.
* Stealer now drops garbage items that block useful items from chest from being taken, when the chest is full as well...
* Stealer now checks whether armor slot isn't occupied, when equipping while stealing.
* Removed forgotten debug message.

Improved ItemStack?.isEmpty()
* Used kotlin contract to make stack smart-cast to not null ItemStack.

Improved AutoPot, AutoSoup
* No longer closes visually open inventory when simulating inventory closing after each click.

A bit of refactoring and other minor stuff.
  • Loading branch information
CzechHek committed Oct 10, 2023
1 parent c3c9d4d commit 959aa72
Show file tree
Hide file tree
Showing 103 changed files with 2,230 additions and 644 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Expand Up @@ -66,6 +66,10 @@ dependencies {

include 'org.apache.httpcomponents:httpmime:4.3.3'

// https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core
include 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'


include fileTree(include: ["*.jar"], dir: "libs")
}

Expand Down
10 changes: 6 additions & 4 deletions src/main/java/net/ccbluex/liquidbounce/LiquidBounce.kt
Expand Up @@ -42,10 +42,11 @@ import net.ccbluex.liquidbounce.utils.Background
import net.ccbluex.liquidbounce.utils.ClassUtils.hasForge
import net.ccbluex.liquidbounce.utils.ClientUtils.LOGGER
import net.ccbluex.liquidbounce.utils.ClientUtils.disableFastRender
import net.ccbluex.liquidbounce.utils.InventoryUtils
import net.ccbluex.liquidbounce.utils.MovementUtils
import net.ccbluex.liquidbounce.utils.RotationUtils
import net.ccbluex.liquidbounce.utils.TickedActions
import net.ccbluex.liquidbounce.utils.inventory.InventoryUtils
import net.ccbluex.liquidbounce.utils.render.MiniMapRegister
import net.ccbluex.liquidbounce.utils.timing.TickedActions
import kotlin.concurrent.thread

object LiquidBounce {
Expand Down Expand Up @@ -102,13 +103,14 @@ object LiquidBounce {
registerListener(InventoryUtils)
registerListener(MiniMapRegister)
registerListener(TickedActions)
registerListener(MovementUtils)

// Load client fonts
loadFonts()

// Load settings
loadSettings(false) {
LOGGER.info("Successfully loaded ${it.count()} settings.")
LOGGER.info("Successfully loaded ${it.size} settings.")
}

// Register commands
Expand Down Expand Up @@ -174,7 +176,7 @@ object LiquidBounce {

// Refresh cape service
CapeService.refreshCapeCarriers {
LOGGER.info("Successfully loaded ${CapeService.capeCarriers.count()} cape carriers.")
LOGGER.info("Successfully loaded ${CapeService.capeCarriers.size} cape carriers.")
}

// Load background
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/net/ccbluex/liquidbounce/cape/CapeService.kt
Expand Up @@ -6,15 +6,14 @@
package net.ccbluex.liquidbounce.cape

import com.google.gson.JsonParser
import net.ccbluex.liquidbounce.api.ClientApi.API_ENDPOINT
import net.ccbluex.liquidbounce.event.EventTarget
import net.ccbluex.liquidbounce.event.Listenable
import net.ccbluex.liquidbounce.event.SessionEvent
import net.ccbluex.liquidbounce.utils.ClientUtils.LOGGER
import net.ccbluex.liquidbounce.utils.MinecraftInstance
import net.ccbluex.liquidbounce.utils.login.UserUtils
import net.ccbluex.liquidbounce.utils.misc.HttpUtils.get
import net.ccbluex.liquidbounce.utils.timer.MSTimer
import net.ccbluex.liquidbounce.utils.timing.MSTimer
import org.apache.http.HttpHeaders
import org.apache.http.HttpStatus
import org.apache.http.client.methods.HttpDelete
Expand Down
8 changes: 3 additions & 5 deletions src/main/java/net/ccbluex/liquidbounce/event/EventManager.kt
Expand Up @@ -23,7 +23,7 @@ object EventManager {

val invokableEventTargets = registry.getOrDefault(eventClass, ArrayList())
invokableEventTargets += EventHook(listener, method, eventTarget)
registry[eventClass] = invokableEventTargets
registry[eventClass] = invokableEventTargets.sortedByDescending { it.priority }.toMutableList()
}
}

Expand All @@ -33,10 +33,8 @@ object EventManager {
* @param listenable for unregister
*/
fun unregisterListener(listenable: Listenable) =
registry.forEach { (key, targets) ->
registry.forEach { (_, targets) ->
targets.removeIf { it.eventClass == listenable }

registry[key] = targets
}

/**
Expand All @@ -47,7 +45,7 @@ object EventManager {
fun callEvent(event: Event) {
val targets = registry[event.javaClass] ?: return

for (invokableEventTarget in targets.sortedByDescending { it.priority }) {
for (invokableEventTarget in targets) {
try {
if (!invokableEventTarget.eventClass.handleEvents() && !invokableEventTarget.isIgnoreCondition)
continue
Expand Down
Expand Up @@ -7,7 +7,7 @@ package net.ccbluex.liquidbounce.features.command.commands

import net.ccbluex.liquidbounce.features.command.Command
import net.ccbluex.liquidbounce.utils.PacketUtils.sendPacket
import net.ccbluex.liquidbounce.utils.item.ItemUtils
import net.ccbluex.liquidbounce.utils.inventory.ItemUtils
import net.ccbluex.liquidbounce.utils.misc.StringUtils
import net.minecraft.item.Item
import net.minecraft.network.play.client.C10PacketCreativeInventoryAction
Expand All @@ -32,23 +32,7 @@ class GiveCommand : Command("give", "item", "i", "get") {
return
}

var emptySlot = -1

for (i in 36..44) {
if (thePlayer.inventoryContainer.getSlot(i).stack == null) {
emptySlot = i
break
}
}

if (emptySlot == -1) {
for (i in 9..44) {
if (thePlayer.inventoryContainer.getSlot(i).stack == null) {
emptySlot = i
break
}
}
}
val emptySlot = thePlayer.inventory.firstEmptyStack

if (emptySlot != -1) {
sendPacket(C10PacketCreativeInventoryAction(emptySlot, itemStack))
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/net/ccbluex/liquidbounce/features/module/Module.kt
Expand Up @@ -13,11 +13,14 @@ import net.ccbluex.liquidbounce.lang.translation
import net.ccbluex.liquidbounce.ui.client.hud.HUD.addNotification
import net.ccbluex.liquidbounce.ui.client.hud.element.elements.Arraylist
import net.ccbluex.liquidbounce.ui.client.hud.element.elements.Notification
import net.ccbluex.liquidbounce.utils.CoroutineUtils.waitUntil
import net.ccbluex.liquidbounce.utils.MinecraftInstance
import net.ccbluex.liquidbounce.utils.extensions.toLowerCamelCase
import net.ccbluex.liquidbounce.utils.misc.RandomUtils.nextFloat
import net.ccbluex.liquidbounce.utils.timing.TickedActions
import net.ccbluex.liquidbounce.value.Value
import net.minecraft.client.audio.PositionedSoundRecord
import net.minecraft.item.ItemStack
import net.minecraft.util.ResourceLocation
import org.lwjgl.input.Keyboard

Expand Down Expand Up @@ -68,6 +71,8 @@ open class Module @JvmOverloads constructor(
// Call toggle
onToggle(value)

TickScheduler.clear()

// Play sound and add notification
if (!isStarting) {
mc.soundHandler.playSound(PositionedSoundRecord.create(ResourceLocation("random.click"), 1F))
Expand Down Expand Up @@ -143,4 +148,51 @@ open class Module @JvmOverloads constructor(
* Events should be handled when module is enabled
*/
override fun handleEvents() = state

internal object TickScheduler {
lateinit var instance: Module

internal fun schedule(id: Int, allowDuplicates: Boolean = false, action: () -> Unit) =
TickedActions.schedule(id, instance, allowDuplicates, action)

internal fun scheduleClick(slot: Int, button: Int, mode: Int, allowDuplicates: Boolean = false, windowId: Int = mc.thePlayer.openContainer.windowId, action: ((ItemStack?) -> Unit)? = null) =
schedule(slot, allowDuplicates) {
val newStack = mc.playerController.windowClick(windowId, slot, button, mode, mc.thePlayer)
action?.invoke(newStack)
}

operator fun plusAssign(action: () -> Unit) {
schedule(-1, true, action)
}

// Schedule actions to be executed in following ticks, one each tick
// Thread is frozen until all actions were executed (suitable for coroutines)
internal fun scheduleAndSuspend(vararg actions: () -> Unit) =
actions.forEach {
this += it
waitUntil(::isEmpty)
}

internal fun scheduleAndSuspend(id: Int = -1, allowDuplicates: Boolean = true, action: () -> Unit) {
schedule(id, allowDuplicates, action)
waitUntil(::isEmpty)
}

internal fun isScheduled(id: Int) = TickedActions.isScheduled(id, instance)

// Checks if id click is scheduled: if (id in TickScheduler)
operator fun contains(id: Int) = isScheduled(id)

internal fun clear() = TickedActions.clear(instance)

internal val size
get() = TickedActions.size(instance)

internal fun isEmpty() = TickedActions.isEmpty(instance)

}

init {
TickScheduler.instance = this
}
}
Expand Up @@ -14,6 +14,7 @@ enum class ModuleCategory(val displayName: String) {
WORLD("World"),
MISC("Misc"),
EXPLOIT("Exploit"),
FUN("Fun")
FUN("Fun"),
BETA("Beta")

}
Expand Up @@ -11,6 +11,9 @@ import net.ccbluex.liquidbounce.event.EventTarget
import net.ccbluex.liquidbounce.event.KeyEvent
import net.ccbluex.liquidbounce.event.Listenable
import net.ccbluex.liquidbounce.features.command.CommandManager.registerCommand
import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineArmorer
import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineCleaner
import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineStealer
import net.ccbluex.liquidbounce.features.module.modules.combat.*
import net.ccbluex.liquidbounce.features.module.modules.exploit.*
import net.ccbluex.liquidbounce.features.module.modules.`fun`.Derp
Expand All @@ -22,6 +25,7 @@ import net.ccbluex.liquidbounce.features.module.modules.render.*
import net.ccbluex.liquidbounce.features.module.modules.world.*
import net.ccbluex.liquidbounce.features.module.modules.world.Timer
import net.ccbluex.liquidbounce.utils.ClientUtils.LOGGER
import net.ccbluex.liquidbounce.utils.inventory.InventoryManager
import java.util.*


Expand Down Expand Up @@ -99,6 +103,9 @@ object ModuleManager : Listenable {
Clip,
ComponentOnHover,
ConsoleSpammer,
CoroutineArmorer,
CoroutineCleaner,
CoroutineStealer,
Criticals,
Damage,
Derp,
Expand Down Expand Up @@ -202,6 +209,8 @@ object ModuleManager : Listenable {
Zoot
)

InventoryManager.startCoroutine()

LOGGER.info("[ModuleManager] Loaded ${modules.size} modules.")
}

Expand Down

0 comments on commit 959aa72

Please sign in to comment.