From 3b454374ec340c98e85ed7f56bdd259429ce1870 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 12 Dec 2024 22:29:54 +0700 Subject: [PATCH] Stagehands, they don't work because of Luna (: --- .../kotlin/ru/dbotthepony/kstarbound/Ext.kt | 1 + .../ru/dbotthepony/kstarbound/Registries.kt | 28 ++++ .../dbotthepony/kstarbound/defs/EntityType.kt | 5 +- .../kstarbound/lua/bindings/WorldBindings.kt | 87 ++++++++-- .../lua/bindings/WorldEntityBindings.kt | 48 +++--- .../kstarbound/server/ServerConnection.kt | 2 +- .../ru/dbotthepony/kstarbound/world/World.kt | 2 + .../world/entities/ItemDropEntity.kt | 5 +- .../world/entities/StagehandEntity.kt | 152 ++++++++++++++++++ .../world/entities/StatusController.kt | 2 +- .../world/entities/tile/WorldObject.kt | 1 - 11 files changed, 293 insertions(+), 40 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/StagehandEntity.kt diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Ext.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Ext.kt index f67be762..99d9deea 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Ext.kt @@ -50,6 +50,7 @@ operator fun ImmutableMap.Builder.set(key: K, value: V) inline fun Gson.fromJson(reader: JsonReader): T? = fromJson(reader, T::class.java) inline fun Gson.fromJson(reader: JsonElement): T? = getAdapter(T::class.java).read(FastJsonTreeReader(reader)) +// TODO: mark these nullable fun Gson.fromJsonFast(reader: JsonElement, type: Class): T = getAdapter(type).read(FastJsonTreeReader(reader)) fun Gson.fromJsonFast(reader: JsonElement, type: TypeToken): T = getAdapter(type).read(FastJsonTreeReader(reader)) inline fun Gson.fromJsonFast(reader: JsonElement): T = getAdapter(object : TypeToken() {}).read(FastJsonTreeReader(reader)) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt index af2e067f..f194cd2d 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Registries.kt @@ -117,6 +117,33 @@ object Registries { private val monsterParts = HashMap, HashMap>>() private val loggedMonsterPartMisses = Collections.synchronizedSet(ObjectOpenHashSet>()) + private val stagehands = HashMap>() + + 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, patches: Map>): List> { + 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? { val key = category to type @@ -275,6 +302,7 @@ object Registries { tasks.addAll(loadRegistry(dungeons, patchTree, fileTree["dungeon"] ?: listOf(), key(DungeonDefinition::name))) 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(monsterTypes, patchTree, fileTree["monstertype"] ?: listOf(), key(MonsterTypeDefinition::type))) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/EntityType.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/EntityType.kt index 0692eece..2cb0d049 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/EntityType.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/EntityType.kt @@ -16,6 +16,7 @@ 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.ProjectileEntity +import ru.dbotthepony.kstarbound.world.entities.StagehandEntity import ru.dbotthepony.kstarbound.world.entities.player.PlayerEntity import ru.dbotthepony.kstarbound.world.entities.tile.ContainerObject 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) { override suspend fun fromNetwork(stream: DataInputStream, isLegacy: Boolean): AbstractEntity { - TODO("STAGEHAND") + return StagehandEntity(stream, isLegacy) } override fun fromStorage(data: JsonObject): AbstractEntity { - TODO("STAGEHAND") + return StagehandEntity(data) } }, diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldBindings.kt index 4f754d34..aca02d62 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldBindings.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.kstarbound.lua.bindings import com.google.gson.JsonObject import it.unimi.dsi.fastutil.ints.IntArrayList import it.unimi.dsi.fastutil.objects.ObjectArrayList +import kotlinx.coroutines.runBlocking import org.apache.logging.log4j.LogManager import org.classdump.luna.ByteString import org.classdump.luna.LuaRuntimeException @@ -11,17 +12,22 @@ import org.classdump.luna.runtime.ExecutionContext import org.classdump.luna.runtime.LuaFunction import ru.dbotthepony.kommons.collect.map 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.Starbound import ru.dbotthepony.kstarbound.defs.ActorMovementParameters 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.monster.MonsterVariant import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyLiquid import ru.dbotthepony.kstarbound.defs.tile.isNotEmptyTile import ru.dbotthepony.kstarbound.defs.world.TerrestrialWorldParameters import ru.dbotthepony.kstarbound.fromJsonFast import ru.dbotthepony.kstarbound.json.builder.IStringSerializable +import ru.dbotthepony.kstarbound.json.mergeJson import ru.dbotthepony.kstarbound.math.vector.Vector2d import ru.dbotthepony.kstarbound.lua.LuaEnvironment 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.entities.AbstractEntity 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.StagehandEntity import ru.dbotthepony.kstarbound.world.entities.api.ScriptedEntity import ru.dbotthepony.kstarbound.world.entities.tile.WorldObject 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) returnBuffer.setTo() } else { - val create = ItemDropEntity(descriptor) + val create = ItemDropEntity(descriptor, lua.random) create.movement.velocity = initialVelocity if (intangibleTime is Number) { @@ -453,8 +462,7 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) { val items = Registries.treasurePools .getOrThrow(pool.decode()) .value - // not using lua.random because we are, well, world's bindings - .evaluate(if (seed != null) random(seed.toLong()) else self.random, level.toDouble()) + .evaluate(if (seed != null) random(seed.toLong()) else lua.random, level.toDouble()) val pos = toVector2d(position) @@ -465,18 +473,79 @@ fun provideWorldBindings(self: World<*, *>, lua: LuaEnvironment) { entities.add(entity.entityID) } } 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())) } - callbacks["spawnMonster"] = luaFunction { - // TODO - returnBuffer.setTo(0L) + callbacks["spawnMonster"] = luaFunction { type: ByteString, position: Table, overrides: Any? -> + try { + val parameters = JsonObject() + parameters["aggressive"] = lua.random.nextBoolean() + + if (overrides != null) { + mergeJson(parameters, toJsonFromLua(overrides)) + } + + 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"] = luaStub("spawnNpc") - callbacks["spawnStagehand"] = luaStub("spawnStagehand") + + 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["spawnVehicle"] = luaStub("spawnVehicle") diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt index 78ee210a..fd1e1c42 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/WorldEntityBindings.kt @@ -72,7 +72,7 @@ private val centerStr = ByteString.of("center") private val boundModeStr = ByteString.of("boundMode") private val orderStr = ByteString.of("order") -private fun ExecutionContext.entityQueryImpl(self: World<*, *>, options: Table, predicate: Predicate = Predicate { true }): Table { +private fun ExecutionContext.entityQueryImpl(self: World<*, *>, lua: LuaEnvironment, options: Table, predicate: Predicate = Predicate { true }): Table { val withoutEntityId = (indexNoYield(options, withoutEntityIdStr) as Number?)?.toInt() 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()) { null -> {} // do nothing - "random" -> entitites.shuffle(self.random) + "random" -> entitites.shuffle(lua.random) "nearest" -> { 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()) } -private fun ExecutionContext.intermediateQueryFunction(self: World<*, *>, pos1: Table, pos2OrRadius: Any, options: Table?, predicate: Predicate) { +private fun ExecutionContext.intermediateQueryFunction(self: World<*, *>, lua: LuaEnvironment, pos1: Table, pos2OrRadius: Any, options: Table?, predicate: Predicate) { val actualOptions = options ?: tableOf() 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]) } - 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) { +private fun ExecutionContext.intermediateLineQueryFunction(self: World<*, *>, lua: LuaEnvironment, pos1: Table, pos2: Table, options: Table?, predicate: Predicate) { val actualOptions = options ?: tableOf() actualOptions[lineStr] = tableOf(pos1, pos2) - returnBuffer.setTo(entityQueryImpl(self, actualOptions, predicate)) + returnBuffer.setTo(entityQueryImpl(self, lua, actualOptions, predicate)) } -private inline fun createQueryFunction(self: World<*, *>) = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? -> - intermediateQueryFunction(self, pos1, pos2OrRadius, options, Predicate { it is T }) +private inline fun createQueryFunction(self: World<*, *>, lua: LuaEnvironment) = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? -> + intermediateQueryFunction(self, lua, pos1, pos2OrRadius, options, Predicate { it is T }) } -private inline fun createLineQueryFunction(self: World<*, *>) = luaFunction { pos1: Table, pos2: Table, options: Table? -> - intermediateLineQueryFunction(self, pos1, pos2, options, Predicate { it is T }) +private inline fun createLineQueryFunction(self: World<*, *>, lua: LuaEnvironment) = luaFunction { pos1: Table, pos2: Table, options: Table? -> + intermediateLineQueryFunction(self, lua, pos1, pos2, options, Predicate { it is T }) } fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEnvironment) { - callbacks["entityQuery"] = createQueryFunction(self) - callbacks["monsterQuery"] = createQueryFunction(self) // TODO - callbacks["npcQuery"] = createQueryFunction(self) // TODO - callbacks["itemDropQuery"] = createQueryFunction(self) - callbacks["playerQuery"] = createQueryFunction(self) + callbacks["entityQuery"] = createQueryFunction(self, lua) + callbacks["monsterQuery"] = createQueryFunction(self, lua) // TODO + callbacks["npcQuery"] = createQueryFunction(self, lua) // TODO + callbacks["itemDropQuery"] = createQueryFunction(self, lua) + callbacks["playerQuery"] = createQueryFunction(self, lua) - callbacks["entityLineQuery"] = createLineQueryFunction(self) - callbacks["monsterLineQuery"] = createLineQueryFunction(self) // TODO - callbacks["npcLineQuery"] = createLineQueryFunction(self) // TODO - callbacks["itemDropLineQuery"] = createLineQueryFunction(self) - callbacks["playerLineQuery"] = createLineQueryFunction(self) + callbacks["entityLineQuery"] = createLineQueryFunction(self, lua) + callbacks["monsterLineQuery"] = createLineQueryFunction(self, lua) // TODO + callbacks["npcLineQuery"] = createLineQueryFunction(self, lua) // TODO + callbacks["itemDropLineQuery"] = createLineQueryFunction(self, lua) + callbacks["playerLineQuery"] = createLineQueryFunction(self, lua) callbacks["objectQuery"] = luaFunction { pos1: Table, pos2OrRadius: Any, options: Table? -> var objectName: String? = null @@ -260,7 +260,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn if (options != null) 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) }) } @@ -271,7 +271,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn if (options != null) 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) }) } @@ -287,7 +287,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn 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) }) } @@ -303,7 +303,7 @@ fun provideWorldEntitiesBindings(self: World<*, *>, callbacks: Table, lua: LuaEn 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) }) } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt index 28f879ec..9bde92e0 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/server/ServerConnection.kt @@ -748,7 +748,7 @@ class ServerConnection(val server: StarboundServer, type: ConnectionType) : Conn enqueueWarp(WarpAlias.OwnShip) } - //enqueueWarp(WarpAction.World(WorldID.Instance("outpost"))) + enqueueWarp(WarpAction.World(WorldID.Instance("outpost"))) scope.launch { shipFlightEventLoop(context.shipCoordinate, context.systemLocation) } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt index d63c0b9e..95368db3 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/World.kt @@ -670,6 +670,8 @@ abstract class World, ChunkType : Chunk 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 { + return lua.call(fnName, *arguments) + } + + override fun evalScript(code: String): Array { + return lua.eval(code) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/StatusController.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/StatusController.kt index 01695feb..7f2b21ae 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/StatusController.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/StatusController.kt @@ -318,7 +318,7 @@ class StatusController(val entity: ActorEntity, val config: StatusControllerConf } fun deserialize(data: SerializedData) { - + // TODO } // ----- Persistent status effects diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/WorldObject.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/WorldObject.kt index d6cbead4..6537a91a 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/WorldObject.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/tile/WorldObject.kt @@ -549,7 +549,6 @@ open class WorldObject(val config: Registry.Entry) : TileEntit provideEntityBindings(this, lua) provideAnimatorBindings(animator, lua) lua.attach(config.value.scripts) - lua.random = world.random luaUpdate.stepCount = lookupProperty(JsonPath("scriptDelta")) { JsonPrimitive(5) }.asDouble lua.init() }