Compare commits
10 Commits
a17bb2a732
...
09f7e8ac70
Author | SHA1 | Date | |
---|---|---|---|
09f7e8ac70 | |||
4bd85c0e0e | |||
ebd2dd3ab1 | |||
39cd0472b7 | |||
57aea29da2 | |||
7babb729b0 | |||
f77cf29567 | |||
900ce863ae | |||
c3d1c8c636 | |||
7346883f01 |
@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m
|
||||
|
||||
kotlinVersion=1.9.10
|
||||
kotlinCoroutinesVersion=1.8.0
|
||||
kommonsVersion=3.0.1
|
||||
kommonsVersion=3.1.0
|
||||
|
||||
ffiVersion=2.2.13
|
||||
lwjglVersion=3.3.0
|
||||
|
@ -40,7 +40,7 @@ class ResumeInfo {
|
||||
if (resumable instanceof ProtectedResumable) {
|
||||
// top is protected, can handle the error
|
||||
ProtectedResumable pr = (ProtectedResumable) resumable;
|
||||
pr.resumeError(context, savedState, Conversions.toErrorObject(error));
|
||||
pr.resumeError(context, savedState, error);
|
||||
Dispatch.evaluateTailCalls(context);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -4,7 +4,10 @@ import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.reflect.TypeToken
|
||||
@ -14,6 +17,7 @@ import kotlinx.coroutines.future.asCompletableFuture
|
||||
import kotlinx.coroutines.future.await
|
||||
import kotlinx.coroutines.launch
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kommons.gson.contains
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.DamageKind
|
||||
@ -21,14 +25,13 @@ import ru.dbotthepony.kstarbound.defs.Json2Function
|
||||
import ru.dbotthepony.kstarbound.defs.JsonConfigFunction
|
||||
import ru.dbotthepony.kstarbound.defs.JsonFunction
|
||||
import ru.dbotthepony.kstarbound.defs.MarkovTextGenerator
|
||||
import ru.dbotthepony.kstarbound.defs.Species
|
||||
import ru.dbotthepony.kstarbound.defs.actor.Species
|
||||
import ru.dbotthepony.kstarbound.defs.StatusEffectDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
||||
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.actor.TenantDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.`object`.ObjectDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.actor.player.TechDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.animation.ParticleConfig
|
||||
@ -54,6 +57,7 @@ import ru.dbotthepony.kstarbound.item.ItemRegistry
|
||||
import ru.dbotthepony.kstarbound.json.JsonPatch
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.json.fromJsonTreeFast
|
||||
import ru.dbotthepony.kstarbound.json.mergeJson
|
||||
import ru.dbotthepony.kstarbound.world.terrain.TerrainSelectorType
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.util.random.random
|
||||
@ -62,6 +66,7 @@ import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Future
|
||||
import java.util.random.RandomGenerator
|
||||
import kotlin.NoSuchElementException
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
@ -87,7 +92,6 @@ object Registries {
|
||||
val jsonFunctions = Registry<JsonFunction>("json function").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val json2Functions = Registry<Json2Function>("json 2function").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val jsonConfigFunctions = Registry<JsonConfigFunction>("json config function").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val npcTypes = Registry<NpcTypeDefinition>("npc type").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val projectiles = Registry<ProjectileDefinition>("projectile").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val tenants = Registry<TenantDefinition>("tenant").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
val treasurePools = Registry<TreasurePoolDefinition>("treasure pool").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
@ -110,14 +114,14 @@ object Registries {
|
||||
val damageKinds = Registry<DamageKind>("damage kind").also(registriesInternal::add).also { adapters.add(it.adapter()) }
|
||||
|
||||
private val monsterParts = HashMap<Pair<String, String>, HashMap<String, Pair<MonsterPartDefinition, IStarboundFile>>>()
|
||||
private val loggedMisses = Collections.synchronizedSet(ObjectOpenHashSet<Pair<String, String>>())
|
||||
private val loggedMonsterPartMisses = Collections.synchronizedSet(ObjectOpenHashSet<Pair<String, String>>())
|
||||
|
||||
fun selectMonsterPart(category: String, type: String, random: RandomGenerator): MonsterPartDefinition? {
|
||||
val key = category to type
|
||||
val get = monsterParts[key]
|
||||
|
||||
if (get.isNullOrEmpty()) {
|
||||
if (loggedMisses.add(key)) {
|
||||
if (loggedMonsterPartMisses.add(key)) {
|
||||
LOGGER.error("No such monster part combination of category '$category' and type '$type'")
|
||||
}
|
||||
|
||||
@ -157,6 +161,49 @@ object Registries {
|
||||
}
|
||||
}
|
||||
|
||||
private val npcTypes = HashMap<String, Pair<IStarboundFile, JsonObject>>()
|
||||
|
||||
fun buildNPCConfig(type: String, overrides: JsonElement = JsonNull.INSTANCE): JsonObject {
|
||||
val baseConfig = npcTypes.getOrElse(type) { throw NoSuchElementException("No such NPC type $type") }.second
|
||||
val config = mergeJson(baseConfig.deepCopy(), overrides)
|
||||
|
||||
if ("baseType" in baseConfig) {
|
||||
return buildNPCConfig(baseConfig["baseType"].asString, config)
|
||||
} else {
|
||||
return config
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNpcTypes(files: Collection<IStarboundFile>, patches: Map<String, Collection<IStarboundFile>>): List<Future<*>> {
|
||||
return files.map { listedFile ->
|
||||
Starbound.GLOBAL_SCOPE.launch {
|
||||
try {
|
||||
val elem = JsonPatch.applyAsync(listedFile.asyncJsonReader(), patches[listedFile.computeFullPath()]) as JsonObject
|
||||
val type = elem.get("type").asString
|
||||
|
||||
if ("scripts" in elem) {
|
||||
val fPath = listedFile.computeFullPath()
|
||||
val scripts = elem["scripts"].asJsonArray
|
||||
|
||||
for (i in 0 until scripts.size()) {
|
||||
scripts[i] = JsonPrimitive(AssetPathStack.relativeTo(fPath, scripts[i].asString))
|
||||
}
|
||||
}
|
||||
|
||||
Starbound.submit {
|
||||
val existing = npcTypes.put(type, listedFile to elem)
|
||||
|
||||
if (existing != null) {
|
||||
LOGGER.warn("Overwriting existing NPC definition '$type' (new originate from $listedFile, old originating from ${existing.first})")
|
||||
}
|
||||
}
|
||||
} catch (err: Throwable) {
|
||||
LOGGER.error("Loading NPC type definition file $listedFile", err)
|
||||
}
|
||||
}.asCompletableFuture()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> key(mapper: (T) -> String): (T) -> Pair<String, KOptional<Int?>> {
|
||||
return { mapper.invoke(it) to KOptional() }
|
||||
}
|
||||
@ -236,7 +283,6 @@ object Registries {
|
||||
tasks.addAll(loadRegistry(particles, patchTree, fileTree["particle"] ?: listOf(), { (it.kind ?: throw NullPointerException("Missing 'kind' value")) to KOptional() }))
|
||||
tasks.addAll(loadRegistry(questTemplates, patchTree, fileTree["questtemplate"] ?: listOf(), key(QuestTemplate::id)))
|
||||
tasks.addAll(loadRegistry(techs, patchTree, fileTree["tech"] ?: listOf(), key(TechDefinition::name)))
|
||||
tasks.addAll(loadRegistry(npcTypes, patchTree, fileTree["npctype"] ?: listOf(), key(NpcTypeDefinition::type)))
|
||||
tasks.addAll(loadRegistry(biomes, patchTree, fileTree["biome"] ?: listOf(), key(BiomeDefinition::name)))
|
||||
tasks.addAll(loadRegistry(grassVariants, patchTree, fileTree["grass"] ?: listOf(), key(GrassVariant.Data::name)))
|
||||
tasks.addAll(loadRegistry(treeStemVariants, patchTree, fileTree["modularstem"] ?: listOf(), key(TreeVariant.StemData::name)))
|
||||
@ -259,6 +305,8 @@ object Registries {
|
||||
// declaring game data
|
||||
tasks.addAll(loadMixed(spawnTypes, fileTree["spawntypes"] ?: listOf(), patchTree, SpawnType::name))
|
||||
|
||||
tasks.addAll(loadNpcTypes(fileTree["npctype"] ?: listOf(), patchTree))
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,10 @@ object VersionRegistry {
|
||||
return migrate(read, name)
|
||||
}
|
||||
|
||||
fun load(reader: JsonElement): JsonElement {
|
||||
return migrate(VersionedJson.fromJson(reader))
|
||||
}
|
||||
|
||||
private val adapter by lazy { Starbound.gson.getAdapter(VersionedJson::class.java) }
|
||||
|
||||
fun load(): Future<*> {
|
||||
|
@ -6,7 +6,7 @@ import com.google.gson.annotations.JsonAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import kotlinx.coroutines.future.await
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readUUID
|
||||
import ru.dbotthepony.kstarbound.io.readVector2d
|
||||
import ru.dbotthepony.kstarbound.io.readVector2f
|
||||
|
@ -0,0 +1,44 @@
|
||||
package ru.dbotthepony.kstarbound.defs.actor
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonNull
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.util.random.nextRange
|
||||
import ru.dbotthepony.kstarbound.util.random.random
|
||||
import java.util.random.RandomGenerator
|
||||
import kotlin.math.max
|
||||
|
||||
data class NPCVariant(
|
||||
val species: Registry.Entry<Species>,
|
||||
val scripts: ImmutableList<AssetPath>,
|
||||
val initialScriptDelta: Int = 5,
|
||||
) {
|
||||
@JsonFactory
|
||||
data class SerializedData(
|
||||
val levelVariance: Vector2d = Vector2d.ZERO,
|
||||
val scripts: ImmutableList<AssetPath>,
|
||||
val initialScriptDelta: Int = 5,
|
||||
val scriptConfig: JsonElement = JsonNull.INSTANCE,
|
||||
val humanoidConfig: String? = null,
|
||||
)
|
||||
|
||||
companion object {
|
||||
suspend fun create(species: Registry.Entry<Species>, type: String, level: Double, random: RandomGenerator, overrides: JsonElement = JsonNull.INSTANCE): NPCVariant {
|
||||
val config = Registries.buildNPCConfig(type, overrides)
|
||||
|
||||
val serialized = Starbound.gson.fromJson(config, SerializedData::class.java)
|
||||
val finalLevel = max(0.0, random.nextRange(serialized.levelVariance) + level)
|
||||
TODO()
|
||||
}
|
||||
|
||||
suspend fun create(species: Registry.Entry<Species>, type: String, level: Double, seed: Long, overrides: JsonElement = JsonNull.INSTANCE): NPCVariant {
|
||||
return create(species, type, level, random(seed), overrides)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package ru.dbotthepony.kstarbound.defs
|
||||
package ru.dbotthepony.kstarbound.defs.actor
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.defs.ColorReplacements
|
||||
import ru.dbotthepony.kstarbound.defs.StatusEffectDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.image.SpriteReference
|
||||
import ru.dbotthepony.kstarbound.defs.actor.player.BlueprintLearnList
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
@ -11,31 +14,36 @@ import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
@JsonFactory
|
||||
data class Species(
|
||||
val kind: String,
|
||||
val charCreationTooltip: Tooltip,
|
||||
val charCreationTooltip: Tooltip = Tooltip(),
|
||||
val nameGen: ImmutableList<String>,
|
||||
val ouchNoises: ImmutableList<String>,
|
||||
val charGenTextLabels: ImmutableList<String>,
|
||||
val skull: String,
|
||||
val ouchNoises: ImmutableList<AssetPath>,
|
||||
val charGenTextLabels: ImmutableList<String> = ImmutableList.of(),
|
||||
val skull: AssetPath = AssetPath("/humanoid/any/dead.png"), // ваш свет угасает
|
||||
val defaultBlueprints: BlueprintLearnList,
|
||||
|
||||
val headOptionAsHairColor: Boolean = false,
|
||||
val headOptionAsFacialhair: Boolean = false,
|
||||
val altOptionAsUndyColor: Boolean = false,
|
||||
val altOptionAsHairColor: Boolean = false,
|
||||
val bodyColorAsFacialMaskSubColor: Boolean = false,
|
||||
val altOptionAsFacialMask: Boolean = false,
|
||||
val hairColorAsBodySubColor: Boolean = false,
|
||||
val bodyColorAsFacialMaskSubColor: Boolean = false,
|
||||
val altColorAsFacialMaskSubColor: Boolean = false,
|
||||
|
||||
val bodyColor: ImmutableList<ColorReplacements>,
|
||||
val undyColor: ImmutableList<ColorReplacements>,
|
||||
val hairColor: ImmutableList<ColorReplacements>,
|
||||
val genders: ImmutableList<Gender>,
|
||||
val genders: ImmutableList<GenderSettings>,
|
||||
val statusEffects: ImmutableSet<Registry.Ref<StatusEffectDefinition>> = ImmutableSet.of(),
|
||||
) {
|
||||
@JsonFactory
|
||||
data class Tooltip(val title: String, val subTitle: String, val description: String)
|
||||
data class Tooltip(val title: String = "", val subTitle: String = "", val description: String = "")
|
||||
|
||||
@JsonFactory
|
||||
data class Gender(
|
||||
val name: String,
|
||||
val image: SpriteReference,
|
||||
val characterImage: SpriteReference,
|
||||
data class GenderSettings(
|
||||
val name: String = "",
|
||||
val image: SpriteReference = SpriteReference.NEVER,
|
||||
val characterImage: SpriteReference = SpriteReference.NEVER,
|
||||
val hairGroup: String? = null,
|
||||
val hair: ImmutableSet<String>,
|
||||
val shirt: ImmutableSet<ItemDescriptor>,
|
@ -1,4 +1,4 @@
|
||||
package ru.dbotthepony.kstarbound.defs.npc
|
||||
package ru.dbotthepony.kstarbound.defs.actor
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap
|
@ -11,9 +11,8 @@ import ru.dbotthepony.kstarbound.world.entities.behavior.RandomizeNode
|
||||
import ru.dbotthepony.kstarbound.world.entities.behavior.SequenceNode
|
||||
|
||||
enum class CompositeNodeType(override val jsonName: String, val factory: (Map<String, NodeParameter>, ImmutableList<AbstractBehaviorNode>) -> AbstractBehaviorNode) : IStringSerializable {
|
||||
SEQUENCE("Sequence", { _, c -> SequenceNode(c) }),
|
||||
// in original engine, selector and sequence nodes are identical code-wise
|
||||
SELECTOR("Selector", { _, c -> SequenceNode(c) }),
|
||||
SEQUENCE("Sequence", { _, c -> SequenceNode(c, isSelector = false) }),
|
||||
SELECTOR("Selector", { _, c -> SequenceNode(c, isSelector = true) }),
|
||||
PARALLEL("Parallel", { p, c -> ParallelNode(p, c) }),
|
||||
DYNAMIC("Dynamic", { _, c -> DynamicNode(c) }),
|
||||
RANDOMIZE("Randomize", { _, c -> RandomizeNode(c) });
|
||||
|
@ -1,8 +1,8 @@
|
||||
package ru.dbotthepony.kstarbound.defs.actor.player
|
||||
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
|
||||
enum class PlayerBusyState(override val jsonName: String) : IStringSerializable {
|
||||
|
@ -10,7 +10,7 @@ import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.ActorMovementParameters
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.Species
|
||||
import ru.dbotthepony.kstarbound.defs.actor.Species
|
||||
import ru.dbotthepony.kstarbound.defs.actor.StatusControllerConfig
|
||||
import ru.dbotthepony.kstarbound.util.SBPattern
|
||||
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
|
||||
|
@ -1,8 +1,8 @@
|
||||
package ru.dbotthepony.kstarbound.defs.actor.player
|
||||
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
|
||||
enum class PlayerGamemode(override val jsonName: String) : IStringSerializable {
|
||||
|
@ -20,7 +20,7 @@ import org.classdump.luna.runtime.ExecutionContext
|
||||
import ru.dbotthepony.kommons.gson.contains
|
||||
import ru.dbotthepony.kommons.gson.get
|
||||
import ru.dbotthepony.kommons.gson.value
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readVarLong
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeVarLong
|
||||
|
@ -1,9 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound.defs.npc
|
||||
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
|
||||
@JsonFactory
|
||||
data class NpcTypeDefinition(
|
||||
val type: String,
|
||||
val baseType: String? = null,
|
||||
)
|
@ -5,7 +5,7 @@ import com.google.gson.JsonObject
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import ru.dbotthepony.kommons.gson.contains
|
||||
import ru.dbotthepony.kommons.gson.get
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2i
|
||||
|
44
src/main/kotlin/ru/dbotthepony/kstarbound/io/SQLSavepoint.kt
Normal file
44
src/main/kotlin/ru/dbotthepony/kstarbound/io/SQLSavepoint.kt
Normal file
@ -0,0 +1,44 @@
|
||||
package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import java.io.Closeable
|
||||
import java.sql.Connection
|
||||
import java.sql.PreparedStatement
|
||||
|
||||
class SQLSavepoint(connection: Connection, name: String) : Closeable {
|
||||
private val begin: PreparedStatement
|
||||
private val finish: PreparedStatement
|
||||
private val rollback: PreparedStatement
|
||||
|
||||
init {
|
||||
check('"' !in name) { "Invalid identifier: $name" }
|
||||
|
||||
begin = connection.prepareStatement("""
|
||||
SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
|
||||
finish = connection.prepareStatement("""
|
||||
RELEASE SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
|
||||
rollback = connection. prepareStatement("""
|
||||
ROLLBACK TO SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun execute(block: () -> Unit) {
|
||||
try {
|
||||
begin.execute()
|
||||
block.invoke()
|
||||
finish.execute()
|
||||
} catch (err: Throwable) {
|
||||
rollback.execute()
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
begin.close()
|
||||
finish.close()
|
||||
rollback.close()
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import java.sql.Connection
|
||||
import java.sql.PreparedStatement
|
||||
|
||||
data class SavepointStatements(val begin: PreparedStatement, val commit: PreparedStatement, val rollback: PreparedStatement)
|
||||
|
||||
fun Connection.createSavepoint(name: String): SavepointStatements {
|
||||
check('"' !in name) { "Invalid identifier: $name" }
|
||||
|
||||
val begin = prepareStatement("""
|
||||
SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
|
||||
val commit = prepareStatement("""
|
||||
RELEASE SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
|
||||
val rollback = prepareStatement("""
|
||||
ROLLBACK TO SAVEPOINT "$name"
|
||||
""".trimIndent())
|
||||
|
||||
return SavepointStatements(begin, commit, rollback)
|
||||
}
|
338
src/main/kotlin/ru/dbotthepony/kstarbound/io/StreamCodec.kt
Normal file
338
src/main/kotlin/ru/dbotthepony/kstarbound/io/StreamCodec.kt
Normal file
@ -0,0 +1,338 @@
|
||||
package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import ru.dbotthepony.kommons.io.readBigDecimal
|
||||
import ru.dbotthepony.kommons.io.readBinaryString
|
||||
import ru.dbotthepony.kommons.io.readByteArray
|
||||
import ru.dbotthepony.kommons.io.readKOptional
|
||||
import ru.dbotthepony.kommons.io.readMap
|
||||
import ru.dbotthepony.kommons.io.readOptional
|
||||
import ru.dbotthepony.kommons.io.readSignedVarInt
|
||||
import ru.dbotthepony.kommons.io.readSignedVarLong
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.readVarLong
|
||||
import ru.dbotthepony.kommons.io.writeBigDecimal
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeByteArray
|
||||
import ru.dbotthepony.kommons.io.writeKOptional
|
||||
import ru.dbotthepony.kommons.io.writeMap
|
||||
import ru.dbotthepony.kommons.io.writeOptional
|
||||
import ru.dbotthepony.kommons.io.writeSignedVarInt
|
||||
import ru.dbotthepony.kommons.io.writeSignedVarLong
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
import ru.dbotthepony.kommons.io.writeVarLong
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Represents value which can be encoded onto or decoded from stream.
|
||||
*/
|
||||
interface StreamCodec<V> {
|
||||
fun read(stream: DataInputStream): V
|
||||
fun write(stream: DataOutputStream, value: V)
|
||||
|
||||
/**
|
||||
* Defensive copy
|
||||
*/
|
||||
fun copy(value: V): V
|
||||
|
||||
/**
|
||||
* Optional custom equality check
|
||||
*/
|
||||
fun compare(a: V, b: V): Boolean {
|
||||
return a == b
|
||||
}
|
||||
|
||||
class Impl<V>(
|
||||
private val reader: (stream: DataInputStream) -> V,
|
||||
private val writer: (stream: DataOutputStream, value: V) -> Unit,
|
||||
private val copier: ((value: V) -> V) = { it },
|
||||
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
||||
) : StreamCodec<V> {
|
||||
constructor(
|
||||
reader: (stream: DataInputStream) -> V,
|
||||
payloadSize: Long,
|
||||
writer: (stream: DataOutputStream, value: V) -> Unit,
|
||||
copier: ((value: V) -> V) = { it },
|
||||
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
||||
) : this({ stream -> reader.invoke(stream) }, writer, copier, comparator)
|
||||
|
||||
override fun read(stream: DataInputStream): V {
|
||||
return reader.invoke(stream)
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: V) {
|
||||
writer.invoke(stream, value)
|
||||
}
|
||||
|
||||
override fun copy(value: V): V {
|
||||
return copier.invoke(value)
|
||||
}
|
||||
|
||||
override fun compare(a: V, b: V): Boolean {
|
||||
return comparator.invoke(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
class Nullable<V>(val parent: StreamCodec<V>) : StreamCodec<V?> {
|
||||
override fun read(stream: DataInputStream): V? {
|
||||
return if (stream.read() == 0) null else parent.read(stream)
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: V?) {
|
||||
if (value === null)
|
||||
stream.write(0)
|
||||
else {
|
||||
stream.write(1)
|
||||
parent.write(stream, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun copy(value: V?): V? {
|
||||
return if (value === null) null else parent.copy(value)
|
||||
}
|
||||
|
||||
override fun compare(a: V?, b: V?): Boolean {
|
||||
if (a === null && b === null) return true
|
||||
if (a === null || b === null) return false
|
||||
return parent.compare(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
class Collection<E, C : MutableCollection<E>>(val elementCodec: StreamCodec<E>, val collectionFactory: (Int) -> C) : StreamCodec<C> {
|
||||
override fun read(stream: DataInputStream): C {
|
||||
val size = stream.readVarInt()
|
||||
|
||||
if (size <= 0) {
|
||||
return collectionFactory.invoke(0)
|
||||
}
|
||||
|
||||
val collection = collectionFactory.invoke(size)
|
||||
|
||||
for (i in 0 until size) {
|
||||
collection.add(elementCodec.read(stream))
|
||||
}
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: C) {
|
||||
stream.writeVarInt(value.size)
|
||||
value.forEach { elementCodec.write(stream, it) }
|
||||
}
|
||||
|
||||
override fun copy(value: C): C {
|
||||
val new = collectionFactory.invoke(value.size)
|
||||
value.forEach { new.add(elementCodec.copy(it)) }
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
class Map<K, V, C : MutableMap<K, V>>(val keyCodec: StreamCodec<K>, val valueCodec: StreamCodec<V>, val factory: (Int) -> C): StreamCodec<C> {
|
||||
override fun read(stream: DataInputStream): C {
|
||||
return stream.readMap(keyCodec::read, valueCodec::read, factory)
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: C) {
|
||||
stream.writeMap(value, keyCodec::write, valueCodec::write)
|
||||
}
|
||||
|
||||
override fun copy(value: C): C {
|
||||
val new = factory.invoke(value.size)
|
||||
|
||||
for ((k, v) in value.entries) {
|
||||
new[keyCodec.copy(k)] = valueCodec.copy(v)
|
||||
}
|
||||
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
class Enum<V : kotlin.Enum<V>>(clazz: Class<out V>) : StreamCodec<V> {
|
||||
val clazz = searchClass(clazz)
|
||||
val values: List<V> = listOf(*this.clazz.enumConstants!!)
|
||||
val valuesMap = values.associateBy { it.name }
|
||||
|
||||
override fun read(stream: DataInputStream): V {
|
||||
val id = stream.readVarInt()
|
||||
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: V) {
|
||||
stream.writeVarInt(value.ordinal)
|
||||
}
|
||||
|
||||
override fun copy(value: V): V {
|
||||
return value
|
||||
}
|
||||
|
||||
override fun compare(a: V, b: V): Boolean {
|
||||
return a === b
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* FIXME: enums with abstract methods which get compiled to subclasses, whose DO NOT expose "parent's" enum constants array
|
||||
*
|
||||
* is there an already existing solution?
|
||||
*/
|
||||
fun <V : kotlin.Enum<V>> searchClass(clazz: Class<out V>): Class<out V> {
|
||||
var search: Class<*> = clazz
|
||||
|
||||
while (search.enumConstants == null && search.superclass != null) {
|
||||
search = search.superclass
|
||||
}
|
||||
|
||||
if (search.enumConstants == null) {
|
||||
throw ClassCastException("$clazz does not represent an enum or enum subclass")
|
||||
}
|
||||
|
||||
return search as Class<out V>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KOptional<V>(val codec: StreamCodec<V>) : StreamCodec<ru.dbotthepony.kommons.util.KOptional<V>> {
|
||||
override fun read(stream: DataInputStream): ru.dbotthepony.kommons.util.KOptional<V> {
|
||||
return stream.readKOptional(codec::read)
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: ru.dbotthepony.kommons.util.KOptional<V>) {
|
||||
stream.writeKOptional(value, codec::write)
|
||||
}
|
||||
|
||||
override fun copy(value: ru.dbotthepony.kommons.util.KOptional<V>): ru.dbotthepony.kommons.util.KOptional<V> {
|
||||
return value.map(codec::copy)
|
||||
}
|
||||
}
|
||||
|
||||
class Optional<V : Any>(val codec: StreamCodec<V>) : StreamCodec<java.util.Optional<V>> {
|
||||
override fun read(stream: DataInputStream): java.util.Optional<V> {
|
||||
return stream.readOptional(codec::read)
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: java.util.Optional<V>) {
|
||||
stream.writeOptional(value, codec::write)
|
||||
}
|
||||
|
||||
override fun copy(value: java.util.Optional<V>): java.util.Optional<V> {
|
||||
return value.map(codec::copy)
|
||||
}
|
||||
}
|
||||
|
||||
class Mapping<T, R>(private val codec: StreamCodec<T>, private val from: T.() -> R, private val to: R.() -> T, private val copy: R.() -> R = { this }) : StreamCodec<R> {
|
||||
override fun read(stream: DataInputStream): R {
|
||||
return from(codec.read(stream))
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: R) {
|
||||
codec.write(stream, to(value))
|
||||
}
|
||||
|
||||
override fun copy(value: R): R {
|
||||
return copy.invoke(value)
|
||||
}
|
||||
}
|
||||
|
||||
class Pair<L, R>(private val left: StreamCodec<L>, private val right: StreamCodec<R>) : StreamCodec<kotlin.Pair<L, R>> {
|
||||
override fun read(stream: DataInputStream): kotlin.Pair<L, R> {
|
||||
val left = left.read(stream)
|
||||
val right = right.read(stream)
|
||||
return left to right
|
||||
}
|
||||
|
||||
override fun write(stream: DataOutputStream, value: kotlin.Pair<L, R>) {
|
||||
left.write(stream, value.first)
|
||||
right.write(stream, value.second)
|
||||
}
|
||||
|
||||
override fun copy(value: kotlin.Pair<L, R>): kotlin.Pair<L, R> {
|
||||
val left = left.copy(value.first)
|
||||
val right = right.copy(value.second)
|
||||
|
||||
if (left !== this.left && right !== this.right) {
|
||||
return left to right
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, R> StreamCodec<T>.map(from: T.() -> R, to: R.() -> T): StreamCodec<R> {
|
||||
return StreamCodec.Mapping(this, from, to)
|
||||
}
|
||||
|
||||
fun <T, R> StreamCodec<T>.map(from: T.() -> R, to: R.() -> T, copy: R.() -> R): StreamCodec<R> {
|
||||
return StreamCodec.Mapping(this, from, to, copy)
|
||||
}
|
||||
|
||||
fun <T : Any> StreamCodec<T>.optional(): StreamCodec<Optional<T>> = StreamCodec.Optional(this)
|
||||
fun <T> StreamCodec<T>.koptional(): StreamCodec<KOptional<T>> = StreamCodec.KOptional(this)
|
||||
fun <T> StreamCodec<T>.nullable(): StreamCodec<T?> = StreamCodec.Nullable(this)
|
||||
|
||||
val NullValueCodec = StreamCodec.Impl({ _ -> null }, { _, _ -> })
|
||||
val BooleanValueCodec = StreamCodec.Impl(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean)
|
||||
val ByteValueCodec = StreamCodec.Impl(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) })
|
||||
val ShortValueCodec = StreamCodec.Impl(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) })
|
||||
val CharValueCodec = StreamCodec.Impl(DataInputStream::readChar, 2L, { s, v -> s.writeShort(v.code) })
|
||||
val IntValueCodec = StreamCodec.Impl(DataInputStream::readInt, 4L, DataOutputStream::writeInt)
|
||||
val LongValueCodec = StreamCodec.Impl(DataInputStream::readLong, 8L, DataOutputStream::writeLong)
|
||||
val FloatValueCodec = StreamCodec.Impl(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat)
|
||||
val DoubleValueCodec = StreamCodec.Impl(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble)
|
||||
val BigDecimalValueCodec = StreamCodec.Impl(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
||||
val UUIDValueCodec = StreamCodec.Impl({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
|
||||
val VarIntValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarInt, DataOutputStream::writeSignedVarInt)
|
||||
val VarLongValueCodec = StreamCodec.Impl(DataInputStream::readSignedVarLong, DataOutputStream::writeSignedVarLong)
|
||||
val BinaryStringCodec = StreamCodec.Impl(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
|
||||
|
||||
val UnsignedVarLongCodec = StreamCodec.Impl(DataInputStream::readVarLong, DataOutputStream::writeVarLong)
|
||||
val UnsignedVarIntCodec = StreamCodec.Impl(DataInputStream::readVarInt, DataOutputStream::writeVarInt)
|
||||
|
||||
val ByteArrayCodec = StreamCodec.Impl(DataInputStream::readByteArray, DataOutputStream::writeByteArray)
|
||||
|
||||
val RGBCodec = StreamCodec.Impl(
|
||||
{ s -> RGBAColor(s.readFloat(), s.readFloat(), s.readFloat()) },
|
||||
{ s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue) })
|
||||
|
||||
val RGBACodec = StreamCodec.Impl(
|
||||
{ s -> RGBAColor(s.readFloat(), s.readFloat(), s.readFloat(), s.readFloat()) },
|
||||
{ s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) })
|
||||
|
||||
val OptionalBooleanValueCodec = StreamCodec.Optional(BooleanValueCodec)
|
||||
val OptionalByteValueCodec = StreamCodec.Optional(ByteValueCodec)
|
||||
val OptionalShortValueCodec = StreamCodec.Optional(ShortValueCodec)
|
||||
val OptionalCharValueCodec = StreamCodec.Optional(CharValueCodec)
|
||||
val OptionalIntValueCodec = StreamCodec.Optional(IntValueCodec)
|
||||
val OptionalLongValueCodec = StreamCodec.Optional(LongValueCodec)
|
||||
val OptionalFloatValueCodec = StreamCodec.Optional(FloatValueCodec)
|
||||
val OptionalDoubleValueCodec = StreamCodec.Optional(DoubleValueCodec)
|
||||
val OptionalBigDecimalValueCodec = StreamCodec.Optional(BigDecimalValueCodec)
|
||||
val OptionalUUIDValueCodec = StreamCodec.Optional(UUIDValueCodec)
|
||||
val OptionalVarIntValueCodec = StreamCodec.Optional(VarIntValueCodec)
|
||||
val OptionalVarLongValueCodec = StreamCodec.Optional(VarLongValueCodec)
|
||||
val OptionalBinaryStringCodec = StreamCodec.Optional(BinaryStringCodec)
|
||||
val OptionalRGBCodec = StreamCodec.Optional(RGBCodec)
|
||||
val OptionalRGBACodec = StreamCodec.Optional(RGBACodec)
|
||||
|
||||
val KOptionalBooleanValueCodec = StreamCodec.KOptional(BooleanValueCodec)
|
||||
val KOptionalByteValueCodec = StreamCodec.KOptional(ByteValueCodec)
|
||||
val KOptionalShortValueCodec = StreamCodec.KOptional(ShortValueCodec)
|
||||
val KOptionalCharValueCodec = StreamCodec.KOptional(CharValueCodec)
|
||||
val KOptionalIntValueCodec = StreamCodec.KOptional(IntValueCodec)
|
||||
val KOptionalLongValueCodec = StreamCodec.KOptional(LongValueCodec)
|
||||
val KOptionalFloatValueCodec = StreamCodec.KOptional(FloatValueCodec)
|
||||
val KOptionalDoubleValueCodec = StreamCodec.KOptional(DoubleValueCodec)
|
||||
val KOptionalBigDecimalValueCodec = StreamCodec.KOptional(BigDecimalValueCodec)
|
||||
val KOptionalUUIDValueCodec = StreamCodec.KOptional(UUIDValueCodec)
|
||||
val KOptionalVarIntValueCodec = StreamCodec.KOptional(VarIntValueCodec)
|
||||
val KOptionalVarLongValueCodec = StreamCodec.KOptional(VarLongValueCodec)
|
||||
val KOptionalBinaryStringCodec = StreamCodec.KOptional(BinaryStringCodec)
|
||||
val KOptionalRGBCodec = StreamCodec.KOptional(RGBCodec)
|
||||
val KOptionalRGBACodec = StreamCodec.KOptional(RGBACodec)
|
||||
|
||||
fun <E : Enum<E>> Class<E>.codec() = StreamCodec.Enum(this)
|
||||
fun <E : Enum<E>> KClass<E>.codec() = StreamCodec.Enum(this.java)
|
@ -2,8 +2,6 @@ package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import it.unimi.dsi.fastutil.bytes.ByteArrayList
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import ru.dbotthepony.kommons.io.DelegateSyncher
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readBinaryString
|
||||
import ru.dbotthepony.kommons.io.readDouble
|
||||
import ru.dbotthepony.kommons.io.readFloat
|
||||
@ -263,27 +261,6 @@ val Vector4iCodec = StreamCodec.Impl(DataInputStream::readVector4i, DataOutputSt
|
||||
val Vector4dCodec = StreamCodec.Impl(DataInputStream::readVector4d, DataOutputStream::writeStruct4d)
|
||||
val Vector4fCodec = StreamCodec.Impl(DataInputStream::readVector4f, DataOutputStream::writeStruct4f)
|
||||
|
||||
fun DelegateSyncher.vec2i(value: Vector2i, setter: DelegateSetter<Vector2i> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector2i> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector2iCodec)
|
||||
fun DelegateSyncher.vec2d(value: Vector2d, setter: DelegateSetter<Vector2d> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector2d> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector2dCodec)
|
||||
fun DelegateSyncher.vec2f(value: Vector2f, setter: DelegateSetter<Vector2f> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector2f> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector2fCodec)
|
||||
|
||||
fun DelegateSyncher.vec3i(value: Vector3i, setter: DelegateSetter<Vector3i> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector3i> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector3iCodec)
|
||||
fun DelegateSyncher.vec3d(value: Vector3d, setter: DelegateSetter<Vector3d> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector3d> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector3dCodec)
|
||||
fun DelegateSyncher.vec3f(value: Vector3f, setter: DelegateSetter<Vector3f> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector3f> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector3fCodec)
|
||||
|
||||
fun DelegateSyncher.vec4i(value: Vector4i, setter: DelegateSetter<Vector4i> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector4i> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector4iCodec)
|
||||
fun DelegateSyncher.vec4d(value: Vector4d, setter: DelegateSetter<Vector4d> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector4d> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector4dCodec)
|
||||
fun DelegateSyncher.vec4f(value: Vector4f, setter: DelegateSetter<Vector4f> = DelegateSetter.passthrough(), getter: DelegateGetter<Vector4f> = DelegateGetter.passthrough()) = Slot(
|
||||
ListenableDelegate.maskSmart(value, getter, setter), Vector4fCodec)
|
||||
|
||||
fun OutputStream.writeEnumStupid(index: Int, isLegacy: Boolean) {
|
||||
if (isLegacy) writeInt(index) else write(index)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.item
|
||||
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
|
@ -40,5 +40,9 @@ data class VersionedJson(val id: String, val version: Int?, val content: JsonEle
|
||||
|
||||
companion object {
|
||||
private val adapter by lazy { Starbound.gson.getAdapter<VersionedJson>() }
|
||||
|
||||
fun fromJson(data: JsonElement): VersionedJson {
|
||||
return adapter.fromJsonTree(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ fun provideRootBindings(lua: LuaEnvironment) {
|
||||
table["imageSize"] = imageSize
|
||||
table["imageSpaces"] = luaFunctionNS("imageSpaces", ::imageSpaces)
|
||||
table["nonEmptyRegion"] = luaFunction(::nonEmptyRegion)
|
||||
table["npcConfig"] = registryDef(Registries.npcTypes)
|
||||
//table["npcConfig"] = registryDef(Registries.npcTypes)
|
||||
|
||||
table["npcVariant"] = luaStub("npcVariant")
|
||||
table["projectileGravityMultiplier"] = luaStub("projectileGravityMultiplier")
|
||||
|
@ -13,9 +13,9 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.cancel
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kstarbound.math.AABBi
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.network.syncher
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.util.Listenable
|
||||
import ru.dbotthepony.kommons.util.ListenableDelegate
|
||||
import java.io.DataInputStream
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.network.syncher
|
||||
|
||||
import ru.dbotthepony.kommons.io.UnsignedVarLongCodec
|
||||
import ru.dbotthepony.kstarbound.io.UnsignedVarLongCodec
|
||||
import java.io.DataInputStream
|
||||
import java.util.function.Consumer
|
||||
|
||||
|
@ -4,34 +4,25 @@ import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.TypeAdapter
|
||||
import ru.dbotthepony.kommons.io.BinaryStringCodec
|
||||
import ru.dbotthepony.kommons.io.BooleanValueCodec
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.RGBACodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.UnsignedVarIntCodec
|
||||
import ru.dbotthepony.kommons.io.UnsignedVarLongCodec
|
||||
import ru.dbotthepony.kommons.io.VarIntValueCodec
|
||||
import ru.dbotthepony.kommons.io.VarLongValueCodec
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kommons.io.readByteArray
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.readVarLong
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeByteArray
|
||||
import ru.dbotthepony.kommons.io.writeShort
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
import ru.dbotthepony.kommons.io.writeVarLong
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
import ru.dbotthepony.kstarbound.defs.world.SkyType
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.RGBACodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.UnsignedVarIntCodec
|
||||
import ru.dbotthepony.kstarbound.io.UnsignedVarLongCodec
|
||||
import ru.dbotthepony.kstarbound.io.VarIntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.VarLongValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.Vector2dCodec
|
||||
import ru.dbotthepony.kstarbound.io.Vector2fCodec
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kstarbound.io.readAABB
|
||||
import ru.dbotthepony.kstarbound.io.readAABBLegacy
|
||||
import ru.dbotthepony.kstarbound.io.readAABBLegacyOptional
|
||||
@ -45,6 +36,8 @@ import ru.dbotthepony.kstarbound.json.readJsonElement
|
||||
import ru.dbotthepony.kstarbound.json.readJsonObject
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonElement
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonObject
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
|
@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.network.syncher
|
||||
import com.google.gson.TypeAdapter
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readByteArray
|
||||
import ru.dbotthepony.kommons.io.writeByteArray
|
||||
import ru.dbotthepony.kstarbound.json.BinaryJsonReader
|
||||
|
@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.network.syncher
|
||||
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readByteArray
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ru.dbotthepony.kstarbound.network.syncher
|
||||
|
||||
import ru.dbotthepony.kommons.collect.ListenableMap
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.network.syncher
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.writeVarInt
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.server.world
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||
@ -15,12 +16,13 @@ import ru.dbotthepony.kommons.io.writeCollection
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.VersionRegistry
|
||||
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||
import ru.dbotthepony.kstarbound.io.createSavepoint
|
||||
import ru.dbotthepony.kstarbound.io.SQLSavepoint
|
||||
import ru.dbotthepony.kstarbound.json.VersionedJson
|
||||
import ru.dbotthepony.kstarbound.json.readJsonArrayInflated
|
||||
import ru.dbotthepony.kstarbound.json.readJsonElement
|
||||
import ru.dbotthepony.kstarbound.json.readJsonObjectInflated
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonArrayDeflated
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonElement
|
||||
import ru.dbotthepony.kstarbound.json.writeJsonObjectDeflated
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2i
|
||||
import ru.dbotthepony.kstarbound.util.CarriedExecutor
|
||||
@ -39,7 +41,6 @@ import java.io.File
|
||||
import java.lang.ref.Cleaner
|
||||
import java.sql.Connection
|
||||
import java.sql.DriverManager
|
||||
import java.sql.PreparedStatement
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.Deflater
|
||||
@ -96,28 +97,26 @@ class NativeLocalWorldStorage(file: File?) : WorldStorage() {
|
||||
|
||||
it.execute("""
|
||||
CREATE TABLE IF NOT EXISTS "entities" (
|
||||
"x" INTEGER NOT NULL,
|
||||
"y" INTEGER NOT NULL,
|
||||
"data" BLOB NOT NULL,
|
||||
PRIMARY KEY ("x", "y")
|
||||
)
|
||||
""".trimIndent())
|
||||
|
||||
it.execute("""
|
||||
CREATE TABLE IF NOT EXISTS "unique_entities" (
|
||||
"unique_id" BLOB NOT NULL PRIMARY KEY,
|
||||
-- store chunks because rules for entities belonging to specific chunk might get different over time
|
||||
"chunkX" INTEGER NOT NULL,
|
||||
"chunkY" INTEGER NOT NULL,
|
||||
"x" REAL NOT NULL,
|
||||
"y" REAL NOT NULL,
|
||||
"unique_id" VARCHAR,
|
||||
"type" VARCHAR NOT NULL,
|
||||
"version" INTEGER NOT NULL,
|
||||
"data" BLOB NOT NULL
|
||||
"y" REAL NOT NULL
|
||||
)
|
||||
""".trimIndent())
|
||||
|
||||
// Enforce unique-ness of unique entity IDs
|
||||
// If another entity pops-up with same unique id, then it will overwrite entity in other chunk
|
||||
// (unless colliding entities are both loaded into world's memory, which will cause runtime exception to be thrown;
|
||||
// and no overwrite will happen)
|
||||
it.execute("""
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "entities_unique_id" ON "entities" ("unique_id")
|
||||
""".trimIndent())
|
||||
|
||||
it.execute("""
|
||||
CREATE INDEX IF NOT EXISTS "entities_chunk_pos" ON "entities" ("chunkX", "chunkY")
|
||||
CREATE INDEX IF NOT EXISTS "entities_chunk_pos" ON "unique_entities" ("chunkX", "chunkY")
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@ -167,7 +166,7 @@ class NativeLocalWorldStorage(file: File?) : WorldStorage() {
|
||||
}
|
||||
|
||||
private val readEntities = connection.prepareStatement("""
|
||||
SELECT "type", "version", "data" FROM "entities" WHERE "chunkX" = ? AND "chunkY" = ?
|
||||
SELECT "data" FROM "entities" WHERE "x" = ? AND "y" = ?
|
||||
""".trimIndent())
|
||||
|
||||
override fun loadEntities(pos: ChunkPos): CompletableFuture<Collection<AbstractEntity>> {
|
||||
@ -178,20 +177,22 @@ class NativeLocalWorldStorage(file: File?) : WorldStorage() {
|
||||
val entities = ArrayList<AbstractEntity>()
|
||||
|
||||
readEntities.executeQuery().use {
|
||||
while (it.next()) {
|
||||
val rtype = it.getString(1)
|
||||
val version = it.getInt(2)
|
||||
val type = EntityType.entries.firstOrNull { it.storeName == rtype }
|
||||
if (it.next()) {
|
||||
val data = it.getBytes(1).readJsonArrayInflated()
|
||||
|
||||
if (type != null) {
|
||||
try {
|
||||
val data = it.getBytes(3).readJsonObjectInflated()
|
||||
entities.add(type.fromStorage(VersionRegistry.migrate(VersionedJson(rtype, version, data)) as JsonObject))
|
||||
} catch (err: Throwable) {
|
||||
LOGGER.error("Unable to deserialize entity in chunk $pos", err)
|
||||
for (entry in data) {
|
||||
val versioned = VersionedJson.fromJson(entry)
|
||||
val type = EntityType.entries.firstOrNull { it.storeName == versioned.id }
|
||||
|
||||
if (type != null) {
|
||||
try {
|
||||
entities.add(type.fromStorage(VersionRegistry.migrate(versioned) as JsonObject))
|
||||
} catch (err: Throwable) {
|
||||
LOGGER.error("Unable to deserialize entity in chunk $pos", err)
|
||||
}
|
||||
} else {
|
||||
LOGGER.error("Unknown entity type ${versioned.id} in chunk $pos")
|
||||
}
|
||||
} else {
|
||||
LOGGER.error("Unknown entity type $rtype in chunk $pos")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -240,57 +241,53 @@ class NativeLocalWorldStorage(file: File?) : WorldStorage() {
|
||||
}
|
||||
}
|
||||
|
||||
private val clearEntities = connection.prepareStatement("""
|
||||
DELETE FROM "entities" WHERE "chunkX" = ? AND "chunkY" = ?
|
||||
private val clearUniqueEntities = connection.prepareStatement("""
|
||||
DELETE FROM "unique_entities" WHERE "chunkX" = ? AND "chunkY" = ?
|
||||
""".trimIndent())
|
||||
|
||||
private val beginSaveEntities: PreparedStatement
|
||||
private val finishSaveEntities: PreparedStatement
|
||||
private val rollbackSaveEntities: PreparedStatement
|
||||
private val entitiesSavepoint = SQLSavepoint(connection, "save_entities")
|
||||
|
||||
init {
|
||||
val (begin, commit, rollback) = connection.createSavepoint("save_entities")
|
||||
beginSaveEntities = begin
|
||||
finishSaveEntities = commit
|
||||
rollbackSaveEntities = rollback
|
||||
}
|
||||
private val writeEntities = connection.prepareStatement("""
|
||||
REPLACE INTO "entities" ("x", "y", "data")
|
||||
VALUES (?, ?, ?)
|
||||
""".trimIndent())
|
||||
|
||||
private val writeEntity = connection.prepareStatement("""
|
||||
REPLACE INTO "entities" ("chunkX", "chunkY", "x", "y", "unique_id", "type", "version", "data")
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
private val writeUniqueEntity = connection.prepareStatement("""
|
||||
REPLACE INTO "unique_entities" ("unique_id", "chunkX", "chunkY", "x", "y")
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""".trimIndent())
|
||||
|
||||
override fun saveEntities(pos: ChunkPos, entities: Collection<AbstractEntity>) {
|
||||
executor.execute {
|
||||
beginSaveEntities.execute()
|
||||
entitiesSavepoint.execute {
|
||||
clearUniqueEntities.setInt(1, pos.x)
|
||||
clearUniqueEntities.setInt(2, pos.y)
|
||||
clearUniqueEntities.execute()
|
||||
|
||||
try {
|
||||
clearEntities.setInt(1, pos.x)
|
||||
clearEntities.setInt(2, pos.y)
|
||||
clearEntities.execute()
|
||||
val storeData = JsonArray()
|
||||
|
||||
for (entity in entities) {
|
||||
Starbound.storeJson {
|
||||
val data = JsonObject()
|
||||
entity.serialize(data)
|
||||
storeData.add(VersionRegistry.make(entity.type.storeName, data).toJson())
|
||||
|
||||
writeEntity.setInt(1, pos.x)
|
||||
writeEntity.setInt(2, pos.y)
|
||||
writeEntity.setDouble(3, entity.position.x)
|
||||
writeEntity.setDouble(4, entity.position.y)
|
||||
writeEntity.setString(5, entity.uniqueID.get())
|
||||
writeEntity.setString(6, entity.type.storeName)
|
||||
writeEntity.setInt(7, VersionRegistry.currentVersion(entity.type.storeName))
|
||||
writeEntity.setBytes(8, data.writeJsonObjectDeflated())
|
||||
if (entity.uniqueID.get() != null) {
|
||||
writeUniqueEntity.setString(1, entity.uniqueID.get())
|
||||
writeUniqueEntity.setInt(2, pos.x)
|
||||
writeUniqueEntity.setInt(3, pos.y)
|
||||
writeUniqueEntity.setDouble(4, entity.position.x)
|
||||
writeUniqueEntity.setDouble(5, entity.position.y)
|
||||
|
||||
writeEntity.execute()
|
||||
writeUniqueEntity.execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finishSaveEntities.execute()
|
||||
} catch (err: Throwable) {
|
||||
rollbackSaveEntities.execute()
|
||||
throw err
|
||||
writeEntities.setInt(1, pos.x)
|
||||
writeEntities.setInt(2, pos.y)
|
||||
writeEntities.setBytes(3, storeData.writeJsonArrayDeflated())
|
||||
writeEntities.execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -430,7 +427,7 @@ class NativeLocalWorldStorage(file: File?) : WorldStorage() {
|
||||
}
|
||||
|
||||
private val findUniqueEntity = connection.prepareStatement("""
|
||||
SELECT "chunkX", "chunkY", "x", "y" FROM "entities" WHERE "unique_id" = ?
|
||||
SELECT "chunkX", "chunkY", "x", "y" FROM "unique_entities" WHERE "unique_id" = ?
|
||||
""".trimIndent())
|
||||
|
||||
override fun findUniqueEntity(identifier: String): CompletableFuture<UniqueEntitySearchResult?> {
|
||||
|
@ -58,6 +58,6 @@ object AssetPathStack {
|
||||
if (path.isNotEmpty() && path[0] == '/')
|
||||
return path
|
||||
|
||||
return if (base.endsWith('/')) "$base$path" else "$base/$path"
|
||||
return if (base.endsWith('/')) "$base$path".sbIntern() else "$base/$path".sbIntern()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ru.dbotthepony.kstarbound.util
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
import java.util.*
|
||||
|
@ -5,6 +5,7 @@ import com.google.gson.JsonElement
|
||||
import it.unimi.dsi.fastutil.bytes.ByteConsumer
|
||||
import org.classdump.luna.ByteString
|
||||
import ru.dbotthepony.kommons.util.IStruct2d
|
||||
import ru.dbotthepony.kommons.util.IStruct2f
|
||||
import ru.dbotthepony.kommons.util.IStruct2i
|
||||
import ru.dbotthepony.kommons.util.XXHash32
|
||||
import ru.dbotthepony.kommons.util.XXHash64
|
||||
@ -263,6 +264,10 @@ fun RandomGenerator.nextRange(range: IStruct2d): Double {
|
||||
return if (range.component1() == range.component2()) return range.component1() else nextDouble(range.component1(), range.component2())
|
||||
}
|
||||
|
||||
fun RandomGenerator.nextRange(range: IStruct2f): Float {
|
||||
return if (range.component1() == range.component2()) return range.component1() else nextFloat(range.component1(), range.component2())
|
||||
}
|
||||
|
||||
fun <T> MutableList<T>.shuffle(random: RandomGenerator) {
|
||||
for (i in 0 until size) {
|
||||
val rand = random.nextInt(size)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import ru.dbotthepony.kommons.io.VarIntValueCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kommons.math.linearInterpolation
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
@ -12,6 +11,7 @@ import ru.dbotthepony.kstarbound.defs.world.SkyGlobalConfig
|
||||
import ru.dbotthepony.kstarbound.defs.world.SkyParameters
|
||||
import ru.dbotthepony.kstarbound.defs.world.SkyType
|
||||
import ru.dbotthepony.kstarbound.defs.world.WarpPhase
|
||||
import ru.dbotthepony.kstarbound.io.VarIntValueCodec
|
||||
import ru.dbotthepony.kstarbound.network.syncher.MasterElement
|
||||
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
|
||||
|
@ -1,7 +1,7 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
|
@ -7,7 +7,6 @@ import it.unimi.dsi.fastutil.bytes.ByteArrayList
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kommons.io.nullable
|
||||
import ru.dbotthepony.kommons.util.Either
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
@ -20,6 +19,7 @@ import ru.dbotthepony.kstarbound.defs.DamageType
|
||||
import ru.dbotthepony.kstarbound.defs.EntityDamageTeam
|
||||
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||
import ru.dbotthepony.kstarbound.defs.HitType
|
||||
import ru.dbotthepony.kstarbound.io.nullable
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.network.packets.DamageNotificationPacket
|
||||
|
@ -1,6 +1,5 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import ru.dbotthepony.kommons.io.nullable
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
import ru.dbotthepony.kstarbound.Globals
|
||||
@ -9,6 +8,7 @@ import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.defs.ActorMovementParameters
|
||||
import ru.dbotthepony.kstarbound.defs.JumpProfile
|
||||
import ru.dbotthepony.kstarbound.defs.MovementParameters
|
||||
import ru.dbotthepony.kstarbound.io.nullable
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedData
|
||||
@ -239,7 +239,7 @@ class ActorMovementController() : MovementController() {
|
||||
updateParameters(calculateMovementParameters(actorMovementParameters))
|
||||
}
|
||||
|
||||
// TODO: run is unsed
|
||||
// TODO: run is unused
|
||||
fun pathMove(position: Vector2d, run: Boolean, parameters: PathFinder.Parameters? = null): Pair<Vector2d, Boolean>? {
|
||||
// FIXME: code flow is stupid
|
||||
|
||||
@ -281,6 +281,7 @@ class ActorMovementController() : MovementController() {
|
||||
controlMove = null
|
||||
controlRun = false
|
||||
controlCrouch = false
|
||||
controlDown = false
|
||||
controlJump = false
|
||||
controlJumpAnyway = false
|
||||
controlFly = null
|
||||
|
@ -9,8 +9,8 @@ import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kommons.gson.contains
|
||||
import ru.dbotthepony.kommons.gson.getArray
|
||||
import ru.dbotthepony.kommons.gson.set
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kommons.math.RGBAColor
|
||||
import ru.dbotthepony.kstarbound.math.matrix.Matrix3d
|
||||
import ru.dbotthepony.kstarbound.math.matrix.Matrix3f
|
||||
|
@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.world.entities
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
|
@ -12,10 +12,7 @@ import org.classdump.luna.ByteString
|
||||
import org.classdump.luna.Table
|
||||
import ru.dbotthepony.kommons.gson.get
|
||||
import ru.dbotthepony.kommons.gson.set
|
||||
import ru.dbotthepony.kommons.io.DoubleValueCodec
|
||||
import ru.dbotthepony.kommons.io.FloatValueCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kommons.io.nullable
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kommons.util.Either
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
@ -39,6 +36,9 @@ import ru.dbotthepony.kstarbound.defs.actor.StatusControllerConfig
|
||||
import ru.dbotthepony.kstarbound.defs.item.TreasurePoolDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.monster.MonsterVariant
|
||||
import ru.dbotthepony.kstarbound.fromJsonFast
|
||||
import ru.dbotthepony.kstarbound.io.DoubleValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.FloatValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.nullable
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||
import ru.dbotthepony.kstarbound.lua.LuaMessageHandlerComponent
|
||||
|
@ -1,11 +1,9 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||
import ru.dbotthepony.kommons.io.DoubleValueCodec
|
||||
import ru.dbotthepony.kommons.io.FloatValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kommons.util.Listenable
|
||||
@ -17,6 +15,8 @@ import ru.dbotthepony.kstarbound.Globals
|
||||
import ru.dbotthepony.kstarbound.Registry
|
||||
import ru.dbotthepony.kstarbound.defs.MovementParameters
|
||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||
import ru.dbotthepony.kstarbound.io.DoubleValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.FloatValueCodec
|
||||
import ru.dbotthepony.kstarbound.math.Interpolator
|
||||
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
|
||||
import ru.dbotthepony.kstarbound.network.syncher.networkedBoolean
|
||||
@ -197,9 +197,6 @@ open class MovementController {
|
||||
var movementParameters: MovementParameters = Globals.movementParameters
|
||||
protected set
|
||||
|
||||
var gravityMultiplier = 1.0
|
||||
var isGravityDisabled = false
|
||||
|
||||
open fun isAtWorldLimit(bottomOnly: Boolean = false): Boolean {
|
||||
return false // TODO
|
||||
}
|
||||
@ -212,7 +209,7 @@ open class MovementController {
|
||||
}
|
||||
|
||||
fun determineGravity(): Vector2d {
|
||||
if (isGravityDisabled)
|
||||
if (movementParameters.gravityEnabled == false)
|
||||
return Vector2d.ZERO
|
||||
|
||||
return world.chunkMap.gravityAt(position)
|
||||
@ -279,7 +276,7 @@ open class MovementController {
|
||||
*/
|
||||
// TODO: Ghost collisions occur, where objects trip on edges
|
||||
open fun move(delta: Double) {
|
||||
isZeroGravity = isGravityDisabled || gravityMultiplier == 0.0 || determineGravity().lengthSquared == 0.0
|
||||
isZeroGravity = movementParameters.gravityEnabled == false || (movementParameters.gravityMultiplier ?: 1.0) == 0.0 || determineGravity().lengthSquared == 0.0
|
||||
|
||||
val movementParameters = movementParameters
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kstarbound.world.entities.api.InteractiveEntity
|
||||
import ru.dbotthepony.kstarbound.world.entities.api.ScriptedEntity
|
||||
import java.io.DataOutputStream
|
||||
|
||||
class NPCEntity : ActorEntity(), InteractiveEntity, ScriptedEntity {
|
||||
override val type: EntityType
|
||||
get() = EntityType.NPC
|
||||
override val statusController: StatusController
|
||||
get() = TODO("Not yet implemented")
|
||||
override val damageBarType: DamageBarType
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun writeNetwork(stream: DataOutputStream, isLegacy: Boolean) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override val metaBoundingBox: AABB
|
||||
get() = TODO("Not yet implemented")
|
||||
override val name: String
|
||||
get() = TODO("Not yet implemented")
|
||||
override val description: String
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun callScript(fnName: String, vararg arguments: Any?): Array<Any?> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun evalScript(code: String): Array<Any?> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
@ -102,6 +102,9 @@ class PathController(val controller: ActorMovementController, var edgeTimer: Dou
|
||||
this.path.addAll(newPath)
|
||||
}
|
||||
}
|
||||
} else if (this.path.isEmpty() && newPath.isNotEmpty()) {
|
||||
merged = true
|
||||
this.path.addAll(newPath)
|
||||
}
|
||||
|
||||
if (!merged && controller.position != this.startPosition) {
|
||||
@ -130,7 +133,11 @@ class PathController(val controller: ActorMovementController, var edgeTimer: Dou
|
||||
}
|
||||
|
||||
this.edgeTimer = newEdgeTimer
|
||||
return this.path.isEmpty()
|
||||
|
||||
if (this.path.isEmpty())
|
||||
return true
|
||||
else
|
||||
return null
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@ -139,7 +146,7 @@ class PathController(val controller: ActorMovementController, var edgeTimer: Dou
|
||||
fun findPath(target: Vector2d): Boolean? {
|
||||
// reached the end of the last path and we have a new target position to move toward
|
||||
|
||||
if (path.isEmpty() && controller.world.geometry.diff(this.target!!, target).lengthSquared > 0.1) {
|
||||
if (this.target != null && path.isEmpty() && controller.world.geometry.diff(this.target!!, target).lengthSquared > 0.1) {
|
||||
reset()
|
||||
this.target = target
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ import ru.dbotthepony.kommons.collect.ListenableMap
|
||||
import ru.dbotthepony.kommons.collect.collect
|
||||
import ru.dbotthepony.kommons.collect.map
|
||||
import ru.dbotthepony.kommons.gson.set
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.nullable
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readKOptional
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeKOptional
|
||||
@ -40,6 +39,7 @@ import ru.dbotthepony.kstarbound.defs.actor.StatModifier
|
||||
import ru.dbotthepony.kstarbound.defs.actor.StatModifierType
|
||||
import ru.dbotthepony.kstarbound.defs.actor.StatusControllerConfig
|
||||
import ru.dbotthepony.kstarbound.fromJsonFast
|
||||
import ru.dbotthepony.kstarbound.io.nullable
|
||||
import ru.dbotthepony.kstarbound.io.readInternedString
|
||||
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||
|
@ -23,6 +23,9 @@ abstract class AbstractBehaviorNode {
|
||||
RUNNING(null)
|
||||
}
|
||||
|
||||
var calls = 0
|
||||
protected set
|
||||
|
||||
abstract fun run(delta: Double, state: BehaviorState): Status
|
||||
abstract fun reset()
|
||||
|
||||
|
@ -14,6 +14,7 @@ class ActionNode(val name: String, val parameters: Map<String, NodeParameter>, v
|
||||
private val nodeID = BehaviorState.NODE_GARBAGE_INDEX.getAndIncrement()
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
var coroutine = coroutine
|
||||
var firstTime = false
|
||||
|
||||
@ -67,7 +68,7 @@ class ActionNode(val name: String, val parameters: Map<String, NodeParameter>, v
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ActionNode[$name, parameters=$parameters, outputs=$outputs, coroutine=$coroutine]"
|
||||
return "ActionNode[$calls / $name, parameters=$parameters, outputs=$outputs, coroutine=$coroutine]"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -15,6 +15,7 @@ class DecoratorNode(val name: String, val parameters: Map<String, NodeParameter>
|
||||
private val nodeID = BehaviorState.NODE_GARBAGE_INDEX.getAndIncrement()
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
var coroutine = coroutine
|
||||
|
||||
if (coroutine == null) {
|
||||
@ -100,7 +101,7 @@ class DecoratorNode(val name: String, val parameters: Map<String, NodeParameter>
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "DecoratorNode[$name, coroutine=$coroutine, parameters=$parameters, children=$child]"
|
||||
return "DecoratorNode[$calls / $name, coroutine=$coroutine, parameters=$parameters, children=$child]"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -8,6 +8,7 @@ class DynamicNode(val children: ImmutableList<AbstractBehaviorNode>) : AbstractB
|
||||
private var index = 0
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
for ((i, node) in children.withIndex()) {
|
||||
val status = node.runAndReset(delta, state)
|
||||
|
||||
@ -27,7 +28,7 @@ class DynamicNode(val children: ImmutableList<AbstractBehaviorNode>) : AbstractB
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "DynamicNode[${children.size}, index=$index, current=${children.getOrNull(index)}]"
|
||||
return "DynamicNode[$calls / ${children.size}, index=$index, current=${children.getOrNull(index)}]"
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
|
@ -34,6 +34,7 @@ class ParallelNode(parameters: Map<String, NodeParameter>, val children: Immutab
|
||||
private var lastSucceeded = -1
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
var failed = 0
|
||||
var succeeded = 0
|
||||
|
||||
@ -58,7 +59,7 @@ class ParallelNode(parameters: Map<String, NodeParameter>, val children: Immutab
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ParallelNode[children=${children.size}, successLimit=$successLimit, failLimit=$failLimit, lastFailed=$lastFailed, lastSucceeded=$lastSucceeded]"
|
||||
return "ParallelNode[$calls / children=${children.size}, successLimit=$successLimit, failLimit=$failLimit, lastFailed=$lastFailed, lastSucceeded=$lastSucceeded]"
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
|
@ -8,6 +8,8 @@ class RandomizeNode(val children: ImmutableList<AbstractBehaviorNode>) : Abstrac
|
||||
var index = -1
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
|
||||
if (index == -1 && children.isNotEmpty())
|
||||
index = state.lua.random.nextInt(children.size)
|
||||
|
||||
@ -19,9 +21,9 @@ class RandomizeNode(val children: ImmutableList<AbstractBehaviorNode>) : Abstrac
|
||||
|
||||
override fun toString(): String {
|
||||
if (index == -1)
|
||||
return "RandomizeNode[${children.size}, not chosen]"
|
||||
return "RandomizeNode[$calls / ${children.size}, not chosen]"
|
||||
else
|
||||
return "RandomizeNode[${children.size}, ${children[index]}]"
|
||||
return "RandomizeNode[$calls / ${children.size}, ${children[index]}]"
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
|
@ -4,25 +4,30 @@ import com.google.common.collect.ImmutableList
|
||||
import org.classdump.luna.runtime.ExecutionContext
|
||||
import ru.dbotthepony.kstarbound.lua.userdata.BehaviorState
|
||||
|
||||
class SequenceNode(val children: ImmutableList<AbstractBehaviorNode>) : AbstractBehaviorNode() {
|
||||
class SequenceNode(val children: ImmutableList<AbstractBehaviorNode>, val isSelector: Boolean) : AbstractBehaviorNode() {
|
||||
private var index = 0
|
||||
|
||||
override fun run(delta: Double, state: BehaviorState): Status {
|
||||
calls++
|
||||
|
||||
while (index < children.size) {
|
||||
val child = children[index]
|
||||
val status = child.runAndReset(delta, state)
|
||||
|
||||
if (status == Status.FAILURE || status == Status.RUNNING)
|
||||
if ((isSelector && status == Status.SUCCESS || !isSelector && status == Status.FAILURE) || status == Status.RUNNING)
|
||||
return status
|
||||
|
||||
index++
|
||||
}
|
||||
|
||||
return Status.SUCCESS
|
||||
return if (isSelector) Status.FAILURE else Status.SUCCESS
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "SequenceNode[${children.size}, index=$index, current=${children.getOrNull(index)}]"
|
||||
if (isSelector)
|
||||
return "SelectorNode[$calls / ${children.size}, index=$index, current=${children.getOrNull(index)}]"
|
||||
else
|
||||
return "SequenceNode[$calls / ${children.size}, index=$index, current=${children.getOrNull(index)}]"
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities.player
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.defs.actor.EssentialSlot
|
||||
import ru.dbotthepony.kstarbound.item.ItemStack
|
||||
import java.io.DataInputStream
|
||||
|
@ -3,8 +3,6 @@ package ru.dbotthepony.kstarbound.world.entities.player
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import ru.dbotthepony.kommons.arrays.Object2DArray
|
||||
import ru.dbotthepony.kommons.guava.immutableList
|
||||
import ru.dbotthepony.kommons.io.LongValueCodec
|
||||
import ru.dbotthepony.kommons.io.UnsignedVarLongCodec
|
||||
import ru.dbotthepony.kommons.io.readKOptional
|
||||
import ru.dbotthepony.kommons.io.writeKOptional
|
||||
import ru.dbotthepony.kommons.util.KOptional
|
||||
@ -14,6 +12,8 @@ import ru.dbotthepony.kstarbound.Globals
|
||||
import ru.dbotthepony.kstarbound.defs.actor.EquipmentSlot
|
||||
import ru.dbotthepony.kstarbound.defs.actor.EssentialSlot
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
import ru.dbotthepony.kstarbound.io.LongValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.UnsignedVarLongCodec
|
||||
import ru.dbotthepony.kstarbound.item.ItemStack
|
||||
import ru.dbotthepony.kstarbound.network.syncher.NetworkedGroup
|
||||
import ru.dbotthepony.kstarbound.network.syncher.legacyCodec
|
||||
|
@ -1,9 +1,9 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities.player
|
||||
|
||||
import ru.dbotthepony.kommons.io.IntValueCodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.koptional
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.IntValueCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.koptional
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kommons.io.readKOptional
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kommons.io.writeKOptional
|
||||
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities.tile
|
||||
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.readSignedVarInt
|
||||
import ru.dbotthepony.kommons.io.readVarInt
|
||||
import ru.dbotthepony.kommons.io.writeSignedVarInt
|
||||
|
@ -26,9 +26,8 @@ import ru.dbotthepony.kstarbound.defs.`object`.ObjectOrientation
|
||||
import ru.dbotthepony.kommons.gson.get
|
||||
import ru.dbotthepony.kommons.gson.set
|
||||
import ru.dbotthepony.kommons.guava.immutableSet
|
||||
import ru.dbotthepony.kommons.io.RGBACodec
|
||||
import ru.dbotthepony.kommons.io.StreamCodec
|
||||
import ru.dbotthepony.kommons.io.map
|
||||
import ru.dbotthepony.kstarbound.io.StreamCodec
|
||||
import ru.dbotthepony.kstarbound.io.map
|
||||
import ru.dbotthepony.kommons.io.writeBinaryString
|
||||
import ru.dbotthepony.kstarbound.math.AABB
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
@ -46,6 +45,7 @@ import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||
import ru.dbotthepony.kstarbound.defs.`object`.ObjectType
|
||||
import ru.dbotthepony.kstarbound.defs.quest.QuestArcDescriptor
|
||||
import ru.dbotthepony.kstarbound.defs.tile.TileDamage
|
||||
import ru.dbotthepony.kstarbound.io.RGBACodec
|
||||
import ru.dbotthepony.kstarbound.io.Vector2iCodec
|
||||
import ru.dbotthepony.kstarbound.json.JsonPath
|
||||
import ru.dbotthepony.kstarbound.json.jsonArrayOf
|
||||
|
Loading…
Reference in New Issue
Block a user