@axpecter/lync 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +250 -68
  2. package/package.json +1 -1
  3. package/src/Types.luau +13 -2
  4. package/src/api/Group.luau +77 -46
  5. package/src/api/Namespace.luau +13 -6
  6. package/src/api/Packet.luau +52 -30
  7. package/src/api/Query.luau +116 -90
  8. package/src/api/Scope.luau +73 -0
  9. package/src/api/Signal.luau +10 -4
  10. package/src/codec/Base.luau +7 -3
  11. package/src/codec/composite/Array.luau +18 -15
  12. package/src/codec/composite/Map.luau +45 -31
  13. package/src/codec/composite/Optional.luau +3 -2
  14. package/src/codec/composite/Shared.luau +7 -5
  15. package/src/codec/composite/Struct.luau +6 -4
  16. package/src/codec/composite/Tagged.luau +6 -6
  17. package/src/codec/composite/Tuple.luau +9 -7
  18. package/src/codec/datatype/Buffer.luau +3 -2
  19. package/src/codec/datatype/CFrame.luau +2 -1
  20. package/src/codec/datatype/Instance.luau +3 -2
  21. package/src/codec/datatype/Sequence.luau +3 -4
  22. package/src/codec/datatype/String.luau +3 -6
  23. package/src/codec/meta/Auto.luau +77 -72
  24. package/src/codec/meta/Bitfield.luau +5 -4
  25. package/src/codec/meta/Enum.luau +6 -5
  26. package/src/codec/meta/Quantized.luau +5 -4
  27. package/src/codec/meta/Unknown.luau +5 -1
  28. package/src/codec/primitive/Float16.luau +5 -4
  29. package/src/codec/primitive/Varint.luau +2 -2
  30. package/src/index.d.ts +65 -26
  31. package/src/init.luau +60 -42
  32. package/src/internal/Baseline.luau +6 -2
  33. package/src/internal/Channel.luau +11 -6
  34. package/src/internal/Middleware.luau +18 -8
  35. package/src/internal/Pool.luau +5 -5
  36. package/src/internal/Registry.luau +4 -4
  37. package/src/transport/Bridge.luau +4 -3
  38. package/src/transport/Client.luau +4 -3
  39. package/src/transport/Gate.luau +5 -5
  40. package/src/transport/Reader.luau +3 -3
  41. package/src/transport/Server.luau +14 -16
package/src/init.luau CHANGED
@@ -7,22 +7,22 @@ local RunService = game:GetService ("RunService")
7
7
  -- Codec: primitive
8
8
  local BoolCodec = require (script.codec.primitive.Bool)
9
9
  local Float16 = require (script.codec.primitive.Float16)
10
- local Number = require (script.codec.primitive.Number)
10
+ local NumberCodec = require (script.codec.primitive.Number)
11
11
 
12
12
  -- Codec: datatype
13
- local Buffer = require (script.codec.datatype.Buffer)
13
+ local BufferCodec = require (script.codec.datatype.Buffer)
14
14
  local CFrameCodec = require (script.codec.datatype.CFrame)
15
- local Color = require (script.codec.datatype.Color)
15
+ local ColorCodec = require (script.codec.datatype.Color)
16
16
  local InstanceCodec = require (script.codec.datatype.Instance)
17
- local IntVector = require (script.codec.datatype.IntVector)
17
+ local IntVectorCodec = require (script.codec.datatype.IntVector)
18
18
  local NumberRangeCodec = require (script.codec.datatype.NumberRange)
19
19
  local RayCodec = require (script.codec.datatype.Ray)
20
20
  local RectCodec = require (script.codec.datatype.Rect)
21
- local Region = require (script.codec.datatype.Region)
22
- local Sequence = require (script.codec.datatype.Sequence)
23
- local String = require (script.codec.datatype.String)
21
+ local RegionCodec = require (script.codec.datatype.Region)
22
+ local SequenceCodec = require (script.codec.datatype.Sequence)
23
+ local StringCodec = require (script.codec.datatype.String)
24
24
  local UDimCodec = require (script.codec.datatype.UDim)
25
- local Vector = require (script.codec.datatype.Vector)
25
+ local VectorCodec = require (script.codec.datatype.Vector)
26
26
 
27
27
  -- Codec: composite
28
28
  local Array = require (script.codec.composite.Array)
@@ -43,21 +43,35 @@ local Unknown = require (script.codec.meta.Unknown)
43
43
 
44
44
  -- Internal
45
45
  local Channel = require (script.internal.Channel)
46
- local Gate = require (script.transport.Gate)
47
46
  local Middleware = require (script.internal.Middleware)
48
47
  local Pool = require (script.internal.Pool)
49
48
 
49
+ -- Transport
50
+ local Client = require (script.transport.Client)
51
+ local Gate = require (script.transport.Gate)
52
+ local Server = require (script.transport.Server)
53
+
50
54
  -- API
51
55
  local Group = require (script.api.Group)
52
56
  local Namespace = require (script.api.Namespace)
53
57
  local Packet = require (script.api.Packet)
54
58
  local Query = require (script.api.Query)
59
+ local Scope = require (script.api.Scope)
55
60
 
56
- -- Transport
57
- local Client = require (script.transport.Client)
58
- local Server = require (script.transport.Server)
61
+ -- Constants ----------------------------------------------------------
59
62
 
60
- -- Public -----------------------------------------------------------------
63
+ local ALL = table.freeze ({ _tag = "all" })
64
+
65
+ -- Private ------------------------------------------------------------
66
+
67
+ local function except (...: any): any
68
+ local count = select ("#", ...)
69
+ local set = {} :: { [Player]: true }
70
+ for i = 1, count do
71
+ set[select (i, ...)] = true
72
+ end
73
+ return { _tag = "except", _set = set }
74
+ end
61
75
 
62
76
  local function start (): ()
63
77
  if RunService:IsServer () then
@@ -67,9 +81,10 @@ local function start (): ()
67
81
  end
68
82
  end
69
83
 
84
+ -- Public -------------------------------------------------------------
85
+
70
86
  local Lync = {
71
- VERSION = "1.3.1",
72
- version = "1.3.1",
87
+ VERSION = "1.4.1",
73
88
 
74
89
  -- Lifecycle
75
90
  start = start,
@@ -80,37 +95,37 @@ local Lync = {
80
95
  defineNamespace = Namespace.define,
81
96
 
82
97
  -- Primitives
83
- u8 = Number.u8,
84
- u16 = Number.u16,
85
- u32 = Number.u32,
86
- i8 = Number.i8,
87
- i16 = Number.i16,
88
- i32 = Number.i32,
89
- f32 = Number.f32,
90
- f64 = Number.f64,
98
+ u8 = NumberCodec.u8,
99
+ u16 = NumberCodec.u16,
100
+ u32 = NumberCodec.u32,
101
+ i8 = NumberCodec.i8,
102
+ i16 = NumberCodec.i16,
103
+ i32 = NumberCodec.i32,
104
+ f32 = NumberCodec.f32,
105
+ f64 = NumberCodec.f64,
91
106
  bool = BoolCodec.bool,
92
107
  f16 = Float16.f16,
93
108
 
94
109
  -- Datatypes
95
- string = String.string,
96
- boundedString = String.bounded,
97
- vec2 = Vector.vec2,
98
- vec3 = Vector.vec3,
110
+ string = StringCodec.string,
111
+ boundedString = StringCodec.bounded,
112
+ vec2 = VectorCodec.vec2,
113
+ vec3 = VectorCodec.vec3,
99
114
  cframe = CFrameCodec.cframe,
100
- color3 = Color.color3,
115
+ color3 = ColorCodec.color3,
101
116
  inst = InstanceCodec.inst,
102
- buff = Buffer.buff,
117
+ buff = BufferCodec.buff,
103
118
  udim = UDimCodec.udim,
104
119
  udim2 = UDimCodec.udim2,
105
120
  numberRange = NumberRangeCodec.numberRange,
106
121
  rect = RectCodec.rect,
107
- vec2int16 = IntVector.vec2int16,
108
- vec3int16 = IntVector.vec3int16,
109
- region3 = Region.region3,
110
- region3int16 = Region.region3int16,
122
+ vec2int16 = IntVectorCodec.vec2int16,
123
+ vec3int16 = IntVectorCodec.vec3int16,
124
+ region3 = RegionCodec.region3,
125
+ region3int16 = RegionCodec.region3int16,
111
126
  ray = RayCodec.ray,
112
- numberSequence = Sequence.numberSequence,
113
- colorSequence = Sequence.colorSequence,
127
+ numberSequence = SequenceCodec.numberSequence,
128
+ colorSequence = SequenceCodec.colorSequence,
114
129
 
115
130
  -- Composites
116
131
  struct = Struct.struct,
@@ -139,15 +154,18 @@ local Lync = {
139
154
  onSend = Middleware.addSend,
140
155
  onReceive = Middleware.addReceive,
141
156
 
157
+ -- Target descriptors
158
+ all = ALL,
159
+ except = except,
160
+
161
+ -- Middleware sentinel
162
+ DROP = Middleware.DROP,
163
+
142
164
  -- Groups
143
165
  createGroup = Group.create,
144
- destroyGroup = Group.destroy,
145
- addToGroup = Group.add,
146
- removeFromGroup = Group.remove,
147
- hasInGroup = Group.has,
148
- getGroupSet = Group.getSet,
149
- groupCount = Group.count,
150
- forEachInGroup = Group.forEach,
166
+
167
+ -- Scope
168
+ scope = Scope.create,
151
169
 
152
170
  -- Configuration (call before start)
153
171
  setChannelMaxSize = Channel.setMaxSize,
@@ -2,15 +2,18 @@
2
2
  --!optimize 2
3
3
  -- Read-side baseline cache keyed by source (player or client sentinel).
4
4
 
5
- -- State ------------------------------------------------------------------
5
+ -- State --------------------------------------------------------------
6
6
 
7
7
  local _readKey = false :: any
8
8
  local _readCaches = {} :: { [any]: { [number]: any } }
9
9
 
10
- -- Public -----------------------------------------------------------------
10
+ -- Public -------------------------------------------------------------
11
11
 
12
12
  local Baseline = {}
13
13
 
14
+ -- One-way latch: set to true on first delta write, never reset. This
15
+ -- avoids a setReadKey call on every non-delta frame at the cost of a
16
+ -- cheap branch once deltas are first used in the session.
14
17
  Baseline.hasDelta = false
15
18
 
16
19
  function Baseline.setReadKey (key: any): ()
@@ -38,4 +41,5 @@ function Baseline.clearSource (key: any): ()
38
41
  _readCaches[key] = nil
39
42
  end
40
43
 
44
+ -- Not frozen: hasDelta is mutated at runtime by setCache.
41
45
  return Baseline
@@ -6,7 +6,7 @@ local Types = require (script.Parent.Parent.Types)
6
6
 
7
7
  type ChannelState = Types.ChannelState
8
8
 
9
- -- Constants --------------------------------------------------------------
9
+ -- Constants ----------------------------------------------------------
10
10
 
11
11
  local INITIAL_SIZE = 1024
12
12
  local MAX_SIZE = 262144
@@ -18,12 +18,15 @@ local band32 = bit32.band
18
18
  local countlz = bit32.countlz
19
19
  local lshift = bit32.lshift
20
20
 
21
- -- State ------------------------------------------------------------------
21
+ -- State --------------------------------------------------------------
22
22
 
23
23
  local _maxSize = MAX_SIZE
24
+
25
+ -- Packet name for overflow diagnostics. Not coroutine-safe: concurrent
26
+ -- serializers may overwrite before the error fires.
24
27
  local _currentPacket = ""
25
28
 
26
- -- Public -----------------------------------------------------------------
29
+ -- Public -------------------------------------------------------------
27
30
 
28
31
  local Channel = {}
29
32
 
@@ -163,9 +166,11 @@ local function sealOpen (ch: ChannelState): ()
163
166
  end
164
167
  end
165
168
 
166
- -- Writes a query frame. Seals any open batch, then writes:
167
- -- id (u8) + correlationId (u16) + status (u8)
168
- -- Status 0 = payload follows. Status 1 = nil response.
169
+ --[[
170
+ Writes a query frame. Seals any open batch, then writes:
171
+ id (u8) + correlationId (u16) + status (u8)
172
+ Status 0 = payload follows. Status 1 = nil response.
173
+ ]]
169
174
  function Channel.writeQuery (
170
175
  ch: ChannelState,
171
176
  id: number,
@@ -2,8 +2,6 @@
2
2
  --!optimize 2
3
3
  -- Ordered intercept chains for send and receive.
4
4
 
5
- -- State ------------------------------------------------------------------
6
-
7
5
  type Handler = (data: any, name: string, player: Player?) -> any?
8
6
 
9
7
  type Chain = {
@@ -11,16 +9,22 @@ type Chain = {
11
9
  snapshot: { Handler }?,
12
10
  }
13
11
 
12
+ -- Constants ----------------------------------------------------------
13
+
14
+ local DROP = table.freeze ({ _tag = "drop" })
15
+
16
+ -- State --------------------------------------------------------------
17
+
14
18
  local _send: Chain = { handlers = {}, snapshot = nil }
15
19
  local _receive: Chain = { handlers = {}, snapshot = nil }
16
20
 
17
- -- Private ----------------------------------------------------------------
21
+ -- Private ------------------------------------------------------------
18
22
 
19
23
  local function runChain (chain: { Handler }, data: any, name: string, player: Player?): any?
20
24
  local current = data
21
25
  for i = 1, #chain do
22
26
  local result = chain[i] (current, name, player)
23
- if result == nil then
27
+ if result == nil or result == DROP then
24
28
  return nil
25
29
  end
26
30
  current = result
@@ -55,6 +59,10 @@ local function run (chain: Chain, data: any, name: string, player: Player?): any
55
59
  return nil
56
60
  end
57
61
 
62
+ if result == DROP then
63
+ return nil
64
+ end
65
+
58
66
  return result
59
67
  end
60
68
 
@@ -71,10 +79,14 @@ local function addTo (chain: Chain, fn: Handler): () -> ()
71
79
  end
72
80
  end
73
81
 
74
- -- Public -----------------------------------------------------------------
82
+ -- Public -------------------------------------------------------------
75
83
 
76
84
  local Middleware = {}
77
85
 
86
+ Middleware.hasSend = false
87
+ Middleware.hasReceive = false
88
+ Middleware.DROP = DROP
89
+
78
90
  function Middleware.addSend (fn: Handler): () -> ()
79
91
  local remover = addTo (_send, fn)
80
92
  Middleware.hasSend = true
@@ -103,7 +115,5 @@ function Middleware.runReceive (data: any, name: string, player: Player?): any?
103
115
  return run (_receive, data, name, player)
104
116
  end
105
117
 
106
- Middleware.hasSend = false
107
- Middleware.hasReceive = false
108
-
118
+ -- Not frozen: hasSend and hasReceive are mutated at runtime.
109
119
  return Middleware
@@ -7,24 +7,24 @@ local Types = require (script.Parent.Parent.Types)
7
7
 
8
8
  type ChannelState = Types.ChannelState
9
9
 
10
- -- Constants --------------------------------------------------------------
10
+ -- Constants ----------------------------------------------------------
11
11
 
12
12
  local DEFAULT_MAX = 16
13
13
 
14
- -- State ------------------------------------------------------------------
14
+ -- State --------------------------------------------------------------
15
15
 
16
16
  local _stack = {} :: { ChannelState }
17
17
  local _depth = 0
18
18
  local _maxSize = DEFAULT_MAX
19
19
 
20
- -- Public -----------------------------------------------------------------
20
+ -- Public -------------------------------------------------------------
21
21
 
22
22
  local Pool = {}
23
23
 
24
- -- Override the max idle ChannelStates in the pool. Default 16. Range: 2128.
24
+ -- Override the max idle ChannelStates in the pool. Default 16. Range: 2-128.
25
25
  function Pool.setMaxSize (count: number): ()
26
26
  if count < 2 or count > 128 then
27
- error (`[Lync] Pool max size must be 2128, got {count}`)
27
+ error (`[Lync] Pool max size must be 2-128, got {count}`)
28
28
  end
29
29
  _maxSize = count
30
30
  end
@@ -8,20 +8,20 @@ type Codec<T> = Types.Codec<T>
8
8
  type Registration = Types.Registration
9
9
  type RateLimitConfig = Types.RateLimitConfig
10
10
 
11
- -- Constants --------------------------------------------------------------
11
+ -- Constants ----------------------------------------------------------
12
12
 
13
13
  local KIND_PACKET = 0
14
14
  local KIND_REQUEST = 1
15
15
  local KIND_RESPONSE = 2
16
16
  local MAX_PACKETS = 255
17
17
 
18
- -- State ------------------------------------------------------------------
18
+ -- State --------------------------------------------------------------
19
19
 
20
20
  local _entries = {} :: { Registration }
21
21
  local _names = {} :: { [string]: number }
22
22
  local _nextId = 1
23
23
 
24
- -- Private ----------------------------------------------------------------
24
+ -- Private ------------------------------------------------------------
25
25
 
26
26
  local function assign (
27
27
  name: string,
@@ -77,7 +77,7 @@ local function assign (
77
77
  return reg
78
78
  end
79
79
 
80
- -- Public -----------------------------------------------------------------
80
+ -- Public -------------------------------------------------------------
81
81
 
82
82
  local Registry = {
83
83
  KIND_PACKET = KIND_PACKET,
@@ -5,19 +5,19 @@
5
5
  local ReplicatedStorage = game:GetService ("ReplicatedStorage")
6
6
  local RunService = game:GetService ("RunService")
7
7
 
8
- -- Constants --------------------------------------------------------------
8
+ -- Constants ----------------------------------------------------------
9
9
 
10
10
  local FOLDER = "_lync"
11
11
  local RELIABLE = "R"
12
12
  local UNRELIABLE = "U"
13
13
  local TIMEOUT = 10
14
14
 
15
- -- State ------------------------------------------------------------------
15
+ -- State --------------------------------------------------------------
16
16
 
17
17
  local _reliable: RemoteEvent
18
18
  local _unreliable: UnreliableRemoteEvent
19
19
 
20
- -- Public -----------------------------------------------------------------
20
+ -- Public -------------------------------------------------------------
21
21
 
22
22
  local Bridge = {}
23
23
 
@@ -63,4 +63,5 @@ function Bridge.setup (): ()
63
63
  table.freeze (Bridge)
64
64
  end
65
65
 
66
+ -- Not frozen at module level: setup() populates reliable/unreliable then freezes.
66
67
  return Bridge
@@ -13,15 +13,16 @@ local Types = require (script.Parent.Parent.Types)
13
13
  type ChannelState = Types.ChannelState
14
14
  type Codec<T> = Types.Codec<T>
15
15
 
16
- -- State ------------------------------------------------------------------
16
+ -- State --------------------------------------------------------------
17
17
 
18
18
  local NOT_STARTED = "[Lync] Client not started. Call Lync.start() before sending"
19
+
19
20
  local _reliable = nil :: ChannelState?
20
21
  local _unreliable = nil :: ChannelState?
21
22
  local _prevRecv = nil :: buffer?
22
23
  local _isStarted = false
23
24
 
24
- -- Private ----------------------------------------------------------------
25
+ -- Private ------------------------------------------------------------
25
26
 
26
27
  local function receive (data: any, refs: any, applyXor: boolean): ()
27
28
  local buf = Reader.decodeIncoming (data)
@@ -67,7 +68,7 @@ local function flush (): ()
67
68
  flushChannel (Bridge.unreliable, _unreliable :: ChannelState, false)
68
69
  end
69
70
 
70
- -- Public -----------------------------------------------------------------
71
+ -- Public -------------------------------------------------------------
71
72
 
72
73
  local Client = {}
73
74
 
@@ -7,7 +7,7 @@ local Types = require (script.Parent.Parent.Types)
7
7
  type Registration = Types.Registration
8
8
  type RateLimitConfig = Types.RateLimitConfig
9
9
 
10
- -- Constants --------------------------------------------------------------
10
+ -- Constants ----------------------------------------------------------
11
11
 
12
12
  local DEFAULT_MAX_DEPTH = 16
13
13
 
@@ -15,7 +15,7 @@ local isfinite = math.isfinite
15
15
  local min = math.min
16
16
  local clock = os.clock
17
17
 
18
- -- State ------------------------------------------------------------------
18
+ -- State --------------------------------------------------------------
19
19
 
20
20
  type Bucket = {
21
21
  tokens: number,
@@ -27,7 +27,7 @@ local _buckets = {} :: { [Player]: { [number]: Bucket } }
27
27
  local _dropHandlers =
28
28
  {} :: { (player: Player, reason: string, packetName: string, data: any?) -> () }
29
29
 
30
- -- Private ----------------------------------------------------------------
30
+ -- Private ------------------------------------------------------------
31
31
 
32
32
  local function fireDrop (player: Player, reason: string, packetName: string, data: any?): ()
33
33
  for _, handler in _dropHandlers do
@@ -47,7 +47,7 @@ local function isClean (value: any, depth: number): boolean
47
47
  return isfinite (value)
48
48
  end
49
49
 
50
- -- String, boolean, nil are always clean . Exit before table/vector/userdata checks
50
+ -- String, boolean, nil are always clean. Exit before table/vector/userdata checks.
51
51
  if t == "string" or t == "boolean" or t == "nil" then
52
52
  return true
53
53
  end
@@ -152,7 +152,7 @@ local function checkRate (player: Player, reg: Registration): boolean
152
152
  return false
153
153
  end
154
154
 
155
- -- Public -----------------------------------------------------------------
155
+ -- Public -------------------------------------------------------------
156
156
 
157
157
  local Gate = {}
158
158
 
@@ -11,14 +11,14 @@ local registryGet = Registry.get
11
11
  local gateCheck = Gate.check
12
12
  local gateReportDrop = Gate.reportDrop
13
13
 
14
- -- Constants --------------------------------------------------------------
14
+ -- Constants ----------------------------------------------------------
15
15
 
16
16
  local KIND_PACKET = Registry.KIND_PACKET
17
17
  local KIND_REQUEST = Registry.KIND_REQUEST
18
18
 
19
19
  local MAX_INCOMING = 65536
20
20
 
21
- -- Public -----------------------------------------------------------------
21
+ -- Public -------------------------------------------------------------
22
22
 
23
23
  local Reader = {}
24
24
 
@@ -126,7 +126,7 @@ function Reader.process (
126
126
  end
127
127
  else
128
128
  -- Query frame: id(u8, already read) + correlationId(u16) + status(u8) = 3 more bytes
129
- if pos + 2 >= length then
129
+ if pos + 3 > length then
130
130
  break
131
131
  end
132
132
 
@@ -8,13 +8,7 @@ local RunService = game:GetService ("RunService")
8
8
  local Baseline = require (script.Parent.Parent.internal.Baseline)
9
9
  local Bridge = require (script.Parent.Bridge)
10
10
  local Channel = require (script.Parent.Parent.internal.Channel)
11
-
12
- local channelWriteBatch = Channel.writeBatch
13
- local channelWriteBatchRaw = Channel.writeBatchRaw
14
- local channelSetPacket = Channel.setCurrentPacket
15
-
16
11
  local Gate = require (script.Parent.Gate)
17
- local Group = require (script.Parent.Parent.api.Group)
18
12
  local Middleware = require (script.Parent.Parent.internal.Middleware)
19
13
  local Pool = require (script.Parent.Parent.internal.Pool)
20
14
  local Reader = require (script.Parent.Reader)
@@ -23,7 +17,11 @@ local Types = require (script.Parent.Parent.Types)
23
17
  type ChannelState = Types.ChannelState
24
18
  type Codec<T> = Types.Codec<T>
25
19
 
26
- -- State ------------------------------------------------------------------
20
+ local channelWriteBatch = Channel.writeBatch
21
+ local channelWriteBatchRaw = Channel.writeBatchRaw
22
+ local channelSetPacket = Channel.setCurrentPacket
23
+
24
+ -- State --------------------------------------------------------------
27
25
 
28
26
  type PlayerState = {
29
27
  reliable: ChannelState,
@@ -35,7 +33,7 @@ local _prevRecv = {} :: { [Player]: buffer }
35
33
  local _isStarted = false
36
34
  local _broadScratch = Channel.create ()
37
35
 
38
- -- Private ----------------------------------------------------------------
36
+ -- Private ------------------------------------------------------------
39
37
 
40
38
  local function onPlayerAdded (player: Player): ()
41
39
  _players[player] = {
@@ -161,7 +159,7 @@ local function broadcastToAll (
161
159
  codec: Codec<any>,
162
160
  data: any,
163
161
  isUnreliable: boolean,
164
- except: Player?
162
+ exceptSet: { [Player]: true }?
165
163
  ): ()
166
164
  local final, snapLen, snapRefs = prepareBroadcast (name, codec, data)
167
165
  if final == nil and data ~= nil then
@@ -170,7 +168,7 @@ local function broadcastToAll (
170
168
 
171
169
  local scratchBuff = _broadScratch.buff
172
170
  for player, state in _players do
173
- if except and player == except then
171
+ if exceptSet and exceptSet[player] then
174
172
  continue
175
173
  end
176
174
  local ch = if isUnreliable then state.unreliable else state.reliable
@@ -228,7 +226,7 @@ local function broadcastToSet (
228
226
  end
229
227
  end
230
228
 
231
- -- Public -----------------------------------------------------------------
229
+ -- Public -------------------------------------------------------------
232
230
 
233
231
  local Server = {}
234
232
 
@@ -304,25 +302,25 @@ function Server.writeToList (
304
302
  end
305
303
 
306
304
  function Server.writeToAllExcept (
307
- except: Player,
305
+ exceptSet: { [Player]: true },
308
306
  id: number,
309
307
  name: string,
310
308
  codec: Codec<any>,
311
309
  data: any,
312
310
  isUnreliable: boolean
313
311
  ): ()
314
- broadcastToAll (id, name, codec, data, isUnreliable, except)
312
+ broadcastToAll (id, name, codec, data, isUnreliable, exceptSet)
315
313
  end
316
314
 
317
- function Server.writeToGroup (
318
- groupName: string,
315
+ function Server.writeToSet (
316
+ set: { [Player]: true },
319
317
  id: number,
320
318
  name: string,
321
319
  codec: Codec<any>,
322
320
  data: any,
323
321
  isUnreliable: boolean
324
322
  ): ()
325
- broadcastToSet (Group.getSet (groupName), id, name, codec, data, isUnreliable)
323
+ broadcastToSet (set, id, name, codec, data, isUnreliable)
326
324
  end
327
325
 
328
326
  -- Shared for both query requests and responses (identical wire format).