feat: Implement safety checks for elevator teleportation to prevent players from getting stuck in blocks.
This commit is contained in:
parent
152bb5096d
commit
d1702b5018
|
|
@ -7,6 +7,8 @@ import com.destroystokyo.paper.event.player.PlayerJumpEvent
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.util.BoundingBox
|
||||||
|
|
||||||
import com.github.kaaariyaaa.elevator.App
|
import com.github.kaaariyaaa.elevator.App
|
||||||
|
|
||||||
|
|
@ -23,19 +25,25 @@ class EventListener(private val plugin: App) : Listener {
|
||||||
val blockUnder = player.location.subtract(0.0, 1.0, 0.0).block
|
val blockUnder = player.location.subtract(0.0, 1.0, 0.0).block
|
||||||
|
|
||||||
if (blockUnder.type.isSolid && blockUnder.type in oreBlock) {
|
if (blockUnder.type.isSolid && blockUnder.type in oreBlock) {
|
||||||
var location = blockUnder.location
|
var location = blockUnder.location.clone()
|
||||||
location = location.add(0.0, 1.0, 0.0)
|
location.add(0.0, 1.0, 0.0)
|
||||||
|
|
||||||
val maxHeight = plugin.config.getInt("maxHeight", 64)
|
val maxHeight = plugin.config.getInt("maxHeight", 64)
|
||||||
var distance = 0
|
var distance = 0
|
||||||
|
|
||||||
while (!(location.block.type in oreBlock) && distance < maxHeight) {
|
while (distance < maxHeight) {
|
||||||
location = location.add(0.0, 1.0, 0.0)
|
|
||||||
distance++
|
|
||||||
}
|
|
||||||
|
|
||||||
if (location.block.type in oreBlock) {
|
if (location.block.type in oreBlock) {
|
||||||
player.teleport(location.add(0.5, 1.0, 0.5).addRotation(player.location.yaw, player.location.pitch))
|
val feet = location.clone().add(0.0, 1.0, 0.0)
|
||||||
|
if (isSafe(player, feet)) {
|
||||||
|
val dest = location.clone().add(0.5, 1.0, 0.5)
|
||||||
|
dest.yaw = player.location.yaw
|
||||||
|
dest.pitch = player.location.pitch
|
||||||
|
player.teleport(dest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
location.add(0.0, 1.0, 0.0)
|
||||||
|
distance++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,20 +56,83 @@ class EventListener(private val plugin: App) : Listener {
|
||||||
val blockUnder = player.location.subtract(0.0, 1.0, 0.0).block
|
val blockUnder = player.location.subtract(0.0, 1.0, 0.0).block
|
||||||
|
|
||||||
if (blockUnder.type in oreBlock) {
|
if (blockUnder.type in oreBlock) {
|
||||||
var location = blockUnder.location
|
var location = blockUnder.location.clone()
|
||||||
location = location.subtract(0.0, 1.0, 0.0)
|
location.subtract(0.0, 1.0, 0.0)
|
||||||
|
|
||||||
val maxHeight = plugin.config.getInt("maxHeight", 64)
|
val maxHeight = plugin.config.getInt("maxHeight", 64)
|
||||||
var distance = 0
|
var distance = 0
|
||||||
|
|
||||||
while (!(location.block.type in oreBlock) && distance < maxHeight) {
|
while (distance < maxHeight) {
|
||||||
location = location.subtract(0.0, 1.0, 0.0)
|
if (location.block.type in oreBlock) {
|
||||||
|
val feet = location.clone().add(0.0, 1.0, 0.0)
|
||||||
|
if (isSafe(player, feet)) {
|
||||||
|
val dest = location.clone().add(0.5, 1.0, 0.5)
|
||||||
|
dest.yaw = player.location.yaw
|
||||||
|
dest.pitch = player.location.pitch
|
||||||
|
player.teleport(dest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
location.subtract(0.0, 1.0, 0.0)
|
||||||
distance++
|
distance++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (location.block.type in oreBlock) {
|
private fun isSafe(player: Player, feetLocation: Location): Boolean {
|
||||||
player.teleport(location.add(0.5, 1.0, 0.5).addRotation(player.location.yaw, player.location.pitch))
|
val x = feetLocation.blockX + 0.5
|
||||||
|
val y = feetLocation.blockY.toDouble()
|
||||||
|
val z = feetLocation.blockZ + 0.5
|
||||||
|
|
||||||
|
val playerBox = player.boundingBox
|
||||||
|
val halfW = playerBox.widthX / 2.0
|
||||||
|
val halfD = playerBox.widthZ / 2.0
|
||||||
|
val h = playerBox.height
|
||||||
|
|
||||||
|
// 足元の座標からプレイヤーの高さ分のBoundingBoxを作成し、全身(上半身含む)の衝突判定を行う
|
||||||
|
val targetBox = org.bukkit.util.BoundingBox(x - halfW, y, z - halfD, x + halfW, y + h, z + halfD)
|
||||||
|
val world = feetLocation.world
|
||||||
|
|
||||||
|
val minX = kotlin.math.floor(targetBox.minX).toInt()
|
||||||
|
val maxX = kotlin.math.ceil(targetBox.maxX).toInt()
|
||||||
|
val minY = kotlin.math.floor(targetBox.minY).toInt()
|
||||||
|
val maxY = kotlin.math.ceil(targetBox.maxY).toInt()
|
||||||
|
val minZ = kotlin.math.floor(targetBox.minZ).toInt()
|
||||||
|
val maxZ = kotlin.math.ceil(targetBox.maxZ).toInt()
|
||||||
|
|
||||||
|
for (bx in minX..maxX) {
|
||||||
|
for (by in minY..maxY) {
|
||||||
|
for (bz in minZ..maxZ) {
|
||||||
|
val block = world.getBlockAt(bx, by, bz)
|
||||||
|
if (block.isEmpty) continue
|
||||||
|
|
||||||
|
val voxelShape = block.collisionShape
|
||||||
|
for (box in voxelShape.boundingBoxes as Collection<BoundingBox>) {
|
||||||
|
val absBox = box.clone().shift(bx.toDouble(), by.toDouble(), bz.toDouble())
|
||||||
|
|
||||||
|
// 先に交差判定を行う
|
||||||
|
if (!targetBox.overlaps(absBox)) continue
|
||||||
|
|
||||||
|
// カーペット(高さ <= 0.0625)や開いた/下付きトラップドアのような軽微な衝突は無視する
|
||||||
|
// 物体が大きく遮っている場合はテレポートを阻止する
|
||||||
|
// カーペットの高さは0.0625。下付きトラップドアは通常0.1875。
|
||||||
|
// 足元の障害物が最小限であればテレポートを許可する。
|
||||||
|
|
||||||
|
val intersection = targetBox.clone().intersection(absBox)
|
||||||
|
val intHeight = intersection.height
|
||||||
|
|
||||||
|
// 交差が非常に小さい場合(カーペットに触れている程度など)は許可する
|
||||||
|
// 足元にあり、高さが0.2未満(トラップドアは約0.1875)であれば許容する
|
||||||
|
val isAtFeetLevel = (absBox.minY - y) < 0.1
|
||||||
|
if (isAtFeetLevel && absBox.height < 0.2) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user