mirror of
https://github.com/CCBlueX/LiquidBounce.git
synced 2025-09-04 16:27:38 +00:00
Added cache to player simulation (#3759)
This commit is contained in:
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
16
gradlew
vendored
16
gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -202,11 +202,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@@ -379,7 +379,7 @@ object FakeLag : Listenable {
|
||||
val arrows = ModuleAutoDodge.findFlyingArrows(world)
|
||||
val playerSimulation = RigidPlayerSimulation(pos)
|
||||
|
||||
return ModuleAutoDodge.getInflictedHits(playerSimulation, arrows, maxTicks = 40) { }
|
||||
return ModuleAutoDodge.getInflictedHits(playerSimulation, arrows, maxTicks = 40)
|
||||
}
|
||||
|
||||
enum class LagResult {
|
||||
|
@@ -25,7 +25,6 @@ import net.ccbluex.liquidbounce.event.handler
|
||||
import net.ccbluex.liquidbounce.event.repeatable
|
||||
import net.ccbluex.liquidbounce.features.module.Category
|
||||
import net.ccbluex.liquidbounce.features.module.Module
|
||||
import net.ccbluex.liquidbounce.features.module.modules.render.murdermystery.ModuleMurderMystery
|
||||
import net.ccbluex.liquidbounce.render.renderEnvironmentForGUI
|
||||
import net.ccbluex.liquidbounce.utils.aiming.Rotation
|
||||
import net.ccbluex.liquidbounce.utils.aiming.RotationManager
|
||||
@@ -180,12 +179,12 @@ object ModuleAutoBow : Module("AutoBow", Category.COMBAT, aliases = arrayOf("Bow
|
||||
arrow.tick()
|
||||
|
||||
players.forEach { (entity, player) ->
|
||||
player.tick()
|
||||
val playerSnapshot = player.getSnapshotAt(i)
|
||||
|
||||
val playerHitBox =
|
||||
Box(-0.3, 0.0, -0.3, 0.3, 1.8, 0.3)
|
||||
.expand(0.3)
|
||||
.offset(player.pos)
|
||||
.offset(playerSnapshot.pos)
|
||||
|
||||
val raycastResult = playerHitBox.raycast(lastPos, arrow.pos)
|
||||
|
||||
@@ -198,12 +197,12 @@ object ModuleAutoBow : Module("AutoBow", Category.COMBAT, aliases = arrayOf("Bow
|
||||
return null
|
||||
}
|
||||
|
||||
fun findAndBuildSimulatedPlayers(): List<Pair<AbstractClientPlayerEntity, SimulatedPlayer>> {
|
||||
fun findAndBuildSimulatedPlayers(): List<Pair<AbstractClientPlayerEntity, SimulatedPlayerCache>> {
|
||||
return world.players.filter {
|
||||
it != player &&
|
||||
Line(player.pos, player.rotationVector).squaredDistanceTo(it.pos) < 10.0 * 10.0
|
||||
}.map {
|
||||
Pair(it, SimulatedPlayer.fromOtherPlayer(it, SimulatedPlayer.SimulatedPlayerInput.guessInput(it)))
|
||||
Pair(it, PlayerSimulationCache.getSimulationForOtherPlayers(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ import net.ccbluex.liquidbounce.render.engine.Color4b
|
||||
import net.ccbluex.liquidbounce.render.renderEnvironmentForWorld
|
||||
import net.ccbluex.liquidbounce.render.withColor
|
||||
import net.ccbluex.liquidbounce.utils.combat.findEnemy
|
||||
import net.ccbluex.liquidbounce.utils.entity.SimulatedPlayer
|
||||
import net.ccbluex.liquidbounce.utils.entity.PlayerSimulationCache
|
||||
import net.ccbluex.liquidbounce.utils.math.toVec3
|
||||
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -149,8 +149,7 @@ internal object ModuleTickBase : Module("TickBase", Category.COMBAT) {
|
||||
|
||||
tickBuffer.clear()
|
||||
|
||||
val input = SimulatedPlayer.SimulatedPlayerInput.fromClientPlayer(event.directionalInput)
|
||||
val simulatedPlayer = SimulatedPlayer.fromClientPlayer(input)
|
||||
val simulatedPlayer = PlayerSimulationCache.getSimulationForLocalPlayer()
|
||||
|
||||
if (tickBalance <= 0) {
|
||||
reachedTheLimit = true
|
||||
@@ -166,13 +165,15 @@ internal object ModuleTickBase : Module("TickBase", Category.COMBAT) {
|
||||
return@handler
|
||||
}
|
||||
|
||||
repeat(min(tickBalance.toInt(), maxTicksAtATime)) {
|
||||
simulatedPlayer.tick()
|
||||
val tickRange = 0 until min(tickBalance.toInt(), maxTicksAtATime)
|
||||
val snapshots = simulatedPlayer.getSnapshotsBetween(tickRange)
|
||||
|
||||
snapshots.forEach {
|
||||
tickBuffer += TickData(
|
||||
simulatedPlayer.pos,
|
||||
simulatedPlayer.fallDistance,
|
||||
simulatedPlayer.velocity,
|
||||
simulatedPlayer.onGround
|
||||
it.pos,
|
||||
it.fallDistance,
|
||||
it.velocity,
|
||||
it.onGround
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -28,9 +28,10 @@ import net.ccbluex.liquidbounce.features.module.modules.render.murdermystery.Mod
|
||||
import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.ModuleScaffold
|
||||
import net.ccbluex.liquidbounce.utils.client.EventScheduler
|
||||
import net.ccbluex.liquidbounce.utils.client.Timer
|
||||
import net.ccbluex.liquidbounce.utils.entity.CachedPlayerSimulation
|
||||
import net.ccbluex.liquidbounce.utils.entity.PlayerSimulation
|
||||
import net.ccbluex.liquidbounce.utils.entity.PlayerSimulationCache
|
||||
import net.ccbluex.liquidbounce.utils.entity.SimulatedArrow
|
||||
import net.ccbluex.liquidbounce.utils.entity.SimulatedPlayer
|
||||
import net.ccbluex.liquidbounce.utils.kotlin.Priority
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.entity.projectile.ArrowEntity
|
||||
@@ -65,12 +66,10 @@ object ModuleAutoDodge : Module("AutoDodge", Category.COMBAT) {
|
||||
|
||||
val arrows = findFlyingArrows(world)
|
||||
|
||||
val input = SimulatedPlayer.SimulatedPlayerInput.fromClientPlayer(event.directionalInput)
|
||||
|
||||
val simulatedPlayer = SimulatedPlayer.fromClientPlayer(input)
|
||||
val simulatedPlayer = CachedPlayerSimulation(PlayerSimulationCache.getSimulationForLocalPlayer())
|
||||
|
||||
val inflictedHit =
|
||||
getInflictedHits(simulatedPlayer, arrows, hitboxExpansion = DodgePlanner.SAFE_DISTANCE_WITH_PADDING) {}
|
||||
getInflictedHits(simulatedPlayer, arrows, hitboxExpansion = DodgePlanner.SAFE_DISTANCE_WITH_PADDING)
|
||||
?: return@handler
|
||||
|
||||
val dodgePlan =
|
||||
@@ -112,13 +111,10 @@ object ModuleAutoDodge : Module("AutoDodge", Category.COMBAT) {
|
||||
arrows: List<ArrowEntity>,
|
||||
maxTicks: Int = 80,
|
||||
hitboxExpansion: Double = 0.7,
|
||||
behaviour: (T) -> Unit,
|
||||
): HitInfo? {
|
||||
val simulatedArrows = arrows.map { SimulatedArrow(world, it.pos, it.velocity, false) }
|
||||
|
||||
for (i in 0 until maxTicks) {
|
||||
behaviour(simulatedPlayer)
|
||||
|
||||
simulatedPlayer.tick()
|
||||
|
||||
simulatedArrows.forEachIndexed { arrowIndex, arrow ->
|
||||
|
@@ -32,7 +32,7 @@ import net.ccbluex.liquidbounce.features.module.modules.player.ModuleBlink
|
||||
import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.ModuleScaffold
|
||||
import net.ccbluex.liquidbounce.render.*
|
||||
import net.ccbluex.liquidbounce.render.engine.Color4b
|
||||
import net.ccbluex.liquidbounce.utils.entity.SimulatedPlayer
|
||||
import net.ccbluex.liquidbounce.utils.entity.PlayerSimulationCache
|
||||
import net.ccbluex.liquidbounce.utils.entity.eyes
|
||||
import net.ccbluex.liquidbounce.utils.math.geometry.Face
|
||||
import net.ccbluex.liquidbounce.utils.math.geometry.Line
|
||||
@@ -59,33 +59,26 @@ object ModuleDebug : Module("Debug", Category.RENDER) {
|
||||
object RenderSimulatedPlayer : ToggleableConfigurable(this, "SimulatedPlayer", false) {
|
||||
|
||||
private val ticksToPredict by int("TicksToPredict", 20, 5..100)
|
||||
private val simLines = mutableListOf<Vec3d>()
|
||||
|
||||
@Suppress("unused")
|
||||
val tickRep = handler<MovementInputEvent> { event ->
|
||||
val tickRep = handler<MovementInputEvent> { _ ->
|
||||
// We aren't actually where we are because of blink.
|
||||
// So this module shall not cause any disturbance in that case.
|
||||
if (ModuleBlink.enabled) {
|
||||
return@handler
|
||||
}
|
||||
|
||||
simLines.clear()
|
||||
|
||||
val input =
|
||||
SimulatedPlayer.SimulatedPlayerInput.fromClientPlayer(event.directionalInput)
|
||||
|
||||
val simulatedPlayer = SimulatedPlayer.fromClientPlayer(input)
|
||||
|
||||
repeat(ticksToPredict) {
|
||||
simulatedPlayer.tick()
|
||||
simLines.add(simulatedPlayer.pos)
|
||||
}
|
||||
PlayerSimulationCache.getSimulationForLocalPlayer().simulateUntil(this.ticksToPredict)
|
||||
}
|
||||
|
||||
val renderHandler = handler<WorldRenderEvent> { event ->
|
||||
val cachedPositions = PlayerSimulationCache
|
||||
.getSimulationForLocalPlayer()
|
||||
.getSnapshotsBetween(0 until this.ticksToPredict)
|
||||
|
||||
renderEnvironmentForWorld(event.matrixStack) {
|
||||
withColor(Color4b.BLUE) {
|
||||
drawLineStrip(positions = simLines.map { relativeToCamera(it).toVec3() }.toTypedArray())
|
||||
drawLineStrip(positions = cachedPositions.map { relativeToCamera(it.pos).toVec3() })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,10 +129,6 @@ object ModuleDebug : Module("Debug", Category.RENDER) {
|
||||
|
||||
val pointTo = face.nearestPointTo(line)
|
||||
|
||||
if (pointTo == null) {
|
||||
return@repeatable
|
||||
}
|
||||
|
||||
ModuleDebug.debugGeometry(
|
||||
ModuleScaffold,
|
||||
"targetPoint",
|
||||
@@ -212,7 +201,7 @@ object ModuleDebug : Module("Debug", Category.RENDER) {
|
||||
textList.forEachIndexed { index, text ->
|
||||
context.drawCenteredTextWithShadow(
|
||||
mc.textRenderer, text, width / 2, 40 +
|
||||
(mc.textRenderer.fontHeight * index), Color4b.WHITE.toRGBA()
|
||||
(mc.textRenderer.fontHeight * index), Color4b.WHITE.toRGBA()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,151 @@
|
||||
package net.ccbluex.liquidbounce.utils.entity
|
||||
|
||||
import net.ccbluex.liquidbounce.event.Listenable
|
||||
import net.ccbluex.liquidbounce.event.events.GameTickEvent
|
||||
import net.ccbluex.liquidbounce.event.events.MovementInputEvent
|
||||
import net.ccbluex.liquidbounce.event.handler
|
||||
import net.ccbluex.liquidbounce.utils.client.player
|
||||
import net.ccbluex.liquidbounce.utils.movement.DirectionalInput
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
object PlayerSimulationCache: Listenable {
|
||||
private val otherPlayerCache = ConcurrentHashMap<PlayerEntity, SimulatedPlayerCache>()
|
||||
private var localPlayerCache: SimulatedPlayerCache? = null
|
||||
|
||||
private val gameTickHandler = handler<GameTickEvent> {
|
||||
this.otherPlayerCache.clear()
|
||||
}
|
||||
|
||||
private val movementHandler = handler<MovementInputEvent> {
|
||||
val simulatedPlayer = SimulatedPlayer.fromClientPlayer(
|
||||
SimulatedPlayer.SimulatedPlayerInput.fromClientPlayer(it.directionalInput)
|
||||
)
|
||||
|
||||
localPlayerCache = SimulatedPlayerCache(simulatedPlayer)
|
||||
}
|
||||
|
||||
fun getSimulationForOtherPlayers(player: PlayerEntity): SimulatedPlayerCache {
|
||||
return otherPlayerCache.computeIfAbsent(player) {
|
||||
val simulatedPlayer = SimulatedPlayer.fromOtherPlayer(
|
||||
player,
|
||||
SimulatedPlayer.SimulatedPlayerInput.guessInput(player)
|
||||
)
|
||||
|
||||
SimulatedPlayerCache(simulatedPlayer)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSimulationForLocalPlayer(): SimulatedPlayerCache {
|
||||
val cached = localPlayerCache
|
||||
|
||||
if (cached != null) {
|
||||
return cached
|
||||
}
|
||||
|
||||
val simulatedPlayer = SimulatedPlayer.fromClientPlayer(
|
||||
SimulatedPlayer.SimulatedPlayerInput.fromClientPlayer(DirectionalInput(player.input))
|
||||
)
|
||||
|
||||
val simulatedPlayerCache = SimulatedPlayerCache(simulatedPlayer)
|
||||
|
||||
localPlayerCache = simulatedPlayerCache
|
||||
|
||||
return simulatedPlayerCache
|
||||
}
|
||||
}
|
||||
|
||||
class SimulatedPlayerCache(private val simulatedPlayer: SimulatedPlayer) {
|
||||
private var currentSimulationStep = 0
|
||||
private val simulationSteps = ArrayList<SimulatedPlayerSnapshot>().apply {
|
||||
add(SimulatedPlayerSnapshot(simulatedPlayer))
|
||||
}
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
|
||||
fun simulateUntil(ticks: Int) {
|
||||
check(ticks > 0) { "ticks must be greater than 0" }
|
||||
|
||||
if (currentSimulationStep >= ticks) {
|
||||
return
|
||||
}
|
||||
|
||||
lock.write {
|
||||
while (currentSimulationStep < ticks) {
|
||||
simulatedPlayer.tick()
|
||||
simulationSteps.add(SimulatedPlayerSnapshot(simulatedPlayer))
|
||||
|
||||
this.currentSimulationStep++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSnapshotAt(ticks: Int): SimulatedPlayerSnapshot {
|
||||
simulateUntil(ticks)
|
||||
|
||||
lock.read {
|
||||
return simulationSteps[ticks]
|
||||
}
|
||||
}
|
||||
|
||||
fun simulate() = sequence<SimulatedPlayerSnapshot> {
|
||||
var idx = 0
|
||||
|
||||
while (true) {
|
||||
yield(getSnapshotAt(idx))
|
||||
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
fun getSnapshotsBetween(tickRange: IntRange): List<SimulatedPlayerSnapshot> {
|
||||
check(tickRange.endInclusive < 60 * 20) { "tried to simulate a player for more than a minute!" }
|
||||
|
||||
simulateUntil(tickRange.endInclusive + 1)
|
||||
|
||||
return lock.read {
|
||||
ArrayList(simulationSteps.subList(tickRange.start, tickRange.endInclusive + 1))
|
||||
}
|
||||
}
|
||||
|
||||
fun simulateBetween(tickRange: IntRange): Sequence<SimulatedPlayerSnapshot> {
|
||||
check(tickRange.endInclusive < 60 * 20) { "tried to simulate a player for more than a minute!" }
|
||||
|
||||
simulateUntil(tickRange.endInclusive + 1)
|
||||
|
||||
return sequence<SimulatedPlayerSnapshot> {
|
||||
var idx = 0
|
||||
|
||||
while (true) {
|
||||
yield(getSnapshotAt(idx))
|
||||
|
||||
idx++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SimulatedPlayerSnapshot(s: SimulatedPlayer) {
|
||||
val pos = s.pos
|
||||
val fallDistance = s.fallDistance
|
||||
val velocity = s.velocity
|
||||
val onGround = s.onGround
|
||||
}
|
||||
|
||||
/**
|
||||
* Yes, this name sucks as [SimulatedPlayerCache] already exists, but I don't know a better name :/
|
||||
*/
|
||||
class CachedPlayerSimulation(val simulatedPlayer: SimulatedPlayerCache): PlayerSimulation {
|
||||
override val pos: Vec3d
|
||||
get() = this.simulatedPlayer.getSnapshotAt(this.ticks).pos
|
||||
|
||||
private var ticks = 0
|
||||
|
||||
override fun tick() {
|
||||
this.ticks++
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user