diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt index d6c8b86d..321cb6c5 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt @@ -67,8 +67,11 @@ import ru.dbotthepony.kstarbound.io.json.factory.ImmutableCollectionAdapterFacto import ru.dbotthepony.kstarbound.lua.LuaState import ru.dbotthepony.kstarbound.lua.loadInternalScript import ru.dbotthepony.kstarbound.math.* +import ru.dbotthepony.kstarbound.util.ITimeSource import ru.dbotthepony.kstarbound.util.ItemStack +import ru.dbotthepony.kstarbound.util.JVMTimeSource import ru.dbotthepony.kstarbound.util.PathStack +import ru.dbotthepony.kstarbound.util.PausableTimeSource import ru.dbotthepony.kstarbound.util.SBPattern import ru.dbotthepony.kstarbound.util.WriteOnce import ru.dbotthepony.kstarbound.util.filterNotNull @@ -88,6 +91,8 @@ import java.util.function.Supplier import java.util.stream.Collector import kotlin.NoSuchElementException import kotlin.collections.ArrayList +import kotlin.random.Random +import kotlin.random.nextInt class Starbound : ISBFileLocator { private val logger = LogManager.getLogger() @@ -361,7 +366,11 @@ class Starbound : ISBFileLocator { return Vector2i(image.width, image.height) } - fun pushLuaAPI(state: LuaState) { + /** + * **ПРЕДУПРЕЖДЕНИЕ:** + * [time] не должен иметь ссылок (прямые или непрямые) на [state], иначе произойдёт утечка памяти! + */ + fun pushLuaAPI(state: LuaState, time: ITimeSource = JVMTimeSource.INSTANCE) { state.pushWeak(this) { args -> luaRequire(args.lua, args) 0 @@ -563,6 +572,42 @@ class Starbound : ISBFileLocator { 1 } + state.setTableFunction("generateName", this) { args -> + val assetName = args.getString() + val seed = if (args.hasSomethingAt()) args.getLong() else time.nanos + val names = loadJsonAsset(assetName) ?: throw NoSuchElementException("No such JSON asset $assetName") + + if (names !is JsonArray) { + var possibleName: String? = null + + if (names is JsonObject) { + for ((k, v) in names.entrySet()) { + if (v is JsonArray && !v.isEmpty) { + if (possibleName == null || (names[possibleName] as JsonArray).size() < v.size()) + possibleName = k + } + } + } + + if (possibleName != null) { + if (assetName.contains(':')) { + throw IllegalArgumentException("JSON asset $assetName is not an array, did you mean $assetName.$possibleName?") + } else { + throw IllegalArgumentException("JSON asset $assetName is not an array, did you mean $assetName:$possibleName?") + } + } else { + throw IllegalArgumentException("JSON asset $assetName is not an array") + } + } + + if (names.isEmpty) { + throw IllegalStateException("JSON array $assetName is empty") + } + + args.push(names[Random(seed).nextInt(0, names.size())]) + 1 + } + state.pop() state.load(polyfill, "@starbound.jar!/scripts/polyfill.lua")