Little faster big dungeon placement

This commit is contained in:
DBotThePony 2024-05-05 22:53:31 +07:00
parent 74937b15ac
commit 161d19f263
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 17 additions and 10 deletions

View File

@ -21,6 +21,8 @@ import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.util.random.random
import java.util.concurrent.CompletableFuture
import java.util.random.RandomGenerator
import kotlin.math.roundToInt
import kotlin.math.sqrt
// Dungeons in Starbound are separated into two categories:
// A. Dungeons described using specific tileset (palette, defined through JSON) and corresponding image maps (chunks)
@ -98,6 +100,10 @@ data class DungeonDefinition(
metadata.anchor.stream().map { anchor -> actualParts.first { it.name == anchor } }.collect(ImmutableList.toImmutableList())
}
private val expectedSize by lazy {
(partMap.values.sumOf { it.reader.size.x.toDouble() * it.reader.size.y.toDouble() } / sqrt(partMap.size.toDouble())).roundToInt()
}
private fun connectableParts(connector: DungeonPart.JigsawConnector): List<DungeonPart.JigsawConnector> {
val result = ArrayList<DungeonPart.JigsawConnector>()
@ -217,7 +223,7 @@ data class DungeonDefinition(
scope: CoroutineScope = Starbound.GLOBAL_SCOPE
): CompletableFuture<DungeonWorld> {
require(dungeonID in 0 .. NO_DUNGEON_ID) { "Dungeon ID out of range: $dungeonID" }
val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends)
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 }
@ -243,7 +249,7 @@ data class DungeonDefinition(
fun build(anchor: DungeonPart, world: ServerWorld, random: RandomGenerator, x: Int, y: Int, dungeonID: Int = NO_DUNGEON_ID, markSurfaceAndTerrain: Boolean = false, forcePlacement: Boolean = false, terrainSurfaceSpaceExtends: Int = 0, commit: Boolean = true, scope: CoroutineScope = Starbound.GLOBAL_SCOPE): CompletableFuture<DungeonWorld> {
require(anchor in anchorParts) { "$anchor does not belong to $name" }
val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends)
val dungeonWorld = DungeonWorld(world, random, if (markSurfaceAndTerrain) y else null, terrainSurfaceSpaceExtends, expectedSize = expectedSize)
return scope.async {
generate0(anchor, dungeonWorld, x, y, forcePlacement, dungeonID)

View File

@ -40,11 +40,12 @@ import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
import java.util.function.Supplier
import java.util.random.RandomGenerator
import kotlin.math.max
// Facade world for generating dungeons, so generation can be performed without affecting world state,
// and if error occurs, won't require world's rollback, as well allowing dungeon to be generated mostly
// off world's thread.
class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val markSurfaceLevel: Int? = null, val terrainSurfaceSpaceExtends: Int = 0) {
class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val markSurfaceLevel: Int? = null, val terrainSurfaceSpaceExtends: Int = 0, expectedSize: Int = 0) {
val geometry = parent.geometry
data class Material(
@ -80,11 +81,11 @@ class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val mar
val targetChunkState = if (parent.template.worldParameters is FloatingDungeonWorldParameters) ChunkState.FULL else ChunkState.TERRAIN
private val liquid = HashMap<Vector2i, AbstractLiquidState>(8192, 0.5f)
private val foregroundMaterial = HashMap<Vector2i, Material>(8192, 0.5f)
private val foregroundModifier = HashMap<Vector2i, Modifier>(8192, 0.5f)
private val backgroundMaterial = HashMap<Vector2i, Material>(8192, 0.5f)
private val backgroundModifier = HashMap<Vector2i, Modifier>(8192, 0.5f)
private val liquid = HashMap<Vector2i, AbstractLiquidState>(max(8192, expectedSize), 0.5f)
private val foregroundMaterial = HashMap<Vector2i, Material>(max(8192, expectedSize), 0.5f)
private val foregroundModifier = HashMap<Vector2i, Modifier>(max(8192, expectedSize), 0.5f)
private val backgroundMaterial = HashMap<Vector2i, Material>(max(8192, expectedSize), 0.5f)
private val backgroundModifier = HashMap<Vector2i, Modifier>(max(8192, expectedSize), 0.5f)
// for entity spaces which should be considered empty if they
// are occupied by tile entity
@ -93,8 +94,8 @@ class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val mar
// entities themselves to be removed
private val tileEntitiesToRemove = HashSet<TileEntity>(2048, 0.5f)
val touchedTiles = HashSet<Vector2i>(16384, 0.5f)
val protectTile = HashSet<Vector2i>(16384, 0.5f)
val touchedTiles = HashSet<Vector2i>(max(16384, expectedSize), 0.5f)
val protectTile = HashSet<Vector2i>(max(16384, expectedSize), 0.5f)
private val boundingBoxes = ArrayList<AABBi>()