@rbxts/replecs 0.4.0-rc.3 → 0.4.0-rc.5
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.
- package/out/replecs/client/init.luau +23 -9
- package/out/replecs/handshake.luau +35 -0
- package/out/replecs/index.d.ts +43 -0
- package/out/replecs/init.luau +8 -0
- package/out/replecs/server/filter_group.luau +296 -126
- package/out/replecs/server/init.luau +174 -134
- package/out/replecs/server/registry.luau +30 -1
- package/out/replecs/shared.luau +3 -1
- package/out/replecs/types.luau +3 -0
- package/out/replecs/ver.luau +1 -1
- package/package.json +3 -2
|
@@ -1,196 +1,366 @@
|
|
|
1
|
+
--!optimize 2
|
|
1
2
|
local types = require (script.Parent.Parent:WaitForChild('types'))
|
|
2
3
|
local registry = require (script.Parent:WaitForChild('registry'))
|
|
3
4
|
local bitmasks = require (script.Parent:WaitForChild('bitmasks'))
|
|
4
5
|
local utils = require (script.Parent:WaitForChild('utils'))
|
|
5
|
-
local common = require (script.Parent.Parent:WaitForChild('common'))
|
|
6
6
|
|
|
7
7
|
type Bitmask = buffer
|
|
8
|
+
type Player = any
|
|
8
9
|
|
|
9
10
|
type FilterSimple = types.FilterSimple
|
|
11
|
+
type FilterPredicator = types.FilterPredicator
|
|
10
12
|
|
|
11
13
|
type Set<T> = { [T]: boolean }
|
|
12
|
-
type Map<K, V> = { [K]: V }
|
|
13
14
|
type Array<T> = { T }
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
type Registry = registry.Registry
|
|
16
|
+
|
|
17
|
+
local KINDS = {
|
|
18
|
+
source = 1,
|
|
19
|
+
predicate = 2,
|
|
20
|
+
intersect = 3,
|
|
21
|
+
union = 4,
|
|
22
|
+
exclude = 5,
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
export type
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
export type FilterNodeClass = {
|
|
26
|
+
kind: number,
|
|
27
|
+
registry: Registry?,
|
|
28
|
+
|
|
29
|
+
inputs: Array<FilterNode>,
|
|
30
|
+
input_versions: Array<number>,
|
|
31
|
+
dependents: Set<FilterNode>,
|
|
32
|
+
|
|
33
|
+
value: Bitmask?,
|
|
34
|
+
scratch: Bitmask?,
|
|
35
|
+
version: number,
|
|
36
|
+
dirty: boolean,
|
|
37
|
+
resolved_epoch: number,
|
|
38
|
+
resolved_cycle: number,
|
|
39
|
+
|
|
40
|
+
-- source only
|
|
41
|
+
member_set: Set<Player>?,
|
|
42
|
+
inverted: boolean?,
|
|
43
|
+
predicator: FilterPredicator?,
|
|
27
44
|
}
|
|
28
45
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
parent: FilterGroup?,
|
|
46
|
+
local filter_node = {}
|
|
47
|
+
filter_node.__index = filter_node
|
|
32
48
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
connected_listeners: ListenerConnections,
|
|
36
|
-
}
|
|
49
|
+
export type FilterNode = FilterNodeClass & typeof(filter_node)
|
|
50
|
+
export type FilterOperand = FilterNode | FilterSimple
|
|
37
51
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
include = 3,
|
|
42
|
-
}
|
|
52
|
+
function filter_node.is_filter_node(value: any): boolean
|
|
53
|
+
return typeof(value) == "table" and getmetatable(value) == filter_node
|
|
54
|
+
end
|
|
43
55
|
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
function filter_node.bind(node: FilterNode, reg: Registry)
|
|
57
|
+
if node.registry == reg then
|
|
58
|
+
return
|
|
59
|
+
end
|
|
60
|
+
if node.registry then
|
|
61
|
+
error "filter is already bound to a different server"
|
|
62
|
+
end
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
node.registry = reg
|
|
65
|
+
node.value = buffer.create(reg.bitmask_size)
|
|
66
|
+
node.scratch = buffer.create(reg.bitmask_size)
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
for _, input in node.inputs do
|
|
69
|
+
filter_node.bind(input, reg)
|
|
70
|
+
end
|
|
51
71
|
end
|
|
52
72
|
|
|
53
|
-
local function
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
local function create_node(kind: number, reg: Registry?): FilterNode
|
|
74
|
+
local self: FilterNodeClass = {
|
|
75
|
+
kind = kind,
|
|
76
|
+
registry = nil,
|
|
77
|
+
|
|
78
|
+
inputs = {},
|
|
79
|
+
input_versions = {},
|
|
80
|
+
dependents = setmetatable({}, { __mode = "k" }) :: any,
|
|
81
|
+
|
|
82
|
+
value = nil,
|
|
83
|
+
scratch = nil,
|
|
84
|
+
version = 0,
|
|
85
|
+
dirty = true,
|
|
86
|
+
resolved_epoch = -1,
|
|
87
|
+
resolved_cycle = -1,
|
|
88
|
+
|
|
89
|
+
member_set = nil,
|
|
90
|
+
inverted = nil,
|
|
91
|
+
predicator = nil,
|
|
92
|
+
}
|
|
93
|
+
setmetatable(self, filter_node)
|
|
94
|
+
|
|
95
|
+
local node = self :: any
|
|
96
|
+
if reg then
|
|
97
|
+
filter_node.bind(node, reg)
|
|
56
98
|
end
|
|
99
|
+
return node
|
|
57
100
|
end
|
|
58
101
|
|
|
59
|
-
function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
102
|
+
local function mark_dirty(node: FilterNode)
|
|
103
|
+
if node.dirty then
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
node.dirty = true
|
|
107
|
+
for dependent in node.dependents do
|
|
108
|
+
mark_dirty(dependent)
|
|
109
|
+
end
|
|
64
110
|
end
|
|
65
111
|
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if not index then
|
|
70
|
-
return
|
|
112
|
+
local function assert_source(node: FilterNode, method: string)
|
|
113
|
+
if node.kind ~= KINDS.source then
|
|
114
|
+
error(`{method}() is only available on source filters, derived filters are read only`)
|
|
71
115
|
end
|
|
116
|
+
end
|
|
117
|
+
|
|
72
118
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
119
|
+
local function resolve_source(node: FilterNode, reg: Registry, scratch: Bitmask)
|
|
120
|
+
bitmasks.clear(scratch)
|
|
121
|
+
for member in node.member_set :: Set<Player> do
|
|
122
|
+
local index = registry.resolve_member(reg, member)
|
|
123
|
+
if index then
|
|
124
|
+
bitmasks.set(scratch, index)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
if node.inverted then
|
|
128
|
+
bitmasks.exclude(reg.registered_bitmask, scratch, scratch)
|
|
77
129
|
end
|
|
78
|
-
connected.listeners_indexes[listener] = nil
|
|
79
130
|
end
|
|
80
131
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
132
|
+
|
|
133
|
+
local function resolve_predicate(node: FilterNode, reg: Registry, scratch: Bitmask)
|
|
134
|
+
bitmasks.clear(scratch)
|
|
135
|
+
local predicator = node.predicator :: FilterPredicator
|
|
136
|
+
for member, index in reg.client_indexes do
|
|
137
|
+
if predicator(member) then
|
|
138
|
+
bitmasks.set(scratch, index)
|
|
139
|
+
end
|
|
86
140
|
end
|
|
87
141
|
end
|
|
88
142
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
local
|
|
93
|
-
|
|
94
|
-
|
|
143
|
+
|
|
144
|
+
local function resolve_computed(node: FilterNode, scratch: Bitmask): boolean
|
|
145
|
+
local inputs = node.inputs
|
|
146
|
+
local input_versions = node.input_versions
|
|
147
|
+
|
|
148
|
+
local changed = false
|
|
149
|
+
for i, input in inputs do
|
|
150
|
+
filter_node.resolve(input)
|
|
151
|
+
if input.version ~= input_versions[i] then
|
|
152
|
+
changed = true
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
if not changed then
|
|
156
|
+
return false
|
|
95
157
|
end
|
|
96
158
|
|
|
97
|
-
|
|
159
|
+
for i, input in inputs do
|
|
160
|
+
input_versions[i] = input.version
|
|
161
|
+
end
|
|
98
162
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
bitmasks.
|
|
103
|
-
|
|
104
|
-
bitmasks.
|
|
163
|
+
bitmasks.load(inputs[1].value :: Bitmask, scratch)
|
|
164
|
+
local kind = node.kind
|
|
165
|
+
local op: (Bitmask, Bitmask, Bitmask) -> () = if kind == KINDS.intersect
|
|
166
|
+
then bitmasks.band
|
|
167
|
+
elseif kind == KINDS.union then bitmasks.bor
|
|
168
|
+
else bitmasks.exclude
|
|
169
|
+
for i = 2, #inputs do
|
|
170
|
+
op(scratch, inputs[i].value :: Bitmask, scratch)
|
|
105
171
|
end
|
|
172
|
+
return true
|
|
106
173
|
end
|
|
107
174
|
|
|
108
|
-
function
|
|
109
|
-
local
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
175
|
+
function filter_node.resolve(node: FilterNode): Bitmask
|
|
176
|
+
local reg = node.registry
|
|
177
|
+
if not reg then
|
|
178
|
+
error "filter is not bound to a server, pass it to a set_* call first"
|
|
179
|
+
end
|
|
180
|
+
local value = node.value :: Bitmask
|
|
181
|
+
local kind = node.kind
|
|
182
|
+
|
|
183
|
+
if kind == KINDS.predicate then
|
|
184
|
+
if node.resolved_cycle == reg.cycle then
|
|
185
|
+
return value
|
|
186
|
+
end
|
|
187
|
+
node.resolved_cycle = reg.cycle
|
|
188
|
+
elseif not node.dirty and node.resolved_epoch == reg.epoch then
|
|
189
|
+
return value
|
|
190
|
+
end
|
|
191
|
+
node.dirty = false
|
|
192
|
+
node.resolved_epoch = reg.epoch
|
|
193
|
+
|
|
194
|
+
local scratch = node.scratch :: Bitmask
|
|
195
|
+
if kind == KINDS.source then
|
|
196
|
+
resolve_source(node, reg, scratch)
|
|
197
|
+
elseif kind == KINDS.predicate then
|
|
198
|
+
resolve_predicate(node, reg, scratch)
|
|
199
|
+
elseif not resolve_computed(node, scratch) then
|
|
200
|
+
return value
|
|
115
201
|
end
|
|
116
202
|
|
|
117
|
-
|
|
118
|
-
|
|
203
|
+
if bitmasks.equals(scratch, value) then
|
|
204
|
+
return value
|
|
205
|
+
end
|
|
206
|
+
node.value = scratch
|
|
207
|
+
node.scratch = value
|
|
208
|
+
node.version += 1
|
|
209
|
+
return scratch
|
|
119
210
|
end
|
|
120
211
|
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
filter_group.apply_filter(self, bitmask)
|
|
124
|
-
|
|
125
|
-
fire_listeners(self, bitmask)
|
|
212
|
+
function filter_node.set(self: FilterNode, filter: FilterSimple)
|
|
213
|
+
assert_source(self, "set")
|
|
126
214
|
|
|
127
|
-
|
|
128
|
-
|
|
215
|
+
local members: Set<Player> = {}
|
|
216
|
+
local inverted = false
|
|
217
|
+
if typeof(filter) == "table" then
|
|
218
|
+
inverted = not utils.is_include_filter(filter)
|
|
219
|
+
for member, allow in filter :: Set<Player> do
|
|
220
|
+
if allow == inverted then
|
|
221
|
+
error "a filter set cannot mix included and excluded players"
|
|
222
|
+
end
|
|
223
|
+
members[member] = true
|
|
224
|
+
end
|
|
225
|
+
else
|
|
226
|
+
members[filter] = true
|
|
129
227
|
end
|
|
228
|
+
|
|
229
|
+
self.member_set = members
|
|
230
|
+
self.inverted = inverted
|
|
231
|
+
mark_dirty(self)
|
|
130
232
|
end
|
|
131
233
|
|
|
132
|
-
|
|
133
|
-
|
|
234
|
+
function filter_node.add(self: FilterNode, player: Player)
|
|
235
|
+
assert_source(self, "add")
|
|
236
|
+
local members = self.member_set :: Set<Player>
|
|
237
|
+
if members[player] then
|
|
238
|
+
return
|
|
239
|
+
end
|
|
240
|
+
members[player] = true
|
|
241
|
+
mark_dirty(self)
|
|
242
|
+
end
|
|
134
243
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
244
|
+
function filter_node.remove(self: FilterNode, player: Player)
|
|
245
|
+
assert_source(self, "remove")
|
|
246
|
+
local members = self.member_set :: Set<Player>
|
|
247
|
+
if not members[player] then
|
|
248
|
+
return
|
|
140
249
|
end
|
|
250
|
+
members[player] = nil
|
|
251
|
+
mark_dirty(self)
|
|
252
|
+
end
|
|
141
253
|
|
|
142
|
-
|
|
254
|
+
function filter_node.clear(self: FilterNode)
|
|
255
|
+
assert_source(self, "clear")
|
|
256
|
+
local members = self.member_set :: Set<Player>
|
|
257
|
+
if next(members) == nil then
|
|
258
|
+
return
|
|
259
|
+
end
|
|
260
|
+
table.clear(members)
|
|
261
|
+
mark_dirty(self)
|
|
143
262
|
end
|
|
144
263
|
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
264
|
+
function filter_node.create_source(reg: Registry?, initial: FilterSimple?): FilterNode
|
|
265
|
+
local node = create_node(KINDS.source, reg)
|
|
266
|
+
node.member_set = {}
|
|
267
|
+
node.inverted = false
|
|
268
|
+
if initial ~= nil then
|
|
269
|
+
filter_node.set(node, initial)
|
|
148
270
|
end
|
|
271
|
+
return node
|
|
272
|
+
end
|
|
149
273
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
274
|
+
function filter_node.create_everyone(reg: Registry?): FilterNode
|
|
275
|
+
local node = create_node(KINDS.source, reg)
|
|
276
|
+
node.member_set = {}
|
|
277
|
+
node.inverted = true
|
|
278
|
+
return node
|
|
155
279
|
end
|
|
156
280
|
|
|
157
|
-
function
|
|
158
|
-
local
|
|
281
|
+
function filter_node.create_predicate(reg: Registry?, predicator: FilterPredicator): FilterNode
|
|
282
|
+
local node = create_node(KINDS.predicate, reg)
|
|
283
|
+
node.predicator = predicator
|
|
284
|
+
return node
|
|
285
|
+
end
|
|
159
286
|
|
|
160
|
-
|
|
161
|
-
|
|
287
|
+
local function to_node(operand: FilterOperand): FilterNode
|
|
288
|
+
if filter_node.is_filter_node(operand) then
|
|
289
|
+
return operand :: FilterNode
|
|
162
290
|
end
|
|
291
|
+
return filter_node.create_source(nil, operand :: FilterSimple)
|
|
292
|
+
end
|
|
163
293
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
294
|
+
local function create_computed(kind: number, base: FilterNode, operands: Array<FilterOperand>): FilterNode
|
|
295
|
+
local node = create_node(kind, nil)
|
|
296
|
+
local inputs = node.inputs
|
|
297
|
+
local input_versions = node.input_versions
|
|
298
|
+
|
|
299
|
+
inputs[1] = base
|
|
300
|
+
input_versions[1] = -1
|
|
301
|
+
local reg = base.registry
|
|
302
|
+
|
|
303
|
+
for i, operand in operands do
|
|
304
|
+
local input = to_node(operand)
|
|
305
|
+
inputs[i + 1] = input
|
|
306
|
+
input_versions[i + 1] = -1
|
|
307
|
+
reg = reg or input.registry
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
for _, input in inputs do
|
|
311
|
+
input.dependents[node] = true
|
|
312
|
+
end
|
|
313
|
+
if reg then
|
|
314
|
+
filter_node.bind(node, reg)
|
|
315
|
+
end
|
|
316
|
+
return node
|
|
169
317
|
end
|
|
170
318
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
319
|
+
function filter_node.filter(self: FilterNode, ...: FilterOperand): FilterNode
|
|
320
|
+
return create_computed(KINDS.intersect, self, { ... })
|
|
321
|
+
end
|
|
174
322
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
listeners_indexes = {},
|
|
179
|
-
},
|
|
180
|
-
derived = setmetatable({}, { __mode = "k" }) :: any,
|
|
181
|
-
assigned_filter = nil,
|
|
182
|
-
}
|
|
323
|
+
function filter_node.extend(self: FilterNode, ...: FilterOperand): FilterNode
|
|
324
|
+
return create_computed(KINDS.union, self, { ... })
|
|
325
|
+
end
|
|
183
326
|
|
|
184
|
-
|
|
185
|
-
return self
|
|
327
|
+
function filter_node.exclude(self: FilterNode, ...: FilterOperand): FilterNode
|
|
328
|
+
return create_computed(KINDS.exclude, self, { ... })
|
|
186
329
|
end
|
|
187
330
|
|
|
188
|
-
function
|
|
189
|
-
local
|
|
190
|
-
|
|
331
|
+
function filter_node.members(self: FilterNode): Set<Player>
|
|
332
|
+
local value = filter_node.resolve(self)
|
|
333
|
+
local index_clients = (self.registry :: Registry).index_clients
|
|
334
|
+
|
|
335
|
+
local members: Set<Player> = {}
|
|
336
|
+
bitmasks.iter_set(value, function(index)
|
|
337
|
+
local client = index_clients[index]
|
|
338
|
+
if client ~= nil then
|
|
339
|
+
members[client] = true
|
|
340
|
+
end
|
|
341
|
+
end)
|
|
342
|
+
return members
|
|
343
|
+
end
|
|
191
344
|
|
|
192
|
-
|
|
193
|
-
|
|
345
|
+
local function lookup_index(reg: Registry, player: Player): number?
|
|
346
|
+
local index = reg.client_indexes[player]
|
|
347
|
+
if index then
|
|
348
|
+
return index
|
|
349
|
+
end
|
|
350
|
+
local aliased = reg.client_aliases[player]
|
|
351
|
+
if aliased == nil then
|
|
352
|
+
return nil
|
|
353
|
+
end
|
|
354
|
+
return reg.client_indexes[aliased]
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
function filter_node.contains(self: FilterNode, player: Player): boolean
|
|
358
|
+
local value = filter_node.resolve(self)
|
|
359
|
+
local index = lookup_index(self.registry :: Registry, player)
|
|
360
|
+
if index == nil then
|
|
361
|
+
return false
|
|
362
|
+
end
|
|
363
|
+
return bitmasks.test(value, index)
|
|
194
364
|
end
|
|
195
365
|
|
|
196
|
-
return
|
|
366
|
+
return filter_node
|