Skip to content

Commit 48e2849

Browse files
committed
fix: npc movement slaps
1 parent 1f9bc6c commit 48e2849

1 file changed

Lines changed: 24 additions & 18 deletions

File tree

src/main/kotlin/cc/modlabs/kpaper/npc/NPCImpl.kt

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,45 +1213,51 @@ class NPCImpl(
12131213
return false
12141214
}
12151215

1216-
// For feet position, use collision shape to check if there's collision at the specific Y
1217-
// NPC stands ON blocks, not IN them, so we need to check collision at the feet Y coordinate
1216+
// For feet position, check if there's collision at the feet Y
12181217
val feetBlockY = y.toInt()
12191218
val blockAtFeet = world.getBlockAt(x, feetBlockY, z)
12201219
val relativeY = y - feetBlockY // Y position relative to the block (0.0 to 1.0)
12211220

1221+
// If the block at feet level is passable (air), no collision - NPC can stand here
1222+
if (isPassable(blockAtFeet)) {
1223+
return true
1224+
}
1225+
1226+
// Block is not passable, check if NPC is standing on top of it using collision shape
12221227
try {
12231228
val collisionShape = blockAtFeet.collisionShape
12241229
if (collisionShape != null) {
1225-
// Create a small bounding box representing the NPC's feet at this Y position
1226-
// NPC feet are roughly 0.6x0.6 at the center of the block
1227-
val feetCheckBox = org.bukkit.util.BoundingBox(
1228-
0.2, relativeY - 0.1, 0.2, // min (relative to block)
1229-
0.8, relativeY + 0.1, 0.8 // max (relative to block)
1230-
)
1231-
1232-
// If the collision shape overlaps at the feet position, there's collision
1233-
// But if relativeY is at or above the top of the collision shape, it's fine (NPC stands ON it)
12341230
val boundingBoxes = collisionShape.boundingBoxes
12351231
if (boundingBoxes.isNotEmpty()) {
12361232
val maxBlockY = boundingBoxes.maxOfOrNull { it.maxY } ?: 1.0
12371233
// If feet Y is at or above the top of the collision shape, NPC can stand on it
1238-
if (relativeY >= maxBlockY - 0.1) {
1239-
return true // Standing on top of the block
1234+
if (relativeY >= maxBlockY - 0.15) {
1235+
return true // Standing on top of the block (with small tolerance)
12401236
}
1241-
// Otherwise, check if there's collision
1237+
// Check if there's collision at the feet position
1238+
val feetCheckBox = org.bukkit.util.BoundingBox(
1239+
0.2, (relativeY - 0.15).coerceAtLeast(0.0), 0.2, // min (relative to block)
1240+
0.8, (relativeY + 0.15).coerceAtMost(1.0), 0.8 // max (relative to block)
1241+
)
12421242
if (collisionShape.overlaps(feetCheckBox)) {
12431243
return false // Collision at feet
12441244
}
1245+
// No collision detected, allow it
1246+
return true
12451247
}
12461248
}
1249+
// No collision shape or empty, check if block is walkable (NPC might be standing on it)
1250+
if (isWalkable(blockAtFeet) && relativeY >= 0.3) {
1251+
return true // Standing on a walkable block
1252+
}
12471253
} catch (e: Exception) {
1248-
// Fallback: if block is passable, no collision
1249-
// But if NPC is standing ON the block (relativeY > 0.5), allow it
1250-
if (relativeY <= 0.5 && !isPassable(blockAtFeet)) {
1251-
return false
1254+
// Fallback: if relativeY is high enough (standing on top) or block is walkable, allow it
1255+
if (relativeY >= 0.3 || isWalkable(blockAtFeet)) {
1256+
return true
12521257
}
12531258
}
12541259

1260+
// Default: allow if no collision detected
12551261
return true
12561262
}
12571263

0 commit comments

Comments
 (0)