mirror of
https://github.com/BigJk/end_of_eden.git
synced 2026-02-06 10:48:09 +00:00
164 lines
3.8 KiB
Go
164 lines
3.8 KiB
Go
package luhelp
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/fatih/structs"
|
|
"github.com/gobeam/stringy"
|
|
"github.com/samber/lo"
|
|
"github.com/sanity-io/litter"
|
|
lua "github.com/yuin/gopher-lua"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
const LuaTag = "lua"
|
|
|
|
func baseToLua(val any) lua.LValue {
|
|
switch val := val.(type) {
|
|
case float64:
|
|
return lua.LNumber(val)
|
|
case float32:
|
|
return lua.LNumber(val)
|
|
case int:
|
|
return lua.LNumber(val)
|
|
case int64:
|
|
return lua.LNumber(val)
|
|
case string:
|
|
return lua.LString(val)
|
|
case bool:
|
|
return lua.LBool(val)
|
|
}
|
|
return lua.LNil
|
|
}
|
|
|
|
var intType = reflect.TypeOf(int(0))
|
|
|
|
// ToLua converts a go value to a lua value.
|
|
func ToLua(state *lua.LState, val any) lua.LValue {
|
|
if val == nil {
|
|
return lua.LNil
|
|
}
|
|
valType := reflect.TypeOf(val)
|
|
|
|
switch valType.Kind() {
|
|
case reflect.Pointer:
|
|
valValue := reflect.ValueOf(val)
|
|
if valValue.IsNil() {
|
|
return lua.LNil
|
|
}
|
|
return ToLua(state, valValue.Elem().Interface())
|
|
case reflect.Struct:
|
|
s := structs.New(val)
|
|
s.TagName = LuaTag
|
|
return ToLua(state, s.Map())
|
|
case reflect.Map:
|
|
resultTable := state.NewTable()
|
|
valValue := reflect.ValueOf(val)
|
|
keys := valValue.MapKeys()
|
|
for i := range keys {
|
|
if keys[i].Kind() == reflect.String {
|
|
key := strings.ToLower(stringy.New(keys[i].Interface().(string)).SnakeCase().Get())
|
|
luaVal := ToLua(state, valValue.MapIndex(keys[i]).Interface())
|
|
resultTable.RawSetString(key, luaVal)
|
|
} else if keys[i].CanConvert(intType) {
|
|
resultTable.RawSetInt(keys[i].Convert(intType).Interface().(int), ToLua(state, valValue.MapIndex(keys[i]).Interface()))
|
|
}
|
|
}
|
|
return resultTable
|
|
case reflect.Slice:
|
|
resultTable := state.NewTable()
|
|
valValue := reflect.ValueOf(val)
|
|
for i := 0; i < valValue.Len(); i++ {
|
|
resultTable.Append(ToLua(state, valValue.Index(i).Interface()))
|
|
}
|
|
return resultTable
|
|
default:
|
|
return baseToLua(val)
|
|
}
|
|
}
|
|
|
|
var noProtect = os.Getenv("EOE_NO_PROTECT") == "1"
|
|
|
|
// BindToLua will create a OwnedCallback from a lua function and state.
|
|
func BindToLua(state *lua.LState, value lua.LValue) OwnedCallback {
|
|
return func(args ...any) (any, error) {
|
|
// Call our lua function
|
|
if err := state.CallByParam(lua.P{
|
|
Fn: value,
|
|
NRet: 1,
|
|
Protect: !noProtect,
|
|
}, lo.Map(args, func(item any, index int) lua.LValue {
|
|
return ToLua(state, item)
|
|
})...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Fetch return value
|
|
ret := state.Get(-1)
|
|
state.Pop(1)
|
|
|
|
// Parse to accepted return values
|
|
switch ret.Type() {
|
|
case lua.LTString:
|
|
return lua.LVAsString(ret), nil
|
|
case lua.LTNumber:
|
|
return float64(lua.LVAsNumber(ret)), nil
|
|
case lua.LTBool:
|
|
return lua.LVAsBool(ret), nil
|
|
case lua.LTTable:
|
|
mapper := NewMapper(state)
|
|
maxn := value.(*lua.LTable).MaxN()
|
|
if maxn == 0 {
|
|
var data map[string]any
|
|
if err := mapper.Map(ret.(*lua.LTable), &data); err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
data := make([]any, 0)
|
|
if err := mapper.Map(ret.(*lua.LTable), &data); err != nil {
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// Don't error for now
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
// ToString converts a lua value to a string.
|
|
func ToString(val lua.LValue, mapper *Mapper) string {
|
|
switch val.Type() {
|
|
case lua.LTString:
|
|
return lua.LVAsString(val)
|
|
case lua.LTNumber:
|
|
return fmt.Sprint(float64(lua.LVAsNumber(val)))
|
|
case lua.LTBool:
|
|
return fmt.Sprint(lua.LVAsBool(val))
|
|
case lua.LTTable:
|
|
maxn := val.(*lua.LTable).MaxN()
|
|
if maxn == 0 {
|
|
var data map[string]interface{}
|
|
if err := mapper.Map(val.(*lua.LTable), &data); err != nil {
|
|
return "Error: " + err.Error()
|
|
}
|
|
return litter.Sdump(data)
|
|
}
|
|
|
|
ret := make([]any, 0)
|
|
if err := mapper.Map(val.(*lua.LTable), &ret); err != nil {
|
|
return "Error: " + err.Error()
|
|
}
|
|
return litter.Sdump(ret)
|
|
case lua.LTUserData:
|
|
return fmt.Sprint(val.(*lua.LUserData).Value)
|
|
case lua.LTNil:
|
|
return "nil"
|
|
}
|
|
|
|
return "<" + val.Type().String() + ">"
|
|
}
|