Skip to content

Commit 9434c39

Browse files
committed
Merge branch 'feature/movement' into feature/friends
2 parents 4f465d5 + 7a48550 commit 9434c39

File tree

9 files changed

+215
-20
lines changed

9 files changed

+215
-20
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.lambda.mixin.items;
2+
3+
import com.lambda.module.modules.movement.TridentBoost;
4+
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
5+
import net.minecraft.item.TridentItem;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.ModifyArg;
9+
10+
@Mixin(TridentItem.class)
11+
public class TridentMixin {
12+
// Forge doesn't support the @ModityArgs annotation, so we have to chain multiple @ModifyArg
13+
@ModifyArg(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;addVelocity(DDD)V"), index = 0)
14+
private double modifyVelocity0(double velocity) { return TridentBoost.INSTANCE.isEnabled() ? velocity * TridentBoost.INSTANCE.getTridentSpeed() : velocity; }
15+
16+
@ModifyArg(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;addVelocity(DDD)V"), index = 1)
17+
private double modifyVelocity1(double velocity) { return TridentBoost.INSTANCE.isEnabled() ? velocity * TridentBoost.INSTANCE.getTridentSpeed() : velocity; }
18+
19+
@ModifyArg(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;addVelocity(DDD)V"), index = 2)
20+
private double modifyVelocity2(double velocity) { return TridentBoost.INSTANCE.isEnabled() ? velocity * TridentBoost.INSTANCE.getTridentSpeed() : velocity; }
21+
22+
@ModifyExpressionValue(method = {"onStoppedUsing", "use"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;isTouchingWaterOrRain()Z"))
23+
private boolean modifyIsTouchingWaterOrRain(boolean original) { return TridentBoost.INSTANCE.isEnabled() ? TridentBoost.INSTANCE.getForceUse() : original; }
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.lambda.mixin.world;
2+
3+
import com.lambda.module.modules.movement.TridentFlight;
4+
import net.minecraft.util.math.BlockPos;
5+
import net.minecraft.world.World;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
10+
11+
@Mixin(World.class)
12+
public class WorldMixin {
13+
@Inject(method = "hasRain", at = @At("HEAD"), cancellable = true)
14+
private void hasRain(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
15+
if (TridentFlight.INSTANCE.isEnabled()) cir.setReturnValue(TridentFlight.INSTANCE.getRain());
16+
}
17+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.lambda.module.modules.movement
2+
3+
import com.lambda.event.events.PacketEvent
4+
import com.lambda.event.events.TickEvent
5+
import com.lambda.event.listener.SafeListener.Companion.listener
6+
import com.lambda.module.Module
7+
import com.lambda.module.tag.ModuleTag
8+
import com.lambda.util.world.EntityUtils.getEntities
9+
import net.minecraft.entity.passive.AbstractHorseEntity
10+
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket
11+
12+
object HorseUtils : Module(
13+
name = "HorseUtils",
14+
description = "Various utilities for horses.",
15+
defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS)
16+
) {
17+
private val page by setting("Page", Page.General)
18+
19+
/* General */
20+
private val forceMount by setting("Force Mount", true, description = "Attempts to force mount chested entities.", visibility = { page == Page.General })
21+
private val tameHorses by setting("Tame Horses", true, description = "Automatically tames horses (client-side only).", visibility = { page == Page.General })
22+
23+
/* Rendering */
24+
private val showInfo by setting("Show Info", true, description = "Renders information about entities.", visibility = { page == Page.Rendering })
25+
26+
private val theHonses = mutableListOf<AbstractHorseEntity>() // Petah, the honse is here
27+
private val tame: (AbstractHorseEntity) -> Unit = { horse -> if (tameHorses) horse.setHorseFlag(4, true) }
28+
29+
private enum class Page {
30+
General, Rendering
31+
}
32+
33+
init {
34+
listener<TickEvent.Pre> {
35+
getEntities(theHonses, iterator = tame)
36+
}
37+
38+
listener<PacketEvent.Send.Pre> { event ->
39+
if (!forceMount) return@listener
40+
if (event.packet !is PlayerInteractEntityC2SPacket) return@listener
41+
if (event.packet.type !is PlayerInteractEntityC2SPacket.InteractAtHandler) return@listener
42+
43+
val entity = world.getEntityById(event.packet.entityId) ?: return@listener
44+
if (entity !is AbstractHorseEntity) return@listener
45+
46+
event.cancel()
47+
}
48+
}
49+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.lambda.module.modules.movement
2+
3+
import com.lambda.module.Module
4+
import com.lambda.module.tag.ModuleTag
5+
6+
object TridentBoost : Module(
7+
name = "TridentBoost",
8+
description = "Boosts you with tridents",
9+
defaultTags = setOf(ModuleTag.MOVEMENT)
10+
) {
11+
val tridentSpeed by setting("Speed Factor", 2.0, 0.1..3.0, 0.1, description = "Speed factor of the trident boost")
12+
val forceUse by setting("Force Use", true, description = "Try to use the trident outside of water or rain")
13+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.lambda.module.modules.movement
2+
3+
import com.lambda.event.events.TickEvent
4+
import com.lambda.event.listener.SafeListener.Companion.listener
5+
import com.lambda.module.Module
6+
import com.lambda.module.tag.ModuleTag
7+
import net.minecraft.enchantment.EnchantmentHelper
8+
import net.minecraft.entity.MovementType
9+
import net.minecraft.item.TridentItem
10+
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket
11+
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket
12+
import net.minecraft.util.math.BlockPos
13+
import net.minecraft.util.math.Direction
14+
import net.minecraft.util.math.Vec3d
15+
import kotlin.math.cos
16+
import kotlin.math.sin
17+
import kotlin.math.sqrt
18+
19+
20+
object TridentFlight : Module(
21+
name = "TridentFlight",
22+
description = "Allows you to fly with tridents",
23+
defaultTags = setOf(ModuleTag.MOVEMENT, ModuleTag.BYPASS, ModuleTag.GRIM),
24+
) {
25+
private val bounce by setting("Bounce", true, description = "Automatically use the trident")
26+
private val delay by setting("Delay", 0, 0..20, 1, description = "Delay in ticks before releasing the trident", visibility = { bounce })
27+
private val tridentSpeed by setting("Speed Factor", 1.0, 0.1..5.0, 0.1, description = "Speed factor of the trident flight")
28+
29+
val rain by setting("Rain", true, description = "Set rain client-side to allow flight")
30+
31+
private var ticks = 0
32+
33+
init {
34+
listener<TickEvent.Pre> {
35+
if (ticks >= delay &&
36+
player.activeItem.item is TridentItem)
37+
{
38+
val tridentSlot = player.inventory.selectedSlot
39+
val spoofSlot = player.inventory.swappableHotbarSlot
40+
41+
connection.sendPacket(UpdateSelectedSlotC2SPacket(tridentSlot))
42+
connection.sendPacket(PlayerActionC2SPacket(PlayerActionC2SPacket.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, Direction.DOWN))
43+
44+
val level = EnchantmentHelper.getRiptide(player.activeItem)
45+
val yaw = player.yaw * (Math.PI / 180)
46+
val pitch = player.pitch * (Math.PI / 180)
47+
48+
val x = -sin(yaw) * cos(pitch)
49+
val y = -sin(pitch)
50+
val z = cos(yaw) * cos(pitch)
51+
52+
val dot = sqrt(x * x + y * y + z * z)
53+
val multiplier = (3 * ((1.0 + level) / 4.0)) / dot
54+
55+
player.addVelocity(
56+
x * multiplier * tridentSpeed,
57+
y * multiplier * tridentSpeed,
58+
z * multiplier * tridentSpeed
59+
)
60+
61+
if (player.isOnGround)
62+
player.move(MovementType.SELF, Vec3d(0.0, 1.19999, 0.0))
63+
64+
connection.sendPacket(UpdateSelectedSlotC2SPacket(spoofSlot))
65+
66+
ticks = 0
67+
}
68+
69+
ticks++
70+
}
71+
}
72+
}

common/src/main/kotlin/com/lambda/util/collections/Extensions.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ package com.lambda.util.collections
1414
* @param predicate The predicate function that determines whether an element should be included based on its type and other criteria.
1515
*/
1616
inline fun <reified R, C : MutableCollection<in R>> Iterable<*>.filterIsInstanceTo(
17-
destination: C,
17+
destination: C? = null,
1818
predicate: (R) -> Boolean
1919
) {
20+
if (destination == null) return
2021
for (element in this) if (element is R && predicate(element)) destination.add(element)
2122
}

common/src/main/kotlin/com/lambda/util/world/EntityUtils.kt

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import net.minecraft.util.math.ChunkSectionPos
77
import net.minecraft.util.math.Vec3d
88
import kotlin.math.ceil
99

10+
val nullptr = null
1011

1112
object EntityUtils {
1213
/**
@@ -22,20 +23,22 @@ object EntityUtils {
2223
range: Double = 6.0,
2324
noinline predicate: (T) -> Boolean = { true },
2425
): T? {
26+
var closest: T? = null
27+
var closestDistance = Double.MAX_VALUE
28+
29+
val iterator: (T) -> Unit = {
30+
val distance = it.squaredDistanceTo(pos)
31+
if (distance < closestDistance) {
32+
closest = it
33+
closestDistance = distance
34+
}
35+
}
36+
2537
// Speculative execution trolling
26-
val entities = ArrayList<T>()
27-
if (range > 64) getEntities(entities, predicate)
28-
// I have an idea for optimization.
29-
//
30-
// Since the search operates linearly, eventually it will reach the midpoint.
31-
// Calculate the distance between the first and last entities.
32-
// Obtain the delta value.
33-
// Theoretically, the closest entity should be within a cubic space of delta^3 blocks.
34-
// If there are no entities within this delta box, examine the outer box. (Although this is unlikely given the fact that the closest entity is within the delta box.)
35-
// The performance improvement is relative to the initial state.
36-
else getFastEntities(pos, range, entities, predicate)
38+
if (range > 64) getEntities(nullptr, predicate, iterator)
39+
else getFastEntities(pos, range, nullptr, predicate, iterator)
3740

38-
return entities.minByOrNull { it.squaredDistanceTo(pos) }
41+
return closest
3942
}
4043

4144
/**
@@ -62,15 +65,18 @@ object EntityUtils {
6265
*
6366
* @param pos The position to search from.
6467
* @param distance The maximum distance to search for entities.
68+
* @param pointer The mutable list to store the entities in.
6569
* @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties.
70+
* @param iterator Optional iterator to perform operations on each entity.
6671
* @return A list of entities of type [T] within the specified distance from the position, excluding the player.
6772
*
6873
*/
6974
inline fun <reified T : Entity> SafeContext.getFastEntities(
7075
pos: Vec3d,
7176
distance: Double,
72-
pointer: MutableList<T>,
77+
pointer: MutableList<T>? = nullptr,
7378
noinline predicate: (T) -> Boolean = { true },
79+
noinline iterator: (T) -> Unit = { },
7480
) {
7581
val chunks = ceil(distance / 16).toInt()
7682
val sectionX = pos.x.toInt() shr 4
@@ -85,6 +91,7 @@ object EntityUtils {
8591
for (z in sectionZ - chunks..sectionZ + chunks) {
8692
val section = world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue
8793
section.collection.filterIsInstanceTo(pointer) { entity ->
94+
iterator(entity)
8895
entity != player && entity.squaredDistanceTo(pos) <= distance * distance && predicate(entity)
8996
}
9097
}
@@ -98,14 +105,17 @@ object EntityUtils {
98105
* This function retrieves entities of type [T] within a specified distance from a given position. Unlike
99106
* [getFastEntities], it traverses all entities in the world to find matches, while also excluding the player entity.
100107
*
101-
* @param predicate Optional predicate to filter entities.
102-
* @return A list of entities of type [T] within the specified distance from the position without the player.
108+
* @param pointer The mutable list to store the entities in.
109+
* @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties.
110+
* @param iterator Optional iterator to perform operations on each entity.
103111
*/
104112
inline fun <reified T : Entity> SafeContext.getEntities(
105-
pointer: MutableList<T>,
106-
noinline predicate: (T) -> Boolean = { true }
113+
pointer: MutableList<T>? = nullptr,
114+
noinline predicate: (T) -> Boolean = { true },
115+
noinline iterator: (T) -> Unit = { },
107116
) {
108117
world.entities.filterIsInstanceTo(pointer) { entity ->
118+
iterator(entity)
109119
entity != player && predicate(entity)
110120
}
111121
}

common/src/main/resources/lambda.accesswidener

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ accessible field net/minecraft/client/world/ClientWorld entityManager Lnet/minec
1111
# Entity
1212
accessible field net/minecraft/entity/projectile/FireworkRocketEntity shooter Lnet/minecraft/entity/LivingEntity;
1313
accessible method net/minecraft/entity/Entity movementInputToVelocity (Lnet/minecraft/util/math/Vec3d;FF)Lnet/minecraft/util/math/Vec3d;
14+
accessible method net/minecraft/entity/passive/AbstractHorseEntity setHorseFlag (IZ)V
1415

1516
# Camera
1617
accessible method net/minecraft/client/render/Camera setPos (DDD)V
@@ -34,6 +35,12 @@ accessible field net/minecraft/text/Style insertion Ljava/lang/String;
3435
accessible field net/minecraft/text/Style font Lnet/minecraft/util/Identifier;
3536
accessible method net/minecraft/text/Style <init> (Lnet/minecraft/text/TextColor;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lnet/minecraft/text/ClickEvent;Lnet/minecraft/text/HoverEvent;Ljava/lang/String;Lnet/minecraft/util/Identifier;)V
3637

38+
# Packet
39+
accessible field net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket entityId I
40+
accessible field net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket type Lnet/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler;
41+
accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler
42+
accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractAtHandler
43+
3744
# Other
3845
accessible field net/minecraft/client/world/ClientEntityManager cache Lnet/minecraft/world/entity/SectionedEntityCache;
3946
accessible field net/minecraft/world/entity/EntityTrackingSection collection Lnet/minecraft/util/collection/TypeFilterableList;

common/src/main/resources/lambda.mixins.common.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
"render.GameRendererMixin",
2323
"render.GlStateManagerMixin",
2424
"render.InGameHudMixin",
25-
"render.VertexBufferMixin",
2625
"render.LightmapTextureManagerMixin",
2726
"render.LivingEntityRendererMixin",
2827
"render.RenderTickCounterMixin",
29-
"render.WorldRendererMixin"
28+
"render.VertexBufferMixin",
29+
"render.WorldRendererMixin",
30+
"world.WorldMixin",
31+
"items.TridentMixin"
3032
],
3133
"injectors": {
3234
"defaultRequire": 1

0 commit comments

Comments
 (0)