]> git.lizzy.rs Git - hydra-dragonfire.git/commitdiff
Add map component
authorElias Fleckenstein <eliasfleckenstein@web.de>
Tue, 31 May 2022 12:24:19 +0000 (14:24 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Tue, 31 May 2022 12:24:19 +0000 (14:24 +0200)
39 files changed:
README.md
builtin/base64.lua [new file with mode: 0644]
builtin/escapes.lua
builtin/vector.lua
client.go
convert/push_auto.go
convert/push_mkauto.lua
convert/push_static.go
convert/read_auto.go
convert/read_mkauto.lua
convert/read_static.go
convert/spec.lua
convert/spec/casemap [new file with mode: 0644]
convert/spec/client/enum [new file with mode: 0644]
convert/spec/client/flag [new file with mode: 0644]
convert/spec/client/pkt [new file with mode: 0644]
convert/spec/client/struct [new file with mode: 0644]
convert/spec/server/enum [new file with mode: 0644]
convert/spec/server/flag [new file with mode: 0644]
convert/spec/server/pkt [new file with mode: 0644]
convert/spec/server/struct [new file with mode: 0644]
doc/api.md
doc/client.md
doc/client_pkts.md
doc/map.md [new file with mode: 0644]
doc/server_pkts.md
example/dump-traffic.lua
example/print-node.lua [new file with mode: 0755]
hydra.go
map.go [new file with mode: 0644]
spec/casemap [deleted file]
spec/client/enum [deleted file]
spec/client/flag [deleted file]
spec/client/pkt [deleted file]
spec/client/struct [deleted file]
spec/server/enum [deleted file]
spec/server/flag [deleted file]
spec/server/pkt [deleted file]
spec/server/struct [deleted file]

index 2b75b0d3b49818ad3fe578201459068b285d9d0a..275a6d5ee5ef2804bb0b7f18ca28c8b5f5d4c15a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Only selected packets will be returned by `poll`, to avoid unnecessary conversio
 Poll will return early if the script is interrupted by a signal, one of the selected clients is disconnected or the configured timeout elapses.
 
 Additionally, different native components can be enabled per-client to manage state.
-Currently only the `auth` component is available, but components like `map`, `objs`, `inv`, `pos`, `playerlist` etc. will be added in the future.
+Currently `auth` and `map` components are available, and components like `objs`, `inv`, `pos`, `player_list` etc. will be added in the future.
 Components handle packets asynchronously, they will process them even if poll is not called.
 
 # Further Documentation
diff --git a/builtin/base64.lua b/builtin/base64.lua
new file mode 100644 (file)
index 0000000..5afa64a
--- /dev/null
@@ -0,0 +1,43 @@
+--[[ builtin/base64.lua ]]--
+
+-- Taken from: http://lua-users.org/wiki/BaseSixtyFour with minor modifications
+
+-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
+-- licensed under the terms of the LGPL2
+
+local base64 = {}
+package.loaded.base64 = base64
+
+-- character table string
+local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+-- encoding
+function base64.encode(data)
+    return ((data:gsub('.', function(x)
+        local r,b='',x:byte()
+        for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+        if (#x < 6) then return '' end
+        local c=0
+        for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+        return b:sub(c+1,c+1)
+    end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function base64.decode(data)
+    data = string.gsub(data, '[^'..b..'=]', '')
+    return (data:gsub('.', function(x)
+        if (x == '=') then return '' end
+        local r,f='',(b:find(x)-1)
+        for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+        return r;
+    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+        if (#x ~= 8) then return '' end
+        local c=0
+        for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+        return string.char(c)
+    end))
+end
+
index 12ba174247c22301771dd0e2f9d5af86b34a5045..e3ff1610cadc8cc377292aa28e3f9256a5cc5f8d 100644 (file)
@@ -2,7 +2,7 @@
 -- code taken from minetest/builtin/common/misc_helpers.lua with modifications
 
 local escapes = {}
-package.loaded["escapes"] = escapes
+package.loaded.escapes = escapes
 
 escapes.ESCAPE_CHAR = string.char(0x1b)
 
index eed368f328ea2c9315e6b83d5a903f3c75b14c18..654a8393f863908ddc5d56a988832ad46b7c10ef 100644 (file)
@@ -43,7 +43,10 @@ mt_vec2.__index = {
                assert(type(self.x) == "number")
                assert(type(self.y) == "number")
                return self
-       end
+       end,
+       round = function(self)
+               return vec2(math.round(self.x), math.round(self.y))
+       end,
 }
 
 function vec2(a, b)
@@ -91,7 +94,10 @@ mt_vec3.__index = {
                assert(type(self.y) == "number")
                assert(type(self.z) == "number")
                return self
-       end
+       end,
+       round = function(self)
+               return vec3(math.floor(self.x), math.floor(self.y), math.floor(self.z))
+       end,
 }
 
 function vec3(a, b, c)
index d27af337946edb5c5c3d21a409b9b555de76f4fb..13795e5ecfced6d50d57502fab03ea9a885e2943 100644 (file)
--- a/client.go
+++ b/client.go
@@ -212,6 +212,8 @@ func l_client_enable(l *lua.LState) int {
                        switch compname {
                        case "auth":
                                component = &Auth{}
+                       case "map":
+                               component = &Map{}
                        default:
                                panic("invalid component: " + compname)
                        }
index 282a5f5c3d1fc4937c48fc14aca132fe64a92477..beb30c25271984720542a223ad3277fc6ccce82d 100644 (file)
@@ -6,7 +6,7 @@ import (
        "github.com/yuin/gopher-lua"
 )
 
-func pushAnimType(l *lua.LState, val mt.AnimType) lua.LValue {
+func PushAnimType(l *lua.LState, val mt.AnimType) lua.LValue {
        switch val {
        case mt.NoAnim:
                return lua.LNil
@@ -19,7 +19,7 @@ func pushAnimType(l *lua.LState, val mt.AnimType) lua.LValue {
        return lua.LNil
 }
 
-func pushChatMsgType(l *lua.LState, val mt.ChatMsgType) lua.LValue {
+func PushChatMsgType(l *lua.LState, val mt.ChatMsgType) lua.LValue {
        switch val {
        case mt.RawMsg:
                return lua.LString("raw")
@@ -34,7 +34,7 @@ func pushChatMsgType(l *lua.LState, val mt.ChatMsgType) lua.LValue {
        return lua.LNil
 }
 
-func pushHotbarParam(l *lua.LState, val mt.HotbarParam) lua.LValue {
+func PushHotbarParam(l *lua.LState, val mt.HotbarParam) lua.LValue {
        switch val {
        case mt.HotbarSize:
                return lua.LString("size")
@@ -47,7 +47,7 @@ func pushHotbarParam(l *lua.LState, val mt.HotbarParam) lua.LValue {
        return lua.LNil
 }
 
-func pushHUDField(l *lua.LState, val mt.HUDField) lua.LValue {
+func PushHUDField(l *lua.LState, val mt.HUDField) lua.LValue {
        switch val {
        case mt.HUDPos:
                return lua.LString("pos")
@@ -80,7 +80,7 @@ func pushHUDField(l *lua.LState, val mt.HUDField) lua.LValue {
        return lua.LNil
 }
 
-func pushHUDType(l *lua.LState, val mt.HUDType) lua.LValue {
+func PushHUDType(l *lua.LState, val mt.HUDType) lua.LValue {
        switch val {
        case mt.ImgHUD:
                return lua.LString("img")
@@ -99,7 +99,7 @@ func pushHUDType(l *lua.LState, val mt.HUDType) lua.LValue {
        return lua.LNil
 }
 
-func pushKickReason(l *lua.LState, val mt.KickReason) lua.LValue {
+func PushKickReason(l *lua.LState, val mt.KickReason) lua.LValue {
        switch val {
        case mt.WrongPasswd:
                return lua.LString("wrong_passwd")
@@ -132,7 +132,7 @@ func pushKickReason(l *lua.LState, val mt.KickReason) lua.LValue {
        return lua.LNil
 }
 
-func pushModChanSig(l *lua.LState, val mt.ModChanSig) lua.LValue {
+func PushModChanSig(l *lua.LState, val mt.ModChanSig) lua.LValue {
        switch val {
        case mt.JoinOK:
                return lua.LString("join_ok")
@@ -151,7 +151,7 @@ func pushModChanSig(l *lua.LState, val mt.ModChanSig) lua.LValue {
        return lua.LNil
 }
 
-func pushPlayerListUpdateType(l *lua.LState, val mt.PlayerListUpdateType) lua.LValue {
+func PushPlayerListUpdateType(l *lua.LState, val mt.PlayerListUpdateType) lua.LValue {
        switch val {
        case mt.InitPlayers:
                return lua.LString("init")
@@ -164,7 +164,7 @@ func pushPlayerListUpdateType(l *lua.LState, val mt.PlayerListUpdateType) lua.LV
        return lua.LNil
 }
 
-func pushSoundSrcType(l *lua.LState, val mt.SoundSrcType) lua.LValue {
+func PushSoundSrcType(l *lua.LState, val mt.SoundSrcType) lua.LValue {
        switch val {
        case mt.NoSrc:
                return lua.LNil
@@ -177,86 +177,76 @@ func pushSoundSrcType(l *lua.LState, val mt.SoundSrcType) lua.LValue {
        return lua.LNil
 }
 
-func pushAuthMethods(l *lua.LState, val mt.AuthMethods) lua.LValue {
+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)
-       }
+       l.SetField(tbl, "legacy_passwd", lua.LBool(val&mt.LegacyPasswd != 0))
+       l.SetField(tbl, "srp", lua.LBool(val&mt.SRP != 0))
+       l.SetField(tbl, "first_srp", lua.LBool(val&mt.FirstSRP != 0))
        return tbl
 }
 
-func pushCSMRestrictionFlags(l *lua.LState, val mt.CSMRestrictionFlags) lua.LValue {
+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)
-       }
+       l.SetField(tbl, "no_csms", lua.LBool(val&mt.NoCSMs != 0))
+       l.SetField(tbl, "no_chat_msgs", lua.LBool(val&mt.NoChatMsgs != 0))
+       l.SetField(tbl, "no_node_defs", lua.LBool(val&mt.NoNodeDefs != 0))
+       l.SetField(tbl, "limit_map_range", lua.LBool(val&mt.LimitMapRange != 0))
+       l.SetField(tbl, "no_player_list", lua.LBool(val&mt.NoPlayerList != 0))
        return tbl
 }
 
-func pushHUDFlags(l *lua.LState, val mt.HUDFlags) lua.LValue {
+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)
-       }
+       l.SetField(tbl, "hotbar", lua.LBool(val&mt.ShowHotbar != 0))
+       l.SetField(tbl, "health_bar", lua.LBool(val&mt.ShowHealthBar != 0))
+       l.SetField(tbl, "crosshair", lua.LBool(val&mt.ShowCrosshair != 0))
+       l.SetField(tbl, "wielded_item", lua.LBool(val&mt.ShowWieldedItem != 0))
+       l.SetField(tbl, "breath_bar", lua.LBool(val&mt.ShowBreathBar != 0))
+       l.SetField(tbl, "minimap", lua.LBool(val&mt.ShowMinimap != 0))
+       l.SetField(tbl, "radar_minimap", lua.LBool(val&mt.ShowRadarMinimap != 0))
+       return tbl
+}
+
+func PushMapBlkFlags(l *lua.LState, val mt.MapBlkFlags) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "is_underground", lua.LBool(val&mt.BlkIsUnderground != 0))
+       l.SetField(tbl, "day_night_diff", lua.LBool(val&mt.BlkDayNightDiff != 0))
+       l.SetField(tbl, "light_expired", lua.LBool(val&mt.BlkLightExpired != 0))
+       l.SetField(tbl, "not_generated", lua.LBool(val&mt.BlkNotGenerated != 0))
        return tbl
 }
 
-func pushHUD(l *lua.LState, val mt.HUD) lua.LValue {
+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, "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, "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, "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 {
+func PushMapBlk(l *lua.LState, val mt.MapBlk) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "flags", PushMapBlkFlags(l, val.Flags))
+       l.SetField(tbl, "lit_from", lua.LNumber(val.LitFrom))
+       l.SetField(tbl, "node_metas", PushNodeMetas(l, val.NodeMetas))
+       l.SetField(tbl, "param0", Push4096[mt.Content](l, val.Param0))
+       l.SetField(tbl, "param1", Push4096[uint8](l, val.Param1))
+       l.SetField(tbl, "param2", Push4096[uint8](l, val.Param2))
+       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))
@@ -264,12 +254,29 @@ func pushNode(l *lua.LState, val mt.Node) lua.LValue {
        return tbl
 }
 
-func pushTileAnim(l *lua.LState, val mt.TileAnim) lua.LValue {
+func PushNodeMeta(l *lua.LState, val mt.NodeMeta) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "fields", PushNodeMetaFields(l, val.Fields))
+       l.SetField(tbl, "inv", PushInv(l, val.Inv))
+       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, "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))
+       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 PushToolCaps(l *lua.LState, val mt.ToolCaps) lua.LValue {
+       tbl := l.NewTable()
+       l.SetField(tbl, "attack_cooldown", lua.LNumber(val.AttackCooldown))
+       l.SetField(tbl, "dmg_groups", PushGroups(l, val.DmgGroups))
+       l.SetField(tbl, "group_caps", PushGroupCaps(l, val.GroupCaps))
+       l.SetField(tbl, "max_drop_lvl", lua.LNumber(val.MaxDropLvl))
+       l.SetField(tbl, "punch_uses", lua.LNumber(val.PunchUses))
        return tbl
 }
 
@@ -405,49 +412,50 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
        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, "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))
+               l.SetField(tbl, "sudo_auth_methods", PushAuthMethods(l, val.SudoAuthMethods))
        case *mt.ToCltAddHUD:
-               l.SetField(tbl, "hud", pushHUD(l, val.HUD))
+               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])}))
+               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, "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, "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, "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, "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, "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])}))
+               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])}))
+               l.SetField(tbl, "blk", PushMapBlk(l, val.Blk))
+               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])}))
+                       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, "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))
@@ -459,13 +467,13 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                        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])}))
+                       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])}))
+                       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])}))
+                       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)))
@@ -474,7 +482,7 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                        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])}))
+                       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))
@@ -483,19 +491,19 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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))
+               l.SetField(tbl, "type", PushChatMsgType(l, val.Type))
        case *mt.ToCltCloudParams:
-               l.SetField(tbl, "ambient_color", pushColor(l, val.AmbientColor))
+               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, "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, "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, "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_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))
@@ -505,8 +513,8 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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])}))
+               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))
@@ -518,7 +526,7 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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, "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))
@@ -526,8 +534,8 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
        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))
+               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:
@@ -536,18 +544,18 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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))
+               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, "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])}))
+               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)))
@@ -559,7 +567,7 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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))
+               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)))
@@ -567,7 +575,7 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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, "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))
@@ -582,6 +590,8 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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.ToCltNodeMetasChanged:
+               l.SetField(tbl, "changed", PushChangedNodeMetas(l, val.Changed))
        case *mt.ToCltOverrideDayNightRatio:
                l.SetField(tbl, "override", lua.LBool(val.Override))
                l.SetField(tbl, "ratio", lua.LNumber(val.Ratio))
@@ -593,56 +603,56 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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, "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))
+               l.SetField(tbl, "src_type", PushSoundSrcType(l, val.SrcType))
        case *mt.ToCltPrivs:
-               l.SetField(tbl, "privs", pushStringSet(l, val.Privs))
+               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])}))
+               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, "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, "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))
+                       l.SetField(tbl, "dawn_horizon", PushColor(l, val.DawnHorizon))
                }
                if val.Type == "regular" {
-                       l.SetField(tbl, "dawn_sky", pushColor(l, val.DawnSky))
+                       l.SetField(tbl, "dawn_sky", PushColor(l, val.DawnSky))
                }
                if val.Type == "regular" {
-                       l.SetField(tbl, "day_horizon", pushColor(l, val.DayHorizon))
+                       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, "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, "indoor", PushColor(l, val.Indoor))
                }
-               l.SetField(tbl, "moon_fog_tint", pushColor(l, val.MoonFogTint))
+               l.SetField(tbl, "moon_fog_tint", PushColor(l, val.MoonFogTint))
                if val.Type == "regular" {
-                       l.SetField(tbl, "night_horizon", pushColor(l, val.NightHorizon))
+                       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, "night_sky", PushColor(l, val.NightSky))
                }
-               l.SetField(tbl, "sun_fog_tint", pushColor(l, val.SunFogTint))
+               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, "textures", PushStringList[mt.Texture](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, "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))
@@ -651,16 +661,16 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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, "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, "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, "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))
@@ -677,8 +687,8 @@ func PushPkt(l *lua.LState, pkt *mt.Pkt) lua.LValue {
                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))
+               l.SetField(tbl, "players", PushStringList[string](l, val.Players))
+               l.SetField(tbl, "type", PushPlayerListUpdateType(l, val.Type))
        }
        return tbl
 }
index 3e0293259acbdeb536453a11562cee0c95138e8f..df13198df9a93e2080925d4efa2295e1311a1787 100755 (executable)
@@ -5,7 +5,7 @@ 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"
+       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" ..
@@ -17,11 +17,10 @@ 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"
+       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"
+               funcs = funcs .. "\tl.SetField(tbl, \"" .. var  .. "\", lua.LBool(val&mt." .. apply_prefix(fields, var) .. " != 0))\n"
        end
 
        funcs = funcs .. "\treturn tbl\n}\n\n"
@@ -32,22 +31,24 @@ local tolua = {
        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])}})",
+       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 c = name:sub(1, 1)
+               if c ~= "{" and c ~= "%" then
                        local camel = "val." .. camel_case(name)
 
                        local idt = indent
                        local condition = fields["{" .. name .. "}"]
+                       local typeparam = fields["%" .. name .. "%"]
 
                        if condition then
                                impl = impl .. indent .. "if " .. condition .. " {\n"
@@ -58,7 +59,9 @@ local function fields_tolua(fields, indent)
                        if tolua[type] then
                                impl = impl .. tolua[type]:gsub("VAL", camel)
                        else
-                               impl = impl .. "push" .. camel_case(type) .. "(l, " .. camel .. ")"
+                               impl = impl .. "Push" .. camel_case(type)
+                                       .. (typeparam and "[" .. typeparam .. "]" or "")
+                                       .. "(l, " .. camel .. ")"
                        end
                        impl = impl .. ")\n"
 
@@ -74,7 +77,7 @@ 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"
+               .. "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
index 4eb7cb07e556f22d489d27a06f52669987f10b6d..75001a7f75e67a2f0203c5e946a969ae7e9e6042 100644 (file)
@@ -8,14 +8,14 @@ import (
 
 //go:generate ./push_mkauto.lua
 
-func vec2(l *lua.LState, val [2]lua.LNumber) {
+func CreateVec2(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) {
+func CreateVec3(l *lua.LState, val [3]lua.LNumber) {
        l.Push(l.GetGlobal("vec3"))
        l.Push(val[0])
        l.Push(val[1])
@@ -29,17 +29,17 @@ func popValue(l *lua.LState) lua.LValue {
        return ret
 }
 
-func pushVec2(l *lua.LState, val [2]lua.LNumber) lua.LValue {
-       vec2(l, val)
+func PushVec2(l *lua.LState, val [2]lua.LNumber) lua.LValue {
+       CreateVec2(l, val)
        return popValue(l)
 }
 
-func pushVec3(l *lua.LState, val [3]lua.LNumber) lua.LValue {
-       vec3(l, val)
+func PushVec3(l *lua.LState, val [3]lua.LNumber) lua.LValue {
+       CreateVec3(l, val)
        return popValue(l)
 }
 
-func pushBox1(l *lua.LState, val [2]lua.LNumber) lua.LValue {
+func PushBox1(l *lua.LState, val [2]lua.LNumber) lua.LValue {
        l.Push(l.GetGlobal("box"))
        l.Push(val[0])
        l.Push(val[1])
@@ -47,23 +47,23 @@ func pushBox1(l *lua.LState, val [2]lua.LNumber) lua.LValue {
        return popValue(l)
 }
 
-func pushBox2(l *lua.LState, val [2][2]lua.LNumber) lua.LValue {
+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])
+       CreateVec2(l, val[0])
+       CreateVec2(l, val[1])
        l.Call(2, 1)
        return popValue(l)
 }
 
-func pushBox3(l *lua.LState, val [2][3]lua.LNumber) lua.LValue {
+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])
+       CreateVec3(l, val[0])
+       CreateVec3(l, val[1])
        l.Call(2, 1)
        return popValue(l)
 }
 
-func pushColor(l *lua.LState, val color.NRGBA) lua.LValue {
+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))
@@ -72,7 +72,7 @@ func pushColor(l *lua.LState, val color.NRGBA) lua.LValue {
        return tbl
 }
 
-func pushStringSet(l *lua.LState, val []string) lua.LValue {
+func PushStringSet(l *lua.LState, val []string) lua.LValue {
        tbl := l.NewTable()
        for _, str := range val {
                l.SetField(tbl, str, lua.LTrue)
@@ -80,7 +80,7 @@ func pushStringSet(l *lua.LState, val []string) lua.LValue {
        return tbl
 }
 
-func stringList[T ~string](l *lua.LState, val []T) lua.LValue {
+func PushStringList[T ~string](l *lua.LState, val []T) lua.LValue {
        tbl := l.NewTable()
        for _, s := range val {
                tbl.Append(lua.LString(s))
@@ -88,10 +88,96 @@ func stringList[T ~string](l *lua.LState, val []T) lua.LValue {
        return tbl
 }
 
-func pushStringList(l *lua.LState, val []string) lua.LValue {
-       return stringList[string](l, val)
+func Push4096[T uint8 | mt.Content](l *lua.LState, val [4096]T) lua.LValue {
+       tbl := l.NewTable()
+       for i, v := range val {
+               l.RawSetInt(tbl, i, lua.LNumber(v))
+       }
+       return tbl
+}
+
+func PushFields(l *lua.LState, val []mt.Field) lua.LValue {
+       tbl := l.NewTable()
+       for _, pair := range val {
+               l.SetField(tbl, pair.Name, lua.LString(pair.Value))
+       }
+       return tbl
+}
+
+func PushNodeMetaFields(l *lua.LState, val []mt.NodeMetaField) lua.LValue {
+       tbl := l.NewTable()
+       for _, pair := range val {
+               l.SetField(tbl, pair.Name, lua.LString(pair.Value))
+       }
+       return tbl
+}
+
+func PushInv(l *lua.LState, val mt.Inv) lua.LValue {
+       linv := l.NewTable()
+       for _, list := range val {
+               llist := l.NewTable()
+               l.SetField(llist, "width", lua.LNumber(list.Width))
+               for _, stack := range list.Stacks {
+                       lmeta := l.NewTable()
+                       l.SetField(lmeta, "fields", PushFields(l, stack.Fields()))
+                       if toolcaps, ok := stack.ToolCaps(); ok {
+                               l.SetField(lmeta, "tool_caps", PushToolCaps(l, toolcaps))
+                       }
+
+                       lstack := l.NewTable()
+                       l.SetField(lstack, "name", lua.LString(stack.Name))
+                       l.SetField(lstack, "count", lua.LNumber(stack.Count))
+                       l.SetField(lstack, "wear", lua.LNumber(stack.Wear))
+                       l.SetField(lstack, "meta", lmeta)
+
+                       llist.Append(lstack)
+               }
+               l.SetField(linv, list.Name, llist)
+       }
+       return linv
+}
+
+func PushNodeMetas(l *lua.LState, val map[uint16]*mt.NodeMeta) lua.LValue {
+       tbl := l.NewTable()
+       for i, meta := range val {
+               l.RawSetInt(tbl, int(i), PushNodeMeta(l, *meta))
+       }
+       return tbl
+}
+
+func PushChangedNodeMetas(l *lua.LState, val map[[3]int16]*mt.NodeMeta) lua.LValue {
+       lmetas := l.NewTable()
+       for pos, meta := range val {
+               lmeta := l.NewTable()
+               l.SetField(lmeta, "pos", PushVec3(l, [3]lua.LNumber{lua.LNumber(pos[0]), lua.LNumber(pos[1]), lua.LNumber(pos[2])}))
+               l.SetField(lmeta, "meta", PushNodeMeta(l, *meta))
+               lmetas.Append(lmeta)
+       }
+       return lmetas
 }
 
-func pushTextureList(l *lua.LState, val []mt.Texture) lua.LValue {
-       return stringList[mt.Texture](l, val)
+func PushGroups(l *lua.LState, val []mt.Group) lua.LValue {
+       tbl := l.NewTable()
+       for _, group := range val {
+               l.SetField(tbl, group.Name, lua.LNumber(group.Rating))
+       }
+       return tbl
+}
+
+func PushGroupCaps(l *lua.LState, val []mt.ToolGroupCap) lua.LValue {
+       lcaps := l.NewTable()
+       for _, groupcap := range val {
+               ltimes := l.NewTable()
+               for _, digtime := range groupcap.Times {
+                       l.RawSetInt(ltimes, int(digtime.Rating), lua.LNumber(digtime.Time))
+               }
+
+               lcap := l.NewTable()
+               l.SetField(lcap, "uses", lua.LNumber(groupcap.Uses))
+               l.SetField(lcap, "max_lvl", lua.LNumber(groupcap.MaxLvl))
+               l.SetField(lcap, "times", ltimes)
+
+               l.SetField(lcaps, groupcap.Name, lcap)
+       }
+       return lcaps
 }
index c5a39be78e968e5baa8a9b0cb213c11515019872..efb3d623eb793975845f98cb8ace6d8bf5c05806 100644 (file)
@@ -4,37 +4,38 @@ package convert
 import (
        "github.com/anon55555/mt"
        "github.com/yuin/gopher-lua"
+       "math"
 )
 
-func readAOID(l *lua.LState, val lua.LValue, ptr *mt.AOID) {
+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))
+       *ptr = mt.AOID(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readCompressionModes(l *lua.LState, val lua.LValue, ptr *mt.CompressionModes) {
+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))
+       *ptr = mt.CompressionModes(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readInt16(l *lua.LState, val lua.LValue, ptr *int16) {
+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))
+       *ptr = int16(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readInt32(l *lua.LState, val lua.LValue, ptr *int32) {
+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))
+       *ptr = int32(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readInteraction(l *lua.LState, val lua.LValue, ptr *mt.Interaction) {
+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")
        }
@@ -57,7 +58,7 @@ func readInteraction(l *lua.LState, val lua.LValue, ptr *mt.Interaction) {
        }
 }
 
-func readKeys(l *lua.LState, val lua.LValue, ptr *mt.Keys) {
+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")
        }
@@ -93,20 +94,20 @@ func readKeys(l *lua.LState, val lua.LValue, ptr *mt.Keys) {
        }
 }
 
-func readPlayerPos(l *lua.LState, val lua.LValue, ptr *mt.PlayerPos) {
+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)
+       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) {
+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")
        }
@@ -114,11 +115,11 @@ func readSliceSoundID(l *lua.LState, val lua.LValue, ptr *[]mt.SoundID) {
        n := tbl.MaxN()
        *ptr = make([]mt.SoundID, n)
        for i := range *ptr {
-               readSoundID(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+               ReadSoundID(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
        }
 }
 
-func readSliceString(l *lua.LState, val lua.LValue, ptr *[]string) {
+func ReadSliceString(l *lua.LState, val lua.LValue, ptr *[]string) {
        if val.Type() != lua.LTTable {
                panic("invalid value for []string: must be a table")
        }
@@ -126,11 +127,11 @@ func readSliceString(l *lua.LState, val lua.LValue, ptr *[]string) {
        n := tbl.MaxN()
        *ptr = make([]string, n)
        for i := range *ptr {
-               readString(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+               ReadString(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
        }
 }
 
-func readSliceVec3Int16(l *lua.LState, val lua.LValue, ptr *[][3]int16) {
+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")
        }
@@ -138,47 +139,47 @@ func readSliceVec3Int16(l *lua.LState, val lua.LValue, ptr *[][3]int16) {
        n := tbl.MaxN()
        *ptr = make([][3]int16, n)
        for i := range *ptr {
-               readVec3Int16(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+               ReadVec3Int16(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
        }
 }
 
-func readSoundID(l *lua.LState, val lua.LValue, ptr *mt.SoundID) {
+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))
+       *ptr = mt.SoundID(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readUint16(l *lua.LState, val lua.LValue, ptr *uint16) {
+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))
+       *ptr = uint16(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readUint8(l *lua.LState, val lua.LValue, ptr *uint8) {
+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))
+       *ptr = uint8(math.Round(float64(val.(lua.LNumber))))
 }
 
-func readVec3Int16(l *lua.LState, val lua.LValue, ptr *[3]int16) {
+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])
+       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) {
+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])
+       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 {
@@ -187,88 +188,88 @@ func ReadCmd(l *lua.LState) mt.Cmd {
        case "chat_msg":
                ptr := &mt.ToSrvChatMsg{}
                val := l.CheckTable(3)
-               readString(l, l.GetField(val, "msg"), &ptr.Msg)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               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)
+               ReadString(l, l.GetField(val, "channel"), &ptr.Channel)
+               ReadString(l, l.GetField(val, "msg"), &ptr.Msg)
                return ptr
        case "nil":
                ptr := &mt.ToSrvNil{}
@@ -276,24 +277,24 @@ func ReadCmd(l *lua.LState) mt.Cmd {
        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)
+               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)
+               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)
+               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)
+               ReadSliceString(l, l.GetField(val, "filenames"), &ptr.Filenames)
                return ptr
        case "respawn":
                ptr := &mt.ToSrvRespawn{}
@@ -301,18 +302,18 @@ func ReadCmd(l *lua.LState) mt.Cmd {
        case "select_item":
                ptr := &mt.ToSrvSelectItem{}
                val := l.CheckTable(3)
-               readUint16(l, l.GetField(val, "slot"), &ptr.Slot)
+               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)
+               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)
+               ReadSliceByte(l, l.GetField(val, "m"), &ptr.M)
                return ptr
        }
 
index f749f9920cc0210d932e167e196d69cefc0f0229..7ef82dd5c1db538066fa0eeefa67ccfc132c6e11 100755 (executable)
@@ -11,7 +11,7 @@ local readers = {
        PointedThing = true,
 }
 
-local static_uses = {
+local external = {
        "[3]int16",
        "AOID"
 }
@@ -40,7 +40,7 @@ local function generate(name)
        end
 
        if not readers[fnname] then
-               local fun = "func read" .. fnname .. "(l *lua.LState, val lua.LValue, ptr *" .. type  .. ") {\n"
+               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 "
@@ -53,7 +53,7 @@ local function generate(name)
        n := tbl.MaxN()
        *ptr = make(]] .. type .. [[, n)
        for i := range *ptr {
-               read]] .. childfn .. [[(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
+               Read]] .. childfn .. [[(l, l.RawGetInt(tbl, i+1), &(*ptr)[i])
        }
 ]]
                        else
@@ -64,14 +64,20 @@ local function generate(name)
                                        end
 
                                        fun = fun
-                                               .. "\tread" .. childfn
+                                               .. "\tRead" .. childfn
                                                .. "(l, l.GetField(val, \"" .. v .. "\"), &(*ptr)[" .. (i - 1) .. "])\n"
                                end
                        end
                else
+                       local is_float = type == "float32" or type == "float64"
+
                        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"
+                               .. "\t*ptr = " .. type .. "("
+                               .. (is_float and "" or "math.Round(float64(")
+                               .. "val.(lua.LNumber)"
+                               .. (is_float and "" or "))")
+                               .. ")\n"
                end
 
                fun = fun .. "}\n\n"
@@ -82,13 +88,13 @@ local function generate(name)
        return fnname, type
 end
 
-for _, use in ipairs(static_uses) do
+for _, use in ipairs(external) 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"
+       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
@@ -135,7 +141,7 @@ 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."
+               impl = impl .. indent .. "Read" .. generate(type) .. "(l, l.GetField(val, \"" .. name .. "\"), &ptr."
                        .. camel_case(name) .. ")\n"
        end
 
@@ -183,6 +189,7 @@ package convert
 import (
        "github.com/anon55555/mt"
        "github.com/yuin/gopher-lua"
+       "math"
 )
 
 ]] .. funcs .. [[
index 3e7dc3009eaa8c1dfea1da7f59be7ebe78fabd5a..3be41e1068ba911ca4f61acef3ea6a730fd4eaf6 100644 (file)
@@ -7,28 +7,28 @@ import (
 
 //go:generate ./read_mkauto.lua
 
-func readBool(l *lua.LState, val lua.LValue, ptr *bool) {
+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) {
+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) {
+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) {
+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")
        }
@@ -40,7 +40,7 @@ func readSliceField(l *lua.LState, val lua.LValue, ptr *[]mt.Field) {
        })
 }
 
-func readPointedThing(l *lua.LState, val lua.LValue, ptr *mt.PointedThing) {
+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")
        }
@@ -48,12 +48,12 @@ func readPointedThing(l *lua.LState, val lua.LValue, ptr *mt.PointedThing) {
 
        if id != lua.LNil {
                pt := &mt.PointedAO{}
-               readAOID(l, id, &(*pt).ID)
+               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)
+               ReadVec3Int16(l, l.GetField(val, "under"), &(*pt).Under)
+               ReadVec3Int16(l, l.GetField(val, "above"), &(*pt).Above)
                *ptr = pt
        }
 }
index 588f4d715976ed7105fa48c481bb747ecad9fc45..d7ba4325bc7ac37627e5164d88eb88207efc45a5 100644 (file)
@@ -40,8 +40,9 @@ local function parse_pair(pair, value_first)
 
        if idx then
                local first, second = pair:sub(1, idx - 1), pair:sub(idx + 1)
+               local c = first:sub(1, 1)
 
-               if value_first and first:sub(1, 1) ~= "{" then
+               if value_first and c ~= "{" and c ~= "%" then
                        return second, first
                else
                        return first, second
@@ -52,7 +53,7 @@ local function parse_pair(pair, value_first)
 end
 
 function parse_spec(name, value_first)
-       local f = io.open("../spec/" .. name, "r")
+       local f = io.open("spec/" .. name, "r")
        local spec = {}
        local top
 
diff --git a/convert/spec/casemap b/convert/spec/casemap
new file mode 100644 (file)
index 0000000..ab4c10a
--- /dev/null
@@ -0,0 +1,28 @@
+id ID
+ao AO
+hud HUD
+hp HP
+fov FOV
+srp SRP
+sha1 SHA1
+ao_rm_add AORmAdd
+ao_msgs AOMsgs
+src_aoid SrcAOID
+ao_collision AOCollision
+add_hud AddHUD
+rm_hud RmHUD
+change_hud ChangeHUD
+hud_flags HUDFlags
+hud_type HUDType
+hud_field HUDField
+first_srp FirstSRP
+csm_restriction_flags CSMRestrictionFlags
+srp_bytes_salt_b SRPBytesSaltB
+srp_bytes_a SRPBytesA
+srp_bytes_m SRPBytesM
+no_csms NoCSMs
+join_ok JoinOK
+leave_ok LeaveOK
+no_sha1 NoSHA1
+fov80 FOV80
+ids IDs
diff --git a/convert/spec/client/enum b/convert/spec/client/enum
new file mode 100644 (file)
index 0000000..cd5f166
--- /dev/null
@@ -0,0 +1,70 @@
+kick_reason
+       wrong_passwd
+       unexpected_data
+       srv_is_singleplayer
+       unsupported_ver
+       bad_name_chars
+       bad_name
+       too_many_clts
+       empty_passwd
+       already_connected
+       srv_err
+       custom
+       shutdown
+       crash
+chat_msg_type
+       postfix Msg
+       raw
+       normal
+       announce
+       sys
+sound_src_type
+       postfix Src
+       no
+       pos
+       ao
+anim_type
+       postfix Anim
+       no
+       vertical_frame
+       sprite_sheet
+hud_type
+       postfix HUD
+       img
+       text
+       statbar
+       inv
+       waypoint
+       img_waypoint
+hud_field
+       prefix HUD
+       pos
+       name
+       scale
+       text
+       number
+       item
+       dir
+       align
+       offset
+       world_pos
+       size
+       z_index
+       text_2
+hotbar_param
+       prefix Hotbar
+       size
+       img
+       sel_img
+mod_chan_sig
+       join_ok
+       join_fail
+       leave_ok
+       leave_fail
+       not_registered
+       set_state
+player_list_update_type
+       postfix Players
+       init
+       add
+       remove
diff --git a/convert/spec/client/flag b/convert/spec/client/flag
new file mode 100644 (file)
index 0000000..17a8c7a
--- /dev/null
@@ -0,0 +1,25 @@
+auth_methods
+       legacy_passwd
+       srp
+       first_srp
+csm_restriction_flags
+       no_csms
+       no_chat_msgs
+       no_node_defs
+       limit_map_range
+       no_player_list
+hud_flags
+       prefix Show
+       hotbar
+       health_bar
+       crosshair
+       wielded_item
+       breath_bar
+       minimap
+       radar_minimap
+map_blk_flags
+       prefix Blk
+       is_underground
+       day_night_diff
+       light_expired
+       not_generated
diff --git a/convert/spec/client/pkt b/convert/spec/client/pkt
new file mode 100644 (file)
index 0000000..0a15002
--- /dev/null
@@ -0,0 +1,276 @@
+hello
+       number serialize_ver
+       number compression
+       number proto_ver
+       auth_methods auth_methods
+       string username
+accept_auth
+       vec3 player_pos
+       number map_seed
+       number send_interval
+       auth_methods sudo_auth_methods
+accept_sudo_mode
+deny_sudo_mode
+kick
+       kick_reason reason
+       {custom} val.Reason == mt.Custom || val.Reason == mt.Shutdown || val.Reason == mt.Crash
+       string custom
+       {reconnect} val.Reason == mt.Shutdown || val.Reason == mt.Crash
+       boolean reconnect
+blk_data
+       vec3 blkpos
+       map_blk blk
+add_node
+       vec3 pos
+       node node
+       boolean keep_meta
+remove_node
+       vec3 pos
+inv
+       string inv
+time_of_day
+       number time
+       number speed
+csm_restriction_flags
+       csm_restriction_flags flags
+       number map_range
+add_player_vel
+       vec3 vel
+media_push
+       fixed_string sha1
+       string filename
+       boolean should_cache
+       string data
+chat_msg
+       chat_msg_type type
+       string sender
+       string text
+       number timestamp
+ao_rm_add
+       # TODO
+ao_msgs
+       # TODO
+hp
+       number hp
+move_player
+       vec3 pos
+       number pitch
+       number yaw
+legacy_kick
+       string reason
+fov
+       number fov
+       boolean multiplier
+       number transition_time
+death_screen
+       boolean point_cam
+       vec3 point_at
+media
+       # TODO
+node_defs
+       # TODO
+announce_media
+       # TODO
+item_defs
+       # TODO
+play_sound
+       number id
+       string name
+       number gain
+       sound_src_type src_type
+       vec3 pos
+       number src_aoid
+       boolean loop
+       number fade
+       number pitch
+       boolean ephemeral
+stop_sound
+       number id
+privs
+       string_set privs
+inv_formspec
+       string formspec
+detached_inv
+       string name
+       boolean keep
+       number len
+       string inv
+show_formspec
+       string formspec
+       string formname
+movement
+       number default_accel
+       number air_accel
+       number fast_accel
+       number walk_speed
+       number crouch_speed
+       number fast_speed
+       number climb_speed
+       number jump_speed
+       number fluidity
+       number smoothing
+       number sink
+       number gravity
+spawn_particle
+       vec3 pos
+       vec3 vel
+       vec3 acc
+       number expiration_time
+       number size
+       boolean collide
+       string texture
+       boolean vertical
+       boolean collision_rm
+       tile_anim anim_params
+       number glow
+       boolean ao_collision
+       number node_param0
+       number node_param2
+       number node_tile
+add_particle_spawner
+       number amount
+       number duration
+       box3 pos
+       box3 vel
+       box3 acc
+       box1 expiration_time
+       box1 size
+       boolean collide
+       string texture
+       number id
+       boolean vertical
+       boolean collision_rm
+       tile_anim anim_params
+       number glow
+       boolean ao_collision
+       number node_param0
+       number node_param2
+       number node_tile
+add_hud
+       number id
+       hud hud
+rm_hud
+       number id
+change_hud
+       number id
+       hud_field field
+       {pos} val.Field == mt.HUDPos
+       {name} val.Field == mt.HUDName
+       {text} val.Field == mt.HUDText
+       {number} val.Field == mt.HUDNumber
+       {item} val.Field == mt.HUDItem
+       {dir} val.Field == mt.HUDDir
+       {align} val.Field == mt.HUDAlign
+       {offset} val.Field == mt.HUDOffset
+       {world_pos} val.Field == mt.HUDWorldPos
+       {size} val.Field == mt.HUDSize
+       {z_index} val.Field == mt.HUDZIndex
+       {text_2} val.Field == mt.HUDText2
+       vec2 pos
+       string name
+       string text
+       number number
+       number item
+       number dir
+       vec2 align
+       vec2 offset
+       vec3 world_pos
+       vec2 size
+       number z_index
+       string text_2
+hud_flags
+       hud_flags flags
+       hud_flags mask
+set_hotbar_param
+       hotbar_param param
+       number size
+       string img
+breath
+       number breath
+sky_params
+       color bg_color
+       string type
+       boolean clouds
+       color sun_fog_tint
+       color moon_fog_tint
+       string fog_tint_type
+       {textures} val.Type == "skybox"
+       %textures% mt.Texture
+       string_list textures
+       {day_sky} val.Type == "regular"
+       {day_horizon} val.Type == "regular"
+       {dawn_sky} val.Type == "regular"
+       {dawn_horizon} val.Type == "regular"
+       {night_sky} val.Type == "regular"
+       {night_horizon} val.Type == "regular"
+       {indoor} val.Type == "regular"
+       color day_sky
+       color day_horizon
+       color dawn_sky
+       color dawn_horizon
+       color night_sky
+       color night_horizon
+       color indoor
+override_day_night_ratio
+       boolean override
+       number ratio
+local_player_anim
+       box1 idle
+       box1 walk
+       box1 dig
+       box1 walk_dig
+       number speed
+eye_offset
+       vec3 first
+       vec3 third
+del_particle_spawner
+       number id
+cloud_params
+       number density
+       color diffuse_color
+       color ambient_color
+       number height
+       number thickness
+       vec2 speed
+fade_sound
+       number id
+       number step
+       number gain
+update_player_list
+       player_list_update_type type
+       %players% string
+       string_list players
+mod_chan_msg
+       string channel
+       string sender
+       string msg
+mod_chan_sig
+       mod_chan_sig signal
+       string channel
+node_metas_changed
+       changed_node_metas changed
+sun_params
+       boolean visible
+       string texture
+       string tone_map
+       string rise
+       boolean rising
+       number size
+moon_params
+       boolean visible
+       string texture
+       string tone_map
+       number size
+star_params
+       boolean visible
+       number count
+       color color
+       number size
+srp_bytes_salt_b
+       string salt
+       string b
+formspec_prepend
+       string prepend
+minimap_modes
+       # TODO
+disco
diff --git a/convert/spec/client/struct b/convert/spec/client/struct
new file mode 100644 (file)
index 0000000..f3bbd10
--- /dev/null
@@ -0,0 +1,43 @@
+node
+       number param0
+       number param1
+       number param2
+tile_anim
+       anim_type type
+       vec2 aspect_ratio
+       vec2 n_frames
+       number duration
+hud
+       hud_type type
+       vec2 pos
+       string name
+       vec2 scale
+       string text
+       number number
+       number item
+       number dir
+       vec2 align
+       vec2 offset
+       vec3 world_pos
+       vec2 size
+       number z_index
+       string text_2
+map_blk
+       map_blk_flags flags
+       number lit_from
+       %param0% mt.Content
+       4096 param0
+       %param1% uint8
+       4096 param1
+       %param2% uint8
+       4096 param2
+       node_metas node_metas
+node_meta
+       node_meta_fields fields
+       inv inv
+tool_caps
+       number attack_cooldown
+       number max_drop_lvl
+       group_caps group_caps
+       groups dmg_groups
+       number punch_uses
diff --git a/convert/spec/server/enum b/convert/spec/server/enum
new file mode 100644 (file)
index 0000000..6f49e6d
--- /dev/null
@@ -0,0 +1,7 @@
+interaction
+       dig
+       stop_digging
+       dug
+       place
+       use
+       activate
diff --git a/convert/spec/server/flag b/convert/spec/server/flag
new file mode 100644 (file)
index 0000000..4f8c164
--- /dev/null
@@ -0,0 +1,12 @@
+keys
+       postfix Key
+       forward
+       backward
+       left
+       right
+       jump
+       special
+       sneak
+       dig
+       place
+       zoom
diff --git a/convert/spec/server/pkt b/convert/spec/server/pkt
new file mode 100644 (file)
index 0000000..5578d55
--- /dev/null
@@ -0,0 +1,63 @@
+nil
+init
+       uint8 serialize_ver
+       CompressionModes supported_compression
+       uint16 min_proto_ver
+       uint16 max_proto_ver
+       string player_name
+       bool send_full_item_meta
+init2
+       string lang
+join_mod_chan
+       string channel
+leave_mod_chan
+       string channel
+msg_mod_chan
+       string channel
+       string msg
+player_pos
+       PlayerPos pos
+got_blks
+       [][3]int16 blks
+deleted_blks
+       [][3]int16 blks
+inv_action
+       string action
+chat_msg
+       string msg
+fall_dmg
+       uint16 amount
+select_item
+       uint16 slot
+respawn
+interact
+       Interaction action
+       uint16 item_slot
+       PointedThing pointed
+       PlayerPos pos
+removed_sounds
+       []SoundID ids
+node_meta_fields
+       [3]int16 pos
+       string formname
+       []Field fields
+inv_fields
+       string formname
+       []Field fields
+req_media
+       []string filenames
+clt_ready
+       uint8 major
+       uint8 minor
+       uint8 patch
+       string version
+       uint16 formspec
+first_srp
+       []byte salt
+       []byte verifier
+       bool empty_passwd
+srp_bytes_a
+       []byte a
+       bool no_sha1
+srp_bytes_m
+       []byte m
diff --git a/convert/spec/server/struct b/convert/spec/server/struct
new file mode 100644 (file)
index 0000000..e971dbc
--- /dev/null
@@ -0,0 +1,8 @@
+player_pos
+       [3]int32 pos100
+       [3]int32 vel100
+       int32 pitch100
+       int32 yaw100
+       Keys keys
+       uint8 fov80
+       uint8 wanted_range
index 8dda81e8e5f4c926969d457e60c77b7c6b6a0ebe..2105a81786325fdb6f43dbb54e8897d76ef62a68 100644 (file)
@@ -15,6 +15,7 @@ Hydra uses gopher-lua, Lua 5.1
 
 - `escapes`: contains utility functions to deal with minetest escape sequences, see [escapes.md](escapes.md)
 - `client`: a function to create a client from command line arguments in the form `<server> <username> <password>`. This is trivial but so commonly used that this function was added to avoid repetition in scripts.
+- `base64`: contains the `base64.encode(data)` function to base64 encode a string as well as `base64.decode(data)` to decode
 
 ## Standard library additions
 
index 984459184bb416cd0aa752aa61e15017637b56d0..9c1922e16aa753a41ae5fdcc542f66e5731206b2 100644 (file)
@@ -22,3 +22,4 @@ After being disconnect, a client cannot be reconnected.
 Enabled components can be accessed by using `self.<component name>`.
 
 - `self.auth`: Handles authentication. Recommended for the vast majority of scripts. See [auth.md](auth.md).
+- `self.map`: Stores MapBlocks received from server. See [map.md](map.md).
index 7f967a082a61eaac6f1d5ecbd7974d5f2a0b2a07..2594b9dcee8c8d017e821c1e8ba0d1bd6227a7a0 100644 (file)
@@ -1,4 +1,4 @@
 # Client Packets
 TODO: automatically generate documentation from spec.
 
-For now, have a look at [spec/client](../spec/client)
+For now, have a look at [spec/client](../convert/spec/client)
diff --git a/doc/map.md b/doc/map.md
new file mode 100644 (file)
index 0000000..26fd51a
--- /dev/null
@@ -0,0 +1,13 @@
+# Map Component
+Source code: [map.go](../map.go)
+
+Map handles the `blk_data` and `node_metas_changed` packets.
+Map may send `got_blks`, `deleted_blks` packets.
+
+## Functions
+
+`self:clear()`: Forget all blocks.
+
+`self:block(blkpos)`: Return the `map_blk` at `blkpos` as found in the `blk_data` packet (See [client_pkts.md](client_pkts.md)). `nil` if block is not present.
+
+`self:node(pos)`: Return a node in the form `{ param0 = 126, param1 = 0, param2 = 0, meta = { ... } }`. The meta field is a `node_meta` as found in the `blk_data` packet. `nil` if node is not present.
index 0b343673f99e7c503a38337f7a4105ac74af5013..ac8741e6c1c529c8b30c8f22607ed2829fe81df0 100644 (file)
@@ -1,4 +1,4 @@
 # Server Packets
 TODO: automatically generate documentation from spec.
 
-For now, have a look at [spec/server](../spec/server)
+For now, have a look at [spec/server](../convert/spec/server)
index b3d89da1869febf2522f1b384c49d004d4aeca68..5dc83b6eea4ffad1db81006ba892a8f6f74f35a6 100755 (executable)
@@ -1,19 +1,53 @@
 #!/usr/bin/env hydra-dragonfire
+local escapes = require("escapes")
+local base64 = require("base64")
 local client = require("client")()
 
 client:wildcard(true)
 client:connect()
 
+local function dump(val, indent)
+       local t = type(val)
+       local mt = getmetatable(val)
+
+       if t ~= "table" or mt and mt.__tostring then
+               if t == "string" then
+                       val = val:gsub("\n", "\\n")
+               end
+               print(val)
+       else
+               print(val._type or "")
+
+               local idt = (indent or "") .. "  "
+               for k, v in pairs(val) do
+                       if k ~= "_type" then
+                               io.write(idt .. k .. " ")
+                               dump(v, idt)
+                       end
+               end
+       end
+end
+
 while not hydra.canceled() do
        local pkt, interrupt = client:poll()
 
        if pkt then
-               print(pkt._type)
-               for k, v in pairs(pkt) do
-                       if k ~= "_type" then
-                               print("", k, v)
-                       end
+               if pkt._type == "srp_bytes_salt_b" then
+                       pkt.b = base64.encode(pkt.b)
+                       pkt.salt = base64.encode(pkt.salt)
+               end
+
+               if pkt._type == "chat_msg" then
+                       pkt.text = escapes.strip_all(pkt.text)
+               end
+
+               if pkt._type == "blk_data" then
+                       pkt.blk.param0 = {}
+                       pkt.blk.param1 = {}
+                       pkt.blk.param2 = {}
                end
+
+               dump(pkt)
        elseif not interrupt then
                print("disconnected")
                break
diff --git a/example/print-node.lua b/example/print-node.lua
new file mode 100755 (executable)
index 0000000..3cf514e
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env hydra-dragonfire
+local client = require("client")()
+client:enable("map")
+
+client:subscribe("move_player")
+client:connect()
+
+local pos
+
+while not hydra.canceled() do
+       local pkt, interrupted = client:poll(1)
+
+       if pkt then
+               pos = (pkt.pos / hydra.BS + vec3(0, -1, 0)):round()
+       elseif not interrupted then
+               break
+       elseif pos then
+               local node = client.map:node(pos)
+               print(pos, node and node.param0)
+       end
+end
+
+client:close()
index c8f1e6778363355c4600319b9f78407aa52b3e85..f34ca2bb733f55f03b659a4cc1a4ce6f87e5cab7 100644 (file)
--- a/hydra.go
+++ b/hydra.go
@@ -28,11 +28,15 @@ var builtinEscapes string
 //go:embed builtin/client.lua
 var builtinClient string
 
+//go:embed builtin/base64.lua
+var builtinBase64 string
+
 var builtinFiles = []string{
        builtinLuaX,
        builtinVector,
        builtinEscapes,
        builtinClient,
+       builtinBase64,
 }
 
 var hydraFuncs = map[string]lua.LGFunction{
@@ -107,6 +111,7 @@ func main() {
 
        l.SetField(l.NewTypeMetatable("hydra.auth"), "__index", l.SetFuncs(l.NewTable(), authFuncs))
        l.SetField(l.NewTypeMetatable("hydra.client"), "__index", l.NewFunction(l_client_index))
+       l.SetField(l.NewTypeMetatable("hydra.map"), "__index", l.SetFuncs(l.NewTable(), mapFuncs))
 
        for _, str := range builtinFiles {
                if err := l.DoString(str); err != nil {
diff --git a/map.go b/map.go
new file mode 100644 (file)
index 0000000..08b97ec
--- /dev/null
+++ b/map.go
@@ -0,0 +1,116 @@
+package main
+
+import (
+       "github.com/anon55555/mt"
+       "github.com/dragonfireclient/hydra-dragonfire/convert"
+       "github.com/yuin/gopher-lua"
+       "sync"
+)
+
+type Map struct {
+       client   *Client
+       mu       sync.Mutex
+       blocks   map[[3]int16]*mt.MapBlk
+       userdata *lua.LUserData
+}
+
+var mapFuncs = map[string]lua.LGFunction{
+       "clear": l_map_clear,
+       "block": l_map_block,
+       "node":  l_map_node,
+}
+
+func getMap(l *lua.LState) *Map {
+       return l.CheckUserData(1).Value.(*Map)
+}
+
+func (mtmap *Map) create(client *Client, l *lua.LState) {
+       mtmap.client = client
+       mtmap.blocks = map[[3]int16]*mt.MapBlk{}
+       mtmap.userdata = l.NewUserData()
+       mtmap.userdata.Value = mtmap
+       l.SetMetatable(mtmap.userdata, l.GetTypeMetatable("hydra.map"))
+}
+
+func (mtmap *Map) push() lua.LValue {
+       return mtmap.userdata
+}
+
+func (mtmap *Map) connect() {
+}
+
+func (mtmap *Map) process(pkt *mt.Pkt) {
+       switch cmd := pkt.Cmd.(type) {
+       case *mt.ToCltBlkData:
+               mtmap.mu.Lock()
+               mtmap.blocks[cmd.Blkpos] = &cmd.Blk
+               mtmap.client.conn.SendCmd(&mt.ToSrvGotBlks{Blks: [][3]int16{cmd.Blkpos}})
+               mtmap.mu.Unlock()
+       }
+}
+
+func l_map_clear(l *lua.LState) int {
+       mtmap := getMap(l)
+
+       mtmap.mu.Lock()
+       defer mtmap.mu.Unlock()
+
+       var cmd mt.ToSrvDeletedBlks
+       for pos := range mtmap.blocks {
+               cmd.Blks = append(cmd.Blks, pos)
+       }
+
+       mtmap.blocks = map[[3]int16]*mt.MapBlk{}
+
+       mtmap.client.conn.SendCmd(&cmd)
+
+       return 0
+}
+
+func l_map_block(l *lua.LState) int {
+       mtmap := getMap(l)
+       var blkpos [3]int16
+       convert.ReadVec3Int16(l, l.Get(2), &blkpos)
+
+       mtmap.mu.Lock()
+       defer mtmap.mu.Unlock()
+
+       block, ok := mtmap.blocks[blkpos]
+       if ok {
+               l.Push(convert.PushMapBlk(l, *block))
+       } else {
+               l.Push(lua.LNil)
+       }
+
+       return 1
+}
+
+func l_map_node(l *lua.LState) int {
+       mtmap := getMap(l)
+
+       var pos [3]int16
+       convert.ReadVec3Int16(l, l.Get(2), &pos)
+       blkpos, i := mt.Pos2Blkpos(pos)
+
+       mtmap.mu.Lock()
+       defer mtmap.mu.Unlock()
+
+       block, block_exists := mtmap.blocks[blkpos]
+       if block_exists {
+               meta, meta_exists := block.NodeMetas[i]
+               if !meta_exists {
+                       meta = &mt.NodeMeta{}
+               }
+
+               lnode := l.NewTable()
+               l.SetField(lnode, "param0", lua.LNumber(block.Param0[i]))
+               l.SetField(lnode, "param1", lua.LNumber(block.Param1[i]))
+               l.SetField(lnode, "param2", lua.LNumber(block.Param2[i]))
+               l.SetField(lnode, "meta", convert.PushNodeMeta(l, *meta))
+               l.Push(lnode)
+       } else {
+               l.Push(lua.LNil)
+       }
+
+       return 1
+}
diff --git a/spec/casemap b/spec/casemap
deleted file mode 100644 (file)
index ab4c10a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-id ID
-ao AO
-hud HUD
-hp HP
-fov FOV
-srp SRP
-sha1 SHA1
-ao_rm_add AORmAdd
-ao_msgs AOMsgs
-src_aoid SrcAOID
-ao_collision AOCollision
-add_hud AddHUD
-rm_hud RmHUD
-change_hud ChangeHUD
-hud_flags HUDFlags
-hud_type HUDType
-hud_field HUDField
-first_srp FirstSRP
-csm_restriction_flags CSMRestrictionFlags
-srp_bytes_salt_b SRPBytesSaltB
-srp_bytes_a SRPBytesA
-srp_bytes_m SRPBytesM
-no_csms NoCSMs
-join_ok JoinOK
-leave_ok LeaveOK
-no_sha1 NoSHA1
-fov80 FOV80
-ids IDs
diff --git a/spec/client/enum b/spec/client/enum
deleted file mode 100644 (file)
index cd5f166..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-kick_reason
-       wrong_passwd
-       unexpected_data
-       srv_is_singleplayer
-       unsupported_ver
-       bad_name_chars
-       bad_name
-       too_many_clts
-       empty_passwd
-       already_connected
-       srv_err
-       custom
-       shutdown
-       crash
-chat_msg_type
-       postfix Msg
-       raw
-       normal
-       announce
-       sys
-sound_src_type
-       postfix Src
-       no
-       pos
-       ao
-anim_type
-       postfix Anim
-       no
-       vertical_frame
-       sprite_sheet
-hud_type
-       postfix HUD
-       img
-       text
-       statbar
-       inv
-       waypoint
-       img_waypoint
-hud_field
-       prefix HUD
-       pos
-       name
-       scale
-       text
-       number
-       item
-       dir
-       align
-       offset
-       world_pos
-       size
-       z_index
-       text_2
-hotbar_param
-       prefix Hotbar
-       size
-       img
-       sel_img
-mod_chan_sig
-       join_ok
-       join_fail
-       leave_ok
-       leave_fail
-       not_registered
-       set_state
-player_list_update_type
-       postfix Players
-       init
-       add
-       remove
diff --git a/spec/client/flag b/spec/client/flag
deleted file mode 100644 (file)
index e13f4da..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-auth_methods
-       legacy_passwd
-       srp
-       first_srp
-csm_restriction_flags
-       no_csms
-       no_chat_msgs
-       no_node_defs
-       limit_map_range
-       no_player_list
-hud_flags
-       prefix Show
-       hotbar
-       health_bar
-       crosshair
-       wielded_item
-       breath_bar
-       minimap
-       radar_minimap
diff --git a/spec/client/pkt b/spec/client/pkt
deleted file mode 100644 (file)
index 2a150e3..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-hello
-       number serialize_ver
-       number compression
-       number proto_ver
-       auth_methods auth_methods
-       string username
-accept_auth
-       vec3 player_pos
-       number map_seed
-       number send_interval
-       auth_methods sudo_auth_methods
-accept_sudo_mode
-deny_sudo_mode
-kick
-       kick_reason reason
-       {custom} val.Reason == mt.Custom || val.Reason == mt.Shutdown || val.Reason == mt.Crash
-       string custom
-       {reconnect} val.Reason == mt.Shutdown || val.Reason == mt.Crash
-       boolean reconnect
-blk_data
-       vec3 blkpos
-       # TODO
-add_node
-       vec3 pos
-       node node
-       boolean keep_meta
-remove_node
-       vec3 pos
-inv
-       string inv
-time_of_day
-       number time
-       number speed
-csm_restriction_flags
-       csm_restriction_flags flags
-       number map_range
-add_player_vel
-       vec3 vel
-media_push
-       fixed_string sha1
-       string filename
-       boolean should_cache
-       string data
-chat_msg
-       chat_msg_type type
-       string sender
-       string text
-       number timestamp
-ao_rm_add
-       # TODO
-ao_msgs
-       # TODO
-hp
-       number hp
-move_player
-       vec3 pos
-       number pitch
-       number yaw
-legacy_kick
-       string reason
-fov
-       number fov
-       boolean multiplier
-       number transition_time
-death_screen
-       boolean point_cam
-       vec3 point_at
-media
-       # TODO
-node_defs
-       # TODO
-announce_media
-       # TODO
-item_defs
-       # TODO
-play_sound
-       number id
-       string name
-       number gain
-       sound_src_type src_type
-       vec3 pos
-       number src_aoid
-       boolean loop
-       number fade
-       number pitch
-       boolean ephemeral
-stop_sound
-       number id
-privs
-       string_set privs
-inv_formspec
-       string formspec
-detached_inv
-       string name
-       boolean keep
-       number len
-       string inv
-show_formspec
-       string formspec
-       string formname
-movement
-       number default_accel
-       number air_accel
-       number fast_accel
-       number walk_speed
-       number crouch_speed
-       number fast_speed
-       number climb_speed
-       number jump_speed
-       number fluidity
-       number smoothing
-       number sink
-       number gravity
-spawn_particle
-       vec3 pos
-       vec3 vel
-       vec3 acc
-       number expiration_time
-       number size
-       boolean collide
-       string texture
-       boolean vertical
-       boolean collision_rm
-       tile_anim anim_params
-       number glow
-       boolean ao_collision
-       number node_param0
-       number node_param2
-       number node_tile
-add_particle_spawner
-       number amount
-       number duration
-       box3 pos
-       box3 vel
-       box3 acc
-       box1 expiration_time
-       box1 size
-       boolean collide
-       string texture
-       number id
-       boolean vertical
-       boolean collision_rm
-       tile_anim anim_params
-       number glow
-       boolean ao_collision
-       number node_param0
-       number node_param2
-       number node_tile
-add_hud
-       number id
-       hud hud
-rm_hud
-       number id
-change_hud
-       number id
-       hud_field field
-       {pos} val.Field == mt.HUDPos
-       {name} val.Field == mt.HUDName
-       {text} val.Field == mt.HUDText
-       {number} val.Field == mt.HUDNumber
-       {item} val.Field == mt.HUDItem
-       {dir} val.Field == mt.HUDDir
-       {align} val.Field == mt.HUDAlign
-       {offset} val.Field == mt.HUDOffset
-       {world_pos} val.Field == mt.HUDWorldPos
-       {size} val.Field == mt.HUDSize
-       {z_index} val.Field == mt.HUDZIndex
-       {text_2} val.Field == mt.HUDText2
-       vec2 pos
-       string name
-       string text
-       number number
-       number item
-       number dir
-       vec2 align
-       vec2 offset
-       vec3 world_pos
-       vec2 size
-       number z_index
-       string text_2
-hud_flags
-       hud_flags flags
-       hud_flags mask
-set_hotbar_param
-       hotbar_param param
-       number size
-       string img
-breath
-       number breath
-sky_params
-       color bg_color
-       string type
-       boolean clouds
-       color sun_fog_tint
-       color moon_fog_tint
-       string fog_tint_type
-       {textures} val.Type == "skybox"
-       texture_list textures
-       {day_sky} val.Type == "regular"
-       {day_horizon} val.Type == "regular"
-       {dawn_sky} val.Type == "regular"
-       {dawn_horizon} val.Type == "regular"
-       {night_sky} val.Type == "regular"
-       {night_horizon} val.Type == "regular"
-       {indoor} val.Type == "regular"
-       color day_sky
-       color day_horizon
-       color dawn_sky
-       color dawn_horizon
-       color night_sky
-       color night_horizon
-       color indoor
-override_day_night_ratio
-       boolean override
-       number ratio
-local_player_anim
-       box1 idle
-       box1 walk
-       box1 dig
-       box1 walk_dig
-       number speed
-eye_offset
-       vec3 first
-       vec3 third
-del_particle_spawner
-       number id
-cloud_params
-       number density
-       color diffuse_color
-       color ambient_color
-       number height
-       number thickness
-       vec2 speed
-fade_sound
-       number id
-       number step
-       number gain
-update_player_list
-       player_list_update_type type
-       string_list players
-mod_chan_msg
-       string channel
-       string sender
-       string msg
-mod_chan_sig
-       mod_chan_sig signal
-       string channel
-node_metas_changed
-       # TODO
-sun_params
-       boolean visible
-       string texture
-       string tone_map
-       string rise
-       boolean rising
-       number size
-moon_params
-       boolean visible
-       string texture
-       string tone_map
-       number size
-star_params
-       boolean visible
-       number count
-       color color
-       number size
-srp_bytes_salt_b
-       string salt
-       string b
-formspec_prepend
-       string prepend
-minimap_modes
-       # TODO
-disco
diff --git a/spec/client/struct b/spec/client/struct
deleted file mode 100644 (file)
index d18189c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-node
-       number param0
-       number param1
-       number param2
-tile_anim
-       anim_type type
-       vec2 aspect_ratio
-       vec2 n_frames
-       number duration
-hud
-       hud_type type
-       vec2 pos
-       string name
-       vec2 scale
-       string text
-       number number
-       number item
-       number dir
-       vec2 align
-       vec2 offset
-       vec3 world_pos
-       vec2 size
-       number z_index
-       string text_2
diff --git a/spec/server/enum b/spec/server/enum
deleted file mode 100644 (file)
index 6f49e6d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-interaction
-       dig
-       stop_digging
-       dug
-       place
-       use
-       activate
diff --git a/spec/server/flag b/spec/server/flag
deleted file mode 100644 (file)
index 4f8c164..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-keys
-       postfix Key
-       forward
-       backward
-       left
-       right
-       jump
-       special
-       sneak
-       dig
-       place
-       zoom
diff --git a/spec/server/pkt b/spec/server/pkt
deleted file mode 100644 (file)
index 5578d55..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-nil
-init
-       uint8 serialize_ver
-       CompressionModes supported_compression
-       uint16 min_proto_ver
-       uint16 max_proto_ver
-       string player_name
-       bool send_full_item_meta
-init2
-       string lang
-join_mod_chan
-       string channel
-leave_mod_chan
-       string channel
-msg_mod_chan
-       string channel
-       string msg
-player_pos
-       PlayerPos pos
-got_blks
-       [][3]int16 blks
-deleted_blks
-       [][3]int16 blks
-inv_action
-       string action
-chat_msg
-       string msg
-fall_dmg
-       uint16 amount
-select_item
-       uint16 slot
-respawn
-interact
-       Interaction action
-       uint16 item_slot
-       PointedThing pointed
-       PlayerPos pos
-removed_sounds
-       []SoundID ids
-node_meta_fields
-       [3]int16 pos
-       string formname
-       []Field fields
-inv_fields
-       string formname
-       []Field fields
-req_media
-       []string filenames
-clt_ready
-       uint8 major
-       uint8 minor
-       uint8 patch
-       string version
-       uint16 formspec
-first_srp
-       []byte salt
-       []byte verifier
-       bool empty_passwd
-srp_bytes_a
-       []byte a
-       bool no_sha1
-srp_bytes_m
-       []byte m
diff --git a/spec/server/struct b/spec/server/struct
deleted file mode 100644 (file)
index e971dbc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-player_pos
-       [3]int32 pos100
-       [3]int32 vel100
-       int32 pitch100
-       int32 yaw100
-       Keys keys
-       uint8 fov80
-       uint8 wanted_range