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 org.lwjgl.Version
|
||||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||||
import ru.dbotthepony.kstarbound.server.IntegratedStarboundServer
|
import ru.dbotthepony.kstarbound.server.IntegratedStarboundServer
|
||||||
import ru.dbotthepony.kstarbound.util.random.random
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
|
|
||||||
|
@ -151,6 +151,12 @@ object Starbound : BlockableEventLoop("Universe Thread"), Scheduler, ISBFileLoca
|
|||||||
@JvmField
|
@JvmField
|
||||||
val COROUTINE_EXECUTOR = ExecutorWithScheduler(EXECUTOR, this).asCoroutineDispatcher()
|
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
|
@JvmField
|
||||||
val CLEANER: Cleaner = Cleaner.create {
|
val CLEANER: Cleaner = Cleaner.create {
|
||||||
val t = Thread(it, "Starbound Global Cleaner")
|
val t = Thread(it, "Starbound Global Cleaner")
|
||||||
|
@ -345,7 +345,7 @@ class Image private constructor(
|
|||||||
.weigher<IStarboundFile, ByteBuffer> { key, value -> value.capacity() }
|
.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 МиБ */))
|
.maximumWeight((Runtime.getRuntime().maxMemory() / 4L).coerceIn(1_024L * 1_024L * 32L /* 32 МиБ */, 1_024L * 1_024L * 256L /* 256 МиБ */))
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.EXECUTOR) // SCREENED_EXECUTOR shouldn't be used here
|
||||||
.buildAsync(CacheLoader {
|
.buildAsync(CacheLoader {
|
||||||
readImageDirect(it).data
|
readImageDirect(it).data
|
||||||
})
|
})
|
||||||
|
@ -228,7 +228,7 @@ data class BiomePlaceables(
|
|||||||
return null // whut
|
return null // whut
|
||||||
|
|
||||||
if (staticRandomDouble(x, y, blockSeed) <= blockProbability) {
|
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 {
|
} else {
|
||||||
if (weightedItems.isEmpty())
|
if (weightedItems.isEmpty())
|
||||||
|
@ -259,7 +259,7 @@ class WorldTemplate(val geometry: WorldGeometry) {
|
|||||||
for (layer in worldParameters.layers) {
|
for (layer in worldParameters.layers) {
|
||||||
if (layer.dungeons.isNotEmpty()) {
|
if (layer.dungeons.isNotEmpty()) {
|
||||||
val dungeonSpacing = geometry.size.x / layer.dungeons.size
|
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) {
|
for (dungeon in layer.dungeons) {
|
||||||
if (dungeon.isPresent) {
|
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
|
.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?
|
// downside is memory consumption, but why should it matter when we save 80% of cpu time?
|
||||||
.expireAfterAccess(Duration.ofSeconds(20))
|
.expireAfterAccess(Duration.ofSeconds(20))
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.SCREENED_EXECUTOR)
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
// .recordStats()
|
// .recordStats()
|
||||||
.build<Vector2i, CellInfo> { (x, y) -> cellInfo0(x, y) }
|
.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()
|
val table = lua.newTable()
|
||||||
lua.globals["root"] = table
|
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["makeCurrentVersionedJson"] = luaStub("makeCurrentVersionedJson")
|
||||||
table["loadVersionedJson"] = luaStub("loadVersionedJson")
|
table["loadVersionedJson"] = luaStub("loadVersionedJson")
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import ru.dbotthepony.kstarbound.util.random.staticRandomLong
|
|||||||
import ru.dbotthepony.kstarbound.util.toStarboundString
|
import ru.dbotthepony.kstarbound.util.toStarboundString
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.random.RandomGenerator
|
import java.util.random.RandomGenerator
|
||||||
|
import kotlin.math.sign
|
||||||
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package ru.dbotthepony.kstarbound.lua.bindings
|
package ru.dbotthepony.kstarbound.lua.bindings
|
||||||
|
|
||||||
import org.classdump.luna.Table
|
import org.classdump.luna.Table
|
||||||
|
import org.classdump.luna.runtime.ExecutionContext
|
||||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||||
import ru.dbotthepony.kstarbound.lua.get
|
import ru.dbotthepony.kstarbound.lua.get
|
||||||
import ru.dbotthepony.kstarbound.lua.luaFunction
|
import ru.dbotthepony.kstarbound.lua.luaFunction
|
||||||
import ru.dbotthepony.kstarbound.lua.set
|
import ru.dbotthepony.kstarbound.lua.set
|
||||||
|
import ru.dbotthepony.kstarbound.lua.toPoly
|
||||||
import ru.dbotthepony.kstarbound.lua.toVector2d
|
import ru.dbotthepony.kstarbound.lua.toVector2d
|
||||||
import ru.dbotthepony.kstarbound.world.World
|
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)
|
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)
|
.maximumSize(1024L)
|
||||||
.softValues()
|
.softValues()
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.SCREENED_EXECUTOR)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun getChunkFuture(pos: Vector2i): CompletableFuture<KOptional<UniverseChunk>> {
|
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.SpawnTarget
|
||||||
import ru.dbotthepony.kstarbound.defs.WarpAction
|
import ru.dbotthepony.kstarbound.defs.WarpAction
|
||||||
import ru.dbotthepony.kstarbound.defs.WorldID
|
import ru.dbotthepony.kstarbound.defs.WorldID
|
||||||
|
import ru.dbotthepony.kstarbound.defs.world.FlyingType
|
||||||
import ru.dbotthepony.kstarbound.network.IPacket
|
import ru.dbotthepony.kstarbound.network.IPacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
|
import ru.dbotthepony.kstarbound.network.packets.EntityCreatePacket
|
||||||
import ru.dbotthepony.kstarbound.network.packets.EntityDestroyPacket
|
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() {
|
fun tick() {
|
||||||
if (!client.worldStartAcknowledged)
|
if (!client.worldStartAcknowledged)
|
||||||
return
|
return
|
||||||
@ -144,11 +147,12 @@ class ServerWorldTracker(val world: ServerWorld, val client: ServerConnection, p
|
|||||||
}
|
}
|
||||||
|
|
||||||
run {
|
run {
|
||||||
if (skyUpdateWaitTicks++ >= 20) {
|
if (skyUpdateWaitTicks++ >= 20 || world.sky.flyingType != lastSeenFlyingType) {
|
||||||
val (data, version) = world.sky.networkedGroup.write(skyVersion, isLegacy = client.isLegacy)
|
val (data, version) = world.sky.networkedGroup.write(skyVersion, isLegacy = client.isLegacy)
|
||||||
skyVersion = version
|
skyVersion = version
|
||||||
send(EnvironmentUpdatePacket(data, ByteArrayList()))
|
send(EnvironmentUpdatePacket(data, ByteArrayList()))
|
||||||
skyUpdateWaitTicks = 0
|
skyUpdateWaitTicks = 0
|
||||||
|
lastSeenFlyingType = world.sky.flyingType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.kstarbound.util
|
package ru.dbotthepony.kstarbound.util
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
@ -129,7 +130,7 @@ open class BlockableEventLoop(name: String) : Thread(name), ScheduledExecutorSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scheduledQueue.isNotEmpty()) {
|
if (scheduledQueue.isNotEmpty()) {
|
||||||
val executed = ArrayList<ScheduledTask<*>>()
|
val executed = ObjectArrayList<ScheduledTask<*>>(4)
|
||||||
var lastSize: Int
|
var lastSize: Int
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -86,14 +86,14 @@ fun staticRandomDouble(vararg values: Any?): Double {
|
|||||||
return staticRandom64(*values).ushr(11) * 1.1102230246251565E-16
|
return staticRandom64(*values).ushr(11) * 1.1102230246251565E-16
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticRandomInt(origin: Int, bound: Int, vararg values: Any?): Int {
|
fun staticRandomInt(min: Int, max: Int, vararg values: Any?): Int {
|
||||||
val rand = staticRandomDouble(*values)
|
val hash = staticRandomDouble(*values)
|
||||||
return origin + ((bound - origin) * rand).toInt()
|
return (min + (max - min + 1) * hash).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticRandomLong(origin: Long, bound: Long, vararg values: Any?): Long {
|
fun staticRandomLong(min: Long, max: Long, vararg values: Any?): Long {
|
||||||
val rand = staticRandomDouble(*values)
|
val hash = staticRandomDouble(*values)
|
||||||
return origin + ((bound - origin) * rand).toLong()
|
return (min + (max - min + 1L) * hash).toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun staticRandom64(vararg values: Any?): Long {
|
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
|
// bulk mark collision dirty of neighbour chunks as well as ours
|
||||||
protected fun signalChunkContentsUpdated() {
|
protected fun signalChunkContentsUpdated() {
|
||||||
val signalPositions = ArrayList<Vector2i>()
|
val signalPositions = ObjectArrayList<Vector2i>(24)
|
||||||
|
|
||||||
for (x in 1 .. 2) {
|
for (x in 1 .. 2) {
|
||||||
for (y in 1 .. 2) {
|
for (y in 1 .. 2) {
|
||||||
|
@ -98,12 +98,18 @@ class Sky() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startFlying(enterHyperspace: Boolean, startInWarp: Boolean = false) {
|
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)
|
if (startInWarp)
|
||||||
flyingType = FlyingType.WARP
|
flyingType = FlyingType.WARP
|
||||||
else if (flyingType == FlyingType.NONE)
|
else if (flyingType == FlyingType.NONE)
|
||||||
flyingType = FlyingType.DISEMBARKING
|
flyingType = FlyingType.DISEMBARKING
|
||||||
|
|
||||||
// flyingTimer = 0.0
|
|
||||||
this.enterHyperspace = enterHyperspace
|
this.enterHyperspace = enterHyperspace
|
||||||
this.startInWarp = startInWarp
|
this.startInWarp = startInWarp
|
||||||
}
|
}
|
||||||
@ -113,6 +119,11 @@ class Sky() {
|
|||||||
|
|
||||||
if (skyType != SkyType.WARP)
|
if (skyType != SkyType.WARP)
|
||||||
skyType = SkyType.ORBITAL
|
skyType = SkyType.ORBITAL
|
||||||
|
|
||||||
|
if (flyingType == FlyingType.NONE || flyingType == FlyingType.ARRIVING) {
|
||||||
|
this.skyParameters = destination
|
||||||
|
this.destination = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastFlyingType = FlyingType.NONE
|
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 {
|
fun polyDistance(poly: Poly, point: IStruct2d): Double {
|
||||||
return poly.distance(nearestTo(poly.centre, point))
|
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()
|
.softValues()
|
||||||
.expireAfterAccess(Duration.ofMinutes(1))
|
.expireAfterAccess(Duration.ofMinutes(1))
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.SCREENED_EXECUTOR)
|
||||||
.build<Int, Layer>(::Layer)
|
.build<Int, Layer>(::Layer)
|
||||||
|
|
||||||
private inner class Sector(val sector: Vector2i) {
|
private inner class Sector(val sector: Vector2i) {
|
||||||
@ -131,7 +131,7 @@ class KarstCaveTerrainSelector(data: Data, parameters: TerrainSelectorParameters
|
|||||||
.softValues()
|
.softValues()
|
||||||
.expireAfterAccess(Duration.ofMinutes(1))
|
.expireAfterAccess(Duration.ofMinutes(1))
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.SCREENED_EXECUTOR)
|
||||||
.build<Vector2i, Sector>(::Sector)
|
.build<Vector2i, Sector>(::Sector)
|
||||||
|
|
||||||
override fun get(x: Int, y: Int): Double {
|
override fun get(x: Int, y: Int): Double {
|
||||||
|
@ -185,7 +185,7 @@ class WormCaveTerrainSelector(data: Data, parameters: TerrainSelectorParameters)
|
|||||||
.softValues()
|
.softValues()
|
||||||
.expireAfterAccess(Duration.ofMinutes(1))
|
.expireAfterAccess(Duration.ofMinutes(1))
|
||||||
.scheduler(Starbound)
|
.scheduler(Starbound)
|
||||||
.executor(Starbound.EXECUTOR)
|
.executor(Starbound.SCREENED_EXECUTOR)
|
||||||
.build<Vector2i, Sector>(::Sector)
|
.build<Vector2i, Sector>(::Sector)
|
||||||
|
|
||||||
override fun get(x: Int, y: Int): Double {
|
override fun get(x: Int, y: Int): Double {
|
||||||
|
Loading…
Reference in New Issue
Block a user