hibiscus/src/main/kotlin/codes/som/hibiscus/features/movement/Flight.kt

150 lines
5.1 KiB
Kotlin

package codes.som.hibiscus.features.movement
import codes.som.hibiscus.api.event.EventPhase
import codes.som.hibiscus.api.feature.Feature
import codes.som.hibiscus.api.feature.FeatureCategory
import codes.som.hibiscus.events.*
import codes.som.hibiscus.mc
import codes.som.hibiscus.mixins.MixinExtUpdatePlayerAbilitiesC2SPacket
import codes.som.hibiscus.player
import codes.som.hibiscus.subsystems.tps.TPSDetectionSubsystem
import codes.som.hibiscus.util.ext.requireExtension
import codes.som.hibiscus.util.math.calcMoveVec
import codes.som.hibiscus.util.math.getMoveInputVecFromPlayerInput
import codes.som.hibiscus.world
import net.minecraft.entity.MovementType
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
import net.minecraft.network.packet.c2s.play.UpdatePlayerAbilitiesC2SPacket
import net.minecraft.util.math.Vec3d
import net.minecraft.util.shape.VoxelShape
class Flight : Feature("Flight", FeatureCategory.MOVEMENT) {
private var flyKickCounter = 0
private var lockY = 0.0
private val spoofAbilityPackets by values.bool("Spoof Outgoing Ability Packets", true)
private val vanillaKickBypass by values.bool("Vanilla Kick Bypass", true)
private val mode by values.enum("Mode", FlightMode.HARD)
private val speed by values.float("Speed", 1.0f, 0.01f, 50.0f)
init {
on(cond = { mode == FlightMode.VANILLA }) { _: PlayerTickEvent ->
player.abilities.flying = true
player.abilities.flySpeed = speed * 0.05f
}
on(cond = { mode == FlightMode.HARD }) { event: MovePlayerEvent ->
if (event.movementType != MovementType.SELF)
return@on
val movement =
calcMoveVec(getMoveInputVecFromPlayerInput(player.input), player.yaw)
.multiply(if (player.isSprinting) 1.5 else 0.75)
.multiply(1.0, 0.75, 1.0)
.multiply(speed.toDouble())
// TODO: Some form of acceleration
event.x = movement.x
event.y = movement.y
event.z = movement.z
player.velocity = movement.multiply(0.25, 0.25, 0.25)
}
on(cond = { mode != FlightMode.VANILLA }) { _: PlayerInputTickEvent ->
// player.input.sneaking = false
}
var lastMoveTime: Long = -1
on(cond = { mode == FlightMode.MAXIMUM }, phase = EventPhase.AFTER) { event: MovePlayerEvent ->
if (event.movementType != MovementType.SELF)
return@on
var tpsMultiplier = TPSDetectionSubsystem.average().coerceAtMost(1.0)
if (tpsMultiplier < 1) {
tpsMultiplier = 1 - (1 - tpsMultiplier) * 4.0
}
val currTime = System.currentTimeMillis()
val movement =
if (lastMoveTime == -1L || currTime - lastMoveTime >= (1000.0 / 21.0) * tpsMultiplier) {
calcMoveVec(getMoveInputVecFromPlayerInput(player.input), player.yaw)
.normalize()
.multiply(speed.toDouble() * (10.0 - 1 / 8))
.multiply(1.0, 0.5, 1.0)
} else {
Vec3d.ZERO
}
if (movement != Vec3d.ZERO)
lastMoveTime = currTime
event.x = movement.x
event.y = movement.y
event.z = movement.z
player.velocity = Vec3d.ZERO
}
on(cond = { spoofAbilityPackets }) { event: SendPacketEvent ->
val (packet) = event
if (packet is UpdatePlayerAbilitiesC2SPacket) {
requireExtension<MixinExtUpdatePlayerAbilitiesC2SPacket>(packet)
packet.setFlying(player.abilities.allowFlying)
}
if (packet is ClientCommandC2SPacket) {
if (packet.mode == ClientCommandC2SPacket.Mode.PRESS_SHIFT_KEY) {
event.cancel()
}
}
}
on(cond = { vanillaKickBypass }) { event: NetworkMovingEvent ->
flyKickCounter++
if (flyKickCounter >= 16) {
if (flyKickCounter == 16)
lockY = event.y - 0.0625
val playerNotColliding = world.getBlockCollisions(
null, player.boundingBox
.offset(0.0, lockY - player.y, 0.0)
.expand(0.0625)
.stretch(0.0, -0.55, 0.0)
).all(VoxelShape::isEmpty)
if (playerNotColliding)
event.y = lockY
}
if (flyKickCounter >= 24)
flyKickCounter = 0
}
}
override fun onEnable() {
if (mc.player != null)
lockY = player.y - 0.03126
}
override fun onDisable() {
player.abilities.flying = false
player.abilities.flySpeed = 0.05f
}
override fun createFeatureCommand() =
super.createFeatureCommand().apply {
alias("fly")
}
enum class FlightMode {
VANILLA, HARD, MAXIMUM;
override fun toString(): String {
return name[0] + name.substring(1).lowercase()
}
}
}