From 79e606f6099795aaaff37fe0a7a7d92d00c49d19 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 6 May 2024 12:45:38 +0700 Subject: [PATCH] Rollback immediate placement, make custom terrain regions actually work --- .../defs/dungeon/DungeonDefinition.kt | 6 +- .../kstarbound/defs/dungeon/DungeonWorld.kt | 126 +++--------------- .../kstarbound/server/world/ServerWorld.kt | 18 +-- .../kstarbound/world/CoordinateMapper.kt | 8 +- 4 files changed, 29 insertions(+), 129 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonDefinition.kt index d6f00975..d499b760 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonDefinition.kt @@ -221,10 +221,9 @@ data class DungeonDefinition( terrainSurfaceSpaceExtends: Int = 0, commit: Boolean = true, scope: CoroutineScope = Starbound.GLOBAL_SCOPE, - immediate: Boolean = false, ): CompletableFuture { require(dungeonID in 0 .. NO_DUNGEON_ID) { "Dungeon ID out of range: $dungeonID" } - val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends, expectedSize = expectedSize, immediate = immediate) + val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends, expectedSize = expectedSize) val validAnchors = anchorParts.filter { world.template.threatLevel in it.minimumThreatLevel .. it.maximumThreatLevel } @@ -259,10 +258,9 @@ data class DungeonDefinition( terrainSurfaceSpaceExtends: Int = 0, commit: Boolean = true, scope: CoroutineScope = Starbound.GLOBAL_SCOPE, - immediate: Boolean = false ): CompletableFuture { require(anchor in anchorParts) { "$anchor does not belong to $name" } - val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends, expectedSize = expectedSize, immediate = immediate) + val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends, expectedSize = expectedSize) return scope.async { generate0(anchor, dungeonWorld, x, y, forcePlacement, dungeonID) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonWorld.kt index 4747b777..8a91ac80 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/dungeon/DungeonWorld.kt @@ -53,13 +53,6 @@ class DungeonWorld( val markSurfaceLevel: Int? = null, val terrainSurfaceSpaceExtends: Int = 0, expectedSize: Int = 0, - - /** - * Whenever tile changes should be passthrough, if possible - * (improved generation speed and memory usage, but expects world chunks to be already - * loaded into memory AND no concurrent chunkmap operations are performed) - */ - val immediate: Boolean = false, ) { val geometry = parent.geometry @@ -94,13 +87,13 @@ class DungeonWorld( var hasGenerated = false private set - val targetChunkState = if (parent.template.worldParameters is FloatingDungeonWorldParameters) ChunkState.FULL else ChunkState.TERRAIN + val targetChunkState = if (parent.template.worldParameters is FloatingDungeonWorldParameters) ChunkState.FULL else ChunkState.EMPTY - private val liquid = HashMap(if (immediate) 2048 else max(8192, expectedSize), 0.5f) - private val foregroundMaterial = HashMap(if (immediate) 2048 else max(8192, expectedSize), 0.5f) - private val foregroundModifier = HashMap(if (immediate) 2048 else max(8192, expectedSize), 0.5f) - private val backgroundMaterial = HashMap(if (immediate) 2048 else max(8192, expectedSize), 0.5f) - private val backgroundModifier = HashMap(if (immediate) 2048 else max(8192, expectedSize), 0.5f) + private val liquid = HashMap(max(8192, expectedSize * 2), 0.5f) + private val foregroundMaterial = HashMap(max(8192, expectedSize * 2), 0.5f) + private val foregroundModifier = HashMap(max(8192, expectedSize * 2), 0.5f) + private val backgroundMaterial = HashMap(max(8192, expectedSize * 2), 0.5f) + private val backgroundModifier = HashMap(max(8192, expectedSize * 2), 0.5f) // for entity spaces which should be considered empty if they // are occupied by tile entity @@ -109,8 +102,8 @@ class DungeonWorld( // entities themselves to be removed private val tileEntitiesToRemove = HashSet(2048, 0.5f) - val touchedTiles = HashSet(max(16384, expectedSize), 0.5f) - val protectTile = HashSet(max(16384, expectedSize), 0.5f) + val touchedTiles = HashSet(max(16384, expectedSize * 4), 0.5f) + val protectTile = HashSet(max(16384, expectedSize * 4), 0.5f) private val boundingBoxes = ArrayList() @@ -276,15 +269,16 @@ class DungeonWorld( private val emptyMaterial = Material(AbstractTileState.EMPTY.material, AbstractTileState.EMPTY.hueShift, AbstractTileState.EMPTY.color) private val emptyModifier = Modifier(AbstractTileState.EMPTY.modifier, AbstractTileState.EMPTY.modifierHueShift) - private fun setCombinedFallback( + fun setCombined( x: Int, y: Int, foreground: AbstractTileState?, background: AbstractTileState?, liquid: AbstractLiquidState?, - setForegroundMaterial: Boolean, - setForegroundModifier: Boolean, - setBackgroundMaterial: Boolean, - setBackgroundModifier: Boolean, + dungeonId: Int? = null, + setForegroundMaterial: Boolean = true, + setForegroundModifier: Boolean = true, + setBackgroundMaterial: Boolean = true, + setBackgroundModifier: Boolean = true, ) { val pos = geometry.wrap(Vector2i(x, y)) @@ -305,95 +299,17 @@ class DungeonWorld( } if (liquid != null) this.liquid[pos] = liquid - } - - fun setCombined( - x: Int, y: Int, - foreground: AbstractTileState?, - background: AbstractTileState?, - liquid: AbstractLiquidState?, - dungeonId: Int? = null, - setForegroundMaterial: Boolean = true, - setForegroundModifier: Boolean = true, - setBackgroundMaterial: Boolean = true, - setBackgroundModifier: Boolean = true, - ) { - if (immediate) { - val cell = parent.getCell(x, y).mutable() - if (foreground != null) cell.foreground.from(foreground, setForegroundMaterial, setForegroundModifier) - if (background != null) cell.background.from(background, setBackgroundMaterial, setBackgroundModifier) - if (liquid != null) cell.liquid.from(liquid) - - cell.dungeonId = dungeonId ?: cell.dungeonId - - if (!parent.setCell(x, y, cell.immutable())) { - LOGGER.debug("Cell at $x, $y is out of preloaded bounds for immediate dungeon generator... While this won't affect dungeon generation, it will degrade performance and signify there is a bug somewhere.") - - setCombinedFallback( - x = x, - y = y, - foreground = foreground, - background = background, - liquid = liquid, - setForegroundMaterial = setForegroundMaterial, - setForegroundModifier = setForegroundModifier, - setBackgroundMaterial = setBackgroundMaterial, - setBackgroundModifier = setBackgroundModifier, - ) - } else { - val pos = geometry.wrap(Vector2i(x, y)) - - if (foreground != null) { - if (setForegroundMaterial) this.foregroundMaterial.remove(pos) - if (setForegroundModifier) this.foregroundModifier.remove(pos) - } - - if (background != null) { - if (setBackgroundMaterial) this.backgroundMaterial.remove(pos) - if (setBackgroundModifier) this.backgroundModifier.remove(pos) - } - - if (liquid != null) this.liquid.remove(pos) - } - } else { - setCombinedFallback( - x = x, - y = y, - foreground = foreground, - background = background, - liquid = liquid, - setForegroundMaterial = setForegroundMaterial, - setForegroundModifier = setForegroundModifier, - setBackgroundMaterial = setBackgroundMaterial, - setBackgroundModifier = setBackgroundModifier, - ) - } + if (dungeonId != null) dungeonIDs[pos] = dungeonId } fun clearTile(x: Int, y: Int) { val pos = geometry.wrap(Vector2i(x, y)) - if (immediate) { - if (parent.setCell(x, y, AbstractCell.EMPTY)) { - this.foregroundMaterial.remove(pos) - this.foregroundModifier.remove(pos) - this.backgroundMaterial.remove(pos) - this.backgroundModifier.remove(pos) - this.liquid.remove(pos) - } else { - this.foregroundMaterial[pos] = emptyMaterial - this.foregroundModifier[pos] = emptyModifier - this.backgroundMaterial[pos] = emptyMaterial - this.backgroundModifier[pos] = emptyModifier - this.liquid[pos] = AbstractLiquidState.EMPTY - } - } else { - this.foregroundMaterial[pos] = emptyMaterial - this.foregroundModifier[pos] = emptyModifier - this.backgroundMaterial[pos] = emptyMaterial - this.backgroundModifier[pos] = emptyModifier - this.liquid[pos] = AbstractLiquidState.EMPTY - } + this.foregroundMaterial[pos] = emptyMaterial + this.foregroundModifier[pos] = emptyModifier + this.backgroundMaterial[pos] = emptyMaterial + this.backgroundModifier[pos] = emptyModifier + this.liquid[pos] = AbstractLiquidState.EMPTY dungeonIDs.remove(pos) } @@ -623,7 +539,7 @@ class DungeonWorld( }.await() for (box in boundingBoxes) { - tickets.addAll(parent.permanentChunkTicket(box, targetChunkState).await()) + tickets.addAll(parent.permanentChunkTicket(box, ChunkState.TERRAIN).await()) } // apply tiles to world per-chunk diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt index 0a8d65d3..e3a48d1d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/world/ServerWorld.kt @@ -565,20 +565,8 @@ class ServerWorld private constructor( x = geometry.x.cell(x) - val tickets = ArrayList() - val dungeonWorld = try { - // if immediate placement will cause issues it can be safely toggled off - var immediate = false - - if (dungeon.dungeon.value.anchorParts.size == 1 && dungeon.dungeon.value.partMap.size == 1) { - immediate = true - LOGGER.info("Trying to immediately place dungeon ${dungeon.dungeon.key} at $x, ${dungeon.baseHeight}...") - tickets.addAll(permanentChunkTicket(AABBi.withSide(Vector2i(x, dungeon.baseHeight), dungeon.dungeon.value.anchorParts.first().reader.size), ChunkState.TERRAIN).await()) - tickets.forEach { it.chunk.await() } - } else { - LOGGER.info("Trying to place dungeon ${dungeon.dungeon.key} at $x, ${dungeon.baseHeight}...") - } + LOGGER.info("Trying to place dungeon ${dungeon.dungeon.key} at $x, ${dungeon.baseHeight}...") dungeon.dungeon.value.generate( this, @@ -586,12 +574,10 @@ class ServerWorld private constructor( x, dungeon.baseHeight, dungeon.blendWithTerrain, dungeon.forcePlacement, - dungeonID = currentDungeonID, - immediate = immediate).await() + dungeonID = currentDungeonID).await() } catch (err: Throwable) { LOGGER.error("Exception while placing dungeon ${dungeon.dungeon.key} at $x, ${dungeon.baseHeight}", err) // continue - tickets.forEach { it.cancel() } break } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt index 572f9049..17661a1a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/CoordinateMapper.kt @@ -247,11 +247,11 @@ abstract class CoordinateMapper { private var cellsEdgeFloat = cellsF override fun diff(a: Int, b: Int): Int { - return (a - b).coerceIn(0, cells) + return (a - b).coerceIn(-cells, cells) } override fun diff(a: Double, b: Double): Double { - return (a - b).coerceIn(0.0, cellsD) + return (a - b).coerceIn(-cellsD, cellsD) } init { @@ -304,11 +304,11 @@ abstract class CoordinateMapper { } override fun nearestTo(source: Int, target: Int): Int { - return diff(source, target) + return target } override fun nearestTo(source: Double, target: Double): Double { - return diff(source, target) + return target } } }