feat: ファクション所有とドラフト・アクティベート
This commit is contained in:
parent
2621d28e67
commit
767f974228
2
Lands
2
Lands
|
|
@ -1 +1 @@
|
|||
Subproject commit d27057dc89e228ce120c5b5b4534b3c130e8480a
|
||||
Subproject commit 0f432b0e89614bc07bd710423284da5e0228e25a
|
||||
|
|
@ -46,7 +46,14 @@ class LandSectorPlugin : JavaPlugin() {
|
|||
return
|
||||
}
|
||||
|
||||
val service = SectorService(db)
|
||||
val landsPlugin = server.pluginManager.getPlugin("lands") as? net.hareworks.hcu.lands.App
|
||||
val landService = landsPlugin?.landService
|
||||
if (landService == null) {
|
||||
logger.severe("Lands plugin or service not ready.")
|
||||
return
|
||||
}
|
||||
|
||||
val service = SectorService(db, landService)
|
||||
try {
|
||||
service.init()
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -63,7 +70,8 @@ class LandSectorPlugin : JavaPlugin() {
|
|||
|
||||
val selService = selectionService
|
||||
if (selService != null) {
|
||||
server.pluginManager.registerEvents(SectorListener(this, service, pIdService, selService), this)
|
||||
val factionService = net.hareworks.hcu.faction.service.FactionService()
|
||||
server.pluginManager.registerEvents(SectorListener(this, service, pIdService, selService, factionService), this)
|
||||
server.pluginManager.registerEvents(net.hareworks.hcu.landsector.listener.SelectionListener(this, selService, service), this)
|
||||
|
||||
// Schedule visualization task
|
||||
|
|
|
|||
|
|
@ -36,8 +36,13 @@ class LandSectorCommand(private val landSectorPlugin: LandSectorPlugin) {
|
|||
integer("sectorId") {
|
||||
executes {
|
||||
val id = argument<Int>("sectorId")
|
||||
sender.sendMessage(Component.text("Activation for Sector #$id pending implementation.", NamedTextColor.YELLOW))
|
||||
// TODO: Validate selection and lock in
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.activateSector(id)) {
|
||||
sender.sendMessage(Component.text("Sector #$id activated and land secured!", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Failed to activate sector #$id (Already active or empty parts?).", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +123,45 @@ class LandSectorCommand(private val landSectorPlugin: LandSectorPlugin) {
|
|||
}
|
||||
}
|
||||
|
||||
literal("transfer") {
|
||||
integer("sectorId") {
|
||||
integer("targetActorId") {
|
||||
executes {
|
||||
val sectorId = argument<Int>("sectorId")
|
||||
val targetActorId = argument<Int>("targetActorId")
|
||||
val player = sender as? Player ?: return@executes
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.transferSector(sectorId, targetActorId)) {
|
||||
sender.sendMessage(Component.text("Transfer successful!", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Transfer failed.", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal("range") {
|
||||
literal("delete") {
|
||||
integer("sectorId") {
|
||||
integer("rangeIndex") {
|
||||
executes {
|
||||
val sectorId = argument<Int>("sectorId")
|
||||
val rangeIndex = argument<Int>("rangeIndex")
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.deleteRange(sectorId, rangeIndex)) {
|
||||
sender.sendMessage(Component.text("Range #$rangeIndex in Sector #$sectorId deleted.", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Failed to delete range. (Invalid index or sector already confirmed?)", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal("delete") {
|
||||
integer("id") {
|
||||
executes {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package net.hareworks.hcu.landsector.database
|
||||
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.hareworks.hcu.lands.model.LandData
|
||||
import org.jetbrains.exposed.v1.core.Table
|
||||
|
||||
object SectorDraftsTable : Table("sector_drafts") {
|
||||
val sectorId = integer("sector_id").references(SectorsTable.id)
|
||||
val data = text("data").transform(
|
||||
{ json -> Json.decodeFromString(LandData.serializer(), json) },
|
||||
{ value -> Json.encodeToString(LandData.serializer(), value) }
|
||||
)
|
||||
|
||||
override val primaryKey = PrimaryKey(sectorId)
|
||||
}
|
||||
|
|
@ -11,20 +11,7 @@ object SectorsTable : Table("land_sectors") {
|
|||
val z = integer("z")
|
||||
val hp = integer("hp").default(1000)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
}
|
||||
|
||||
object SectorRangesTable : Table("land_sector_ranges") {
|
||||
val id = integer("id").autoIncrement()
|
||||
val sectorId = integer("sector_id").references(SectorsTable.id)
|
||||
val type = varchar("type", 16)
|
||||
val x1 = integer("x1")
|
||||
val y1 = integer("y1")
|
||||
val z1 = integer("z1")
|
||||
val x2 = integer("x2")
|
||||
val y2 = integer("y2")
|
||||
val z2 = integer("z2")
|
||||
val isSneaking = bool("is_sneaking")
|
||||
val landId = integer("land_id").nullable()
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,15 @@ import net.hareworks.hcu.landsector.service.SelectionService
|
|||
import net.kyori.adventure.text.event.ClickEvent
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
|
||||
import net.hareworks.hcu.faction.service.FactionService
|
||||
import net.hareworks.hcu.faction.database.schema.FactionRole
|
||||
|
||||
class SectorListener(
|
||||
private val plugin: LandSectorPlugin,
|
||||
private val sectorService: SectorService,
|
||||
private val playerIdService: PlayerIdService,
|
||||
private val selectionService: SelectionService
|
||||
private val selectionService: SelectionService,
|
||||
private val factionService: FactionService
|
||||
) : Listener {
|
||||
|
||||
@EventHandler
|
||||
|
|
@ -216,7 +220,33 @@ class SectorListener(
|
|||
if (pEntry == null) return
|
||||
val sector = sectorService.getSector(sectorId) ?: return
|
||||
|
||||
if (sector.ownerActorId != pEntry.actorId) {
|
||||
// Resolve Owner Name
|
||||
var ownerName = "Unknown"
|
||||
// Try getting faction name
|
||||
val factionName = factionService.getFactionName(sector.ownerActorId)
|
||||
if (factionName != null) {
|
||||
ownerName = "Faction: $factionName"
|
||||
} else {
|
||||
// Assume player. Ideally resolve UUID from ActorID, but for now ID or fallback
|
||||
// We don't have direct Player Actor ID -> Name cache here easily without querying DB or UUID service
|
||||
// Just show ID for now to be safe, or "Player #ID"
|
||||
ownerName = "Player #${sector.ownerActorId}"
|
||||
}
|
||||
|
||||
val canManage = if (sector.ownerActorId == pEntry.actorId) {
|
||||
true
|
||||
} else {
|
||||
// Or if owner is my faction and I am EXEC/OWNER
|
||||
val myFaction = factionService.getFactionOfPlayer(player.uniqueId)
|
||||
if (myFaction == sector.ownerActorId) {
|
||||
val myRole = factionService.getRole(myFaction, player.uniqueId)
|
||||
myRole == FactionRole.OWNER || myRole == FactionRole.EXEC
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (!canManage) {
|
||||
player.sendMessage(Component.text("You are not the owner of this sector.", NamedTextColor.RED))
|
||||
return
|
||||
}
|
||||
|
|
@ -230,7 +260,21 @@ class SectorListener(
|
|||
|
||||
// Build Page Content
|
||||
val content = Component.text()
|
||||
.append(Component.text("Sector Core @ ${sector.x},${sector.y},${sector.z}\n\n", NamedTextColor.BLACK))
|
||||
.append(Component.text("Sector Core @ ${sector.x},${sector.y},${sector.z}\n", NamedTextColor.BLACK))
|
||||
.append(Component.text("Owner: $ownerName\n\n", NamedTextColor.DARK_GRAY))
|
||||
|
||||
// Transfer Check
|
||||
val myFaction = factionService.getFactionOfPlayer(player.uniqueId)
|
||||
if (myFaction != null && sector.ownerActorId != myFaction) {
|
||||
val myRole = factionService.getRole(myFaction, player.uniqueId)
|
||||
if (myRole == FactionRole.OWNER || myRole == FactionRole.EXEC) {
|
||||
content.append(
|
||||
Component.text("[Transfer to Faction]\n\n", NamedTextColor.GOLD)
|
||||
.clickEvent(ClickEvent.runCommand("/landsector transfer $sectorId $myFaction"))
|
||||
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(Component.text("Click to transfer ownership to your faction")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Actions Row 1
|
||||
content.append(
|
||||
|
|
@ -260,6 +304,12 @@ class SectorListener(
|
|||
content.append(Component.text("Parts:", NamedTextColor.BLACK))
|
||||
ranges.forEach { range ->
|
||||
content.append(Component.text("\n- [${range.id}] ${range.type}", NamedTextColor.DARK_GRAY))
|
||||
content.append(Component.text(" "))
|
||||
content.append(
|
||||
Component.text("[x]", NamedTextColor.RED)
|
||||
.clickEvent(ClickEvent.runCommand("/landsector range delete $sectorId ${range.id}"))
|
||||
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(Component.text("Click to delete range")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ data class Sector(
|
|||
val x: Int,
|
||||
val y: Int,
|
||||
val z: Int,
|
||||
val hp: Int
|
||||
val hp: Int,
|
||||
val landId: Int? = null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package net.hareworks.hcu.landsector.service
|
||||
|
||||
import net.hareworks.hcu.landsector.database.SectorDraftsTable
|
||||
import net.hareworks.hcu.landsector.database.SectorsTable
|
||||
import net.hareworks.hcu.landsector.database.SectorRangesTable
|
||||
// SectorRangesTable removed
|
||||
import net.hareworks.hcu.landsector.model.Sector
|
||||
import net.hareworks.hcu.landsector.model.SectorRange
|
||||
import net.hareworks.hcu.landsector.model.SelectionMode
|
||||
|
|
@ -17,15 +18,21 @@ import org.jetbrains.exposed.v1.jdbc.deleteWhere
|
|||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class SectorService(private val database: Database) {
|
||||
// ... class definition ...
|
||||
class SectorService(private val database: Database, private val landService: net.hareworks.hcu.lands.service.LandService) {
|
||||
|
||||
private val hpCache = ConcurrentHashMap<Int, Int>()
|
||||
private val dirtySet = ConcurrentHashMap.newKeySet<Int>()
|
||||
private val sectorsCache = ConcurrentHashMap<Int, Sector>()
|
||||
|
||||
// Draft storage: SectorId -> Land (Draft)
|
||||
private val draftLands = ConcurrentHashMap<Int, net.hareworks.hcu.lands.model.Land>()
|
||||
|
||||
fun init() {
|
||||
transaction(database) {
|
||||
SchemaUtils.createMissingTablesAndColumns(SectorsTable, SectorRangesTable)
|
||||
SchemaUtils.createMissingTablesAndColumns(SectorsTable, SectorDraftsTable)
|
||||
|
||||
// Load Sectors
|
||||
SectorsTable.selectAll().forEach {
|
||||
val id = it[SectorsTable.id]
|
||||
val sector = Sector(
|
||||
|
|
@ -35,10 +42,28 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
it[SectorsTable.hp]
|
||||
it[SectorsTable.hp],
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
sectorsCache[id] = sector
|
||||
}
|
||||
|
||||
// Load Drafts
|
||||
SectorDraftsTable.selectAll().forEach {
|
||||
val sId = it[SectorDraftsTable.sectorId]
|
||||
val data = it[SectorDraftsTable.data]
|
||||
val sector = sectorsCache[sId]
|
||||
|
||||
if (sector != null && sector.landId == null) {
|
||||
draftLands[sId] = net.hareworks.hcu.lands.model.Land(
|
||||
id = -1,
|
||||
name = "Draft Sector $sId",
|
||||
actorId = sector.ownerActorId,
|
||||
world = sector.world,
|
||||
data = data
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,11 +76,29 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.y] = y
|
||||
it[SectorsTable.z] = z
|
||||
it[SectorsTable.hp] = 1000
|
||||
it[SectorsTable.landId] = null
|
||||
}[SectorsTable.id]
|
||||
|
||||
hpCache[id] = 1000
|
||||
val sector = Sector(id, ownerActorId, world, x, y, z, 1000)
|
||||
val sector = Sector(id, ownerActorId, world, x, y, z, 1000, null)
|
||||
sectorsCache[id] = sector
|
||||
|
||||
// Initialize draft land
|
||||
val draftLand = net.hareworks.hcu.lands.model.Land(
|
||||
id = -1, // Dummy ID
|
||||
name = "Draft Sector $id",
|
||||
actorId = ownerActorId,
|
||||
world = world,
|
||||
data = net.hareworks.hcu.lands.model.LandData()
|
||||
)
|
||||
draftLands[id] = draftLand
|
||||
|
||||
// Persist draft
|
||||
SectorDraftsTable.insert {
|
||||
it[SectorDraftsTable.sectorId] = id
|
||||
it[SectorDraftsTable.data] = draftLand.data
|
||||
}
|
||||
|
||||
sector
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +120,8 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
it[SectorsTable.hp]
|
||||
it[SectorsTable.hp],
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +182,7 @@ class SectorService(private val database: Database) {
|
|||
val sector = transaction(database) {
|
||||
val record = SectorsTable.selectAll().andWhere { SectorsTable.id eq id }.singleOrNull() ?: return@transaction null
|
||||
|
||||
SectorRangesTable.deleteWhere { SectorRangesTable.sectorId eq id }
|
||||
SectorDraftsTable.deleteWhere { SectorDraftsTable.sectorId eq id }
|
||||
SectorsTable.deleteWhere { SectorsTable.id eq id }
|
||||
|
||||
Sector(
|
||||
|
|
@ -148,7 +192,8 @@ class SectorService(private val database: Database) {
|
|||
record[SectorsTable.x],
|
||||
record[SectorsTable.y],
|
||||
record[SectorsTable.z],
|
||||
record[SectorsTable.hp]
|
||||
record[SectorsTable.hp],
|
||||
record[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +201,11 @@ class SectorService(private val database: Database) {
|
|||
hpCache.remove(id)
|
||||
dirtySet.remove(id)
|
||||
sectorsCache.remove(id)
|
||||
draftLands.remove(id)
|
||||
|
||||
if (sector.landId != null) {
|
||||
landService.deleteLand(sector.landId)
|
||||
}
|
||||
}
|
||||
|
||||
return sector
|
||||
|
|
@ -203,7 +253,8 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
hp
|
||||
hp,
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -226,46 +277,195 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
hp
|
||||
hp,
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addRange(sectorId: Int, mode: SelectionMode, x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int, isSneaking: Boolean): SectorRange {
|
||||
return transaction(database) {
|
||||
val id = SectorRangesTable.insert {
|
||||
it[SectorRangesTable.sectorId] = sectorId
|
||||
it[SectorRangesTable.type] = mode.name
|
||||
it[SectorRangesTable.x1] = x1
|
||||
it[SectorRangesTable.y1] = y1
|
||||
it[SectorRangesTable.z1] = z1
|
||||
it[SectorRangesTable.x2] = x2
|
||||
it[SectorRangesTable.y2] = y2
|
||||
it[SectorRangesTable.z2] = z2
|
||||
it[SectorRangesTable.isSneaking] = isSneaking
|
||||
}[SectorRangesTable.id]
|
||||
fun addRange(sectorId: Int, mode: SelectionMode, x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int, isSneaking: Boolean): Any? {
|
||||
val sector = getSector(sectorId) ?: return null
|
||||
|
||||
SectorRange(id, sectorId, mode, x1, y1, z1, x2, y2, z2, isSneaking)
|
||||
// Cannot edit if already confirmed
|
||||
if (sector.landId != null) return null
|
||||
|
||||
val draft = draftLands.computeIfAbsent(sectorId) {
|
||||
net.hareworks.hcu.lands.model.Land(
|
||||
id = -1,
|
||||
name = "Draft Sector $sectorId",
|
||||
actorId = sector.ownerActorId,
|
||||
world = sector.world,
|
||||
data = net.hareworks.hcu.lands.model.LandData()
|
||||
)
|
||||
}
|
||||
|
||||
val shape = when (mode) {
|
||||
SelectionMode.CUBOID -> {
|
||||
net.hareworks.hcu.lands.model.Shape.Cuboid(x1, y1, z1, x2, y2, z2)
|
||||
}
|
||||
SelectionMode.CYLINDER -> {
|
||||
// Convert bounds to cylinder params
|
||||
// Approximating from bounding box
|
||||
val minX = minOf(x1, x2)
|
||||
val maxX = maxOf(x1, x2)
|
||||
val minZ = minOf(z1, z2)
|
||||
val maxZ = maxOf(z1, z2)
|
||||
val minY = minOf(y1, y2)
|
||||
val maxY = maxOf(y1, y2)
|
||||
|
||||
val cx = (minX + maxX) / 2
|
||||
val cz = (minZ + maxZ) / 2
|
||||
val cy = (minY + maxY) / 2
|
||||
|
||||
// Radius is max dist from center to edge of bounding box in X or Z
|
||||
val radiusX = (maxX - minX) / 2.0
|
||||
val radiusZ = (maxZ - minZ) / 2.0
|
||||
val radius = maxOf(radiusX, radiusZ)
|
||||
|
||||
val height = maxY - minY + 1
|
||||
val bottom = (cy - minY)
|
||||
val top = (maxY - cy)
|
||||
|
||||
net.hareworks.hcu.lands.model.Shape.Cylinder(cx, cy, cz, radius, bottom, top)
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
// Use LandService modify pattern or direct replacement since stored in local map
|
||||
val newParts = draft.data.parts.toMutableList()
|
||||
newParts.add(shape)
|
||||
val newDraft = draft.copy(data = draft.data.copy(parts = newParts))
|
||||
draftLands[sectorId] = newDraft
|
||||
|
||||
// Persist change
|
||||
transaction(database) {
|
||||
// Check if exists first? Or upsert if supported easily.
|
||||
// We know it exists from creation, but safety check.
|
||||
val count = SectorDraftsTable.update({ SectorDraftsTable.sectorId eq sectorId }) {
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
if (count == 0) {
|
||||
SectorDraftsTable.insert {
|
||||
it[SectorDraftsTable.sectorId] = sectorId
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shape
|
||||
}
|
||||
|
||||
fun getRanges(sectorId: Int): List<SectorRange> {
|
||||
val sector = getSector(sectorId) ?: return emptyList()
|
||||
|
||||
val land = if (sector.landId != null) {
|
||||
landService.getLand(sector.landId)
|
||||
} else {
|
||||
draftLands[sectorId]
|
||||
} ?: return emptyList()
|
||||
|
||||
// Convert Shapes back to SectorRanges for UI compatibility
|
||||
return land.data.parts.mapIndexed { index, shape ->
|
||||
when (shape) {
|
||||
is net.hareworks.hcu.lands.model.Shape.Cuboid -> {
|
||||
SectorRange(
|
||||
index, // Use index as ID for UI
|
||||
sectorId,
|
||||
SelectionMode.CUBOID,
|
||||
shape.x1, shape.y1, shape.z1,
|
||||
shape.x2, shape.y2, shape.z2,
|
||||
false
|
||||
)
|
||||
}
|
||||
is net.hareworks.hcu.lands.model.Shape.Cylinder -> {
|
||||
SectorRange(
|
||||
index,
|
||||
sectorId,
|
||||
SelectionMode.CYLINDER,
|
||||
shape.x, shape.y, shape.z,
|
||||
shape.x, shape.y, shape.z,
|
||||
false
|
||||
)
|
||||
}
|
||||
// Default fallback for unknown shapes if any (shouldn't happen with current limited types)
|
||||
else -> SectorRange(index, sectorId, SelectionMode.CUBOID, 0,0,0,0,0,0, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteRange(sectorId: Int, rangeIndex: Int): Boolean {
|
||||
val sector = getSector(sectorId) ?: return false
|
||||
if (sector.landId != null) return false // Cannot edit confirmed
|
||||
|
||||
val draft = draftLands[sectorId] ?: return false
|
||||
if (rangeIndex < 0 || rangeIndex >= draft.data.parts.size) return false
|
||||
|
||||
val newParts = draft.data.parts.toMutableList()
|
||||
newParts.removeAt(rangeIndex)
|
||||
val newDraft = draft.copy(data = draft.data.copy(parts = newParts))
|
||||
draftLands[sectorId] = newDraft
|
||||
|
||||
// Persist change
|
||||
transaction(database) {
|
||||
SectorDraftsTable.update({ SectorDraftsTable.sectorId eq sectorId }) {
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun activateSector(sectorId: Int): Boolean {
|
||||
val sector = getSector(sectorId) ?: return false
|
||||
if (sector.landId != null) return false // Already active
|
||||
|
||||
val draft = draftLands[sectorId] ?: return false
|
||||
if (draft.data.parts.isEmpty()) return false
|
||||
|
||||
val landName = "Sector_${sectorId}_${System.currentTimeMillis()}"
|
||||
|
||||
if (landService.createLand(landName, draft.actorId, draft.world)) {
|
||||
// Find the created land to get ID
|
||||
val lands = landService.findLandsByName(landName)
|
||||
val createdLand = lands.firstOrNull() ?: return false
|
||||
|
||||
// Update parts
|
||||
landService.modifyLand(createdLand.id) { data ->
|
||||
data.copy(parts = draft.data.parts)
|
||||
}
|
||||
|
||||
// Update Sector DB & Delete Draft
|
||||
transaction(database) {
|
||||
SectorsTable.update({ SectorsTable.id eq sectorId }) {
|
||||
it[SectorsTable.landId] = createdLand.id
|
||||
}
|
||||
SectorDraftsTable.deleteWhere { SectorDraftsTable.sectorId eq sectorId }
|
||||
}
|
||||
|
||||
// Update cache & Clear draft
|
||||
sectorsCache[sectorId] = sector.copy(landId = createdLand.id)
|
||||
draftLands.remove(sectorId)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun transferSector(id: Int, newOwnerActorId: Int): Boolean {
|
||||
return transaction(database) {
|
||||
SectorRangesTable.selectAll().andWhere { SectorRangesTable.sectorId eq sectorId }.map {
|
||||
SectorRange(
|
||||
it[SectorRangesTable.id],
|
||||
it[SectorRangesTable.sectorId],
|
||||
SelectionMode.valueOf(it[SectorRangesTable.type]),
|
||||
it[SectorRangesTable.x1],
|
||||
it[SectorRangesTable.y1],
|
||||
it[SectorRangesTable.z1],
|
||||
it[SectorRangesTable.x2],
|
||||
it[SectorRangesTable.y2],
|
||||
it[SectorRangesTable.z2],
|
||||
it[SectorRangesTable.isSneaking]
|
||||
)
|
||||
val updated = SectorsTable.update({ SectorsTable.id eq id }) {
|
||||
it[ownerActorId] = newOwnerActorId
|
||||
}
|
||||
if (updated > 0) {
|
||||
// Update cache
|
||||
val current = sectorsCache[id]
|
||||
if (current != null) {
|
||||
sectorsCache[id] = current.copy(ownerActorId = newOwnerActorId)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,14 @@ class LandSectorPlugin : JavaPlugin() {
|
|||
return
|
||||
}
|
||||
|
||||
val service = SectorService(db)
|
||||
val landsPlugin = server.pluginManager.getPlugin("lands") as? net.hareworks.hcu.lands.App
|
||||
val landService = landsPlugin?.landService
|
||||
if (landService == null) {
|
||||
logger.severe("Lands plugin or service not ready.")
|
||||
return
|
||||
}
|
||||
|
||||
val service = SectorService(db, landService)
|
||||
try {
|
||||
service.init()
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -63,7 +70,8 @@ class LandSectorPlugin : JavaPlugin() {
|
|||
|
||||
val selService = selectionService
|
||||
if (selService != null) {
|
||||
server.pluginManager.registerEvents(SectorListener(this, service, pIdService, selService), this)
|
||||
val factionService = net.hareworks.hcu.faction.service.FactionService()
|
||||
server.pluginManager.registerEvents(SectorListener(this, service, pIdService, selService, factionService), this)
|
||||
server.pluginManager.registerEvents(net.hareworks.hcu.landsector.listener.SelectionListener(this, selService, service), this)
|
||||
|
||||
// Schedule visualization task
|
||||
|
|
|
|||
|
|
@ -36,8 +36,13 @@ class LandSectorCommand(private val landSectorPlugin: LandSectorPlugin) {
|
|||
integer("sectorId") {
|
||||
executes {
|
||||
val id = argument<Int>("sectorId")
|
||||
sender.sendMessage(Component.text("Activation for Sector #$id pending implementation.", NamedTextColor.YELLOW))
|
||||
// TODO: Validate selection and lock in
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.activateSector(id)) {
|
||||
sender.sendMessage(Component.text("Sector #$id activated and land secured!", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Failed to activate sector #$id (Already active or empty parts?).", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +123,45 @@ class LandSectorCommand(private val landSectorPlugin: LandSectorPlugin) {
|
|||
}
|
||||
}
|
||||
|
||||
literal("transfer") {
|
||||
integer("sectorId") {
|
||||
integer("targetActorId") {
|
||||
executes {
|
||||
val sectorId = argument<Int>("sectorId")
|
||||
val targetActorId = argument<Int>("targetActorId")
|
||||
val player = sender as? Player ?: return@executes
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.transferSector(sectorId, targetActorId)) {
|
||||
sender.sendMessage(Component.text("Transfer successful!", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Transfer failed.", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal("range") {
|
||||
literal("delete") {
|
||||
integer("sectorId") {
|
||||
integer("rangeIndex") {
|
||||
executes {
|
||||
val sectorId = argument<Int>("sectorId")
|
||||
val rangeIndex = argument<Int>("rangeIndex")
|
||||
val service = landSectorPlugin.sectorService ?: return@executes
|
||||
|
||||
if (service.deleteRange(sectorId, rangeIndex)) {
|
||||
sender.sendMessage(Component.text("Range #$rangeIndex in Sector #$sectorId deleted.", NamedTextColor.GREEN))
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Failed to delete range. (Invalid index or sector already confirmed?)", NamedTextColor.RED))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal("delete") {
|
||||
integer("id") {
|
||||
executes {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package net.hareworks.hcu.landsector.database
|
||||
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.hareworks.hcu.lands.model.LandData
|
||||
import org.jetbrains.exposed.v1.core.Table
|
||||
|
||||
object SectorDraftsTable : Table("sector_drafts") {
|
||||
val sectorId = integer("sector_id").references(SectorsTable.id)
|
||||
val data = text("data").transform(
|
||||
{ json -> Json.decodeFromString(LandData.serializer(), json) },
|
||||
{ value -> Json.encodeToString(LandData.serializer(), value) }
|
||||
)
|
||||
|
||||
override val primaryKey = PrimaryKey(sectorId)
|
||||
}
|
||||
|
|
@ -11,20 +11,7 @@ object SectorsTable : Table("land_sectors") {
|
|||
val z = integer("z")
|
||||
val hp = integer("hp").default(1000)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
}
|
||||
|
||||
object SectorRangesTable : Table("land_sector_ranges") {
|
||||
val id = integer("id").autoIncrement()
|
||||
val sectorId = integer("sector_id").references(SectorsTable.id)
|
||||
val type = varchar("type", 16)
|
||||
val x1 = integer("x1")
|
||||
val y1 = integer("y1")
|
||||
val z1 = integer("z1")
|
||||
val x2 = integer("x2")
|
||||
val y2 = integer("y2")
|
||||
val z2 = integer("z2")
|
||||
val isSneaking = bool("is_sneaking")
|
||||
val landId = integer("land_id").nullable()
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,15 @@ import net.hareworks.hcu.landsector.service.SelectionService
|
|||
import net.kyori.adventure.text.event.ClickEvent
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
|
||||
import net.hareworks.hcu.faction.service.FactionService
|
||||
import net.hareworks.hcu.faction.database.schema.FactionRole
|
||||
|
||||
class SectorListener(
|
||||
private val plugin: LandSectorPlugin,
|
||||
private val sectorService: SectorService,
|
||||
private val playerIdService: PlayerIdService,
|
||||
private val selectionService: SelectionService
|
||||
private val selectionService: SelectionService,
|
||||
private val factionService: FactionService
|
||||
) : Listener {
|
||||
|
||||
@EventHandler
|
||||
|
|
@ -216,7 +220,33 @@ class SectorListener(
|
|||
if (pEntry == null) return
|
||||
val sector = sectorService.getSector(sectorId) ?: return
|
||||
|
||||
if (sector.ownerActorId != pEntry.actorId) {
|
||||
// Resolve Owner Name
|
||||
var ownerName = "Unknown"
|
||||
// Try getting faction name
|
||||
val factionName = factionService.getFactionName(sector.ownerActorId)
|
||||
if (factionName != null) {
|
||||
ownerName = "Faction: $factionName"
|
||||
} else {
|
||||
// Assume player. Ideally resolve UUID from ActorID, but for now ID or fallback
|
||||
// We don't have direct Player Actor ID -> Name cache here easily without querying DB or UUID service
|
||||
// Just show ID for now to be safe, or "Player #ID"
|
||||
ownerName = "Player #${sector.ownerActorId}"
|
||||
}
|
||||
|
||||
val canManage = if (sector.ownerActorId == pEntry.actorId) {
|
||||
true
|
||||
} else {
|
||||
// Or if owner is my faction and I am EXEC/OWNER
|
||||
val myFaction = factionService.getFactionOfPlayer(player.uniqueId)
|
||||
if (myFaction == sector.ownerActorId) {
|
||||
val myRole = factionService.getRole(myFaction, player.uniqueId)
|
||||
myRole == FactionRole.OWNER || myRole == FactionRole.EXEC
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (!canManage) {
|
||||
player.sendMessage(Component.text("You are not the owner of this sector.", NamedTextColor.RED))
|
||||
return
|
||||
}
|
||||
|
|
@ -230,7 +260,21 @@ class SectorListener(
|
|||
|
||||
// Build Page Content
|
||||
val content = Component.text()
|
||||
.append(Component.text("Sector Core @ ${sector.x},${sector.y},${sector.z}\n\n", NamedTextColor.BLACK))
|
||||
.append(Component.text("Sector Core @ ${sector.x},${sector.y},${sector.z}\n", NamedTextColor.BLACK))
|
||||
.append(Component.text("Owner: $ownerName\n\n", NamedTextColor.DARK_GRAY))
|
||||
|
||||
// Transfer Check
|
||||
val myFaction = factionService.getFactionOfPlayer(player.uniqueId)
|
||||
if (myFaction != null && sector.ownerActorId != myFaction) {
|
||||
val myRole = factionService.getRole(myFaction, player.uniqueId)
|
||||
if (myRole == FactionRole.OWNER || myRole == FactionRole.EXEC) {
|
||||
content.append(
|
||||
Component.text("[Transfer to Faction]\n\n", NamedTextColor.GOLD)
|
||||
.clickEvent(ClickEvent.runCommand("/landsector transfer $sectorId $myFaction"))
|
||||
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(Component.text("Click to transfer ownership to your faction")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Actions Row 1
|
||||
content.append(
|
||||
|
|
@ -260,6 +304,12 @@ class SectorListener(
|
|||
content.append(Component.text("Parts:", NamedTextColor.BLACK))
|
||||
ranges.forEach { range ->
|
||||
content.append(Component.text("\n- [${range.id}] ${range.type}", NamedTextColor.DARK_GRAY))
|
||||
content.append(Component.text(" "))
|
||||
content.append(
|
||||
Component.text("[x]", NamedTextColor.RED)
|
||||
.clickEvent(ClickEvent.runCommand("/landsector range delete $sectorId ${range.id}"))
|
||||
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(Component.text("Click to delete range")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ data class Sector(
|
|||
val x: Int,
|
||||
val y: Int,
|
||||
val z: Int,
|
||||
val hp: Int
|
||||
val hp: Int,
|
||||
val landId: Int? = null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package net.hareworks.hcu.landsector.service
|
||||
|
||||
import net.hareworks.hcu.landsector.database.SectorDraftsTable
|
||||
import net.hareworks.hcu.landsector.database.SectorsTable
|
||||
import net.hareworks.hcu.landsector.database.SectorRangesTable
|
||||
// SectorRangesTable removed
|
||||
import net.hareworks.hcu.landsector.model.Sector
|
||||
import net.hareworks.hcu.landsector.model.SectorRange
|
||||
import net.hareworks.hcu.landsector.model.SelectionMode
|
||||
|
|
@ -17,15 +18,21 @@ import org.jetbrains.exposed.v1.jdbc.deleteWhere
|
|||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class SectorService(private val database: Database) {
|
||||
// ... class definition ...
|
||||
class SectorService(private val database: Database, private val landService: net.hareworks.hcu.lands.service.LandService) {
|
||||
|
||||
private val hpCache = ConcurrentHashMap<Int, Int>()
|
||||
private val dirtySet = ConcurrentHashMap.newKeySet<Int>()
|
||||
private val sectorsCache = ConcurrentHashMap<Int, Sector>()
|
||||
|
||||
// Draft storage: SectorId -> Land (Draft)
|
||||
private val draftLands = ConcurrentHashMap<Int, net.hareworks.hcu.lands.model.Land>()
|
||||
|
||||
fun init() {
|
||||
transaction(database) {
|
||||
SchemaUtils.createMissingTablesAndColumns(SectorsTable, SectorRangesTable)
|
||||
SchemaUtils.createMissingTablesAndColumns(SectorsTable, SectorDraftsTable)
|
||||
|
||||
// Load Sectors
|
||||
SectorsTable.selectAll().forEach {
|
||||
val id = it[SectorsTable.id]
|
||||
val sector = Sector(
|
||||
|
|
@ -35,10 +42,28 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
it[SectorsTable.hp]
|
||||
it[SectorsTable.hp],
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
sectorsCache[id] = sector
|
||||
}
|
||||
|
||||
// Load Drafts
|
||||
SectorDraftsTable.selectAll().forEach {
|
||||
val sId = it[SectorDraftsTable.sectorId]
|
||||
val data = it[SectorDraftsTable.data]
|
||||
val sector = sectorsCache[sId]
|
||||
|
||||
if (sector != null && sector.landId == null) {
|
||||
draftLands[sId] = net.hareworks.hcu.lands.model.Land(
|
||||
id = -1,
|
||||
name = "Draft Sector $sId",
|
||||
actorId = sector.ownerActorId,
|
||||
world = sector.world,
|
||||
data = data
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,11 +76,29 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.y] = y
|
||||
it[SectorsTable.z] = z
|
||||
it[SectorsTable.hp] = 1000
|
||||
it[SectorsTable.landId] = null
|
||||
}[SectorsTable.id]
|
||||
|
||||
hpCache[id] = 1000
|
||||
val sector = Sector(id, ownerActorId, world, x, y, z, 1000)
|
||||
val sector = Sector(id, ownerActorId, world, x, y, z, 1000, null)
|
||||
sectorsCache[id] = sector
|
||||
|
||||
// Initialize draft land
|
||||
val draftLand = net.hareworks.hcu.lands.model.Land(
|
||||
id = -1, // Dummy ID
|
||||
name = "Draft Sector $id",
|
||||
actorId = ownerActorId,
|
||||
world = world,
|
||||
data = net.hareworks.hcu.lands.model.LandData()
|
||||
)
|
||||
draftLands[id] = draftLand
|
||||
|
||||
// Persist draft
|
||||
SectorDraftsTable.insert {
|
||||
it[SectorDraftsTable.sectorId] = id
|
||||
it[SectorDraftsTable.data] = draftLand.data
|
||||
}
|
||||
|
||||
sector
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +120,8 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
it[SectorsTable.hp]
|
||||
it[SectorsTable.hp],
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +182,7 @@ class SectorService(private val database: Database) {
|
|||
val sector = transaction(database) {
|
||||
val record = SectorsTable.selectAll().andWhere { SectorsTable.id eq id }.singleOrNull() ?: return@transaction null
|
||||
|
||||
SectorRangesTable.deleteWhere { SectorRangesTable.sectorId eq id }
|
||||
SectorDraftsTable.deleteWhere { SectorDraftsTable.sectorId eq id }
|
||||
SectorsTable.deleteWhere { SectorsTable.id eq id }
|
||||
|
||||
Sector(
|
||||
|
|
@ -148,7 +192,8 @@ class SectorService(private val database: Database) {
|
|||
record[SectorsTable.x],
|
||||
record[SectorsTable.y],
|
||||
record[SectorsTable.z],
|
||||
record[SectorsTable.hp]
|
||||
record[SectorsTable.hp],
|
||||
record[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +201,11 @@ class SectorService(private val database: Database) {
|
|||
hpCache.remove(id)
|
||||
dirtySet.remove(id)
|
||||
sectorsCache.remove(id)
|
||||
draftLands.remove(id)
|
||||
|
||||
if (sector.landId != null) {
|
||||
landService.deleteLand(sector.landId)
|
||||
}
|
||||
}
|
||||
|
||||
return sector
|
||||
|
|
@ -203,7 +253,8 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
hp
|
||||
hp,
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -226,46 +277,195 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
hp
|
||||
hp,
|
||||
it[SectorsTable.landId]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addRange(sectorId: Int, mode: SelectionMode, x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int, isSneaking: Boolean): SectorRange {
|
||||
return transaction(database) {
|
||||
val id = SectorRangesTable.insert {
|
||||
it[SectorRangesTable.sectorId] = sectorId
|
||||
it[SectorRangesTable.type] = mode.name
|
||||
it[SectorRangesTable.x1] = x1
|
||||
it[SectorRangesTable.y1] = y1
|
||||
it[SectorRangesTable.z1] = z1
|
||||
it[SectorRangesTable.x2] = x2
|
||||
it[SectorRangesTable.y2] = y2
|
||||
it[SectorRangesTable.z2] = z2
|
||||
it[SectorRangesTable.isSneaking] = isSneaking
|
||||
}[SectorRangesTable.id]
|
||||
fun addRange(sectorId: Int, mode: SelectionMode, x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int, isSneaking: Boolean): Any? {
|
||||
val sector = getSector(sectorId) ?: return null
|
||||
|
||||
SectorRange(id, sectorId, mode, x1, y1, z1, x2, y2, z2, isSneaking)
|
||||
// Cannot edit if already confirmed
|
||||
if (sector.landId != null) return null
|
||||
|
||||
val draft = draftLands.computeIfAbsent(sectorId) {
|
||||
net.hareworks.hcu.lands.model.Land(
|
||||
id = -1,
|
||||
name = "Draft Sector $sectorId",
|
||||
actorId = sector.ownerActorId,
|
||||
world = sector.world,
|
||||
data = net.hareworks.hcu.lands.model.LandData()
|
||||
)
|
||||
}
|
||||
|
||||
val shape = when (mode) {
|
||||
SelectionMode.CUBOID -> {
|
||||
net.hareworks.hcu.lands.model.Shape.Cuboid(x1, y1, z1, x2, y2, z2)
|
||||
}
|
||||
SelectionMode.CYLINDER -> {
|
||||
// Convert bounds to cylinder params
|
||||
// Approximating from bounding box
|
||||
val minX = minOf(x1, x2)
|
||||
val maxX = maxOf(x1, x2)
|
||||
val minZ = minOf(z1, z2)
|
||||
val maxZ = maxOf(z1, z2)
|
||||
val minY = minOf(y1, y2)
|
||||
val maxY = maxOf(y1, y2)
|
||||
|
||||
val cx = (minX + maxX) / 2
|
||||
val cz = (minZ + maxZ) / 2
|
||||
val cy = (minY + maxY) / 2
|
||||
|
||||
// Radius is max dist from center to edge of bounding box in X or Z
|
||||
val radiusX = (maxX - minX) / 2.0
|
||||
val radiusZ = (maxZ - minZ) / 2.0
|
||||
val radius = maxOf(radiusX, radiusZ)
|
||||
|
||||
val height = maxY - minY + 1
|
||||
val bottom = (cy - minY)
|
||||
val top = (maxY - cy)
|
||||
|
||||
net.hareworks.hcu.lands.model.Shape.Cylinder(cx, cy, cz, radius, bottom, top)
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
// Use LandService modify pattern or direct replacement since stored in local map
|
||||
val newParts = draft.data.parts.toMutableList()
|
||||
newParts.add(shape)
|
||||
val newDraft = draft.copy(data = draft.data.copy(parts = newParts))
|
||||
draftLands[sectorId] = newDraft
|
||||
|
||||
// Persist change
|
||||
transaction(database) {
|
||||
// Check if exists first? Or upsert if supported easily.
|
||||
// We know it exists from creation, but safety check.
|
||||
val count = SectorDraftsTable.update({ SectorDraftsTable.sectorId eq sectorId }) {
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
if (count == 0) {
|
||||
SectorDraftsTable.insert {
|
||||
it[SectorDraftsTable.sectorId] = sectorId
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shape
|
||||
}
|
||||
|
||||
fun getRanges(sectorId: Int): List<SectorRange> {
|
||||
val sector = getSector(sectorId) ?: return emptyList()
|
||||
|
||||
val land = if (sector.landId != null) {
|
||||
landService.getLand(sector.landId)
|
||||
} else {
|
||||
draftLands[sectorId]
|
||||
} ?: return emptyList()
|
||||
|
||||
// Convert Shapes back to SectorRanges for UI compatibility
|
||||
return land.data.parts.mapIndexed { index, shape ->
|
||||
when (shape) {
|
||||
is net.hareworks.hcu.lands.model.Shape.Cuboid -> {
|
||||
SectorRange(
|
||||
index, // Use index as ID for UI
|
||||
sectorId,
|
||||
SelectionMode.CUBOID,
|
||||
shape.x1, shape.y1, shape.z1,
|
||||
shape.x2, shape.y2, shape.z2,
|
||||
false
|
||||
)
|
||||
}
|
||||
is net.hareworks.hcu.lands.model.Shape.Cylinder -> {
|
||||
SectorRange(
|
||||
index,
|
||||
sectorId,
|
||||
SelectionMode.CYLINDER,
|
||||
shape.x, shape.y, shape.z,
|
||||
shape.x, shape.y, shape.z,
|
||||
false
|
||||
)
|
||||
}
|
||||
// Default fallback for unknown shapes if any (shouldn't happen with current limited types)
|
||||
else -> SectorRange(index, sectorId, SelectionMode.CUBOID, 0,0,0,0,0,0, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteRange(sectorId: Int, rangeIndex: Int): Boolean {
|
||||
val sector = getSector(sectorId) ?: return false
|
||||
if (sector.landId != null) return false // Cannot edit confirmed
|
||||
|
||||
val draft = draftLands[sectorId] ?: return false
|
||||
if (rangeIndex < 0 || rangeIndex >= draft.data.parts.size) return false
|
||||
|
||||
val newParts = draft.data.parts.toMutableList()
|
||||
newParts.removeAt(rangeIndex)
|
||||
val newDraft = draft.copy(data = draft.data.copy(parts = newParts))
|
||||
draftLands[sectorId] = newDraft
|
||||
|
||||
// Persist change
|
||||
transaction(database) {
|
||||
SectorDraftsTable.update({ SectorDraftsTable.sectorId eq sectorId }) {
|
||||
it[SectorDraftsTable.data] = newDraft.data
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun activateSector(sectorId: Int): Boolean {
|
||||
val sector = getSector(sectorId) ?: return false
|
||||
if (sector.landId != null) return false // Already active
|
||||
|
||||
val draft = draftLands[sectorId] ?: return false
|
||||
if (draft.data.parts.isEmpty()) return false
|
||||
|
||||
val landName = "Sector_${sectorId}_${System.currentTimeMillis()}"
|
||||
|
||||
if (landService.createLand(landName, draft.actorId, draft.world)) {
|
||||
// Find the created land to get ID
|
||||
val lands = landService.findLandsByName(landName)
|
||||
val createdLand = lands.firstOrNull() ?: return false
|
||||
|
||||
// Update parts
|
||||
landService.modifyLand(createdLand.id) { data ->
|
||||
data.copy(parts = draft.data.parts)
|
||||
}
|
||||
|
||||
// Update Sector DB & Delete Draft
|
||||
transaction(database) {
|
||||
SectorsTable.update({ SectorsTable.id eq sectorId }) {
|
||||
it[SectorsTable.landId] = createdLand.id
|
||||
}
|
||||
SectorDraftsTable.deleteWhere { SectorDraftsTable.sectorId eq sectorId }
|
||||
}
|
||||
|
||||
// Update cache & Clear draft
|
||||
sectorsCache[sectorId] = sector.copy(landId = createdLand.id)
|
||||
draftLands.remove(sectorId)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun transferSector(id: Int, newOwnerActorId: Int): Boolean {
|
||||
return transaction(database) {
|
||||
SectorRangesTable.selectAll().andWhere { SectorRangesTable.sectorId eq sectorId }.map {
|
||||
SectorRange(
|
||||
it[SectorRangesTable.id],
|
||||
it[SectorRangesTable.sectorId],
|
||||
SelectionMode.valueOf(it[SectorRangesTable.type]),
|
||||
it[SectorRangesTable.x1],
|
||||
it[SectorRangesTable.y1],
|
||||
it[SectorRangesTable.z1],
|
||||
it[SectorRangesTable.x2],
|
||||
it[SectorRangesTable.y2],
|
||||
it[SectorRangesTable.z2],
|
||||
it[SectorRangesTable.isSneaking]
|
||||
)
|
||||
val updated = SectorsTable.update({ SectorsTable.id eq id }) {
|
||||
it[ownerActorId] = newOwnerActorId
|
||||
}
|
||||
if (updated > 0) {
|
||||
// Update cache
|
||||
val current = sectorsCache[id]
|
||||
if (current != null) {
|
||||
sectorsCache[id] = current.copy(ownerActorId = newOwnerActorId)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user