Misc perfromance improvements
This commit is contained in:
parent
100afadd5c
commit
fffc0b6102
@ -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
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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())
|
||||
|
@ -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) }
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
@ -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>> {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user