Misc perfromance improvements

This commit is contained in:
DBotThePony 2024-04-19 11:54:41 +07:00
parent 100afadd5c
commit fffc0b6102
Signed by: DBot
GPG Key ID: DCC23B5715498507
18 changed files with 60 additions and 47 deletions

View File

@ -4,7 +4,6 @@ import org.apache.logging.log4j.LogManager
import org.lwjgl.Version
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.server.IntegratedStarboundServer
import ru.dbotthepony.kstarbound.util.random.random
import java.io.File
import java.net.InetSocketAddress

View File

@ -151,6 +151,12 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
@JvmField
val COROUTINE_EXECUTOR = ExecutorWithScheduler(EXECUTOR, this).asCoroutineDispatcher()
// this is required for Caffeine since it ignores scheduler
// (and suffers noticeable throughput penalty) in rescheduleCleanUpIfIncomplete()
// if executor is specified as ForkJoinPool.commonPool()
@JvmField
val SCREENED_EXECUTOR: ExecutorService = object : ExecutorService by EXECUTOR {}
@JvmField
val CLEANER: Cleaner = Cleaner.create {
val t = Thread(it, "Starbound Global Cleaner")

View File

@ -345,7 +345,7 @@ class Image private constructor(
.weigher<IStarboundFile, ByteBuffer> { key, value -> value.capacity() }
.maximumWeight((Runtime.getRuntime().maxMemory() / 4L).coerceIn(1_024L * 1_024L * 32L /* 32 МиБ */, 1_024L * 1_024L * 256L /* 256 МиБ */))
.scheduler(Starbound)
.executor(Starbound.EXECUTOR)
.executor(Starbound.EXECUTOR) // SCREENED_EXECUTOR shouldn't be used here
.buildAsync(CacheLoader {
readImageDirect(it).data
})

View File

@ -228,7 +228,7 @@ data class BiomePlaceables(
return null // whut
if (staticRandomDouble(x, y, blockSeed) <= blockProbability) {
return Placement(randomItems[staticRandomInt(0, randomItems.size, x, y, blockSeed)], Vector2i(x, y), priority)
return Placement(randomItems[staticRandomInt(0, randomItems.size - 1, x, y, blockSeed)], Vector2i(x, y), priority)
}
} else {
if (weightedItems.isEmpty())

View File

@ -259,7 +259,7 @@ class WorldTemplate(val geometry: WorldGeometry) {
for (layer in worldParameters.layers) {
if (layer.dungeons.isNotEmpty()) {
val dungeonSpacing = geometry.size.x / layer.dungeons.size
var dungeonOffset = staticRandomInt(0, geometry.size.x, seed, layer.layerBaseHeight, "dungeon")
var dungeonOffset = staticRandomInt(0, geometry.size.x - 1, seed, layer.layerBaseHeight, "dungeon")
for (dungeon in layer.dungeons) {
if (dungeon.isPresent) {
@ -303,7 +303,7 @@ class WorldTemplate(val geometry: WorldGeometry) {
.maximumSize(1_500_000L) // plentiful of space, and allows for high hit ratio (around 79%) in most situations
// downside is memory consumption, but why should it matter when we save 80% of cpu time?
.expireAfterAccess(Duration.ofSeconds(20))
.executor(Starbound.EXECUTOR)
.executor(Starbound.SCREENED_EXECUTOR)
.scheduler(Starbound)
// .recordStats()
.build<Vector2i, CellInfo> { (x, y) -> cellInfo0(x, y) }

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.kstarbound.lua.bindings
import org.classdump.luna.ByteString
import org.classdump.luna.LuaRuntimeException
import org.classdump.luna.TableFactory
import org.classdump.luna.impl.NonsuspendableFunctionException
import org.classdump.luna.runtime.AbstractFunction1
import org.classdump.luna.runtime.ExecutionContext
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.lua.from
class AssetJsonFunction(private val tables: TableFactory) : AbstractFunction1<ByteString>() {
override fun resume(context: ExecutionContext?, suspendedState: Any?) {
throw NonsuspendableFunctionException(this::class.java)
}
override fun invoke(context: ExecutionContext, arg1: ByteString?) {
arg1 ?: throw LuaRuntimeException("bad argument #1 to root.assetJson (string expected, got nil)")
val load = Starbound.loadJsonAsset(arg1.decode())
if (load == null) {
context.returnBuffer.setTo()
} else {
context.returnBuffer.setTo(tables.from(load))
}
}
}

View File

@ -350,7 +350,10 @@ fun provideRootBindings(lua: LuaEnvironment) {
val table = lua.newTable()
lua.globals["root"] = table
table["assetJson"] = AssetJsonFunction(lua)
table["assetJson"] = luaFunction { path: ByteString ->
returnBuffer.setTo(from(Starbound.loadJsonAsset(path.decode())))
}
table["makeCurrentVersionedJson"] = luaStub("makeCurrentVersionedJson")
table["loadVersionedJson"] = luaStub("loadVersionedJson")

View File

@ -29,6 +29,7 @@ import ru.dbotthepony.kstarbound.util.random.staticRandomLong
import ru.dbotthepony.kstarbound.util.toStarboundString
import java.util.*
import java.util.random.RandomGenerator
import kotlin.math.sign
private val LOGGER = LogManager.getLogger()

View File

@ -1,10 +1,12 @@
package ru.dbotthepony.kstarbound.lua.bindings
import org.classdump.luna.Table
import org.classdump.luna.runtime.ExecutionContext
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
import ru.dbotthepony.kstarbound.lua.get
import ru.dbotthepony.kstarbound.lua.luaFunction
import ru.dbotthepony.kstarbound.lua.set
import ru.dbotthepony.kstarbound.lua.toPoly
import ru.dbotthepony.kstarbound.lua.toVector2d
import ru.dbotthepony.kstarbound.world.World
@ -23,4 +25,8 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) {
returnBuffer.setTo(self.geometry.diff(toVector2d(arg1), toVector2d(arg2)).length)
}
}
callbacks["polyContains"] = luaFunction { poly: Table, position: Table ->
returnBuffer.setTo(self.geometry.polyContains(toPoly(poly), toVector2d(position)))
}
}

View File

@ -221,7 +221,7 @@ class ServerUniverse private constructor(marker: Nothing?) : Universe(), Closeab
.maximumSize(1024L)
.softValues()
.scheduler(Starbound)
.executor(Starbound.EXECUTOR)
.executor(Starbound.SCREENED_EXECUTOR)
.build()
fun getChunkFuture(pos: Vector2i): CompletableFuture<KOptional<UniverseChunk>> {

View File

@ -18,6 +18,7 @@ import ru.dbotthepony.kstarbound.client.network.packets.ChunkCellsPacket
import ru.dbotthepony.kstarbound.defs.SpawnTarget
import ru.dbotthepony.kstarbound.defs.WarpAction
import ru.dbotthepony.kstarbound.defs.WorldID
import ru.dbotthepony.kstarbound.defs.world.FlyingType
import ru.dbotthepony.kstarbound.network.IPacket
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
import ru.dbotthepony.kstarbound.network.packets.EntityDestroyPacket
@ -127,6 +128,8 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
}
}
private var lastSeenFlyingType = FlyingType.NONE
fun tick() {
if (!client.worldStartAcknowledged)
return
@ -144,11 +147,12 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
}
run {
if (skyUpdateWaitTicks++ >= 20) {
if (skyUpdateWaitTicks++ >= 20 || world.sky.flyingType != lastSeenFlyingType) {
val (data, version) = world.sky.networkedGroup.write(skyVersion, isLegacy = client.isLegacy)
skyVersion = version
send(EnvironmentUpdatePacket(data, ByteArrayList()))
skyUpdateWaitTicks = 0
lastSeenFlyingType = world.sky.flyingType
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.kstarbound.util
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
@ -129,7 +130,7 @@ open class BlockableEventLoop(name: String) : Thread(name), ScheduledExecutorSer
}
if (scheduledQueue.isNotEmpty()) {
val executed = ArrayList<ScheduledTask<*>>()
val executed = ObjectArrayList<ScheduledTask<*>>(4)
var lastSize: Int
do {

View File

@ -86,14 +86,14 @@ fun staticRandomDouble(vararg values: Any?): Double {
return staticRandom64(*values).ushr(11) * 1.1102230246251565E-16
}
fun staticRandomInt(origin: Int, bound: Int, vararg values: Any?): Int {
val rand = staticRandomDouble(*values)
return origin + ((bound - origin) * rand).toInt()
fun staticRandomInt(min: Int, max: Int, vararg values: Any?): Int {
val hash = staticRandomDouble(*values)
return (min + (max - min + 1) * hash).toInt()
}
fun staticRandomLong(origin: Long, bound: Long, vararg values: Any?): Long {
val rand = staticRandomDouble(*values)
return origin + ((bound - origin) * rand).toLong()
fun staticRandomLong(min: Long, max: Long, vararg values: Any?): Long {
val hash = staticRandomDouble(*values)
return (min + (max - min + 1L) * hash).toLong()
}
fun staticRandom64(vararg values: Any?): Long {

View File

@ -90,7 +90,7 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
// bulk mark collision dirty of neighbour chunks as well as ours
protected fun signalChunkContentsUpdated() {
val signalPositions = ArrayList<Vector2i>()
val signalPositions = ObjectArrayList<Vector2i>(24)
for (x in 1 .. 2) {
for (y in 1 .. 2) {

View File

@ -98,12 +98,18 @@ class Sky() {
}
fun startFlying(enterHyperspace: Boolean, startInWarp: Boolean = false) {
if (flyingType == FlyingType.NONE)
flyingTimer = 0.0
else if (flyingType == FlyingType.WARP && warpPhase == WarpPhase.SLOWING_DOWN) {
warpPhase = WarpPhase.SPEEDING_UP
flyingTimer = speedupTime
}
if (startInWarp)
flyingType = FlyingType.WARP
else if (flyingType == FlyingType.NONE)
flyingType = FlyingType.DISEMBARKING
// flyingTimer = 0.0
this.enterHyperspace = enterHyperspace
this.startInWarp = startInWarp
}
@ -113,6 +119,11 @@ class Sky() {
if (skyType != SkyType.WARP)
skyType = SkyType.ORBITAL
if (flyingType == FlyingType.NONE || flyingType == FlyingType.ARRIVING) {
this.skyParameters = destination
this.destination = null
}
}
private var lastFlyingType = FlyingType.NONE

View File

@ -240,4 +240,13 @@ data class WorldGeometry(val size: Vector2i, val loopX: Boolean = true, val loop
fun polyDistance(poly: Poly, point: IStruct2d): Double {
return poly.distance(nearestTo(poly.centre, point))
}
fun split(poly: Poly): List<Poly> {
TODO()
}
fun polyContains(poly: Poly, point: IStruct2d): Boolean {
val wrap = wrap(point)
return split(poly).any { it.contains(wrap) }
}
}

View File

@ -62,7 +62,7 @@ class KarstCaveTerrainSelector(data: Data, parameters: TerrainSelectorParameters
.softValues()
.expireAfterAccess(Duration.ofMinutes(1))
.scheduler(Starbound)
.executor(Starbound.EXECUTOR)
.executor(Starbound.SCREENED_EXECUTOR)
.build<Int, Layer>(::Layer)
private inner class Sector(val sector: Vector2i) {
@ -131,7 +131,7 @@ class KarstCaveTerrainSelector(data: Data, parameters: TerrainSelectorParameters
.softValues()
.expireAfterAccess(Duration.ofMinutes(1))
.scheduler(Starbound)
.executor(Starbound.EXECUTOR)
.executor(Starbound.SCREENED_EXECUTOR)
.build<Vector2i, Sector>(::Sector)
override fun get(x: Int, y: Int): Double {

View File

@ -185,7 +185,7 @@ class WormCaveTerrainSelector(data: Data, parameters: TerrainSelectorParameters)
.softValues()
.expireAfterAccess(Duration.ofMinutes(1))
.scheduler(Starbound)
.executor(Starbound.EXECUTOR)
.executor(Starbound.SCREENED_EXECUTOR)
.build<Vector2i, Sector>(::Sector)
override fun get(x: Int, y: Int): Double {