6 |
7 | # Holy Light
8 |
9 | (Holy) Light is a *light*weight, robust, secure, and easy-to-use Remote Event wrapper for Roblox.
10 |
11 | ## Get Started
12 |
13 | Light is currently in development. The full source is not public at the moment, but documentation is available
14 | [here](https://light.ardi.gg/).
15 | If you like Light or find it interesting, consider leaving a ⭐ to save it for later, or watching the repository.
16 |
17 | ## Credits
18 |
19 | - Alice: Holy-Light Icon
20 | - Lewi: Helped develop docs :pray:
21 | - Max: Ported docs/types to roblox-ts
22 |
--------------------------------------------------------------------------------
/default.project.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "light",
3 | "tree": {
4 | "$className": "DataModel",
5 | "ReplicatedStorage": {
6 | "light": {
7 | "$path": "src"
8 | },
9 | "shared": {
10 | "$path": "dev/shared"
11 | }
12 | },
13 | "ServerScriptService": {
14 | "Server": {
15 | "$path": "dev/server"
16 | }
17 | },
18 | "ReplicatedFirst": {
19 | "Client": {
20 | "$path": "dev/client"
21 | }
22 | },
23 | "Workspace": {
24 | "$properties": {
25 | "FilteringEnabled": true
26 | },
27 | "Baseplate": {
28 | "$className": "Part",
29 | "$properties": {
30 | "Anchored": true,
31 | "Color": [
32 | 0.38823,
33 | 0.37254,
34 | 0.38823
35 | ],
36 | "Locked": true,
37 | "Position": [
38 | 0,
39 | -10,
40 | 0
41 | ],
42 | "Size": [
43 | 512,
44 | 20,
45 | 512
46 | ]
47 | }
48 | }
49 | },
50 | "Lighting": {
51 | "$properties": {
52 | "Ambient": [
53 | 0,
54 | 0,
55 | 0
56 | ],
57 | "Brightness": 2,
58 | "GlobalShadows": true,
59 | "Outlines": false,
60 | "Technology": "Voxel"
61 | }
62 | },
63 | "SoundService": {
64 | "$properties": {
65 | "RespectFilteringEnabled": true
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/dev/client/init.client.luau:
--------------------------------------------------------------------------------
1 | game.Loaded:Wait()
2 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
3 |
4 | local light = require(ReplicatedStorage.light).client
5 | local messages = require(ReplicatedStorage.shared.messages)
6 |
7 | light.begin_replication()
8 |
9 | task.wait(0.5)
10 |
11 | local I = true
12 | local O = false
13 |
14 | light.send(messages.foo, { O, O, O, O })
15 | light.send(messages.foo, { O, O, O, I })
16 | light.send(messages.foo, { I, O, I, O })
17 |
18 | light.connect(messages.foo, function(data: typeof(messages.foo)): ()
19 | print(data)
20 | end)
21 |
22 | light.connect(messages.player_connected, function(data: typeof(messages.player_connected)): ()
23 | print(data)
24 | end)
25 |
26 | light.send(messages.bar, { 1, 25, 255, 0, 10 })
27 |
--------------------------------------------------------------------------------
/dev/server/init.server.luau:
--------------------------------------------------------------------------------
1 | local Players = game:GetService("Players")
2 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
3 |
4 | local light = require(ReplicatedStorage.light).server
5 | local messages = require(ReplicatedStorage.shared.messages)
6 |
7 | light.begin_replication()
8 |
9 | Players.PlayerAdded:Connect(function(plr): ()
10 | light.send(messages.foo, plr, { true, true, false, true })
11 | light.broadcast_to_all(messages.player_connected, plr)
12 | light.broadcast_to_all_except(messages.player_connected, plr, plr)
13 | end)
14 |
15 | light.connect(messages.foo, function(plr, data)
16 | print(plr, data)
17 | end)
18 |
19 | light.connect(messages.bar, function(plr, data)
20 | print(plr, data)
21 | end)
22 |
--------------------------------------------------------------------------------
/dev/shared/messages.luau:
--------------------------------------------------------------------------------
1 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
2 |
3 | local light = require(ReplicatedStorage:WaitForChild("light")).shared
4 |
5 | local ty = light.datatypes
6 |
7 | local messages = {
8 | foo = { ty.bool },
9 | bar = { ty.u8 },
10 | player_connected = ty.instances.Player,
11 | }
12 |
13 | local container = light.container(messages)
14 |
15 | return container
16 |
--------------------------------------------------------------------------------
/docs/api/begin_replication.md:
--------------------------------------------------------------------------------
1 | # Begin Replication
2 |
3 | `#!luau function light.begin_replication()` Can be called at any time to allow messages to be sent on the client or
4 | server, but it's best to get it out of the way. Calling multiple times or from multiple files has no additional effects.
5 | If you call it later on, all of the messages you try to send will still get queued up.
6 |
7 | ## `#!luau function light.begin_replication`
8 |
9 | ```luau title=' '
10 | function begin_replication(
11 | ): ()
12 | ```
13 |
14 | You can use [`#!luau light.step_replication()`](./step_replication.md) instead of this if you prefer a manual
15 | replication step.
16 |
--------------------------------------------------------------------------------
/docs/api/datatypes/any.md:
--------------------------------------------------------------------------------
1 | # Any
2 |
3 | Represents a value which should be serialized with the format Roblox's Remote Events use.
4 |
5 | !!!tip Consider alternatives
6 |
7 | Consider using [Instances](./instances.md) or [Checked](./generics/checked.md) over `any`. This is because `any`
8 | can't check that the type sent over the network is correct, and can be manipulated by exploiters.
9 |
10 | !!!danger Unreliables
11 |
12 | Using this while [sending unreliably](../network/messages/sending/send_unreliably.md) can cause things to
13 | consistently fail to send if the packet is too large.
14 |
15 | ## `#!luau local light.datatypes.any`
16 |
17 | ```luau title=' '
18 | local any: any
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/api/datatypes/bool.md:
--------------------------------------------------------------------------------
1 | # Bool
2 |
3 | Represents `true | false`.
4 |
5 | Booleans (for most intents and purposes)(1) cost 1/8th of a byte to send over the network.
6 | {.annotate}
7 |
8 | 1. To learn more about how Light's Bitpacking works, check out
9 | [The Internals Blog](../../blog/internals/bitpacks.md) on the topic.
10 |
11 | ## `#!luau local light.datatypes.bool`
12 |
13 | ```luau title=' '
14 | local bool: true | false
15 | ```
16 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/buff.md:
--------------------------------------------------------------------------------
1 | # Buffers
2 |
3 | Represents a
4 | `#!luau buffer`.
5 |
6 | Includes an optional parameter for length which will default to [`#!luau datatypes.vlq(3)`](./vlq.md).
7 |
8 | The length datatype should NOT be a regular number—instead: use a
9 | datatype that represents a number, like a [`uint`](../numbers/uints.md), or a
10 | [`range`](./range.md#function-lightdatatypesrange).
11 |
12 | ## `#!luau function light.datatypes.buff`
13 |
14 | ```luau title=' '
15 | function buff(
16 | length: Datatype?
17 | ): (Datatype)
18 | ```
19 |
20 | A couple of ways you could use the optional `length` parameter:
21 |
22 | ```luau
23 | local types = light.datatypes
24 |
25 | local some_buff = types.buff( types.u8 ) -- Buffer between 0-255 bytes
26 | ```
27 |
28 | ```luau
29 | local some_buff = types.buff( types.range(0, 50) ) -- Buffer should be between 0 and 50 bytes.
30 | ```
31 |
32 | ```luau
33 | local some_buff = types.buff( types.literal(3) ) -- A buffer with 3 bytes.
34 | ```
35 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/cached.md:
--------------------------------------------------------------------------------
1 | # Cached
2 |
3 | In light, [you can use lua table syntax](./tables/index.md) to represent a [Datatype](../index.md#what-is-a-datatype), and it'll be
4 | converted automatically when you use it in a Message.
5 |
6 | This API exists to manually cache the result of a [Datatype](../index.md#what-is-a-datatype). This will internally turn it into a numeric
7 | ID if it isn't one already, rendering it unusable for anything other than ser/des and messages. Messages cache their
8 | [Datatypes](../index.md#what-is-a-datatype) automatically, but this can be useful in conjunction with other features like
9 | [Computed Datatypes](./computed.md).
10 |
11 | ## `#!luau function light.datatypes.cached`
12 |
13 | ```luau title=' '
14 | function cached(
15 | value: Datatype
16 | ): (Datatype)
17 | ```
18 |
19 | An example
20 | LinkedList [Datatype](../index.md#what-is-a-datatype)
21 | using [`#!luau datatypes.cached()`](./cached.md) and [`#!luau datatypes.computed()`](./computed.md):
22 |
23 | ```luau title="linked_list.luau"
24 | local types = datatypes
25 |
26 | -- as a word of warning, you probably shouldn't give this a `head` field.
27 | local function linkedlist(value: Datatype)
28 | local Datatype
29 |
30 | Datatype = types.cached {
31 | next = types.optional(types.computed(function()
32 | return Datatype
33 | end)),
34 |
35 | value = value
36 | }
37 |
38 | return Datatype
39 | end
40 |
41 | return linkedlist
42 | ```
43 |
44 | !!! danger "[`#!luau light.computed()`](./computed.md) allows for recursive types."
45 |
46 | If you pass a self-referential table, serialization may hang forever.
47 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/checked.md:
--------------------------------------------------------------------------------
1 | # Checked
2 |
3 | For types that are especially hard to describe, you could use `checked`. Checked is generally an [any](../any.md)
4 | [Datatype](../index.md#what-is-a-datatype) which allows you to pass a "sanity check" callback. This makes sure that even
5 | though Roblox's default networking is used, you still get proper type validation & annotation.
6 |
7 | ## `#!luau function light.datatypes.checked`
8 |
9 | ```luau title=' '
10 | function checked(
11 | sanity_check: (Input) -> (Checked)
12 | ): (Datatype)
13 | ```
14 |
15 | ## Example
16 |
17 | Let's say you want to send a [SkateboardPlatform](https://robloxapi.github.io/ref/class/SkateboardPlatform.html)
18 | across the network. (Blasphemy)
19 |
20 | ```luau title='blasphemy.luau'
21 | local ty = light.datatypes
22 |
23 | local skateboard_platform = ty.checked(function(input: Instance)
24 | assert(input:IsA("SkateboardPlatform"))
25 | return input :: SkateboardPlatform
26 | end)
27 | ```
28 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/clamp.md:
--------------------------------------------------------------------------------
1 | # Clamp
2 |
3 | Represents a range of possible integers by providing a minimum and maximum, then encoding / decoding the equivalent of
4 | `#!luau math.clamp(input, minimum, maximum)`.
5 |
6 | ## `#!luau function light.datatypes.clamp`
7 |
8 | ```luau title=' '
9 | function clamp(
10 | minimum: number,
11 | maximum: number
12 | ): (Datatype)
13 | ```
14 |
15 | ## Size
16 |
17 | Will use the minimum number of bytes possible to represent the range of possible numbers:
18 |
19 | | `#!luau math.abs(maximum - minimum) < n` | Size |
20 | | -----------------------------------------------------------------------------------------------------------------------------------------: | :-------- |
21 | | `n = 256` | `1 Byte` |
22 | | `n = 65,536` | `2 Bytes` |
23 | | `n = 16,777,216` | `3 Bytes` |
24 | | `n = 4,294,967,296` | `4 Bytes` |
25 | | `n = 2 ^ 40` | `5 Bytes` |
26 | | `n = 2 ^ 48` | `6 Bytes` |
27 | | `n = 2 ^ 56` | `7 Bytes` |
28 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/literal.md:
--------------------------------------------------------------------------------
1 | # Literals
2 |
3 | Literals represent a value which is "literally" something.
4 |
5 | Any value you pass to a literal will be decoded as a constant and cost zero bytes. Literals do not perform any
6 | validation on inputs; instead, the value will be cast to the literal value on serialization[¹](#validating).
7 |
8 | ## `#!luau function light.datatypes.literal`
9 |
10 | ```luau title=' '
11 | function literal(
12 | value: Value
13 | ): (Datatype)
14 | ```
15 |
16 | ## Validating
17 |
18 | If you want to make sure the input equals the value the literal represents, you could use an
19 | [Identifier Enum](./enums.md#identifier-enums)(1) with only a single item:
20 | {.annotate}
21 |
22 | 1. By doing this, you acknowledge that there are inherent risks involved in using an
23 | [Identifier Enum](./enums.md#identifier-enums) for the purpose of validating a literal value, including the risk of
24 | emotional distress, personal injury, death, and/or property damage. I understand that by participating in this
25 | activity, I am voluntarily accepting these risks. I hereby release and discharge holy-light from any and all
26 | liability, claims, demands, or causes of action of any kind whatsoever arising out of or in connection with my
27 | participation in this activity, including but not limited to claims for emotional distress, personal injury, death,
28 | and/or property damage.
29 |
30 | ```luau
31 | local ty = light.datatypes
32 |
33 | local literal = ty.literal(15)
34 | local checked_literal = ty.enum({15})
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/optional.md:
--------------------------------------------------------------------------------
1 | # Optionals
2 |
3 | Optionals represent a value which could be `nil`, and can be applied to any datatype. Optionals are most often used from
4 | within a [`struct`](./tables/struct.md), where you might not want or need all fields to exist in the data you're
5 | sending.
6 |
7 | ## `#!luau function light.datatypes.optional`
8 |
9 | ```luau title=' '
10 | function optional(
11 | inner: Datatype
12 | ): Datatype
13 | ```
14 |
15 | ## Example
16 |
17 | Let's say you want to represent some settings that have a value or be unset. A really simple and efficient way to encode
18 | that data is with a struct of optionals.
19 |
20 | ```luau
21 | local ty = light.datatypes
22 |
23 | local opt = ty.optional
24 |
25 | local settings_packet = {
26 | field_of_view = opt(ty.range(60, 140)),
27 | depth_of_field = opt(ty.bool),
28 | sprint_key = opt(ty.)
29 | }
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/roblox_vect2.md:
--------------------------------------------------------------------------------
1 | # Vector2
2 |
3 | Represents a
4 | Roblox `#!luau Vector2`
5 | [Datatype](../index.md#what-is-a-datatype).
6 |
7 | There is an optional `coord` parameter representing each coordinate (`x`, `y`) which defaults to
8 | [`f32`](../numbers/floats.md). It is worth noting that an [`f64`](../numbers/floats.md) [Datatype](../index.md#what-is-a-datatype)'s
9 | precision won't apply here, so [`f32`](../numbers/floats.md) is always better for vectors.
10 |
11 | ## `#!luau function light.datatypes.roblox_vect2`
12 |
13 | ```luau title=' '
14 | function roblox_vect2(
15 | coord: Datatype?
16 | ): Datatype
17 | ```
18 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/str.md:
--------------------------------------------------------------------------------
1 | # Strings
2 |
3 | Represents a string value.
4 |
5 | Includes an optional parameter for length which will default to
6 | [`#!luau datatypes.vlq(3)`](./vlq.md#size-index).
7 |
8 | The length datatype should NOT be a regular number—instead: use a
9 | datatype that represents a number, like a [`uint`](../numbers/uints.md), or a
10 | [`range`](./range.md#function-lightdatatypesrange).
11 |
12 | ## `#!luau function light.datatypes.str`
13 |
14 | ```luau title=' '
15 | function str(
16 | length: Datatype?
17 | ): Datatype
18 | ```
19 |
20 | A couple of ways you could use the optional `length` parameter:
21 |
22 | ```luau
23 | local ty = light.datatypes
24 |
25 | local some_str = ty.str( ty.u8 ) -- length between 0-255
26 | ```
27 |
28 | ```luau
29 | local some_str = ty.str( ty.range(0, 50) ) -- String should be between length 0 and 50.
30 | ```
31 |
32 | ```luau
33 | local some_str = ty.str( ty.literal(3) ) -- A string of length 3.
34 | ```
35 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/tables/arr.md:
--------------------------------------------------------------------------------
1 | # Arrays
2 |
3 | Arrays are quite simple.
4 |
5 | An array represents a contiguous list of values in a table. I.e., `#!luau { "a", "b", "c" }`
6 |
7 | An array shouldn't have any `#!luau nil`s or "gaps". If you want holes in a table, use [Maps](./map.md).
8 |
9 | You can define a valid array [Datatype](../../index.md#what-is-a-datatype) using a simple table, just like luau:
10 |
11 | ```luau
12 | local ty = light.datatypes
13 |
14 | local some_array = { ty.u8 }
15 | ```
16 |
17 | Using the above table syntax will behave the same as passing the table into the API shown below.
18 |
19 | ## `#!luau function light.datatypes.arr`
20 |
21 | ```luau title=' '
22 | function arr(
23 | item: Datatype,
24 | length: Datatype?
25 | ): (Datatype<{T}>)
26 | ```
27 |
28 | First argument should be any [Datatype](../../index.md#what-is-a-datatype) which cannot be `#!luau nil`. The `length`
29 | parameter describes the number of items in the array, and will default to
30 | [`#!luau datatypes.u16`](../../numbers/uints.md).
31 |
32 | The length datatype should NOT be a regular number—instead: use a
33 | datatype that represents a number, like a [`uint`](../../numbers/uints.md), or a
34 | [`range`](../range.md#function-lightdatatypesrange).
35 |
36 | A couple of ways you could use the optional `length` parameter:
37 |
38 | ```luau
39 | local some_arr = ty.arr( ty.u8, ty.range(0, 50) ) -- Array should have between 0 and 50 items.
40 | ```
41 |
42 | ```luau
43 | local some_arr = ty.arr( ty.u8, ty.literal(3) ) -- Array will always have three items.
44 | ```
45 |
46 | ```luau
47 | local some_arr = ty.arr( ty.u8, ty.u8 ) -- between 0-255 items.
48 | ```
49 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/tables/index.md:
--------------------------------------------------------------------------------
1 | # Tables
2 |
3 | Table [Datatypes](../../index.md#what-is-a-datatype) represent a luau table.
4 |
5 | A big advantage to light as a library is that all [Datatypes](../../index.md#what-is-a-datatype) which directly represent a table can be
6 | defined easily with lua table syntax and used almost anywhere in the library. For more info, see
7 | [`#!luau datatypes.cached()`](../cached.md).
8 |
9 | ## [Arrays](./arr.md) [`#!luau datatypes.arr()`](./arr.md#function-lightdatatypesarr)
10 |
11 | ```luau
12 | local ty = light.datatypes
13 | local u8 = ty.u8
14 |
15 | local some_array = { u8 } -- This is a totally valid array Datatype
16 | ```
17 |
18 | ## [Maps](./map.md) [`#!luau datatypes.map()`](./map.md#function-lightdatatypesmap)
19 |
20 | ```luau
21 | local str = ty.str()
22 |
23 | local some_map = { [str] = u8 }
24 | -- Exporting types has never been easier
25 | export type some_map = typeof(some_map)
26 | ```
27 |
28 | ## [Structs](./struct.md) [`#!luau datatypes.struct()`](./struct.md#function-lightdatatypesstruct)
29 |
30 | ```luau
31 | local struct = {--(1)!
32 | a = u8,
33 | b = {
34 | c = { u8 },
35 | d = { [str] = u8 }
36 | }
37 | }
38 | ```
39 |
40 | 1. Struct Merging
41 |
42 | Because of this design, merging structs together is as simple as writing yourself a table_merge utility:
43 |
44 | ```luau title='struct_merge.luau'
45 | local function struct_merge(from: From, into: Into): Into & From
46 | local output = table.clone(into)
47 | for field_name, field_type in from do
48 | assert(not output[field_name], `Duplicate Field Name: {field_name}`)
49 | output[field_name] = field_type
50 | end
51 | return output
52 | end
53 | ```
54 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/tables/map.md:
--------------------------------------------------------------------------------
1 | # Maps
2 |
3 | Maps (a.k.a. Dictionaries) are quite simple.
4 |
5 | A map represents a set of keys and values in a table.(1)
6 | {.annotate}
7 |
8 | 1. I.e., This is something you might want to represent with a map:
9 |
10 | ```luau
11 | local abc = { [tostring(math.random())] = 255 }
12 | ```
13 |
14 | You can define a valid map [Datatype](../../index.md#what-is-a-datatype) using a simple table, just like luau:
15 |
16 | ```luau
17 | local ty = light.datatypes
18 |
19 | local some_map = { [ty.str()] = ty.u8 }
20 | ```
21 |
22 | Using the above table syntax will behave the same as passing the table into the API shown below.
23 |
24 | ## `#!luau function light.datatypes.map`
25 |
26 | ```luau title=' '
27 | function map(
28 | key: Datatype,
29 | value: Datatype,
30 | length: Datatype?
31 | ): (Datatype<{ [Key]: Value }>)
32 | ```
33 |
34 | First two arguments should be any [Datatypes](../../index.md#what-is-a-datatype) which cannot represent `#!luau nil`.
35 | The `length` parameter should represent the number of keys in the map, and will default to
36 | [`#!luau datatypes.u16`](../../numbers/uints.md).
37 |
38 | The length datatype should NOT be a regular number—instead: use a
39 | datatype that represents a number, like a [`uint`](../../numbers/uints.md), or a
40 | [`range`](../range.md#function-lightdatatypesrange).
41 |
42 | A couple of ways you could use the optional `length` parameter:
43 |
44 | ```luau
45 | local some_map = ty.map( ty.str(), ty.u8, ty.u8 ) -- between 0-255 keys.
46 | ```
47 |
48 | ```luau
49 | local some_map = ty.map( ty.str(), ty.u8, ty.range(0, 50) ) -- Map should have between 0 and 50 keys.
50 | ```
51 |
52 | ```luau
53 | local some_map = ty.map( ty.str(), ty.u8, ty.literal(3) ) -- Map will always have three keys.
54 | ```
55 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/tables/struct.md:
--------------------------------------------------------------------------------
1 | # Structs
2 |
3 | Structs are quite simple.
4 |
5 | A struct represents a fixed set of string keys and value datatypes.
6 |
7 | Structs are not guaranteed to have exactly the field order you defined them with, but the order of their fields is
8 | identical on client and server.
9 |
10 | You can define a valid struct [Datatype](../../index.md#what-is-a-datatype) using a simple table, just like luau:
11 |
12 | ```luau
13 | local ty = light.datatypes
14 |
15 | local some_struct = {--(1)!
16 | a = ty.u8,
17 | b = ty.i16,
18 | c = {
19 | some = ty.str(),
20 | thing = ty.u8
21 | }
22 | }
23 | ```
24 |
25 | 1. Struct Merging
26 |
27 | Because of this design, merging structs together is as simple as writing a table merging utility:
28 |
29 | ```luau title='struct_merge.luau'
30 | local function struct_merge(from: From, into: Into): Into & From
31 | local output = table.clone(into)
32 | for field_name, field_type in from do
33 | assert(not output[field_name], `Duplicate Field Name: {field_name}`)
34 | output[field_name] = field_type
35 | end
36 | return output
37 | end
38 | ```
39 |
40 | Using the above table syntax will behave the same as passing the table into the API shown below.
41 |
42 | ## `#!luau function light.datatypes.struct`
43 |
44 | ```luau title=' '
45 | function struct(--Sync--
46 | map: Fields, -- { [string]: Datatype }
47 | ): (Datatype)
48 | ```
49 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/vect2.md:
--------------------------------------------------------------------------------
1 | # Vect2
2 |
3 | Represents a 2 component luau `#!luau vector`.
4 |
5 | There is an optional `coord` parameter representing each coordinate (`x`, `y`) which defaults to
6 | [`f32`](../numbers/floats.md). It is worth noting that an [`f64`](../numbers/floats.md) [Datatype](../index.md#what-is-a-datatype)'s
7 | precision won't apply here, so [`f32`](../numbers/floats.md) is always better for vectors.
8 |
9 | ## `#!luau function light.datatypes.vect2`
10 |
11 | ```luau title=' '
12 | function vect2(
13 | coord: Datatype?
14 | ): Datatype
15 | ```
16 |
17 | The `coord` parameter defines how each coordinate of [`#!luau light.vect2()`] will be encoded. If left unselected, it
18 | will choose [`float32`](../numbers/floats.md) by default. Luau cannot represent floats beyond
19 | [`f32`](../numbers/floats.md) in a vector, so using a [`f64`](../numbers/floats.md) for this would be wasteful.
20 |
--------------------------------------------------------------------------------
/docs/api/datatypes/generics/vect3.md:
--------------------------------------------------------------------------------
1 | # Vect3
2 |
3 | Represents a 3 component luau `#!luau vector`.
4 |
5 | There is an optional `coord` parameter representing each coordinate (`x`, `y`, `z`) which defaults to
6 | [`f32`](../numbers/floats.md). It is worth noting that an [`f64`](../numbers/floats.md) [Datatype](../index.md#what-is-a-datatype)'s
7 | precision won't apply here, so [`f32`](../numbers/floats.md) is always be better for vectors.
8 |
9 | ## `#!luau function light.datatypes.vect3`
10 |
11 | ```luau title=' '
12 | function vect3(
13 | coord: Datatype?
14 | ): Datatype
15 | ```
16 |
--------------------------------------------------------------------------------
/docs/api/datatypes/index.md:
--------------------------------------------------------------------------------
1 | # Datatypes
2 |
3 | ## What is a Datatype?
4 |
5 | A datatype is something that represents a set of possible values. When you're sending something across the network
6 | with light, you'll need to define what you want that thing to look like. Light has a lot of tools for doing
7 | just that, but here's an example of one of the primitive number Datatypes:
8 |
9 | [`#!luau local u8 = light.datatypes.u8`](./numbers/uints.md)
10 |
11 | The prefix `u` indicates the number should be an "unsigned integer"; a whole number greater than zero. The number to the right, `8`, is the number
12 | of "bits"[^1] the value will take up across the network. A u8 represents a value between `0` and `255`
13 |
14 | ## Lying to luau
15 |
16 | Generally, places where you see `#!luau Datatype` in these docs, you will only see `#!luau T` or a type in your
17 | editor. Generally, this avoids causing problems with Luau's type system.
18 |
19 | [^1]:
20 |
21 | 8 bits is also known as a byte. `#!luau local bytes = bits // 8` &
22 | `#!luau local bits = 8·bytes`
23 |
--------------------------------------------------------------------------------
/docs/api/datatypes/numbers/floats.md:
--------------------------------------------------------------------------------
1 | # Floating Points
2 |
3 | Floating points represent a number with decimal places.
4 |
5 | You can tell a [Datatype](../index.md#what-is-a-datatype) represents a decimal number if its name has the `f` prefix.
6 | The number afterward tells you how many bits the [Datatype](../index.md#what-is-a-datatype) costs to send over the
7 | network.
8 |
9 | ## Size Index
10 |
11 | | Name | Size | Maximum Int | Minimum Int |
12 | | -----: | :-------- | ----------- | -------------- |
13 | | `f32` | `4 bytes` | `16777216` | `−16777216` |
14 | | `f64` | `8 bytes` | `2^53` | `-2^53` |
15 |
16 | You can access each one with `light.datatypes.`.
17 |
--------------------------------------------------------------------------------
/docs/api/datatypes/numbers/ints.md:
--------------------------------------------------------------------------------
1 | # Signed Integers
2 |
3 | Signed Integers represent a number which is divisible by one and could be negative.
4 |
5 | You can tell a [Datatype](../index.md#what-is-a-datatype) represents a signed integer if its name has the `i` prefix.
6 | The number afterward tells you how many bits the [Datatype](../index.md#what-is-a-datatype) costs to send over the network.
7 |
8 | ## Size Index
9 |
10 | | Name | Size | Maximum Int | Minimum Int |
11 | | -----: | :-------- | ----------------- | ----------------- |
12 | | `i8` | `1 byte` | `127` | `- 128` |
13 | | `i16` | `2 bytes` | `32,767` | `- 32,768` |
14 | | `i24` | `3 bytes` | `8,388,607` | `- 8,388,608` |
15 | | `i32` | `4 bytes` | `2,147,483,647` | `- 2,147,483,648` |
16 | | `i40` | `5 bytes` | `2^39 - 1` | `- 2^39` |
17 | | `i48` | `6 bytes` | `2^47 - 1` | `- 2^47` |
18 | | `i53` | `7 bytes` | `2^52 - 1` | `- 2^52` |
19 |
20 | You can access each one with `light.datatypes.`.
21 |
22 | The set of possible values is defined as `-2 ^ (bits - 1)` to `2 ^ (bits - 1) - 1`.
23 |
--------------------------------------------------------------------------------
/docs/api/datatypes/numbers/uints.md:
--------------------------------------------------------------------------------
1 | # Unsigned Integers
2 |
3 | Unsigned Integers represent a whole number which is greater than or equal to zero. For numbers with decimal places, you
4 | should use a [Float](./floats.md).
5 |
6 | You can tell a [Datatype](../index.md#what-is-a-datatype) represents an unsigned integer if its name has the `u` prefix.
7 | The number afterward tells you how many bits the [Datatype](../index.md#what-is-a-datatype) costs to send over the network.
8 |
9 | ## Size Index
10 |
11 | | Name | Size | Maximum Int | Minimum Int |
12 | | -----: | :---------- | --------------- | -------------- |
13 | | `u8` | `1 byte` | `255` | `0` |
14 | | `u16` | `2 bytes` | `65,535` | `0` |
15 | | `u24` | `3 bytes` | `16,777,215` | `0` |
16 | | `u32` | `4 bytes` | `4,294,967,295` | `0` |
17 | | `u40` | `5 bytes` | `2^40 - 1` | `0` |
18 | | `u48` | `6 bytes` | `2^48 - 1` | `0` |
19 | | `u56` | `7 bytes` | `2^53` | `0` |
20 |
21 | You can access each one with `light.datatypes.`.
22 |
23 | The set of possible values is defined as `0` to `(2 ^ bits) - 1`.
24 |
--------------------------------------------------------------------------------
/docs/api/index.md:
--------------------------------------------------------------------------------
1 | # API Documentation
2 |
3 | This part of the documentation is for all of the properties and functions you're able to access inside of light's API.
4 | It also teaches you more about Datatypes and ways you could use them efficiently.
5 |
6 | ## Tags
7 |
8 | ###
9 |
10 | API can be accessed on the client:
11 | `#!luau require(ReplicatedStorage.light).client`
12 |
13 | ###
14 |
15 | API can be accessed on the server:
16 | `#!luau require(ReplicatedStorage.light).server`
17 |
18 | ###
19 |
20 | API can be accessed in a shared context:
21 | `#!luau require(ReplicatedStorage.light).shared`
22 |
23 | ###
24 |
25 | Function can run without yielding the current thread
26 |
27 | ###
28 |
29 | Function can yield the current thread
30 |
31 | ###
32 |
33 | Function can error under specific circumstances.(1)
34 | {.annotate}
35 |
36 | 1. This tag does not include errors from user mistakes, like trying to write a `string` into a `u8` Datatype, or calling
37 | an API with the wrong parameters.
38 |
39 | ###
40 |
41 | This part of the API is considered experimental for now, and may change or be removed at any point.
42 |
--------------------------------------------------------------------------------
/docs/api/internals/get_holy.md:
--------------------------------------------------------------------------------
1 | # Get Holy
2 |
3 | [`#!luau light.get_holy()`](./get_holy.md) allows you to access the [holy](https://github.com/hardlyardi/holy) serdes
4 | "Instance" Light uses.
5 |
6 | ## `#!luau function light.internal.get_holy()`
7 |
8 | ```luau title=' '
9 | function get_holy(
10 | ): (HolyApi)
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/api/internals/index.md:
--------------------------------------------------------------------------------
1 | # Internal API
2 |
3 | If you're a regular user, your reading can stop here. More advanced features are available under this section, but they
4 | often require in-depth technical knowledge to use safely. The APIs here are a lower priority when it comes to breaking
5 | changes and documentation, so you're more likely to end up somewhere confusing or broken.
6 |
--------------------------------------------------------------------------------
/docs/api/internals/io/input.md:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 | [`#!luau light.input()`](./input.md) is a function which allows you to use light's internal serialization on your own
4 | [DynamicWriter](./writer/index.md).
5 |
6 | ## `#!luau function light.internal.input`
7 |
8 | ```luau title=' '
9 | function input(
10 | writer: DynamicWriter,
11 | type: Datatype,
12 | data: T
13 | ): ()
14 | ```
15 |
16 | You'll need to provide a valid [DynamicWriter](./writer/index.md), [Datatype](../../datatypes/index.md#what-is-a-datatype), and some
17 | data to serialize. You can deserialize the data with [Output](./output.md).
18 |
19 | !!! danger "Use correct data or `#!luau pcall()`"
20 |
21 | If the data is incorrect, this function may error.
22 |
23 | !!! danger "The buffer may change"
24 |
25 | After calling light.input, the buffer the writer contains may change because it had to be resized. Do not hold onto
26 | buffers when using this API, each time you call it assume the only safe way to get the buffer directly is with
27 | [`#!luau light.internal.get_writer_buff()`](./writer/get_writer_buff.md).
28 |
--------------------------------------------------------------------------------
/docs/api/internals/io/output.md:
--------------------------------------------------------------------------------
1 | # Output
2 |
3 | [`#!luau light.output()`](./input.md) is a function which allows you to use light's internal deserialization on your own
4 | [DynamicWriter](./writer/index.md). Usually after you've called [`#!luau light.input()`](./input.md) already.
5 |
6 | ## `#!luau function light.internal.output`
7 |
8 | ```luau title=' '
9 | function output(
10 | writer: DynamicWriter,
11 | type: Datatype
12 | ): (Data)
13 | ```
14 |
15 | You'll need to provide a valid [DynamicWriter](./writer/index.md), and [Datatype](../../datatypes/index.md#what-is-a-datatype). You can
16 | serialize the data with [`#!luau light.input()`](./input.md).
17 |
18 | !!! danger "Use correct data or `#!luau pcall()`"
19 |
20 | If the data is incorrect, this function may error.
21 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/get_byte_ptr.md:
--------------------------------------------------------------------------------
1 | # Get Byte Ptr
2 |
3 | Requires a valid [DynamicWriter](./index.md), returns its current byte_ptr.
4 |
5 | ## `#!luau function light.internal.get_byte_ptr()`
6 |
7 | ```luau title=' '
8 | function get_byte_ptr(
9 | writer: DynamicWriter
10 | ): (number)
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/get_writer_buff.md:
--------------------------------------------------------------------------------
1 | # Get Buffer
2 |
3 | Returns a buffer from a valid [DynamicWriter](./index.md).
4 |
5 | ## `#!luau function light.internal.get_writer_buff()`
6 |
7 | ```luau title=' '
8 | function get_writer_buff(
9 | writer: DynamicWriter
10 | ): (buffer)
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/index.md:
--------------------------------------------------------------------------------
1 | # Dynamic Writer
2 |
3 | Light exposes the ability to access internal serialization and deserialization with the input/output API. A dynamic
4 | writer and the underlying API provides an interface for using light's features at a low level. You can create one with
5 | [`#!luau light.internal.writer_from_buff()`](./writer_from_buff.md) or
6 | [`#!luau light.internal.writer_from_size()`](./writer_from_size.md). You can write to them with
7 | [`#!luau light.internal.input()`](../input.md) and read their data with
8 | [`#!luau light.internal.output()`](../output.md).
9 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/set_byte_ptr.md:
--------------------------------------------------------------------------------
1 | # Set Byte Ptr
2 |
3 | Requires a valid [DynamicWriter](./index.md), and a byte ptr.
4 |
5 | !!! danger "No bounds check"
6 |
7 | No bounds check will be done on the byte ptr, it can be set to an area of the buffer that is out of bounds.
8 |
9 | ## `#!luau function light.internal.set_byte_ptr()`
10 |
11 | ```luau title=' '
12 | function set_byte_ptr(
13 | writer: DynamicWriter,
14 | byte_ptr: number
15 | ): ()
16 | ```
17 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/try_realloc.md:
--------------------------------------------------------------------------------
1 | # Try Realloc
2 |
3 | Makes sure a valid [DynamicWriter](./index.md) has the amount of space specified, resizing the buffer if necessary.
4 |
5 | !!! danger "The buffer may change"
6 |
7 | After calling [`#!luau light.internal.try_realloc()`](./try_realloc.md), the buffer the writer contains may change
8 | because it had to be resized. Do not hold onto buffers when using this API. Each time you call it, the only
9 | safe way to get the buffer is with [`#!luau light.io.get_writer_buff()`](./get_writer_buff.md).
10 |
11 | ## `#!luau function light.internal.try_realloc()`
12 |
13 | ```luau title=' '
14 | function try_realloc(
15 | writer: DynamicWriter,
16 | target_ptr: number
17 | ): ()
18 | ```
19 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/writer_from_buff.md:
--------------------------------------------------------------------------------
1 | # DynamicWriter From Buffer
2 |
3 | Returns a valid [DynamicWriter](./index.md) from a buffer.
4 |
5 | ## `#!luau function light.internal.writer_from_buff()`
6 |
7 | ```luau title=' '
8 | function writer_from_buff(
9 | buff: buffer
10 | ): (DynamicWriter)
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/api/internals/io/writer/writer_from_size.md:
--------------------------------------------------------------------------------
1 | # DynamicWriter From Size
2 |
3 | Allocates a buffer and returns a valid [DynamicWriter](./index.md) from a size of bytes.
4 |
5 | ## `#!luau function light.internal.writer_from_size()`
6 |
7 | ```luau title=' '
8 | function writer_from_size(
9 | bytes: number
10 | ): (DynamicWriter)
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/api/network/messages/creation/container.md:
--------------------------------------------------------------------------------
1 | # Containers
2 |
3 | Containers are the recommended and easy way to group together messages in light by name.
4 |
5 | Container inputs should be a map of string message-names to any valid [Datatype](../../../datatypes/index.md#what-is-a-datatype).
6 | This includes [Datatypes](../../../datatypes/index.md#what-is-a-datatype) like arrays or maps that are defined with luau tables.
7 | I.e., `#!luau { light.datatypes.u8 }`
8 |
9 | !!! info "If messages inside are already synchronized beforehand, the container will not yield."
10 |
11 | The server defines the messages immediately, so `#!luau container {...}` will never yield on the server.
12 |
13 | ## `#!luau function light.container` (On The Client)
14 |
15 | ```luau title=' '
16 | function container(
17 | message_names: MessageNames, -- { [string]: Datatype }
18 | namespace: string? --(1)!
19 | ): (MessageNames)
20 | ```
21 |
22 | ## `#!luau function light.container` (On The Server)
23 |
24 | ```luau title=' '
25 | function container(
26 | message_names: T, -- { [string]: Datatype }
27 | namespace: string?
28 | ): (T)
29 | ```
30 |
31 | !!!tip "Namespaces don't impact behavior"
32 |
33 | Namespaces do not impact message ordering whatsoever in light. They are entirely cosmetic, allowing you to have
34 | multiple containers with overlapping message names.
35 |
36 | Some example code using containers:
37 |
38 | ```luau
39 | local light = require(ReplicatedStorage.light).shared
40 |
41 | local ty = light.datatypes
42 |
43 | return light.container({
44 | abc = { ty.u8 }, -- send a table of u8 numbers
45 | }, "some-cool-namespace")
46 | ```
47 |
48 | !!! tip "You can replicate the above code 1:1 with [`#!luau light.message()`](./message.md)"
49 |
--------------------------------------------------------------------------------
/docs/api/network/messages/creation/message.md:
--------------------------------------------------------------------------------
1 | # Message
2 |
3 | Message does the same thing as a [`#!luau light.container()`](./container.md), but doesn't force you to put it in a
4 | string map.
5 |
6 | ## `#!luau function light.message` (On The Client)
7 |
8 | ```luau title=' '
9 | function message(
10 | name: string,
11 | template: Datatype
12 | ): (Message)
13 | ```
14 |
15 | ## `#!luau function light.message` (On The Server)
16 |
17 | ```luau title=' '
18 | function message(
19 | name: string,
20 | template: Datatype
21 | ): (Message)
22 | ```
23 |
24 | `template` in both above samples should always be any valid [Datatype](../../../datatypes/index.md#what-is-a-datatype).
25 | This includes [Datatypes](../../../datatypes/index.md#what-is-a-datatype) like arrays or maps that are defined with luau tables.
26 | I.e., `#!luau { light.datatypes.u8 }`
27 |
28 | If you wanted to create messages en-masse without restricting yourself to the structure of a container, this can be
29 | very useful. You could also use it to re-invent the wheel:
30 |
31 | ```luau
32 | local ty = light.datatypes
33 |
34 | return light.container({
35 | abc = { ty.u8 }, -- send a table of u8 numbers
36 | })
37 | ```
38 |
39 | Is equivalent* to:
40 |
41 | ```luau
42 | return {
43 | abc = light.message("abc", { light.u8 })
44 | }
45 | ```
46 |
--------------------------------------------------------------------------------
/docs/api/network/messages/listening/connect.md:
--------------------------------------------------------------------------------
1 | # Connect
2 |
3 | Connect sets a callback for a given message when it is sent. A message can only have one connection, but you can always
4 | connect your messages into a choice signal implementation. Callbacks can be removed with
5 | [`#!luau light.disconnect()`](./disconnect.md). Message callbacks will be spawned asynchronously with thread reuse. To
6 | create a non-yielding callback you can use [`#!luau light.connect_sync()`](./connect_sync.md)
7 |
8 | !!! tip "This function can error if there is already a callback connected."
9 |
10 | Consider calling [`#!luau light.disconnect()`](./disconnect.md) first if this is an issue.
11 |
12 | ## `#!luau function light.connect`
13 |
14 | ```luau title=' '
15 | function connect(
16 | message: Message,
17 | callback: (Data) -> ()
18 | ): ()
19 | ```
20 |
21 | ## `#!luau function light.connect`
22 |
23 | ```luau title=' '
24 | function connect(
25 | message: Message,
26 | callback: (Player, Data) -> ()
27 | ): ()
28 | ```
29 |
30 | Some example code using [`#!luau light.connect()`](./connect.md):
31 |
32 | ```luau
33 | light.connect(messages.ping, function(player)
34 | print("pong!")
35 | end)
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/api/network/messages/listening/disconnect.md:
--------------------------------------------------------------------------------
1 | # Disconnect
2 |
3 | Remove a callback from a message. [`#!luau light.disconnect()`](./disconnect.md) returns the old callback if there was
4 | one.
5 |
6 | ## `#!luau function light.disconnect`
7 |
8 | ```luau title=' '
9 | function disconnect(
10 | message: Message
11 | ) -> (
12 | ((Data) -> ())?
13 | )
14 | ```
15 |
16 | ## `#!luau function light.disconnect`
17 |
18 | ```luau title=' '
19 | function disconnect(
20 | message: Message
21 | ) -> (
22 | ((Player, Data) -> ())?
23 | )
24 | ```
25 |
26 | An example message-call profiler using
27 | [`#!luau light.disconnect()`](./disconnect.md) and
28 | [`#!luau light.connect_sync()`](./connect_sync.md):
29 |
30 | ```luau title="profiler.luau"
31 | local profile_message
32 | do
33 | local sessions = {}
34 | function profile_message(message: Message)
35 | if sessions[message] then
36 | return nil
37 | end
38 |
39 | local old_callback = light.disconnect(message)
40 |
41 | if not old_callback then
42 | return nil
43 | end
44 |
45 | local calls = 0
46 |
47 | light.connect_sync(message, function(...)
48 | calls += 1
49 |
50 | old_callback(...)
51 | end)
52 |
53 | -- wrapping in a coroutine since session shouldn't be ended twice
54 | sessions[message] = coroutine.wrap(function()
55 | sessions[message] = nil
56 |
57 | light.disconnect(message)
58 |
59 | light.connect(message, old_callback)
60 |
61 | return table.freeze({
62 | calls = calls
63 | })
64 | end)
65 |
66 | return sessions[message]
67 | end
68 | end
69 | ```
70 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast.md:
--------------------------------------------------------------------------------
1 | # Broadcast
2 |
3 | [`#!luau light.broadcast()`](./broadcast.md) will send a message to a list of players on the server.
4 |
5 | !!!tip "Sending to individual players"
6 |
7 | To send to an individual, check out [`#!luau light.send()`](./send.md)
8 |
9 | ## `#!luau function light.broadcast`
10 |
11 | ```luau title=' '
12 | function broadcast(
13 | message: Message,
14 | to: { Player },
15 | data: T
16 | ): ()
17 | ```
18 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast_to_all.md:
--------------------------------------------------------------------------------
1 | # Broadcast To All
2 |
3 | [`#!luau light.broadcast_to_all()`](./broadcast_to_all.md) sends a message to all players who are ingame.
4 |
5 | ## `#!luau function light.broadcast_to_all`
6 |
7 | ```luau title=' '
8 | function broadcast_to_all(
9 | message: Message,
10 | data: T
11 | ): ()
12 | ```
13 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast_to_all_except.md:
--------------------------------------------------------------------------------
1 | # Broadcast To All Except
2 |
3 | Broadcast To All Except is identical to calling
4 | [`#!luau light.broadcast()`](./broadcast.md) to all players except a player or list of players.
5 |
6 | ## `#!luau function light.broadcast_to_all_except`
7 |
8 | ```luau title=' '
9 | function broadcast_to_all_except(
10 | message: Message,
11 | exclude: Player | { Player },
12 | data: T
13 | ): ()
14 | ```
15 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast_unreliably.md:
--------------------------------------------------------------------------------
1 | # Broadcast Unreliably
2 |
3 | Identical behavior to [`#!luau light.broadcast()`](./broadcast.md), except the message is
4 | unreliable.
5 | There is no size limit on light unreliable sending—however, sending
6 | [instances](../../../datatypes/instances.md) /
7 | [any](../../../datatypes/any.md) /
8 | [checked](../../../datatypes/generics/checked.md)
9 | can cause it to exceed size thresholds and fail to send.
10 |
11 | ## `#!luau function light.broadcast_unreliably`
12 |
13 | ```luau title=' '
14 | function broadcast_unreliably(
15 | message: Message,
16 | to: { Player },
17 | data: T
18 | ): ()
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast_unreliably_to_all.md:
--------------------------------------------------------------------------------
1 | # Broadcast Unreliably To All
2 |
3 | Identical behavior to [`#!luau light.broadcast_to_all()`](./broadcast_to_all.md), except the message is
4 | unreliable.
5 | There is no size limit on light unreliable sending—however, sending
6 | [instances](../../../datatypes/instances.md) /
7 | [any](../../../datatypes/any.md) /
8 | [checked](../../../datatypes/generics/checked.md)
9 | can cause it to exceed size thresholds and fail to send.
10 |
11 | ## `#!luau function light.broadcast_unreliably_to_all`
12 |
13 | ```luau title=' '
14 | function broadcast_unreliably_to_all(
15 | message: Message,
16 | data: T
17 | ): ()
18 | ```
19 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/broadcast_unreliably_to_all_except.md:
--------------------------------------------------------------------------------
1 | # Broadcast Unreliably To All Except
2 |
3 | Identical behavior to [`#!luau light.broadcast_to_all_except()`](./broadcast_to_all_except.md), except the message is
4 | unreliable.
5 | There is no size limit on light unreliable sending—however, sending
6 | [instances](../../../datatypes/instances.md) /
7 | [any](../../../datatypes/any.md) /
8 | [checked](../../../datatypes/generics/checked.md)
9 | can cause it to exceed size thresholds and fail to send.
10 |
11 | ## `#!luau function light.broadcast_unreliably_to_all_except`
12 |
13 | ```luau title=' '
14 | function broadcast_unreliably_to_all_except(
15 | message: Message,
16 | except: Player | { Player }
17 | data: T
18 | ): ()
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/send.md:
--------------------------------------------------------------------------------
1 | # Send
2 |
3 | Allows you to send a message to a specific target.
4 |
5 | ## `#!luau function light.send`
6 |
7 | ```luau title=' '
8 | function send(
9 | message: Message,
10 | data: T
11 | ): ()
12 | ```
13 |
14 | ```luau title=' '
15 | function send(
16 | message: Message,
17 | to: Player,
18 | data: T
19 | ): ()
20 | ```
21 |
22 | ## On the Client
23 |
24 | Send a message with given data to the server, for example:
25 |
26 | ```luau
27 | light.send(messages.abc, 123)
28 | ```
29 |
30 | ## On The Server
31 |
32 | Send a message with given data to a player, for example:
33 |
34 | ```luau
35 | Players.PlayerAdded:Connect(function(player)
36 | light.send(messages.abc, player, 123)
37 | end)
38 | ```
39 |
40 | !!! tip "Sending messages to multiple people"
41 |
42 | To send messages to multiple people on the server, check out [`#!luau light.broadcast()`](./broadcast.md).
43 |
--------------------------------------------------------------------------------
/docs/api/network/messages/sending/send_unreliably.md:
--------------------------------------------------------------------------------
1 | # Send Unreliably
2 |
3 | Identical behavior to [`#!luau light.send()`](./send.md), except the message is
4 | unreliable.
5 | There is no size limit on light unreliable sending—however, sending
6 | [instances](../../../datatypes/instances.md) /
7 | [any](../../../datatypes/any.md) /
8 | [checked](../../../datatypes/generics/checked.md)
9 | can cause it to exceed size thresholds and fail to send.
10 |
11 | ## `#!luau function light.send_unreliably`
12 |
13 | ```luau title=' '
14 | function send_unreliably(
15 | message: Message,
16 | data: T
17 | ): ()
18 | ```
19 |
20 | !!! tip "Sending messages to multiple people"
21 |
22 | To send unreliable messages to multiple people on the server, check out
23 | [`#!luau light.broadcast_unreliably()`](./broadcast_unreliably.md).
24 |
25 | ## `#!luau function light.send_unreliably`
26 |
27 | ```luau title=' '
28 | function send_unreliably(
29 | message: Message,
30 | to: Player,
31 | data: T
32 | ): ()
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/api/step_replication.md:
--------------------------------------------------------------------------------
1 | # Step Replication
2 |
3 | This function will step the network batch.
4 |
5 | ## `#!luau function light.step_replication`
6 |
7 | ```luau title=' '
8 | function step_replication(
9 | ): ()
10 | ```
11 |
12 | Some example code:
13 |
14 | ```luau
15 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
16 | local RunService = game:GetService("RunService")
17 |
18 | local light = require(ReplicatedStorage.light).shared
19 |
20 | -- identical to initializing without manual replication
21 | RunService.PostSimulation:Connect(function()
22 | light.step_replication()
23 | end)
24 | ```
25 |
--------------------------------------------------------------------------------
/docs/api/stfu.md:
--------------------------------------------------------------------------------
1 | # Shut The Fuck Up
2 |
3 | This function silences warnings from datatype assembly, as well as strips information from runtime error reporting.
4 |
5 | ## `#!luau function light.stfu`
6 |
7 | ```luau title=' '
8 | function stfu(
9 | sybau: boolean
10 | ): ()
11 | ```
12 |
13 | As an example, you may want to send an array of [`any`](./datatypes/any.md). Since `any` is considered "nilable" by
14 | default, using it in an array will print a warning to your console. To silence it, you can use `#!luau light.stfu()`:
15 |
16 | ```luau
17 | local ty = light.datatypes
18 |
19 | light.stfu(true)
20 | local arr_any = ty.arr(ty.any)
21 | light.stfu(false)
22 |
23 | return light.container({
24 | foo = { ty.u8 },
25 | bar = arr_any,
26 | })
27 | ```
28 |
--------------------------------------------------------------------------------
/docs/assets/images/light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hardlyardi/light/a5e020252faff88235ca28f803373c9e8d33995c/docs/assets/images/light.png
--------------------------------------------------------------------------------
/docs/assets/images/lightbanner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hardlyardi/light/a5e020252faff88235ca28f803373c9e8d33995c/docs/assets/images/lightbanner.png
--------------------------------------------------------------------------------
/docs/assets/images/the_cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hardlyardi/light/a5e020252faff88235ca28f803373c9e8d33995c/docs/assets/images/the_cat.jpg
--------------------------------------------------------------------------------
/docs/blog/internals/cframe_encoding.md:
--------------------------------------------------------------------------------
1 | # Light's CFrame Encoding
2 |
3 | Light uses a somewhat "novel" approach to encoding CFrame Orientation.
4 |
5 | ## TODO
6 |
--------------------------------------------------------------------------------
/docs/blog/internals/holy/cached_closures.md:
--------------------------------------------------------------------------------
1 | # Cached Closures
2 |
3 | Caching closures is a basic optimization
4 | [Holy](https://github.com/hardlyardi/holy) and
5 | [Squash](https://github.com/Data-Oriented-House/Squash) use
6 | to work with "generic" [Datatypes](../../../api/datatypes/index.md#what-is-a-datatype).(1) It works generally by storing
7 | an "input" hash based on parameters, and saving the result shape ID. This caching system is important to make sure
8 | memory usage stays low (by not creating new serialization/deserialization functions), and to prevent ser/de IDs from
9 | getting out of hand in size. As an example, here's the [vect3 caching](../../../api/datatypes/generics/vect3.md) src:
10 | {.annotate}
11 |
12 | 1. Generic [Datatypes](../../../api/datatypes/index.md#what-is-a-datatype) are
13 | functions which take in [Datatype(s)](../../../api/datatypes/index.md) and return a
14 | [Datatype](../../../api/datatypes/index.md#what-is-a-datatype)
15 |
16 | ```luau
17 | local vect3_shape_cache = {} :: { [Shape]: Shape }--(1)!
18 | local function vect3(coord_shape: Shape?): Shape
19 | local coord_shape = coord_shape or f32
20 |
21 | local cached = vect3_shape_cache[coord_shape]
22 | if cached then return cached end
23 |
24 | local vector_shape = new_id()
25 | vect3_shape_cache[coord_shape] = vector_shape--(2)!
26 |
27 | -- ...
28 | end
29 | ```
30 |
31 | 1. Store the input types which have generated a datatype before, as well as what ser/des id the input maps to
32 | 2. Cache the input type with the created vector id
33 |
34 | Although caching is already done automatically for most things, there is an API for
35 | [caching a datatype instantly as a numeric ID](../../../api/datatypes/generics/cached.md).
36 |
--------------------------------------------------------------------------------
/docs/blog/internals/holy/index.md:
--------------------------------------------------------------------------------
1 | # Holy
2 |
3 | For now, holy internal docs are parked on this page. Eventually they'll be [moved](https://holy.ardi.gg/)
4 |
5 | ## TODO
6 |
--------------------------------------------------------------------------------
/docs/blog/internals/holy/special_cased_generics.md:
--------------------------------------------------------------------------------
1 | # Special Cased Generics
2 |
--------------------------------------------------------------------------------
/docs/blog/internals/index.md:
--------------------------------------------------------------------------------
1 | # Internals Blog
2 |
3 | This is a place where I store & document the process for new, old, or learnt techniques that Light utilizes.
4 | These should not be vital to someone using Light, and are more useful if you're interested in creating something similar to, interested in working on, or interested about Light.
5 |
--------------------------------------------------------------------------------
/docs/blog/internals/intern_strings.md:
--------------------------------------------------------------------------------
1 | # Light's Intern Strings
2 |
3 | !!!info "Discontinued"
4 |
5 | Intern strings have been discontinued in light. They may be revisited later, but for now are not included in the
6 | library.
7 |
8 | Intern Strings are a relatively simple & lightweight datatype. They
9 | serve to save resources on serialization/deserialization of repeated "arbitrary" strings. This is done by holding onto
10 | an optional intern string "index" for each [stream](./dynamic_streams.md). This looks something like:
11 |
12 | ```luau title="serialize internstr"
13 | local index = intern_str_match[string_data]
14 | if not index then
15 | table.insert(intern_str_batch, string_data)
16 | index = #intern_str_batch
17 | str_ptr_index[string_data] = index
18 | end
19 | serialize_u16(index)
20 | ```
21 |
22 | This means every intern string will be a "static" datatype, allowing strings to be
23 | [reallocation merged](./holy/reallocation_merging.md). Using the same intern string in multiple places can also help
24 | compression, and speed up [serialization/deserialization](./holy/index.md), because there is only one
25 | readstring/writestring call for each unique interned string used in a [stream](./dynamic_streams.md).
26 |
27 | In the future, this might be expanded to a broader system which holds onto interned strings persistently between frames.
28 |
--------------------------------------------------------------------------------
/docs/blog/internals/message_sync.md:
--------------------------------------------------------------------------------
1 | # Light's Message Synchronization
2 |
3 | ## TODO
4 |
--------------------------------------------------------------------------------
/docs/blog/performance/index.md:
--------------------------------------------------------------------------------
1 | # Performance
2 |
3 | ## Benchmarks
4 |
5 | as u can see. holy-light is da goat :3
6 |
--------------------------------------------------------------------------------
/docs/layouts/social_card.yml:
--------------------------------------------------------------------------------
1 | definitions:
2 | - &page_title >-
3 | {%- if layout.title -%}
4 | {{ layout.title }}
5 | {%- else -%}
6 | {{ page.meta.get("title", page.title) }}
7 | {%- endif -%}
8 |
9 | - &twitter_page_title >-
10 | {%- if layout.title -%}
11 | {{ layout.title }}
12 | {%- else -%}
13 | {{ page.meta.get("title", page.title) }}
14 | {%- endif %} - {{ config.site_name }}
15 |
16 | - &page_description >-
17 | {%- if layout.description -%}
18 | {{ layout.description }}
19 | {%- else -%}
20 | {{ page.meta.get("description", config.site_description) | x }}
21 | {%- endif -%}
22 |
23 | size: { width: 1200, height: 630 }
24 | layers:
25 | - background:
26 | image: docs/assets/images/lightbanner.png
27 |
28 | - size: { width: 32, height: 32 }
29 | offset: { x: 64, y: 544 }
30 | icon:
31 | value: >-
32 | {%- if page.meta.tags -%}
33 | material/tag-text-outline
34 | {%- endif -%}
35 | color: "#F6BC00"
36 |
37 | - size: { width: 320, height: 32 }
38 | offset: { x: 108, y: 544 }
39 | typography:
40 | content: >-
41 | {%- if page.meta.tags -%}
42 | {{ page.meta.tags | join(", ") }}
43 | {%- endif -%}
44 |
45 | tags:
46 | og:type: website
47 | og:site_name: Light
48 | og:title: *page_title
49 | og:description: *page_description
50 | og:image: "{{ image.url }}"
51 | og:image:type: "{{ image.type }}"
52 | og:image:width: "{{ image.width }}"
53 | og:image:height: "{{ image.height }}"
54 | og:url: "{{ page.canonical_url }}"
55 |
56 | twitter:card: summary_large_image
57 | twitter:title: *twitter_page_title
58 | twitter:description: *page_description
59 | twitter:image: "{{ image.url }}"
60 |
--------------------------------------------------------------------------------
/docs/overrides/hooks/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 |
--------------------------------------------------------------------------------
/docs/quick-start/index.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | If using Roblox Studio, prebuilt `.rbxm` files are available in light's github releases.
4 |
5 | You can also install light through pesde in the command line:
6 |
7 | ```ps1
8 | pesde add hardlyardi/light
9 | pesde install
10 | ```
11 |
12 | Or, install with Wally in `wally.toml`:
13 |
14 | ```toml
15 | light = "hardlyardi/light@0.1.0"
16 | ```
17 |
--------------------------------------------------------------------------------
/lune/benchmark.luau:
--------------------------------------------------------------------------------
1 | return nil
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rbxts/light",
3 | "version": "0.1.0",
4 | "description": "---",
5 | "main": "src/init.luau",
6 | "author": "@rbxts",
7 | "license": "MIT",
8 | "module": "commonjs",
9 | "repository": "https://github.com/hardlyardi/light",
10 | "homepage": "https://light.ardi.gg/",
11 | "devDependencies": {
12 | "@rbxts/compiler-types": "^2.2.0-types.0",
13 | "@rbxts/types": "^1.0.761",
14 | "@typescript-eslint/eslint-plugin": "^8.31.0",
15 | "@typescript-eslint/parser": "^8.31.0",
16 | "eslint": "9.25.1",
17 | "eslint-config-prettier": "^10.1.2",
18 | "eslint-plugin-prettier": "^5.1.3",
19 | "eslint-plugin-roblox-ts": "^0.0.36",
20 | "prettier": "^3.2.5",
21 | "typescript": "^5.4.2"
22 | },
23 | "types": "src/index.d.ts",
24 | "files": [
25 | "src"
26 | ]
27 | }
--------------------------------------------------------------------------------
/pesde.toml:
--------------------------------------------------------------------------------
1 | name = "hardlyardi/light"
2 | version = "0.1.0"
3 | description = "A remote event wrapper for Roblox"
4 | authors = ["hardlyardi"]
5 | repository = "https://github.com/hardlyardi/light"
6 | license = "MIT"
7 | private = false
8 |
9 | workspace_members = ["pkgs/*"]
10 |
11 | includes = ["pesde.toml", "README.md", "LICENSE", "src/**/*.luau"]
12 |
13 | [engines]
14 | pesde = "0.7.0-rc.3"
15 | lune = "^0.9.3"
16 |
17 | [target]
18 | environment = "roblox"
19 | lib = "src/init.luau"
20 |
21 | [indices]
22 | default = "https://github.com/pesde-pkg/index"
23 |
24 | [dev_dependencies]
25 | rojo_scripts = { name = "pesde/scripts_rojo", version = "^0.1.0", target = "lune" }
26 | rojo = { name = "pesde/rojo", version = "^7.4.4", target = "lune" }
27 |
--------------------------------------------------------------------------------
/rokit.toml:
--------------------------------------------------------------------------------
1 | [tools]
2 | rojo = "rojo-rbx/rojo@7.5.1"
3 | lune = "lune-org/lune@0.9.3"
4 | stylua = "JohnnyMorganz/StyLua@2.1.0"
5 | pesde = "daimond113/pesde@0.6.2+registry.0.2.2"
6 | wally = "UpliftGames/wally@0.3.2"
7 |
--------------------------------------------------------------------------------
/src/api_client/begin_replication/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local schedule = require("../../include/schedule/main.h")
28 | local step_replication = require("../step_replication/main")
29 |
30 | local already_began = false
31 |
32 | local function begin_replication(): ()
33 | if already_began then return end
34 |
35 | already_began = true
36 | schedule.before_replication:connect(function(): ()
37 | step_replication()
38 | end)
39 | end
40 |
41 | return begin_replication
42 |
--------------------------------------------------------------------------------
/src/api_client/send/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local global_stream = require("../../streams/global_stream")
28 | local message_types = require("../../messages/types")
29 | local write_outgoing_message = require("../../streams/write_outgoing_message")
30 |
31 | type MessageId = message_types.MessageId
32 |
33 | local function send(message_id: MessageId, input: Data): ()
34 | write_outgoing_message(message_id, global_stream, input)
35 | end
36 |
37 | return send
38 |
--------------------------------------------------------------------------------
/src/api_client/send_unreliably/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local message_types = require("../../messages/types")
28 |
29 | type MessageId = message_types.MessageId
30 |
31 | local function send_unreliably(message_id: MessageId, input: Data): ()
32 | error("TODO: Implement")
33 | end
34 |
35 | return send_unreliably
36 |
--------------------------------------------------------------------------------
/src/api_server/begin_replication/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local schedule = require("../../include/schedule/main.h")
28 | local step_replication = require("../step_replication/main")
29 |
30 | local already_began = false
31 |
32 | local function begin_replication(): ()
33 | if already_began then return end
34 |
35 | already_began = true
36 | schedule.before_replication:connect(function(): ()
37 | step_replication()
38 | end)
39 | end
40 |
41 | return begin_replication
42 |
--------------------------------------------------------------------------------
/src/api_server/broadcast_to_all/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local global_stream = require("../../streams/global_stream")
28 | local message_types = require("../../messages/types")
29 | local write_outgoing_message = require("../../streams/write_outgoing_message")
30 |
31 | type MessageId = message_types.MessageId
32 |
33 | local function broadcast_to_all(message_id: MessageId, input: Data)
34 | write_outgoing_message(message_id, global_stream, input)
35 | end
36 |
37 | return broadcast_to_all
38 |
--------------------------------------------------------------------------------
/src/api_server/broadcast_unreliably/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local clients_types = require("../../include/clients/types")
28 | local message_types = require("../../messages/types")
29 |
30 | type MessageId = message_types.MessageId
31 | type Client = clients_types.Identity
32 |
33 | local function broadcast_unreliably(message_id: MessageId, to: { Client }, input: Data): ()
34 | error("TODO: Implement")
35 | end
36 |
37 | return broadcast_unreliably
38 |
--------------------------------------------------------------------------------
/src/api_server/broadcast_unreliably_to_all/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local message_types = require("../../messages/types")
28 |
29 | type MessageId = message_types.MessageId
30 |
31 | local function broadcast_unreliably_to_all(message_id: MessageId, input: Data): ()
32 | error("TODO: Implement")
33 | end
34 |
35 | return broadcast_unreliably_to_all
36 |
--------------------------------------------------------------------------------
/src/api_server/broadcast_unreliably_to_all_except/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local clients_types = require("../../include/clients/types")
28 | local message_types = require("../../messages/types")
29 |
30 | type MessageId = message_types.MessageId
31 | type Client = clients_types.Identity
32 |
33 | @native
34 | local function broadcast_unreliably_to_all_except(
35 | message_id: MessageId,
36 | broadcast_to_except: Client | { Client },
37 | input: Data
38 | ): ()
39 | error("TODO: Implement")
40 | end
41 |
42 | return broadcast_unreliably_to_all_except
43 |
--------------------------------------------------------------------------------
/src/api_server/send_unreliably/main.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local clients_types = require("../../include/clients/types")
28 | local message_types = require("../../messages/types")
29 |
30 | type MessageId = message_types.MessageId
31 | type Client = clients_types.Identity
32 |
33 | local function send_unreliably(message_id: MessageId, to: Client, input: Data): ()
34 | error("TODO: Implement")
35 | end
36 |
37 | return send_unreliably
38 |
--------------------------------------------------------------------------------
/src/impl/_README/impl.luau:
--------------------------------------------------------------------------------
1 | --[[impl.md
2 | # Impl
3 |
4 | General implementations for header files from src/include
5 | --]]
6 | return nil
7 |
--------------------------------------------------------------------------------
/src/impl/_README/impl.md:
--------------------------------------------------------------------------------
1 | # Impl
2 |
3 | General implementations for header files from src/include
4 |
--------------------------------------------------------------------------------
/src/impl/datatypes/enum/overload.api.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local datatypes = require("../../../include/datatypes/main.h")
28 | local identifier_enum = require("./identifier")
29 | local tagged_enum = require("./tagged")
30 |
31 | function datatypes.enum(first: any, second: any): any
32 | if second == nil then
33 | return identifier_enum(first)
34 | else
35 | -- Luau
36 | return tagged_enum(first, second :: any)
37 | end
38 | end
39 |
40 | return nil
41 |
--------------------------------------------------------------------------------
/src/impl/datatypes/mirrors/_README/mirrors.md:
--------------------------------------------------------------------------------
1 | # Mirrors
2 |
3 | These are simple, one-line mirrors of holy Datatypes. They're here to enforce defaults or for code consistency. For
4 | actual Datatype code, look at Datatypes outside of mirror or inside holy.
5 |
--------------------------------------------------------------------------------
/src/impl/datatypes/mirrors/buff.api.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local datatypes = require("../../../include/datatypes/main.h")
28 | local holy = require("../../../holy")
29 |
30 | type HolyDatatype = holy.Datatype
31 |
32 | local ty = holy.datatypes
33 |
34 | --[=[
35 | 1:1 mirror of buff (length vlq(3))
36 | ]=]
37 | function datatypes.buff(length_datatype: HolyDatatype?): HolyDatatype
38 | return ty.buff(length_datatype or ty.vlq(3))
39 | end
40 |
41 | return nil
42 |
--------------------------------------------------------------------------------
/src/impl/datatypes/mirrors/clamp.api.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local datatypes = require("../../../include/datatypes/main.h")
28 | local holy = require("../../../holy")
29 |
30 | type HolyDatatype = holy.Datatype
31 |
32 | local ty = holy.datatypes
33 |
34 | --[=[
35 | 1:1 mirror of clamp
36 | ]=]
37 | function datatypes.clamp(minimum: number, maximum: number): HolyDatatype
38 | return ty.clamp(minimum, maximum)
39 | end
40 |
41 | return nil
42 |
--------------------------------------------------------------------------------
/src/impl/datatypes/mirrors/computed.api.luau:
--------------------------------------------------------------------------------
1 | --[[MIT License Copyright (c) 2025 @hardlyardi
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 | ]]
21 | --[[
22 | --FOR DESCRIPTIONS OF API & CODE FUNCTION, ETC: https://light.ardi.gg/
23 | --FOR ISSUES, BUG REPORTS, OR FEATURE REQUESTS: https://light.ardi.gg/github
24 | --ROBLOX OSS SERVER: https://discord.com/invite/5KjV64PA3d
25 | --MY DISCORD (please only contact for important questions): https://discord.com/users/331399684415553538/
26 | ]]
27 | local datatypes = require("../../../include/datatypes/main.h")
28 | local holy = require("../../../holy")
29 |
30 | type HolyDatatype = holy.Datatype
31 |
32 | local ty = holy.datatypes
33 |
34 | --[=[
35 | 1:1 mirror of computed
36 | ]=]
37 | function datatypes.computed