package ru.dbotthepony.kstarbound.world import ru.dbotthepony.kommons.util.AABBi import ru.dbotthepony.kommons.util.IStruct2i import ru.dbotthepony.kommons.util.KOptional import ru.dbotthepony.kommons.vector.Vector2i import ru.dbotthepony.kstarbound.defs.world.CelestialBaseInformation import ru.dbotthepony.kstarbound.defs.world.CelestialParameters import java.util.concurrent.CompletableFuture abstract class Universe { abstract val region: AABBi abstract val baseInformation: CelestialBaseInformation abstract suspend fun parameters(pos: UniversePos): CelestialParameters? suspend fun name(pos: UniversePos): String? { return parameters(pos)?.name } /** * Return all valid system coordinates in the given x/y range. All systems * are guaranteed to have unique x/y coordinates, and are meant to be viewed * from the top in 2d. The z-coordinate is there simpy as a validation * parameter. * * [callback] determines when to stop scanning (returning non empty KOptional will stop scanning) */ abstract suspend fun scanSystems(region: AABBi, callback: suspend (UniversePos) -> KOptional): KOptional abstract suspend fun scanConstellationLines(region: AABBi, aggressive: Boolean = false): List> /** * Similar to [scanSystems], but scans for ALL systems in given range, on multiple threads */ abstract suspend fun findSystems(region: AABBi, includedTypes: Set? = null): List abstract suspend fun hasChildren(pos: UniversePos): Boolean abstract suspend fun children(pos: UniversePos): List /** * Returns false if part or all of the specified region is not loaded. This * is only relevant for calls to scanSystems and scanConstellationLines, and * does not imply that each individual system in the given region is fully * loaded with all planets moons etc, only that scanSystem and * scanConstellationLines are not waiting on missing data. */ abstract fun scanRegionFullyLoaded(region: AABBi): Boolean fun chunkPositions(region: AABBi): List { if (region.mins == region.maxs) return emptyList() val result = ArrayList() val mins = world2chunk(region.mins) val maxs = world2chunk(region.maxs - Vector2i.POSITIVE_XY) for (x in mins.x .. maxs.x) { for (y in mins.y .. maxs.y) { result.add(Vector2i(x, y)) } } return result } fun world2chunk(pos: IStruct2i): Vector2i { val (x, y) = pos return Vector2i( (x - positiveModulo(x, baseInformation.chunkSize)) / baseInformation.chunkSize, (y - positiveModulo(y, baseInformation.chunkSize)) / baseInformation.chunkSize) } fun chunkRegion(chunkPos: IStruct2i): AABBi { val mins = Vector2i(chunkPos) * baseInformation.chunkSize return AABBi(mins, mins + Vector2i.POSITIVE_XY * baseInformation.chunkSize) } }