Major performance fix

This commit is contained in:
dam 2026-06-13 04:43:29 +03:00
parent cd74bb46b1
commit 8274f43f45
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB
2 changed files with 71 additions and 26 deletions

View file

@ -282,7 +282,10 @@ object CombatMovementIntents {
reserveOccupiedTiles(reservedTiles, attacker, attacker.location)
return
}
if (canAttackFrom(attacker, target, attacker.location, targetLocation, trace)) {
if (projectedTargetLocation != targetLocation && canAttackFrom(
attacker, target, attacker.location, targetLocation, trace
)
) {
stopWalk(attacker)
face(attacker, target)
projectedLocations[attacker] = attacker.location
@ -309,8 +312,6 @@ object CombatMovementIntents {
}
}
val candidates = movementDestinationsFor(attacker, target, targetLocation, pathfinder, trace)
val standingOnCandidate = candidates.any { it.location == attacker.location }
val projectedAttackerLocation = CombatMovementPlanner.predictedMovementLocation(attacker) ?: attacker.location
if (projectedAttackerLocation != attacker.location && canAttackFrom(
attacker, target, projectedAttackerLocation, targetLocation, trace
@ -322,6 +323,9 @@ object CombatMovementIntents {
return
}
val candidates = movementDestinationsFor(attacker, target, targetLocation, pathfinder, trace)
val standingOnCandidate = candidates.any { it.location == attacker.location }
val queueStationaryContinuation =
attacker.properties.combatPulse.style == CombatStyle.MELEE && !CombatMovementPlanner.hasMovementStepThisTick(
target
@ -516,10 +520,10 @@ object CombatMovementIntents {
for (x in minX..maxX) {
for (y in minY..maxY) {
val tile = Location.create(x, y, targetLocation.z)
if (!RegionManager.isTeleportPermitted(tile)) {
if (distanceSquaredToClosestOccupiedTile(target, targetLocation, tile) > range * range) {
continue
}
if (distanceSquaredToClosestOccupiedTile(target, targetLocation, tile) <= range * range) {
if (RegionManager.isTeleportPermitted(tile)) {
tiles.add(tile)
}
}

View file

@ -119,30 +119,59 @@ class RsmodPathfinder(
z: Int,
clipMaskSupplier: ClipMaskSupplier?
): Boolean {
val flags = if (clipMaskSupplier == null) {
if (clipMaskSupplier == null) {
RegionManager.loadClippingWindow(Location.create(srcX, srcY, z), SEARCH_MAP_SIZE)
RegionManager.RSMOD_CLIPPING_FLAGS
} else {
CollisionFlagMap().also {
loadCollisionWindow(
flags = it, start = Location.create(srcX, srcY, z), supplier = clipMaskSupplier
)
return ReachStrategy.reached(
flags = RegionManager.RSMOD_CLIPPING_FLAGS,
level = z,
srcX = srcX,
srcZ = srcY,
destX = destX,
destZ = destY,
destWidth = if (destWidth == 0) 1 else destWidth,
destHeight = if (destHeight == 0) 1 else destHeight,
srcSize = moverSize,
objRot = rotation,
objShape = routeShape(type, destWidth, destHeight),
blockAccessFlags = walkingFlag
)
}
// Reach checks only read tiles within the source/destination rectangles and
// their cross-axis combinations, so loading just their padded bounding box
// into a reused map produces the same reads as a freshly allocated full map.
val flags = suppliedReachFlags.get()
val destSize = maxOf(if (destWidth == 0) 1 else destWidth, if (destHeight == 0) 1 else destHeight)
val minX = maxOf(0, minOf(srcX, destX) - 1)
val minY = maxOf(0, minOf(srcY, destY) - 1)
val maxX = maxOf(srcX + moverSize, destX + destSize) + 1
val maxY = maxOf(srcY + moverSize, destY + destSize) + 1
try {
for (x in minX..maxX) {
for (y in minY..maxY) {
flags[x, y, z] = clipMaskSupplier.getClippingFlag(z, x, y)
}
}
return ReachStrategy.reached(
flags = flags,
level = z,
srcX = srcX,
srcZ = srcY,
destX = destX,
destZ = destY,
destWidth = if (destWidth == 0) 1 else destWidth,
destHeight = if (destHeight == 0) 1 else destHeight,
srcSize = moverSize,
objRot = rotation,
objShape = routeShape(type, destWidth, destHeight),
blockAccessFlags = walkingFlag
)
} finally {
for (zoneX in (minX shr 3)..(maxX shr 3)) {
for (zoneY in (minY shr 3)..(maxY shr 3)) {
flags.deallocateIfPresent(zoneX shl 3, zoneY shl 3, z)
}
}
}
return ReachStrategy.reached(
flags = flags,
level = z,
srcX = srcX,
srcZ = srcY,
destX = destX,
destZ = destY,
destWidth = if (destWidth == 0) 1 else destWidth,
destHeight = if (destHeight == 0) 1 else destHeight,
srcSize = moverSize,
objRot = rotation,
objShape = routeShape(type, destWidth, destHeight),
blockAccessFlags = walkingFlag
)
}
@JvmStatic
@ -222,6 +251,16 @@ class RsmodPathfinder(
val source = sourceLocation.transform(sourceX, sourceY, 0)
for (targetX in 0 until targetSize) {
for (targetY in 0 until targetSize) {
if (maxRaySteps == 1) {
// A ray between distinct tiles emits a coordinate per axis
// step, so tiles further than one orthogonal step apart can
// never satisfy a single-step ray.
val manhattan =
kotlin.math.abs(source.x - (targetLocation.x + targetX)) + kotlin.math.abs(source.y - (targetLocation.y + targetY))
if (manhattan > 1) {
continue
}
}
val destination = targetLocation.transform(targetX, targetY, 0)
val rayCast = lineOfSightLoaded(source, destination, 1, 1, 1)
if (rayCast.success && rayCast.coordinates.size <= maxRaySteps) {
@ -259,6 +298,8 @@ class RsmodPathfinder(
else -> -1
}
private val suppliedReachFlags = ThreadLocal.withInitial { CollisionFlagMap() }
private val projectileLineValidator = ThreadLocal.withInitial {
LineValidator(RegionManager.RSMOD_PROJECTILE_FLAGS)
}