Compare commits

...

10 Commits

59 changed files with 718 additions and 236 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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<*> {

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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>,

View File

@ -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

View File

@ -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) });

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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,
)

View File

@ -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

View 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()
}
}

View File

@ -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)
}

View 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)

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?> {

View File

@ -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()
}
}

View File

@ -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.*

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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()

View File

@ -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 {

View File

@ -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 {

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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() {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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