Skip to content

Commit fc1833d

Browse files
committed
Merge combat world utils
1 parent c3d5b63 commit fc1833d

File tree

6 files changed

+224
-129
lines changed

6 files changed

+224
-129
lines changed

common/src/main/kotlin/com/lambda/module/modules/EntityTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.lambda.module.modules
33
import com.lambda.event.events.TickEvent
44
import com.lambda.event.listener.SafeListener.Companion.listener
55
import com.lambda.module.Module
6-
import com.lambda.util.world.EntityUtils.getClosestEntity
6+
import com.lambda.util.world.WorldUtils.getClosestEntity
77
import net.minecraft.entity.Entity
88

99
object EntityTest : Module(

common/src/main/kotlin/com/lambda/module/modules/combat/CrystalAura.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@ package com.lambda.module.modules.combat
22

33
import com.lambda.config.InteractionSettings
44
import com.lambda.config.RotationSettings
5-
import com.lambda.event.events.RotationEvent
65
import com.lambda.event.events.TickEvent
76
import com.lambda.event.listener.SafeListener.Companion.concurrentListener
87
import com.lambda.event.listener.SafeListener.Companion.listener
98
import com.lambda.module.Module
109
import com.lambda.module.tag.ModuleTag
11-
import com.lambda.util.Communication.info
12-
import com.lambda.util.combat.Explosion.velocity
13-
import com.lambda.util.world.EntityUtils.getClosestEntity
14-
import com.lambda.util.world.EntityUtils.getFastEntities
15-
import net.minecraft.entity.Entity
10+
import com.lambda.util.world.WorldUtils.getClosestEntity
1611
import net.minecraft.entity.LivingEntity
1712
import net.minecraft.util.Hand
18-
import net.minecraft.world.explosion.Explosion
1913

2014
object CrystalAura : Module(
2115
name = "CrystalAura",

common/src/main/kotlin/com/lambda/module/modules/movement/HorseUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.lambda.event.events.TickEvent
55
import com.lambda.event.listener.SafeListener.Companion.listener
66
import com.lambda.module.Module
77
import com.lambda.module.tag.ModuleTag
8-
import com.lambda.util.world.EntityUtils.getEntities
8+
import com.lambda.util.world.WorldUtils.getEntities
99
import net.minecraft.entity.passive.AbstractHorseEntity
1010
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket
1111

common/src/main/kotlin/com/lambda/util/combat/Explosion.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.lambda.util.combat
33
import com.lambda.context.SafeContext
44
import com.lambda.util.math.VecUtils.minus
55
import com.lambda.util.math.VecUtils.times
6-
import com.lambda.util.world.EntityUtils.getFastEntities
6+
import com.lambda.util.world.WorldUtils.getFastEntities
77
import net.minecraft.enchantment.ProtectionEnchantment
88
import net.minecraft.entity.LivingEntity
99
import net.minecraft.util.math.BlockPos

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

Lines changed: 0 additions & 119 deletions
This file was deleted.
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
package com.lambda.util.world
2+
3+
import com.lambda.context.SafeContext
4+
import com.lambda.util.collections.filterPointer
5+
import com.lambda.util.math.VecUtils.distSq
6+
import net.minecraft.block.Block
7+
import net.minecraft.entity.Entity
8+
import net.minecraft.fluid.Fluid
9+
import net.minecraft.util.math.BlockPos
10+
import net.minecraft.util.math.ChunkSectionPos
11+
import net.minecraft.util.math.Vec3d
12+
import net.minecraft.util.math.Vec3i
13+
import kotlin.math.ceil
14+
15+
/**
16+
* Utility functions for working with the Minecraft world.
17+
*
18+
* This object employs a pass-by-reference model, allowing functions to modify
19+
* data structures passed to them rather than creating new ones. This approach
20+
* offers 2 main benefits:
21+
*
22+
* - **Performance**: Pass-by-reference avoids unnecessary memory allocations
23+
* and reallocations that can occur when creating new data structures.
24+
*
25+
* - **Reduced Garbage Collection Overhead**: In languages with garbage collection
26+
* like Kotlin, creating and discarding many temporary objects can lead to increased
27+
* overhead. Pass-by-reference helps mitigate this by minimizing the creation of
28+
* temporary objects.
29+
*
30+
* When you create a new object, the JVM allocates memory for it on the heap.
31+
* When it is no longer needed, the garbage collector frees up the memory.
32+
* This process **IS** expensive, especially if you are creating and discarding many objects
33+
* in a short period of time, for example, when retrieving all the 200 pigs in your farm every game tick.
34+
*
35+
* @see <a href="https://www.ibm.com/docs/en/i/7.4?topic=calls-pass-by-reference">IBM - Pass By Reference</a>
36+
* @see <a href="https://www.cs.fsu.edu/~myers/c++/notes/references.html">Florida State University - Pass By Reference vs. Pass By Value</a>
37+
* @see <a href="https://www.ibm.com/docs/no/aix/7.2?topic=monitoring-garbage-collection-impacts-java-performance">IBM - Garbage Collection Impacts on Java Performance</a>
38+
* @see <a href="https://devdiaries.medium.com/gc-and-its-effect-on-java-performance-9cba51ffb196">Medium - GC and Its Effect on Java Performance</a>
39+
*
40+
*/
41+
object WorldUtils {
42+
/**
43+
* Gets the closest entity of type [T] within a specified range.
44+
*
45+
* @param pos The position to search from.
46+
* @param range The maximum distance to search for entities.
47+
* @param predicate Optional predicate to filter entities.
48+
* @return The first entity of type [T] that is closest to the position within the specified range.
49+
*/
50+
inline fun <reified T : Entity> SafeContext.getClosestEntity(
51+
pos: Vec3d = player.pos,
52+
range: Double = 6.0,
53+
noinline predicate: (T) -> Boolean = { true },
54+
): T? {
55+
var closest: T? = null
56+
var closestDistance = Double.MAX_VALUE
57+
58+
val comparator = { entity: T ->
59+
val distance = pos.squaredDistanceTo(entity.pos)
60+
if (distance < closestDistance) {
61+
closest = entity
62+
closestDistance = distance
63+
}
64+
}
65+
66+
// Speculative execution trolling
67+
if (range > 64) getEntities(null, comparator, predicate)
68+
else getFastEntities(pos, range, null, comparator, predicate)
69+
70+
return closest
71+
}
72+
73+
/**
74+
* Gets all entities of type [T] within a specified distance from a position.
75+
*
76+
* This function retrieves entities of type [T] within a specified distance from a given position. It efficiently
77+
* queries nearby chunks based on the distance and returns a list of matching entities, excluding the player entity.
78+
*
79+
*
80+
* Getting all Zombie entities within a certain distance:
81+
* ```
82+
* val nearbyZombies = getFastEntities<ZombieEntity>(playerPos, 20.0)
83+
* ```
84+
*
85+
* Getting all hostile entities within a certain distance:
86+
* ```
87+
* val hostileEntities = getFastEntities<HostileEntity>(playerPos, 30.0)
88+
* ```
89+
* This fetches all hostile entities (e.g., Monsters) within a 30-block radius from the player's position.
90+
*
91+
* Please note that this implementation is optimized for performance at small distances. For larger distances, it is
92+
* recommended to use the [getEntities] function instead.
93+
* With the time complexity, we can determine that after 64 blocks, the performance of this function will degrade.
94+
*
95+
* @param pos The position to search from.
96+
* @param distance The maximum distance to search for entities.
97+
* @param pointer The mutable list to store the entities in.
98+
* @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties.
99+
* @param iterator Optional iterator to perform operations on each entity.
100+
* @return A list of entities of type [T] within the specified distance from the position, excluding the player.
101+
*
102+
*/
103+
inline fun <reified T : Entity> SafeContext.getFastEntities(
104+
pos: Vec3d,
105+
distance: Double,
106+
pointer: MutableList<T>? = null,
107+
noinline iterator: (T) -> Unit = { },
108+
noinline predicate: (T) -> Boolean = { true },
109+
) {
110+
val chunks = ceil(distance / 16).toInt()
111+
val sectionX = pos.x.toInt() shr 4
112+
val sectionY = pos.y.toInt() shr 4
113+
val sectionZ = pos.z.toInt() shr 4
114+
115+
// Here we iterate over all sections within the specified distance and add all entities of type [T] to the list.
116+
// We do not have to worry about performance here, as the number of sections is very limited.
117+
// For example, if the player is on the edge of a section and the distance is 16, we only have to iterate over 9 sections.
118+
for (x in sectionX - chunks..sectionX + chunks) {
119+
for (y in sectionY - chunks..sectionY + chunks) {
120+
for (z in sectionZ - chunks..sectionZ + chunks) {
121+
val section = world.entityManager.cache.findTrackingSection(ChunkSectionPos.asLong(x, y, z)) ?: continue
122+
section.collection.filterPointer(pointer, iterator) { entity ->
123+
entity != player && entity.squaredDistanceTo(pos) <= distance * distance && predicate(entity)
124+
}
125+
}
126+
}
127+
}
128+
}
129+
130+
/**
131+
* Gets all entities of type [T] within a specified distance from a position.
132+
*
133+
* This function retrieves entities of type [T] within a specified distance from a given position. Unlike
134+
* [getFastEntities], it traverses all entities in the world to find matches, while also excluding the player entity.
135+
*
136+
* @param pointer The mutable list to store the entities in.
137+
* @param predicate Optional predicate to filter entities. It allows custom filtering based on entity properties.
138+
* @param iterator Optional iterator to perform operations on each entity.
139+
*/
140+
inline fun <reified T : Entity> SafeContext.getEntities(
141+
pointer: MutableList<T>? = null,
142+
noinline iterator: (T) -> Unit = { },
143+
noinline predicate: (T) -> Boolean = { true },
144+
) {
145+
world.entities.filterPointer(pointer, iterator) { entity ->
146+
entity != player && predicate(entity)
147+
}
148+
}
149+
150+
/**
151+
* Returns all the position within the range where the predicate is true.
152+
*
153+
* @param pos The position to search from.
154+
* @param rangeX The maximum distance to search for entities in the x-axis.
155+
* @param rangeY The maximum distance to search for entities in the y-axis.
156+
* @param rangeZ The maximum distance to search for entities in the z-axis.
157+
* @param pointer The mutable list to store the positions in.
158+
* @param predicate Optional predicate to filter the blocks.
159+
* @param iterator Optional iterator to perform operations on each block.
160+
*
161+
* @return A list of positions that match the predicate.
162+
*/
163+
fun SafeContext.searchBlock(
164+
pos: Vec3i,
165+
rangeX: Int,
166+
rangeY: Int,
167+
rangeZ: Int,
168+
pointer: MutableList<Block>? = null,
169+
iterator: (Block) -> Unit = { },
170+
predicate: (Block) -> Boolean = { true },
171+
) = searchBlock(pos, Vec3i(rangeX, rangeY, rangeZ), pointer, iterator, predicate)
172+
173+
/**
174+
* Returns all the position within the range where the predicate is true.
175+
*
176+
* @param pos The position to search from.
177+
* @param range The maximum distance to search for entities in each axis.
178+
* @param pointer The mutable list to store the positions in.
179+
* @param predicate Optional predicate to filter the blocks.
180+
* @param iterator Optional iterator to perform operations on each block.
181+
*
182+
* @return A list of positions that match the predicate.
183+
*/
184+
fun SafeContext.searchBlock(
185+
pos: Vec3i,
186+
range: Vec3i,
187+
pointer: MutableList<Block>? = null,
188+
iterator: (Block) -> Unit = { },
189+
predicate: (Block) -> Boolean = { true },
190+
) {
191+
// TODO: Implement O(1) pointer mapping
192+
BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z)
193+
.map { world.getBlockState(it).block }.filterPointer(pointer, iterator) { block ->
194+
predicate(block)
195+
}
196+
}
197+
198+
/**
199+
* Returns all the position within the range where the predicate is true.
200+
*
201+
* @param pos The position to search from.
202+
* @param range The maximum distance to search for fluids in each axis.
203+
* @param pointer The mutable list to store the positions in.
204+
* @param predicate Optional predicate to filter the fluids.
205+
* @param iterator Optional iterator to perform operations on each fluid.
206+
*/
207+
inline fun <reified T : Fluid> SafeContext.searchFluid(
208+
pos: Vec3i,
209+
range: Vec3i,
210+
pointer: MutableList<T>? = null,
211+
noinline predicate: (T) -> Boolean = { true },
212+
noinline iterator: (T) -> Unit = { },
213+
) {
214+
// TODO: Implement O(1) pointer mapping
215+
BlockPos.iterateOutwards(BlockPos(pos), range.x, range.y, range.z)
216+
.map { world.getFluidState(it).fluid }.filterPointer(pointer, iterator) { fluid ->
217+
predicate(fluid)
218+
}
219+
}
220+
}

0 commit comments

Comments
 (0)