Little faster big dungeon placement
This commit is contained in:
parent
74937b15ac
commit
161d19f263
@ -21,6 +21,8 @@ import ru.dbotthepony.kstarbound.util.AssetPathStack
|
|||||||
import ru.dbotthepony.kstarbound.util.random.random
|
import ru.dbotthepony.kstarbound.util.random.random
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
// Dungeons in Starbound are separated into two categories:
|
// Dungeons in Starbound are separated into two categories:
|
||||||
// A. Dungeons described using specific tileset (palette, defined through JSON) and corresponding image maps (chunks)
|
// 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())
|
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> {
|
private fun connectableParts(connector: DungeonPart.JigsawConnector): List<DungeonPart.JigsawConnector> {
|
||||||
val result = ArrayList<DungeonPart.JigsawConnector>()
|
val result = ArrayList<DungeonPart.JigsawConnector>()
|
||||||
|
|
||||||
@ -217,7 +223,7 @@ data class DungeonDefinition(
|
|||||||
scope: CoroutineScope = Starbound.GLOBAL_SCOPE
|
scope: CoroutineScope = Starbound.GLOBAL_SCOPE
|
||||||
): CompletableFuture<DungeonWorld> {
|
): CompletableFuture<DungeonWorld> {
|
||||||
require(dungeonID in 0 .. NO_DUNGEON_ID) { "Dungeon ID out of range: $dungeonID" }
|
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 }
|
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> {
|
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" }
|
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 {
|
return scope.async {
|
||||||
generate0(anchor, dungeonWorld, x, y, forcePlacement, dungeonID)
|
generate0(anchor, dungeonWorld, x, y, forcePlacement, dungeonID)
|
||||||
|
@ -40,11 +40,12 @@ import java.util.concurrent.CompletableFuture
|
|||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
// Facade world for generating dungeons, so generation can be performed without affecting world state,
|
// 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
|
// and if error occurs, won't require world's rollback, as well allowing dungeon to be generated mostly
|
||||||
// off world's thread.
|
// 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
|
val geometry = parent.geometry
|
||||||
|
|
||||||
data class Material(
|
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
|
val targetChunkState = if (parent.template.worldParameters is FloatingDungeonWorldParameters) ChunkState.FULL else ChunkState.TERRAIN
|
||||||
|
|
||||||
private val liquid = HashMap<Vector2i, AbstractLiquidState>(8192, 0.5f)
|
private val liquid = HashMap<Vector2i, AbstractLiquidState>(max(8192, expectedSize), 0.5f)
|
||||||
private val foregroundMaterial = HashMap<Vector2i, Material>(8192, 0.5f)
|
private val foregroundMaterial = HashMap<Vector2i, Material>(max(8192, expectedSize), 0.5f)
|
||||||
private val foregroundModifier = HashMap<Vector2i, Modifier>(8192, 0.5f)
|
private val foregroundModifier = HashMap<Vector2i, Modifier>(max(8192, expectedSize), 0.5f)
|
||||||
private val backgroundMaterial = HashMap<Vector2i, Material>(8192, 0.5f)
|
private val backgroundMaterial = HashMap<Vector2i, Material>(max(8192, expectedSize), 0.5f)
|
||||||
private val backgroundModifier = HashMap<Vector2i, Modifier>(8192, 0.5f)
|
private val backgroundModifier = HashMap<Vector2i, Modifier>(max(8192, expectedSize), 0.5f)
|
||||||
|
|
||||||
// for entity spaces which should be considered empty if they
|
// for entity spaces which should be considered empty if they
|
||||||
// are occupied by tile entity
|
// are occupied by tile entity
|
||||||
@ -93,8 +94,8 @@ class DungeonWorld(val parent: ServerWorld, val random: RandomGenerator, val mar
|
|||||||
// entities themselves to be removed
|
// entities themselves to be removed
|
||||||
private val tileEntitiesToRemove = HashSet<TileEntity>(2048, 0.5f)
|
private val tileEntitiesToRemove = HashSet<TileEntity>(2048, 0.5f)
|
||||||
|
|
||||||
val touchedTiles = HashSet<Vector2i>(16384, 0.5f)
|
val touchedTiles = HashSet<Vector2i>(max(16384, expectedSize), 0.5f)
|
||||||
val protectTile = HashSet<Vector2i>(16384, 0.5f)
|
val protectTile = HashSet<Vector2i>(max(16384, expectedSize), 0.5f)
|
||||||
|
|
||||||
private val boundingBoxes = ArrayList<AABBi>()
|
private val boundingBoxes = ArrayList<AABBi>()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user