@@ -26,9 +26,12 @@ import com.lambda.event.listener.SafeListener.Companion.listen
2626import com.lambda.interaction.managers.rotating.Rotation
2727import com.lambda.interaction.managers.rotating.RotationConfig
2828import com.lambda.interaction.managers.rotating.RotationMode
29+ import com.lambda.interaction.managers.rotating.visibilty.lookAt
2930import com.lambda.interaction.managers.rotating.visibilty.lookAtHit
3031import com.lambda.module.Module
3132import com.lambda.module.tag.ModuleTag
33+ import com.lambda.util.Describable
34+ import com.lambda.util.NamedEnum
3235import com.lambda.util.extension.rotation
3336import com.lambda.util.math.interpolate
3437import com.lambda.util.math.plus
@@ -44,6 +47,10 @@ import com.lambda.util.player.MovementUtils.roundedStrafing
4447import com.lambda.util.player.MovementUtils.verticalMovement
4548import com.lambda.util.world.raycast.RayCastUtils.orMiss
4649import net.minecraft.client.option.Perspective
50+ import net.minecraft.util.hit.BlockHitResult
51+ import net.minecraft.util.hit.HitResult
52+ import net.minecraft.util.math.BlockPos
53+ import net.minecraft.util.math.Direction
4754import net.minecraft.util.math.Vec3d
4855
4956object Freecam : Module(
@@ -52,14 +59,19 @@ object Freecam : Module(
5259 tag = ModuleTag .PLAYER ,
5360 autoDisable = true ,
5461) {
55- private val speed by setting(" Speed" , 0.5 , 0.1 .. 1.0 , 0.1 )
62+ private val speed by setting(" Speed" , 0.5 , 0.1 .. 1.0 , 0.1 , " Freecam movement speed " , unit = " m/s " )
5663 private val sprint by setting(" Sprint Multiplier" , 3.0 , 0.1 .. 10.0 , 0.1 , description = " Set below 1.0 to fly slower on sprint." )
5764 private val reach by setting(" Reach" , 10.0 , 1.0 .. 100.0 , 1.0 , " Freecam reach distance" )
58- private val rotateToTarget by setting(" Rotate to target" , false )
65+ private val rotateMode by setting(" Rotate Mode" , FreecamRotationMode .None , " Rotation mode" )
66+ .onValueChange { _, it -> if (it == FreecamRotationMode .LookAtTarget ) mc.crosshairTarget = BlockHitResult .createMissed(Vec3d .ZERO , Direction .UP , BlockPos .ORIGIN ) }
67+ private val relative by setting(" Relative" , false , " Moves freecam relative to player position" )
68+ .onValueChange { _, it -> if (it) lastPlayerPosition = player.pos }
69+ private val keepYLevel by setting(" Keep Y Level" , false , " Don't change the camera y-level on player movement" ) { relative }
5970
6071 override val rotationConfig = RotationConfig .Instant (RotationMode .Lock )
6172
6273 private var lastPerspective = Perspective .FIRST_PERSON
74+ private var lastPlayerPosition: Vec3d = Vec3d .ZERO
6375 private var prevPosition: Vec3d = Vec3d .ZERO
6476 private var position: Vec3d = Vec3d .ZERO
6577 private val lerpPos: Vec3d
@@ -90,17 +102,25 @@ object Freecam : Module(
90102 position = player.eyePos
91103 rotation = player.rotation
92104 velocity = Vec3d .ZERO
105+ lastPlayerPosition = player.pos
93106 }
94107
95108 onDisable {
96109 mc.options.perspective = lastPerspective
97110 }
98111
99112 listen<UpdateManagerEvent .Rotation > {
100- if (! rotateToTarget) return @listen
101-
102- mc.crosshairTarget?.let {
103- lookAtHit(it)?.requestBy(this @Freecam)
113+ when (rotateMode) {
114+ FreecamRotationMode .None -> return @listen
115+ FreecamRotationMode .KeepRotation -> lookAt(rotation).requestBy(this @Freecam)
116+ FreecamRotationMode .LookAtTarget ->
117+ mc.crosshairTarget?.let {
118+ when (it) {
119+ is BlockHitResult -> lookAt(it.pos).requestBy(this @Freecam)
120+ else -> lookAtHit(it)?.requestBy(this @Freecam)
121+
122+ }
123+ }
104124 }
105125 }
106126
@@ -135,14 +155,26 @@ object Freecam : Module(
135155 // Update position
136156 prevPosition = position
137157 position + = velocity
138- }
139158
140- listen<RenderEvent .UpdateTarget > {
141- it.cancel()
159+ if (relative) {
160+ val delta = player.pos.subtract(lastPlayerPosition)
161+ position + = if (keepYLevel) Vec3d (delta.x, 0.0 , delta.z) else delta
162+ lastPlayerPosition = player.pos
163+ }
164+ }
142165
166+ listen<RenderEvent .UpdateTarget >(priority = 1 ) { event -> // Higher priority then RotationManager to run before RotationManager modifies mc.crosshairTarget
143167 mc.crosshairTarget = rotation
144168 .rayCast(reach, lerpPos)
145169 .orMiss // Can't be null (otherwise mc will spam "Null returned as 'hitResult', this shouldn't happen!")
170+
171+ mc.crosshairTarget?.let { if (it.type != HitResult .Type .MISS ) event.cancel() }
146172 }
147173 }
174+
175+ enum class FreecamRotationMode (override val displayName : String , override val description : String ) : NamedEnum, Describable {
176+ None (" None" , " No rotation changes" ),
177+ LookAtTarget (" Look At Target" , " Look at the block or entity under your crosshair" ),
178+ KeepRotation (" Keep Rotation" , " Look in the same direction as the camera" );
179+ }
148180}
0 commit comments