feat: 設置と削除・HP
This commit is contained in:
parent
5771e1b9d1
commit
ad4245d764
|
|
@ -59,10 +59,16 @@ class LandSectorPlugin : JavaPlugin() {
|
|||
|
||||
server.pluginManager.registerEvents(SectorListener(this, service, pIdService), this)
|
||||
|
||||
// Schedule auto-save every 5 minutes
|
||||
server.scheduler.runTaskTimerAsynchronously(this, Runnable {
|
||||
service.flushChanges()
|
||||
}, 6000L, 6000L)
|
||||
|
||||
logger.info("LandSector initialized with services.")
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
sectorService?.flushChanges()
|
||||
logger.info("LandSector plugin has been disabled!")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
package net.hareworks.hcu.landsector.command
|
||||
|
||||
import net.hareworks.hcu.landsector.LandSectorPlugin
|
||||
import net.hareworks.hcu.landsector.model.Sector
|
||||
import net.hareworks.kommand_lib.kommand
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.Shulker
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
|
||||
class LandSectorCommand(private val plugin: LandSectorPlugin) {
|
||||
class LandSectorCommand(private val landSectorPlugin: LandSectorPlugin) {
|
||||
fun register() {
|
||||
kommand(plugin) {
|
||||
kommand(landSectorPlugin) {
|
||||
command("landsector") {
|
||||
literal("give") {
|
||||
executes {
|
||||
|
|
@ -22,7 +26,7 @@ class LandSectorCommand(private val plugin: LandSectorPlugin) {
|
|||
val meta = item.itemMeta
|
||||
meta.displayName(Component.text("Sector Core", NamedTextColor.LIGHT_PURPLE))
|
||||
meta.persistentDataContainer.set(
|
||||
NamespacedKey(plugin, "component"),
|
||||
NamespacedKey(landSectorPlugin, "component"),
|
||||
PersistentDataType.STRING,
|
||||
"sector_core"
|
||||
)
|
||||
|
|
@ -32,6 +36,97 @@ class LandSectorCommand(private val plugin: LandSectorPlugin) {
|
|||
sender.sendMessage(Component.text("Gave 1 Sector Core.", NamedTextColor.GREEN))
|
||||
}
|
||||
}
|
||||
|
||||
literal("list") {
|
||||
executes {
|
||||
val player = sender as? Player ?: return@executes
|
||||
val service = landSectorPlugin.sectorService
|
||||
if (service == null) {
|
||||
sender.sendMessage(Component.text("SectorService not ready.", NamedTextColor.RED))
|
||||
return@executes
|
||||
}
|
||||
|
||||
val worldName = player.world.name
|
||||
val loc = player.location
|
||||
|
||||
val sectors = service.getAllSectors(worldName)
|
||||
.sortedBy { sector ->
|
||||
val sx = sector.x + 0.5
|
||||
val sy = sector.y + 1.0
|
||||
val sz = sector.z + 0.5
|
||||
|
||||
(loc.x - sx) * (loc.x - sx) +
|
||||
(loc.y - sy) * (loc.y - sy) +
|
||||
(loc.z - sz) * (loc.z - sz)
|
||||
}
|
||||
|
||||
sender.sendMessage(Component.text("=== Sector List (${sectors.size}) ===", NamedTextColor.GOLD))
|
||||
sectors.forEach { sector ->
|
||||
val distSq = (loc.x - (sector.x + 0.5)) * (loc.x - (sector.x + 0.5)) +
|
||||
(loc.y - (sector.y + 1.0)) * (loc.y - (sector.y + 1.0)) +
|
||||
(loc.z - (sector.z + 0.5)) * (loc.z - (sector.z + 0.5))
|
||||
val dist = Math.sqrt(distSq).toInt()
|
||||
|
||||
sender.sendMessage(
|
||||
Component.text()
|
||||
.append(Component.text("#${sector.id} ", NamedTextColor.YELLOW))
|
||||
.append(Component.text("(${sector.x}, ${sector.y}, ${sector.z}) ", NamedTextColor.GRAY))
|
||||
.append(Component.text("HP: ${sector.hp} ", NamedTextColor.RED))
|
||||
.append(Component.text("- ${dist}m", NamedTextColor.AQUA))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal("delete") {
|
||||
integer("id") {
|
||||
executes {
|
||||
val id = argument<Int>("id")
|
||||
val service = landSectorPlugin.sectorService
|
||||
if (service == null) {
|
||||
sender.sendMessage(Component.text("SectorService not ready.", NamedTextColor.RED))
|
||||
return@executes
|
||||
}
|
||||
|
||||
val sector = service.deleteSector(id)
|
||||
if (sector == null) {
|
||||
sender.sendMessage(Component.text("Sector #$id not found.", NamedTextColor.RED))
|
||||
} else {
|
||||
// Physical removal
|
||||
val world = Bukkit.getWorld(sector.world)
|
||||
if (world != null) {
|
||||
val x = sector.x
|
||||
val y = sector.y
|
||||
val z = sector.z
|
||||
|
||||
val blockBase = world.getBlockAt(x, y - 1, z)
|
||||
val blockTop = world.getBlockAt(x, y + 1, z)
|
||||
|
||||
if (blockBase.type == Material.BEDROCK) blockBase.type = Material.AIR
|
||||
if (blockTop.type == Material.BEDROCK) blockTop.type = Material.AIR
|
||||
|
||||
// Remove Entity
|
||||
val center = Location(world, x + 0.5, y.toDouble(), z + 0.5)
|
||||
if (center.chunk.isLoaded) {
|
||||
val entities = world.getNearbyEntities(center, 0.5, 0.5, 0.5)
|
||||
entities.forEach { entity ->
|
||||
if (entity is Shulker) {
|
||||
val key = NamespacedKey(landSectorPlugin, "sector_id")
|
||||
val sId = entity.persistentDataContainer.get(key, PersistentDataType.INTEGER)
|
||||
if (sId == id || sId == null) {
|
||||
entity.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(Component.text("Sector #$id deleted.", NamedTextColor.GREEN))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ object SectorsTable : Table("land_sectors") {
|
|||
val x = integer("x")
|
||||
val y = integer("y")
|
||||
val z = integer("z")
|
||||
val hp = integer("hp").default(1000)
|
||||
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,24 @@ import net.kyori.adventure.text.Component
|
|||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.Particle
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.EntityType
|
||||
import org.bukkit.entity.Shulker
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.BlockPlaceEvent
|
||||
import org.bukkit.event.entity.EntityDamageEvent
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.world.ChunkLoadEvent
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.BlockDisplay
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import org.bukkit.util.Transformation
|
||||
import org.joml.Vector3f
|
||||
import org.joml.Quaternionf
|
||||
import org.bukkit.block.data.type.Slab
|
||||
|
||||
class SectorListener(
|
||||
private val plugin: LandSectorPlugin,
|
||||
|
|
@ -52,29 +63,249 @@ class SectorListener(
|
|||
return
|
||||
}
|
||||
|
||||
// Spawn Shulker
|
||||
val shulkerLoc = loc.clone().add(0.5, 1.0, 0.5)
|
||||
val shulker = player.world.spawnEntity(shulkerLoc, EntityType.SHULKER) as Shulker
|
||||
shulker.setAI(false)
|
||||
shulker.isInvulnerable = true
|
||||
shulker.isInvisible = true
|
||||
|
||||
val param = shulker.getAttribute(Attribute.MAX_HEALTH)
|
||||
param?.baseValue = 1000.0
|
||||
shulker.health = 1000.0
|
||||
|
||||
// Place top bedrock
|
||||
above2.type = Material.BEDROCK
|
||||
|
||||
// Record to DB (using Shulker pos as center)
|
||||
sectorService.createSector(
|
||||
// Record to DB first to get ID
|
||||
val sector = sectorService.createSector(
|
||||
playerEntry.actorId,
|
||||
player.world.name,
|
||||
above1.x,
|
||||
above1.y,
|
||||
above1.z
|
||||
)
|
||||
|
||||
if (sector == null) {
|
||||
player.sendMessage(Component.text("Failed to create sector record.", NamedTextColor.RED))
|
||||
event.isCancelled = true
|
||||
return
|
||||
}
|
||||
|
||||
// Create Visuals
|
||||
val sectorKey = NamespacedKey(plugin, "sector_id")
|
||||
val locCenter = loc.clone().add(0.5, 0.0, 0.5)
|
||||
|
||||
// 1. Command Block
|
||||
val cbLoc = locCenter.clone().add(0.0, 1.5, 0.0)
|
||||
val cb = player.world.spawnEntity(cbLoc, EntityType.BLOCK_DISPLAY) as BlockDisplay
|
||||
cb.block = Material.COMMAND_BLOCK.createBlockData {
|
||||
(it as org.bukkit.block.data.Directional).facing = org.bukkit.block.BlockFace.UP
|
||||
}
|
||||
cb.transformation = Transformation(
|
||||
Vector3f(-0.25f, -0.25f, -0.25f),
|
||||
Quaternionf(0f, 0f, 0f, 1f),
|
||||
Vector3f(0.5f, 0.5f, 0.5f),
|
||||
Quaternionf(0f, 0f, 0f, 1f)
|
||||
)
|
||||
cb.persistentDataContainer.set(sectorKey, PersistentDataType.INTEGER, sector.id)
|
||||
|
||||
// 2. Tinted Glass
|
||||
val glass = player.world.spawnEntity(cbLoc, EntityType.BLOCK_DISPLAY) as BlockDisplay
|
||||
glass.block = Material.TINTED_GLASS.createBlockData()
|
||||
glass.transformation = Transformation(
|
||||
Vector3f(-0.4375f, -0.4375f, -0.4375f),
|
||||
Quaternionf(0f, 0f, 0f, 1f),
|
||||
Vector3f(0.875f, 0.875f, 0.875f),
|
||||
Quaternionf(0f, 0f, 0f, 1f)
|
||||
)
|
||||
glass.persistentDataContainer.set(sectorKey, PersistentDataType.INTEGER, sector.id)
|
||||
|
||||
// 3. Top Cauldron
|
||||
val topCauldronLoc = locCenter.clone().add(0.0, 2.3125, 0.0)
|
||||
val topCauldron = player.world.spawnEntity(topCauldronLoc, EntityType.BLOCK_DISPLAY) as BlockDisplay
|
||||
topCauldron.block = Material.CAULDRON.createBlockData()
|
||||
topCauldron.transformation = Transformation(
|
||||
Vector3f(0.4990f, -0.4990f, 0.4990f),
|
||||
Quaternionf(0f, 1f, 0f, 0f),
|
||||
Vector3f(0.9980f, 0.9980f, 0.9980f),
|
||||
Quaternionf(0f, 0f, 0f, 1f)
|
||||
)
|
||||
topCauldron.persistentDataContainer.set(sectorKey, PersistentDataType.INTEGER, sector.id)
|
||||
|
||||
// 4. Bottom Cauldron
|
||||
val botCauldronLoc = locCenter.clone().add(0.0, 0.6875, 0.0)
|
||||
val botCauldron = player.world.spawnEntity(botCauldronLoc, EntityType.BLOCK_DISPLAY) as BlockDisplay
|
||||
botCauldron.block = Material.CAULDRON.createBlockData()
|
||||
botCauldron.transformation = Transformation(
|
||||
Vector3f(-0.4990f, 0.4990f, 0.4990f),
|
||||
Quaternionf(1f, 0f, 0f, 0f),
|
||||
Vector3f(0.9980f, 0.9980f, 0.9980f),
|
||||
Quaternionf(0f, 0f, 0f, 1f)
|
||||
)
|
||||
botCauldron.persistentDataContainer.set(sectorKey, PersistentDataType.INTEGER, sector.id)
|
||||
|
||||
// Spawn Shulker (Hitbox)
|
||||
val shulkerLoc = loc.clone().add(0.5, 1.0, 0.5) // Y+1, sits in space 1-2.
|
||||
val shulker = player.world.spawnEntity(shulkerLoc, EntityType.SHULKER) as Shulker
|
||||
shulker.setAI(false)
|
||||
shulker.isInvisible = true
|
||||
// shulker.isInvulnerable = true // REMOVED to allow damage
|
||||
|
||||
val param = shulker.getAttribute(Attribute.MAX_HEALTH)
|
||||
param?.baseValue = 1000.0
|
||||
shulker.health = 1000.0
|
||||
shulker.maximumNoDamageTicks = 0
|
||||
|
||||
// Tag Shulker with Sector ID
|
||||
shulker.persistentDataContainer.set(sectorKey, PersistentDataType.INTEGER, sector.id)
|
||||
|
||||
// Place Blocks
|
||||
block.type = Material.DEEPSLATE_TILE_SLAB
|
||||
val bottomSlab = block.blockData as Slab
|
||||
bottomSlab.type = Slab.Type.BOTTOM
|
||||
block.blockData = bottomSlab
|
||||
|
||||
above2.type = Material.DEEPSLATE_TILE_SLAB
|
||||
val topSlab = above2.blockData as Slab
|
||||
topSlab.type = Slab.Type.TOP
|
||||
above2.blockData = topSlab
|
||||
|
||||
player.sendMessage(Component.text("Sector Core placed!", NamedTextColor.GREEN))
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onDamage(event: EntityDamageEvent) {
|
||||
val entity = event.entity
|
||||
if (entity !is Shulker) return
|
||||
|
||||
val sectorKey = NamespacedKey(plugin, "sector_id")
|
||||
if (!entity.persistentDataContainer.has(sectorKey, PersistentDataType.INTEGER)) return
|
||||
|
||||
val sectorId = entity.persistentDataContainer.get(sectorKey, PersistentDataType.INTEGER) ?: return
|
||||
|
||||
// Prevent vanilla death logic but show damage effect
|
||||
// We restore health to max after processing
|
||||
val damage = event.finalDamage
|
||||
val maxHealth = entity.getAttribute(Attribute.MAX_HEALTH)?.value ?: 1000.0
|
||||
|
||||
val newHp = sectorService.reduceHealth(sectorId, damage.toInt())
|
||||
|
||||
// Cancel the event so it doesn't actually die in vanilla terms,
|
||||
// OR let it happen but force health reset.
|
||||
// Cancelling prevents the red flash in some versions/cases, so setting damage to 0 is often better
|
||||
// if we want the effect. But resetting health is robust.
|
||||
// Let's reset health.
|
||||
entity.health = maxHealth
|
||||
entity.noDamageTicks = 0
|
||||
|
||||
if (newHp != null) {
|
||||
val loc = entity.location
|
||||
val world = entity.world
|
||||
|
||||
// Effects
|
||||
world.playSound(loc, Sound.BLOCK_ANVIL_PLACE, 1.0f, 0.5f) // Heavy metallic sound
|
||||
world.spawnParticle(Particle.BLOCK, loc.add(0.0, 0.5, 0.0), 20, 0.3, 0.3, 0.3, Material.BEDROCK.createBlockData())
|
||||
|
||||
// Action Bar Display
|
||||
if (event is EntityDamageByEntityEvent && event.damager is Player) {
|
||||
val player = event.damager as Player
|
||||
val percent = newHp.toDouble() / maxHealth.toDouble()
|
||||
val color = when {
|
||||
percent > 0.5 -> NamedTextColor.GREEN
|
||||
percent > 0.2 -> NamedTextColor.YELLOW
|
||||
else -> NamedTextColor.RED
|
||||
}
|
||||
|
||||
val progressBar = createProgressBar(newHp, maxHealth.toInt(), color)
|
||||
|
||||
val message = Component.text()
|
||||
.append(Component.text("Sector Core ", NamedTextColor.GOLD))
|
||||
.append(progressBar)
|
||||
.append(Component.text(" "))
|
||||
.append(Component.text(newHp, color))
|
||||
.append(Component.text("/", NamedTextColor.GRAY))
|
||||
.append(Component.text(maxHealth.toInt(), NamedTextColor.GRAY))
|
||||
.build()
|
||||
|
||||
player.sendActionBar(message)
|
||||
}
|
||||
|
||||
if (newHp <= 0) {
|
||||
// Destruction
|
||||
entity.remove()
|
||||
|
||||
// Remove other visuals in chunk
|
||||
val chunk = entity.chunk
|
||||
chunk.entities.forEach { ent ->
|
||||
val sId = ent.persistentDataContainer.get(sectorKey, PersistentDataType.INTEGER)
|
||||
if (sId == sectorId) ent.remove()
|
||||
}
|
||||
|
||||
// Remove blocks.
|
||||
// We know Shulker is at x, y, z.
|
||||
// Base is y-1, Top is y+1
|
||||
val loc = entity.location
|
||||
val world = entity.world
|
||||
val x = loc.blockX
|
||||
val y = loc.blockY
|
||||
val z = loc.blockZ
|
||||
|
||||
val base = world.getBlockAt(x, y - 1, z)
|
||||
val top = world.getBlockAt(x, y + 1, z)
|
||||
|
||||
if (base.type == Material.DEEPSLATE_TILE_SLAB) base.type = Material.AIR
|
||||
if (top.type == Material.DEEPSLATE_TILE_SLAB) top.type = Material.AIR
|
||||
|
||||
world.dropItemNaturally(loc, org.bukkit.inventory.ItemStack(Material.DEEPSLATE_TILE_SLAB, 2))
|
||||
|
||||
// Maybe delete from DB or mark as destroyed?
|
||||
// For now, valid destruction.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProgressBar(current: Int, max: Int, color: NamedTextColor): Component {
|
||||
val totalBars = 20
|
||||
val percent = current.toDouble() / max.toDouble()
|
||||
val filledBars = (totalBars * percent).toInt().coerceIn(0, totalBars)
|
||||
val emptyBars = totalBars - filledBars
|
||||
|
||||
return Component.text()
|
||||
.append(Component.text("[", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.text("|".repeat(filledBars), color))
|
||||
.append(Component.text("|".repeat(emptyBars), NamedTextColor.GRAY))
|
||||
.append(Component.text("]", NamedTextColor.DARK_GRAY))
|
||||
.build()
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onChunkLoad(event: ChunkLoadEvent) {
|
||||
if (event.isNewChunk) return // Optimization: New chunks won't have old sectors to cleanup
|
||||
|
||||
val chunk = event.chunk
|
||||
val entities = chunk.entities
|
||||
val sectorKey = NamespacedKey(plugin, "sector_id")
|
||||
|
||||
entities.forEach { entity ->
|
||||
if (entity.persistentDataContainer.has(sectorKey, PersistentDataType.INTEGER)) {
|
||||
val sectorId = entity.persistentDataContainer.get(sectorKey, PersistentDataType.INTEGER) ?: return@forEach
|
||||
|
||||
// Check existance async
|
||||
plugin.server.scheduler.runTaskAsynchronously(plugin, Runnable {
|
||||
val exists = sectorService.exists(sectorId)
|
||||
if (!exists) {
|
||||
plugin.server.scheduler.runTask(plugin, Runnable {
|
||||
// Re-verify ent validity
|
||||
if (entity.isValid) {
|
||||
entity.remove()
|
||||
// We should also clean up blocks, but that requires knowing where they are relative to entity
|
||||
val loc = entity.location
|
||||
val world = entity.world
|
||||
val x = loc.blockX
|
||||
val y = loc.blockY
|
||||
val z = loc.blockZ
|
||||
|
||||
// Entity is at x, y, z
|
||||
// Base is y-1, Top is y+1
|
||||
val base = world.getBlockAt(x, y - 1, z)
|
||||
val top = world.getBlockAt(x, y + 1, z)
|
||||
|
||||
if (base.type == Material.DEEPSLATE_TILE_SLAB) base.type = Material.AIR
|
||||
if (top.type == Material.DEEPSLATE_TILE_SLAB) top.type = Material.AIR
|
||||
|
||||
plugin.logger.info("Removed orphaned sector artifacts for ID $sectorId at $x,$y,$z")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ data class Sector(
|
|||
val world: String,
|
||||
val x: Int,
|
||||
val y: Int,
|
||||
val z: Int
|
||||
val z: Int,
|
||||
val hp: Int
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,18 @@ import org.jetbrains.exposed.v1.jdbc.Database
|
|||
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.select
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import org.jetbrains.exposed.v1.jdbc.andWhere
|
||||
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) {
|
||||
|
||||
private val hpCache = ConcurrentHashMap<Int, Int>()
|
||||
private val dirtySet = ConcurrentHashMap.newKeySet<Int>()
|
||||
|
||||
fun init() {
|
||||
transaction(database) {
|
||||
SchemaUtils.createMissingTablesAndColumns(SectorsTable)
|
||||
|
|
@ -26,9 +33,11 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.x] = x
|
||||
it[SectorsTable.y] = y
|
||||
it[SectorsTable.z] = z
|
||||
it[SectorsTable.hp] = 1000
|
||||
}[SectorsTable.id]
|
||||
|
||||
Sector(id, ownerActorId, world, x, y, z)
|
||||
hpCache[id] = 1000
|
||||
Sector(id, ownerActorId, world, x, y, z, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,9 +55,106 @@ class SectorService(private val database: Database) {
|
|||
it[SectorsTable.world],
|
||||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z]
|
||||
it[SectorsTable.z],
|
||||
it[SectorsTable.hp]
|
||||
)
|
||||
}.singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun reduceHealth(id: Int, amount: Int): Int? {
|
||||
// Try get from cache
|
||||
var currentHp = hpCache[id]
|
||||
|
||||
// If not in cache, load from DB
|
||||
if (currentHp == null) {
|
||||
val sector = transaction(database) {
|
||||
SectorsTable.selectAll().andWhere { SectorsTable.id eq id }.singleOrNull()
|
||||
} ?: return null // Not found
|
||||
|
||||
currentHp = sector[SectorsTable.hp]
|
||||
hpCache[id] = currentHp
|
||||
}
|
||||
|
||||
val newHp = (currentHp!! - amount).coerceAtLeast(0)
|
||||
hpCache[id] = newHp
|
||||
dirtySet.add(id)
|
||||
|
||||
return newHp
|
||||
}
|
||||
|
||||
fun flushChanges() {
|
||||
if (dirtySet.isEmpty()) return
|
||||
|
||||
// Take a snapshot of keys to update
|
||||
val toUpdate = dirtySet.toMutableSet()
|
||||
dirtySet.removeAll(toUpdate) // Clear them from dirty set so we don't re-save unless modified again
|
||||
|
||||
if (toUpdate.isEmpty()) return
|
||||
|
||||
transaction(database) {
|
||||
toUpdate.forEach { id ->
|
||||
val hp = hpCache[id] ?: return@forEach
|
||||
SectorsTable.update({ SectorsTable.id eq id }) {
|
||||
it[SectorsTable.hp] = hp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteSector(id: Int): Sector? {
|
||||
val sector = transaction(database) {
|
||||
val record = SectorsTable.selectAll().andWhere { SectorsTable.id eq id }.singleOrNull() ?: return@transaction null
|
||||
|
||||
SectorsTable.deleteWhere { SectorsTable.id eq id }
|
||||
|
||||
Sector(
|
||||
record[SectorsTable.id],
|
||||
record[SectorsTable.ownerActorId],
|
||||
record[SectorsTable.world],
|
||||
record[SectorsTable.x],
|
||||
record[SectorsTable.y],
|
||||
record[SectorsTable.z],
|
||||
record[SectorsTable.hp]
|
||||
)
|
||||
}
|
||||
|
||||
if (sector != null) {
|
||||
hpCache.remove(id)
|
||||
dirtySet.remove(id)
|
||||
}
|
||||
|
||||
return sector
|
||||
}
|
||||
|
||||
fun exists(id: Int): Boolean {
|
||||
if (hpCache.containsKey(id)) return true
|
||||
|
||||
return transaction(database) {
|
||||
SectorsTable.selectAll().andWhere { SectorsTable.id eq id }.count() > 0
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllSectors(world: String): List<Sector> {
|
||||
return transaction(database) {
|
||||
SectorsTable.selectAll()
|
||||
.andWhere { SectorsTable.world eq world }
|
||||
.map {
|
||||
// Update HP from cache if exists
|
||||
val id = it[SectorsTable.id]
|
||||
val cachedHp = hpCache[id]
|
||||
val hp = cachedHp ?: it[SectorsTable.hp]
|
||||
|
||||
Sector(
|
||||
id,
|
||||
it[SectorsTable.ownerActorId],
|
||||
it[SectorsTable.world],
|
||||
it[SectorsTable.x],
|
||||
it[SectorsTable.y],
|
||||
it[SectorsTable.z],
|
||||
hp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user