]> git.lizzy.rs Git - hydra-dragonfire.git/commitdiff
Move conversion code into convert package
authorElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 29 May 2022 22:09:33 +0000 (00:09 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Sun, 29 May 2022 22:09:33 +0000 (00:09 +0200)
18 files changed:
auth.go
builtin/client.lua
client.go
convert/push_auto.go [new file with mode: 0644]
convert/push_mkauto.lua [new file with mode: 0755]
convert/push_static.go [new file with mode: 0644]
convert/read_auto.go [new file with mode: 0644]
convert/read_mkauto.lua [new file with mode: 0755]
convert/read_static.go [new file with mode: 0644]
convert/spec.lua [new file with mode: 0644]
fromlua/generate.lua [deleted file]
fromlua/generated.go [deleted file]
fromlua/static.go [deleted file]
hydra.go
parse_spec.lua [deleted file]
tolua/generate.lua [deleted file]
tolua/generated.go [deleted file]
tolua/static.go [deleted file]

diff --git a/auth.go b/auth.go
index 07599e726d961e3269e7c5b1dea2cc85831d9b3a..cfac361c64387b647c15f69ca9ea0f8156925277 100644 (file)
--- a/auth.go
+++ b/auth.go
@@ -3,7 +3,7 @@ package main
 import (
        "github.com/HimbeerserverDE/srp"
        "github.com/anon55555/mt"
-       "github.com/dragonfireclient/hydra-dragonfire/tolua"
+       "github.com/dragonfireclient/hydra-dragonfire/convert"
        "github.com/yuin/gopher-lua"
        "strings"
        "time"
@@ -57,7 +57,7 @@ func (auth *Auth) create(client *Client, l *lua.LState) {
        l.SetMetatable(auth.userdata, l.GetTypeMetatable("hydra.auth"))
 }
 
-func (auth *Auth) tolua() lua.LValue {
+func (auth *Auth) push() lua.LValue {
        return auth.userdata
 }
 
@@ -90,7 +90,7 @@ func (auth *Auth) checkState(state authState, pkt *mt.Pkt) bool {
                return true
        }
 
-       auth.fail("received " + string(tolua.PktType(pkt)) + " in invalid state")
+       auth.fail("received " + string(convert.PushPktType(pkt)) + " in invalid state")
        return false
 }
 
index b4ed556b1c4442846137b34b5a651512da8982fe..a7618f4ed943c0f0f24dc4adac0902f27b78dfb7 100644 (file)
@@ -1,4 +1,5 @@
 --[[ builtin/client.lua ]]--
+
 function package.loaded.client()
        local address, name, password = unpack(arg)
        local client = hydra.client(address)
index 341f564a257bc6e3e1c1b910f0b1c40c45ca8242..d065709019a3301da6178edc3563a9da0e359c7c 100644 (file)
--- a/client.go
+++ b/client.go
@@ -3,8 +3,7 @@ package main
 import (
        "errors"
        "github.com/anon55555/mt"
-       "github.com/dragonfireclient/hydra-dragonfire/fromlua"
-       "github.com/dragonfireclient/hydra-dragonfire/tolua"
+       "github.com/dragonfireclient/hydra-dragonfire/convert"
        "github.com/yuin/gopher-lua"
        "net"
        "sync"
@@ -20,7 +19,7 @@ const (
 
 type Component interface {
        create(client *Client, l *lua.LState)
-       tolua() lua.LValue
+       push() lua.LValue
        connect()
        process(pkt *mt.Pkt)
 }
@@ -109,7 +108,7 @@ func l_client_index(l *lua.LState) int {
        if fun, exists := clientFuncs[key]; exists {
                l.Push(l.NewFunction(fun))
        } else if component, exists := client.components[key]; exists {
-               l.Push(component.tolua())
+               l.Push(component.push())
        } else {
                l.Push(lua.LNil)
        }
@@ -168,7 +167,7 @@ func l_client_connect(l *lua.LState) int {
                                        component.process(&pkt)
                                }
 
-                               if _, exists := client.subscribed[string(tolua.PktType(&pkt))]; exists || client.wildcard {
+                               if _, exists := client.subscribed[string(convert.PushPktType(&pkt))]; exists || client.wildcard {
                                        client.queue <- &pkt
                                }
 
@@ -193,7 +192,7 @@ func l_client_poll(l *lua.LState) int {
        client := getClient(l)
        _, pkt, timeout := doPoll(l, []*Client{client})
 
-       l.Push(tolua.Pkt(l, pkt))
+       l.Push(convert.PushPkt(l, pkt))
        l.Push(lua.LBool(timeout))
        return 2
 }
@@ -258,7 +257,7 @@ func l_client_wildcard(l *lua.LState) int {
 
 func l_client_send(l *lua.LState) int {
        client := getClient(l)
-       cmd := fromlua.Cmd(l)
+       cmd := convert.ReadCmd(l)
        doAck := l.ToBool(4)
 
        client.mu.Lock()
diff --git a/convert/push_auto.go b/convert/push_auto.go
new file mode 100644 (file)
index 0000000..282a5f5
--- /dev/null
@@ -0,0 +1,684 @@
+// generated by push_mkauto.lua, DO NOT EDIT
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+)
+
+func pushAnimType(l *lua.LState, val mt.AnimType) lua.LValue {
+       switch val {
+       case mt.NoAnim:
+               return lua.LNil
+       case mt.VerticalFrameAnim:
+               return lua.LString("vertical_frame")
+       case mt.SpriteSheetAnim:
+               return lua.LString("sprite_sheet")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushChatMsgType(l *lua.LState, val mt.ChatMsgType) lua.LValue {
+       switch val {
+       case mt.RawMsg:
+               return lua.LString("raw")
+       case mt.NormalMsg:
+               return lua.LString("normal")
+       case mt.AnnounceMsg:
+               return lua.LString("announce")
+       case mt.SysMsg:
+               return lua.LString("sys")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushHotbarParam(l *lua.LState, val mt.HotbarParam) lua.LValue {
+       switch val {
+       case mt.HotbarSize:
+               return lua.LString("size")
+       case mt.HotbarImg:
+               return lua.LString("img")
+       case mt.HotbarSelImg:
+               return lua.LString("sel_img")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushHUDField(l *lua.LState, val mt.HUDField) lua.LValue {
+       switch val {
+       case mt.HUDPos:
+               return lua.LString("pos")
+       case mt.HUDName:
+               return lua.LString("name")
+       case mt.HUDScale:
+               return lua.LString("scale")
+       case mt.HUDText:
+               return lua.LString("text")
+       case mt.HUDNumber:
+               return lua.LString("number")
+       case mt.HUDItem:
+               return lua.LString("item")
+       case mt.HUDDir:
+               return lua.LString("dir")
+       case mt.HUDAlign:
+               return lua.LString("align")
+       case mt.HUDOffset:
+               return lua.LString("offset")
+       case mt.HUDWorldPos:
+               return lua.LString("world_pos")
+       case mt.HUDSize:
+               return lua.LString("size")
+       case mt.HUDZIndex:
+               return lua.LString("z_index")
+       case mt.HUDText2:
+               return lua.LString("text_2")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushHUDType(l *lua.LState, val mt.HUDType) lua.LValue {
+       switch val {
+       case mt.ImgHUD:
+               return lua.LString("img")
+       case mt.TextHUD:
+               return lua.LString("text")
+       case mt.StatbarHUD:
+               return lua.LString("statbar")
+       case mt.InvHUD:
+               return lua.LString("inv")
+       case mt.WaypointHUD:
+               return lua.LString("waypoint")
+       case mt.ImgWaypointHUD:
+               return lua.LString("img_waypoint")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushKickReason(l *lua.LState, val mt.KickReason) lua.LValue {
+       switch val {
+       case mt.WrongPasswd:
+               return lua.LString("wrong_passwd")
+       case mt.UnexpectedData:
+               return lua.LString("unexpected_data")
+       case mt.SrvIsSingleplayer:
+               return lua.LString("srv_is_singleplayer")
+       case mt.UnsupportedVer:
+               return lua.LString("unsupported_ver")
+       case mt.BadNameChars:
+               return lua.LString("bad_name_chars")
+       case mt.BadName:
+               return lua.LString("bad_name")
+       case mt.TooManyClts:
+               return lua.LString("too_many_clts")
+       case mt.EmptyPasswd:
+               return lua.LString("empty_passwd")
+       case mt.AlreadyConnected:
+               return lua.LString("already_connected")
+       case mt.SrvErr:
+               return lua.LString("srv_err")
+       case mt.Custom:
+               return lua.LString("custom")
+       case mt.Shutdown:
+               return lua.LString("shutdown")
+       case mt.Crash:
+               return lua.LString("crash")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushModChanSig(l *lua.LState, val mt.ModChanSig) lua.LValue {
+       switch val {
+       case mt.JoinOK:
+               return lua.LString("join_ok")
+       case mt.JoinFail:
+               return lua.LString("join_fail")
+       case mt.LeaveOK:
+               return lua.LString("leave_ok")
+       case mt.LeaveFail:
+               return lua.LString("leave_fail")
+       case mt.NotRegistered:
+               return lua.LString("not_registered")
+       case mt.SetState:
+               return lua.LString("set_state")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushPlayerListUpdateType(l *lua.LState, val mt.PlayerListUpdateType) lua.LValue {
+       switch val {
+       case mt.InitPlayers:
+               return lua.LString("init")
+       case mt.AddPlayers:
+               return lua.LString("add")
+       case mt.RemovePlayers:
+               return lua.LString("remove")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushSoundSrcType(l *lua.LState, val mt.SoundSrcType) lua.LValue {
+       switch val {
+       case mt.NoSrc:
+               return lua.LNil
+       case mt.PosSrc:
+               return lua.LString("pos")
+       case mt.AOSrc:
+               return lua.LString("ao")
+       }
+       panic("impossible")
+       return lua.LNil
+}
+
+func pushAuthMethods(l *lua.LState, val mt.AuthMethods) lua.LValue {
+       tbl := l.NewTable()
+       if val&mt.LegacyPasswd != 0 {
+               l.SetField(tbl, "legacy_passwd", lua.LTrue)
+       }
+       if val&mt.SRP != 0 {
+               l.SetField(tbl, "srp", lua.LTrue)
+       }
+       if val&mt.FirstSRP != 0 {
+               l.SetField(tbl, "first_srp", lua.LTrue)
+       }
+       return tbl
+}
+
+func pushCSMRestrictionFlags(l *lua.LState, val mt.CSMRestrictionFlags) lua.LValue {
+       tbl := l.NewTable()
+       if val&mt.NoCSMs != 0 {
+               l.SetField(tbl, "no_csms", lua.LTrue)
+       }
+       if val&mt.NoChatMsgs != 0 {
+               l.SetField(tbl, "no_chat_msgs", lua.LTrue)
+       }
+       if val&mt.NoNodeDefs != 0 {
+               l.SetField(tbl, "no_node_defs", lua.LTrue)
+       }
+       if val&mt.LimitMapRange != 0 {
+               l.SetField(tbl, "limit_map_range", lua.LTrue)
+       }
+       if val&mt.NoPlayerList != 0 {
+               l.SetField(tbl, "no_player_list", lua.LTrue)
+       }
+       return tbl
+}
+
+func pushHUDFlags(l *lua.LState, val mt.HUDFlags) lua.LValue {
+       tbl := l.NewTable()
+       if val&mt.ShowHotbar != 0 {
+               l.SetField(tbl, "hotbar", lua.LTrue)
+       }
+       if val&mt.ShowHealthBar != 0 {
+               l.SetField(tbl, "health_bar", lua.LTrue)
+       }
+       if val&mt.ShowCrosshair != 0 {
+               l.SetField(tbl, "crosshair", lua.LTrue)
+       }
+       if val&mt.ShowWieldedItem != 0 {
+               l.SetField(tbl, "wielded_item", lua.LTrue)
+       }
+       if val&mt.ShowBreathBar != 0 {
+               l.SetField(tbl, "breath_bar", lua.LTrue)
+       }
+       if val&mt.ShowMinimap != 0 {
+               l.SetField(tbl, "minimap", lua.LTrue)
+       }
+       if val&mt.ShowRadarMinimap != 0 {
+               l.SetField(tbl, "radar_minimap", lua.LTrue)
+       }
+       return tbl
+}
+
+func pushHUD(l *lua.LState, val mt.HUD) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "align", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Align[0]), lua.LNumber(val.Align[1])}))
+       l.SetField(tbl, "dir", lua.LNumber(val.Dir))
+       l.SetField(tbl, "item", lua.LNumber(val.Item))
+       l.SetField(tbl, "name", lua.LString(string(val.Name)))
+       l.SetField(tbl, "number", lua.LNumber(val.Number))
+       l.SetField(tbl, "offset", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Offset[0]), lua.LNumber(val.Offset[1])}))
+       l.SetField(tbl, "pos", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1])}))
+       l.SetField(tbl, "scale", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Scale[0]), lua.LNumber(val.Scale[1])}))
+       l.SetField(tbl, "size", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
+       l.SetField(tbl, "text", lua.LString(string(val.Text)))
+       l.SetField(tbl, "text_2", lua.LString(string(val.Text2)))
+       l.SetField(tbl, "type", pushHUDType(l, val.Type))
+       l.SetField(tbl, "world_pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.WorldPos[0]), lua.LNumber(val.WorldPos[1]), lua.LNumber(val.WorldPos[2])}))
+       l.SetField(tbl, "z_index", lua.LNumber(val.ZIndex))
+       return tbl
+}
+
+func pushNode(l *lua.LState, val mt.Node) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "param0", lua.LNumber(val.Param0))
+       l.SetField(tbl, "param1", lua.LNumber(val.Param1))
+       l.SetField(tbl, "param2", lua.LNumber(val.Param2))
+       return tbl
+}
+
+func pushTileAnim(l *lua.LState, val mt.TileAnim) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "aspect_ratio", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.AspectRatio[0]), lua.LNumber(val.AspectRatio[1])}))
+       l.SetField(tbl, "duration", lua.LNumber(val.Duration))
+       l.SetField(tbl, "n_frames", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.NFrames[0]), lua.LNumber(val.NFrames[1])}))
+       l.SetField(tbl, "type", pushAnimType(l, val.Type))
+       return tbl
+}
+
+func PushPktType(pkt *mt.Pkt) lua.LString {
+       switch pkt.Cmd.(type) {
+       case *mt.ToCltAcceptAuth:
+               return lua.LString("accept_auth")
+       case *mt.ToCltAcceptSudoMode:
+               return lua.LString("accept_sudo_mode")
+       case *mt.ToCltAddHUD:
+               return lua.LString("add_hud")
+       case *mt.ToCltAddNode:
+               return lua.LString("add_node")
+       case *mt.ToCltAddParticleSpawner:
+               return lua.LString("add_particle_spawner")
+       case *mt.ToCltAddPlayerVel:
+               return lua.LString("add_player_vel")
+       case *mt.ToCltAnnounceMedia:
+               return lua.LString("announce_media")
+       case *mt.ToCltAOMsgs:
+               return lua.LString("ao_msgs")
+       case *mt.ToCltAORmAdd:
+               return lua.LString("ao_rm_add")
+       case *mt.ToCltBlkData:
+               return lua.LString("blk_data")
+       case *mt.ToCltBreath:
+               return lua.LString("breath")
+       case *mt.ToCltChangeHUD:
+               return lua.LString("change_hud")
+       case *mt.ToCltChatMsg:
+               return lua.LString("chat_msg")
+       case *mt.ToCltCloudParams:
+               return lua.LString("cloud_params")
+       case *mt.ToCltCSMRestrictionFlags:
+               return lua.LString("csm_restriction_flags")
+       case *mt.ToCltDeathScreen:
+               return lua.LString("death_screen")
+       case *mt.ToCltDelParticleSpawner:
+               return lua.LString("del_particle_spawner")
+       case *mt.ToCltDenySudoMode:
+               return lua.LString("deny_sudo_mode")
+       case *mt.ToCltDetachedInv:
+               return lua.LString("detached_inv")
+       case *mt.ToCltDisco:
+               return lua.LString("disco")
+       case *mt.ToCltEyeOffset:
+               return lua.LString("eye_offset")
+       case *mt.ToCltFadeSound:
+               return lua.LString("fade_sound")
+       case *mt.ToCltFormspecPrepend:
+               return lua.LString("formspec_prepend")
+       case *mt.ToCltFOV:
+               return lua.LString("fov")
+       case *mt.ToCltHello:
+               return lua.LString("hello")
+       case *mt.ToCltHP:
+               return lua.LString("hp")
+       case *mt.ToCltHUDFlags:
+               return lua.LString("hud_flags")
+       case *mt.ToCltInv:
+               return lua.LString("inv")
+       case *mt.ToCltInvFormspec:
+               return lua.LString("inv_formspec")
+       case *mt.ToCltItemDefs:
+               return lua.LString("item_defs")
+       case *mt.ToCltKick:
+               return lua.LString("kick")
+       case *mt.ToCltLegacyKick:
+               return lua.LString("legacy_kick")
+       case *mt.ToCltLocalPlayerAnim:
+               return lua.LString("local_player_anim")
+       case *mt.ToCltMedia:
+               return lua.LString("media")
+       case *mt.ToCltMediaPush:
+               return lua.LString("media_push")
+       case *mt.ToCltMinimapModes:
+               return lua.LString("minimap_modes")
+       case *mt.ToCltModChanMsg:
+               return lua.LString("mod_chan_msg")
+       case *mt.ToCltModChanSig:
+               return lua.LString("mod_chan_sig")
+       case *mt.ToCltMoonParams:
+               return lua.LString("moon_params")
+       case *mt.ToCltMovePlayer:
+               return lua.LString("move_player")
+       case *mt.ToCltMovement:
+               return lua.LString("movement")
+       case *mt.ToCltNodeDefs:
+               return lua.LString("node_defs")
+       case *mt.ToCltNodeMetasChanged:
+               return lua.LString("node_metas_changed")
+       case *mt.ToCltOverrideDayNightRatio:
+               return lua.LString("override_day_night_ratio")
+       case *mt.ToCltPlaySound:
+               return lua.LString("play_sound")
+       case *mt.ToCltPrivs:
+               return lua.LString("privs")
+       case *mt.ToCltRemoveNode:
+               return lua.LString("remove_node")
+       case *mt.ToCltRmHUD:
+               return lua.LString("rm_hud")
+       case *mt.ToCltSetHotbarParam:
+               return lua.LString("set_hotbar_param")
+       case *mt.ToCltShowFormspec:
+               return lua.LString("show_formspec")
+       case *mt.ToCltSkyParams:
+               return lua.LString("sky_params")
+       case *mt.ToCltSpawnParticle:
+               return lua.LString("spawn_particle")
+       case *mt.ToCltSRPBytesSaltB:
+               return lua.LString("srp_bytes_salt_b")
+       case *mt.ToCltStarParams:
+               return lua.LString("star_params")
+       case *mt.ToCltStopSound:
+               return lua.LString("stop_sound")
+       case *mt.ToCltSunParams:
+               return lua.LString("sun_params")
+       case *mt.ToCltTimeOfDay:
+               return lua.LString("time_of_day")
+       case *mt.ToCltUpdatePlayerList:
+               return lua.LString("update_player_list")
+       }
+       panic("impossible")
+       return ""
+}
+
+func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
+       if pkt == nil {
+               return lua.LNil
+       }
+       tbl := l.NewTable()
+       l.SetField(tbl, "_type", PushPktType(pkt))
+       switch val := pkt.Cmd.(type) {
+       case *mt.ToCltAcceptAuth:
+               l.SetField(tbl, "map_seed", lua.LNumber(val.MapSeed))
+               l.SetField(tbl, "player_pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.PlayerPos[0]), lua.LNumber(val.PlayerPos[1]), lua.LNumber(val.PlayerPos[2])}))
+               l.SetField(tbl, "send_interval", lua.LNumber(val.SendInterval))
+               l.SetField(tbl, "sudo_auth_methods", pushAuthMethods(l, val.SudoAuthMethods))
+       case *mt.ToCltAddHUD:
+               l.SetField(tbl, "hud", pushHUD(l, val.HUD))
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+       case *mt.ToCltAddNode:
+               l.SetField(tbl, "keep_meta", lua.LBool(val.KeepMeta))
+               l.SetField(tbl, "node", pushNode(l, val.Node))
+               l.SetField(tbl, "pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
+       case *mt.ToCltAddParticleSpawner:
+               l.SetField(tbl, "acc", pushBox3(l, [2][3]lua.LNumber{{lua.LNumber(val.Acc[0][0]), lua.LNumber(val.Acc[0][1]), lua.LNumber(val.Acc[0][2])}, {lua.LNumber(val.Acc[1][0]), lua.LNumber(val.Acc[1][1]), lua.LNumber(val.Acc[1][2])}}))
+               l.SetField(tbl, "amount", lua.LNumber(val.Amount))
+               l.SetField(tbl, "anim_params", pushTileAnim(l, val.AnimParams))
+               l.SetField(tbl, "ao_collision", lua.LBool(val.AOCollision))
+               l.SetField(tbl, "collide", lua.LBool(val.Collide))
+               l.SetField(tbl, "collision_rm", lua.LBool(val.CollisionRm))
+               l.SetField(tbl, "duration", lua.LNumber(val.Duration))
+               l.SetField(tbl, "expiration_time", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.ExpirationTime[0]), lua.LNumber(val.ExpirationTime[1])}))
+               l.SetField(tbl, "glow", lua.LNumber(val.Glow))
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+               l.SetField(tbl, "node_param0", lua.LNumber(val.NodeParam0))
+               l.SetField(tbl, "node_param2", lua.LNumber(val.NodeParam2))
+               l.SetField(tbl, "node_tile", lua.LNumber(val.NodeTile))
+               l.SetField(tbl, "pos", pushBox3(l, [2][3]lua.LNumber{{lua.LNumber(val.Pos[0][0]), lua.LNumber(val.Pos[0][1]), lua.LNumber(val.Pos[0][2])}, {lua.LNumber(val.Pos[1][0]), lua.LNumber(val.Pos[1][1]), lua.LNumber(val.Pos[1][2])}}))
+               l.SetField(tbl, "size", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
+               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
+               l.SetField(tbl, "vel", pushBox3(l, [2][3]lua.LNumber{{lua.LNumber(val.Vel[0][0]), lua.LNumber(val.Vel[0][1]), lua.LNumber(val.Vel[0][2])}, {lua.LNumber(val.Vel[1][0]), lua.LNumber(val.Vel[1][1]), lua.LNumber(val.Vel[1][2])}}))
+               l.SetField(tbl, "vertical", lua.LBool(val.Vertical))
+       case *mt.ToCltAddPlayerVel:
+               l.SetField(tbl, "vel", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Vel[0]), lua.LNumber(val.Vel[1]), lua.LNumber(val.Vel[2])}))
+       case *mt.ToCltBlkData:
+               l.SetField(tbl, "blkpos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Blkpos[0]), lua.LNumber(val.Blkpos[1]), lua.LNumber(val.Blkpos[2])}))
+       case *mt.ToCltBreath:
+               l.SetField(tbl, "breath", lua.LNumber(val.Breath))
+       case *mt.ToCltChangeHUD:
+               if val.Field == mt.HUDAlign {
+                       l.SetField(tbl, "align", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Align[0]), lua.LNumber(val.Align[1])}))
+               }
+               if val.Field == mt.HUDDir {
+                       l.SetField(tbl, "dir", lua.LNumber(val.Dir))
+               }
+               l.SetField(tbl, "field", pushHUDField(l, val.Field))
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+               if val.Field == mt.HUDItem {
+                       l.SetField(tbl, "item", lua.LNumber(val.Item))
+               }
+               if val.Field == mt.HUDName {
+                       l.SetField(tbl, "name", lua.LString(string(val.Name)))
+               }
+               if val.Field == mt.HUDNumber {
+                       l.SetField(tbl, "number", lua.LNumber(val.Number))
+               }
+               if val.Field == mt.HUDOffset {
+                       l.SetField(tbl, "offset", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Offset[0]), lua.LNumber(val.Offset[1])}))
+               }
+               if val.Field == mt.HUDPos {
+                       l.SetField(tbl, "pos", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1])}))
+               }
+               if val.Field == mt.HUDSize {
+                       l.SetField(tbl, "size", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
+               }
+               if val.Field == mt.HUDText {
+                       l.SetField(tbl, "text", lua.LString(string(val.Text)))
+               }
+               if val.Field == mt.HUDText2 {
+                       l.SetField(tbl, "text_2", lua.LString(string(val.Text2)))
+               }
+               if val.Field == mt.HUDWorldPos {
+                       l.SetField(tbl, "world_pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.WorldPos[0]), lua.LNumber(val.WorldPos[1]), lua.LNumber(val.WorldPos[2])}))
+               }
+               if val.Field == mt.HUDZIndex {
+                       l.SetField(tbl, "z_index", lua.LNumber(val.ZIndex))
+               }
+       case *mt.ToCltChatMsg:
+               l.SetField(tbl, "sender", lua.LString(string(val.Sender)))
+               l.SetField(tbl, "text", lua.LString(string(val.Text)))
+               l.SetField(tbl, "timestamp", lua.LNumber(val.Timestamp))
+               l.SetField(tbl, "type", pushChatMsgType(l, val.Type))
+       case *mt.ToCltCloudParams:
+               l.SetField(tbl, "ambient_color", pushColor(l, val.AmbientColor))
+               l.SetField(tbl, "density", lua.LNumber(val.Density))
+               l.SetField(tbl, "diffuse_color", pushColor(l, val.DiffuseColor))
+               l.SetField(tbl, "height", lua.LNumber(val.Height))
+               l.SetField(tbl, "speed", pushVec2(l, [2]lua.LNumber{lua.LNumber(val.Speed[0]), lua.LNumber(val.Speed[1])}))
+               l.SetField(tbl, "thickness", lua.LNumber(val.Thickness))
+       case *mt.ToCltCSMRestrictionFlags:
+               l.SetField(tbl, "flags", pushCSMRestrictionFlags(l, val.Flags))
+               l.SetField(tbl, "map_range", lua.LNumber(val.MapRange))
+       case *mt.ToCltDeathScreen:
+               l.SetField(tbl, "point_at", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.PointAt[0]), lua.LNumber(val.PointAt[1]), lua.LNumber(val.PointAt[2])}))
+               l.SetField(tbl, "point_cam", lua.LBool(val.PointCam))
+       case *mt.ToCltDelParticleSpawner:
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+       case *mt.ToCltDetachedInv:
+               l.SetField(tbl, "inv", lua.LString(string(val.Inv)))
+               l.SetField(tbl, "keep", lua.LBool(val.Keep))
+               l.SetField(tbl, "len", lua.LNumber(val.Len))
+               l.SetField(tbl, "name", lua.LString(string(val.Name)))
+       case *mt.ToCltEyeOffset:
+               l.SetField(tbl, "first", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.First[0]), lua.LNumber(val.First[1]), lua.LNumber(val.First[2])}))
+               l.SetField(tbl, "third", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Third[0]), lua.LNumber(val.Third[1]), lua.LNumber(val.Third[2])}))
+       case *mt.ToCltFadeSound:
+               l.SetField(tbl, "gain", lua.LNumber(val.Gain))
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+               l.SetField(tbl, "step", lua.LNumber(val.Step))
+       case *mt.ToCltFormspecPrepend:
+               l.SetField(tbl, "prepend", lua.LString(string(val.Prepend)))
+       case *mt.ToCltFOV:
+               l.SetField(tbl, "fov", lua.LNumber(val.FOV))
+               l.SetField(tbl, "multiplier", lua.LBool(val.Multiplier))
+               l.SetField(tbl, "transition_time", lua.LNumber(val.TransitionTime))
+       case *mt.ToCltHello:
+               l.SetField(tbl, "auth_methods", pushAuthMethods(l, val.AuthMethods))
+               l.SetField(tbl, "compression", lua.LNumber(val.Compression))
+               l.SetField(tbl, "proto_ver", lua.LNumber(val.ProtoVer))
+               l.SetField(tbl, "serialize_ver", lua.LNumber(val.SerializeVer))
+               l.SetField(tbl, "username", lua.LString(string(val.Username)))
+       case *mt.ToCltHP:
+               l.SetField(tbl, "hp", lua.LNumber(val.HP))
+       case *mt.ToCltHUDFlags:
+               l.SetField(tbl, "flags", pushHUDFlags(l, val.Flags))
+               l.SetField(tbl, "mask", pushHUDFlags(l, val.Mask))
+       case *mt.ToCltInv:
+               l.SetField(tbl, "inv", lua.LString(string(val.Inv)))
+       case *mt.ToCltInvFormspec:
+               l.SetField(tbl, "formspec", lua.LString(string(val.Formspec)))
+       case *mt.ToCltKick:
+               if val.Reason == mt.Custom || val.Reason == mt.Shutdown || val.Reason == mt.Crash {
+                       l.SetField(tbl, "custom", lua.LString(string(val.Custom)))
+               }
+               l.SetField(tbl, "reason", pushKickReason(l, val.Reason))
+               if val.Reason == mt.Shutdown || val.Reason == mt.Crash {
+                       l.SetField(tbl, "reconnect", lua.LBool(val.Reconnect))
+               }
+       case *mt.ToCltLegacyKick:
+               l.SetField(tbl, "reason", lua.LString(string(val.Reason)))
+       case *mt.ToCltLocalPlayerAnim:
+               l.SetField(tbl, "dig", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.Dig[0]), lua.LNumber(val.Dig[1])}))
+               l.SetField(tbl, "idle", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.Idle[0]), lua.LNumber(val.Idle[1])}))
+               l.SetField(tbl, "speed", lua.LNumber(val.Speed))
+               l.SetField(tbl, "walk", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.Walk[0]), lua.LNumber(val.Walk[1])}))
+               l.SetField(tbl, "walk_dig", pushBox1(l, [2]lua.LNumber{lua.LNumber(val.WalkDig[0]), lua.LNumber(val.WalkDig[1])}))
+       case *mt.ToCltMediaPush:
+               l.SetField(tbl, "data", lua.LString(string(val.Data)))
+               l.SetField(tbl, "filename", lua.LString(string(val.Filename)))
+               l.SetField(tbl, "sha1", lua.LString(string(val.SHA1[:])))
+               l.SetField(tbl, "should_cache", lua.LBool(val.ShouldCache))
+       case *mt.ToCltModChanMsg:
+               l.SetField(tbl, "channel", lua.LString(string(val.Channel)))
+               l.SetField(tbl, "msg", lua.LString(string(val.Msg)))
+               l.SetField(tbl, "sender", lua.LString(string(val.Sender)))
+       case *mt.ToCltModChanSig:
+               l.SetField(tbl, "channel", lua.LString(string(val.Channel)))
+               l.SetField(tbl, "signal", pushModChanSig(l, val.Signal))
+       case *mt.ToCltMoonParams:
+               l.SetField(tbl, "size", lua.LNumber(val.Size))
+               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
+               l.SetField(tbl, "tone_map", lua.LString(string(val.ToneMap)))
+               l.SetField(tbl, "visible", lua.LBool(val.Visible))
+       case *mt.ToCltMovePlayer:
+               l.SetField(tbl, "pitch", lua.LNumber(val.Pitch))
+               l.SetField(tbl, "pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
+               l.SetField(tbl, "yaw", lua.LNumber(val.Yaw))
+       case *mt.ToCltMovement:
+               l.SetField(tbl, "air_accel", lua.LNumber(val.AirAccel))
+               l.SetField(tbl, "climb_speed", lua.LNumber(val.ClimbSpeed))
+               l.SetField(tbl, "crouch_speed", lua.LNumber(val.CrouchSpeed))
+               l.SetField(tbl, "default_accel", lua.LNumber(val.DefaultAccel))
+               l.SetField(tbl, "fast_accel", lua.LNumber(val.FastAccel))
+               l.SetField(tbl, "fast_speed", lua.LNumber(val.FastSpeed))
+               l.SetField(tbl, "fluidity", lua.LNumber(val.Fluidity))
+               l.SetField(tbl, "gravity", lua.LNumber(val.Gravity))
+               l.SetField(tbl, "jump_speed", lua.LNumber(val.JumpSpeed))
+               l.SetField(tbl, "sink", lua.LNumber(val.Sink))
+               l.SetField(tbl, "smoothing", lua.LNumber(val.Smoothing))
+               l.SetField(tbl, "walk_speed", lua.LNumber(val.WalkSpeed))
+       case *mt.ToCltOverrideDayNightRatio:
+               l.SetField(tbl, "override", lua.LBool(val.Override))
+               l.SetField(tbl, "ratio", lua.LNumber(val.Ratio))
+       case *mt.ToCltPlaySound:
+               l.SetField(tbl, "ephemeral", lua.LBool(val.Ephemeral))
+               l.SetField(tbl, "fade", lua.LNumber(val.Fade))
+               l.SetField(tbl, "gain", lua.LNumber(val.Gain))
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+               l.SetField(tbl, "loop", lua.LBool(val.Loop))
+               l.SetField(tbl, "name", lua.LString(string(val.Name)))
+               l.SetField(tbl, "pitch", lua.LNumber(val.Pitch))
+               l.SetField(tbl, "pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
+               l.SetField(tbl, "src_aoid", lua.LNumber(val.SrcAOID))
+               l.SetField(tbl, "src_type", pushSoundSrcType(l, val.SrcType))
+       case *mt.ToCltPrivs:
+               l.SetField(tbl, "privs", pushStringSet(l, val.Privs))
+       case *mt.ToCltRemoveNode:
+               l.SetField(tbl, "pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
+       case *mt.ToCltRmHUD:
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+       case *mt.ToCltSetHotbarParam:
+               l.SetField(tbl, "img", lua.LString(string(val.Img)))
+               l.SetField(tbl, "param", pushHotbarParam(l, val.Param))
+               l.SetField(tbl, "size", lua.LNumber(val.Size))
+       case *mt.ToCltShowFormspec:
+               l.SetField(tbl, "formname", lua.LString(string(val.Formname)))
+               l.SetField(tbl, "formspec", lua.LString(string(val.Formspec)))
+       case *mt.ToCltSkyParams:
+               l.SetField(tbl, "bg_color", pushColor(l, val.BgColor))
+               l.SetField(tbl, "clouds", lua.LBool(val.Clouds))
+               if val.Type == "regular" {
+                       l.SetField(tbl, "dawn_horizon", pushColor(l, val.DawnHorizon))
+               }
+               if val.Type == "regular" {
+                       l.SetField(tbl, "dawn_sky", pushColor(l, val.DawnSky))
+               }
+               if val.Type == "regular" {
+                       l.SetField(tbl, "day_horizon", pushColor(l, val.DayHorizon))
+               }
+               if val.Type == "regular" {
+                       l.SetField(tbl, "day_sky", pushColor(l, val.DaySky))
+               }
+               l.SetField(tbl, "fog_tint_type", lua.LString(string(val.FogTintType)))
+               if val.Type == "regular" {
+                       l.SetField(tbl, "indoor", pushColor(l, val.Indoor))
+               }
+               l.SetField(tbl, "moon_fog_tint", pushColor(l, val.MoonFogTint))
+               if val.Type == "regular" {
+                       l.SetField(tbl, "night_horizon", pushColor(l, val.NightHorizon))
+               }
+               if val.Type == "regular" {
+                       l.SetField(tbl, "night_sky", pushColor(l, val.NightSky))
+               }
+               l.SetField(tbl, "sun_fog_tint", pushColor(l, val.SunFogTint))
+               if val.Type == "skybox" {
+                       l.SetField(tbl, "textures", pushTextureList(l, val.Textures))
+               }
+               l.SetField(tbl, "type", lua.LString(string(val.Type)))
+       case *mt.ToCltSpawnParticle:
+               l.SetField(tbl, "acc", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Acc[0]), lua.LNumber(val.Acc[1]), lua.LNumber(val.Acc[2])}))
+               l.SetField(tbl, "anim_params", pushTileAnim(l, val.AnimParams))
+               l.SetField(tbl, "ao_collision", lua.LBool(val.AOCollision))
+               l.SetField(tbl, "collide", lua.LBool(val.Collide))
+               l.SetField(tbl, "collision_rm", lua.LBool(val.CollisionRm))
+               l.SetField(tbl, "expiration_time", lua.LNumber(val.ExpirationTime))
+               l.SetField(tbl, "glow", lua.LNumber(val.Glow))
+               l.SetField(tbl, "node_param0", lua.LNumber(val.NodeParam0))
+               l.SetField(tbl, "node_param2", lua.LNumber(val.NodeParam2))
+               l.SetField(tbl, "node_tile", lua.LNumber(val.NodeTile))
+               l.SetField(tbl, "pos", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
+               l.SetField(tbl, "size", lua.LNumber(val.Size))
+               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
+               l.SetField(tbl, "vel", pushVec3(l, [3]lua.LNumber{lua.LNumber(val.Vel[0]), lua.LNumber(val.Vel[1]), lua.LNumber(val.Vel[2])}))
+               l.SetField(tbl, "vertical", lua.LBool(val.Vertical))
+       case *mt.ToCltSRPBytesSaltB:
+               l.SetField(tbl, "b", lua.LString(string(val.B)))
+               l.SetField(tbl, "salt", lua.LString(string(val.Salt)))
+       case *mt.ToCltStarParams:
+               l.SetField(tbl, "color", pushColor(l, val.Color))
+               l.SetField(tbl, "count", lua.LNumber(val.Count))
+               l.SetField(tbl, "size", lua.LNumber(val.Size))
+               l.SetField(tbl, "visible", lua.LBool(val.Visible))
+       case *mt.ToCltStopSound:
+               l.SetField(tbl, "id", lua.LNumber(val.ID))
+       case *mt.ToCltSunParams:
+               l.SetField(tbl, "rise", lua.LString(string(val.Rise)))
+               l.SetField(tbl, "rising", lua.LBool(val.Rising))
+               l.SetField(tbl, "size", lua.LNumber(val.Size))
+               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
+               l.SetField(tbl, "tone_map", lua.LString(string(val.ToneMap)))
+               l.SetField(tbl, "visible", lua.LBool(val.Visible))
+       case *mt.ToCltTimeOfDay:
+               l.SetField(tbl, "speed", lua.LNumber(val.Speed))
+               l.SetField(tbl, "time", lua.LNumber(val.Time))
+       case *mt.ToCltUpdatePlayerList:
+               l.SetField(tbl, "players", pushStringList(l, val.Players))
+               l.SetField(tbl, "type", pushPlayerListUpdateType(l, val.Type))
+       }
+       return tbl
+}
diff --git a/convert/push_mkauto.lua b/convert/push_mkauto.lua
new file mode 100755 (executable)
index 0000000..3e02932
--- /dev/null
@@ -0,0 +1,127 @@
+#!/usr/bin/env lua
+require("spec")
+
+local funcs = ""
+
+for name, fields in spairs(parse_spec("client/enum")) do
+       local camel = camel_case(name)
+       funcs = funcs .. "func push" .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\tswitch val {\n"
+
+       for _, var in ipairs(fields) do
+               funcs = funcs .. "\tcase mt." .. apply_prefix(fields, var) .. ":\n\t\t" ..
+                       (var == "no" and "return lua.LNil" or "return lua.LString(\"" .. var .. "\")") .. "\n"
+       end
+
+       funcs = funcs .. "\t}\n\tpanic(\"impossible\")\n\treturn lua.LNil\n}\n\n"
+end
+
+for name, fields in spairs(parse_spec("client/flag")) do
+       local camel = camel_case(name)
+       funcs = funcs .. "func push" .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\ttbl := l.NewTable()\n"
+
+       for _, var in ipairs(fields) do
+               funcs = funcs .. "\tif val&mt." .. apply_prefix(fields, var)
+                       .. " != 0 {\n\t\tl.SetField(tbl, \"" .. var  .. "\", lua.LTrue)\n\t}\n"
+       end
+
+       funcs = funcs .. "\treturn tbl\n}\n\n"
+end
+
+local tolua = {
+       string = "lua.LString(string(VAL))",
+       fixed_string = "lua.LString(string(VAL[:]))",
+       boolean = "lua.LBool(VAL)",
+       number = "lua.LNumber(VAL)",
+       vec2 = "pushVec2(l, [2]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1])})",
+       vec3 = "pushVec3(l, [3]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1]), lua.LNumber(VAL[2])})",
+       box1 = "pushBox1(l, [2]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1])})",
+       box2 = "pushBox2(l, [2][2]lua.LNumber{{lua.LNumber(VAL[0][0]), lua.LNumber(VAL[0][1])}, {lua.LNumber(VAL[1][0]), lua.LNumber(VAL[1][1])}})",
+       box3 = "pushBox3(l, [2][3]lua.LNumber{{lua.LNumber(VAL[0][0]), lua.LNumber(VAL[0][1]), lua.LNumber(VAL[0][2])}, {lua.LNumber(VAL[1][0]), lua.LNumber(VAL[1][1]), lua.LNumber(VAL[1][2])}})",
+}
+
+local function fields_tolua(fields, indent)
+       local impl = ""
+
+       for name, type in spairs(fields) do
+               if name:sub(1, 1) ~= "{" then
+                       local camel = "val." .. camel_case(name)
+
+                       local idt = indent
+                       local condition = fields["{" .. name .. "}"]
+
+                       if condition then
+                               impl = impl .. indent .. "if " .. condition .. " {\n"
+                               idt = idt .. "\t"
+                       end
+
+                       impl = impl .. idt .. "l.SetField(tbl, \"" .. name .. "\", "
+                       if tolua[type] then
+                               impl = impl .. tolua[type]:gsub("VAL", camel)
+                       else
+                               impl = impl .. "push" .. camel_case(type) .. "(l, " .. camel .. ")"
+                       end
+                       impl = impl .. ")\n"
+
+                       if condition then
+                               impl = impl .. indent .. "}\n"
+                       end
+               end
+       end
+
+       return impl
+end
+
+for name, fields in spairs(parse_spec("client/struct", true)) do
+       local camel = camel_case(name)
+       funcs = funcs
+               .. "func push" .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\ttbl := l.NewTable()\n"
+               .. fields_tolua(fields, "\t")
+               .. "\treturn tbl\n}\n\n"
+end
+
+local pkt_type_impl = ""
+local pkt_impl = ""
+
+for name, fields in spairs(parse_spec("client/pkt", true)) do
+       local case = "\tcase *mt.ToClt" .. camel_case(name) .. ":\n"
+
+       pkt_type_impl = pkt_type_impl
+               .. case .. "\t\treturn lua.LString(\"" .. name .. "\")\n"
+
+       if next(fields) then
+               pkt_impl = pkt_impl .. case .. fields_tolua(fields, "\t\t")
+       end
+end
+
+local f = io.open("push_auto.go", "w")
+f:write([[
+// generated by push_mkauto.lua, DO NOT EDIT
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+)
+
+]] .. funcs .. [[
+func PushPktType(pkt *mt.Pkt) lua.LString {
+       switch pkt.Cmd.(type) {
+]] .. pkt_type_impl .. [[
+       }
+       panic("impossible")
+       return ""
+}
+
+func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
+       if pkt == nil {
+               return lua.LNil
+       }
+       tbl := l.NewTable()
+       l.SetField(tbl, "_type", PushPktType(pkt))
+       switch val := pkt.Cmd.(type) {
+]] .. pkt_impl .. [[
+       }
+       return tbl
+}
+]])
+f:close()
diff --git a/convert/push_static.go b/convert/push_static.go
new file mode 100644 (file)
index 0000000..4eb7cb0
--- /dev/null
@@ -0,0 +1,97 @@
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+       "image/color"
+)
+
+//go:generate ./push_mkauto.lua
+
+func vec2(l *lua.LState, val [2]lua.LNumber) {
+       l.Push(l.GetGlobal("vec2"))
+       l.Push(val[0])
+       l.Push(val[1])
+       l.Call(2, 1)
+}
+
+func vec3(l *lua.LState, val [3]lua.LNumber) {
+       l.Push(l.GetGlobal("vec3"))
+       l.Push(val[0])
+       l.Push(val[1])
+       l.Push(val[2])
+       l.Call(3, 1)
+}
+
+func popValue(l *lua.LState) lua.LValue {
+       ret := l.Get(-1)
+       l.Pop(1)
+       return ret
+}
+
+func pushVec2(l *lua.LState, val [2]lua.LNumber) lua.LValue {
+       vec2(l, val)
+       return popValue(l)
+}
+
+func pushVec3(l *lua.LState, val [3]lua.LNumber) lua.LValue {
+       vec3(l, val)
+       return popValue(l)
+}
+
+func pushBox1(l *lua.LState, val [2]lua.LNumber) lua.LValue {
+       l.Push(l.GetGlobal("box"))
+       l.Push(val[0])
+       l.Push(val[1])
+       l.Call(2, 1)
+       return popValue(l)
+}
+
+func pushBox2(l *lua.LState, val [2][2]lua.LNumber) lua.LValue {
+       l.Push(l.GetGlobal("box"))
+       vec2(l, val[0])
+       vec2(l, val[1])
+       l.Call(2, 1)
+       return popValue(l)
+}
+
+func pushBox3(l *lua.LState, val [2][3]lua.LNumber) lua.LValue {
+       l.Push(l.GetGlobal("box"))
+       vec3(l, val[0])
+       vec3(l, val[1])
+       l.Call(2, 1)
+       return popValue(l)
+}
+
+func pushColor(l *lua.LState, val color.NRGBA) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "r", lua.LNumber(val.R))
+       l.SetField(tbl, "g", lua.LNumber(val.G))
+       l.SetField(tbl, "b", lua.LNumber(val.B))
+       l.SetField(tbl, "a", lua.LNumber(val.A))
+       return tbl
+}
+
+func pushStringSet(l *lua.LState, val []string) lua.LValue {
+       tbl := l.NewTable()
+       for _, str := range val {
+               l.SetField(tbl, str, lua.LTrue)
+       }
+       return tbl
+}
+
+func stringList[T ~string](l *lua.LState, val []T) lua.LValue {
+       tbl := l.NewTable()
+       for _, s := range val {
+               tbl.Append(lua.LString(s))
+       }
+       return tbl
+}
+
+func pushStringList(l *lua.LState, val []string) lua.LValue {
+       return stringList[string](l, val)
+}
+
+func pushTextureList(l *lua.LState, val []mt.Texture) lua.LValue {
+       return stringList[mt.Texture](l, val)
+}
diff --git a/convert/read_auto.go b/convert/read_auto.go
new file mode 100644 (file)
index 0000000..c5a39be
--- /dev/null
@@ -0,0 +1,320 @@
+// generated by read_mkauto.lua, DO NOT EDIT
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+)
+
+func readAOID(l *lua.LState, val lua.LValue, ptr *mt.AOID) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for AOID: must be a number")
+       }
+       *ptr = mt.AOID(val.(lua.LNumber))
+}
+
+func readCompressionModes(l *lua.LState, val lua.LValue, ptr *mt.CompressionModes) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for CompressionModes: must be a number")
+       }
+       *ptr = mt.CompressionModes(val.(lua.LNumber))
+}
+
+func readInt16(l *lua.LState, val lua.LValue, ptr *int16) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for int16: must be a number")
+       }
+       *ptr = int16(val.(lua.LNumber))
+}
+
+func readInt32(l *lua.LState, val lua.LValue, ptr *int32) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for int32: must be a number")
+       }
+       *ptr = int32(val.(lua.LNumber))
+}
+
+func readInteraction(l *lua.LState, val lua.LValue, ptr *mt.Interaction) {
+       if val.Type() != lua.LTString {
+               panic("invalid value for Interaction: must be a string")
+       }
+       str := string(val.(lua.LString))
+       switch str {
+       case "dig":
+               *ptr = mt.Dig
+       case "stop_digging":
+               *ptr = mt.StopDigging
+       case "dug":
+               *ptr = mt.Dug
+       case "place":
+               *ptr = mt.Place
+       case "use":
+               *ptr = mt.Use
+       case "activate":
+               *ptr = mt.Activate
+       default:
+               panic("invalid value for interaction: " + str)
+       }
+}
+
+func readKeys(l *lua.LState, val lua.LValue, ptr *mt.Keys) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for Keys: must be a table")
+       }
+       if l.GetField(val, "forward") == lua.LTrue {
+               *ptr = *ptr | mt.ForwardKey
+       }
+       if l.GetField(val, "backward") == lua.LTrue {
+               *ptr = *ptr | mt.BackwardKey
+       }
+       if l.GetField(val, "left") == lua.LTrue {
+               *ptr = *ptr | mt.LeftKey
+       }
+       if l.GetField(val, "right") == lua.LTrue {
+               *ptr = *ptr | mt.RightKey
+       }
+       if l.GetField(val, "jump") == lua.LTrue {
+               *ptr = *ptr | mt.JumpKey
+       }
+       if l.GetField(val, "special") == lua.LTrue {
+               *ptr = *ptr | mt.SpecialKey
+       }
+       if l.GetField(val, "sneak") == lua.LTrue {
+               *ptr = *ptr | mt.SneakKey
+       }
+       if l.GetField(val, "dig") == lua.LTrue {
+               *ptr = *ptr | mt.DigKey
+       }
+       if l.GetField(val, "place") == lua.LTrue {
+               *ptr = *ptr | mt.PlaceKey
+       }
+       if l.GetField(val, "zoom") == lua.LTrue {
+               *ptr = *ptr | mt.ZoomKey
+       }
+}
+
+func readPlayerPos(l *lua.LState, val lua.LValue, ptr *mt.PlayerPos) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for PlayerPos: must be a table")
+       }
+       readUint8(l, l.GetField(val, "fov80"), &ptr.FOV80)
+       readKeys(l, l.GetField(val, "keys"), &ptr.Keys)
+       readInt32(l, l.GetField(val, "pitch100"), &ptr.Pitch100)
+       readVec3Int32(l, l.GetField(val, "pos100"), &ptr.Pos100)
+       readVec3Int32(l, l.GetField(val, "vel100"), &ptr.Vel100)
+       readUint8(l, l.GetField(val, "wanted_range"), &ptr.WantedRange)
+       readInt32(l, l.GetField(val, "yaw100"), &ptr.Yaw100)
+}
+
+func readSliceSoundID(l *lua.LState, val lua.LValue, ptr *[]mt.SoundID) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for []SoundID: must be a table")
+       }
+       tbl := val.(*lua.LTable)
+       n := tbl.MaxN()
+       *ptr = make([]mt.SoundID, n)
+       for i := range *ptr {
+               readSoundID(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+       }
+}
+
+func readSliceString(l *lua.LState, val lua.LValue, ptr *[]string) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for []string: must be a table")
+       }
+       tbl := val.(*lua.LTable)
+       n := tbl.MaxN()
+       *ptr = make([]string, n)
+       for i := range *ptr {
+               readString(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+       }
+}
+
+func readSliceVec3Int16(l *lua.LState, val lua.LValue, ptr *[][3]int16) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for [][3]int16: must be a table")
+       }
+       tbl := val.(*lua.LTable)
+       n := tbl.MaxN()
+       *ptr = make([][3]int16, n)
+       for i := range *ptr {
+               readVec3Int16(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+       }
+}
+
+func readSoundID(l *lua.LState, val lua.LValue, ptr *mt.SoundID) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for SoundID: must be a number")
+       }
+       *ptr = mt.SoundID(val.(lua.LNumber))
+}
+
+func readUint16(l *lua.LState, val lua.LValue, ptr *uint16) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for uint16: must be a number")
+       }
+       *ptr = uint16(val.(lua.LNumber))
+}
+
+func readUint8(l *lua.LState, val lua.LValue, ptr *uint8) {
+       if val.Type() != lua.LTNumber {
+               panic("invalid value for uint8: must be a number")
+       }
+       *ptr = uint8(val.(lua.LNumber))
+}
+
+func readVec3Int16(l *lua.LState, val lua.LValue, ptr *[3]int16) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for [3]int16: must be a table")
+       }
+       readInt16(l, l.GetField(val, "x"), &(*ptr)[0])
+       readInt16(l, l.GetField(val, "y"), &(*ptr)[1])
+       readInt16(l, l.GetField(val, "z"), &(*ptr)[2])
+}
+
+func readVec3Int32(l *lua.LState, val lua.LValue, ptr *[3]int32) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for [3]int32: must be a table")
+       }
+       readInt32(l, l.GetField(val, "x"), &(*ptr)[0])
+       readInt32(l, l.GetField(val, "y"), &(*ptr)[1])
+       readInt32(l, l.GetField(val, "z"), &(*ptr)[2])
+}
+
+func ReadCmd(l *lua.LState) mt.Cmd {
+       str := l.CheckString(2)
+       switch str {
+       case "chat_msg":
+               ptr := &mt.ToSrvChatMsg{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "msg"), &ptr.Msg)
+               return ptr
+       case "clt_ready":
+               ptr := &mt.ToSrvCltReady{}
+               val := l.CheckTable(3)
+               readUint16(l, l.GetField(val, "formspec"), &ptr.Formspec)
+               readUint8(l, l.GetField(val, "major"), &ptr.Major)
+               readUint8(l, l.GetField(val, "minor"), &ptr.Minor)
+               readUint8(l, l.GetField(val, "patch"), &ptr.Patch)
+               readString(l, l.GetField(val, "version"), &ptr.Version)
+               return ptr
+       case "deleted_blks":
+               ptr := &mt.ToSrvDeletedBlks{}
+               val := l.CheckTable(3)
+               readSliceVec3Int16(l, l.GetField(val, "blks"), &ptr.Blks)
+               return ptr
+       case "fall_dmg":
+               ptr := &mt.ToSrvFallDmg{}
+               val := l.CheckTable(3)
+               readUint16(l, l.GetField(val, "amount"), &ptr.Amount)
+               return ptr
+       case "first_srp":
+               ptr := &mt.ToSrvFirstSRP{}
+               val := l.CheckTable(3)
+               readBool(l, l.GetField(val, "empty_passwd"), &ptr.EmptyPasswd)
+               readSliceByte(l, l.GetField(val, "salt"), &ptr.Salt)
+               readSliceByte(l, l.GetField(val, "verifier"), &ptr.Verifier)
+               return ptr
+       case "got_blks":
+               ptr := &mt.ToSrvGotBlks{}
+               val := l.CheckTable(3)
+               readSliceVec3Int16(l, l.GetField(val, "blks"), &ptr.Blks)
+               return ptr
+       case "init":
+               ptr := &mt.ToSrvInit{}
+               val := l.CheckTable(3)
+               readUint16(l, l.GetField(val, "max_proto_ver"), &ptr.MaxProtoVer)
+               readUint16(l, l.GetField(val, "min_proto_ver"), &ptr.MinProtoVer)
+               readString(l, l.GetField(val, "player_name"), &ptr.PlayerName)
+               readBool(l, l.GetField(val, "send_full_item_meta"), &ptr.SendFullItemMeta)
+               readUint8(l, l.GetField(val, "serialize_ver"), &ptr.SerializeVer)
+               readCompressionModes(l, l.GetField(val, "supported_compression"), &ptr.SupportedCompression)
+               return ptr
+       case "init2":
+               ptr := &mt.ToSrvInit2{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "lang"), &ptr.Lang)
+               return ptr
+       case "interact":
+               ptr := &mt.ToSrvInteract{}
+               val := l.CheckTable(3)
+               readInteraction(l, l.GetField(val, "action"), &ptr.Action)
+               readUint16(l, l.GetField(val, "item_slot"), &ptr.ItemSlot)
+               readPointedThing(l, l.GetField(val, "pointed"), &ptr.Pointed)
+               readPlayerPos(l, l.GetField(val, "pos"), &ptr.Pos)
+               return ptr
+       case "inv_action":
+               ptr := &mt.ToSrvInvAction{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "action"), &ptr.Action)
+               return ptr
+       case "inv_fields":
+               ptr := &mt.ToSrvInvFields{}
+               val := l.CheckTable(3)
+               readSliceField(l, l.GetField(val, "fields"), &ptr.Fields)
+               readString(l, l.GetField(val, "formname"), &ptr.Formname)
+               return ptr
+       case "join_mod_chan":
+               ptr := &mt.ToSrvJoinModChan{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "channel"), &ptr.Channel)
+               return ptr
+       case "leave_mod_chan":
+               ptr := &mt.ToSrvLeaveModChan{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "channel"), &ptr.Channel)
+               return ptr
+       case "msg_mod_chan":
+               ptr := &mt.ToSrvMsgModChan{}
+               val := l.CheckTable(3)
+               readString(l, l.GetField(val, "channel"), &ptr.Channel)
+               readString(l, l.GetField(val, "msg"), &ptr.Msg)
+               return ptr
+       case "nil":
+               ptr := &mt.ToSrvNil{}
+               return ptr
+       case "node_meta_fields":
+               ptr := &mt.ToSrvNodeMetaFields{}
+               val := l.CheckTable(3)
+               readSliceField(l, l.GetField(val, "fields"), &ptr.Fields)
+               readString(l, l.GetField(val, "formname"), &ptr.Formname)
+               readVec3Int16(l, l.GetField(val, "pos"), &ptr.Pos)
+               return ptr
+       case "player_pos":
+               ptr := &mt.ToSrvPlayerPos{}
+               val := l.CheckTable(3)
+               readPlayerPos(l, l.GetField(val, "pos"), &ptr.Pos)
+               return ptr
+       case "removed_sounds":
+               ptr := &mt.ToSrvRemovedSounds{}
+               val := l.CheckTable(3)
+               readSliceSoundID(l, l.GetField(val, "ids"), &ptr.IDs)
+               return ptr
+       case "req_media":
+               ptr := &mt.ToSrvReqMedia{}
+               val := l.CheckTable(3)
+               readSliceString(l, l.GetField(val, "filenames"), &ptr.Filenames)
+               return ptr
+       case "respawn":
+               ptr := &mt.ToSrvRespawn{}
+               return ptr
+       case "select_item":
+               ptr := &mt.ToSrvSelectItem{}
+               val := l.CheckTable(3)
+               readUint16(l, l.GetField(val, "slot"), &ptr.Slot)
+               return ptr
+       case "srp_bytes_a":
+               ptr := &mt.ToSrvSRPBytesA{}
+               val := l.CheckTable(3)
+               readSliceByte(l, l.GetField(val, "a"), &ptr.A)
+               readBool(l, l.GetField(val, "no_sha1"), &ptr.NoSHA1)
+               return ptr
+       case "srp_bytes_m":
+               ptr := &mt.ToSrvSRPBytesM{}
+               val := l.CheckTable(3)
+               readSliceByte(l, l.GetField(val, "m"), &ptr.M)
+               return ptr
+       }
+
+       panic("invalid packet type: " + str)
+}
diff --git a/convert/read_mkauto.lua b/convert/read_mkauto.lua
new file mode 100755 (executable)
index 0000000..f749f99
--- /dev/null
@@ -0,0 +1,198 @@
+#!/usr/bin/env lua
+require("spec")
+
+local readers = {
+       SliceByte = true,
+       Byte = true,
+       String = true,
+       SliceField = true,
+       Field = true,
+       Bool = true,
+       PointedThing = true,
+}
+
+local static_uses = {
+       "[3]int16",
+       "AOID"
+}
+
+local function generate(name)
+       local fnname, index, child, childfn, childtype
+       local type = name
+
+       local open = name:find("%[")
+       local clos = name:find("%]")
+
+       if open == 1 then
+               index = name:sub(open + 1, clos - 1)
+               child = name:sub(clos + 1)
+               childfn, childtype = generate(child)
+               fnname = (index == "" and "Slice" or "Vec" .. index) .. childfn
+
+               type = "[" .. index .. "]" .. childtype
+       else
+               fnname = camel_case(name)
+
+               local c = name:sub(1, 1)
+               if c == c:upper() then
+                        type = "mt." .. name
+               end
+       end
+
+       if not readers[fnname] then
+               local fun = "func read" .. fnname .. "(l *lua.LState, val lua.LValue, ptr *" .. type  .. ") {\n"
+
+               if child then
+                       fun = fun .. "\tif val.Type() != lua.LTTable {\n\t\tpanic(\"invalid value for "
+                               .. name .. ": must be a table\")\n\t}\n"
+
+                       if index == "" then
+                               fun = fun ..
+[[
+       tbl := val.(*lua.LTable)
+       n := tbl.MaxN()
+       *ptr = make(]] .. type .. [[, n)
+       for i := range *ptr {
+               read]] .. childfn .. [[(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+       }
+]]
+                       else
+                               local n = tonumber(index)
+                               for i, v in ipairs({"x", "y", "z"}) do
+                                       if i > n then
+                                               break
+                                       end
+
+                                       fun = fun
+                                               .. "\tread" .. childfn
+                                               .. "(l, l.GetField(val, \"" .. v .. "\"), &(*ptr)[" .. (i - 1) .. "])\n"
+                               end
+                       end
+               else
+                       fun = fun .. "\tif val.Type() != lua.LTNumber {\n\t\tpanic(\"invalid value for "
+                               .. name .. ": must be a number\")\n\t}\n"
+                               .. "\t*ptr = " .. type .. "(val.(lua.LNumber))\n"
+               end
+
+               fun = fun .. "}\n\n"
+
+               readers[fnname] = fun
+       end
+
+       return fnname, type
+end
+
+for _, use in ipairs(static_uses) do
+       generate(use)
+end
+
+local function signature(name, prefix, type)
+       local camel = camel_case(name)
+       return "func read" .. camel .. "(l *lua.LState, val lua.LValue, ptr *" .. prefix .. camel  .. ") {\n"
+end
+
+for name, fields in spairs(parse_spec("server/enum")) do
+       local camel = camel_case(name)
+       local fun = signature(name, "mt.")
+
+       local impl = ""
+       for _, var in ipairs(fields) do
+               local equals = "*ptr = mt." .. apply_prefix(fields, var) .. "\n"
+
+               if var == "no" then
+                       fun = fun .. "\tif val.Type() == lua.LTNil {\n\t\t" .. equals .. "\t\treturn\n\t}\n"
+               else
+                       impl = impl .. "\tcase \"" .. var .. "\":\n\t\t" .. equals
+               end
+       end
+
+       fun = fun
+               .. "\tif val.Type() != lua.LTString {\n\t\tpanic(\"invalid value for "
+               .. camel .. ": must be a string\")\n\t}\n"
+               .. "\tstr := string(val.(lua.LString))\n"
+               .. "\tswitch str {\n" .. impl
+               .. "\tdefault:\n\t\tpanic(\"invalid value for " .. name .. ": \" + str)\n\t}\n}\n\n"
+
+       readers[camel] = fun
+end
+
+for name, fields in spairs(parse_spec("server/flag")) do
+       local camel = camel_case(name)
+       local fun = signature(name, "mt.")
+               .. "\tif val.Type() != lua.LTTable {\n\t\tpanic(\"invalid value for "
+               .. camel .. ": must be a table\")\n\t}\n"
+
+       for _, var in ipairs(fields) do
+               fun = fun .. "\tif l.GetField(val, \"" .. var .. "\") == lua.LTrue {\n"
+                       .. "\t\t*ptr = *ptr | mt." .. apply_prefix(fields, var) .. "\n\t}\n"
+       end
+
+       fun = fun .. "}\n\n"
+       readers[camel] = fun
+end
+
+local function fields_fromlua(fields, indent)
+       local impl = ""
+
+       for name, type in spairs(fields) do
+               impl = impl .. indent .. "read" .. generate(type) .. "(l, l.GetField(val, \"" .. name .. "\"), &ptr."
+                       .. camel_case(name) .. ")\n"
+       end
+
+       return impl
+end
+
+for name, fields in spairs(parse_spec("server/struct", true)) do
+       local camel = camel_case(name)
+       readers[camel] = signature(name, "mt.")
+               .. "\tif val.Type() != lua.LTTable {\n"
+               .. "\t\tpanic(\"invalid value for " .. camel .. ": must be a table\")\n\t}\n"
+               .. fields_fromlua(fields, "\t")
+               .. "}\n\n"
+end
+
+local pkt_impl = ""
+
+for name, fields in spairs(parse_spec("server/pkt", true)) do
+       pkt_impl = pkt_impl
+               .. "\tcase \"" .. name .. "\"" .. "" .. ":\n"
+               .. "\t\tptr := &mt.ToSrv" .. camel_case(name) .. "{}\n"
+
+       if next(fields) then
+               pkt_impl = pkt_impl
+                       .. "\t\tval := l.CheckTable(3)\n"
+                       .. fields_fromlua(fields, "\t\t")
+       end
+
+       pkt_impl = pkt_impl
+               .. "\t\treturn ptr\n"
+end
+
+local funcs = ""
+for _, fn in spairs(readers) do
+       if type(fn) == "string" then
+               funcs = funcs .. fn
+       end
+end
+
+local f = io.open("read_auto.go", "w")
+f:write([[
+// generated by read_mkauto.lua, DO NOT EDIT
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+)
+
+]] .. funcs .. [[
+func ReadCmd(l *lua.LState) mt.Cmd {
+       str := l.CheckString(2)
+       switch str {
+]] .. pkt_impl .. [[
+       }
+
+       panic("invalid packet type: " + str)
+}
+]])
+f:close()
diff --git a/convert/read_static.go b/convert/read_static.go
new file mode 100644 (file)
index 0000000..2f62473
--- /dev/null
@@ -0,0 +1,59 @@
+package convert
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/yuin/gopher-lua"
+)
+
+//go:generate ./read_mkauto.lua
+
+func readBool(l *lua.LState, val lua.LValue, ptr *bool) {
+       if val.Type() != lua.LTBool {
+               panic("invalid value for bool: must be a boolean")
+       }
+       *ptr = bool(val.(lua.LBool))
+}
+
+func readString(l *lua.LState, val lua.LValue, ptr *string) {
+       if val.Type() != lua.LTString {
+               panic("invalid value for string: must be a string")
+       }
+       *ptr = string(val.(lua.LString))
+}
+
+func readSliceByte(l *lua.LState, val lua.LValue, ptr *[]byte) {
+       if val.Type() != lua.LTString {
+               panic("invalid value for []byte: must be a string")
+       }
+       *ptr = []byte(val.(lua.LString))
+}
+
+func readSliceField(l *lua.LState, val lua.LValue, ptr *[]mt.Field) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for []Field: must be a table")
+       }
+       val.(*lua.LTable).ForEach(func(k, v lua.LValue) {
+               if k.Type() != lua.LTString || v.Type() != lua.LTString {
+                       panic("invalid value for Field: key and value must be strings")
+               }
+               *ptr = append(*ptr, mt.Field{Name: string(k.(lua.LString)), Value: string(v.(lua.LString))})
+       })
+}
+
+func readPointedThing(l *lua.LState, val lua.LValue, ptr *mt.PointedThing) {
+       if val.Type() != lua.LTTable {
+               panic("invalid value for PointedThing: must be a table")
+       }
+       id := l.GetField(val, "id")
+
+       if id == lua.LNil {
+               pt := &mt.PointedAO{}
+               readAOID(l, id, &(*pt).ID)
+               *ptr = pt
+       } else {
+               pt := &mt.PointedNode{}
+               readVec3Int16(l, l.GetField(val, "under"), &(*pt).Under)
+               readVec3Int16(l, l.GetField(val, "above"), &(*pt).Above)
+               *ptr = pt
+       }
+}
diff --git a/convert/spec.lua b/convert/spec.lua
new file mode 100644 (file)
index 0000000..588f4d7
--- /dev/null
@@ -0,0 +1,108 @@
+local function snext(t, state)
+       local key
+
+       if state == nil then
+               t.__sorted = {}
+               for k in pairs(t) do
+                       if k ~= "__sorted" then
+                               table.insert(t.__sorted, k)
+                       end
+               end
+               table.sort(t.__sorted)
+
+               key = t.__sorted[1]
+       else
+               for i, v in ipairs(t.__sorted) do
+                       if v == state then
+                               key = t.__sorted[i + 1]
+                               break
+                       end
+               end
+       end
+
+       if key then
+               return key, t[key]
+       end
+
+       t.__sorted = nil
+end
+
+function spairs(t)
+       return snext, t, nil
+end
+
+local function parse_pair(pair, value_first)
+       if pair:sub(1, 1) == "#" then
+               return
+       end
+
+       local idx = pair:find(" ")
+
+       if idx then
+               local first, second = pair:sub(1, idx - 1), pair:sub(idx + 1)
+
+               if value_first and first:sub(1, 1) ~= "{" then
+                       return second, first
+               else
+                       return first, second
+               end
+       else
+               return pair
+       end
+end
+
+function parse_spec(name, value_first)
+       local f = io.open("../spec/" .. name, "r")
+       local spec = {}
+       local top
+
+       for l in f:lines() do
+               if l:sub(1, 1) == "\t" then
+                       local key, val = parse_pair(l:sub(2), value_first)
+
+                       if val then
+                               top[key] = val
+                       elseif key then
+                               table.insert(top, key)
+                       end
+               else
+                       local key, val = parse_pair(l, value_first)
+
+                       if val then
+                               spec[key] = val
+                       elseif key then
+                               top = {}
+                               spec[key] = top
+                       end
+               end
+       end
+
+       f:close()
+       return spec
+end
+
+local casemap = parse_spec("casemap")
+
+function camel_case(snake)
+       if casemap[snake] then
+               return casemap[snake]
+       end
+
+       local camel = ""
+
+       while #snake > 0 do
+               local idx = snake:find("_") or #snake + 1
+
+               camel = camel
+                       .. snake:sub(1, 1):upper()
+                       .. snake:sub(2, idx - 1)
+
+               snake = snake:sub(idx + 1)
+       end
+
+       return camel
+end
+
+function apply_prefix(fields, str)
+       return (fields.prefix or "") .. camel_case(str) .. (fields.postfix or "")
+end
diff --git a/fromlua/generate.lua b/fromlua/generate.lua
deleted file mode 100755 (executable)
index 75899b7..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-#!/usr/bin/env lua
-dofile("../parse_spec.lua")
-
-local readers = {
-       SliceByte = true,
-       Byte = true,
-       String = true,
-       SliceField = true,
-       Field = true,
-       Bool = true,
-       PointedThing = true,
-}
-
-local static_uses = {
-       "[3]int16",
-       "AOID"
-}
-
-local function generate(name)
-       local fnname, index, child, childfn, childtype
-       local type = name
-
-       local open = name:find("%[")
-       local clos = name:find("%]")
-
-       if open == 1 then
-               index = name:sub(open + 1, clos - 1)
-               child = name:sub(clos + 1)
-               childfn, childtype = generate(child)
-               fnname = (index == "" and "Slice" or "Vec" .. index) .. childfn
-
-               type = "[" .. index .. "]" .. childtype
-       else
-               fnname = camel_case(name)
-
-               local c = name:sub(1, 1)
-               if c == c:upper() then
-                        type = "mt." .. name
-               end
-       end
-
-       if not readers[fnname] then
-               local fun = "func read" .. fnname .. "(l *lua.LState, val lua.LValue, ptr *" .. type  .. ") {\n"
-
-               if child then
-                       fun = fun .. "\tif val.Type() != lua.LTTable {\n\t\tpanic(\"invalid value for "
-                               .. name .. ": must be a table\")\n\t}\n"
-
-                       if index == "" then
-                               fun = fun ..
-[[
-       tbl := val.(*lua.LTable)
-       n := tbl.MaxN()
-       *ptr = make(]] .. type .. [[, n)
-       for i := range *ptr {
-               read]] .. childfn .. [[(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
-       }
-]]
-                       else
-                               local n = tonumber(index)
-                               for i, v in ipairs({"x", "y", "z"}) do
-                                       if i > n then
-                                               break
-                                       end
-
-                                       fun = fun
-                                               .. "\tread" .. childfn
-                                               .. "(l, l.GetField(val, \"" .. v .. "\"), &(*ptr)[" .. (i - 1) .. "])\n"
-                               end
-                       end
-               else
-                       fun = fun .. "\tif val.Type() != lua.LTNumber {\n\t\tpanic(\"invalid value for "
-                               .. name .. ": must be a number\")\n\t}\n"
-                               .. "\t*ptr = " .. type .. "(val.(lua.LNumber))\n"
-               end
-
-               fun = fun .. "}\n\n"
-
-               readers[fnname] = fun
-       end
-
-       return fnname, type
-end
-
-for _, use in ipairs(static_uses) do
-       generate(use)
-end
-
-local function signature(name, prefix, type)
-       local camel = camel_case(name)
-       return "func read" .. camel .. "(l *lua.LState, val lua.LValue, ptr *" .. prefix .. camel  .. ") {\n"
-end
-
-for name, fields in spairs(parse_spec("server/enum")) do
-       local camel = camel_case(name)
-       local fun = signature(name, "mt.")
-
-       local impl = ""
-       for _, var in ipairs(fields) do
-               local equals = "*ptr = mt." .. apply_prefix(fields, var) .. "\n"
-
-               if var == "no" then
-                       fun = fun .. "\tif val.Type() == lua.LTNil {\n\t\t" .. equals .. "\t\treturn\n\t}\n"
-               else
-                       impl = impl .. "\tcase \"" .. var .. "\":\n\t\t" .. equals
-               end
-       end
-
-       fun = fun
-               .. "\tif val.Type() != lua.LTString {\n\t\tpanic(\"invalid value for "
-               .. camel .. ": must be a string\")\n\t}\n"
-               .. "\tstr := string(val.(lua.LString))\n"
-               .. "\tswitch str {\n" .. impl
-               .. "\tdefault:\n\t\tpanic(\"invalid value for " .. name .. ": \" + str)\n\t}\n}\n\n"
-
-       readers[camel] = fun
-end
-
-for name, fields in spairs(parse_spec("server/flag")) do
-       local camel = camel_case(name)
-       local fun = signature(name, "mt.")
-               .. "\tif val.Type() != lua.LTTable {\n\t\tpanic(\"invalid value for "
-               .. camel .. ": must be a table\")\n\t}\n"
-
-       for _, var in ipairs(fields) do
-               fun = fun .. "\tif l.GetField(val, \"" .. var .. "\") == lua.LTrue {\n"
-                       .. "\t\t*ptr = *ptr | mt." .. apply_prefix(fields, var) .. "\n\t}\n"
-       end
-
-       fun = fun .. "}\n\n"
-       readers[camel] = fun
-end
-
-local function fields_fromlua(fields, indent)
-       local impl = ""
-
-       for name, type in spairs(fields) do
-               impl = impl .. indent .. "read" .. generate(type) .. "(l, l.GetField(val, \"" .. name .. "\"), &ptr."
-                       .. camel_case(name) .. ")\n"
-       end
-
-       return impl
-end
-
-for name, fields in spairs(parse_spec("server/struct", true)) do
-       local camel = camel_case(name)
-       readers[camel] = signature(name, "mt.")
-               .. "\tif val.Type() != lua.LTTable {\n"
-               .. "\t\tpanic(\"invalid value for " .. camel .. ": must be a table\")\n\t}\n"
-               .. fields_fromlua(fields, "\t")
-               .. "}\n\n"
-end
-
-local pkt_impl = ""
-
-for name, fields in spairs(parse_spec("server/pkt", true)) do
-       pkt_impl = pkt_impl
-               .. "\tcase \"" .. name .. "\"" .. "" .. ":\n"
-               .. "\t\tptr := &mt.ToSrv" .. camel_case(name) .. "{}\n"
-
-       if next(fields) then
-               pkt_impl = pkt_impl
-                       .. "\t\tval := l.CheckTable(3)\n"
-                       .. fields_fromlua(fields, "\t\t")
-       end
-
-       pkt_impl = pkt_impl
-               .. "\t\treturn ptr\n"
-end
-
-local funcs = ""
-for _, fn in spairs(readers) do
-       if type(fn) == "string" then
-               funcs = funcs .. fn
-       end
-end
-
-local f = io.open("generated.go", "w")
-f:write([[
-// generated by generate.lua, DO NOT EDIT
-package fromlua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-)
-
-]] .. funcs .. [[
-func Cmd(l *lua.LState) mt.Cmd {
-       str := l.CheckString(2)
-       switch str {
-]] .. pkt_impl .. [[
-       }
-
-       panic("invalid packet type: " + str)
-}
-]])
-f:close()
diff --git a/fromlua/generated.go b/fromlua/generated.go
deleted file mode 100644 (file)
index c93c229..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-// generated by generate.lua, DO NOT EDIT
-package fromlua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-)
-
-func readAOID(l *lua.LState, val lua.LValue, ptr *mt.AOID) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for AOID: must be a number")
-       }
-       *ptr = mt.AOID(val.(lua.LNumber))
-}
-
-func readCompressionModes(l *lua.LState, val lua.LValue, ptr *mt.CompressionModes) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for CompressionModes: must be a number")
-       }
-       *ptr = mt.CompressionModes(val.(lua.LNumber))
-}
-
-func readInt16(l *lua.LState, val lua.LValue, ptr *int16) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for int16: must be a number")
-       }
-       *ptr = int16(val.(lua.LNumber))
-}
-
-func readInt32(l *lua.LState, val lua.LValue, ptr *int32) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for int32: must be a number")
-       }
-       *ptr = int32(val.(lua.LNumber))
-}
-
-func readInteraction(l *lua.LState, val lua.LValue, ptr *mt.Interaction) {
-       if val.Type() != lua.LTString {
-               panic("invalid value for Interaction: must be a string")
-       }
-       str := string(val.(lua.LString))
-       switch str {
-       case "dig":
-               *ptr = mt.Dig
-       case "stop_digging":
-               *ptr = mt.StopDigging
-       case "dug":
-               *ptr = mt.Dug
-       case "place":
-               *ptr = mt.Place
-       case "use":
-               *ptr = mt.Use
-       case "activate":
-               *ptr = mt.Activate
-       default:
-               panic("invalid value for interaction: " + str)
-       }
-}
-
-func readKeys(l *lua.LState, val lua.LValue, ptr *mt.Keys) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for Keys: must be a table")
-       }
-       if l.GetField(val, "forward") == lua.LTrue {
-               *ptr = *ptr | mt.ForwardKey
-       }
-       if l.GetField(val, "backward") == lua.LTrue {
-               *ptr = *ptr | mt.BackwardKey
-       }
-       if l.GetField(val, "left") == lua.LTrue {
-               *ptr = *ptr | mt.LeftKey
-       }
-       if l.GetField(val, "right") == lua.LTrue {
-               *ptr = *ptr | mt.RightKey
-       }
-       if l.GetField(val, "jump") == lua.LTrue {
-               *ptr = *ptr | mt.JumpKey
-       }
-       if l.GetField(val, "special") == lua.LTrue {
-               *ptr = *ptr | mt.SpecialKey
-       }
-       if l.GetField(val, "sneak") == lua.LTrue {
-               *ptr = *ptr | mt.SneakKey
-       }
-       if l.GetField(val, "dig") == lua.LTrue {
-               *ptr = *ptr | mt.DigKey
-       }
-       if l.GetField(val, "place") == lua.LTrue {
-               *ptr = *ptr | mt.PlaceKey
-       }
-       if l.GetField(val, "zoom") == lua.LTrue {
-               *ptr = *ptr | mt.ZoomKey
-       }
-}
-
-func readPlayerPos(l *lua.LState, val lua.LValue, ptr *mt.PlayerPos) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for PlayerPos: must be a table")
-       }
-       readUint8(l, l.GetField(val, "fov80"), &ptr.FOV80)
-       readKeys(l, l.GetField(val, "keys"), &ptr.Keys)
-       readInt32(l, l.GetField(val, "pitch100"), &ptr.Pitch100)
-       readVec3Int32(l, l.GetField(val, "pos100"), &ptr.Pos100)
-       readVec3Int32(l, l.GetField(val, "vel100"), &ptr.Vel100)
-       readUint8(l, l.GetField(val, "wanted_range"), &ptr.WantedRange)
-       readInt32(l, l.GetField(val, "yaw100"), &ptr.Yaw100)
-}
-
-func readSliceSoundID(l *lua.LState, val lua.LValue, ptr *[]mt.SoundID) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for []SoundID: must be a table")
-       }
-       tbl := val.(*lua.LTable)
-       n := tbl.MaxN()
-       *ptr = make([]mt.SoundID, n)
-       for i := range *ptr {
-               readSoundID(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
-       }
-}
-
-func readSliceString(l *lua.LState, val lua.LValue, ptr *[]string) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for []string: must be a table")
-       }
-       tbl := val.(*lua.LTable)
-       n := tbl.MaxN()
-       *ptr = make([]string, n)
-       for i := range *ptr {
-               readString(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
-       }
-}
-
-func readSliceVec3Int16(l *lua.LState, val lua.LValue, ptr *[][3]int16) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for [][3]int16: must be a table")
-       }
-       tbl := val.(*lua.LTable)
-       n := tbl.MaxN()
-       *ptr = make([][3]int16, n)
-       for i := range *ptr {
-               readVec3Int16(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
-       }
-}
-
-func readSoundID(l *lua.LState, val lua.LValue, ptr *mt.SoundID) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for SoundID: must be a number")
-       }
-       *ptr = mt.SoundID(val.(lua.LNumber))
-}
-
-func readUint16(l *lua.LState, val lua.LValue, ptr *uint16) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for uint16: must be a number")
-       }
-       *ptr = uint16(val.(lua.LNumber))
-}
-
-func readUint8(l *lua.LState, val lua.LValue, ptr *uint8) {
-       if val.Type() != lua.LTNumber {
-               panic("invalid value for uint8: must be a number")
-       }
-       *ptr = uint8(val.(lua.LNumber))
-}
-
-func readVec3Int16(l *lua.LState, val lua.LValue, ptr *[3]int16) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for [3]int16: must be a table")
-       }
-       readInt16(l, l.GetField(val, "x"), &(*ptr)[0])
-       readInt16(l, l.GetField(val, "y"), &(*ptr)[1])
-       readInt16(l, l.GetField(val, "z"), &(*ptr)[2])
-}
-
-func readVec3Int32(l *lua.LState, val lua.LValue, ptr *[3]int32) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for [3]int32: must be a table")
-       }
-       readInt32(l, l.GetField(val, "x"), &(*ptr)[0])
-       readInt32(l, l.GetField(val, "y"), &(*ptr)[1])
-       readInt32(l, l.GetField(val, "z"), &(*ptr)[2])
-}
-
-func Cmd(l *lua.LState) mt.Cmd {
-       str := l.CheckString(2)
-       switch str {
-       case "chat_msg":
-               ptr := &mt.ToSrvChatMsg{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "msg"), &ptr.Msg)
-               return ptr
-       case "clt_ready":
-               ptr := &mt.ToSrvCltReady{}
-               val := l.CheckTable(3)
-               readUint16(l, l.GetField(val, "formspec"), &ptr.Formspec)
-               readUint8(l, l.GetField(val, "major"), &ptr.Major)
-               readUint8(l, l.GetField(val, "minor"), &ptr.Minor)
-               readUint8(l, l.GetField(val, "patch"), &ptr.Patch)
-               readString(l, l.GetField(val, "version"), &ptr.Version)
-               return ptr
-       case "deleted_blks":
-               ptr := &mt.ToSrvDeletedBlks{}
-               val := l.CheckTable(3)
-               readSliceVec3Int16(l, l.GetField(val, "blks"), &ptr.Blks)
-               return ptr
-       case "fall_dmg":
-               ptr := &mt.ToSrvFallDmg{}
-               val := l.CheckTable(3)
-               readUint16(l, l.GetField(val, "amount"), &ptr.Amount)
-               return ptr
-       case "first_srp":
-               ptr := &mt.ToSrvFirstSRP{}
-               val := l.CheckTable(3)
-               readBool(l, l.GetField(val, "empty_passwd"), &ptr.EmptyPasswd)
-               readSliceByte(l, l.GetField(val, "salt"), &ptr.Salt)
-               readSliceByte(l, l.GetField(val, "verifier"), &ptr.Verifier)
-               return ptr
-       case "got_blks":
-               ptr := &mt.ToSrvGotBlks{}
-               val := l.CheckTable(3)
-               readSliceVec3Int16(l, l.GetField(val, "blks"), &ptr.Blks)
-               return ptr
-       case "init":
-               ptr := &mt.ToSrvInit{}
-               val := l.CheckTable(3)
-               readUint16(l, l.GetField(val, "max_proto_ver"), &ptr.MaxProtoVer)
-               readUint16(l, l.GetField(val, "min_proto_ver"), &ptr.MinProtoVer)
-               readString(l, l.GetField(val, "player_name"), &ptr.PlayerName)
-               readBool(l, l.GetField(val, "send_full_item_meta"), &ptr.SendFullItemMeta)
-               readUint8(l, l.GetField(val, "serialize_ver"), &ptr.SerializeVer)
-               readCompressionModes(l, l.GetField(val, "supported_compression"), &ptr.SupportedCompression)
-               return ptr
-       case "init2":
-               ptr := &mt.ToSrvInit2{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "lang"), &ptr.Lang)
-               return ptr
-       case "interact":
-               ptr := &mt.ToSrvInteract{}
-               val := l.CheckTable(3)
-               readInteraction(l, l.GetField(val, "action"), &ptr.Action)
-               readUint16(l, l.GetField(val, "item_slot"), &ptr.ItemSlot)
-               readPointedThing(l, l.GetField(val, "pointed"), &ptr.Pointed)
-               readPlayerPos(l, l.GetField(val, "pos"), &ptr.Pos)
-               return ptr
-       case "inv_action":
-               ptr := &mt.ToSrvInvAction{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "action"), &ptr.Action)
-               return ptr
-       case "inv_fields":
-               ptr := &mt.ToSrvInvFields{}
-               val := l.CheckTable(3)
-               readSliceField(l, l.GetField(val, "fields"), &ptr.Fields)
-               readString(l, l.GetField(val, "formname"), &ptr.Formname)
-               return ptr
-       case "join_mod_chan":
-               ptr := &mt.ToSrvJoinModChan{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "channel"), &ptr.Channel)
-               return ptr
-       case "leave_mod_chan":
-               ptr := &mt.ToSrvLeaveModChan{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "channel"), &ptr.Channel)
-               return ptr
-       case "msg_mod_chan":
-               ptr := &mt.ToSrvMsgModChan{}
-               val := l.CheckTable(3)
-               readString(l, l.GetField(val, "channel"), &ptr.Channel)
-               readString(l, l.GetField(val, "msg"), &ptr.Msg)
-               return ptr
-       case "nil":
-               ptr := &mt.ToSrvNil{}
-               return ptr
-       case "node_meta_fields":
-               ptr := &mt.ToSrvNodeMetaFields{}
-               val := l.CheckTable(3)
-               readSliceField(l, l.GetField(val, "fields"), &ptr.Fields)
-               readString(l, l.GetField(val, "formname"), &ptr.Formname)
-               readVec3Int16(l, l.GetField(val, "pos"), &ptr.Pos)
-               return ptr
-       case "player_pos":
-               ptr := &mt.ToSrvPlayerPos{}
-               val := l.CheckTable(3)
-               readPlayerPos(l, l.GetField(val, "pos"), &ptr.Pos)
-               return ptr
-       case "removed_sounds":
-               ptr := &mt.ToSrvRemovedSounds{}
-               val := l.CheckTable(3)
-               readSliceSoundID(l, l.GetField(val, "ids"), &ptr.IDs)
-               return ptr
-       case "req_media":
-               ptr := &mt.ToSrvReqMedia{}
-               val := l.CheckTable(3)
-               readSliceString(l, l.GetField(val, "filenames"), &ptr.Filenames)
-               return ptr
-       case "respawn":
-               ptr := &mt.ToSrvRespawn{}
-               return ptr
-       case "select_item":
-               ptr := &mt.ToSrvSelectItem{}
-               val := l.CheckTable(3)
-               readUint16(l, l.GetField(val, "slot"), &ptr.Slot)
-               return ptr
-       case "srp_bytes_a":
-               ptr := &mt.ToSrvSRPBytesA{}
-               val := l.CheckTable(3)
-               readSliceByte(l, l.GetField(val, "a"), &ptr.A)
-               readBool(l, l.GetField(val, "no_sha1"), &ptr.NoSHA1)
-               return ptr
-       case "srp_bytes_m":
-               ptr := &mt.ToSrvSRPBytesM{}
-               val := l.CheckTable(3)
-               readSliceByte(l, l.GetField(val, "m"), &ptr.M)
-               return ptr
-       }
-
-       panic("invalid packet type: " + str)
-}
diff --git a/fromlua/static.go b/fromlua/static.go
deleted file mode 100644 (file)
index b989db8..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package fromlua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-)
-
-//go:generate ./generate.lua
-
-func readBool(l *lua.LState, val lua.LValue, ptr *bool) {
-       if val.Type() != lua.LTBool {
-               panic("invalid value for bool: must be a boolean")
-       }
-       *ptr = bool(val.(lua.LBool))
-}
-
-func readString(l *lua.LState, val lua.LValue, ptr *string) {
-       if val.Type() != lua.LTString {
-               panic("invalid value for string: must be a string")
-       }
-       *ptr = string(val.(lua.LString))
-}
-
-func readSliceByte(l *lua.LState, val lua.LValue, ptr *[]byte) {
-       if val.Type() != lua.LTString {
-               panic("invalid value for []byte: must be a string")
-       }
-       *ptr = []byte(val.(lua.LString))
-}
-
-func readSliceField(l *lua.LState, val lua.LValue, ptr *[]mt.Field) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for []Field: must be a table")
-       }
-       val.(*lua.LTable).ForEach(func(k, v lua.LValue) {
-               if k.Type() != lua.LTString || v.Type() != lua.LTString {
-                       panic("invalid value for Field: key and value must be strings")
-               }
-               *ptr = append(*ptr, mt.Field{Name: string(k.(lua.LString)), Value: string(v.(lua.LString))})
-       })
-}
-
-func readPointedThing(l *lua.LState, val lua.LValue, ptr *mt.PointedThing) {
-       if val.Type() != lua.LTTable {
-               panic("invalid value for PointedThing: must be a table")
-       }
-       id := l.GetField(val, "id")
-
-       if id == lua.LNil {
-               pt := &mt.PointedAO{}
-               readAOID(l, id, &(*pt).ID)
-               *ptr = pt
-       } else {
-               pt := &mt.PointedNode{}
-               readVec3Int16(l, l.GetField(val, "under"), &(*pt).Under)
-               readVec3Int16(l, l.GetField(val, "above"), &(*pt).Above)
-               *ptr = pt
-       }
-}
index 2f976e20b4118d0e84ac0c5f64e93ef72311a4cd..009731c2b001f192b167350ace86f2241ba62c33 100644 (file)
--- a/hydra.go
+++ b/hydra.go
@@ -2,7 +2,7 @@ package main
 
 import (
        _ "embed"
-       "github.com/dragonfireclient/hydra-dragonfire/tolua"
+       "github.com/dragonfireclient/hydra-dragonfire/convert"
        "github.com/yuin/gopher-lua"
        "os"
        "os/signal"
@@ -63,7 +63,7 @@ func l_poll(l *lua.LState) int {
        } else {
                l.Push(client.userdata)
        }
-       l.Push(tolua.Pkt(l, pkt))
+       l.Push(convert.PushPkt(l, pkt))
        l.Push(lua.LBool(timeout))
        return 3
 }
diff --git a/parse_spec.lua b/parse_spec.lua
deleted file mode 100644 (file)
index 588f4d7..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-local function snext(t, state)
-       local key
-
-       if state == nil then
-               t.__sorted = {}
-               for k in pairs(t) do
-                       if k ~= "__sorted" then
-                               table.insert(t.__sorted, k)
-                       end
-               end
-               table.sort(t.__sorted)
-
-               key = t.__sorted[1]
-       else
-               for i, v in ipairs(t.__sorted) do
-                       if v == state then
-                               key = t.__sorted[i + 1]
-                               break
-                       end
-               end
-       end
-
-       if key then
-               return key, t[key]
-       end
-
-       t.__sorted = nil
-end
-
-function spairs(t)
-       return snext, t, nil
-end
-
-local function parse_pair(pair, value_first)
-       if pair:sub(1, 1) == "#" then
-               return
-       end
-
-       local idx = pair:find(" ")
-
-       if idx then
-               local first, second = pair:sub(1, idx - 1), pair:sub(idx + 1)
-
-               if value_first and first:sub(1, 1) ~= "{" then
-                       return second, first
-               else
-                       return first, second
-               end
-       else
-               return pair
-       end
-end
-
-function parse_spec(name, value_first)
-       local f = io.open("../spec/" .. name, "r")
-       local spec = {}
-       local top
-
-       for l in f:lines() do
-               if l:sub(1, 1) == "\t" then
-                       local key, val = parse_pair(l:sub(2), value_first)
-
-                       if val then
-                               top[key] = val
-                       elseif key then
-                               table.insert(top, key)
-                       end
-               else
-                       local key, val = parse_pair(l, value_first)
-
-                       if val then
-                               spec[key] = val
-                       elseif key then
-                               top = {}
-                               spec[key] = top
-                       end
-               end
-       end
-
-       f:close()
-       return spec
-end
-
-local casemap = parse_spec("casemap")
-
-function camel_case(snake)
-       if casemap[snake] then
-               return casemap[snake]
-       end
-
-       local camel = ""
-
-       while #snake > 0 do
-               local idx = snake:find("_") or #snake + 1
-
-               camel = camel
-                       .. snake:sub(1, 1):upper()
-                       .. snake:sub(2, idx - 1)
-
-               snake = snake:sub(idx + 1)
-       end
-
-       return camel
-end
-
-function apply_prefix(fields, str)
-       return (fields.prefix or "") .. camel_case(str) .. (fields.postfix or "")
-end
diff --git a/tolua/generate.lua b/tolua/generate.lua
deleted file mode 100755 (executable)
index 3117713..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env lua
-dofile("../parse_spec.lua")
-
-local funcs = ""
-
-for name, fields in spairs(parse_spec("client/enum")) do
-       local camel = camel_case(name)
-       funcs = funcs .. "func " .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\tswitch val {\n"
-
-       for _, var in ipairs(fields) do
-               funcs = funcs .. "\tcase mt." .. apply_prefix(fields, var) .. ":\n\t\t" ..
-                       (var == "no" and "return lua.LNil" or "return lua.LString(\"" .. var .. "\")") .. "\n"
-       end
-
-       funcs = funcs .. "\t}\n\tpanic(\"impossible\")\n\treturn lua.LNil\n}\n\n"
-end
-
-for name, fields in spairs(parse_spec("client/flag")) do
-       local camel = camel_case(name)
-       funcs = funcs .. "func " .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\ttbl := l.NewTable()\n"
-
-       for _, var in ipairs(fields) do
-               funcs = funcs .. "\tif val&mt." .. apply_prefix(fields, var)
-                       .. " != 0 {\n\t\tl.SetField(tbl, \"" .. var  .. "\", lua.LTrue)\n\t}\n"
-       end
-
-       funcs = funcs .. "\treturn tbl\n}\n\n"
-end
-
-local tolua = {
-       string = "lua.LString(string(VAL))",
-       fixed_string = "lua.LString(string(VAL[:]))",
-       boolean = "lua.LBool(VAL)",
-       number = "lua.LNumber(VAL)",
-       vec2 = "Vec2(l, [2]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1])})",
-       vec3 = "Vec3(l, [3]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1]), lua.LNumber(VAL[2])})",
-       box1 = "Box1(l, [2]lua.LNumber{lua.LNumber(VAL[0]), lua.LNumber(VAL[1])})",
-       box2 = "Box2(l, [2][2]lua.LNumber{{lua.LNumber(VAL[0][0]), lua.LNumber(VAL[0][1])}, {lua.LNumber(VAL[1][0]), lua.LNumber(VAL[1][1])}})",
-       box3 = "Box3(l, [2][3]lua.LNumber{{lua.LNumber(VAL[0][0]), lua.LNumber(VAL[0][1]), lua.LNumber(VAL[0][2])}, {lua.LNumber(VAL[1][0]), lua.LNumber(VAL[1][1]), lua.LNumber(VAL[1][2])}})",
-}
-
-local function fields_tolua(fields, indent)
-       local impl = ""
-
-       for name, type in spairs(fields) do
-               if name:sub(1, 1) ~= "{" then
-                       local camel = "val." .. camel_case(name)
-
-                       local idt = indent
-                       local condition = fields["{" .. name .. "}"]
-
-                       if condition then
-                               impl = impl .. indent .. "if " .. condition .. " {\n"
-                               idt = idt .. "\t"
-                       end
-
-                       impl = impl .. idt .. "l.SetField(tbl, \"" .. name .. "\", "
-                       if tolua[type] then
-                               impl = impl .. tolua[type]:gsub("VAL", camel)
-                       else
-                               impl = impl .. camel_case(type) .. "(l, " .. camel .. ")"
-                       end
-                       impl = impl .. ")\n"
-
-                       if condition then
-                               impl = impl .. indent .. "}\n"
-                       end
-               end
-       end
-
-       return impl
-end
-
-for name, fields in spairs(parse_spec("client/struct", true)) do
-       local camel = camel_case(name)
-       funcs = funcs
-               .. "func " .. camel .. "(l *lua.LState, val mt." .. camel .. ") lua.LValue {\n\ttbl := l.NewTable()\n"
-               .. fields_tolua(fields, "\t")
-               .. "\treturn tbl\n}\n\n"
-end
-
-local pkt_type_impl = ""
-local pkt_impl = ""
-
-for name, fields in spairs(parse_spec("client/pkt", true)) do
-       local case = "\tcase *mt.ToClt" .. camel_case(name) .. ":\n"
-
-       pkt_type_impl = pkt_type_impl
-               .. case .. "\t\treturn lua.LString(\"" .. name .. "\")\n"
-
-       if next(fields) then
-               pkt_impl = pkt_impl .. case .. fields_tolua(fields, "\t\t")
-       end
-end
-
-local f = io.open("generated.go", "w")
-f:write([[
-// generated by generate.lua, DO NOT EDIT
-package tolua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-)
-
-]] .. funcs .. [[
-func PktType(pkt *mt.Pkt) lua.LString {
-       switch pkt.Cmd.(type) {
-]] .. pkt_type_impl .. [[
-       }
-       panic("impossible")
-       return ""
-}
-
-func Pkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
-       if pkt == nil {
-               return lua.LNil
-       }
-       tbl := l.NewTable()
-       l.SetField(tbl, "_type", PktType(pkt))
-       switch val := pkt.Cmd.(type) {
-]] .. pkt_impl .. [[
-       }
-       return tbl
-}
-]])
-f:close()
diff --git a/tolua/generated.go b/tolua/generated.go
deleted file mode 100644 (file)
index ec53231..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-// generated by generate.lua, DO NOT EDIT
-package tolua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-)
-
-func AnimType(l *lua.LState, val mt.AnimType) lua.LValue {
-       switch val {
-       case mt.NoAnim:
-               return lua.LNil
-       case mt.VerticalFrameAnim:
-               return lua.LString("vertical_frame")
-       case mt.SpriteSheetAnim:
-               return lua.LString("sprite_sheet")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func ChatMsgType(l *lua.LState, val mt.ChatMsgType) lua.LValue {
-       switch val {
-       case mt.RawMsg:
-               return lua.LString("raw")
-       case mt.NormalMsg:
-               return lua.LString("normal")
-       case mt.AnnounceMsg:
-               return lua.LString("announce")
-       case mt.SysMsg:
-               return lua.LString("sys")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func HotbarParam(l *lua.LState, val mt.HotbarParam) lua.LValue {
-       switch val {
-       case mt.HotbarSize:
-               return lua.LString("size")
-       case mt.HotbarImg:
-               return lua.LString("img")
-       case mt.HotbarSelImg:
-               return lua.LString("sel_img")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func HUDField(l *lua.LState, val mt.HUDField) lua.LValue {
-       switch val {
-       case mt.HUDPos:
-               return lua.LString("pos")
-       case mt.HUDName:
-               return lua.LString("name")
-       case mt.HUDScale:
-               return lua.LString("scale")
-       case mt.HUDText:
-               return lua.LString("text")
-       case mt.HUDNumber:
-               return lua.LString("number")
-       case mt.HUDItem:
-               return lua.LString("item")
-       case mt.HUDDir:
-               return lua.LString("dir")
-       case mt.HUDAlign:
-               return lua.LString("align")
-       case mt.HUDOffset:
-               return lua.LString("offset")
-       case mt.HUDWorldPos:
-               return lua.LString("world_pos")
-       case mt.HUDSize:
-               return lua.LString("size")
-       case mt.HUDZIndex:
-               return lua.LString("z_index")
-       case mt.HUDText2:
-               return lua.LString("text_2")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func HUDType(l *lua.LState, val mt.HUDType) lua.LValue {
-       switch val {
-       case mt.ImgHUD:
-               return lua.LString("img")
-       case mt.TextHUD:
-               return lua.LString("text")
-       case mt.StatbarHUD:
-               return lua.LString("statbar")
-       case mt.InvHUD:
-               return lua.LString("inv")
-       case mt.WaypointHUD:
-               return lua.LString("waypoint")
-       case mt.ImgWaypointHUD:
-               return lua.LString("img_waypoint")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func KickReason(l *lua.LState, val mt.KickReason) lua.LValue {
-       switch val {
-       case mt.WrongPasswd:
-               return lua.LString("wrong_passwd")
-       case mt.UnexpectedData:
-               return lua.LString("unexpected_data")
-       case mt.SrvIsSingleplayer:
-               return lua.LString("srv_is_singleplayer")
-       case mt.UnsupportedVer:
-               return lua.LString("unsupported_ver")
-       case mt.BadNameChars:
-               return lua.LString("bad_name_chars")
-       case mt.BadName:
-               return lua.LString("bad_name")
-       case mt.TooManyClts:
-               return lua.LString("too_many_clts")
-       case mt.EmptyPasswd:
-               return lua.LString("empty_passwd")
-       case mt.AlreadyConnected:
-               return lua.LString("already_connected")
-       case mt.SrvErr:
-               return lua.LString("srv_err")
-       case mt.Custom:
-               return lua.LString("custom")
-       case mt.Shutdown:
-               return lua.LString("shutdown")
-       case mt.Crash:
-               return lua.LString("crash")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func ModChanSig(l *lua.LState, val mt.ModChanSig) lua.LValue {
-       switch val {
-       case mt.JoinOK:
-               return lua.LString("join_ok")
-       case mt.JoinFail:
-               return lua.LString("join_fail")
-       case mt.LeaveOK:
-               return lua.LString("leave_ok")
-       case mt.LeaveFail:
-               return lua.LString("leave_fail")
-       case mt.NotRegistered:
-               return lua.LString("not_registered")
-       case mt.SetState:
-               return lua.LString("set_state")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func PlayerListUpdateType(l *lua.LState, val mt.PlayerListUpdateType) lua.LValue {
-       switch val {
-       case mt.InitPlayers:
-               return lua.LString("init")
-       case mt.AddPlayers:
-               return lua.LString("add")
-       case mt.RemovePlayers:
-               return lua.LString("remove")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func SoundSrcType(l *lua.LState, val mt.SoundSrcType) lua.LValue {
-       switch val {
-       case mt.NoSrc:
-               return lua.LNil
-       case mt.PosSrc:
-               return lua.LString("pos")
-       case mt.AOSrc:
-               return lua.LString("ao")
-       }
-       panic("impossible")
-       return lua.LNil
-}
-
-func AuthMethods(l *lua.LState, val mt.AuthMethods) lua.LValue {
-       tbl := l.NewTable()
-       if val&mt.LegacyPasswd != 0 {
-               l.SetField(tbl, "legacy_passwd", lua.LTrue)
-       }
-       if val&mt.SRP != 0 {
-               l.SetField(tbl, "srp", lua.LTrue)
-       }
-       if val&mt.FirstSRP != 0 {
-               l.SetField(tbl, "first_srp", lua.LTrue)
-       }
-       return tbl
-}
-
-func CSMRestrictionFlags(l *lua.LState, val mt.CSMRestrictionFlags) lua.LValue {
-       tbl := l.NewTable()
-       if val&mt.NoCSMs != 0 {
-               l.SetField(tbl, "no_csms", lua.LTrue)
-       }
-       if val&mt.NoChatMsgs != 0 {
-               l.SetField(tbl, "no_chat_msgs", lua.LTrue)
-       }
-       if val&mt.NoNodeDefs != 0 {
-               l.SetField(tbl, "no_node_defs", lua.LTrue)
-       }
-       if val&mt.LimitMapRange != 0 {
-               l.SetField(tbl, "limit_map_range", lua.LTrue)
-       }
-       if val&mt.NoPlayerList != 0 {
-               l.SetField(tbl, "no_player_list", lua.LTrue)
-       }
-       return tbl
-}
-
-func HUDFlags(l *lua.LState, val mt.HUDFlags) lua.LValue {
-       tbl := l.NewTable()
-       if val&mt.ShowHotbar != 0 {
-               l.SetField(tbl, "hotbar", lua.LTrue)
-       }
-       if val&mt.ShowHealthBar != 0 {
-               l.SetField(tbl, "health_bar", lua.LTrue)
-       }
-       if val&mt.ShowCrosshair != 0 {
-               l.SetField(tbl, "crosshair", lua.LTrue)
-       }
-       if val&mt.ShowWieldedItem != 0 {
-               l.SetField(tbl, "wielded_item", lua.LTrue)
-       }
-       if val&mt.ShowBreathBar != 0 {
-               l.SetField(tbl, "breath_bar", lua.LTrue)
-       }
-       if val&mt.ShowMinimap != 0 {
-               l.SetField(tbl, "minimap", lua.LTrue)
-       }
-       if val&mt.ShowRadarMinimap != 0 {
-               l.SetField(tbl, "radar_minimap", lua.LTrue)
-       }
-       return tbl
-}
-
-func HUD(l *lua.LState, val mt.HUD) lua.LValue {
-       tbl := l.NewTable()
-       l.SetField(tbl, "align", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Align[0]), lua.LNumber(val.Align[1])}))
-       l.SetField(tbl, "dir", lua.LNumber(val.Dir))
-       l.SetField(tbl, "item", lua.LNumber(val.Item))
-       l.SetField(tbl, "name", lua.LString(string(val.Name)))
-       l.SetField(tbl, "number", lua.LNumber(val.Number))
-       l.SetField(tbl, "offset", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Offset[0]), lua.LNumber(val.Offset[1])}))
-       l.SetField(tbl, "pos", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1])}))
-       l.SetField(tbl, "scale", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Scale[0]), lua.LNumber(val.Scale[1])}))
-       l.SetField(tbl, "size", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
-       l.SetField(tbl, "text", lua.LString(string(val.Text)))
-       l.SetField(tbl, "text_2", lua.LString(string(val.Text2)))
-       l.SetField(tbl, "type", HUDType(l, val.Type))
-       l.SetField(tbl, "world_pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.WorldPos[0]), lua.LNumber(val.WorldPos[1]), lua.LNumber(val.WorldPos[2])}))
-       l.SetField(tbl, "z_index", lua.LNumber(val.ZIndex))
-       return tbl
-}
-
-func Node(l *lua.LState, val mt.Node) lua.LValue {
-       tbl := l.NewTable()
-       l.SetField(tbl, "param0", lua.LNumber(val.Param0))
-       l.SetField(tbl, "param1", lua.LNumber(val.Param1))
-       l.SetField(tbl, "param2", lua.LNumber(val.Param2))
-       return tbl
-}
-
-func TileAnim(l *lua.LState, val mt.TileAnim) lua.LValue {
-       tbl := l.NewTable()
-       l.SetField(tbl, "aspect_ratio", Vec2(l, [2]lua.LNumber{lua.LNumber(val.AspectRatio[0]), lua.LNumber(val.AspectRatio[1])}))
-       l.SetField(tbl, "duration", lua.LNumber(val.Duration))
-       l.SetField(tbl, "n_frames", Vec2(l, [2]lua.LNumber{lua.LNumber(val.NFrames[0]), lua.LNumber(val.NFrames[1])}))
-       l.SetField(tbl, "type", AnimType(l, val.Type))
-       return tbl
-}
-
-func PktType(pkt *mt.Pkt) lua.LString {
-       switch pkt.Cmd.(type) {
-       case *mt.ToCltAcceptAuth:
-               return lua.LString("accept_auth")
-       case *mt.ToCltAcceptSudoMode:
-               return lua.LString("accept_sudo_mode")
-       case *mt.ToCltAddHUD:
-               return lua.LString("add_hud")
-       case *mt.ToCltAddNode:
-               return lua.LString("add_node")
-       case *mt.ToCltAddParticleSpawner:
-               return lua.LString("add_particle_spawner")
-       case *mt.ToCltAddPlayerVel:
-               return lua.LString("add_player_vel")
-       case *mt.ToCltAnnounceMedia:
-               return lua.LString("announce_media")
-       case *mt.ToCltAOMsgs:
-               return lua.LString("ao_msgs")
-       case *mt.ToCltAORmAdd:
-               return lua.LString("ao_rm_add")
-       case *mt.ToCltBlkData:
-               return lua.LString("blk_data")
-       case *mt.ToCltBreath:
-               return lua.LString("breath")
-       case *mt.ToCltChangeHUD:
-               return lua.LString("change_hud")
-       case *mt.ToCltChatMsg:
-               return lua.LString("chat_msg")
-       case *mt.ToCltCloudParams:
-               return lua.LString("cloud_params")
-       case *mt.ToCltCSMRestrictionFlags:
-               return lua.LString("csm_restriction_flags")
-       case *mt.ToCltDeathScreen:
-               return lua.LString("death_screen")
-       case *mt.ToCltDelParticleSpawner:
-               return lua.LString("del_particle_spawner")
-       case *mt.ToCltDenySudoMode:
-               return lua.LString("deny_sudo_mode")
-       case *mt.ToCltDetachedInv:
-               return lua.LString("detached_inv")
-       case *mt.ToCltDisco:
-               return lua.LString("disco")
-       case *mt.ToCltEyeOffset:
-               return lua.LString("eye_offset")
-       case *mt.ToCltFadeSound:
-               return lua.LString("fade_sound")
-       case *mt.ToCltFormspecPrepend:
-               return lua.LString("formspec_prepend")
-       case *mt.ToCltFOV:
-               return lua.LString("fov")
-       case *mt.ToCltHello:
-               return lua.LString("hello")
-       case *mt.ToCltHP:
-               return lua.LString("hp")
-       case *mt.ToCltHUDFlags:
-               return lua.LString("hud_flags")
-       case *mt.ToCltInv:
-               return lua.LString("inv")
-       case *mt.ToCltInvFormspec:
-               return lua.LString("inv_formspec")
-       case *mt.ToCltItemDefs:
-               return lua.LString("item_defs")
-       case *mt.ToCltKick:
-               return lua.LString("kick")
-       case *mt.ToCltLegacyKick:
-               return lua.LString("legacy_kick")
-       case *mt.ToCltLocalPlayerAnim:
-               return lua.LString("local_player_anim")
-       case *mt.ToCltMedia:
-               return lua.LString("media")
-       case *mt.ToCltMediaPush:
-               return lua.LString("media_push")
-       case *mt.ToCltMinimapModes:
-               return lua.LString("minimap_modes")
-       case *mt.ToCltModChanMsg:
-               return lua.LString("mod_chan_msg")
-       case *mt.ToCltModChanSig:
-               return lua.LString("mod_chan_sig")
-       case *mt.ToCltMoonParams:
-               return lua.LString("moon_params")
-       case *mt.ToCltMovePlayer:
-               return lua.LString("move_player")
-       case *mt.ToCltMovement:
-               return lua.LString("movement")
-       case *mt.ToCltNodeDefs:
-               return lua.LString("node_defs")
-       case *mt.ToCltNodeMetasChanged:
-               return lua.LString("node_metas_changed")
-       case *mt.ToCltOverrideDayNightRatio:
-               return lua.LString("override_day_night_ratio")
-       case *mt.ToCltPlaySound:
-               return lua.LString("play_sound")
-       case *mt.ToCltPrivs:
-               return lua.LString("privs")
-       case *mt.ToCltRemoveNode:
-               return lua.LString("remove_node")
-       case *mt.ToCltRmHUD:
-               return lua.LString("rm_hud")
-       case *mt.ToCltSetHotbarParam:
-               return lua.LString("set_hotbar_param")
-       case *mt.ToCltShowFormspec:
-               return lua.LString("show_formspec")
-       case *mt.ToCltSkyParams:
-               return lua.LString("sky_params")
-       case *mt.ToCltSpawnParticle:
-               return lua.LString("spawn_particle")
-       case *mt.ToCltSRPBytesSaltB:
-               return lua.LString("srp_bytes_salt_b")
-       case *mt.ToCltStarParams:
-               return lua.LString("star_params")
-       case *mt.ToCltStopSound:
-               return lua.LString("stop_sound")
-       case *mt.ToCltSunParams:
-               return lua.LString("sun_params")
-       case *mt.ToCltTimeOfDay:
-               return lua.LString("time_of_day")
-       case *mt.ToCltUpdatePlayerList:
-               return lua.LString("update_player_list")
-       }
-       panic("impossible")
-       return ""
-}
-
-func Pkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
-       if pkt == nil {
-               return lua.LNil
-       }
-       tbl := l.NewTable()
-       l.SetField(tbl, "_type", PktType(pkt))
-       switch val := pkt.Cmd.(type) {
-       case *mt.ToCltAcceptAuth:
-               l.SetField(tbl, "map_seed", lua.LNumber(val.MapSeed))
-               l.SetField(tbl, "player_pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.PlayerPos[0]), lua.LNumber(val.PlayerPos[1]), lua.LNumber(val.PlayerPos[2])}))
-               l.SetField(tbl, "send_interval", lua.LNumber(val.SendInterval))
-               l.SetField(tbl, "sudo_auth_methods", AuthMethods(l, val.SudoAuthMethods))
-       case *mt.ToCltAddHUD:
-               l.SetField(tbl, "hud", HUD(l, val.HUD))
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-       case *mt.ToCltAddNode:
-               l.SetField(tbl, "keep_meta", lua.LBool(val.KeepMeta))
-               l.SetField(tbl, "node", Node(l, val.Node))
-               l.SetField(tbl, "pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
-       case *mt.ToCltAddParticleSpawner:
-               l.SetField(tbl, "acc", Box3(l, [2][3]lua.LNumber{{lua.LNumber(val.Acc[0][0]), lua.LNumber(val.Acc[0][1]), lua.LNumber(val.Acc[0][2])}, {lua.LNumber(val.Acc[1][0]), lua.LNumber(val.Acc[1][1]), lua.LNumber(val.Acc[1][2])}}))
-               l.SetField(tbl, "amount", lua.LNumber(val.Amount))
-               l.SetField(tbl, "anim_params", TileAnim(l, val.AnimParams))
-               l.SetField(tbl, "ao_collision", lua.LBool(val.AOCollision))
-               l.SetField(tbl, "collide", lua.LBool(val.Collide))
-               l.SetField(tbl, "collision_rm", lua.LBool(val.CollisionRm))
-               l.SetField(tbl, "duration", lua.LNumber(val.Duration))
-               l.SetField(tbl, "expiration_time", Box1(l, [2]lua.LNumber{lua.LNumber(val.ExpirationTime[0]), lua.LNumber(val.ExpirationTime[1])}))
-               l.SetField(tbl, "glow", lua.LNumber(val.Glow))
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-               l.SetField(tbl, "node_param0", lua.LNumber(val.NodeParam0))
-               l.SetField(tbl, "node_param2", lua.LNumber(val.NodeParam2))
-               l.SetField(tbl, "node_tile", lua.LNumber(val.NodeTile))
-               l.SetField(tbl, "pos", Box3(l, [2][3]lua.LNumber{{lua.LNumber(val.Pos[0][0]), lua.LNumber(val.Pos[0][1]), lua.LNumber(val.Pos[0][2])}, {lua.LNumber(val.Pos[1][0]), lua.LNumber(val.Pos[1][1]), lua.LNumber(val.Pos[1][2])}}))
-               l.SetField(tbl, "size", Box1(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
-               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
-               l.SetField(tbl, "vel", Box3(l, [2][3]lua.LNumber{{lua.LNumber(val.Vel[0][0]), lua.LNumber(val.Vel[0][1]), lua.LNumber(val.Vel[0][2])}, {lua.LNumber(val.Vel[1][0]), lua.LNumber(val.Vel[1][1]), lua.LNumber(val.Vel[1][2])}}))
-               l.SetField(tbl, "vertical", lua.LBool(val.Vertical))
-       case *mt.ToCltAddPlayerVel:
-               l.SetField(tbl, "vel", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Vel[0]), lua.LNumber(val.Vel[1]), lua.LNumber(val.Vel[2])}))
-       case *mt.ToCltBlkData:
-               l.SetField(tbl, "blkpos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Blkpos[0]), lua.LNumber(val.Blkpos[1]), lua.LNumber(val.Blkpos[2])}))
-       case *mt.ToCltBreath:
-               l.SetField(tbl, "breath", lua.LNumber(val.Breath))
-       case *mt.ToCltChangeHUD:
-               if val.Field == mt.HUDAlign {
-                       l.SetField(tbl, "align", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Align[0]), lua.LNumber(val.Align[1])}))
-               }
-               if val.Field == mt.HUDDir {
-                       l.SetField(tbl, "dir", lua.LNumber(val.Dir))
-               }
-               l.SetField(tbl, "field", HUDField(l, val.Field))
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-               if val.Field == mt.HUDItem {
-                       l.SetField(tbl, "item", lua.LNumber(val.Item))
-               }
-               if val.Field == mt.HUDName {
-                       l.SetField(tbl, "name", lua.LString(string(val.Name)))
-               }
-               if val.Field == mt.HUDNumber {
-                       l.SetField(tbl, "number", lua.LNumber(val.Number))
-               }
-               if val.Field == mt.HUDOffset {
-                       l.SetField(tbl, "offset", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Offset[0]), lua.LNumber(val.Offset[1])}))
-               }
-               if val.Field == mt.HUDPos {
-                       l.SetField(tbl, "pos", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1])}))
-               }
-               if val.Field == mt.HUDSize {
-                       l.SetField(tbl, "size", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Size[0]), lua.LNumber(val.Size[1])}))
-               }
-               if val.Field == mt.HUDText {
-                       l.SetField(tbl, "text", lua.LString(string(val.Text)))
-               }
-               if val.Field == mt.HUDText2 {
-                       l.SetField(tbl, "text_2", lua.LString(string(val.Text2)))
-               }
-               if val.Field == mt.HUDWorldPos {
-                       l.SetField(tbl, "world_pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.WorldPos[0]), lua.LNumber(val.WorldPos[1]), lua.LNumber(val.WorldPos[2])}))
-               }
-               if val.Field == mt.HUDZIndex {
-                       l.SetField(tbl, "z_index", lua.LNumber(val.ZIndex))
-               }
-       case *mt.ToCltChatMsg:
-               l.SetField(tbl, "sender", lua.LString(string(val.Sender)))
-               l.SetField(tbl, "text", lua.LString(string(val.Text)))
-               l.SetField(tbl, "timestamp", lua.LNumber(val.Timestamp))
-               l.SetField(tbl, "type", ChatMsgType(l, val.Type))
-       case *mt.ToCltCloudParams:
-               l.SetField(tbl, "ambient_color", Color(l, val.AmbientColor))
-               l.SetField(tbl, "density", lua.LNumber(val.Density))
-               l.SetField(tbl, "diffuse_color", Color(l, val.DiffuseColor))
-               l.SetField(tbl, "height", lua.LNumber(val.Height))
-               l.SetField(tbl, "speed", Vec2(l, [2]lua.LNumber{lua.LNumber(val.Speed[0]), lua.LNumber(val.Speed[1])}))
-               l.SetField(tbl, "thickness", lua.LNumber(val.Thickness))
-       case *mt.ToCltCSMRestrictionFlags:
-               l.SetField(tbl, "flags", CSMRestrictionFlags(l, val.Flags))
-               l.SetField(tbl, "map_range", lua.LNumber(val.MapRange))
-       case *mt.ToCltDeathScreen:
-               l.SetField(tbl, "point_at", Vec3(l, [3]lua.LNumber{lua.LNumber(val.PointAt[0]), lua.LNumber(val.PointAt[1]), lua.LNumber(val.PointAt[2])}))
-               l.SetField(tbl, "point_cam", lua.LBool(val.PointCam))
-       case *mt.ToCltDelParticleSpawner:
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-       case *mt.ToCltDetachedInv:
-               l.SetField(tbl, "inv", lua.LString(string(val.Inv)))
-               l.SetField(tbl, "keep", lua.LBool(val.Keep))
-               l.SetField(tbl, "len", lua.LNumber(val.Len))
-               l.SetField(tbl, "name", lua.LString(string(val.Name)))
-       case *mt.ToCltEyeOffset:
-               l.SetField(tbl, "first", Vec3(l, [3]lua.LNumber{lua.LNumber(val.First[0]), lua.LNumber(val.First[1]), lua.LNumber(val.First[2])}))
-               l.SetField(tbl, "third", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Third[0]), lua.LNumber(val.Third[1]), lua.LNumber(val.Third[2])}))
-       case *mt.ToCltFadeSound:
-               l.SetField(tbl, "gain", lua.LNumber(val.Gain))
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-               l.SetField(tbl, "step", lua.LNumber(val.Step))
-       case *mt.ToCltFormspecPrepend:
-               l.SetField(tbl, "prepend", lua.LString(string(val.Prepend)))
-       case *mt.ToCltFOV:
-               l.SetField(tbl, "fov", lua.LNumber(val.FOV))
-               l.SetField(tbl, "multiplier", lua.LBool(val.Multiplier))
-               l.SetField(tbl, "transition_time", lua.LNumber(val.TransitionTime))
-       case *mt.ToCltHello:
-               l.SetField(tbl, "auth_methods", AuthMethods(l, val.AuthMethods))
-               l.SetField(tbl, "compression", lua.LNumber(val.Compression))
-               l.SetField(tbl, "proto_ver", lua.LNumber(val.ProtoVer))
-               l.SetField(tbl, "serialize_ver", lua.LNumber(val.SerializeVer))
-               l.SetField(tbl, "username", lua.LString(string(val.Username)))
-       case *mt.ToCltHP:
-               l.SetField(tbl, "hp", lua.LNumber(val.HP))
-       case *mt.ToCltHUDFlags:
-               l.SetField(tbl, "flags", HUDFlags(l, val.Flags))
-               l.SetField(tbl, "mask", HUDFlags(l, val.Mask))
-       case *mt.ToCltInv:
-               l.SetField(tbl, "inv", lua.LString(string(val.Inv)))
-       case *mt.ToCltInvFormspec:
-               l.SetField(tbl, "formspec", lua.LString(string(val.Formspec)))
-       case *mt.ToCltKick:
-               if val.Reason == mt.Custom || val.Reason == mt.Shutdown || val.Reason == mt.Crash {
-                       l.SetField(tbl, "custom", lua.LString(string(val.Custom)))
-               }
-               l.SetField(tbl, "reason", KickReason(l, val.Reason))
-               if val.Reason == mt.Shutdown || val.Reason == mt.Crash {
-                       l.SetField(tbl, "reconnect", lua.LBool(val.Reconnect))
-               }
-       case *mt.ToCltLegacyKick:
-               l.SetField(tbl, "reason", lua.LString(string(val.Reason)))
-       case *mt.ToCltLocalPlayerAnim:
-               l.SetField(tbl, "dig", Box1(l, [2]lua.LNumber{lua.LNumber(val.Dig[0]), lua.LNumber(val.Dig[1])}))
-               l.SetField(tbl, "idle", Box1(l, [2]lua.LNumber{lua.LNumber(val.Idle[0]), lua.LNumber(val.Idle[1])}))
-               l.SetField(tbl, "speed", lua.LNumber(val.Speed))
-               l.SetField(tbl, "walk", Box1(l, [2]lua.LNumber{lua.LNumber(val.Walk[0]), lua.LNumber(val.Walk[1])}))
-               l.SetField(tbl, "walk_dig", Box1(l, [2]lua.LNumber{lua.LNumber(val.WalkDig[0]), lua.LNumber(val.WalkDig[1])}))
-       case *mt.ToCltMediaPush:
-               l.SetField(tbl, "data", lua.LString(string(val.Data)))
-               l.SetField(tbl, "filename", lua.LString(string(val.Filename)))
-               l.SetField(tbl, "sha1", lua.LString(string(val.SHA1[:])))
-               l.SetField(tbl, "should_cache", lua.LBool(val.ShouldCache))
-       case *mt.ToCltModChanMsg:
-               l.SetField(tbl, "channel", lua.LString(string(val.Channel)))
-               l.SetField(tbl, "msg", lua.LString(string(val.Msg)))
-               l.SetField(tbl, "sender", lua.LString(string(val.Sender)))
-       case *mt.ToCltModChanSig:
-               l.SetField(tbl, "channel", lua.LString(string(val.Channel)))
-               l.SetField(tbl, "signal", ModChanSig(l, val.Signal))
-       case *mt.ToCltMoonParams:
-               l.SetField(tbl, "size", lua.LNumber(val.Size))
-               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
-               l.SetField(tbl, "tone_map", lua.LString(string(val.ToneMap)))
-               l.SetField(tbl, "visible", lua.LBool(val.Visible))
-       case *mt.ToCltMovePlayer:
-               l.SetField(tbl, "pitch", lua.LNumber(val.Pitch))
-               l.SetField(tbl, "pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
-               l.SetField(tbl, "yaw", lua.LNumber(val.Yaw))
-       case *mt.ToCltMovement:
-               l.SetField(tbl, "air_accel", lua.LNumber(val.AirAccel))
-               l.SetField(tbl, "climb_speed", lua.LNumber(val.ClimbSpeed))
-               l.SetField(tbl, "crouch_speed", lua.LNumber(val.CrouchSpeed))
-               l.SetField(tbl, "default_accel", lua.LNumber(val.DefaultAccel))
-               l.SetField(tbl, "fast_accel", lua.LNumber(val.FastAccel))
-               l.SetField(tbl, "fast_speed", lua.LNumber(val.FastSpeed))
-               l.SetField(tbl, "fluidity", lua.LNumber(val.Fluidity))
-               l.SetField(tbl, "gravity", lua.LNumber(val.Gravity))
-               l.SetField(tbl, "jump_speed", lua.LNumber(val.JumpSpeed))
-               l.SetField(tbl, "sink", lua.LNumber(val.Sink))
-               l.SetField(tbl, "smoothing", lua.LNumber(val.Smoothing))
-               l.SetField(tbl, "walk_speed", lua.LNumber(val.WalkSpeed))
-       case *mt.ToCltOverrideDayNightRatio:
-               l.SetField(tbl, "override", lua.LBool(val.Override))
-               l.SetField(tbl, "ratio", lua.LNumber(val.Ratio))
-       case *mt.ToCltPlaySound:
-               l.SetField(tbl, "ephemeral", lua.LBool(val.Ephemeral))
-               l.SetField(tbl, "fade", lua.LNumber(val.Fade))
-               l.SetField(tbl, "gain", lua.LNumber(val.Gain))
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-               l.SetField(tbl, "loop", lua.LBool(val.Loop))
-               l.SetField(tbl, "name", lua.LString(string(val.Name)))
-               l.SetField(tbl, "pitch", lua.LNumber(val.Pitch))
-               l.SetField(tbl, "pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
-               l.SetField(tbl, "src_aoid", lua.LNumber(val.SrcAOID))
-               l.SetField(tbl, "src_type", SoundSrcType(l, val.SrcType))
-       case *mt.ToCltPrivs:
-               l.SetField(tbl, "privs", StringSet(l, val.Privs))
-       case *mt.ToCltRemoveNode:
-               l.SetField(tbl, "pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
-       case *mt.ToCltRmHUD:
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-       case *mt.ToCltSetHotbarParam:
-               l.SetField(tbl, "img", lua.LString(string(val.Img)))
-               l.SetField(tbl, "param", HotbarParam(l, val.Param))
-               l.SetField(tbl, "size", lua.LNumber(val.Size))
-       case *mt.ToCltShowFormspec:
-               l.SetField(tbl, "formname", lua.LString(string(val.Formname)))
-               l.SetField(tbl, "formspec", lua.LString(string(val.Formspec)))
-       case *mt.ToCltSkyParams:
-               l.SetField(tbl, "bg_color", Color(l, val.BgColor))
-               l.SetField(tbl, "clouds", lua.LBool(val.Clouds))
-               if val.Type == "regular" {
-                       l.SetField(tbl, "dawn_horizon", Color(l, val.DawnHorizon))
-               }
-               if val.Type == "regular" {
-                       l.SetField(tbl, "dawn_sky", Color(l, val.DawnSky))
-               }
-               if val.Type == "regular" {
-                       l.SetField(tbl, "day_horizon", Color(l, val.DayHorizon))
-               }
-               if val.Type == "regular" {
-                       l.SetField(tbl, "day_sky", Color(l, val.DaySky))
-               }
-               l.SetField(tbl, "fog_tint_type", lua.LString(string(val.FogTintType)))
-               if val.Type == "regular" {
-                       l.SetField(tbl, "indoor", Color(l, val.Indoor))
-               }
-               l.SetField(tbl, "moon_fog_tint", Color(l, val.MoonFogTint))
-               if val.Type == "regular" {
-                       l.SetField(tbl, "night_horizon", Color(l, val.NightHorizon))
-               }
-               if val.Type == "regular" {
-                       l.SetField(tbl, "night_sky", Color(l, val.NightSky))
-               }
-               l.SetField(tbl, "sun_fog_tint", Color(l, val.SunFogTint))
-               if val.Type == "skybox" {
-                       l.SetField(tbl, "textures", TextureList(l, val.Textures))
-               }
-               l.SetField(tbl, "type", lua.LString(string(val.Type)))
-       case *mt.ToCltSpawnParticle:
-               l.SetField(tbl, "acc", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Acc[0]), lua.LNumber(val.Acc[1]), lua.LNumber(val.Acc[2])}))
-               l.SetField(tbl, "anim_params", TileAnim(l, val.AnimParams))
-               l.SetField(tbl, "ao_collision", lua.LBool(val.AOCollision))
-               l.SetField(tbl, "collide", lua.LBool(val.Collide))
-               l.SetField(tbl, "collision_rm", lua.LBool(val.CollisionRm))
-               l.SetField(tbl, "expiration_time", lua.LNumber(val.ExpirationTime))
-               l.SetField(tbl, "glow", lua.LNumber(val.Glow))
-               l.SetField(tbl, "node_param0", lua.LNumber(val.NodeParam0))
-               l.SetField(tbl, "node_param2", lua.LNumber(val.NodeParam2))
-               l.SetField(tbl, "node_tile", lua.LNumber(val.NodeTile))
-               l.SetField(tbl, "pos", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Pos[0]), lua.LNumber(val.Pos[1]), lua.LNumber(val.Pos[2])}))
-               l.SetField(tbl, "size", lua.LNumber(val.Size))
-               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
-               l.SetField(tbl, "vel", Vec3(l, [3]lua.LNumber{lua.LNumber(val.Vel[0]), lua.LNumber(val.Vel[1]), lua.LNumber(val.Vel[2])}))
-               l.SetField(tbl, "vertical", lua.LBool(val.Vertical))
-       case *mt.ToCltSRPBytesSaltB:
-               l.SetField(tbl, "b", lua.LString(string(val.B)))
-               l.SetField(tbl, "salt", lua.LString(string(val.Salt)))
-       case *mt.ToCltStarParams:
-               l.SetField(tbl, "color", Color(l, val.Color))
-               l.SetField(tbl, "count", lua.LNumber(val.Count))
-               l.SetField(tbl, "size", lua.LNumber(val.Size))
-               l.SetField(tbl, "visible", lua.LBool(val.Visible))
-       case *mt.ToCltStopSound:
-               l.SetField(tbl, "id", lua.LNumber(val.ID))
-       case *mt.ToCltSunParams:
-               l.SetField(tbl, "rise", lua.LString(string(val.Rise)))
-               l.SetField(tbl, "rising", lua.LBool(val.Rising))
-               l.SetField(tbl, "size", lua.LNumber(val.Size))
-               l.SetField(tbl, "texture", lua.LString(string(val.Texture)))
-               l.SetField(tbl, "tone_map", lua.LString(string(val.ToneMap)))
-               l.SetField(tbl, "visible", lua.LBool(val.Visible))
-       case *mt.ToCltTimeOfDay:
-               l.SetField(tbl, "speed", lua.LNumber(val.Speed))
-               l.SetField(tbl, "time", lua.LNumber(val.Time))
-       case *mt.ToCltUpdatePlayerList:
-               l.SetField(tbl, "players", StringList(l, val.Players))
-               l.SetField(tbl, "type", PlayerListUpdateType(l, val.Type))
-       }
-       return tbl
-}
diff --git a/tolua/static.go b/tolua/static.go
deleted file mode 100644 (file)
index 30d56ef..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-package tolua
-
-import (
-       "github.com/anon55555/mt"
-       "github.com/yuin/gopher-lua"
-       "image/color"
-)
-
-//go:generate ./generate.lua
-
-func pushVec2(l *lua.LState, val [2]lua.LNumber) {
-       l.Push(l.GetGlobal("vec2"))
-       l.Push(val[0])
-       l.Push(val[1])
-       l.Call(2, 1)
-}
-
-func pushVec3(l *lua.LState, val [3]lua.LNumber) {
-       l.Push(l.GetGlobal("vec3"))
-       l.Push(val[0])
-       l.Push(val[1])
-       l.Push(val[2])
-       l.Call(3, 1)
-}
-
-func popValue(l *lua.LState) lua.LValue {
-       ret := l.Get(-1)
-       l.Pop(1)
-       return ret
-}
-
-func Vec2(l *lua.LState, val [2]lua.LNumber) lua.LValue {
-       pushVec2(l, val)
-       return popValue(l)
-}
-
-func Vec3(l *lua.LState, val [3]lua.LNumber) lua.LValue {
-       pushVec3(l, val)
-       return popValue(l)
-}
-
-func Box1(l *lua.LState, val [2]lua.LNumber) lua.LValue {
-       l.Push(l.GetGlobal("box"))
-       l.Push(val[0])
-       l.Push(val[1])
-       l.Call(2, 1)
-       return popValue(l)
-}
-
-func Box2(l *lua.LState, val [2][2]lua.LNumber) lua.LValue {
-       l.Push(l.GetGlobal("box"))
-       pushVec2(l, val[0])
-       pushVec2(l, val[1])
-       l.Call(2, 1)
-       return popValue(l)
-}
-
-func Box3(l *lua.LState, val [2][3]lua.LNumber) lua.LValue {
-       l.Push(l.GetGlobal("box"))
-       pushVec3(l, val[0])
-       pushVec3(l, val[1])
-       l.Call(2, 1)
-       return popValue(l)
-}
-
-func Color(l *lua.LState, val color.NRGBA) lua.LValue {
-       tbl := l.NewTable()
-       l.SetField(tbl, "r", lua.LNumber(val.R))
-       l.SetField(tbl, "g", lua.LNumber(val.G))
-       l.SetField(tbl, "b", lua.LNumber(val.B))
-       l.SetField(tbl, "a", lua.LNumber(val.A))
-       return tbl
-}
-
-func StringSet(l *lua.LState, val []string) lua.LValue {
-       tbl := l.NewTable()
-       for _, str := range val {
-               l.SetField(tbl, str, lua.LTrue)
-       }
-       return tbl
-}
-
-func stringList[T ~string](l *lua.LState, val []T) lua.LValue {
-       tbl := l.NewTable()
-       for _, s := range val {
-               tbl.Append(lua.LString(s))
-       }
-       return tbl
-}
-
-func StringList(l *lua.LState, val []string) lua.LValue {
-       return stringList[string](l, val)
-}
-
-func TextureList(l *lua.LState, val []mt.Texture) lua.LValue {
-       return stringList[mt.Texture](l, val)
-}