Smarter multithreading
This commit is contained in:
parent
6ae8066ebc
commit
425494e104
@ -15,7 +15,6 @@ import java.util.concurrent.ForkJoinPool
|
|||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.full.createType
|
|
||||||
|
|
||||||
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
|
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
|
||||||
return registerTypeAdapter(T::class.java, adapter)
|
return registerTypeAdapter(T::class.java, adapter)
|
||||||
@ -37,17 +36,17 @@ inline fun <reified T> GsonBuilder.registerTypeAdapter(noinline factory: (Gson)
|
|||||||
|
|
||||||
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
|
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
|
||||||
|
|
||||||
operator fun <T> ThreadLocal<T>.getValue(thisRef: Any, property: KProperty<*>): T? {
|
operator fun <T> ThreadLocal<T>.getValue(thisRef: Any, property: KProperty<*>): T {
|
||||||
return get()
|
return get()
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <T> ThreadLocal<T>.setValue(thisRef: Any, property: KProperty<*>, value: T?) {
|
operator fun <T> ThreadLocal<T>.setValue(thisRef: Any, property: KProperty<*>, value: T) {
|
||||||
set(value)
|
set(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <K, V> ImmutableMap.Builder<K, V>.set(key: K, value: V): ImmutableMap.Builder<K, V> = put(key, value)
|
operator fun <K, V> ImmutableMap.Builder<K, V>.set(key: K, value: V): ImmutableMap.Builder<K, V> = put(key, value)
|
||||||
|
|
||||||
fun String.sintern(): String = Starbound.strings.intern(this)
|
fun String.sintern(): String = Starbound.STRINGS.intern(this)
|
||||||
|
|
||||||
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ fun main() {
|
|||||||
for (chunkX in 0 .. 100) {
|
for (chunkX in 0 .. 100) {
|
||||||
//for (chunkX in 0 .. 17) {
|
//for (chunkX in 0 .. 17) {
|
||||||
// for (chunkY in 21 .. 21) {
|
// for (chunkY in 21 .. 21) {
|
||||||
for (chunkY in 18 .. 24) {
|
for (chunkY in 0 .. 24) {
|
||||||
val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
val data = db.read(byteArrayOf(1, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
||||||
val data2 = db.read(byteArrayOf(2, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
val data2 = db.read(byteArrayOf(2, 0, chunkX.toByte(), 0, chunkY.toByte()))
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@ package ru.dbotthepony.kstarbound
|
|||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Interner
|
import com.github.benmanes.caffeine.cache.Interner
|
||||||
import com.google.gson.*
|
import com.google.gson.*
|
||||||
import com.google.gson.internal.bind.JsonTreeReader
|
|
||||||
import com.google.gson.stream.JsonReader
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
@ -15,37 +13,15 @@ import ru.dbotthepony.kstarbound.api.PhysicalFile
|
|||||||
import ru.dbotthepony.kstarbound.defs.*
|
import ru.dbotthepony.kstarbound.defs.*
|
||||||
import ru.dbotthepony.kstarbound.defs.image.Image
|
import ru.dbotthepony.kstarbound.defs.image.Image
|
||||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.BackArmorItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.ChestArmorItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.CurrencyItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.FlashlightDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.HarvestingToolPrototype
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.HeadArmorItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IArmorItemDefinition
|
import ru.dbotthepony.kstarbound.defs.item.api.IArmorItemDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.InventoryIcon
|
import ru.dbotthepony.kstarbound.defs.item.InventoryIcon
|
||||||
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.ItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.LegsArmorItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.LiquidItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.item.impl.MaterialItemDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.monster.MonsterSkillDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.monster.MonsterTypeDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.npc.NpcTypeDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.npc.TenantDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.`object`.ObjectDefinition
|
import ru.dbotthepony.kstarbound.defs.`object`.ObjectDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.`object`.ObjectOrientation
|
import ru.dbotthepony.kstarbound.defs.`object`.ObjectOrientation
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.particle.ParticleDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
import ru.dbotthepony.kstarbound.defs.player.BlueprintLearnList
|
||||||
import ru.dbotthepony.kstarbound.defs.player.PlayerDefinition
|
import ru.dbotthepony.kstarbound.defs.player.PlayerDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.player.RecipeDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.player.TechDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.projectile.ProjectileDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.defs.quest.QuestTemplate
|
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.util.JsonArrayCollector
|
import ru.dbotthepony.kstarbound.util.JsonArrayCollector
|
||||||
import ru.dbotthepony.kstarbound.io.*
|
import ru.dbotthepony.kstarbound.io.*
|
||||||
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
|
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
|
||||||
@ -85,12 +61,10 @@ import ru.dbotthepony.kstarbound.util.filterNotNull
|
|||||||
import ru.dbotthepony.kstarbound.util.set
|
import ru.dbotthepony.kstarbound.util.set
|
||||||
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.lang.ref.Cleaner
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.ForkJoinPool
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.ForkJoinTask
|
import java.util.concurrent.ForkJoinTask
|
||||||
import java.util.concurrent.Future
|
|
||||||
import java.util.function.BiConsumer
|
import java.util.function.BiConsumer
|
||||||
import java.util.function.BinaryOperator
|
import java.util.function.BinaryOperator
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
@ -104,15 +78,22 @@ object Starbound : ISBFileLocator {
|
|||||||
const val TICK_TIME_ADVANCE = 0.01666666666666664
|
const val TICK_TIME_ADVANCE = 0.01666666666666664
|
||||||
const val TICK_TIME_ADVANCE_NANOS = 16_666_666L
|
const val TICK_TIME_ADVANCE_NANOS = 16_666_666L
|
||||||
|
|
||||||
|
val CLEANER: Cleaner = Cleaner.create {
|
||||||
|
val t = Thread(it, "Starbound Global Cleaner Thread")
|
||||||
|
t.isDaemon = true
|
||||||
|
t.priority = 2
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
// currently Caffeine one saves only 4 megabytes of RAM on pretty big modpack
|
// currently Caffeine one saves only 4 megabytes of RAM on pretty big modpack
|
||||||
// Hrm.
|
// Hrm.
|
||||||
// val strings: Interner<String> = Interner.newWeakInterner()
|
// val strings: Interner<String> = Interner.newWeakInterner()
|
||||||
// val strings: Interner<String> = Interner { it }
|
// val strings: Interner<String> = Interner { it }
|
||||||
val strings: Interner<String> = HashTableInterner(5)
|
val STRINGS: Interner<String> = HashTableInterner(5)
|
||||||
|
|
||||||
private val polyfill by lazy { loadInternalScript("polyfill") }
|
private val polyfill by lazy { loadInternalScript("polyfill") }
|
||||||
|
|
||||||
private val logger = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
val gson: Gson = with(GsonBuilder()) {
|
val gson: Gson = with(GsonBuilder()) {
|
||||||
serializeNulls()
|
serializeNulls()
|
||||||
@ -120,9 +101,9 @@ object Starbound : ISBFileLocator {
|
|||||||
setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
|
setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)
|
||||||
setPrettyPrinting()
|
setPrettyPrinting()
|
||||||
|
|
||||||
registerTypeAdapter(InternedStringAdapter(strings))
|
registerTypeAdapter(InternedStringAdapter(STRINGS))
|
||||||
|
|
||||||
InternedJsonElementAdapter(strings).also {
|
InternedJsonElementAdapter(STRINGS).also {
|
||||||
registerTypeAdapter(it)
|
registerTypeAdapter(it)
|
||||||
registerTypeAdapter(it.arrays)
|
registerTypeAdapter(it.arrays)
|
||||||
registerTypeAdapter(it.objects)
|
registerTypeAdapter(it.objects)
|
||||||
@ -134,10 +115,10 @@ object Starbound : ISBFileLocator {
|
|||||||
registerTypeAdapterFactory(JsonImplementationTypeFactory)
|
registerTypeAdapterFactory(JsonImplementationTypeFactory)
|
||||||
|
|
||||||
// ImmutableList, ImmutableSet, ImmutableMap
|
// ImmutableList, ImmutableSet, ImmutableMap
|
||||||
registerTypeAdapterFactory(ImmutableCollectionAdapterFactory(strings))
|
registerTypeAdapterFactory(ImmutableCollectionAdapterFactory(STRINGS))
|
||||||
|
|
||||||
// fastutil collections
|
// fastutil collections
|
||||||
registerTypeAdapterFactory(FastutilTypeAdapterFactory(strings))
|
registerTypeAdapterFactory(FastutilTypeAdapterFactory(STRINGS))
|
||||||
|
|
||||||
// ArrayList
|
// ArrayList
|
||||||
registerTypeAdapterFactory(ArrayListAdapterFactory)
|
registerTypeAdapterFactory(ArrayListAdapterFactory)
|
||||||
@ -146,10 +127,10 @@ object Starbound : ISBFileLocator {
|
|||||||
registerTypeAdapterFactory(EnumAdapter.Companion)
|
registerTypeAdapterFactory(EnumAdapter.Companion)
|
||||||
|
|
||||||
// @JsonBuilder
|
// @JsonBuilder
|
||||||
registerTypeAdapterFactory(BuilderAdapter.Factory(strings))
|
registerTypeAdapterFactory(BuilderAdapter.Factory(STRINGS))
|
||||||
|
|
||||||
// @JsonFactory
|
// @JsonFactory
|
||||||
registerTypeAdapterFactory(FactoryAdapter.Factory(strings))
|
registerTypeAdapterFactory(FactoryAdapter.Factory(STRINGS))
|
||||||
|
|
||||||
// Either<>
|
// Either<>
|
||||||
registerTypeAdapterFactory(EitherTypeAdapter)
|
registerTypeAdapterFactory(EitherTypeAdapter)
|
||||||
@ -192,7 +173,7 @@ object Starbound : ISBFileLocator {
|
|||||||
registerTypeAdapterFactory(Json2Function.Companion)
|
registerTypeAdapterFactory(Json2Function.Companion)
|
||||||
|
|
||||||
// Общее
|
// Общее
|
||||||
registerTypeAdapterFactory(ThingDescription.Factory(strings))
|
registerTypeAdapterFactory(ThingDescription.Factory(STRINGS))
|
||||||
|
|
||||||
registerTypeAdapter(EnumAdapter(DamageType::class, default = DamageType.NORMAL))
|
registerTypeAdapter(EnumAdapter(DamageType::class, default = DamageType.NORMAL))
|
||||||
|
|
||||||
@ -206,7 +187,7 @@ object Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
registerTypeAdapter(ItemStack.Adapter(this@Starbound))
|
registerTypeAdapter(ItemStack.Adapter(this@Starbound))
|
||||||
|
|
||||||
registerTypeAdapterFactory(ItemReference.Factory(strings))
|
registerTypeAdapterFactory(ItemReference.Factory(STRINGS))
|
||||||
registerTypeAdapterFactory(TreasurePoolDefinition.Companion)
|
registerTypeAdapterFactory(TreasurePoolDefinition.Companion)
|
||||||
|
|
||||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
||||||
@ -846,10 +827,10 @@ object Starbound : ISBFileLocator {
|
|||||||
var time = System.currentTimeMillis()
|
var time = System.currentTimeMillis()
|
||||||
|
|
||||||
if (archivePaths.isNotEmpty()) {
|
if (archivePaths.isNotEmpty()) {
|
||||||
log.line("Searching for pak archives...".also(logger::info))
|
log.line("Searching for pak archives...".also(LOGGER::info))
|
||||||
|
|
||||||
for (path in archivePaths) {
|
for (path in archivePaths) {
|
||||||
val line = log.line("Reading index of ${path}...".also(logger::info))
|
val line = log.line("Reading index of ${path}...".also(LOGGER::info))
|
||||||
|
|
||||||
addPak(StarboundPak(path) { _, status ->
|
addPak(StarboundPak(path) { _, status ->
|
||||||
line.text = ("${path.parent}/${path.name}: $status")
|
line.text = ("${path.parent}/${path.name}: $status")
|
||||||
@ -857,9 +838,9 @@ object Starbound : ISBFileLocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.line("Finished reading pak archives in ${System.currentTimeMillis() - time}ms".also(logger::info))
|
log.line("Finished reading pak archives in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
|
||||||
time = System.currentTimeMillis()
|
time = System.currentTimeMillis()
|
||||||
log.line("Building file index...".also(logger::info))
|
log.line("Building file index...".also(LOGGER::info))
|
||||||
|
|
||||||
val ext2files = fileSystems.parallelStream()
|
val ext2files = fileSystems.parallelStream()
|
||||||
.flatMap { it.explore() }
|
.flatMap { it.explore() }
|
||||||
@ -895,7 +876,7 @@ object Starbound : ISBFileLocator {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
log.line("Finished building file index in ${System.currentTimeMillis() - time}ms".also(logger::info))
|
log.line("Finished building file index in ${System.currentTimeMillis() - time}ms".also(LOGGER::info))
|
||||||
|
|
||||||
val tasks = ArrayList<ForkJoinTask<*>>()
|
val tasks = ArrayList<ForkJoinTask<*>>()
|
||||||
val pool = if (parallel) ForkJoinPool.commonPool() else ForkJoinPool(1)
|
val pool = if (parallel) ForkJoinPool.commonPool() else ForkJoinPool(1)
|
||||||
|
@ -13,6 +13,7 @@ import org.lwjgl.opengl.GLCapabilities
|
|||||||
import org.lwjgl.system.MemoryStack
|
import org.lwjgl.system.MemoryStack
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
import ru.dbotthepony.kstarbound.LoadingLog
|
import ru.dbotthepony.kstarbound.LoadingLog
|
||||||
|
import ru.dbotthepony.kstarbound.util.ManualExecutorService
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
@ -49,7 +50,6 @@ import ru.dbotthepony.kstarbound.client.world.ClientWorld
|
|||||||
import ru.dbotthepony.kstarbound.defs.image.Image
|
import ru.dbotthepony.kstarbound.defs.image.Image
|
||||||
import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
|
import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
|
||||||
import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity
|
import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity
|
||||||
import ru.dbotthepony.kstarbound.util.Either
|
|
||||||
import ru.dbotthepony.kstarbound.util.forEachValid
|
import ru.dbotthepony.kstarbound.util.forEachValid
|
||||||
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
||||||
import ru.dbotthepony.kstarbound.world.LightCalculator
|
import ru.dbotthepony.kstarbound.world.LightCalculator
|
||||||
@ -73,29 +73,24 @@ import java.nio.ByteBuffer
|
|||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.concurrent.CancellationException
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
|
||||||
import java.util.concurrent.ExecutionException
|
|
||||||
import java.util.concurrent.ExecutorService
|
|
||||||
import java.util.concurrent.Future
|
|
||||||
import java.util.concurrent.FutureTask
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
import java.util.concurrent.locks.LockSupport
|
import java.util.concurrent.locks.LockSupport
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
|
||||||
import java.util.function.IntConsumer
|
import java.util.function.IntConsumer
|
||||||
import kotlin.NoSuchElementException
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class StarboundClient : Closeable, ExecutorService {
|
class StarboundClient : Closeable {
|
||||||
val window: Long
|
val window: Long
|
||||||
val camera = Camera(this)
|
val camera = Camera(this)
|
||||||
val input = UserInput()
|
val input = UserInput()
|
||||||
val thread: Thread = Thread.currentThread()
|
val thread: Thread = Thread.currentThread()
|
||||||
|
// client specific executor which will accept tasks which involve probable
|
||||||
|
// callback to foreground executor to initialize thread-unsafe data
|
||||||
|
// In above case multiple threads will introduce big congestion for resources
|
||||||
|
val backgroundExecutor = ForkJoinPool(Runtime.getRuntime().availableProcessors().coerceAtMost(4))
|
||||||
|
val foregroundExecutor = ManualExecutorService(thread)
|
||||||
val capabilities: GLCapabilities
|
val capabilities: GLCapabilities
|
||||||
|
|
||||||
var viewportX: Int = 0
|
var viewportX: Int = 0
|
||||||
@ -150,8 +145,6 @@ class StarboundClient : Closeable, ExecutorService {
|
|||||||
|
|
||||||
val loadingLog = LoadingLog()
|
val loadingLog = LoadingLog()
|
||||||
|
|
||||||
private val executeQueue = ConcurrentLinkedQueue<Runnable>()
|
|
||||||
private val futureQueue = ConcurrentLinkedQueue<FutureTask<*>>()
|
|
||||||
private val openglCleanQueue = ReferenceQueue<Any>()
|
private val openglCleanQueue = ReferenceQueue<Any>()
|
||||||
private var openglCleanQueueHead: CleanRef? = null
|
private var openglCleanQueueHead: CleanRef? = null
|
||||||
|
|
||||||
@ -160,118 +153,6 @@ class StarboundClient : Closeable, ExecutorService {
|
|||||||
var prev: CleanRef? = null
|
var prev: CleanRef? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class InPlaceFuture<V>(private val value: V) : Future<V> {
|
|
||||||
override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isCancelled(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isDone(): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(): V {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(timeout: Long, unit: TimeUnit): V {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val EMPTY = InPlaceFuture(Unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun execute(command: Runnable) {
|
|
||||||
if (isSameThread()) {
|
|
||||||
command.run()
|
|
||||||
} else {
|
|
||||||
executeQueue.add(command)
|
|
||||||
LockSupport.unpark(thread)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shutdown() {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shutdownNow(): MutableList<Runnable> {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isShutdown(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isTerminated(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> submit(task: Callable<T>): Future<T> {
|
|
||||||
if (isSameThread()) return InPlaceFuture(task.call())
|
|
||||||
return FutureTask(task).also { futureQueue.add(it); LockSupport.unpark(thread) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> submit(task: Runnable, result: T): Future<T> {
|
|
||||||
if (isSameThread()) { task.run(); return InPlaceFuture(result) }
|
|
||||||
return FutureTask { task.run(); result }.also { futureQueue.add(it); LockSupport.unpark(thread) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun submit(task: Runnable): Future<*> {
|
|
||||||
if (isSameThread()) { task.run(); return InPlaceFuture.EMPTY }
|
|
||||||
return FutureTask { task.run() }.also { futureQueue.add(it); LockSupport.unpark(thread) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> invokeAll(tasks: Collection<Callable<T>>): List<Future<T>> {
|
|
||||||
if (isSameThread()) {
|
|
||||||
return tasks.map { InPlaceFuture(it.call()) }
|
|
||||||
} else {
|
|
||||||
return tasks.map { submit(it) }.onEach { it.get() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> invokeAll(
|
|
||||||
tasks: Collection<Callable<T>>,
|
|
||||||
timeout: Long,
|
|
||||||
unit: TimeUnit
|
|
||||||
): List<Future<T>> {
|
|
||||||
if (isSameThread()) {
|
|
||||||
return tasks.map { InPlaceFuture(it.call()) }
|
|
||||||
} else {
|
|
||||||
return tasks.map { submit(it) }.onEach { it.get(timeout, unit) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> invokeAny(tasks: Collection<Callable<T>>): T {
|
|
||||||
if (tasks.isEmpty())
|
|
||||||
throw NoSuchElementException("Provided task list is empty")
|
|
||||||
|
|
||||||
if (isSameThread()) {
|
|
||||||
return tasks.first().call()
|
|
||||||
} else {
|
|
||||||
return submit(tasks.first()).get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any?> invokeAny(tasks: Collection<Callable<T>>, timeout: Long, unit: TimeUnit): T {
|
|
||||||
if (tasks.isEmpty())
|
|
||||||
throw NoSuchElementException("Provided task list is empty")
|
|
||||||
|
|
||||||
if (isSameThread()) {
|
|
||||||
return tasks.first().call()
|
|
||||||
} else {
|
|
||||||
return submit(tasks.first()).get(timeout, unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var openglObjectsCreated = 0L
|
var openglObjectsCreated = 0L
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -421,20 +302,7 @@ class StarboundClient : Closeable, ExecutorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun executeQueuedTasks() {
|
private fun executeQueuedTasks() {
|
||||||
var next = executeQueue.poll()
|
foregroundExecutor.executeQueuedTasks()
|
||||||
|
|
||||||
while (next != null) {
|
|
||||||
next.run()
|
|
||||||
next = executeQueue.poll()
|
|
||||||
}
|
|
||||||
|
|
||||||
var next2 = futureQueue.poll()
|
|
||||||
|
|
||||||
while (next2 != null) {
|
|
||||||
next2.run()
|
|
||||||
Thread.interrupted()
|
|
||||||
next2 = futureQueue.poll()
|
|
||||||
}
|
|
||||||
|
|
||||||
var next3 = openglCleanQueue.poll() as CleanRef?
|
var next3 = openglCleanQueue.poll() as CleanRef?
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ class StreamVertexBuilder(
|
|||||||
) {
|
) {
|
||||||
val builder = VertexBuilder(attributes, type, initialCapacity)
|
val builder = VertexBuilder(attributes, type, initialCapacity)
|
||||||
|
|
||||||
private val vao = client.submit(Callable { VertexArrayObject() })
|
private val vao = client.foregroundExecutor.submit(Callable { VertexArrayObject() })
|
||||||
private val vbo = client.submit(Callable { BufferObject.VBO() })
|
private val vbo = client.foregroundExecutor.submit(Callable { BufferObject.VBO() })
|
||||||
private val ebo = client.submit(Callable { BufferObject.EBO() })
|
private val ebo = client.foregroundExecutor.submit(Callable { BufferObject.EBO() })
|
||||||
|
|
||||||
private var initialized = false
|
private var initialized = false
|
||||||
|
|
||||||
|
@ -52,14 +52,14 @@ class TileRenderers(val client: StarboundClient) {
|
|||||||
fun getMaterialRenderer(defName: String): TileRenderer {
|
fun getMaterialRenderer(defName: String): TileRenderer {
|
||||||
return matCache.get(defName) {
|
return matCache.get(defName) {
|
||||||
val def = Registries.tiles[defName] // TODO: Пустой рендерер
|
val def = Registries.tiles[defName] // TODO: Пустой рендерер
|
||||||
client.submit(Callable { TileRenderer(this, def!!.value) }).get()
|
client.foregroundExecutor.submit(Callable { TileRenderer(this, def!!.value) }).get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getModifierRenderer(defName: String): TileRenderer {
|
fun getModifierRenderer(defName: String): TileRenderer {
|
||||||
return modCache.get(defName) {
|
return modCache.get(defName) {
|
||||||
val def = Registries.tileModifiers[defName] // TODO: Пустой рендерер
|
val def = Registries.tileModifiers[defName] // TODO: Пустой рендерер
|
||||||
client.submit(Callable { TileRenderer(this, def!!.value) }).get()
|
client.foregroundExecutor.submit(Callable { TileRenderer(this, def!!.value) }).get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class ClientWorld(
|
|||||||
|
|
||||||
isDirty = false
|
isDirty = false
|
||||||
|
|
||||||
currentBakeTask = ForkJoinPool.commonPool().submit(Callable {
|
currentBakeTask = client.backgroundExecutor.submit(Callable {
|
||||||
val meshes = LayeredRenderer(client)
|
val meshes = LayeredRenderer(client)
|
||||||
|
|
||||||
for (x in 0 until renderRegionWidth) {
|
for (x in 0 until renderRegionWidth) {
|
||||||
|
@ -94,7 +94,7 @@ class Image private constructor(
|
|||||||
) ?: throw IllegalArgumentException("File $source is not an image or it is corrupted")
|
) ?: throw IllegalArgumentException("File $source is not an image or it is corrupted")
|
||||||
|
|
||||||
val address = MemoryUtil.memAddress(data)
|
val address = MemoryUtil.memAddress(data)
|
||||||
cleaner.register(data) { STBImage.nstbi_image_free(address) }
|
Starbound.CLEANER.register(data) { STBImage.nstbi_image_free(address) }
|
||||||
|
|
||||||
check(getWidth[0] == width && getHeight[0] == height && components[0] == amountOfChannels) {
|
check(getWidth[0] == width && getHeight[0] == height && components[0] == amountOfChannels) {
|
||||||
"Actual loaded image differs from constructed (this $width x $height with $amountOfChannels channels; loaded ${getWidth[0]} x ${getHeight[0]} with ${components[0]} channels)"
|
"Actual loaded image differs from constructed (this $width x $height with $amountOfChannels channels; loaded ${getWidth[0]} x ${getHeight[0]} with ${components[0]} channels)"
|
||||||
@ -272,7 +272,6 @@ class Image private constructor(
|
|||||||
private val cache = ConcurrentHashMap<String, Optional<List<DataSprite>>>()
|
private val cache = ConcurrentHashMap<String, Optional<List<DataSprite>>>()
|
||||||
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
|
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
|
||||||
private val logger = LogManager.getLogger()
|
private val logger = LogManager.getLogger()
|
||||||
private val cleaner = Cleaner.create { Thread(it, "STB Image Cleaner") }
|
|
||||||
|
|
||||||
private val dataCache: Cache<String, ByteBuffer> = Caffeine.newBuilder()
|
private val dataCache: Cache<String, ByteBuffer> = Caffeine.newBuilder()
|
||||||
.expireAfterAccess(Duration.ofMinutes(1))
|
.expireAfterAccess(Duration.ofMinutes(1))
|
||||||
|
@ -2,7 +2,9 @@ package ru.dbotthepony.kstarbound.io
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||||
|
import ru.dbotthepony.kstarbound.getValue
|
||||||
import ru.dbotthepony.kstarbound.io.json.BinaryJsonReader
|
import ru.dbotthepony.kstarbound.io.json.BinaryJsonReader
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
@ -12,6 +14,7 @@ import java.io.IOError
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.RandomAccessFile
|
import java.io.RandomAccessFile
|
||||||
|
import java.lang.ref.Cleaner
|
||||||
import java.nio.channels.Channels
|
import java.nio.channels.Channels
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -97,11 +100,9 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(reader) {
|
reader.seek(innerOffset + offset)
|
||||||
reader.seek(innerOffset + offset)
|
innerOffset++
|
||||||
innerOffset++
|
return reader.read()
|
||||||
return reader.read()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readNBytes(len: Int): ByteArray {
|
override fun readNBytes(len: Int): ByteArray {
|
||||||
@ -112,13 +113,11 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
|||||||
if (readMax == 0)
|
if (readMax == 0)
|
||||||
return ByteArray(0)
|
return ByteArray(0)
|
||||||
|
|
||||||
synchronized(reader) {
|
val b = ByteArray(readMax)
|
||||||
val b = ByteArray(readMax)
|
reader.seek(innerOffset + offset)
|
||||||
reader.seek(innerOffset + offset)
|
reader.readFully(b)
|
||||||
reader.readFully(b)
|
innerOffset += readMax
|
||||||
innerOffset += readMax
|
return b
|
||||||
return b
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||||
@ -152,7 +151,11 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val reader = RandomAccessFile(path, "r")
|
private val reader by object : ThreadLocal<RandomAccessFile>() {
|
||||||
|
override fun initialValue(): RandomAccessFile {
|
||||||
|
return RandomAccessFile(path, "r")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
readHeader(reader, 0x53) // S
|
readHeader(reader, 0x53) // S
|
||||||
|
@ -14,7 +14,6 @@ import ru.dbotthepony.kstarbound.io.readString
|
|||||||
import ru.dbotthepony.kstarbound.io.readVarInt
|
import ru.dbotthepony.kstarbound.io.readVarInt
|
||||||
import ru.dbotthepony.kstarbound.io.readVarLong
|
import ru.dbotthepony.kstarbound.io.readVarLong
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutputStream
|
|
||||||
import java.io.EOFException
|
import java.io.EOFException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
@ -357,7 +356,7 @@ class BinaryJsonReader(private val stream: DataInputStream) : JsonReader(unreada
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readString(reader: DataInputStream): String {
|
fun readString(reader: DataInputStream): String {
|
||||||
return Starbound.strings.intern(reader.readString(reader.readVarInt()))
|
return Starbound.STRINGS.intern(reader.readString(reader.readVarInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,15 +13,12 @@ import com.google.gson.JsonSyntaxException
|
|||||||
import com.google.gson.TypeAdapter
|
import com.google.gson.TypeAdapter
|
||||||
import com.google.gson.TypeAdapterFactory
|
import com.google.gson.TypeAdapterFactory
|
||||||
import com.google.gson.internal.bind.JsonTreeReader
|
import com.google.gson.internal.bind.JsonTreeReader
|
||||||
import com.google.gson.internal.bind.TypeAdapters
|
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.google.gson.stream.JsonReader
|
import com.google.gson.stream.JsonReader
|
||||||
import com.google.gson.stream.JsonToken
|
import com.google.gson.stream.JsonToken
|
||||||
import com.google.gson.stream.JsonWriter
|
import com.google.gson.stream.JsonWriter
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import it.unimi.dsi.fastutil.ints.IntList
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
@ -512,7 +509,7 @@ class FactoryAdapter<T : Any> private constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
fun <T : Any> createFor(kclass: KClass<T>, config: JsonFactory, gson: Gson, stringInterner: Interner<String> = Starbound.strings): TypeAdapter<T> {
|
fun <T : Any> createFor(kclass: KClass<T>, config: JsonFactory, gson: Gson, stringInterner: Interner<String> = Starbound.STRINGS): TypeAdapter<T> {
|
||||||
val builder = Builder(kclass)
|
val builder = Builder(kclass)
|
||||||
val properties = kclass.declaredMembers.filterIsInstance<KProperty1<T, *>>()
|
val properties = kclass.declaredMembers.filterIsInstance<KProperty1<T, *>>()
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ import java.nio.ByteOrder
|
|||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class LuaState private constructor(private val pointer: Pointer, val stringInterner: Interner<String> = Starbound.strings) : Closeable {
|
class LuaState private constructor(private val pointer: Pointer, val stringInterner: Interner<String> = Starbound.STRINGS) : Closeable {
|
||||||
constructor(stringInterner: Interner<String> = Starbound.strings) : this(LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState"), stringInterner) {
|
constructor(stringInterner: Interner<String> = Starbound.STRINGS) : this(LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState"), stringInterner) {
|
||||||
val pointer = this.pointer
|
val pointer = this.pointer
|
||||||
val panic = ClosureManager.getInstance().newClosure(
|
val panic = ClosureManager.getInstance().newClosure(
|
||||||
{
|
{
|
||||||
@ -44,7 +44,7 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
CallContext.getCallContext(Type.SINT, arrayOf(Type.POINTER), CallingConvention.DEFAULT, false)
|
CallContext.getCallContext(Type.SINT, arrayOf(Type.POINTER), CallingConvention.DEFAULT, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
this.cleanable = CLEANER.register(this) {
|
this.cleanable = Starbound.CLEANER.register(this) {
|
||||||
LuaJNR.INSTANCE.lua_close(pointer)
|
LuaJNR.INSTANCE.lua_close(pointer)
|
||||||
panic.dispose()
|
panic.dispose()
|
||||||
}
|
}
|
||||||
@ -1078,12 +1078,6 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
companion object {
|
companion object {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
private val CLEANER: Cleaner = Cleaner.create {
|
|
||||||
val thread = Thread(it, "Lua State Cleaner")
|
|
||||||
thread.priority = 1
|
|
||||||
thread
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sharedBuffers = ThreadLocal<Long>()
|
private val sharedBuffers = ThreadLocal<Long>()
|
||||||
|
|
||||||
private val sharedStringBufferPtr: Long get() {
|
private val sharedStringBufferPtr: Long get() {
|
||||||
@ -1099,7 +1093,7 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
sharedBuffers.set(p)
|
sharedBuffers.set(p)
|
||||||
val p2 = p
|
val p2 = p
|
||||||
|
|
||||||
CLEANER.register(Thread.currentThread()) {
|
Starbound.CLEANER.register(Thread.currentThread()) {
|
||||||
MemoryIO.getInstance().freeMemory(p2)
|
MemoryIO.getInstance().freeMemory(p2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ object AssetPathStack {
|
|||||||
if (b[0] == '/')
|
if (b[0] == '/')
|
||||||
return b
|
return b
|
||||||
|
|
||||||
return Starbound.strings.intern("$a/$b")
|
return Starbound.STRINGS.intern("$a/$b")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remap(path: String): String {
|
fun remap(path: String): String {
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.util
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
import java.util.concurrent.ExecutorService
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
import java.util.concurrent.FutureTask
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.locks.LockSupport
|
||||||
|
|
||||||
|
class ManualExecutorService(val thread: Thread = Thread.currentThread()) : ExecutorService {
|
||||||
|
private val executeQueue = ConcurrentLinkedQueue<Runnable>()
|
||||||
|
private val futureQueue = ConcurrentLinkedQueue<FutureTask<*>>()
|
||||||
|
|
||||||
|
private data class InPlaceFuture<V>(private val value: V) : Future<V> {
|
||||||
|
override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isCancelled(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDone(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(): V {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(timeout: Long, unit: TimeUnit): V {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val EMPTY = InPlaceFuture(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSameThread(): Boolean {
|
||||||
|
return Thread.currentThread() === thread
|
||||||
|
}
|
||||||
|
|
||||||
|
fun executeQueuedTasks() {
|
||||||
|
check(isSameThread()) { "Trying to execute queued tasks in thread ${Thread.currentThread()}, while correct thread is $thread" }
|
||||||
|
|
||||||
|
var next = executeQueue.poll()
|
||||||
|
|
||||||
|
while (next != null) {
|
||||||
|
next.run()
|
||||||
|
next = executeQueue.poll()
|
||||||
|
}
|
||||||
|
|
||||||
|
var next2 = futureQueue.poll()
|
||||||
|
|
||||||
|
while (next2 != null) {
|
||||||
|
next2.run()
|
||||||
|
Thread.interrupted()
|
||||||
|
next2 = futureQueue.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun execute(command: Runnable) {
|
||||||
|
if (isSameThread()) {
|
||||||
|
command.run()
|
||||||
|
} else {
|
||||||
|
executeQueue.add(command)
|
||||||
|
LockSupport.unpark(thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shutdown() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shutdownNow(): MutableList<Runnable> {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isShutdown(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTerminated(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> submit(task: Callable<T>): Future<T> {
|
||||||
|
if (isSameThread()) return InPlaceFuture(task.call())
|
||||||
|
return FutureTask(task).also { futureQueue.add(it); LockSupport.unpark(thread) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> submit(task: Runnable, result: T): Future<T> {
|
||||||
|
if (isSameThread()) { task.run(); return InPlaceFuture(result) }
|
||||||
|
return FutureTask { task.run(); result }.also { futureQueue.add(it); LockSupport.unpark(thread) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun submit(task: Runnable): Future<*> {
|
||||||
|
if (isSameThread()) { task.run(); return InPlaceFuture.EMPTY
|
||||||
|
}
|
||||||
|
return FutureTask { task.run() }.also { futureQueue.add(it); LockSupport.unpark(thread) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> invokeAll(tasks: Collection<Callable<T>>): List<Future<T>> {
|
||||||
|
if (isSameThread()) {
|
||||||
|
return tasks.map { InPlaceFuture(it.call()) }
|
||||||
|
} else {
|
||||||
|
return tasks.map { submit(it) }.onEach { it.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> invokeAll(
|
||||||
|
tasks: Collection<Callable<T>>,
|
||||||
|
timeout: Long,
|
||||||
|
unit: TimeUnit
|
||||||
|
): List<Future<T>> {
|
||||||
|
if (isSameThread()) {
|
||||||
|
return tasks.map { InPlaceFuture(it.call()) }
|
||||||
|
} else {
|
||||||
|
return tasks.map { submit(it) }.onEach { it.get(timeout, unit) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> invokeAny(tasks: Collection<Callable<T>>): T {
|
||||||
|
if (tasks.isEmpty())
|
||||||
|
throw NoSuchElementException("Provided task list is empty")
|
||||||
|
|
||||||
|
if (isSameThread()) {
|
||||||
|
return tasks.first().call()
|
||||||
|
} else {
|
||||||
|
return submit(tasks.first()).get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any?> invokeAny(tasks: Collection<Callable<T>>, timeout: Long, unit: TimeUnit): T {
|
||||||
|
if (tasks.isEmpty())
|
||||||
|
throw NoSuchElementException("Provided task list is empty")
|
||||||
|
|
||||||
|
if (isSameThread()) {
|
||||||
|
return tasks.first().call()
|
||||||
|
} else {
|
||||||
|
return submit(tasks.first()).get(timeout, unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -204,7 +204,7 @@ class SBPattern private constructor(
|
|||||||
throw IllegalArgumentException("Malformed pattern string: $raw")
|
throw IllegalArgumentException("Malformed pattern string: $raw")
|
||||||
}
|
}
|
||||||
|
|
||||||
pieces.add(Piece(name = Starbound.strings.intern(raw.substring(open + 1, closing))))
|
pieces.add(Piece(name = Starbound.STRINGS.intern(raw.substring(open + 1, closing))))
|
||||||
i = closing + 1
|
i = closing + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ import java.util.function.Consumer
|
|||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
fun String.sbIntern(): String {
|
fun String.sbIntern(): String {
|
||||||
return Starbound.strings.intern(this)
|
return Starbound.STRINGS.intern(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.sbIntern2(): String {
|
fun String.sbIntern2(): String {
|
||||||
return Starbound.strings.intern(this.intern())
|
return Starbound.STRINGS.intern(this.intern())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun traverseJsonPath(path: String?, element: JsonElement?): JsonElement? {
|
fun traverseJsonPath(path: String?, element: JsonElement?): JsonElement? {
|
||||||
|
Loading…
Reference in New Issue
Block a user