Stagehands, they don't work because of Luna (:
This commit is contained in:
parent
aeca7836cd
commit
3b454374ec
@ -50,6 +50,7 @@ operator fun <K : Any, V : Any> ImmutableMap.Builder<K, V>.set(key: K, value: V)
|
|||||||
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
||||||
inline fun <reified T> Gson.fromJson(reader: JsonElement): T? = getAdapter(T::class.java).read(FastJsonTreeReader(reader))
|
inline fun <reified T> Gson.fromJson(reader: JsonElement): T? = getAdapter(T::class.java).read(FastJsonTreeReader(reader))
|
||||||
|
|
||||||
|
// TODO: mark these nullable
|
||||||
fun <T> Gson.fromJsonFast(reader: JsonElement, type: Class<T>): T = getAdapter(type).read(FastJsonTreeReader(reader))
|
fun <T> Gson.fromJsonFast(reader: JsonElement, type: Class<T>): T = getAdapter(type).read(FastJsonTreeReader(reader))
|
||||||
fun <T> Gson.fromJsonFast(reader: JsonElement, type: TypeToken<T>): T = getAdapter(type).read(FastJsonTreeReader(reader))
|
fun <T> Gson.fromJsonFast(reader: JsonElement, type: TypeToken<T>): T = getAdapter(type).read(FastJsonTreeReader(reader))
|
||||||
inline fun <reified T> Gson.fromJsonFast(reader: JsonElement): T = getAdapter(object : TypeToken<T>() {}).read(FastJsonTreeReader(reader))
|
inline fun <reified T> Gson.fromJsonFast(reader: JsonElement): T = getAdapter(object : TypeToken<T>() {}).read(FastJsonTreeReader(reader))
|
||||||
|
@ -117,6 +117,33 @@ object Registries {
|
|||||||
|
|
||||||
private val monsterParts = HashMap<Pair<String, String>, HashMap<String, Pair<MonsterPartDefinition, IStarboundFile>>>()
|
private val monsterParts = HashMap<Pair<String, String>, HashMap<String, Pair<MonsterPartDefinition, IStarboundFile>>>()
|
||||||
private val loggedMonsterPartMisses = Collections.synchronizedSet(ObjectOpenHashSet<Pair<String, String>>())
|
private val loggedMonsterPartMisses = Collections.synchronizedSet(ObjectOpenHashSet<Pair<String, String>>())
|
||||||
|
private val stagehands = HashMap<String, Pair<JsonObject, IStarboundFile>>()
|
||||||
|
|
||||||
|
fun makeStagehandConfig(type: String, overrides: JsonElement? = JsonNull.INSTANCE): JsonObject {
|
||||||
|
val (data) = stagehands[type] ?: throw NoSuchElementException("No such stagehand: $type")
|
||||||
|
return mergeJson(data.deepCopy(), overrides ?: JsonNull.INSTANCE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadStagehands(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()]).asJsonObject
|
||||||
|
val type = elem["type"].asString
|
||||||
|
|
||||||
|
Starbound.submit {
|
||||||
|
val existing = stagehands.put(type, elem to listedFile)
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
LOGGER.warn("Redefining stagehand prototype $type (new def originate from $listedFile, existing originate from ${existing.second})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
LOGGER.error("Loading stagehand definition file $listedFile", err)
|
||||||
|
}
|
||||||
|
}.asCompletableFuture()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun selectMonsterPart(category: String, type: String, random: RandomGenerator): MonsterPartDefinition? {
|
fun selectMonsterPart(category: String, type: String, random: RandomGenerator): MonsterPartDefinition? {
|
||||||
val key = category to type
|
val key = category to type
|
||||||
@ -275,6 +302,7 @@ object Registries {
|
|||||||
tasks.addAll(loadRegistry(dungeons, patchTree, fileTree["dungeon"] ?: listOf(), key(DungeonDefinition::name)))
|
tasks.addAll(loadRegistry(dungeons, patchTree, fileTree["dungeon"] ?: listOf(), key(DungeonDefinition::name)))
|
||||||
|
|
||||||
tasks.addAll(loadMonsterParts(fileTree["monsterpart"] ?: listOf(), patchTree))
|
tasks.addAll(loadMonsterParts(fileTree["monsterpart"] ?: listOf(), patchTree))
|
||||||
|
tasks.addAll(loadStagehands(fileTree["stagehand"] ?: listOf(), patchTree))
|
||||||
|
|
||||||
tasks.addAll(loadRegistry(worldObjects, patchTree, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)))
|
tasks.addAll(loadRegistry(worldObjects, patchTree, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)))
|
||||||
tasks.addAll(loadRegistry(monsterTypes, patchTree, fileTree["monstertype"] ?: listOf(), key(MonsterTypeDefinition::type)))
|
tasks.addAll(loadRegistry(monsterTypes, patchTree, fileTree["monstertype"] ?: listOf(), key(MonsterTypeDefinition::type)))
|
||||||
|
@ -16,6 +16,7 @@ import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
|||||||
import ru.dbotthepony.kstarbound.world.entities.MonsterEntity
|
import ru.dbotthepony.kstarbound.world.entities.MonsterEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.NPCEntity
|
import ru.dbotthepony.kstarbound.world.entities.NPCEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.ProjectileEntity
|
import ru.dbotthepony.kstarbound.world.entities.ProjectileEntity
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.StagehandEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity
|
import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.tile.ContainerObject
|
import ru.dbotthepony.kstarbound.world.entities.tile.ContainerObject
|
||||||
import ru.dbotthepony.kstarbound.world.entities.tile.LoungeableObject
|
import ru.dbotthepony.kstarbound.world.entities.tile.LoungeableObject
|
||||||
@ -102,11 +103,11 @@ enum class EntityType(override val jsonName: String, val storeName: String, val
|
|||||||
|
|
||||||
STAGEHAND("stagehand", "StagehandEntity", true, true) {
|
STAGEHAND("stagehand", "StagehandEntity", true, true) {
|
||||||
override suspend fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
|
override suspend fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity {
|
||||||
TODO("STAGEHAND")
|
return StagehandEntity(stream, isLegacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromStorage(data: JsonObject): AbstractEntity {
|
override fun fromStorage(data: JsonObject): AbstractEntity {
|
||||||
TODO("STAGEHAND")
|
return StagehandEntity(data)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.lua.bindings
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.classdump.luna.ByteString
|
import org.classdump.luna.ByteString
|
||||||
import org.classdump.luna.LuaRuntimeException
|
import org.classdump.luna.LuaRuntimeException
|
||||||
@ -11,17 +12,22 @@ import org.classdump.luna.runtime.ExecutionContext
|
|||||||
import org.classdump.luna.runtime.LuaFunction
|
import org.classdump.luna.runtime.LuaFunction
|
||||||
import ru.dbotthepony.kommons.collect.map
|
import ru.dbotthepony.kommons.collect.map
|
||||||
import ru.dbotthepony.kommons.collect.toList
|
import ru.dbotthepony.kommons.collect.toList
|
||||||
|
import ru.dbotthepony.kommons.gson.contains
|
||||||
|
import ru.dbotthepony.kommons.gson.set
|
||||||
import ru.dbotthepony.kstarbound.Registries
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
import ru.dbotthepony.kstarbound.Starbound
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
import ru.dbotthepony.kstarbound.defs.ActorMovementParameters
|
import ru.dbotthepony.kstarbound.defs.ActorMovementParameters
|
||||||
import ru.dbotthepony.kstarbound.defs.EntityType
|
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||||
|
import ru.dbotthepony.kstarbound.defs.actor.NPCVariant
|
||||||
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
import ru.dbotthepony.kstarbound.defs.item.ItemDescriptor
|
||||||
|
import ru.dbotthepony.kstarbound.defs.monster.MonsterVariant
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyLiquid
|
import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyLiquid
|
||||||
import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyTile
|
import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyTile
|
||||||
import ru.dbotthepony.kstarbound.defs.world.TerrestrialWorldParameters
|
import ru.dbotthepony.kstarbound.defs.world.TerrestrialWorldParameters
|
||||||
import ru.dbotthepony.kstarbound.fromJsonFast
|
import ru.dbotthepony.kstarbound.fromJsonFast
|
||||||
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
|
||||||
|
import ru.dbotthepony.kstarbound.json.mergeJson
|
||||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||||
import ru.dbotthepony.kstarbound.lua.contains
|
import ru.dbotthepony.kstarbound.lua.contains
|
||||||
@ -63,7 +69,10 @@ import ru.dbotthepony.kstarbound.world.api.AbstractLiquidState
|
|||||||
import ru.dbotthepony.kstarbound.world.castRay
|
import ru.dbotthepony.kstarbound.world.castRay
|
||||||
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
|
import ru.dbotthepony.kstarbound.world.entities.AbstractEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
import ru.dbotthepony.kstarbound.world.entities.ItemDropEntity
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.MonsterEntity
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.NPCEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.PathFinder
|
import ru.dbotthepony.kstarbound.world.entities.PathFinder
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.StagehandEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.api.ScriptedEntity
|
import ru.dbotthepony.kstarbound.world.entities.api.ScriptedEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.tile.WorldObject
|
import ru.dbotthepony.kstarbound.world.entities.tile.WorldObject
|
||||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||||
@ -430,7 +439,7 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) {
|
|||||||
LOGGER.debug("Lua script tried to create non existing item {} at {}", itemType, pos)
|
LOGGER.debug("Lua script tried to create non existing item {} at {}", itemType, pos)
|
||||||
returnBuffer.setTo()
|
returnBuffer.setTo()
|
||||||
} else {
|
} else {
|
||||||
val create = ItemDropEntity(descriptor)
|
val create = ItemDropEntity(descriptor, lua.random)
|
||||||
create.movement.velocity = initialVelocity
|
create.movement.velocity = initialVelocity
|
||||||
|
|
||||||
if (intangibleTime is Number) {
|
if (intangibleTime is Number) {
|
||||||
@ -453,8 +462,7 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) {
|
|||||||
val items = Registries.treasurePools
|
val items = Registries.treasurePools
|
||||||
.getOrThrow(pool.decode())
|
.getOrThrow(pool.decode())
|
||||||
.value
|
.value
|
||||||
// not using lua.random because we are, well, world's bindings
|
.evaluate(if (seed != null) random(seed.toLong()) else lua.random, level.toDouble())
|
||||||
.evaluate(if (seed != null) random(seed.toLong()) else self.random, level.toDouble())
|
|
||||||
|
|
||||||
val pos = toVector2d(position)
|
val pos = toVector2d(position)
|
||||||
|
|
||||||
@ -465,18 +473,79 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) {
|
|||||||
entities.add(entity.entityID)
|
entities.add(entity.entityID)
|
||||||
}
|
}
|
||||||
} catch (err: Throwable) {
|
} catch (err: Throwable) {
|
||||||
LOGGER.error("Exception while spawning treasure from $pool at $position", err)
|
LOGGER.error("Exception while spawning treasure from pool '$pool' at $position", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
returnBuffer.setTo(tableOf(*entities.toTypedArray()))
|
returnBuffer.setTo(tableOf(*entities.toTypedArray()))
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks["spawnMonster"] = luaFunction {
|
callbacks["spawnMonster"] = luaFunction { type: ByteString, position: Table, overrides: Any? ->
|
||||||
// TODO
|
try {
|
||||||
returnBuffer.setTo(0L)
|
val parameters = JsonObject()
|
||||||
|
parameters["aggressive"] = lua.random.nextBoolean()
|
||||||
|
|
||||||
|
if (overrides != null) {
|
||||||
|
mergeJson(parameters, toJsonFromLua(overrides))
|
||||||
}
|
}
|
||||||
callbacks["spawnNpc"] = luaStub("spawnNpc")
|
|
||||||
callbacks["spawnStagehand"] = luaStub("spawnStagehand")
|
val level = parameters["level"]?.asDouble ?: 1.0
|
||||||
|
val seed: Long
|
||||||
|
|
||||||
|
if ("seed" !in parameters || !parameters["seed"].asJsonPrimitive.isNumber) {
|
||||||
|
seed = lua.random.nextLong()
|
||||||
|
} else {
|
||||||
|
seed = parameters["seed"].asLong
|
||||||
|
}
|
||||||
|
|
||||||
|
val variant = Registries.monsterTypes.getOrThrow(type.decode()).value.create(seed, parameters)
|
||||||
|
val monster = MonsterEntity(variant, level)
|
||||||
|
monster.position = toVector2d(position)
|
||||||
|
monster.joinWorld(self)
|
||||||
|
returnBuffer.setTo(monster.entityID)
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
LOGGER.error("Exception caught while spawning Monster type $type", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks["spawnNpc"] = luaFunctionN("spawnNpc") {
|
||||||
|
val position = it.nextTable()
|
||||||
|
val species = it.nextString().decode()
|
||||||
|
val type = it.nextString().decode()
|
||||||
|
val level = it.nextFloat()
|
||||||
|
val seed = it.nextOptionalInteger() ?: lua.random.nextLong()
|
||||||
|
val overrides = toJsonFromLua(it.nextOptionalAny(null))
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: this blocks world thread
|
||||||
|
val npc = runBlocking {
|
||||||
|
NPCEntity(NPCVariant.create(
|
||||||
|
Registries.species.getOrThrow(species),
|
||||||
|
type,
|
||||||
|
level,
|
||||||
|
seed,
|
||||||
|
overrides
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
npc.position = toVector2d(position)
|
||||||
|
npc.joinWorld(self)
|
||||||
|
returnBuffer.setTo(npc.entityID)
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
LOGGER.error("Exception caught while spawning NPC $type with species $species", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callbacks["spawnStagehand"] = luaFunction { position: Table, type: ByteString, overrides: Any? ->
|
||||||
|
try {
|
||||||
|
val stagehand = StagehandEntity(type.decode(), toJsonFromLua(overrides))
|
||||||
|
stagehand.position = toVector2d(position)
|
||||||
|
stagehand.joinWorld(self)
|
||||||
|
returnBuffer.setTo(stagehand.entityID)
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
LOGGER.error("Exception caught while spawning stagehand of type '$type'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
callbacks["spawnProjectile"] = luaStub("spawnProjectile")
|
callbacks["spawnProjectile"] = luaStub("spawnProjectile")
|
||||||
callbacks["spawnVehicle"] = luaStub("spawnVehicle")
|
callbacks["spawnVehicle"] = luaStub("spawnVehicle")
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ private val centerStr = ByteString.of("center")
|
|||||||
private val boundModeStr = ByteString.of("boundMode")
|
private val boundModeStr = ByteString.of("boundMode")
|
||||||
private val orderStr = ByteString.of("order")
|
private val orderStr = ByteString.of("order")
|
||||||
|
|
||||||
private fun ExecutionContext.entityQueryImpl(self: World<*, *>, options: Table, predicate: Predicate<AbstractEntity> = Predicate { true }): Table {
|
private fun ExecutionContext.entityQueryImpl(self: World<*, *>, lua: LuaEnvironment, options: Table, predicate: Predicate<AbstractEntity> = Predicate { true }): Table {
|
||||||
val withoutEntityId = (indexNoYield(options, withoutEntityIdStr) as Number?)?.toInt()
|
val withoutEntityId = (indexNoYield(options, withoutEntityIdStr) as Number?)?.toInt()
|
||||||
|
|
||||||
val includedTypes = EnumSet.allOf(EntityType::class.java)
|
val includedTypes = EnumSet.allOf(EntityType::class.java)
|
||||||
@ -200,7 +200,7 @@ private fun ExecutionContext.entityQueryImpl(self: World<*, *>, options: Table,
|
|||||||
|
|
||||||
when (val order = (indexNoYield(options, orderStr) as ByteString?)?.decode()?.lowercase()) {
|
when (val order = (indexNoYield(options, orderStr) as ByteString?)?.decode()?.lowercase()) {
|
||||||
null -> {} // do nothing
|
null -> {} // do nothing
|
||||||
"random" -> entitites.shuffle(self.random)
|
"random" -> entitites.shuffle(lua.random)
|
||||||
"nearest" -> {
|
"nearest" -> {
|
||||||
val nearestPosition = lineQuery?.p0 ?: polyQuery?.centre ?: rectQuery?.centre ?: radiusQuery?.first ?: Vector2d.ZERO
|
val nearestPosition = lineQuery?.p0 ?: polyQuery?.centre ?: rectQuery?.centre ?: radiusQuery?.first ?: Vector2d.ZERO
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ private fun ExecutionContext.entityQueryImpl(self: World<*, *>, options: Table,
|
|||||||
return tableOf(*entitites.map { it.entityID.toLong() }.toTypedArray())
|
return tableOf(*entitites.map { it.entityID.toLong() }.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExecutionContext.intermediateQueryFunction(self: World<*, *>, pos1: Table, pos2OrRadius: Any, options: Table?, predicate: Predicate<AbstractEntity>) {
|
private fun ExecutionContext.intermediateQueryFunction(self: World<*, *>, lua: LuaEnvironment, pos1: Table, pos2OrRadius: Any, options: Table?, predicate: Predicate<AbstractEntity>) {
|
||||||
val actualOptions = options ?: tableOf()
|
val actualOptions = options ?: tableOf()
|
||||||
|
|
||||||
if (pos2OrRadius is Number) {
|
if (pos2OrRadius is Number) {
|
||||||
@ -224,35 +224,35 @@ private fun ExecutionContext.intermediateQueryFunction(self: World<*, *>, pos1:
|
|||||||
actualOptions[rectStr] = tableOf(pos1[1L], pos1[2L], pos2OrRadius[1L], pos2OrRadius[2L])
|
actualOptions[rectStr] = tableOf(pos1[1L], pos1[2L], pos2OrRadius[1L], pos2OrRadius[2L])
|
||||||
}
|
}
|
||||||
|
|
||||||
returnBuffer.setTo(entityQueryImpl(self, actualOptions, predicate))
|
returnBuffer.setTo(entityQueryImpl(self, lua, actualOptions, predicate))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ExecutionContext.intermediateLineQueryFunction(self: World<*, *>, pos1: Table, pos2: Table, options: Table?, predicate: Predicate<AbstractEntity>) {
|
private fun ExecutionContext.intermediateLineQueryFunction(self: World<*, *>, lua: LuaEnvironment, pos1: Table, pos2: Table, options: Table?, predicate: Predicate<AbstractEntity>) {
|
||||||
val actualOptions = options ?: tableOf()
|
val actualOptions = options ?: tableOf()
|
||||||
actualOptions[lineStr] = tableOf(pos1, pos2)
|
actualOptions[lineStr] = tableOf(pos1, pos2)
|
||||||
returnBuffer.setTo(entityQueryImpl(self, actualOptions, predicate))
|
returnBuffer.setTo(entityQueryImpl(self, lua, actualOptions, predicate))
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T : AbstractEntity> createQueryFunction(self: World<*, *>) = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? ->
|
private inline fun <reified T : AbstractEntity> createQueryFunction(self: World<*, *>, lua: LuaEnvironment) = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? ->
|
||||||
intermediateQueryFunction(self, pos1, pos2OrRadius, options, Predicate { it is T })
|
intermediateQueryFunction(self, lua, pos1, pos2OrRadius, options, Predicate { it is T })
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <reified T : AbstractEntity> createLineQueryFunction(self: World<*, *>) = luaFunction { pos1: Table, pos2: Table, options: Table? ->
|
private inline fun <reified T : AbstractEntity> createLineQueryFunction(self: World<*, *>, lua: LuaEnvironment) = luaFunction { pos1: Table, pos2: Table, options: Table? ->
|
||||||
intermediateLineQueryFunction(self, pos1, pos2, options, Predicate { it is T })
|
intermediateLineQueryFunction(self, lua, pos1, pos2, options, Predicate { it is T })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEnvironment) {
|
fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEnvironment) {
|
||||||
callbacks["entityQuery"] = createQueryFunction<AbstractEntity>(self)
|
callbacks["entityQuery"] = createQueryFunction<AbstractEntity>(self, lua)
|
||||||
callbacks["monsterQuery"] = createQueryFunction<AbstractEntity>(self) // TODO
|
callbacks["monsterQuery"] = createQueryFunction<AbstractEntity>(self, lua) // TODO
|
||||||
callbacks["npcQuery"] = createQueryFunction<AbstractEntity>(self) // TODO
|
callbacks["npcQuery"] = createQueryFunction<AbstractEntity>(self, lua) // TODO
|
||||||
callbacks["itemDropQuery"] = createQueryFunction<ItemDropEntity>(self)
|
callbacks["itemDropQuery"] = createQueryFunction<ItemDropEntity>(self, lua)
|
||||||
callbacks["playerQuery"] = createQueryFunction<PlayerEntity>(self)
|
callbacks["playerQuery"] = createQueryFunction<PlayerEntity>(self, lua)
|
||||||
|
|
||||||
callbacks["entityLineQuery"] = createLineQueryFunction<AbstractEntity>(self)
|
callbacks["entityLineQuery"] = createLineQueryFunction<AbstractEntity>(self, lua)
|
||||||
callbacks["monsterLineQuery"] = createLineQueryFunction<AbstractEntity>(self) // TODO
|
callbacks["monsterLineQuery"] = createLineQueryFunction<AbstractEntity>(self, lua) // TODO
|
||||||
callbacks["npcLineQuery"] = createLineQueryFunction<AbstractEntity>(self) // TODO
|
callbacks["npcLineQuery"] = createLineQueryFunction<AbstractEntity>(self, lua) // TODO
|
||||||
callbacks["itemDropLineQuery"] = createLineQueryFunction<ItemDropEntity>(self)
|
callbacks["itemDropLineQuery"] = createLineQueryFunction<ItemDropEntity>(self, lua)
|
||||||
callbacks["playerLineQuery"] = createLineQueryFunction<PlayerEntity>(self)
|
callbacks["playerLineQuery"] = createLineQueryFunction<PlayerEntity>(self, lua)
|
||||||
|
|
||||||
callbacks["objectQuery"] = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? ->
|
callbacks["objectQuery"] = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? ->
|
||||||
var objectName: String? = null
|
var objectName: String? = null
|
||||||
@ -260,7 +260,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn
|
|||||||
if (options != null)
|
if (options != null)
|
||||||
objectName = (indexNoYield(options, "name") as ByteString?)?.decode()
|
objectName = (indexNoYield(options, "name") as ByteString?)?.decode()
|
||||||
|
|
||||||
intermediateQueryFunction(self, pos1, pos2OrRadius, options, Predicate {
|
intermediateQueryFunction(self, lua, pos1, pos2OrRadius, options, Predicate {
|
||||||
it is WorldObject && (objectName == null || it.config.key == objectName)
|
it is WorldObject && (objectName == null || it.config.key == objectName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -271,7 +271,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn
|
|||||||
if (options != null)
|
if (options != null)
|
||||||
objectName = (indexNoYield(options, "name") as ByteString?)?.decode()
|
objectName = (indexNoYield(options, "name") as ByteString?)?.decode()
|
||||||
|
|
||||||
intermediateLineQueryFunction(self, pos1, pos2, options, Predicate {
|
intermediateLineQueryFunction(self, lua, pos1, pos2, options, Predicate {
|
||||||
it is WorldObject && (objectName == null || it.config.key == objectName)
|
it is WorldObject && (objectName == null || it.config.key == objectName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn
|
|||||||
else -> LoungeOrientation.entries.valueOf(orientationName)
|
else -> LoungeOrientation.entries.valueOf(orientationName)
|
||||||
}
|
}
|
||||||
|
|
||||||
intermediateQueryFunction(self, pos1, pos2OrRadius, options, Predicate {
|
intermediateQueryFunction(self, lua, pos1, pos2OrRadius, options, Predicate {
|
||||||
it is LoungeableObject && (orientation == LoungeOrientation.NONE || it.sitOrientation == orientation)
|
it is LoungeableObject && (orientation == LoungeOrientation.NONE || it.sitOrientation == orientation)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -303,7 +303,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn
|
|||||||
else -> LoungeOrientation.entries.valueOf(orientationName!!)
|
else -> LoungeOrientation.entries.valueOf(orientationName!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
intermediateLineQueryFunction(self, pos1, pos2, options, Predicate {
|
intermediateLineQueryFunction(self, lua, pos1, pos2, options, Predicate {
|
||||||
it is LoungeableObject && (orientation == LoungeOrientation.NONE || it.sitOrientation == orientation)
|
it is LoungeableObject && (orientation == LoungeOrientation.NONE || it.sitOrientation == orientation)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -748,7 +748,7 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn
|
|||||||
enqueueWarp(WarpAlias.OwnShip)
|
enqueueWarp(WarpAlias.OwnShip)
|
||||||
}
|
}
|
||||||
|
|
||||||
//enqueueWarp(WarpAction.World(WorldID.Instance("outpost")))
|
enqueueWarp(WarpAction.World(WorldID.Instance("outpost")))
|
||||||
|
|
||||||
scope.launch { shipFlightEventLoop(context.shipCoordinate, context.systemLocation) }
|
scope.launch { shipFlightEventLoop(context.shipCoordinate, context.systemLocation) }
|
||||||
}
|
}
|
||||||
|
@ -670,6 +670,8 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
|||||||
ticks++
|
ticks++
|
||||||
simulationTime += delta
|
simulationTime += delta
|
||||||
|
|
||||||
|
// TODO: Zombie entity handling (don't tick entities ending up in partially loaded chunks,
|
||||||
|
// or chunks which border with unloaded/not sufficiently loaded regions)
|
||||||
if (entityList.size < 128) {
|
if (entityList.size < 128) {
|
||||||
entityList.forEach { it.tickParallel(delta) }
|
entityList.forEach { it.tickParallel(delta) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -30,6 +30,7 @@ import ru.dbotthepony.kstarbound.world.physics.Poly
|
|||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
import java.util.random.RandomGenerator
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class ItemDropEntity() : DynamicEntity() {
|
class ItemDropEntity() : DynamicEntity() {
|
||||||
@ -70,8 +71,8 @@ class ItemDropEntity() : DynamicEntity() {
|
|||||||
movement.applyParameters(MovementParameters(collisionPoly = Either.left(Poly(AABB(Vector2d(-0.5, -0.5), Vector2d(0.5, 0.5))))))
|
movement.applyParameters(MovementParameters(collisionPoly = Either.left(Poly(AABB(Vector2d(-0.5, -0.5), Vector2d(0.5, 0.5))))))
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(item: ItemDescriptor) : this() {
|
constructor(item: ItemDescriptor, random: RandomGenerator? = null) : this() {
|
||||||
this.item = item.build()
|
this.item = item.build(random = random)
|
||||||
this.owningEntity = 0
|
this.owningEntity = 0
|
||||||
this.state = State.AVAILABLE
|
this.state = State.AVAILABLE
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,152 @@
|
|||||||
|
package ru.dbotthepony.kstarbound.world.entities
|
||||||
|
|
||||||
|
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 ru.dbotthepony.kommons.gson.contains
|
||||||
|
import ru.dbotthepony.kommons.gson.get
|
||||||
|
import ru.dbotthepony.kommons.gson.set
|
||||||
|
import ru.dbotthepony.kommons.util.getValue
|
||||||
|
import ru.dbotthepony.kommons.util.setValue
|
||||||
|
import ru.dbotthepony.kstarbound.Registries
|
||||||
|
import ru.dbotthepony.kstarbound.Starbound
|
||||||
|
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||||
|
import ru.dbotthepony.kstarbound.defs.EntityType
|
||||||
|
import ru.dbotthepony.kstarbound.fromJsonFast
|
||||||
|
import ru.dbotthepony.kstarbound.json.jsonArrayOf
|
||||||
|
import ru.dbotthepony.kstarbound.json.putAll
|
||||||
|
import ru.dbotthepony.kstarbound.json.readJsonElement
|
||||||
|
import ru.dbotthepony.kstarbound.json.writeJsonElement
|
||||||
|
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||||
|
import ru.dbotthepony.kstarbound.lua.LuaUpdateComponent
|
||||||
|
import ru.dbotthepony.kstarbound.lua.from
|
||||||
|
import ru.dbotthepony.kstarbound.lua.get
|
||||||
|
import ru.dbotthepony.kstarbound.lua.set
|
||||||
|
import ru.dbotthepony.kstarbound.lua.tableOf
|
||||||
|
import ru.dbotthepony.kstarbound.lua.toJsonFromLua
|
||||||
|
import ru.dbotthepony.kstarbound.math.AABB
|
||||||
|
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||||
|
import ru.dbotthepony.kstarbound.network.syncher.networkedFloat
|
||||||
|
import ru.dbotthepony.kstarbound.world.World
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.api.ScriptedEntity
|
||||||
|
import java.io.DataInputStream
|
||||||
|
import java.io.DataOutputStream
|
||||||
|
|
||||||
|
class StagehandEntity(isRemote: Boolean = false) : AbstractEntity(), ScriptedEntity {
|
||||||
|
constructor(stream: DataInputStream, isLegacy: Boolean) : this(stream.readJsonElement().asJsonObject, true)
|
||||||
|
|
||||||
|
constructor(data: JsonObject, isRemote: Boolean = false) : this(isRemote) {
|
||||||
|
deserialize(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(type: String, overrides: JsonElement? = JsonNull.INSTANCE) : this(Registries.makeStagehandConfig(type, overrides))
|
||||||
|
|
||||||
|
var xPosition by networkedFloat().also { networkGroup.upstream.add(it) }
|
||||||
|
var yPosition by networkedFloat().also { networkGroup.upstream.add(it) }
|
||||||
|
|
||||||
|
init {
|
||||||
|
networkGroup.upstream.add(uniqueID)
|
||||||
|
this.isRemote = isRemote
|
||||||
|
}
|
||||||
|
|
||||||
|
override var position: Vector2d
|
||||||
|
get() = Vector2d(xPosition, yPosition)
|
||||||
|
set(value) {
|
||||||
|
xPosition = value.x
|
||||||
|
yPosition = value.y
|
||||||
|
}
|
||||||
|
|
||||||
|
override val type: EntityType
|
||||||
|
get() = EntityType.STAGEHAND
|
||||||
|
|
||||||
|
private var config: JsonObject = JsonObject()
|
||||||
|
|
||||||
|
var isScripted = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
val lua = LuaEnvironment()
|
||||||
|
val luaUpdate = LuaUpdateComponent(lua)
|
||||||
|
|
||||||
|
init {
|
||||||
|
lua.globals["storage"] = lua.tableOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(data: JsonObject) {
|
||||||
|
super.deserialize(data)
|
||||||
|
|
||||||
|
config = data.deepCopy()
|
||||||
|
isScripted = config["scripts"] is JsonArray
|
||||||
|
|
||||||
|
if ("position" in config) {
|
||||||
|
val pos = config["position"].asJsonArray
|
||||||
|
xPosition = pos[0].asDouble
|
||||||
|
yPosition = pos[1].asDouble
|
||||||
|
}
|
||||||
|
|
||||||
|
var broadcastArea: AABB? = null
|
||||||
|
|
||||||
|
if ("broadcastArea" in config) {
|
||||||
|
broadcastArea = Starbound.gson.fromJsonFast(config["broadcastArena"], AABB::class.java)
|
||||||
|
|
||||||
|
if (broadcastArea.width < 0.0 || broadcastArea.height > 0.0)
|
||||||
|
broadcastArea = null
|
||||||
|
}
|
||||||
|
|
||||||
|
boundingBox = broadcastArea ?: AABB.withSide(Vector2d.ZERO, 5.0)
|
||||||
|
|
||||||
|
if (isScripted && isLocal) {
|
||||||
|
lua.attach(config["scripts"].asJsonArray.map { AssetPath(it.asString) })
|
||||||
|
luaUpdate.stepCount = config.get("scriptDelta", 5.0)
|
||||||
|
|
||||||
|
if ("scriptStorage" in config) {
|
||||||
|
lua.globals["storage"] = lua.from(config["scriptStorage"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJoinWorld(world: World<*, *>) {
|
||||||
|
super.onJoinWorld(world)
|
||||||
|
|
||||||
|
if (isLocal && isScripted) {
|
||||||
|
lua.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(data: JsonObject) {
|
||||||
|
super.serialize(data)
|
||||||
|
|
||||||
|
data.putAll(config, true)
|
||||||
|
data["position"] = jsonArrayOf(JsonPrimitive(xPosition), JsonPrimitive(yPosition))
|
||||||
|
|
||||||
|
if (uniqueID.get() != null)
|
||||||
|
data["uniqueId"] = uniqueID.get()!!
|
||||||
|
else
|
||||||
|
data.remove("uniqueId")
|
||||||
|
|
||||||
|
if (isScripted)
|
||||||
|
data["scriptStorage"] = toJsonFromLua(lua.globals["storage"])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeNetwork(stream: DataOutputStream, isLegacy: Boolean) {
|
||||||
|
stream.writeJsonElement(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var boundingBox = AABB.withSide(Vector2d.ZERO, 5.0)
|
||||||
|
|
||||||
|
override val metaBoundingBox: AABB
|
||||||
|
get() = boundingBox + position
|
||||||
|
override val name: String
|
||||||
|
get() = "Stagehand"
|
||||||
|
override val description: String
|
||||||
|
get() = "Technical entity responsible for doing cool stuff"
|
||||||
|
|
||||||
|
override fun callScript(fnName: String, vararg arguments: Any?): Array<Any?> {
|
||||||
|
return lua.call(fnName, *arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun evalScript(code: String): Array<Any?> {
|
||||||
|
return lua.eval(code)
|
||||||
|
}
|
||||||
|
}
|
@ -318,7 +318,7 @@ class StatusController(val entity: ActorEntity, val config: StatusControllerConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deserialize(data: SerializedData) {
|
fun deserialize(data: SerializedData) {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- Persistent status effects
|
// ----- Persistent status effects
|
||||||
|
@ -549,7 +549,6 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
|
|||||||
provideEntityBindings(this, lua)
|
provideEntityBindings(this, lua)
|
||||||
provideAnimatorBindings(animator, lua)
|
provideAnimatorBindings(animator, lua)
|
||||||
lua.attach(config.value.scripts)
|
lua.attach(config.value.scripts)
|
||||||
lua.random = world.random
|
|
||||||
luaUpdate.stepCount = lookupProperty(JsonPath("scriptDelta")) { JsonPrimitive(5) }.asDouble
|
luaUpdate.stepCount = lookupProperty(JsonPath("scriptDelta")) { JsonPrimitive(5) }.asDouble
|
||||||
lua.init()
|
lua.init()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user