Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
javaVersion=25
mcVersion=1.21.11
group=dev.slne.surf
version=1.21.11-2.69.0
version=1.21.11-2.70.0
relocationPrefix=dev.slne.surf.surfapi.libs
snapshot=false
29 changes: 28 additions & 1 deletion surf-api-bukkit/surf-api-bukkit-api/api/surf-api-bukkit-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,30 @@ public abstract class dev/slne/surf/surfapi/bukkit/api/permission/PermissionRegi
public final fun create (Ljava/lang/String;)Ljava/lang/String;
}

public abstract interface class dev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard {
public static final field Companion Ldev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard$Companion;
public abstract fun ensureTickThread (Lorg/bukkit/World;DDLjava/lang/String;)V
public abstract fun ensureTickThread (Lorg/bukkit/World;IILjava/lang/String;)V
public abstract fun ensureTickThread (Lorg/bukkit/World;Lio/papermc/paper/math/Position;ILjava/lang/String;)V
public abstract fun ensureTickThread (Lorg/bukkit/World;Lio/papermc/paper/math/Position;Ljava/lang/String;)V
public abstract fun ensureTickThread (Lorg/bukkit/World;Lorg/bukkit/util/BoundingBox;Ljava/lang/String;)V
public abstract fun ensureTickThread (Lorg/bukkit/entity/Entity;Ljava/lang/String;)V
}

public final class dev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard$Companion : dev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard {
public fun ensureTickThread (Lorg/bukkit/World;DDLjava/lang/String;)V
public fun ensureTickThread (Lorg/bukkit/World;IILjava/lang/String;)V
public fun ensureTickThread (Lorg/bukkit/World;Lio/papermc/paper/math/Position;ILjava/lang/String;)V
public fun ensureTickThread (Lorg/bukkit/World;Lio/papermc/paper/math/Position;Ljava/lang/String;)V
public fun ensureTickThread (Lorg/bukkit/World;Lorg/bukkit/util/BoundingBox;Ljava/lang/String;)V
public fun ensureTickThread (Lorg/bukkit/entity/Entity;Ljava/lang/String;)V
public final fun getInstance ()Ldev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard;
}

public final class dev/slne/surf/surfapi/bukkit/api/region/TickThreadGuardKt {
public static final fun getTickThreadGuard ()Ldev/slne/surf/surfapi/bukkit/api/region/TickThreadGuard;
}

public abstract interface annotation class dev/slne/surf/surfapi/bukkit/api/scoreboard/ObsoleteScoreboardApi : java/lang/annotation/Annotation {
}

Expand Down Expand Up @@ -2466,14 +2490,17 @@ public final class dev/slne/surf/surfapi/bukkit/api/visualizer/SurfBukkitVisuali
public abstract interface annotation class dev/slne/surf/surfapi/bukkit/api/visualizer/visualizer/ExperimentalVisualizerApi : java/lang/annotation/Annotation {
}

public abstract interface class dev/slne/surf/surfapi/bukkit/api/visualizer/visualizer/SurfVisualizer {
public abstract interface class dev/slne/surf/surfapi/bukkit/api/visualizer/visualizer/SurfVisualizer : java/lang/AutoCloseable {
public static final field Companion Ldev/slne/surf/surfapi/bukkit/api/visualizer/visualizer/SurfVisualizer$Companion;
public static final field DEFAULT_BLOCK_TYPE Lorg/bukkit/block/BlockType;
public abstract fun addViewer (Lorg/bukkit/entity/Player;)V
public abstract fun clearViewers ()V
public abstract fun close ()V
public abstract fun getUid ()Ljava/util/UUID;
public abstract fun getViewerUuids ()Ljava/util/Set;
public abstract fun getViewers ()Lit/unimi/dsi/fastutil/objects/ObjectSet;
public abstract fun hasViewers ()Z
public abstract fun isClosed ()Z
public abstract fun isVisualizing ()Z
public abstract fun removeViewer (Lorg/bukkit/entity/Player;)V
public abstract fun startVisualizing ()Z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ default PacketListenerResult handleEarlyClientboundPacket(Packet packet, @Nullab
if (player != null) {
return handleClientboundPacket(packet, player);
} else {
throw new IllegalStateException(
"No player is available for this clientbound packet yet. " +
"This can happen during early connection phases such as login. " +
"Override handleEarlyClientboundPacket(...) if your listener should handle packets before a Player exists."
);
return PacketListenerResult.CONTINUE;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ default PacketListenerResult handleEarlyServerboundPacket(Packet packet, @Nullab
if (player != null) {
return handleServerboundPacket(packet, player);
} else {
throw new IllegalStateException(
"No player is available for this serverbound packet yet. " +
"This can happen during early connection phases such as login. " +
"Override handleEarlyServerboundPacket(...) if your listener should handle packets before a Player exists."
);
return PacketListenerResult.CONTINUE;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.slne.surf.surfapi.bukkit.api.region

import dev.slne.surf.surfapi.core.api.util.requiredService
import io.papermc.paper.math.Position
import org.bukkit.World
import org.bukkit.entity.Entity
import org.bukkit.util.BoundingBox

@Suppress("UnstableApiUsage")
interface TickThreadGuard {

fun ensureTickThread(world: World, pos: Position, reason: String)
fun ensureTickThread(world: World, pos: Position, blockRadius: Int, reason: String)
fun ensureTickThread(world: World, chunkX: Int, chunkZ: Int, reason: String)

fun ensureTickThread(entity: Entity, reason: String)

fun ensureTickThread(world: World, box: BoundingBox, reason: String)
fun ensureTickThread(world: World, blockX: Double, blockZ: Double, reason: String)

companion object : TickThreadGuard by tickThreadGuard {
val instance = tickThreadGuard
}
}

val tickThreadGuard = requiredService<TickThreadGuard>()
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import com.github.shynixn.mccoroutine.folia.entityDispatcher
import com.github.shynixn.mccoroutine.folia.regionDispatcher
import dev.slne.surf.surfapi.bukkit.api.SurfBukkitApi
import dev.slne.surf.surfapi.core.api.util.getCallerClass
import dev.slne.surf.surfapi.core.api.util.mutableLong2ObjectMapOf
import dev.slne.surf.surfapi.core.api.util.mutableObjectListOf
import io.papermc.paper.math.BlockPosition
import io.papermc.paper.math.Position
import it.unimi.dsi.fastutil.longs.LongOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectList
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.*
import kotlinx.coroutines.future.await
import kotlinx.coroutines.withContext
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import org.bukkit.*
import org.bukkit.block.Block
import org.bukkit.entity.Entity
Expand All @@ -25,6 +24,7 @@ import org.bukkit.plugin.java.JavaPlugin
import org.spongepowered.math.vector.Vector3d
import org.spongepowered.math.vector.Vector3i
import java.util.*
import java.util.concurrent.ConcurrentHashMap

/**
* Creates a [NamespacedKey] using the calling plugin and the given name.
Expand Down Expand Up @@ -230,38 +230,42 @@ fun ChunkSnapshot.getHighestBlockYAtBlockCoordinates(
}

suspend fun Collection<Vector3i>.computeHighestYBlock(world: World): ObjectList<Vector3i> {
val byChunk = mutableLong2ObjectMapOf<ObjectList<Vector3i>>(size / 4 + 1)
val chunkKeys = LongOpenHashSet(size / 4 + 1)
for (point in this) {
val key = Chunk.getChunkKey(point.x() shr 4, point.z() shr 4)
val list = byChunk.computeIfAbsent(key) { mutableObjectListOf() }
list.add(point)
chunkKeys.add(key)
}

val snapshots = mutableLong2ObjectMapOf<ChunkSnapshot>(byChunk.size)
val snapshots = ConcurrentHashMap<Long, ChunkSnapshot>(chunkKeys.size)
coroutineScope {
byChunk.keys.map { key ->
async {
val snapshot =
world.getChunkAtAsync(getXFromChunkKey(key), getZFromChunkKey(key))
val semaphore = Semaphore(16) // Limit concurrent chunk loads to prevent overwhelming the server
val iterator = chunkKeys.iterator()
while (iterator.hasNext()) {
val key = iterator.nextLong()
launch {
semaphore.withPermit {
val chunk = world.getChunkAtAsync(getXFromChunkKey(key), getZFromChunkKey(key))
.await()
.getChunkSnapshot(true, false, false, false)
snapshots.put(key, snapshot)

withContext(
JavaPlugin.getProvidingPlugin(SurfBukkitApi::class.java)
.regionDispatcher(world, chunk.x, chunk.z)
) {
val snapshot = chunk
.getChunkSnapshot(true, false, false, false)
snapshots[key] = snapshot
}
}
}
}.awaitAll()
}
}


val result = mutableObjectListOf<Vector3i>(size)
val it = byChunk.long2ObjectEntrySet().fastIterator()
while (it.hasNext()) {
val entry = it.next()
val key = entry.longKey
val pointsInChunk = entry.value
for (point in this) {
val key = Chunk.getChunkKey(point.x() shr 4, point.z() shr 4)
val snapshot = snapshots[key] ?: error("ChunkSnapshot for key $key not found")
for (point in pointsInChunk) {
val y = snapshot.getHighestBlockYAtBlockCoordinates(point.x(), point.z())
result.add(Vector3i(point.x(), y, point.z()))
}
val y = snapshot.getHighestBlockYAtBlockCoordinates(point.x(), point.z())
result.add(Vector3i(point.x(), y, point.z()))
}

return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.objects.ObjectSet
import org.bukkit.block.BlockType
import org.bukkit.entity.Player
import org.jetbrains.annotations.UnmodifiableView
import java.lang.AutoCloseable
import java.util.*


Expand All @@ -16,7 +17,7 @@ import java.util.*
* and may be subject to changes in future updates.
*/
@ExperimentalVisualizerApi
interface SurfVisualizer {
interface SurfVisualizer : AutoCloseable {
/**
* A unique identifier for the visualizer instance.
* This identifier is used to distinguish one visualizer object from another.
Expand Down Expand Up @@ -52,6 +53,9 @@ interface SurfVisualizer {
* Modifications to the set directly are not allowed, ensuring consistency
* with the visualizer's state.
*/
val viewerUuids: @UnmodifiableView Set<UUID>

@Deprecated("Use viewerUuids instead", ReplaceWith("viewerUuids"))
val viewers: @UnmodifiableView ObjectSet<Player>

/**
Expand Down Expand Up @@ -104,6 +108,27 @@ interface SurfVisualizer {
*/
fun update(strategy: UpdateStrategy = UpdateStrategy.ALL)

/**
* Closes the current visualizer instance, releasing any resources or connections
* associated with it. This method stops any ongoing visualization activities
* and ensures that all registered viewers are cleared.
*
* Once this method is called, the visualizer transitions into a closed state,
* making it unavailable for further operations unless explicitly restarted
* or reinitialized.
*
* Typical usage scenarios include shutting down the visualizer gracefully
* or when it is no longer needed.
*/
override fun close()

/**
* Checks whether the visualizer has been closed.
*
* @return `true` if the visualizer is in a closed state, `false` otherwise.
*/
fun isClosed(): Boolean

/**
* Companion object for the `SurfVisualizer` interface.
* Provides shared constants and utilities related to visualizer functionality.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dev.slne.surf.surfapi.bukkit.api.visualizer.visualizer

import dev.slne.surf.surfapi.bukkit.api.nms.bridges.packets.entity.BlockDisplaySettings
import it.unimi.dsi.fastutil.objects.ObjectSet
import org.jetbrains.annotations.UnmodifiableView
import org.jetbrains.annotations.Unmodifiable
import org.spongepowered.math.vector.Vector3d

/**
Expand All @@ -27,7 +27,7 @@ interface SurfVisualizerArea : SurfVisualizer {
*
* This property is part of the experimental API and may be subject to changes in the future.
*/
val cornerLocations: @UnmodifiableView ObjectSet<Vector3d>
val cornerLocations: @Unmodifiable ObjectSet<Vector3d>

/**
* Adds a location to the set of corner locations in the visualizer area.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class SurfBukkitNmsBridgeImpl : SurfBukkitNmsBridge {
} catch (e: Throwable) {
log.atSevere()
.withCause(e)
.log("Failed to handle serverbound packet")
.log("Failed to handle serverbound packet $clazz for listener $listener")
PacketListenerResult.CONTINUE
}

Expand Down Expand Up @@ -118,7 +118,7 @@ class SurfBukkitNmsBridgeImpl : SurfBukkitNmsBridge {
} catch (e: Throwable) {
log.atSevere()
.withCause(e)
.log("Failed to handle clientbound packet")
.log("Failed to handle clientbound packet ${packet.packetClass} for listener $listener")
PacketListenerResult.CONTINUE
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class SurfBukkitPacketListenerApiImpl : SurfBukkitPacketListenerApi {
}

fun interface ListenerResultConverter<T> {
fun convert(result: T, packet: Packet<*>?): Packet<*>?
fun convert(result: T?, packet: Packet<*>?): Packet<*>?
}

fun interface ListenerInvoker {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dev.slne.surf.surfapi.bukkit.server.impl.region

import ca.spottedleaf.moonrise.common.util.TickThread
import com.google.auto.service.AutoService
import dev.slne.surf.surfapi.bukkit.api.region.TickThreadGuard
import dev.slne.surf.surfapi.bukkit.api.util.chunkX
import dev.slne.surf.surfapi.bukkit.api.util.chunkZ
import dev.slne.surf.surfapi.bukkit.server.nms.toNms
import dev.slne.surf.surfapi.core.api.util.checkInstantiationByServiceLoader
import io.papermc.paper.math.Position
import net.minecraft.core.BlockPos
import net.minecraft.world.phys.AABB
import org.bukkit.World
import org.bukkit.entity.Entity
import org.bukkit.util.BoundingBox

@Suppress("UnstableApiUsage")
@AutoService(TickThreadGuard::class)
class TickThreadGuardImpl : TickThreadGuard {
init {
checkInstantiationByServiceLoader()
}

override fun ensureTickThread(world: World, pos: Position, reason: String) {
TickThread.ensureTickThread(world.toNms(), pos.chunkX, pos.chunkZ, reason)
}

override fun ensureTickThread(
world: World,
pos: Position,
blockRadius: Int,
reason: String
) {
TickThread.ensureTickThread(
world.toNms(),
BlockPos(pos.blockX(), pos.blockY(), pos.blockZ()),
blockRadius,
reason
)
}

override fun ensureTickThread(
world: World,
chunkX: Int,
chunkZ: Int,
reason: String
) {
TickThread.ensureTickThread(world.toNms(), chunkX, chunkZ, reason)
}

override fun ensureTickThread(entity: Entity, reason: String) {
TickThread.ensureTickThread(entity.toNms(), reason)
}

override fun ensureTickThread(world: World, box: BoundingBox, reason: String) {
TickThread.ensureTickThread(
world.toNms(),
AABB(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ),
reason
)
}

override fun ensureTickThread(
world: World,
blockX: Double,
blockZ: Double,
reason: String
) {
TickThread.ensureTickThread(world.toNms(), blockX, blockZ, reason)
}
}
Loading
Loading