feat: update dependencies
This commit is contained in:
parent
1c809b3def
commit
e324a110e5
|
|
@ -1 +1 @@
|
||||||
Subproject commit be85d83428eff52a749747fc495c4bda0e82d035
|
Subproject commit 5535c259494adcd33e659aae9a171c3ebf16e2cf
|
||||||
|
|
@ -18,15 +18,14 @@ val exposedVersion = "1.0.0-rc-4"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib")
|
paperLibrary("org.jetbrains.kotlin:kotlin-stdlib:2.1.0")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") {
|
paperLibrary("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
|
||||||
exclude(group = "org.jetbrains.kotlin")
|
|
||||||
}
|
|
||||||
compileOnly("com.michael-bull.kotlin-result:kotlin-result:2.1.0")
|
compileOnly("com.michael-bull.kotlin-result:kotlin-result:2.1.0")
|
||||||
|
|
||||||
compileOnly("net.hareworks.hcu:hcu-core")
|
compileOnly("net.hareworks.hcu:hcu-core")
|
||||||
compileOnly("net.hareworks:kommand-lib")
|
compileOnly("net.hareworks:kommand-lib")
|
||||||
compileOnly("net.hareworks:permits-lib")
|
compileOnly("net.hareworks:permits-lib")
|
||||||
|
compileOnly("net.hareworks:GhostDisplays")
|
||||||
|
|
||||||
compileOnly("net.kyori:adventure-api:4.25.0")
|
compileOnly("net.kyori:adventure-api:4.25.0")
|
||||||
compileOnly("net.kyori:adventure-text-minimessage:4.25.0")
|
compileOnly("net.kyori:adventure-text-minimessage:4.25.0")
|
||||||
|
|
@ -43,9 +42,10 @@ tasks {
|
||||||
}
|
}
|
||||||
shadowJar {
|
shadowJar {
|
||||||
archiveClassifier.set("min")
|
archiveClassifier.set("min")
|
||||||
minimize()
|
minimize {
|
||||||
dependencies {
|
exclude(dependency("net.hareworks:GhostDisplays"))
|
||||||
exclude(dependency("org.jetbrains.kotlin:kotlin-stdlib"))
|
exclude(dependency("net.hareworks:kommand-lib"))
|
||||||
|
exclude(dependency("net.hareworks:permits-lib"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +61,10 @@ paper {
|
||||||
required = true
|
required = true
|
||||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
}
|
}
|
||||||
|
register("GhostDisplays") {
|
||||||
|
required = true
|
||||||
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
authors =
|
authors =
|
||||||
listOf(
|
listOf(
|
||||||
|
|
|
||||||
2
hcu-core
2
hcu-core
|
|
@ -1 +1 @@
|
||||||
Subproject commit 520a378cd5c3da6321305d07cc0b402b73292add
|
Subproject commit e2375c0876de9ba30be24af84d90443ea844a99b
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
rootProject.name = "faction"
|
rootProject.name = "lands"
|
||||||
includeBuild("hcu-core")
|
includeBuild("hcu-core")
|
||||||
includeBuild("hcu-core/kommand-lib")
|
includeBuild("hcu-core/kommand-lib")
|
||||||
includeBuild("hcu-core/kommand-lib/permits-lib")
|
includeBuild("hcu-core/kommand-lib/permits-lib")
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,12 @@ class App : JavaPlugin() {
|
||||||
this.playerIdService = pIdService
|
this.playerIdService = pIdService
|
||||||
this.actorIdentityService = actorService
|
this.actorIdentityService = actorService
|
||||||
|
|
||||||
|
// Load DisplayService (optional dependency)
|
||||||
|
val displayService = server.servicesManager.load(net.hareworks.ghostdisplays.api.DisplayService::class.java)
|
||||||
|
if (displayService == null) {
|
||||||
|
logger.warning("DisplayService not found. Land name displays will not be shown.")
|
||||||
|
}
|
||||||
|
|
||||||
// Register public API as a Bukkit service
|
// Register public API as a Bukkit service
|
||||||
val landsAPI = net.hareworks.hcu.lands.api.LandsAPIImpl(service)
|
val landsAPI = net.hareworks.hcu.lands.api.LandsAPIImpl(service)
|
||||||
server.servicesManager.register(
|
server.servicesManager.register(
|
||||||
|
|
@ -67,8 +73,10 @@ class App : JavaPlugin() {
|
||||||
org.bukkit.plugin.ServicePriority.Normal
|
org.bukkit.plugin.ServicePriority.Normal
|
||||||
)
|
)
|
||||||
|
|
||||||
// Run visualizer every 20 ticks (1 second)
|
// Run visualizer every 10 ticks (0.5 seconds)
|
||||||
server.scheduler.runTaskTimer(this, VisualizerTask(service), 20L, 10L)
|
val visualizerTask = VisualizerTask(service, displayService)
|
||||||
|
net.hareworks.hcu.lands.task.LandsVisualizer.setVisualizerTask(visualizerTask)
|
||||||
|
server.scheduler.runTaskTimer(this, visualizerTask, 20L, 10L)
|
||||||
|
|
||||||
logger.info("Lands plugin initialized successfully.")
|
logger.info("Lands plugin initialized successfully.")
|
||||||
logger.info("LandsAPI registered as a Bukkit service.")
|
logger.info("LandsAPI registered as a Bukkit service.")
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,43 @@ data class Land(
|
||||||
|
|
||||||
return totalVolume
|
return totalVolume
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getBoundingBox(): net.hareworks.hcu.lands.index.BoundingBox {
|
||||||
|
if (data.parts.isEmpty()) {
|
||||||
|
return net.hareworks.hcu.lands.index.BoundingBox(0, 0, 0, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var minX = Int.MAX_VALUE
|
||||||
|
var minY = Int.MAX_VALUE
|
||||||
|
var minZ = Int.MAX_VALUE
|
||||||
|
var maxX = Int.MIN_VALUE
|
||||||
|
var maxY = Int.MIN_VALUE
|
||||||
|
var maxZ = Int.MIN_VALUE
|
||||||
|
|
||||||
|
data.parts.forEach { shape ->
|
||||||
|
when (shape) {
|
||||||
|
is Shape.Cuboid -> {
|
||||||
|
minX = minOf(minX, shape.minX())
|
||||||
|
maxX = maxOf(maxX, shape.maxX())
|
||||||
|
minY = minOf(minY, shape.minY())
|
||||||
|
maxY = maxOf(maxY, shape.maxY())
|
||||||
|
minZ = minOf(minZ, shape.minZ())
|
||||||
|
maxZ = maxOf(maxZ, shape.maxZ())
|
||||||
|
}
|
||||||
|
is Shape.Cylinder -> {
|
||||||
|
val r = (shape.radius + 0.5).toInt() + 1
|
||||||
|
minX = minOf(minX, shape.x - r)
|
||||||
|
maxX = maxOf(maxX, shape.x + r)
|
||||||
|
minY = minOf(minY, shape.y - shape.bottomHeight)
|
||||||
|
maxY = maxOf(maxY, shape.y + shape.topHeight)
|
||||||
|
minZ = minOf(minZ, shape.z - r)
|
||||||
|
maxZ = maxOf(maxZ, shape.z + r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return net.hareworks.hcu.lands.index.BoundingBox(minX, minY, minZ, maxX, maxY, maxZ)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,32 @@ package net.hareworks.hcu.lands.task
|
||||||
|
|
||||||
import net.hareworks.hcu.lands.model.Shape
|
import net.hareworks.hcu.lands.model.Shape
|
||||||
import net.hareworks.hcu.lands.service.LandService
|
import net.hareworks.hcu.lands.service.LandService
|
||||||
|
import net.hareworks.ghostdisplays.api.DisplayController
|
||||||
|
import net.hareworks.ghostdisplays.api.DisplayService
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Color
|
import org.bukkit.Color
|
||||||
|
import org.bukkit.Location
|
||||||
import org.bukkit.Particle
|
import org.bukkit.Particle
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.entity.TextDisplay
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.math.abs
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
object LandsVisualizer {
|
object LandsVisualizer {
|
||||||
private val enabledPlayers = mutableSetOf<UUID>()
|
private val enabledPlayers = mutableSetOf<UUID>()
|
||||||
|
private var visualizerTask: VisualizerTask? = null
|
||||||
|
|
||||||
|
fun setVisualizerTask(task: VisualizerTask) {
|
||||||
|
visualizerTask = task
|
||||||
|
}
|
||||||
|
|
||||||
fun toggle(player: Player) {
|
fun toggle(player: Player) {
|
||||||
if (enabledPlayers.contains(player.uniqueId)) {
|
if (enabledPlayers.contains(player.uniqueId)) {
|
||||||
enabledPlayers.remove(player.uniqueId)
|
enabledPlayers.remove(player.uniqueId)
|
||||||
|
visualizerTask?.cleanupDisplaysForPlayer(player.uniqueId)
|
||||||
player.sendMessage("Visualization disabled.")
|
player.sendMessage("Visualization disabled.")
|
||||||
} else {
|
} else {
|
||||||
enabledPlayers.add(player.uniqueId)
|
enabledPlayers.add(player.uniqueId)
|
||||||
|
|
@ -26,7 +38,12 @@ object LandsVisualizer {
|
||||||
fun isEnabled(player: Player) = enabledPlayers.contains(player.uniqueId)
|
fun isEnabled(player: Player) = enabledPlayers.contains(player.uniqueId)
|
||||||
}
|
}
|
||||||
|
|
||||||
class VisualizerTask(private val landService: LandService) : Runnable {
|
class VisualizerTask(
|
||||||
|
private val landService: LandService,
|
||||||
|
private val displayService: DisplayService?
|
||||||
|
) : Runnable {
|
||||||
|
private val logger = org.bukkit.Bukkit.getLogger()
|
||||||
|
private val displayControllers = ConcurrentHashMap<UUID, MutableMap<Int, DisplayController<TextDisplay>>>()
|
||||||
override fun run() {
|
override fun run() {
|
||||||
Bukkit.getOnlinePlayers().forEach { p ->
|
Bukkit.getOnlinePlayers().forEach { p ->
|
||||||
if (LandsVisualizer.isEnabled(p)) {
|
if (LandsVisualizer.isEnabled(p)) {
|
||||||
|
|
@ -43,6 +60,30 @@ class VisualizerTask(private val landService: LandService) : Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manage TextDisplays for land names
|
||||||
|
if (displayService != null) {
|
||||||
|
val activeDisplays = displayControllers.getOrPut(p.uniqueId) { mutableMapOf() }
|
||||||
|
val nearbyLandIds = nearbyLands.map { it.id }.toSet()
|
||||||
|
|
||||||
|
// Update displays for nearby lands
|
||||||
|
nearbyLands.forEach { land ->
|
||||||
|
val controller = activeDisplays.getOrPut(land.id) {
|
||||||
|
val newController = createDisplayForLand(p, land)
|
||||||
|
logger.info("[LandsDisplay] Created display for land '${land.name}' (ID: ${land.id}) for player ${p.name}")
|
||||||
|
newController
|
||||||
|
}
|
||||||
|
updateDisplayPosition(controller, p, land)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove displays for lands no longer nearby
|
||||||
|
val toRemove = activeDisplays.keys.filter { it !in nearbyLandIds }
|
||||||
|
toRemove.forEach { landId ->
|
||||||
|
activeDisplays[landId]?.destroy()
|
||||||
|
activeDisplays.remove(landId)
|
||||||
|
logger.info("[LandsDisplay] Removed display for land ID $landId for player ${p.name} (out of range)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nearbyLands.forEach { land ->
|
nearbyLands.forEach { land ->
|
||||||
// Verify that this is the current version of the land
|
// Verify that this is the current version of the land
|
||||||
val currentLand = landService.getLand(land.id)
|
val currentLand = landService.getLand(land.id)
|
||||||
|
|
@ -162,19 +203,6 @@ class VisualizerTask(private val landService: LandService) : Runnable {
|
||||||
|
|
||||||
drawLine(player, x, bottomY, z, x, topY, z, edgeColor, 0.5)
|
drawLine(player, x, bottomY, z, x, topY, z, edgeColor, 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw top face outline in red (outer edges only)
|
|
||||||
// Optimized: Calculate outline once for both faces as they share the same XZ shape
|
|
||||||
val faceOutline = cylinder.getOptimizedFaceOutline()
|
|
||||||
val redColor = Particle.DustOptions(Color.RED, 1.0f)
|
|
||||||
val topFaceY = cylinder.y + cylinder.topHeight
|
|
||||||
|
|
||||||
drawFaceOutline(player, faceOutline, topFaceY + 1.0, redColor, cylinder)
|
|
||||||
|
|
||||||
// Draw bottom face outline in red (outer edges only)
|
|
||||||
val bottomFaceY = cylinder.y - cylinder.bottomHeight
|
|
||||||
|
|
||||||
drawFaceOutline(player, faceOutline, bottomFaceY.toDouble(), redColor, cylinder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -275,4 +303,90 @@ class VisualizerTask(private val landService: LandService) : Runnable {
|
||||||
player.spawnParticle(Particle.DUST, x, y, z, 1, 0.0, 0.0, 0.0, dustOptions)
|
player.spawnParticle(Particle.DUST, x, y, z, 1, 0.0, 0.0, 0.0, dustOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createDisplayForLand(player: Player, land: net.hareworks.hcu.lands.model.Land): DisplayController<TextDisplay> {
|
||||||
|
val position = calculateFaceAttachmentPoint(player, land)
|
||||||
|
val controller = displayService!!.createTextDisplay(position)
|
||||||
|
controller.applyEntityUpdate { display ->
|
||||||
|
display.text(net.kyori.adventure.text.Component.text(land.name))
|
||||||
|
display.billboard = org.bukkit.entity.Display.Billboard.VERTICAL
|
||||||
|
}
|
||||||
|
controller.show(player)
|
||||||
|
logger.info("[LandsDisplay] Display for '${land.name}' made visible to ${player.name} at ${position.blockX}, ${position.blockY}, ${position.blockZ}")
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateDisplayPosition(controller: DisplayController<TextDisplay>, player: Player, land: net.hareworks.hcu.lands.model.Land) {
|
||||||
|
val newPosition = calculateFaceAttachmentPoint(player, land)
|
||||||
|
val currentLoc = controller.display.location
|
||||||
|
|
||||||
|
// Only update if position changed significantly (>0.5 blocks)
|
||||||
|
if (currentLoc.distanceSquared(newPosition) > 0.25) {
|
||||||
|
controller.applyEntityUpdate { display ->
|
||||||
|
display.teleport(newPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateFaceAttachmentPoint(player: Player, land: net.hareworks.hcu.lands.model.Land): Location {
|
||||||
|
val bbox = land.getBoundingBox()
|
||||||
|
val px = player.location.x
|
||||||
|
val py = player.location.y
|
||||||
|
val pz = player.location.z
|
||||||
|
|
||||||
|
// Check if player is within XZ footprint
|
||||||
|
val withinX = px >= bbox.minX && px <= bbox.maxX + 1.0
|
||||||
|
val withinZ = pz >= bbox.minZ && pz <= bbox.maxZ + 1.0
|
||||||
|
|
||||||
|
if (withinX && withinZ) {
|
||||||
|
// Player is above or below the land → use top/bottom face
|
||||||
|
return if (py > bbox.maxY + 1.0) {
|
||||||
|
// Attach to top face
|
||||||
|
Location(
|
||||||
|
player.world,
|
||||||
|
px.coerceIn(bbox.minX.toDouble(), bbox.maxX + 1.0),
|
||||||
|
bbox.maxY + 1.1,
|
||||||
|
pz.coerceIn(bbox.minZ.toDouble(), bbox.maxZ + 1.0)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Attach to bottom face
|
||||||
|
Location(
|
||||||
|
player.world,
|
||||||
|
px.coerceIn(bbox.minX.toDouble(), bbox.maxX + 1.0),
|
||||||
|
bbox.minY - 0.1,
|
||||||
|
pz.coerceIn(bbox.minZ.toDouble(), bbox.maxZ + 1.0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player is outside XZ footprint → use nearest vertical face
|
||||||
|
val clampedX = px.coerceIn(bbox.minX.toDouble(), bbox.maxX + 1.0)
|
||||||
|
val clampedY = py.coerceIn(bbox.minY.toDouble(), bbox.maxY + 1.0)
|
||||||
|
val clampedZ = pz.coerceIn(bbox.minZ.toDouble(), bbox.maxZ + 1.0)
|
||||||
|
|
||||||
|
// Determine which face is nearest
|
||||||
|
val distToWest = abs(px - bbox.minX)
|
||||||
|
val distToEast = abs(px - (bbox.maxX + 1.0))
|
||||||
|
val distToNorth = abs(pz - bbox.minZ)
|
||||||
|
val distToSouth = abs(pz - (bbox.maxZ + 1.0))
|
||||||
|
|
||||||
|
val minDist = minOf(distToWest, distToEast, distToNorth, distToSouth)
|
||||||
|
|
||||||
|
return when (minDist) {
|
||||||
|
distToWest -> Location(player.world, bbox.minX - 0.1, clampedY, clampedZ)
|
||||||
|
distToEast -> Location(player.world, bbox.maxX + 1.1, clampedY, clampedZ)
|
||||||
|
distToNorth -> Location(player.world, clampedX, clampedY, bbox.minZ - 0.1)
|
||||||
|
else -> Location(player.world, clampedX, clampedY, bbox.maxZ + 1.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cleanupDisplaysForPlayer(playerId: UUID) {
|
||||||
|
val count = displayControllers[playerId]?.size ?: 0
|
||||||
|
displayControllers[playerId]?.values?.forEach { it.destroy() }
|
||||||
|
displayControllers.remove(playerId)
|
||||||
|
if (count > 0) {
|
||||||
|
val playerName = Bukkit.getPlayer(playerId)?.name ?: playerId.toString()
|
||||||
|
logger.info("[LandsDisplay] Cleaned up $count display(s) for player $playerName")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user