{"id":13526248,"url":"https://github.com/bjornbytes/trickle","last_synced_at":"2025-04-01T07:31:43.369Z","repository":{"id":145428112,"uuid":"47238217","full_name":"bjornbytes/trickle","owner":"bjornbytes","description":"Lua bitstream","archived":true,"fork":false,"pushed_at":"2020-01-15T22:30:59.000Z","size":9,"stargazers_count":31,"open_issues_count":0,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-02T11:32:13.384Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bjornbytes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-12-02T05:02:41.000Z","updated_at":"2023-10-06T16:36:57.000Z","dependencies_parsed_at":"2024-01-03T04:02:35.729Z","dependency_job_id":null,"html_url":"https://github.com/bjornbytes/trickle","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjornbytes%2Ftrickle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjornbytes%2Ftrickle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjornbytes%2Ftrickle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bjornbytes%2Ftrickle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bjornbytes","download_url":"https://codeload.github.com/bjornbytes/trickle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246600735,"owners_count":20803470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:01:26.919Z","updated_at":"2025-04-01T07:31:43.131Z","avatar_url":"https://github.com/bjornbytes.png","language":"Lua","funding_links":[],"categories":["Serialization"],"sub_categories":[],"readme":"Trickle\n===\n\n\u003e **NOTE** - It's probably better to use Lua's built-in `string.pack` and `string.unpack` now.\n\nTrickle is a bitstream for Lua.  When writing data to a trickle stream, you must specify its size in\nbits.  The stream will automatically pack this data into compressed bytes, which often leads to\ngreatly reduced network bandwidth.  This is useful in networking applications where it is necessary\nto reduce network traffic, such as realtime multiplayer games.\n\nUsage\n---\n\n```lua\nlocal trickle = require 'trickle'\nlocal stream = trickle.create()\n\nstream:write(7, '3bits')\nstream:write(true, 'bool')\nstream:write(1.8, 'float')\n\n-- send over the network\n-- to convert a stream to a string, call tostring(stream)\n-- to convert a string to a stream, call trickle.create(string)\n\nstream:read('3bits') -- 7\nstream:read('bool') -- true\nstream:read('float') -- 1.8\n```\n\nSignatures\n---\n\nA signature describes a high level template for a message.  It can be used to reduce duplication in\nreading and writing of messages, and allows reading and writing of tables of data without having to\nwrite each individual field in a specific order.  First, define a signature:\n\n```lua\nlocal signature = {\n  { 'playerId', '4bits' },\n  { 'x', '8bits' },\n  { 'y', '8bits' },\n  { 'direction', '9bits' } -- direction in degrees\n}\n```\n\nThen, pack a message into a trickle stream using the signature:\n\n```lua\nlocal playerData = {\n  playerId = 1,\n  x = 63,\n  y = 41,\n  direction = 270\n}\n\nstream:pack(playerData, signature)\n```\n\n`unpack` may be used to decode the stream:\n\n```lua\nlocal playerData = stream:unpack(signature)\n```\n\n### Delta Groups\n\nLet's say we only want to send the position of the player if it has changed.  Right now this isn't\npossible with our signature, because we *have* to send 8 bits for the x position and 8 bits for the y\nposition to keep the structure of the signature uniform for the receiving end.  **Delta groups**\nprovide a mechanism to specify these optional groups of data.\n\nTo declare a delta group, specify a `delta` key in the signature table:\n\n```lua\nlocal signature = {\n  { 'playerId', '4bits'},\n  { 'x', '8bits' },\n  { 'y', '8bits' },\n  { 'direction', '9bits' },\n  delta = {\n    { 'x', 'y' },\n    'direction'\n  }\n}\n```\n\nWhat we've done is defined two optional pieces of our message: a group for the position of the\nplayer and a group for the direction of the player.  Now, if we pack a message like this:\n\n```lua\nlocal playerData = {\n  playerId = 1,\n  x = nil,\n  y = nil,\n  direction = nil\n}\n\nstream:pack(playerData, signature)\n```\n\ntrickle will only pack the 4 bit player id into the message, which saves 25 bits!  Internally,\na single bit is added to the beginning of the message for each delta group, signifying whether or\nnot its data is present.  This means that if a delta group contains more than one key (such as the\n'x' and 'y' group above), either all of the data must be present or all of it must be `nil`.  This,\nfor example, would result in an error:\n\n```lua\nlocal playerData = {\n  playerId = 1,\n  x = 17,\n  y = nil,\n  direction = 90\n}\n\nstream:pack(playerData, signature) -- Error: Only part of message delta group \"x, y\" was provided.\n```\n\nDocumentation\n---\n\n- `trickle.create([str])` - Creates a stream.  If `str` is provided then the contents of the stream\n  are set to this initial value.\n- `tostring(stream)` - Serialize the stream's data to a string.\n- `stream:clear()` - Resets the stream to contain no data.\n- `stream:truncate()` - If a byte has been partially written, it will not be present in the stream\n  yet.  `truncate` pads the rest of the byte with null data and adds it to the stream's data.  This\n  is mostly for internal use, and is automatically called when converting the stream to a string.\n\n#### Writing\n\n- `stream:write(value, type)` - Writes a value to the stream.  `type` can either be `string`,\n`float`, `bool`, or `\u003cn\u003ebits` for integers, where `n` is the number of bits the integer should use.\n- `stream:writeString(str)` - Writes a string to the stream.  Uses one byte per character.\n- `stream:writeBool(bool)` - Writes a boolean to the stream.  Uses one bit.\n- `stream:writeFloat(float)` - Writes a float to the stream.  Note that the float is currently\n  serialized as a string.  This is suboptimal and should be improved in the future.\n- `stream:writeBits(value, n)` - Writes a number to the stream, using `n` bits.\n\n#### Reading\n\n- `stream:read(type)` - Reads and returns a value from the stream.\n- `stream:readString()` - Reads and returns a string.\n- `stream:readBool()` - Reads and returns a boolean.\n- `stream:readFloat()` - Reads and returns a float.\n- `stream:readBits(n)` - Readss `n` bits from the string and returns them as a number.\n\n#### Signatures\n\n- `stream:pack(data, signature)` - Packs `data` into the stream according to the structure specified\n  by `signature`.\n- `stream:unpack(signature)` - Uses `signature` to read data from the string, returning a table with\n  the data.\n\nLicense\n---\n\nMIT, see [`LICENSE`](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbjornbytes%2Ftrickle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbjornbytes%2Ftrickle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbjornbytes%2Ftrickle/lists"}