Skip to content

Commit

Permalink
fix: teleport vehicle with RETAIN_PASSENGERS, ensure cooldown is hand…
Browse files Browse the repository at this point in the history
…led on vehicle not player
  • Loading branch information
Boy0000 committed Oct 18, 2024
1 parent 6ba383d commit 008e285
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ object MovementHandler {
override fun isValidTeleport() = true
}

teleportCooldown += player.uniqueId
val teleportEntity = player.vehicle ?: player
teleportCooldown += teleportEntity.uniqueId

if (player.gameMode != GameMode.SPECTATOR && sectionTransition.to.block.isSolid) {
return if (sectionTransition.kind == TransitionKind.ASCEND) {
Expand All @@ -85,6 +86,6 @@ object MovementHandler {
}
}

return TransitionTeleportHandler(player, sectionTransition.from, sectionTransition.to)
return TransitionTeleportHandler(teleportEntity, sectionTransition.from, sectionTransition.to)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,73 @@ import io.papermc.paper.entity.TeleportFlag
import kotlinx.coroutines.delay
import kotlinx.coroutines.future.asDeferred
import org.bukkit.Location
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerTeleportEvent

class TransitionTeleportHandler(val player: Player, val from: Location, val to: Location) : TeleportHandler {
class TransitionTeleportHandler(val teleportEntity: Entity, val from: Location, val to: Location) : TeleportHandler {

override fun handleTeleport() {
val oldLeashedEntities = player.getLeashedEntities()
val spectators = player.world.players.filter { it.spectatorTarget?.uniqueId == player.uniqueId }
val oldLeashedEntities = leashedEntities()
val spectators = spectatorEntities()
val oldVelocity = teleportEntity.velocity
val teleportFlags: Array<TeleportFlag> = listOf(TeleportFlag.Relative.YAW, TeleportFlag.Relative.PITCH, TeleportFlag.Relative.X, TeleportFlag.Relative.Y, TeleportFlag.Relative.Z, TeleportFlag.EntityState.RETAIN_PASSENGERS, TeleportFlag.EntityState.RETAIN_VEHICLE).toTypedArray()

// Unleash all the leashed entities before teleporting them, to prevent leads from dropping.
// The leashes are restored after teleportation.
for (it in oldLeashedEntities) it.setLeashHolder(null)
for (it in spectators) it.spectatorTarget = null
oldLeashedEntities.values.flatten().forEach { it.setLeashHolder(null) }
spectators.values.flatten().forEach { it.spectatorTarget = null }

deeperWorld.plugin.launch {
player.teleportAsync(to, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
oldLeashedEntities.forEach { leashEntity ->
leashEntity.teleportAsync(player.location, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
leashEntity.setLeashHolder(player)
teleportEntity.teleportAsync(to, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
teleportEntity.velocity = oldVelocity
oldLeashedEntities.forEach { (leashHolder, leashEntities) ->
leashEntities.forEach {
it.teleportAsync(teleportEntity.location, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
it.setLeashHolder(leashHolder)
}
}
spectators.forEach { spectator ->
spectator.teleportAsync(player.location, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
spectator.spectatorTarget = player
spectators.forEach { (spectatorTarget, spectators) ->
spectators.forEach {
it.teleportAsync(teleportEntity.location, PlayerTeleportEvent.TeleportCause.PLUGIN, *teleportFlags).asDeferred().await()
it.spectatorTarget = spectatorTarget
}
}

delay(10.ticks)
MovementHandler.teleportCooldown -= player.uniqueId
MovementHandler.teleportCooldown -= teleportEntity.uniqueId
}
}

override fun isValidTeleport(): Boolean {
return true
}

private fun Player.getLeashedEntities(): List<LivingEntity> {
private fun spectatorEntities(): Map<Entity, List<Player>> {
return when (teleportEntity) {
is Player -> mapOf(teleportEntity to teleportEntity.world.players.filter { it.spectatorTarget?.uniqueId == teleportEntity.uniqueId })
else -> teleportEntity.passengers.associateWith { p ->
p.world.players.filter { it.spectatorTarget?.uniqueId == p.uniqueId }
}
}
}

private fun leashedEntities(): Map<LivingEntity, List<LivingEntity>> {
// Max leashed entity range is 10 blocks, therefore these parameter values
return location.getNearbyEntitiesByType(LivingEntity::class.java, 20.0)
.filter { it.isLeashed && it.leashHolder.uniqueId == this.uniqueId }
return when (teleportEntity) {
is Player -> mapOf(teleportEntity to teleportEntity.location
.getNearbyEntitiesByType(LivingEntity::class.java, 20.0)
.filter { it.isLeashed && it.leashHolder.uniqueId == teleportEntity.uniqueId })

else -> teleportEntity.passengers.filterIsInstance<LivingEntity>().associateWith {
it.location.getNearbyEntitiesByType(LivingEntity::class.java, 20.0)
.filter { it.isLeashed && it.leashHolder.uniqueId == teleportEntity.uniqueId }
}
}
}

private fun Entity.recursiveLeashEntities(): List<LivingEntity> {
return location.getNearbyEntitiesByType(LivingEntity::class.java, 20.0).filter { it.isLeashed && it.leashHolder.uniqueId == this.uniqueId }
}
}

0 comments on commit 008e285

Please sign in to comment.