Partial utility bindings
This commit is contained in:
parent
d627526088
commit
658dffc832
@ -119,6 +119,9 @@ In addition to `add`, `multiply`, `merge` and `override` new merge methods are a
|
||||
* Example: Status controller scripts now get `monster` bindings when running in context of Monster's status controller, etc
|
||||
* `behavior.behavior` third argument (specified commonly as `_ENV`) is ignored and can be omitted (set to nil)
|
||||
* It was used solely to get Lua engine (Lua execution context), and could have been deprecated long time ago even in original engine, because there is now a way in original engine to get Lua engine when binding is called
|
||||
* Added `sb.logFatal`, similar to other log functions
|
||||
* `print(...)` now prints to both console (stdout) and logs
|
||||
* `sb.log` functions now accept everything `string.format` accepts, and not only `%s` and `%%`
|
||||
|
||||
## Random
|
||||
* Added `random:randn(deviation: double, mean: double): double`, returns normally distributed double, where `deviation` stands for [Standard deviation](https://en.wikipedia.org/wiki/Standard_deviation), and `mean` specifies middle point
|
||||
|
@ -374,6 +374,14 @@ open class ItemStack(val entry: ItemRegistry.Entry, val config: JsonObject, para
|
||||
return createDescriptor().toJson()
|
||||
}
|
||||
|
||||
fun toTable(allocator: TableFactory): Table? {
|
||||
if (isEmpty) {
|
||||
return null
|
||||
}
|
||||
|
||||
return createDescriptor().toTable(allocator)
|
||||
}
|
||||
|
||||
class Adapter(gson: Gson) : TypeAdapter<ItemStack>() {
|
||||
override fun write(out: JsonWriter, value: ItemStack?) {
|
||||
val json = value?.toJson()
|
||||
|
@ -206,8 +206,8 @@ class LuaEnvironment : StateContext {
|
||||
// TODO: NYI, maybe polyfill?
|
||||
Utf8Lib.installInto(this, globals)
|
||||
|
||||
provideRootBindings(this)
|
||||
provideUtilityBindings(this)
|
||||
// provideRootBindings(this)
|
||||
// provideUtilityBindings(this)
|
||||
}
|
||||
|
||||
private val scripts = ObjectArraySet<ChunkFactory>()
|
||||
|
@ -22,6 +22,8 @@ import ru.dbotthepony.kommons.util.KOptional
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.AssetPath
|
||||
import ru.dbotthepony.kstarbound.json.InternedJsonElementAdapter
|
||||
import ru.dbotthepony.kstarbound.lua.bindings.provideRootBindings
|
||||
import ru.dbotthepony.kstarbound.lua.bindings.provideUtilityBindings
|
||||
import ru.dbotthepony.kstarbound.util.random.random
|
||||
import java.io.Closeable
|
||||
import java.lang.ref.Cleaner
|
||||
@ -71,47 +73,8 @@ class LuaThread private constructor(
|
||||
LuaJNR.INSTANCE.luaopen_utf8(this.pointer)
|
||||
this.storeGlobal("utf8")
|
||||
|
||||
push {
|
||||
LOGGER.info(it.nextString())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__print")
|
||||
|
||||
push {
|
||||
val path = it.nextString()
|
||||
|
||||
try {
|
||||
load(Starbound.readLuaScript(path).join(), "@$path")
|
||||
1
|
||||
} catch (err: Exception) {
|
||||
LOGGER.error("Exception loading Lua script $path", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
storeGlobal("__require")
|
||||
|
||||
push {
|
||||
push(random.nextDouble())
|
||||
1
|
||||
}
|
||||
|
||||
storeGlobal("__random_double")
|
||||
|
||||
push {
|
||||
push(random.nextLong(it.nextLong(), it.nextLong()))
|
||||
1
|
||||
}
|
||||
|
||||
storeGlobal("__random_long")
|
||||
|
||||
push {
|
||||
random = random(it.nextLong())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__random_seed")
|
||||
provideUtilityBindings(this)
|
||||
provideRootBindings(this)
|
||||
|
||||
load(globalScript, "@starbound.jar!/scripts/global.lua")
|
||||
call()
|
||||
@ -818,6 +781,10 @@ class LuaThread private constructor(
|
||||
return this@LuaThread.typeAt(position)
|
||||
}
|
||||
|
||||
fun hasNext(): Boolean {
|
||||
return position <= top
|
||||
}
|
||||
|
||||
fun nextString(position: Int = this.position++, limit: Long = DEFAULT_STRING_LIMIT): String {
|
||||
if (position !in 1 ..this.top)
|
||||
throw IllegalArgumentException("bad argument #$position: string expected, got nil")
|
||||
@ -851,6 +818,13 @@ class LuaThread private constructor(
|
||||
return value ?: throw IllegalArgumentException("bad argument #$position: anything expected, got ${this@LuaThread.typeAt(position)}")
|
||||
}
|
||||
|
||||
fun nextOptionalJson(position: Int = this.position++, limit: Long = DEFAULT_STRING_LIMIT): JsonElement? {
|
||||
if (position !in 1 ..this.top)
|
||||
return null
|
||||
|
||||
return this@LuaThread.getJson(position, limit = limit)
|
||||
}
|
||||
|
||||
fun nextTable(position: Int = this.position++, limit: Long = DEFAULT_STRING_LIMIT): JsonObject {
|
||||
if (position !in 1 ..this.top)
|
||||
throw IllegalArgumentException("bad argument #$position: table expected, got nil")
|
||||
|
@ -1,25 +1,27 @@
|
||||
package ru.dbotthepony.kstarbound.lua.bindings
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import com.google.gson.JsonNull
|
||||
import org.classdump.luna.ByteString
|
||||
import org.classdump.luna.Table
|
||||
import org.classdump.luna.runtime.ExecutionContext
|
||||
import ru.dbotthepony.kommons.util.XXHash32
|
||||
import ru.dbotthepony.kommons.util.XXHash64
|
||||
import ru.dbotthepony.kstarbound.math.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.defs.PerlinNoiseParameters
|
||||
import ru.dbotthepony.kstarbound.json.JsonPath
|
||||
import ru.dbotthepony.kstarbound.lua.LuaEnvironment
|
||||
import ru.dbotthepony.kstarbound.lua.LuaThread
|
||||
import ru.dbotthepony.kstarbound.lua.LuaThread.Companion
|
||||
import ru.dbotthepony.kstarbound.lua.LuaType
|
||||
import ru.dbotthepony.kstarbound.lua.from
|
||||
import ru.dbotthepony.kstarbound.lua.get
|
||||
import ru.dbotthepony.kstarbound.lua.luaFunction
|
||||
import ru.dbotthepony.kstarbound.lua.luaFunctionArray
|
||||
import ru.dbotthepony.kstarbound.lua.luaFunctionN
|
||||
import ru.dbotthepony.kstarbound.lua.nextOptionalFloat
|
||||
import ru.dbotthepony.kstarbound.lua.set
|
||||
import ru.dbotthepony.kstarbound.lua.toByteString
|
||||
import ru.dbotthepony.kstarbound.lua.toJson
|
||||
import ru.dbotthepony.kstarbound.lua.toJsonFromLua
|
||||
import ru.dbotthepony.kstarbound.lua.toVector2d
|
||||
import ru.dbotthepony.kstarbound.lua.userdata.LuaPerlinNoise
|
||||
import ru.dbotthepony.kstarbound.lua.userdata.LuaRandomGenerator
|
||||
@ -28,26 +30,17 @@ import ru.dbotthepony.kstarbound.util.SBPattern
|
||||
import ru.dbotthepony.kstarbound.util.random.AbstractPerlinNoise
|
||||
import ru.dbotthepony.kstarbound.util.random.nextNormalDouble
|
||||
import ru.dbotthepony.kstarbound.util.random.random
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandom32
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandom32FromList
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandom64FromList
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandomDouble
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandomDoubleFromList
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandomIntFromList
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandomLong
|
||||
import ru.dbotthepony.kstarbound.util.random.staticRandomLongFromList
|
||||
import ru.dbotthepony.kstarbound.util.random.toBytes
|
||||
import ru.dbotthepony.kstarbound.util.toStarboundString
|
||||
import java.util.*
|
||||
import java.util.random.RandomGenerator
|
||||
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
|
||||
private val logInfo = luaFunctionN("logInfo") { args ->
|
||||
LOGGER.info(args.nextString().toString().format(*args.copyRemaining()))
|
||||
}
|
||||
|
||||
private val logWarn = luaFunctionN("logWarn") { args ->
|
||||
LOGGER.warn(args.nextString().toString().format(*args.copyRemaining()))
|
||||
}
|
||||
|
||||
private val logError = luaFunctionN("logError") { args ->
|
||||
LOGGER.error(args.nextString().toString().format(*args.copyRemaining()))
|
||||
}
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
private val interpolateSinEase = luaFunctionArray { args ->
|
||||
if (args.size < 3)
|
||||
@ -71,75 +64,224 @@ private val interpolateSinEase = luaFunctionArray { args ->
|
||||
}
|
||||
}
|
||||
|
||||
private val replaceTags = luaFunction { string: ByteString, tags: Table ->
|
||||
returnBuffer.setTo(SBPattern.of(string.toString()).resolveOrSkip({ tags[it]?.toString() }).toByteString())
|
||||
// TODO: Lua-side implementation for better performance?
|
||||
private fun replaceTags(args: LuaThread.ArgStack): Int {
|
||||
val string = args.nextString()
|
||||
val tagsList = args.lua
|
||||
.readTable(
|
||||
args.position++,
|
||||
{ getString(it) ?: throw IllegalStateException("Tags table contain non-string keys") },
|
||||
{ getString(it) ?: throw IllegalStateException("Tags table contain non-string values") }
|
||||
) ?: throw IllegalArgumentException("bad argument #2: table expected, got ${args.peek(args.position - 1)}")
|
||||
|
||||
val tags = tagsList.toMap()
|
||||
|
||||
args.lua.push(SBPattern.of(string).resolveOrSkip({ tags[it] }))
|
||||
return 1
|
||||
}
|
||||
|
||||
private val makePerlinSource = luaFunction { settings: Table ->
|
||||
returnBuffer.setTo(LuaPerlinNoise(AbstractPerlinNoise.of(Starbound.gson.fromJson(settings.toJson(), PerlinNoiseParameters::class.java))))
|
||||
}
|
||||
|
||||
private val staticRandomI32 = luaFunctionArray {
|
||||
returnBuffer.setTo(staticRandom32(*it))
|
||||
private fun hash32(args: LuaThread.ArgStack): Int {
|
||||
val digest = XXHash32(2938728349.toInt())
|
||||
|
||||
while (args.hasNext()) {
|
||||
when (args.peek()) {
|
||||
LuaType.BOOLEAN -> digest.update(if (args.nextBoolean()) 1 else 0)
|
||||
LuaType.NUMBER -> toBytes(digest::update, args.nextDouble())
|
||||
LuaType.STRING -> digest.update(args.nextString().toByteArray(Charsets.UTF_8))
|
||||
else -> throw IllegalArgumentException("bad argument #${args.position} to staticRandomI32")
|
||||
}
|
||||
}
|
||||
|
||||
private val staticRandomDouble = luaFunctionArray {
|
||||
returnBuffer.setTo(staticRandomDouble(*it))
|
||||
return digest.digestAsInt()
|
||||
}
|
||||
|
||||
private val staticRandomDoubleRange = luaFunctionN("staticRandomDoubleRange") {
|
||||
val min = it.nextFloat()
|
||||
val max = it.nextFloat()
|
||||
returnBuffer.setTo(staticRandomDouble(*it.copyRemaining()) * (max - min) + min)
|
||||
private fun hash64(args: LuaThread.ArgStack): Long {
|
||||
val digest = XXHash64(1997293021376312589L)
|
||||
|
||||
while (args.hasNext()) {
|
||||
when (args.peek()) {
|
||||
LuaType.BOOLEAN -> digest.update(if (args.nextBoolean()) 1 else 0)
|
||||
LuaType.NUMBER -> toBytes(digest::update, args.nextDouble())
|
||||
LuaType.STRING -> digest.update(args.nextString().toByteArray(Charsets.UTF_8))
|
||||
else -> throw IllegalArgumentException("bad argument #${args.position} to staticRandomI32")
|
||||
}
|
||||
}
|
||||
|
||||
private val staticRandomI32Range = luaFunctionN("staticRandomI32Range") {
|
||||
val min = it.nextInteger()
|
||||
val max = it.nextInteger()
|
||||
returnBuffer.setTo(staticRandomLong(min, max, *it.copyRemaining()))
|
||||
return digest.digestAsLong()
|
||||
}
|
||||
|
||||
private val mergeJson = luaFunction { a: Any?, b: Any? ->
|
||||
returnBuffer.setTo(from(ru.dbotthepony.kstarbound.json.mergeJson(toJsonFromLua(a), toJsonFromLua(b))))
|
||||
private fun staticRandomI32(args: LuaThread.ArgStack): Int {
|
||||
args.lua.push(hash32(args).toLong())
|
||||
return 1
|
||||
}
|
||||
|
||||
fun provideUtilityBindings(lua: LuaEnvironment) {
|
||||
val table = lua.newTable()
|
||||
lua.globals["sb"] = table
|
||||
|
||||
table["makeUuid"] = luaFunction {
|
||||
returnBuffer.setTo(UUID(lua.random.nextLong(), lua.random.nextLong()).toStarboundString().toByteString())
|
||||
private fun staticRandomI64(args: LuaThread.ArgStack): Int {
|
||||
args.lua.push(hash64(args))
|
||||
return 1
|
||||
}
|
||||
|
||||
table["logInfo"] = logInfo
|
||||
table["logWarn"] = logWarn
|
||||
table["logError"] = logError
|
||||
|
||||
table["nrand"] = luaFunctionN("nrand") { args ->
|
||||
val stdev = args.nextOptionalFloat() ?: 1.0
|
||||
val mean = args.nextOptionalFloat() ?: 0.0
|
||||
lua.random.nextNormalDouble(stdev, mean)
|
||||
private fun staticRandomDouble(args: LuaThread.ArgStack): Int {
|
||||
args.lua.push(hash64(args).ushr(11) * 1.1102230246251565E-16)
|
||||
return 1
|
||||
}
|
||||
|
||||
table["print"] = lua.globals["tostring"]
|
||||
private fun staticRandomDoubleRange(args: LuaThread.ArgStack): Int {
|
||||
val min = args.nextDouble()
|
||||
val max = args.nextDouble()
|
||||
val double = hash64(args).ushr(11) * 1.1102230246251565E-16
|
||||
args.lua.push(double * (max - min) + min)
|
||||
return 1
|
||||
}
|
||||
|
||||
// FIXME: incorrect.
|
||||
private fun staticRandomI64Range(args: LuaThread.ArgStack): Int {
|
||||
val min = args.nextDouble()
|
||||
val max = args.nextDouble()
|
||||
val double = hash64(args).ushr(11) * 1.1102230246251565E-16
|
||||
args.lua.push((min + (max - min + 1L) * double).toLong())
|
||||
return 1
|
||||
}
|
||||
|
||||
// FIXME: incorrect.
|
||||
private fun staticRandomI32Range(args: LuaThread.ArgStack): Int {
|
||||
val min = args.nextDouble()
|
||||
val max = args.nextDouble()
|
||||
val double = hash64(args).ushr(11) * 1.1102230246251565E-16
|
||||
args.lua.push((min + (max - min + 1L) * double).toInt().toLong())
|
||||
return 1
|
||||
}
|
||||
|
||||
// TODO: Lua-side implementation for better performance?
|
||||
private fun makeUuid(args: LuaThread.ArgStack): Int {
|
||||
args.lua.push(UUID(args.lua.random.nextLong(), args.lua.random.nextLong()).toStarboundString())
|
||||
return 1
|
||||
}
|
||||
|
||||
private fun nrand(args: LuaThread.ArgStack): Int {
|
||||
val stdev = args.nextOptionalDouble() ?: 1.0
|
||||
val mean = args.nextOptionalDouble() ?: 0.0
|
||||
args.lua.push(args.lua.random.nextNormalDouble(stdev, mean))
|
||||
return 1
|
||||
}
|
||||
|
||||
// TODO: Lua-side implementation for better performance?
|
||||
private fun jsonMerge(args: LuaThread.ArgStack): Int {
|
||||
val a = args.nextOptionalJson() ?: JsonNull.INSTANCE
|
||||
val b = args.nextOptionalJson() ?: JsonNull.INSTANCE
|
||||
|
||||
args.lua.push(ru.dbotthepony.kstarbound.json.mergeJson(a, b))
|
||||
return 1
|
||||
}
|
||||
|
||||
// TODO: Lua-side implementation for better performance?
|
||||
private fun jsonQuery(args: LuaThread.ArgStack): Int {
|
||||
val json = args.nextOptionalJson() ?: JsonNull.INSTANCE
|
||||
val path = args.nextString()
|
||||
val default = args.nextOptionalJson() ?: JsonNull.INSTANCE
|
||||
|
||||
args.lua.push(JsonPath.query(path).get(json, default))
|
||||
return 1
|
||||
}
|
||||
|
||||
fun provideUtilityBindings(lua: LuaThread) {
|
||||
with(lua) {
|
||||
push {
|
||||
LuaThread.LOGGER.info(it.nextString())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__print")
|
||||
|
||||
push {
|
||||
LuaThread.LOGGER.warn(it.nextString())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__print_warn")
|
||||
|
||||
push {
|
||||
LuaThread.LOGGER.error(it.nextString())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__print_error")
|
||||
|
||||
push {
|
||||
LuaThread.LOGGER.fatal(it.nextString())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__print_fatal")
|
||||
|
||||
push {
|
||||
val path = it.nextString()
|
||||
|
||||
try {
|
||||
load(Starbound.readLuaScript(path).join(), "@$path")
|
||||
1
|
||||
} catch (err: Exception) {
|
||||
LuaThread.LOGGER.error("Exception loading Lua script $path", err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
storeGlobal("__require")
|
||||
|
||||
push {
|
||||
push(random.nextDouble())
|
||||
1
|
||||
}
|
||||
|
||||
storeGlobal("__random_double")
|
||||
|
||||
push {
|
||||
push(random.nextLong(it.nextLong(), it.nextLong()))
|
||||
1
|
||||
}
|
||||
|
||||
storeGlobal("__random_long")
|
||||
|
||||
push {
|
||||
random = random(it.nextLong())
|
||||
0
|
||||
}
|
||||
|
||||
storeGlobal("__random_seed")
|
||||
}
|
||||
|
||||
lua.pushTable()
|
||||
lua.dup()
|
||||
lua.storeGlobal("sb")
|
||||
|
||||
lua.setTableValue("makeUuid", ::makeUuid)
|
||||
lua.setTableValue("nrand", ::nrand)
|
||||
lua.setTableValue("jsonMerge", ::jsonMerge)
|
||||
lua.setTableValue("jsonQuery", ::jsonQuery)
|
||||
|
||||
lua.setTableValue("replaceTags", ::replaceTags)
|
||||
|
||||
lua.setTableValue("staticRandomI32", ::staticRandomI32)
|
||||
lua.setTableValue("staticRandomI32Range", ::staticRandomI32Range)
|
||||
lua.setTableValue("staticRandomI64", ::staticRandomI64)
|
||||
lua.setTableValue("staticRandomI64Range", ::staticRandomI64Range)
|
||||
lua.setTableValue("staticRandomDouble", ::staticRandomDouble)
|
||||
lua.setTableValue("staticRandomDoubleRange", ::staticRandomDoubleRange)
|
||||
|
||||
/*table["print"] = lua.globals["tostring"]
|
||||
table["printJson"] = lua.globals["tostring"]
|
||||
table["interpolateSinEase"] = interpolateSinEase
|
||||
table["replaceTags"] = replaceTags
|
||||
table["makeRandomSource"] = luaFunction { seed: Long? ->
|
||||
returnBuffer.setTo(LuaRandomGenerator(random(seed ?: lua.random.nextLong())))
|
||||
}
|
||||
|
||||
table["makePerlinSource"] = makePerlinSource
|
||||
table["makePerlinSource"] = makePerlinSource*/
|
||||
|
||||
table["staticRandomI32"] = staticRandomI32
|
||||
table["staticRandomI64"] = staticRandomI32
|
||||
table["staticRandomDouble"] = staticRandomDouble
|
||||
lua.pop()
|
||||
|
||||
table["staticRandomDoubleRange"] = staticRandomDoubleRange
|
||||
table["staticRandomI32Range"] = staticRandomI32Range
|
||||
table["staticRandomI64Range"] = staticRandomI32Range
|
||||
|
||||
table["jsonMerge"] = mergeJson
|
||||
}
|
||||
|
||||
fun provideConfigBindings(lua: LuaEnvironment, lookup: ExecutionContext.(path: JsonPath, ifMissing: Any?) -> Any?) {
|
||||
|
@ -35,19 +35,19 @@ fun random(seed: Long = System.nanoTime()): RandomGenerator {
|
||||
*/
|
||||
val threadLocalRandom: RandomGenerator by ThreadLocal.withInitial { random() }
|
||||
|
||||
private fun toBytes(accept: ByteConsumer, value: Short) {
|
||||
fun toBytes(accept: ByteConsumer, value: Short) {
|
||||
accept.accept(value.toByte())
|
||||
accept.accept((value.toInt() ushr 8).toByte())
|
||||
}
|
||||
|
||||
private fun toBytes(accept: ByteConsumer, value: Int) {
|
||||
fun toBytes(accept: ByteConsumer, value: Int) {
|
||||
accept.accept(value.toByte())
|
||||
accept.accept((value ushr 8).toByte())
|
||||
accept.accept((value ushr 16).toByte())
|
||||
accept.accept((value ushr 24).toByte())
|
||||
}
|
||||
|
||||
private fun toBytes(accept: ByteConsumer, value: Long) {
|
||||
fun toBytes(accept: ByteConsumer, value: Long) {
|
||||
accept.accept(value.toByte())
|
||||
accept.accept((value ushr 8).toByte())
|
||||
accept.accept((value ushr 16).toByte())
|
||||
@ -58,15 +58,19 @@ private fun toBytes(accept: ByteConsumer, value: Long) {
|
||||
accept.accept((value ushr 56).toByte())
|
||||
}
|
||||
|
||||
private fun toBytes(accept: ByteConsumer, value: Double) {
|
||||
fun toBytes(accept: ByteConsumer, value: Double) {
|
||||
toBytes(accept, value.toBits())
|
||||
}
|
||||
|
||||
private fun toBytes(accept: ByteConsumer, value: Float) {
|
||||
fun toBytes(accept: ByteConsumer, value: Float) {
|
||||
toBytes(accept, value.toBits())
|
||||
}
|
||||
|
||||
fun staticRandom32(vararg values: Any?): Int {
|
||||
return staticRandom32FromList(values.asIterable())
|
||||
}
|
||||
|
||||
fun staticRandom32FromList(values: Iterable<Any?>): Int {
|
||||
val digest = XXHash32(2938728349.toInt())
|
||||
|
||||
for (value in values) {
|
||||
@ -96,6 +100,10 @@ fun staticRandomDouble(vararg values: Any?): Double {
|
||||
return staticRandom64(*values).ushr(11) * 1.1102230246251565E-16
|
||||
}
|
||||
|
||||
fun staticRandomDoubleFromList(values: Iterable<Any?>): Double {
|
||||
return staticRandom64FromList(values).ushr(11) * 1.1102230246251565E-16
|
||||
}
|
||||
|
||||
fun staticRandomInt(min: Int, max: Int, vararg values: Any?): Int {
|
||||
val hash = staticRandomDouble(*values)
|
||||
return (min + (max - min + 1) * hash).toInt()
|
||||
@ -106,7 +114,21 @@ fun staticRandomLong(min: Long, max: Long, vararg values: Any?): Long {
|
||||
return (min + (max - min + 1L) * hash).toLong()
|
||||
}
|
||||
|
||||
fun staticRandomIntFromList(min: Int, max: Int, values: Iterable<Any?>): Int {
|
||||
val hash = staticRandomDoubleFromList(values)
|
||||
return (min + (max - min + 1) * hash).toInt()
|
||||
}
|
||||
|
||||
fun staticRandomLongFromList(min: Long, max: Long, values: Iterable<Any?>): Long {
|
||||
val hash = staticRandomDoubleFromList(values)
|
||||
return (min + (max - min + 1L) * hash).toLong()
|
||||
}
|
||||
|
||||
fun staticRandom64(vararg values: Any?): Long {
|
||||
return staticRandom64FromList(values.asIterable())
|
||||
}
|
||||
|
||||
fun staticRandom64FromList(values: Iterable<Any?>): Long {
|
||||
val digest = XXHash64(1997293021376312589L)
|
||||
|
||||
for (value in values) {
|
||||
|
@ -147,6 +147,10 @@ end
|
||||
|
||||
do
|
||||
local __print = __print
|
||||
local __print_warn = __print_warn
|
||||
local __print_error = __print_error
|
||||
local __print_fatal = __print_fatal
|
||||
local format = string.format
|
||||
|
||||
function print(...)
|
||||
local values = {}
|
||||
@ -158,6 +162,22 @@ do
|
||||
|
||||
__print(table.concat(values, '\t'))
|
||||
end
|
||||
|
||||
function sb.logInfo(text, ...)
|
||||
__print(format(text, ...))
|
||||
end
|
||||
|
||||
function sb.logWarn(text, ...)
|
||||
__print_warn(format(text, ...))
|
||||
end
|
||||
|
||||
function sb.logError(text, ...)
|
||||
__print_error(format(text, ...))
|
||||
end
|
||||
|
||||
function sb.logFatal(text, ...)
|
||||
__print_fatal(format(text, ...))
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
@ -258,3 +278,5 @@ do
|
||||
__random_seed(floor(seed))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user