Some initial fixes for Lua bindings and stuff

This commit is contained in:
DBotThePony 2024-04-14 11:48:19 +07:00
parent c49c0e4393
commit 403aac63de
Signed by: DBot
GPG Key ID: DCC23B5715498507
9 changed files with 117 additions and 23 deletions

View File

@ -1,18 +1,23 @@
package ru.dbotthepony.kstarbound
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.util.KOptional
import ru.dbotthepony.kstarbound.defs.AssetReference
import ru.dbotthepony.kstarbound.defs.Json2Function
import ru.dbotthepony.kstarbound.defs.JsonConfigFunction
import ru.dbotthepony.kstarbound.defs.JsonFunction
import ru.dbotthepony.kstarbound.defs.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.item.api.IItemDefinition
import ru.dbotthepony.kstarbound.defs.item.impl.BackArmorItemDefinition
@ -36,14 +41,18 @@ import ru.dbotthepony.kstarbound.defs.dungeon.DungeonDefinition
import ru.dbotthepony.kstarbound.defs.projectile.ProjectileDefinition
import ru.dbotthepony.kstarbound.defs.quest.QuestTemplate
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.RenderParameters
import ru.dbotthepony.kstarbound.defs.tile.TileDamageConfig
import ru.dbotthepony.kstarbound.defs.tile.TileModifierDefinition
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.defs.world.BushVariant
import ru.dbotthepony.kstarbound.defs.world.GrassVariant
import ru.dbotthepony.kstarbound.defs.world.TreeVariant
import ru.dbotthepony.kstarbound.defs.world.BiomeDefinition
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.world.terrain.TerrainSelectorType
import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.world.physics.CollisionType
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
@ -156,6 +165,9 @@ object Registries {
tasks.addAll(loadRegistry(tileModifiers, fileTree["matmod"] ?: listOf(), key(TileModifierDefinition::modName, TileModifierDefinition::modId)))
tasks.addAll(loadRegistry(liquid, fileTree["liquid"] ?: listOf(), key(LiquidDefinition::name, LiquidDefinition::liquidId)))
tasks.add(loadMetaMaterials())
tasks.addAll(loadRegistry(dungeons, fileTree["dungeon"] ?: listOf(), key(DungeonDefinition::name)))
tasks.addAll(loadRegistry(worldObjects, fileTree["object"] ?: listOf(), key(ObjectDefinition::objectName)))
tasks.addAll(loadRegistry(statusEffects, fileTree["statuseffect"] ?: listOf(), key(StatusEffectDefinition::name)))
tasks.addAll(loadRegistry(species, fileTree["species"] ?: listOf(), key(Species::kind)))
@ -169,7 +181,6 @@ object Registries {
tasks.addAll(loadRegistry(treeStemVariants, fileTree["modularstem"] ?: listOf(), key(TreeVariant.StemData::name)))
tasks.addAll(loadRegistry(treeFoliageVariants, fileTree["modularfoliage"] ?: listOf(), key(TreeVariant.FoliageData::name)))
tasks.addAll(loadRegistry(bushVariants, fileTree["bush"] ?: listOf(), key(BushVariant.Data::name)))
tasks.addAll(loadRegistry(dungeons, fileTree["dungeon"] ?: listOf(), key(DungeonDefinition::name)))
tasks.addAll(loadCombined(jsonFunctions, fileTree["functions"] ?: listOf()))
tasks.addAll(loadCombined(json2Functions, fileTree["2functions"] ?: listOf()))
@ -282,4 +293,44 @@ object Registries {
return tasks
}
@JsonFactory
data class MetaMaterialDef(
val materialId: Int,
val name: String,
val collisionKind: CollisionType,
val blocksLiquidFlow: Boolean = collisionKind.isSolidCollision,
val isConnectable: Boolean = true,
val supportsMods: Boolean = false,
)
private fun loadMetaMaterials(): Future<*> {
return Starbound.EXECUTOR.submit {
val read = Starbound.loadJsonAsset("/metamaterials.config") ?: return@submit
val read2 = Starbound.gson.getAdapter(object : TypeToken<ImmutableList<MetaMaterialDef>>() {}).fromJsonTree(read)
for (def in read2) {
tiles.add {
tiles.add(key = "metamaterial:${def.name}", id = KOptional(def.materialId), value = TileDefinition(
isMeta = true,
materialId = def.materialId,
materialName = "metamaterial:${def.name}",
descriptionData = ThingDescription.EMPTY,
category = "meta",
renderTemplate = AssetReference.empty(),
renderParameters = RenderParameters.META,
isConnectable = def.isConnectable,
supportsMods = def.supportsMods,
damageTable = AssetReference(TileDamageConfig(
damageFactors = ImmutableMap.of(),
damageRecovery = Double.MAX_VALUE,
maximumEffectTime = 0.0,
totalHealth = Double.MAX_VALUE,
harvestLevel = Int.MAX_VALUE,
))
))
}
}
}
}
}

View File

@ -47,7 +47,7 @@ data class AnimatedPartsDefinition(
init {
var index = 0
for ((k, v) in states) {
for ((k, v) in sortedStates) {
v.name = k
v.index = index++

View File

@ -315,7 +315,7 @@ class Image private constructor(
if (xpixel !in 0 until width)
continue
if (!isTransparent(xpixel, ypixel, flip)) {
if (!isTransparent(xpixel, height - ypixel - 1, flip)) {
fillRatio += 1.0 / (PIXELS_IN_STARBOUND_UNIT * PIXELS_IN_STARBOUND_UNIT)
}
}

View File

@ -120,7 +120,7 @@ const val PROTECTED_ZERO_GRAVITY_DUNGEON_ID = 65524
const val FIRST_RESERVED_DUNGEON_ID = 65520
object BuiltinMetaMaterials {
private fun make(id: Int, name: String, collisionType: CollisionType, isConnectable: Boolean = true) = Registries.tiles.add(key = name, id = KOptional(id), value = TileDefinition(
private fun make(id: Int, name: String, collisionType: CollisionType, isConnectable: Boolean = true) = Registries.tiles.add(key = "metamaterial:$name", id = KOptional(id), value = TileDefinition(
materialId = id,
materialName = "metamaterial:$name",
descriptionData = ThingDescription.EMPTY,
@ -140,7 +140,7 @@ object BuiltinMetaMaterials {
))
), isBuiltin = true)
private fun makeMod(id: Int, name: String) = Registries.tileModifiers.add(key = name, id = KOptional(id), value = TileModifierDefinition(
private fun makeMod(id: Int, name: String) = Registries.tileModifiers.add(key = "metamod:$name", id = KOptional(id), value = TileModifierDefinition(
modId = id,
modName = "metamod:$name",
descriptionData = ThingDescription.EMPTY,
@ -176,7 +176,7 @@ object BuiltinMetaMaterials {
val BIOME_MOD = makeMod(65534, "biome")
val UNDERGROUND_BIOME_MOD = makeMod(65533, "underground_biome")
val NO_LIQUID = Registries.liquid.add(key = "empty", id = KOptional(0), value = LiquidDefinition(
val NO_LIQUID = Registries.liquid.add(key = "metaliquid:empty", id = KOptional(0), value = LiquidDefinition(
name = "metaliquid:empty",
liquidId = 0,
color = RGBAColor.TRANSPARENT_BLACK,

View File

@ -4,6 +4,7 @@ import com.google.gson.JsonElement
import it.unimi.dsi.fastutil.objects.ObjectIterators
import org.classdump.luna.LuaRuntimeException
import org.classdump.luna.Table
import org.classdump.luna.TableFactory
import org.classdump.luna.impl.NonsuspendableFunctionException
import org.classdump.luna.lib.ArgumentIterator
import org.classdump.luna.runtime.AbstractFunction0
@ -99,6 +100,16 @@ operator fun Table.iterator(): Iterator<Map.Entry<Any, Any>> {
}
}
fun TableFactory.tableOf(vararg values: Any?): Table {
val table = newTable(values.size, 0)
for ((i, v) in values.withIndex()) {
table[i + 1L] = v
}
return table
}
@Deprecated("Function is a stub")
fun luaStub(message: String = "not yet implemented"): LuaFunction<Any?, Any?, Any?, Any?, Any?> {
return object : LuaFunction<Any?, Any?, Any?, Any?, Any?>() {

View File

@ -242,20 +242,23 @@ class LuaEnvironment : StateContext {
return true
}
fun invokeGlobal(name: String) {
fun invokeGlobal(name: String, vararg arguments: Any?): Array<out Any?> {
if (errorState)
return
return arrayOf()
val load = globals[name]
if (load is LuaFunction<*, *, *, *, *>) {
try {
executor.call(this, load)
return try {
executor.call(this, load, *arguments)
} catch (err: Throwable) {
errorState = true
throw err
LOGGER.error("Exception while calling global $name", err)
arrayOf()
}
}
return arrayOf()
}
companion object {

View File

@ -3,8 +3,8 @@ package ru.dbotthepony.kstarbound.lua
import ru.dbotthepony.kstarbound.Starbound
class LuaUpdateComponent(val lua: LuaEnvironment) {
var stepCount = 1
private var steps = 0
var stepCount = 1.0
private var steps = 0.0
init {
val script = lua.newTable()
@ -14,15 +14,20 @@ class LuaUpdateComponent(val lua: LuaEnvironment) {
returnBuffer.setTo(stepCount * Starbound.TIMESTEP)
}
script["setUpdateDelta"] = luaFunction { ticks: Int ->
stepCount = ticks
script["setUpdateDelta"] = luaFunction { ticks: Number ->
stepCount = ticks.toDouble()
}
}
fun update() {
if (steps++ >= stepCount) {
steps = 0
lua.invokeGlobal("update")
fun update(delta: Double, vararg arguments: Any?) {
if (stepCount == 0.0)
return
steps += delta / Starbound.TIMESTEP
if (steps >= stepCount) {
steps %= stepCount
lua.invokeGlobal("update", stepCount * Starbound.TIMESTEP, *arguments)
}
}
}

View File

@ -172,7 +172,7 @@ class Animator() {
// sorted by key
// Basically, this is definition of each separate state
val states = config.states
val states = config.sortedStates
var timer = 0.0
var frame = 0
@ -192,7 +192,7 @@ class Animator() {
private var activeStateChanged = false
private var frameChanged = false
private var firstTime = true
private var firstTime = false
var activeState: AnimatedPartsDefinition.StateType.State? = null
set(value) {
@ -233,7 +233,7 @@ class Animator() {
activeState = getState
timer = 0.0
startedEvent.trigger()
firstTime = true
firstTime = false
return true
}
@ -304,6 +304,8 @@ class Animator() {
}
fun finishAnimations() {
firstTime = true
while (true) {
val active = activeState ?: break

View File

@ -11,6 +11,7 @@ import com.google.gson.JsonPrimitive
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import org.apache.logging.log4j.LogManager
import org.classdump.luna.ByteString
import org.classdump.luna.Table
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.vector.Vector2i
@ -71,7 +72,9 @@ import ru.dbotthepony.kstarbound.lua.bindings.provideWorldObjectBindings
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.toJson
import ru.dbotthepony.kstarbound.lua.toJsonFromLua
import ru.dbotthepony.kstarbound.util.asStringOrNull
import ru.dbotthepony.kstarbound.world.Direction
import ru.dbotthepony.kstarbound.world.LightCalculator
@ -412,6 +415,7 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
provideEntityBindings(this, lua)
provideAnimatorBindings(animator, lua)
lua.attach(config.value.scripts)
luaUpdate.stepCount = lookupProperty(JsonPath("scriptDelta")) { JsonPrimitive(5) }.asDouble
lua.init()
}
@ -451,6 +455,24 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
override fun interact(request: InteractRequest): InteractAction {
val diff = world.geometry.diff(request.sourcePos, position)
val result = lua.invokeGlobal("onInteraction", lua.newTable().apply {
this["source"] = lua.tableOf(diff.x, diff.y)
this["sourceId"] = request.source
})
if (result.isNotEmpty()) {
if (result[0] == null)
return InteractAction.NONE
else if (result[0] is ByteString) {
val decoded = (result[0] as ByteString).decode()
return InteractAction(InteractAction.Type.entries.firstOrNull { it.jsonName == decoded } ?: throw NoSuchElementException("Unknown interaction action type $decoded!"))
} else {
val data = result[0] as Table
val decoded = (data[1L] as ByteString).decode()
return InteractAction(InteractAction.Type.entries.firstOrNull { it.jsonName == decoded } ?: throw NoSuchElementException("Unknown interaction action type $decoded!"), 0, toJsonFromLua(data[2L]))
}
}
if (!interactAction.isJsonNull) {
return InteractAction(interactAction.asString, entityID, interactData)
}
@ -493,7 +515,7 @@ open class WorldObject(val config: Registry.Entry<ObjectDefinition>) : TileEntit
}
try {
luaUpdate.update()
luaUpdate.update(delta)
} catch (err: Throwable) {
LogManager.getLogger().error("Error running update", err)
}