Skip to content

Refactor Jesus #402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/main/java/com/lambda/mixin/MixinStateImplementation.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.lambda.mixin;

import com.lambda.client.event.LambdaEventBus;
import com.lambda.client.event.events.AddCollisionBoxToListEvent;
import com.lambda.client.module.modules.movement.Jesus;
import com.lambda.client.module.modules.render.Xray;
import net.minecraft.block.Block;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
Expand All @@ -26,7 +29,10 @@ public class MixinStateImplementation {

@Inject(method = "addCollisionBoxToList", at = @At("HEAD"))
public void addCollisionBoxToList(World worldIn, BlockPos pos, AxisAlignedBB entityBox, List<AxisAlignedBB> collidingBoxes, Entity entityIn, boolean isActualState, CallbackInfo ci) {
Jesus.handleAddCollisionBoxToList(pos, block, entityIn, collidingBoxes);

if (entityIn instanceof EntityPlayerSP)
LambdaEventBus.INSTANCE.post(new AddCollisionBoxToListEvent(collidingBoxes));

}

@Inject(method = "shouldSideBeRendered", at = @At("HEAD"), cancellable = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.lambda.client.event.events

import com.lambda.client.event.Event
import net.minecraft.util.math.AxisAlignedBB

/**
* @author Doogie13
* @since 06/10/2022
*/
class AddCollisionBoxToListEvent(val collisionBoxList : MutableList<AxisAlignedBB>) : Event
217 changes: 165 additions & 52 deletions src/main/kotlin/com/lambda/client/module/modules/movement/Jesus.kt
Original file line number Diff line number Diff line change
@@ -1,98 +1,211 @@
package com.lambda.client.module.modules.movement

import com.lambda.client.commons.extension.ceilToInt
import com.lambda.client.commons.extension.floorToInt
import com.lambda.client.event.SafeClientEvent
import com.lambda.client.event.events.AddCollisionBoxToListEvent
import com.lambda.client.event.events.PacketEvent
import com.lambda.client.event.events.PlayerTravelEvent
import com.lambda.client.mixin.extension.playerMoving
import com.lambda.client.event.events.PlayerMoveEvent
import com.lambda.client.manager.managers.TimerManager.modifyTimer
import com.lambda.client.mixin.extension.playerY
import com.lambda.client.module.Category
import com.lambda.client.module.Module
import com.lambda.client.util.BaritoneUtils
import com.lambda.client.util.EntityUtils
import com.lambda.client.util.EntityUtils.flooredPosition
import com.lambda.client.util.threads.runSafe
import com.lambda.client.util.threads.safeListener
import com.lambda.mixin.accessor.player.AccessorEntityPlayerSP
import net.minecraft.block.Block
import net.minecraft.block.BlockLiquid
import net.minecraft.entity.Entity
import net.minecraft.entity.item.EntityBoat
import net.minecraft.init.Blocks
import net.minecraft.network.play.client.CPacketPlayer
import net.minecraft.network.play.server.SPacketPlayerPosLook
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockPos.PooledMutableBlockPos
import net.minecraftforge.client.event.InputUpdateEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.hypot


object Jesus : Module(
name = "Jesus",
description = "Allows you to walk on water",
category = Category.MOVEMENT
) {
private val mode by setting("Mode", Mode.SOLID)

private enum class Mode {
SOLID, DOLPHIN
private val mode by setting("Mode", Mode.STRICT)

enum class Mode {
SOLID,
STRICT,
DOLPHIN
}

private val waterWalkBox = AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.99, 1.0)
private val preventJump by setting("Prevent Jumping", false, { mode == Mode.SOLID || mode == Mode.STRICT }, description = "Prevent jumping when using Jesus")

private val bb = AxisAlignedBB(-1.0, -1.0, -1.0, 0.0, 0.0, 0.0)
private val liquids = listOf(Blocks.WATER, Blocks.FLOWING_WATER, Blocks.LAVA, Blocks.FLOWING_LAVA)

private var ticksEnabled = 0
private var fakeY = 0.0

init {
onToggle {
BaritoneUtils.settings?.assumeWalkOnWater?.value = it
onDisable {
ticksEnabled = 0
fakeY = .0
}

safeListener<PlayerTravelEvent> {
if (mc.gameSettings.keyBindSneak.isKeyDown || player.fallDistance > 3.0f || !isInWater(player)) return@safeListener
safeListener<ClientTickEvent> {
if (it.phase != TickEvent.Phase.START) return@safeListener

if (mode == Mode.DOLPHIN) {
player.motionY += 0.03999999910593033 // regular jump speed
} else {
player.motionY = 0.1
ticksEnabled++
}

player.ridingEntity?.let {
if (it !is EntityBoat) it.motionY = 0.3
}
safeListener<AddCollisionBoxToListEvent> {
if (mc.gameSettings.keyBindSneak.isKeyDown)
return@safeListener

if ((mode == Mode.SOLID || mode == Mode.STRICT)
&& world.getBlockState(BlockPos(player.positionVector.add(.0, -.1 + player.motionY, .0))).material.isLiquid
) {
it.collisionBoxList.add(bb.offset(player.posX, floor(player.posY), player.posZ))
}
}

safeListener<PacketEvent.Send> {
if (it.packet !is CPacketPlayer || !it.packet.playerMoving) return@safeListener
if (mc.gameSettings.keyBindSneak.isKeyDown || player.ticksExisted % 2 != 0) return@safeListener
safeListener<PlayerMoveEvent> { event ->
(player as AccessorEntityPlayerSP).lcSetLastReportedPosY(-99.9)

if (mc.gameSettings.keyBindSneak.isKeyDown) return@safeListener

val entity = player.ridingEntity ?: player
(player as AccessorEntityPlayerSP).lcSetLastReportedPosY(-999.0)

if (EntityUtils.isAboveLiquid(entity, true) && !isInWater(entity)) {
it.packet.playerY += 0.02
if (player.isInWater || world.getBlockState(player.flooredPosition).material.isLiquid) {
event.y = (.11.also { player.motionY = it })
}

if (player.onGround &&
!checkBlockCollisionNoLiquid(
player.entityBoundingBox.offset(.0, -.01, .0),
liquids + Blocks.AIR
)
) {
when (mode) {
Mode.DOLPHIN -> {
if (hypot(event.x, event.y) > .2873 * .9) {
event.x *= .95
event.z *= .95
}
}
Mode.STRICT -> {
val lava = !checkBlockCollisionNoLiquid(
player.entityBoundingBox.offset(.0, -.01, .0),
listOf(Blocks.AIR, Blocks.LAVA, Blocks.FLOWING_LAVA)
)
// .38 is from lava liquid speed at max speed, 1.24 is from water liquid speed at max speed
// because of the way "Lambda Client" handled its "PlayerMoveEvent" I have to use "magic numbers" to compensate
event.x *= if (lava) .57 else 1.09
event.z *= if (lava) .57 else 1.09
}

else -> {}
}
}
}
}

@JvmStatic
fun handleAddCollisionBoxToList(pos: BlockPos, block: Block, entity: Entity?, collidingBoxes: MutableList<AxisAlignedBB>) {
if (isDisabled || mode == Mode.DOLPHIN) return
if (mc.gameSettings.keyBindSneak.isKeyDown) return
if (block !is BlockLiquid) return
if (entity == null || entity is EntityBoat) return
safeListener<InputUpdateEvent> {
if (preventJump &&
fakeY != .0
) it.movementInput.jump = false
}

val player = mc.player ?: return
if (player.fallDistance > 3.0f) return
safeListener<PacketEvent.Send> { event ->
if (event.packet !is CPacketPlayer) return@safeListener

if (entity != player && entity != player.ridingEntity) return
if (isInWater(entity) || entity.posY < pos.y) return
if (!EntityUtils.isAboveLiquid(entity)) return
if (mc.gameSettings.keyBindSneak.isKeyDown) {
if (mode == Mode.STRICT) {
player.posY -= fakeY
}

collidingBoxes.add(waterWalkBox.offset(pos))
}
fakeY = 0.0
return@safeListener
}

val playerBB = player.entityBoundingBox
if (player.isInWater
|| !world.getBlockState(BlockPos(player.positionVector.add(.0, -.1 + player.motionY, .0))).material.isLiquid
|| world.getCollisionBoxes(player, playerBB.offset(0.0, -.0001, 0.0)).isEmpty()
) {
fakeY = 0.0
return@safeListener
}

val packet = event.packet

when (mode) {
Mode.STRICT -> {
if ((-.4).coerceAtLeast(fakeY).also { fakeY = it } > -.4) {
fakeY -= .08
fakeY *= .98
packet.playerY += fakeY
} else {
packet.playerY += fakeY - if (ticksEnabled % 2 == 0) .0 else -.00001
}

if (checkBlockCollisionNoLiquid(
player.entityBoundingBox.offset(.0, packet.playerY - player.posY, .0),
liquids + Blocks.AIR
)) {
packet.playerY = player.posY
}
}
Mode.SOLID -> {
fakeY = 0.0

private fun isInWater(entity: Entity): Boolean {
mc.world?.let {
val y = (entity.posY + 0.01).floorToInt()
if (ticksEnabled % 2 == 0) packet.playerY -= .001

for (x in entity.posX.floorToInt() until entity.posX.ceilToInt()) {
for (z in entity.posZ.floorToInt() until entity.posZ.ceilToInt()) {
val pos = BlockPos(x, y, z)
if (it.getBlockState(pos).block is BlockLiquid) return true
if (checkBlockCollisionNoLiquid(
player.entityBoundingBox.offset(.0, packet.playerY - player.posY, .0),
liquids + Blocks.AIR
)) {
packet.playerY = player.posY
}
}

else -> {}
}
}

return false
safeListener<PacketEvent.Receive> {
if (it.packet !is SPacketPlayerPosLook) return@safeListener

fakeY = player.posY - it.packet.y
}
}

private fun SafeClientEvent.checkBlockCollisionNoLiquid(bb: AxisAlignedBB, allowed: List<Block>): Boolean {
val minX = floor(bb.minX).toInt()
val maxX = ceil(bb.maxX).toInt()
val minY = floor(bb.minY).toInt()
val maxY = ceil(bb.maxY).toInt()
val minZ = floor(bb.minZ).toInt()
val maxZ = ceil(bb.maxZ).toInt()

val mutableBlockPos = PooledMutableBlockPos.retain()

for (x in minX until maxX) {
for (y in minY until maxY) {
for (z in minZ until maxZ) {
val blockState = world.getBlockState(mutableBlockPos.setPos(x, y, z))

if (!allowed.contains(blockState.block)) {
mutableBlockPos.release()
return true
}
}
}
}

mutableBlockPos.release()
return false
}
}