diff --git a/src/main/java/com/lambda/mixin/MixinStateImplementation.java b/src/main/java/com/lambda/mixin/MixinStateImplementation.java index 209588a58..9272b984b 100644 --- a/src/main/java/com/lambda/mixin/MixinStateImplementation.java +++ b/src/main/java/com/lambda/mixin/MixinStateImplementation.java @@ -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; @@ -26,7 +29,10 @@ public class MixinStateImplementation { @Inject(method = "addCollisionBoxToList", at = @At("HEAD")) public void addCollisionBoxToList(World worldIn, BlockPos pos, AxisAlignedBB entityBox, List 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) diff --git a/src/main/kotlin/com/lambda/client/event/events/AddCollisionBoxToListEvent.kt b/src/main/kotlin/com/lambda/client/event/events/AddCollisionBoxToListEvent.kt new file mode 100644 index 000000000..ba9f3eaa6 --- /dev/null +++ b/src/main/kotlin/com/lambda/client/event/events/AddCollisionBoxToListEvent.kt @@ -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) : Event \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/client/module/modules/movement/Jesus.kt b/src/main/kotlin/com/lambda/client/module/modules/movement/Jesus.kt index 659f3263b..fb8f2fbad 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/movement/Jesus.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/movement/Jesus.kt @@ -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 { - if (mc.gameSettings.keyBindSneak.isKeyDown || player.fallDistance > 3.0f || !isInWater(player)) return@safeListener + safeListener { + 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 { + 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 { - if (it.packet !is CPacketPlayer || !it.packet.playerMoving) return@safeListener - if (mc.gameSettings.keyBindSneak.isKeyDown || player.ticksExisted % 2 != 0) return@safeListener + safeListener { 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) { - 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 { + if (preventJump && + fakeY != .0 + ) it.movementInput.jump = false + } - val player = mc.player ?: return - if (player.fallDistance > 3.0f) return + safeListener { 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 { + if (it.packet !is SPacketPlayerPosLook) return@safeListener + + fakeY = player.posY - it.packet.y + } } + private fun SafeClientEvent.checkBlockCollisionNoLiquid(bb: AxisAlignedBB, allowed: List): 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 + } } \ No newline at end of file