diff --git a/src/main/kotlin/dev/slne/surf/lobby/PaperMain.kt b/src/main/kotlin/dev/slne/surf/lobby/PaperMain.kt index c699478..3399e0c 100644 --- a/src/main/kotlin/dev/slne/surf/lobby/PaperMain.kt +++ b/src/main/kotlin/dev/slne/surf/lobby/PaperMain.kt @@ -9,7 +9,6 @@ import dev.slne.surf.lobby.hook.hologram.SurfHologramHook import dev.slne.surf.lobby.hook.nexo.NexoHook import dev.slne.surf.lobby.hook.npc.SurfNpcHook import dev.slne.surf.lobby.listener.* -import dev.slne.surf.lobby.manager.PushbackManager import dev.slne.surf.redis.RedisApi import dev.slne.surf.surfapi.bukkit.api.event.register import org.bukkit.Bukkit @@ -41,8 +40,6 @@ class PaperMain : SuspendingJavaPlugin() { PlayerMoveListener.register() EntitySpawnListener.register() - PushbackManager.startTask() - lobbyCommand() spawnCommand() diff --git a/src/main/kotlin/dev/slne/surf/lobby/listener/PlayerMoveListener.kt b/src/main/kotlin/dev/slne/surf/lobby/listener/PlayerMoveListener.kt index 5f50119..6096378 100644 --- a/src/main/kotlin/dev/slne/surf/lobby/listener/PlayerMoveListener.kt +++ b/src/main/kotlin/dev/slne/surf/lobby/listener/PlayerMoveListener.kt @@ -2,6 +2,7 @@ package dev.slne.surf.lobby.listener import dev.slne.surf.lobby.lobbyConfig import dev.slne.surf.lobby.manager.ElytraBoostManager +import dev.slne.surf.lobby.manager.PushbackManager import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.player.PlayerMoveEvent @@ -23,6 +24,9 @@ object PlayerMoveListener : Listener { return } + PushbackManager.updateExecutorPosition(player) + PushbackManager.checkPushback(player) + @Suppress("DEPRECATION") // isOnGround is deprecated, but it works fine for our use case as it is only used to check if the player is on the ground to clear the boost, and it is not used for any critical logic. if (player.isOnGround) { ElytraBoostManager.clearBoost(player) diff --git a/src/main/kotlin/dev/slne/surf/lobby/manager/PushbackManager.kt b/src/main/kotlin/dev/slne/surf/lobby/manager/PushbackManager.kt index e145367..fc08487 100644 --- a/src/main/kotlin/dev/slne/surf/lobby/manager/PushbackManager.kt +++ b/src/main/kotlin/dev/slne/surf/lobby/manager/PushbackManager.kt @@ -1,43 +1,62 @@ package dev.slne.surf.lobby.manager -import dev.slne.surf.lobby.plugin +import dev.slne.surf.lobby.utils.CircularBoundingBox import dev.slne.surf.lobby.utils.PermissionRegistry -import dev.slne.surf.surfapi.bukkit.api.util.toPlayers -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf +import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf import org.bukkit.Bukkit import org.bukkit.Effect +import org.bukkit.entity.Player import java.util.* object PushbackManager { - private val pushbacks = mutableObjectSetOf() + private val boundingBoxes = mutableObject2ObjectMapOf() + private val lastPushbackTimes = mutableObject2ObjectMapOf() private const val RANGE = 3.0 private const val FORCE = -0.5 private const val Y_FORCE = 0.5 - - fun startTask() { - Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, { - pushbacks.toPlayers().forEach { player -> - val nearbyPlayers = player.location.getNearbyPlayers(RANGE) { other -> - other != player && !other.hasPermission(PermissionRegistry.PUSHBACK_ITEM) - } - - for (nearby in nearbyPlayers) { - nearby.velocity = player.location.toVector() - .subtract(nearby.location.toVector()) - .multiply(FORCE) - .setY(Y_FORCE) - } - - player.world.playEffect(player.location, Effect.ENDER_SIGNAL, null) - } - }, 20, 20) - } + private const val COOLDOWN_MS = 1000L fun add(uuid: UUID) { - pushbacks.add(uuid) + val player = Bukkit.getPlayer(uuid) ?: return + val loc = player.location + boundingBoxes[uuid] = CircularBoundingBox(loc.x, loc.z, RANGE) } fun remove(uuid: UUID) { - pushbacks.remove(uuid) + boundingBoxes.remove(uuid) + lastPushbackTimes.remove(uuid) + } + + fun updateExecutorPosition(player: Player) { + val box = boundingBoxes[player.uniqueId] ?: return + val loc = player.location + box.updateCenter(loc.x, loc.z) + } + + fun checkPushback(player: Player) { + if (player.hasPermission(PermissionRegistry.PUSHBACK_ITEM)) return + + val now = System.currentTimeMillis() + val lastPushback = lastPushbackTimes[player.uniqueId] + if (lastPushback != null && now - lastPushback < COOLDOWN_MS) return + + val playerLoc = player.location + + for ((executorUuid, box) in boundingBoxes) { + if (executorUuid == player.uniqueId) continue + if (!box.isInside(playerLoc.x, playerLoc.z)) continue + + val executor = Bukkit.getPlayer(executorUuid) ?: continue + if (executor.world != player.world) continue + + player.velocity = executor.location.toVector() + .subtract(playerLoc.toVector()) + .multiply(FORCE) + .setY(Y_FORCE) + + executor.world.playEffect(executor.location, Effect.ENDER_SIGNAL, null) + lastPushbackTimes[player.uniqueId] = now + break + } } } \ No newline at end of file diff --git a/src/main/kotlin/dev/slne/surf/lobby/utils/CircularBoundingBox.kt b/src/main/kotlin/dev/slne/surf/lobby/utils/CircularBoundingBox.kt new file mode 100644 index 0000000..6242ce7 --- /dev/null +++ b/src/main/kotlin/dev/slne/surf/lobby/utils/CircularBoundingBox.kt @@ -0,0 +1,20 @@ +package dev.slne.surf.lobby.utils + +class CircularBoundingBox( + var centerX: Double, + var centerZ: Double, + val radius: Double +) { + private val radiusSquared = radius * radius + + fun isInside(x: Double, z: Double): Boolean { + val dx = x - centerX + val dz = z - centerZ + return dx * dx + dz * dz <= radiusSquared + } + + fun updateCenter(x: Double, z: Double) { + centerX = x + centerZ = z + } +}