@rbxts/replecs 0.3.1 → 0.4.0-rc.2
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 +1760 -0
- package/out/replecs/common.luau +17 -3
- package/out/replecs/cursor.luau +268 -0
- package/out/replecs/handshake.luau +108 -0
- package/out/replecs/init.luau +59 -15
- package/out/replecs/server/bitmasks.luau +322 -0
- package/out/replecs/server/filter_group.luau +196 -0
- package/out/replecs/server/init.luau +3937 -0
- package/out/replecs/server/registry.luau +178 -0
- package/out/replecs/server/utils.luau +20 -0
- package/out/replecs/shared.luau +70 -0
- package/out/replecs/types.luau +31 -16
- package/out/replecs/utils.luau +14 -784
- package/out/replecs/ver.luau +1 -1
- package/package.json +5 -3
- package/out/replecs/client.luau +0 -1673
- package/out/replecs/index.d.ts +0 -257
- package/out/replecs/masking/init.luau +0 -1695
- package/out/replecs/masking/mask_generator.luau +0 -106
- package/out/replecs/server.luau +0 -2216
- package/out/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
--!optimize 2
|
|
2
|
+
local bitmasks = require (script.Parent:WaitForChild('bitmasks'))
|
|
3
|
+
local utils = require (script.Parent.Parent:WaitForChild('utils'))
|
|
4
|
+
|
|
5
|
+
type Set<T> = { [T]: boolean }
|
|
6
|
+
type Map<K, V> = { [K]: V }
|
|
7
|
+
type Array<T> = { T }
|
|
8
|
+
type Bitmask = buffer
|
|
9
|
+
|
|
10
|
+
type Client = any
|
|
11
|
+
export type MemberPredicator = (Client) -> boolean
|
|
12
|
+
|
|
13
|
+
type RegistryClass = {
|
|
14
|
+
client_indexes: Map<Client, number>,
|
|
15
|
+
-- reverse of client_indexes, kept in sync by register/unregister
|
|
16
|
+
index_clients: Map<number, Client>,
|
|
17
|
+
|
|
18
|
+
client_next_index: number,
|
|
19
|
+
client_count: number,
|
|
20
|
+
|
|
21
|
+
-- indexes released by unregister, reused before growing client_next_index
|
|
22
|
+
free_indexes: Array<number>,
|
|
23
|
+
|
|
24
|
+
-- alternate keys a filter may use for a client (a user id, a name...);
|
|
25
|
+
-- resolved to the client before registration is considered
|
|
26
|
+
client_aliases: Map<any, Client>,
|
|
27
|
+
|
|
28
|
+
-- hard cap on registered clients: every bitmask is allocated to hold
|
|
29
|
+
-- exactly this many bits, so an index past it would fall off the buffer
|
|
30
|
+
max_clients: number,
|
|
31
|
+
bitmask_size: number,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
local registry = {}
|
|
35
|
+
registry.__index = registry
|
|
36
|
+
|
|
37
|
+
export type Registry = RegistryClass & typeof(registry)
|
|
38
|
+
|
|
39
|
+
-- a filter can name a player before it joined the registry: register it on
|
|
40
|
+
-- the spot so the bit is stable once the player is ready. a player that
|
|
41
|
+
-- already left is never registered, its bit would leak into every mask
|
|
42
|
+
local function resolve_member(self: Registry, member: Client): number?
|
|
43
|
+
local index = self.client_indexes[member]
|
|
44
|
+
if index then
|
|
45
|
+
return index
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
-- an alias stands for its client: registered or not, the client is what
|
|
49
|
+
-- gets the bit, the alias itself is never registered
|
|
50
|
+
local aliased = self.client_aliases[member]
|
|
51
|
+
if aliased ~= nil then
|
|
52
|
+
member = aliased
|
|
53
|
+
index = self.client_indexes[member]
|
|
54
|
+
if index then
|
|
55
|
+
return index
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if not utils.is_client_valid(member) then
|
|
60
|
+
return nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
registry.register_client(self, member)
|
|
64
|
+
return self.client_indexes[member]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
function registry.add_alias(self: Registry, client: Client, alias: any)
|
|
68
|
+
self.client_aliases[alias] = client
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
function registry.remove_alias(self: Registry, alias: any)
|
|
72
|
+
self.client_aliases[alias] = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
-- drops every alias pointing at the client
|
|
76
|
+
function registry.remove_client_aliases(self: Registry, client: Client)
|
|
77
|
+
local aliases = self.client_aliases
|
|
78
|
+
for alias, aliased in aliases do
|
|
79
|
+
if aliased == client then
|
|
80
|
+
aliases[alias] = nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
function registry.create_bitmask_from_set(self: Registry, member_set: Map<Client, boolean>): Bitmask
|
|
87
|
+
local resolved_members: Array<number> = {}
|
|
88
|
+
for member in member_set do
|
|
89
|
+
local resolved = resolve_member(self, member)
|
|
90
|
+
if resolved then
|
|
91
|
+
table.insert(resolved_members, resolved)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
local bitmask = buffer.create(self.bitmask_size)
|
|
96
|
+
|
|
97
|
+
for _, index in resolved_members do
|
|
98
|
+
bitmasks.set(bitmask, index)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
return bitmask
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
function registry.create_bitmask_from_member(self: Registry, member: Client): Bitmask
|
|
106
|
+
local bitmask = buffer.create(self.bitmask_size)
|
|
107
|
+
local index = resolve_member(self, member)
|
|
108
|
+
if index then
|
|
109
|
+
bitmasks.set(bitmask, index)
|
|
110
|
+
end
|
|
111
|
+
return bitmask
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
function registry.create_bitmask_from_function(self: Registry, predicator: MemberPredicator)
|
|
116
|
+
local bitmask = buffer.create(self.bitmask_size)
|
|
117
|
+
|
|
118
|
+
for member, index in self.client_indexes do
|
|
119
|
+
if predicator(member) then
|
|
120
|
+
bitmasks.set(bitmask, index)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
return bitmask
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
function registry.register_client(self: Registry, member: Client)
|
|
128
|
+
if self.client_indexes[member] then
|
|
129
|
+
return
|
|
130
|
+
end
|
|
131
|
+
if self.client_count >= self.max_clients then
|
|
132
|
+
error(`client limit of {self.max_clients} reached, raise MAX_CLIENTS to register more`)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
local reused = table.remove(self.free_indexes)
|
|
136
|
+
local index: number
|
|
137
|
+
if reused then
|
|
138
|
+
index = reused
|
|
139
|
+
else
|
|
140
|
+
index = self.client_next_index
|
|
141
|
+
self.client_next_index += 1
|
|
142
|
+
end
|
|
143
|
+
self.client_indexes[member] = index
|
|
144
|
+
self.index_clients[index] = member
|
|
145
|
+
self.client_count += 1
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
function registry.unregister_client(self: Registry, member: Client)
|
|
149
|
+
local index = self.client_indexes[member]
|
|
150
|
+
if not index then
|
|
151
|
+
return
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
table.insert(self.free_indexes, index)
|
|
155
|
+
self.client_indexes[member] = nil
|
|
156
|
+
self.index_clients[index] = nil
|
|
157
|
+
self.client_count -= 1
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
local DEFAULT_MAX_CLIENTS = 128
|
|
161
|
+
|
|
162
|
+
function registry.create(max_clients: number?): Registry
|
|
163
|
+
local self = {} :: Registry
|
|
164
|
+
|
|
165
|
+
local cap = max_clients or DEFAULT_MAX_CLIENTS
|
|
166
|
+
self.max_clients = cap
|
|
167
|
+
self.bitmask_size = bitmasks.get_buffer_size(cap)
|
|
168
|
+
self.client_indexes = {}
|
|
169
|
+
self.index_clients = {}
|
|
170
|
+
self.client_next_index = 0
|
|
171
|
+
self.client_count = 0
|
|
172
|
+
self.free_indexes = {}
|
|
173
|
+
self.client_aliases = {}
|
|
174
|
+
|
|
175
|
+
return setmetatable(self, registry) :: any
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
return registry
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Set<T> = { [T]: boolean }
|
|
2
|
+
|
|
3
|
+
local utils = {}
|
|
4
|
+
|
|
5
|
+
function utils.is_include_filter(filter: Set<any>): boolean
|
|
6
|
+
for _, allow in filter do
|
|
7
|
+
return allow
|
|
8
|
+
end
|
|
9
|
+
return true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
function utils.get_used_filter_type(filter: any)
|
|
13
|
+
if typeof(filter) == "table" then
|
|
14
|
+
return utils.is_include_filter(filter)
|
|
15
|
+
else
|
|
16
|
+
return true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
return utils
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
local types = require (script.Parent:WaitForChild('types'))
|
|
2
|
+
local common = require (script.Parent:WaitForChild('common'))
|
|
3
|
+
local customid = require (script.Parent:WaitForChild('customid'))
|
|
4
|
+
|
|
5
|
+
type Component = common.Component
|
|
6
|
+
type Entity = common.Entity
|
|
7
|
+
type World = common.World
|
|
8
|
+
|
|
9
|
+
local ECS_NAME = common.ecs_name
|
|
10
|
+
|
|
11
|
+
local shared = {}
|
|
12
|
+
|
|
13
|
+
local function create_shared_lookup<T>(lookup: { [string]: T }): types.SharedInfo<T>
|
|
14
|
+
local keys = {}
|
|
15
|
+
local indexes = {}
|
|
16
|
+
local members = {}
|
|
17
|
+
|
|
18
|
+
for name in lookup do
|
|
19
|
+
table.insert(keys, name)
|
|
20
|
+
end
|
|
21
|
+
table.sort(keys)
|
|
22
|
+
|
|
23
|
+
for index, name in keys do
|
|
24
|
+
local member = lookup[name]
|
|
25
|
+
members[member] = index
|
|
26
|
+
indexes[index] = member
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
lookup = lookup,
|
|
31
|
+
keys = keys,
|
|
32
|
+
indexes = indexes,
|
|
33
|
+
members = members,
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
function shared.resolve_shared(
|
|
38
|
+
world: World,
|
|
39
|
+
components: types.Components,
|
|
40
|
+
registered_custom_ids: { [customid.CustomId]: boolean },
|
|
41
|
+
serdes: { [Component]: types.Serdes }
|
|
42
|
+
): types.Shared
|
|
43
|
+
local shared = {} :: types.Shared
|
|
44
|
+
|
|
45
|
+
local components_lookup: { [string]: Entity } = table.clone(common.implicitly_shared)
|
|
46
|
+
local custom_ids_lookup = {}
|
|
47
|
+
|
|
48
|
+
for component, name in world:query(ECS_NAME):with(components.shared):iter() do
|
|
49
|
+
if components_lookup[name] then
|
|
50
|
+
common.log_error(`detected two components with the same {name} name: ({components_lookup[name]}, {component})`)
|
|
51
|
+
end
|
|
52
|
+
components_lookup[name] = component
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
for component in world:query(components.shared):without(ECS_NAME):iter() do
|
|
56
|
+
common.log_warn(`shared component: {component} has no name assigned.`)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
for custom in registered_custom_ids do
|
|
60
|
+
custom_ids_lookup[custom.identifier] = custom
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
shared.serdes = serdes
|
|
64
|
+
shared.components = create_shared_lookup(components_lookup)
|
|
65
|
+
shared.custom_ids = create_shared_lookup(custom_ids_lookup) :: types.SharedInfo<customid.CustomId>
|
|
66
|
+
|
|
67
|
+
return shared
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
return shared
|
package/out/replecs/types.luau
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
local customid = require (script.Parent:WaitForChild('customid'))
|
|
2
2
|
local common = require (script.Parent:WaitForChild('common'))
|
|
3
3
|
|
|
4
|
-
export type PlayerFilter = {
|
|
5
|
-
[Player]: boolean,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type FunctionFilter = (player: Player) -> boolean
|
|
9
|
-
export type AnyFilter = PlayerFilter | Player
|
|
10
|
-
|
|
11
4
|
type Entity = common.Entity
|
|
12
5
|
type World = common.World
|
|
13
6
|
type Component<T = any> = common.Component<T>
|
|
14
7
|
|
|
8
|
+
type Player = any
|
|
9
|
+
|
|
10
|
+
export type FilterSet = {
|
|
11
|
+
[Player]: boolean,
|
|
12
|
+
}
|
|
13
|
+
export type FilterPlayer = Player
|
|
14
|
+
export type FilterPredicator = (Player) -> boolean
|
|
15
|
+
export type FilterAny = FilterPlayer | FilterSet | FilterPredicator
|
|
16
|
+
export type FilterSimple = FilterPlayer | FilterSet
|
|
17
|
+
|
|
15
18
|
export type SharedInfo<T> = {
|
|
16
19
|
lookup: { [string]: T },
|
|
17
20
|
keys: { string },
|
|
18
21
|
indexes: { [number]: T },
|
|
19
22
|
members: { [T]: number },
|
|
20
23
|
}
|
|
24
|
+
|
|
21
25
|
export type HandshakeInfo = {
|
|
22
26
|
components: { [string]: boolean },
|
|
23
27
|
custom_ids: { [string]: boolean },
|
|
@@ -34,17 +38,30 @@ export type Serdes<T = any> = {
|
|
|
34
38
|
deserialize: (buffer,...{ any }) -> T,
|
|
35
39
|
}
|
|
36
40
|
|
|
41
|
+
export type Preprocessor<B = any, A = any> = {
|
|
42
|
+
serialize: (B) -> A,
|
|
43
|
+
deserialize: (A) -> B,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type DeltaSerializer<T = any, D = T> = {
|
|
47
|
+
snapshot: ((value: T) -> T)?,
|
|
48
|
+
delta: (old: T, curr: T) -> D,
|
|
49
|
+
apply: (curr: T, delta: D) -> T,
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
export type Components = {
|
|
38
53
|
shared: Entity,
|
|
39
54
|
Shared: Entity,
|
|
40
55
|
networked: Component<any?>,
|
|
41
|
-
Networked: Component<
|
|
42
|
-
reliable: Component<
|
|
43
|
-
Reliable: Component<
|
|
44
|
-
unreliable: Component<
|
|
45
|
-
Unreliable: Component<
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
Networked: Component<FilterAny?>,
|
|
57
|
+
reliable: Component<FilterAny?>,
|
|
58
|
+
Reliable: Component<FilterAny?>,
|
|
59
|
+
unreliable: Component<FilterAny?>,
|
|
60
|
+
Unreliable: Component<FilterAny?>,
|
|
61
|
+
once: Component<FilterAny?>,
|
|
62
|
+
Once: Component<FilterAny?>,
|
|
63
|
+
relation: Component<FilterAny?>,
|
|
64
|
+
Relation: Component<FilterAny?>,
|
|
48
65
|
|
|
49
66
|
serdes: Component<Serdes>,
|
|
50
67
|
Serdes: Component<Serdes>,
|
|
@@ -52,8 +69,6 @@ export type Components = {
|
|
|
52
69
|
Custom: Entity,
|
|
53
70
|
custom_handler: Component<(val: any) -> Entity?>,
|
|
54
71
|
CustomHandler: Component<(val: any) -> Entity?>,
|
|
55
|
-
global: Component<number>,
|
|
56
|
-
Global: Component<number>,
|
|
57
72
|
__alive_tracking__: Entity,
|
|
58
73
|
}
|
|
59
74
|
|