├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.md └── cdata.lua /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # C Data 2 | 3 | This code is licensed under the [**MIT Open Source License**][MIT]. 4 | 5 | Copyright (c) 2015 Landon Manning - LManning17@gmail.com - [LandonManning.com][LM] 6 | 7 | Copyright (c) 2015 Lucien Greathouse - me@lpghatguy.com - [GitHub][LPG] 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | 28 | [MIT]: http://www.opensource.org/licenses/mit-license.html 29 | [LM]: http://LandonManning.com 30 | [LPG]: https://github.com/LPGhatguy 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C Data 2 | 3 | C Data is a simple wrapper for LuaJIT FFI's cast to C String. This is primarily used to serialize Lua tables into network-transferable data. 4 | 5 | It is worth noting that if you encode an incomplete table (missing a key) then when you decode the packet, it will have the missing key with a value of 0. 6 | 7 | 8 | ## Examples 9 | 10 | ### Register Packets 11 | 12 | ```lua 13 | local cdata = require "cdata" 14 | local packets = {} 15 | 16 | -- all structs get a type field so we don't lose our minds. 17 | function add_struct(name, fields, map) 18 | local struct = string.format("typedef struct { uint8_t type; %s } %s;", fields, name) 19 | cdata:new_struct(name, struct) 20 | 21 | -- the packet_type struct isn't a real packet, so don't index it. 22 | if map then 23 | map.name = name 24 | table.insert(packets, map) 25 | packets[name] = #packets 26 | end 27 | end 28 | 29 | -- Slightly special, I guess. 30 | add_struct("packet_type", "") 31 | 32 | add_struct( 33 | "player_whois", [[ 34 | uint16_t id; 35 | ]], { 36 | "id", 37 | } 38 | ) 39 | 40 | add_struct( 41 | "player_create", [[ 42 | uint16_t id; 43 | uint8_t flags; 44 | float position_x, position_y, position_z; 45 | float orientation_x, orientation_y, orientation_z; 46 | unsigned char name[64]; 47 | ]], { 48 | "id", 49 | "flags", 50 | "position_x", "position_y", "position_z", 51 | "orientation_x", "orientation_y", "orientation_z", 52 | "name", 53 | } 54 | ) 55 | 56 | add_struct( 57 | "player_update", [[ 58 | uint16_t id; 59 | float position_x, position_y, position_z; 60 | float orientation_x, orientation_y, orientation_z; 61 | ]], { 62 | "id", 63 | "position_x", "position_y", "position_z", 64 | "orientation_x", "orientation_y", "orientation_z", 65 | } 66 | ) 67 | 68 | add_struct( 69 | "player_action", [[ 70 | uint16_t id; 71 | uint16_t action; 72 | ]], { 73 | "id", 74 | "action", 75 | } 76 | ) 77 | ``` 78 | 79 | 80 | ### Encode Data 81 | 82 | ```lua 83 | local player = self.players[1] 84 | local data = { 85 | type = packets["player_update"], 86 | id = player.id, 87 | position_x = player.position.x, 88 | position_y = player.position.y, 89 | position_z = player.position.z, 90 | orientation_x = player.orientation.x, 91 | orientation_y = player.orientation.y, 92 | orientation_z = player.orientation.z, 93 | } 94 | 95 | local struct = cdata:set_struct("player_update", data) 96 | local encoded = cdata:encode(struct) 97 | ``` 98 | 99 | 100 | ### Decode Data 101 | 102 | ```lua 103 | -- We assume we have a variable named data that we received from the network 104 | local header = cdata:decode("packet_type", data) 105 | local map = packets[header.type] 106 | 107 | if not map then 108 | error(string.format("Invalid packet type (%s) received!", header.type)) 109 | return 110 | end 111 | 112 | local decoded = cdata:decode(map.name, data) 113 | ``` 114 | -------------------------------------------------------------------------------- /cdata.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local cdata = {} 4 | 5 | -- http://www.catb.org/esr/structure-packing/ 6 | function cdata:new_struct(name, struct) 7 | ffi.cdef(struct) 8 | 9 | self.structs = self.structs or {} 10 | self.structs[name] = ffi.typeof(name) 11 | 12 | self.pointers = self.pointers or {} 13 | self.pointers[name] = ffi.typeof(name.."*") 14 | end 15 | 16 | function cdata:set_struct(name, data) 17 | return ffi.new(self.structs[name], data) 18 | end 19 | 20 | function cdata:encode(data) 21 | return ffi.string(ffi.cast("const char*", data), ffi.sizeof(data)) 22 | end 23 | 24 | function cdata:decode(name, data) 25 | return ffi.cast(self.pointers[name], data)[0] 26 | end 27 | 28 | return cdata 29 | --------------------------------------------------------------------------------