Skip to content

Commit 74bf221

Browse files
committed
fix: npc teleport
1 parent d3e3ad0 commit 74bf221

File tree

1 file changed

+19
-53
lines changed

1 file changed

+19
-53
lines changed

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

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import org.bukkit.World
1212
import org.bukkit.block.Block
1313
import org.bukkit.block.data.Bisected
1414
import org.bukkit.block.data.BlockData
15-
import org.bukkit.block.data.type.Slab
1615
import org.bukkit.entity.Entity
1716
import org.bukkit.entity.LivingEntity
1817
import org.bukkit.entity.Mannequin
@@ -969,12 +968,9 @@ class NPCImpl(
969968
newPosition.y = currentLoc.y + 0.2
970969
} else if (groundY != null) {
971970
// There's ground below - check if we should be on it or falling to it
971+
// groundY is already calculated from collision shapes, so it's accurate for all block types
972972
val distanceToGround = currentLoc.y - groundY
973973

974-
// Check if the ground is a slab for smoother positioning
975-
val groundBlock = world.getBlockAt(newPosition.blockX, (groundY - 1).toInt(), newPosition.blockZ)
976-
val isGroundSlab = isSlab(groundBlock)
977-
978974
if (distanceToGround > 0.1) {
979975
// We're above ground - simulate gravity (fall down)
980976
// Gravity: 0.08 blocks per tick (1.6 blocks per second)
@@ -983,19 +979,16 @@ class NPCImpl(
983979
logDebug("[NPC] moveTowards: Falling - distanceToGround=$distanceToGround, fallDistance=$fallDistance, newY=${newPosition.y}")
984980
} else if (distanceToGround < -0.1) {
985981
// We're below ground - place on ground
986-
// For slabs, use the exact slab top Y for smoother walking
987-
if (isGroundSlab) {
988-
newPosition.y = groundY
989-
} else {
990-
newPosition.y = groundY
991-
}
992-
logDebug("[NPC] moveTowards: Below ground, placed on ground at Y=$groundY (slab=$isGroundSlab)")
982+
// groundY is already accurate from collision shapes (handles slabs, stairs, etc.)
983+
newPosition.y = groundY
984+
logDebug("[NPC] moveTowards: Below ground, placed on ground at Y=$groundY")
993985
} else {
994-
// We're on ground - stay there or adjust to slab height if needed
995-
if (isGroundSlab && Math.abs(currentLoc.y - groundY) > 0.1) {
996-
// Adjust to slab height for smoother walking
986+
// We're on ground - stay there or adjust if needed
987+
if (Math.abs(currentLoc.y - groundY) > 0.1) {
988+
// Adjust to ground height for smoother walking
989+
// This works for all block types including slabs and stairs
997990
newPosition.y = groundY
998-
logDebug("[NPC] moveTowards: Adjusted to slab height Y=$groundY")
991+
logDebug("[NPC] moveTowards: Adjusted to ground height Y=$groundY")
999992
} else {
1000993
// We're on ground - stay there
1001994
newPosition.y = currentLoc.y
@@ -1056,31 +1049,6 @@ class NPCImpl(
10561049
logDebug("[NPC] moveTowards: Teleported to ${newPosition.blockX},${newPosition.blockY},${newPosition.blockZ}, yaw=$yaw, pitch=$pitch")
10571050
}
10581051

1059-
/**
1060-
* Checks if a block is a slab (half-height block).
1061-
*/
1062-
private fun isSlab(block: Block): Boolean {
1063-
return block.blockData is Slab
1064-
}
1065-
1066-
/**
1067-
* Gets the top Y coordinate of a slab block.
1068-
* @param block The slab block
1069-
* @param blockY The Y coordinate of the block
1070-
* @return The Y coordinate where the top of the slab is (0.5 for bottom, 1.0 for top, 0.5 for double)
1071-
*/
1072-
private fun getSlabTopY(block: Block, blockY: Int): Double {
1073-
val blockData = block.blockData
1074-
if (blockData is Slab) {
1075-
return when (blockData.type) {
1076-
Slab.Type.BOTTOM -> blockY + 0.5
1077-
Slab.Type.TOP -> blockY + 1.0
1078-
Slab.Type.DOUBLE -> blockY + 1.0
1079-
}
1080-
}
1081-
return blockY + 1.0
1082-
}
1083-
10841052
/**
10851053
* Checks if a block is passable (can be walked through) using the official Paper API.
10861054
* Uses Block.isPassable() which checks if the block has no colliding parts.
@@ -1120,24 +1088,19 @@ class NPCImpl(
11201088
return false
11211089
} catch (e: Exception) {
11221090
// Fallback to material check if collision shape API is not available
1123-
return type.isSolid || isSlab(block)
1091+
return type.isSolid
11241092
}
11251093
}
11261094

11271095
/**
11281096
* Gets the top Y coordinate of a block based on its collision shape.
1129-
* Uses the collision shape's bounding box for accurate height detection.
1130-
* For slabs, this returns the actual top of the slab.
1131-
* For full blocks, returns blockY + 1.0.
1097+
* Uses the collision shape's bounding boxes for accurate height detection.
1098+
* Works for all block types including slabs, stairs, and partial blocks.
11321099
* @see org.bukkit.block.Block#getCollisionShape()
1100+
* @see org.bukkit.util.VoxelShape#getBoundingBoxes()
11331101
*/
11341102
private fun getBlockTopY(block: Block, blockY: Int): Double {
1135-
// Handle slabs specially for precise positioning
1136-
if (isSlab(block)) {
1137-
return getSlabTopY(block, blockY)
1138-
}
1139-
1140-
// For other blocks, use collision shape to determine top
1103+
// Use collision shape to determine top - works for all block types
11411104
try {
11421105
val collisionShape = block.collisionShape
11431106
if (collisionShape != null) {
@@ -1146,6 +1109,7 @@ class NPCImpl(
11461109
val boundingBoxes = collisionShape.boundingBoxes
11471110
if (boundingBoxes.isNotEmpty()) {
11481111
// Find the maximum Y from all bounding boxes
1112+
// This automatically handles slabs, stairs, and other partial blocks
11491113
val maxY = boundingBoxes.maxOfOrNull { it.maxY } ?: 1.0
11501114
return blockY + maxY
11511115
}
@@ -1171,10 +1135,12 @@ class NPCImpl(
11711135
}
11721136

11731137
/**
1174-
* Finds the ground level (top solid block or slab) at the given X, Z coordinates.
1138+
* Finds the ground level at the given X, Z coordinates using collision shapes.
11751139
* Returns null if no solid ground is found within reasonable range.
11761140
* Only returns a ground level if there's sufficient air space above for the NPC to stand.
1177-
* Uses collision shapes for accurate detection.
1141+
* Uses collision shapes and bounding boxes for accurate detection of all block types.
1142+
* @see org.bukkit.block.Block#getCollisionShape()
1143+
* @see org.bukkit.util.VoxelShape#getBoundingBoxes()
11781144
*/
11791145
private fun findGroundLevel(world: World, x: Int, z: Int, startY: Int): Double? {
11801146
// Search from startY + 2 down to startY - 10

0 commit comments

Comments
 (0)