@rbxts/replecs 0.0.1-rc.1 → 0.1.0-alpha2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 replecs authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,9 +1,9 @@
1
1
  --!native
2
2
  --!optimize 2
3
3
 
4
- local jecs = require(script.Parent.Parent.jecs)
5
- local common = require(script.Parent.common)
6
- local utils = require(script.Parent.utils)
4
+ local jecs = require "../jecs"
5
+ local common = require "./common"
6
+ local utils = require "./utils"
7
7
 
8
8
  local cursor = utils.cursor
9
9
  type Cursor = utils.Cursor
@@ -19,6 +19,7 @@ export type Client = {
19
19
 
20
20
  components: common.Components,
21
21
  shared: common.Shared,
22
+ global_id_parser: ((id: number) -> Entity)?,
22
23
  server_ids: { [number]: Entity },
23
24
  client_ids: { [Entity]: number },
24
25
  ordered_creation: boolean,
@@ -27,16 +28,21 @@ export type Client = {
27
28
  init: (self: Client, world: World?) -> (),
28
29
  destroy: (self: Client) -> (),
29
30
  after_replication: (self: Client, callback: () -> ()) -> (),
31
+ parse_global_id: (self: Client, parser: (id: number) -> Entity) -> (),
32
+ get_server_entity: (self: Client, client_entity: Entity) -> number?,
33
+ get_client_entity: (self: Client, server_entity: number) -> Entity?,
30
34
 
31
35
  apply_updates: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
32
36
  apply_unreliable: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
33
37
  apply_full: (self: Client, buf: buffer, all_variants: { { any } }?) -> (),
34
38
  }
35
39
 
40
+ local GLOBAL_ID_OFFSET = 10
36
41
  local ENTITY_ID_TYPES = {
37
- id = 1,
42
+ entity = 1,
38
43
  custom = 2,
39
44
  shared = 3,
45
+ global = 4,
40
46
  }
41
47
 
42
48
  local ECS_NAME = jecs.Name
@@ -87,31 +93,46 @@ local function read_component_value(client: Client, c: Cursor, variants: { any }
87
93
  end
88
94
  end
89
95
 
96
+ local function resolve_global_id(client: Client, global_id: number): Entity
97
+ if not client.global_id_parser then
98
+ error "global id parser not set, consider using client:parse_global_id()"
99
+ end
100
+ local parsed = client.global_id_parser(global_id)
101
+ return parsed
102
+ end
103
+
90
104
  local function read_entity_id(client: Client, c: Cursor, variants: { any }?): (Entity?, number?)
91
105
  local id_type = cursor.readi8(c)
92
106
 
93
- if id_type == ENTITY_ID_TYPES.id then
94
- local server_id = cursor.readu24(c)
95
- return client.server_ids[server_id], server_id
96
- elseif id_type == ENTITY_ID_TYPES.custom then
97
- local component, value = read_component_value(client, c, variants)
98
- local custom_getter = client.custom_ids[component]
99
- if not custom_getter then
100
- error(
101
- `received a custom id for a non custom component, consider adding custom_id to component: {client.world:get(
102
- component,
103
- ECS_NAME
104
- ) or "(no name)"} id: {component}`
105
- )
107
+ if id_type <= 10 then
108
+ if id_type == ENTITY_ID_TYPES.entity then
109
+ local server_id = cursor.readu40(c)
110
+ return client.server_ids[server_id], server_id
111
+ elseif id_type == ENTITY_ID_TYPES.custom then
112
+ local component, value = read_component_value(client, c, variants)
113
+ local custom_getter = client.custom_ids[component]
114
+ if not custom_getter then
115
+ error(
116
+ `received a custom id for a non custom component, consider adding custom_id to component: {client.world:get(
117
+ component,
118
+ ECS_NAME
119
+ ) or "(no name)"} id: {component}`
120
+ )
121
+ end
122
+ return custom_getter(value), nil
123
+ elseif id_type == ENTITY_ID_TYPES.shared then
124
+ return read_component_id(client, c), nil
125
+ elseif id_type == ENTITY_ID_TYPES.global then
126
+ local global_id = cursor.readu8(c) - GLOBAL_ID_OFFSET
127
+ return resolve_global_id(client, global_id), nil
106
128
  end
107
- return custom_getter(value), nil
108
- elseif id_type == ENTITY_ID_TYPES.shared then
109
- return read_component_id(client, c), nil
129
+ error(`malformed entity id {id_type} ` .. cursor.readu32(c))
130
+ else
131
+ return resolve_global_id(client, id_type - GLOBAL_ID_OFFSET), nil
110
132
  end
111
- error("malformed entity id" .. cursor.readu32(c))
112
133
  end
113
134
 
114
- local function process_entity_id(client: Client, c: Cursor, variants: { any }?)
135
+ local function process_entity_id(client: Client, c: Cursor, variants: { any }?, v: boolean?)
115
136
  local entity, server_id = read_entity_id(client, c, variants)
116
137
  if entity then
117
138
  return entity
@@ -124,23 +145,23 @@ local function process_entity(client: Client, c: Cursor, variants: { any }?)
124
145
  local entity = process_entity_id(client, c, variants)
125
146
 
126
147
  local total_tags = cursor.read_vlq(c)
127
- for i = 1, total_tags do
148
+ for _ = 1, total_tags do
128
149
  local tag = read_component_id(client, c)
129
150
  client.world:add(entity, tag)
130
151
  end
131
152
 
132
153
  local total_components = cursor.read_vlq(c)
133
- for i = 1, total_components do
154
+ for _ = 1, total_components do
134
155
  local component, value = read_component_value(client, c, variants)
135
156
  client.world:set(entity, component, value)
136
157
  end
137
158
 
138
159
  local total_pairs = cursor.read_vlq(c)
139
- for i = 1, total_pairs do
160
+ for _ = 1, total_pairs do
140
161
  local relation = read_component_id(client, c)
141
162
  local total_targets = cursor.read_vlq(c)
142
163
 
143
- for i = 1, total_targets do
164
+ for _ = 1, total_targets do
144
165
  local target = process_entity_id(client, c, variants)
145
166
  client.world:add(entity, PAIR(relation, target))
146
167
  end
@@ -161,26 +182,26 @@ local function apply_updates(client: Client, buf: buffer, all_variants: { { any
161
182
  end
162
183
 
163
184
  local total_changed = cursor.read_vlq(c)
164
- for i = 1, total_changed do
185
+ for _ = 1, total_changed do
165
186
  local entity = process_entity_id(client, c, variants)
166
187
  local total_tagged = cursor.read_vlq(c)
167
- for i = 1, total_tagged do
188
+ for _ = 1, total_tagged do
168
189
  local tag = read_component_id(client, c)
169
190
  client.world:add(entity, tag)
170
191
  end
171
192
 
172
193
  local total_components = cursor.read_vlq(c)
173
- for i = 1, total_components do
194
+ for _ = 1, total_components do
174
195
  local component, value = read_component_value(client, c, variants)
175
196
  client.world:set(entity, component, value)
176
197
  end
177
198
 
178
199
  local total_pairs = cursor.read_vlq(c)
179
- for i = 1, total_pairs do
200
+ for _ = 1, total_pairs do
180
201
  local relation = read_component_id(client, c)
181
202
  local total_targets = cursor.read_vlq(c)
182
203
 
183
- for t = 1, total_targets do
204
+ for _ = 1, total_targets do
184
205
  local id_type = cursor.readi8(c)
185
206
  -- here I use negative numbers to indicate removals
186
207
  -- but "process_entity_id" expects a positive value
@@ -198,37 +219,37 @@ local function apply_updates(client: Client, buf: buffer, all_variants: { { any
198
219
  end
199
220
 
200
221
  local total_removed = cursor.read_vlq(c)
201
- for i = 1, total_removed do
222
+ for _ = 1, total_removed do
202
223
  local component = read_component_id(client, c)
203
224
  client.world:remove(entity, component)
204
225
  end
205
226
  end
206
227
 
207
228
  local total_component_deleted = cursor.read_vlq(c)
208
- for i = 1, total_component_deleted do
229
+ for _ = 1, total_component_deleted do
209
230
  local entity = process_entity_id(client, c, variants)
210
231
 
211
232
  local total_tags = cursor.read_vlq(c)
212
- for i = 1, total_tags do
233
+ for _ = 1, total_tags do
213
234
  local tag = read_component_id(client, c)
214
235
  client.world:remove(entity, tag)
215
236
  end
216
237
 
217
238
  local total_components = cursor.read_vlq(c)
218
- for i = 1, total_components do
239
+ for _ = 1, total_components do
219
240
  local component = read_component_id(client, c)
220
241
  client.world:remove(entity, component)
221
242
  end
222
243
 
223
244
  local total_pairs = cursor.read_vlq(c)
224
- for i = 1, total_pairs do
245
+ for _ = 1, total_pairs do
225
246
  local relation = read_component_id(client, c)
226
247
  utils.remove_all_relations(client.world, entity, relation)
227
248
  end
228
249
  end
229
250
 
230
251
  local total_deleted = cursor.read_vlq(c)
231
- for i = 1, total_deleted do
252
+ for _ = 1, total_deleted do
232
253
  local entity, server_id = read_entity_id(client, c, variants)
233
254
  if entity then
234
255
  client.world:delete(entity)
@@ -249,7 +270,7 @@ local function apply_unreliable(client: Client, buf: buffer, all_variants: { { a
249
270
  local total_entities = cursor.read_vlq(c)
250
271
  local variants = all_variants and all_variants[variant_start - a]
251
272
 
252
- for e = 1, total_entities do
273
+ for _ = 1, total_entities do
253
274
  local entity = read_entity_id(client, c, variants)
254
275
  local total_unreliable = cursor.read_vlq(c)
255
276
 
@@ -259,7 +280,7 @@ local function apply_unreliable(client: Client, buf: buffer, all_variants: { { a
259
280
  else
260
281
  -- dont apply unreliable updates to entities that dont exist in the client yet
261
282
  -- but we still need to process the values to keep the cursor in the right place
262
- for u = 1, total_unreliable do
283
+ for _ = 1, total_unreliable do
263
284
  read_component_value(client, c, variants)
264
285
  end
265
286
  end
@@ -276,7 +297,7 @@ local function apply_full(client: Client, buf: buffer, all_variants: { { any } }
276
297
  local total_entities = cursor.read_vlq(c)
277
298
  local variants = all_variants and all_variants[variant_start - a]
278
299
 
279
- for e = 1, total_entities do
300
+ for _ = 1, total_entities do
280
301
  process_entity(client, c, variants)
281
302
  end
282
303
  end
@@ -315,6 +336,14 @@ local function after_replication(client: Client, callback: () -> ())
315
336
  end
316
337
  end
317
338
 
339
+ local function get_server_entity(client: Client, client_entity: Entity): number?
340
+ return client.client_ids[client_entity]
341
+ end
342
+
343
+ local function get_client_entity(client: Client, client_entity: number): Entity?
344
+ return client.server_ids[client_entity]
345
+ end
346
+
318
347
  local function destroy(client: Client)
319
348
  if client.inited == nil then
320
349
  return warn "attempted to destroy a client twice"
@@ -324,6 +353,10 @@ local function destroy(client: Client)
324
353
  -- right now this is kind of useless
325
354
  end
326
355
 
356
+ local function parse_global_id(client: Client, parser: (id: number) -> Entity)
357
+ client.global_id_parser = parser
358
+ end
359
+
327
360
  local client = {}
328
361
  client.__index = client
329
362
  client.init = init
@@ -332,6 +365,9 @@ client.after_replication = after_replication
332
365
  client.apply_updates = apply_updates
333
366
  client.apply_unreliable = apply_unreliable
334
367
  client.apply_full = apply_full
368
+ client.get_server_entity = get_server_entity
369
+ client.get_client_entity = get_client_entity
370
+ client.parse_global_id = parse_global_id
335
371
 
336
372
  local function create(world: World?, components: common.Components): Client
337
373
  local self = {} :: Client
@@ -341,6 +377,7 @@ local function create(world: World?, components: common.Components): Client
341
377
  self.custom_ids = {}
342
378
  self.server_ids = {}
343
379
  self.client_ids = {}
380
+ self.global_id_parser = nil
344
381
  self.world = world :: any
345
382
  self.inited = false
346
383
  self.is_replicating = false
@@ -1,4 +1,4 @@
1
- local jecs = require(script.Parent.Parent.jecs)
1
+ local jecs = require "../jecs"
2
2
 
3
3
  export type PlayerFilter = {
4
4
  [Player]: boolean,
@@ -19,6 +19,7 @@ export type Components = {
19
19
  serdes: jecs.Entity<Serdes>,
20
20
  bytespan: jecs.Entity<number>,
21
21
  custom_id: jecs.Entity<(value: any) -> jecs.Entity>,
22
+ global_id: jecs.Entity<number>,
22
23
  __alive_tracking__: jecs.Entity,
23
24
  }
24
25
 
@@ -10,7 +10,7 @@ declare namespace Replecs {
10
10
  added<T>(
11
11
  this: ObserverWorld,
12
12
  component: Id<T>,
13
- callback: (e: Entity, id: Id<T>, value?: T) => void
13
+ callback: (e: Entity, id: Id<T>, value: T) => void
14
14
  ): () => void;
15
15
  removed<T>(
16
16
  this: ObserverWorld,
@@ -20,40 +20,43 @@ declare namespace Replecs {
20
20
  changed<T>(
21
21
  this: ObserverWorld,
22
22
  component: Id<T>,
23
- callback: (e: Entity, id: Id<T>, value?: T) => void
23
+ callback: (e: Entity, id: Id<T>, value: T) => void
24
24
  ): () => void;
25
25
  }
26
26
 
27
- type MemberFilter = Map<Player, boolean>;
27
+ type MemberFilterMap = Map<Player, boolean>;
28
+ type MemberFilter = Player | MemberFilterMap | undefined;
28
29
  type Member = unknown;
29
30
 
30
31
  interface MaskingController {
31
32
  register_member(member: Member): void;
32
33
  unregister_member(member: Member): void;
33
34
  active_member(member: Member): void;
34
- member_is_active(member: Member): boolean
35
+ member_is_active(member: Member): boolean;
35
36
  }
36
37
 
37
38
  export interface Components {
38
39
  shared: Tag;
39
- networked: Entity<MemberFilter | undefined>;
40
- reliable: Entity<MemberFilter | undefined>;
41
- unreliable: Entity<MemberFilter | undefined>;
42
- pair: Entity<MemberFilter | undefined>;
40
+ networked: Entity<MemberFilter>;
41
+ reliable: Entity<MemberFilter>;
42
+ unreliable: Entity<MemberFilter>;
43
+ pair: Entity<MemberFilter>;
43
44
 
44
45
  serdes: Entity<SerdesTable>;
45
46
  bytespan: Entity<number>;
46
47
  custom_id: Entity<((value: any) => Entity) | undefined>;
48
+ global_id: Entity<number>;
47
49
 
48
50
  Shared: Tag;
49
- Networked: Entity<MemberFilter | undefined>;
50
- Reliable: Entity<MemberFilter | undefined>;
51
- Unreliable: Entity<MemberFilter | undefined>;
52
- Pair: Entity<MemberFilter | undefined>;
51
+ Networked: Entity<MemberFilter>;
52
+ Reliable: Entity<MemberFilter>;
53
+ Unreliable: Entity<MemberFilter>;
54
+ Pair: Entity<MemberFilter>;
53
55
 
54
56
  Serdes: Entity<SerdesTable>;
55
57
  Bytespan: Entity<number>;
56
- CustomId: Entity<((value: any) => Entity) | undefined>;
58
+ CustomId: Entity<(value: any) => Entity>;
59
+ GlobalId: Entity<number>;
57
60
  }
58
61
 
59
62
  export interface Client {
@@ -67,6 +70,10 @@ declare namespace Replecs {
67
70
  apply_updates(buf: buffer, all_variants?: any[][]): void;
68
71
  apply_unreliable(buf: buffer, all_variants?: any[][]): void;
69
72
  apply_full(buf: buffer, all_variants?: any[][]): void;
73
+ parse_global_id(parser: (id: number) => Entity): void;
74
+
75
+ get_server_entity(client_entity: Entity): number | undefined;
76
+ get_client_entity(server_entity: number): Entity | undefined;
70
77
  }
71
78
 
72
79
  export interface Server {
@@ -78,7 +85,9 @@ declare namespace Replecs {
78
85
 
79
86
  get_full(player: Player): LuaTuple<[buffer, any[][]]>;
80
87
  collect_updates(): IterableFunction<LuaTuple<[Player, buffer, any[][]]>>;
81
- collect_unreliable(): IterableFunction<LuaTuple<[Player, buffer, any[][]]>>;
88
+ collect_unreliable(): IterableFunction<
89
+ LuaTuple<[Player, buffer, any[][]]>
90
+ >;
82
91
  mark_player_ready(player: Player): void;
83
92
  is_player_ready(player: Player): boolean;
84
93
 
@@ -89,7 +98,7 @@ declare namespace Replecs {
89
98
  client: Client;
90
99
  server: Server;
91
100
 
92
- after_replication(world: ObserverWorld): void;
101
+ after_replication(callback: () => void): void;
93
102
  }
94
103
 
95
104
  export interface Replecs extends Components {
@@ -1,83 +1,88 @@
1
- local RunService = game:GetService "RunService"
2
- local jecs = require(script.Parent.jecs)
3
- local common = require(script.common)
4
-
5
- local client = require(script.client)
6
- local server = require(script.server)
7
-
8
- export type Server = server.Server
9
- export type Client = client.Client
10
-
11
- export type Replecs = {
12
- server: Server,
13
- client: Client,
14
-
15
- after_replication: (self: Replecs, callback: () -> ()) -> (),
16
- }
17
-
18
- type MemberFilter = {
19
- [Player]: boolean,
20
- }
21
-
22
- local replecs = {
23
- shared = jecs.tag(),
24
- networked = jecs.component() :: jecs.Entity<MemberFilter?>,
25
- reliable = jecs.component() :: jecs.Entity<MemberFilter?>,
26
- unreliable = jecs.component() :: jecs.Entity<MemberFilter?>,
27
- pair = jecs.tag(),
28
-
29
- serdes = jecs.component() :: jecs.Entity<common.Serdes>,
30
- bytespan = jecs.component() :: jecs.Entity<number>,
31
- custom_id = jecs.component() :: jecs.Entity<(any) -> jecs.Entity>,
32
- __alive_tracking__ = jecs.tag(),
33
- }
34
- replecs.__index = replecs
35
- replecs.Serdes = replecs.serdes
36
- replecs.Bytespan = replecs.bytespan
37
- replecs.CustomId = replecs.custom_id
38
- replecs.Networked = replecs.networked
39
- replecs.Reliable = replecs.reliable
40
- replecs.Unreliable = replecs.unreliable
41
- replecs.Pair = replecs.pair
42
- replecs.Shared = replecs.shared
43
-
44
- jecs.meta(replecs.serdes, jecs.Name, "replecs.serdes")
45
- jecs.meta(replecs.bytespan, jecs.Name, "replecs.bytespan")
46
- jecs.meta(replecs.custom_id, jecs.Name, "replecs.custom_id")
47
- jecs.meta(replecs.networked, jecs.Name, "replecs.networked")
48
- jecs.meta(replecs.reliable, jecs.Name, "replecs.reliable")
49
- jecs.meta(replecs.unreliable, jecs.Name, "replecs.unreliable")
50
- jecs.meta(replecs.pair, jecs.Name, "replecs.pair")
51
- jecs.meta(replecs.shared, jecs.Name, "replecs.shared")
52
-
53
- function replecs.create_server(world: jecs.World?): Server
54
- return server.create(world, replecs)
55
- end
56
-
57
- function replecs.create_client(world: jecs.World?): Client
58
- return client.create(world, replecs)
59
- end
60
-
61
- function replecs.create(world: jecs.World?): Replecs
62
- local lib = {} :: Replecs
63
-
64
- if RunService:IsServer() then
65
- lib.server = server.create(world, replecs)
66
- end
67
- if RunService:IsClient() then
68
- lib.client = client.create(world, replecs)
69
- end
70
-
71
- return setmetatable(lib, replecs) :: any
72
- end
73
-
74
- function replecs.after_replication(lib: Replecs, callback: () -> ())
75
- local lib_client = lib.client
76
- if lib_client then
77
- lib_client:after_replication(callback)
78
- else
79
- callback()
80
- end
81
- end
82
-
83
- return replecs
1
+ local jecs = require "./jecs"
2
+ local common = require "@self/common"
3
+
4
+ local client = require "@self/client"
5
+ local server = require "@self/server"
6
+
7
+ export type Server = server.Server
8
+ export type Client = client.Client
9
+
10
+ export type ReplecsLib = {
11
+ server: Server,
12
+ client: Client,
13
+
14
+ after_replication: (self: ReplecsLib, callback: () -> ()) -> (),
15
+ }
16
+
17
+ type MemberFilter = {
18
+ [Player]: boolean,
19
+ }
20
+
21
+ local replecs = {
22
+ shared = jecs.tag(),
23
+ networked = jecs.component() :: jecs.Entity<(MemberFilter | Player)?>,
24
+ reliable = jecs.component() :: jecs.Entity<(MemberFilter | Player)?>,
25
+ unreliable = jecs.component() :: jecs.Entity<(MemberFilter | Player)?>,
26
+ pair = jecs.tag(),
27
+
28
+ serdes = jecs.component() :: jecs.Entity<common.Serdes>,
29
+ bytespan = jecs.component() :: jecs.Entity<number>,
30
+ custom_id = jecs.component() :: jecs.Entity<(any) -> jecs.Entity>,
31
+ global_id = jecs.component() :: jecs.Entity<number>,
32
+ __alive_tracking__ = jecs.tag(),
33
+ }
34
+
35
+ replecs.__index = replecs
36
+ replecs.Serdes = replecs.serdes
37
+ replecs.Bytespan = replecs.bytespan
38
+ replecs.CustomId = replecs.custom_id
39
+ replecs.Networked = replecs.networked
40
+ replecs.Reliable = replecs.reliable
41
+ replecs.Unreliable = replecs.unreliable
42
+ replecs.Pair = replecs.pair
43
+ replecs.Shared = replecs.shared
44
+ replecs.GlobalId = replecs.global_id
45
+
46
+ jecs.meta(replecs.serdes, jecs.Name, "replecs.serdes")
47
+ jecs.meta(replecs.bytespan, jecs.Name, "replecs.bytespan")
48
+ jecs.meta(replecs.custom_id, jecs.Name, "replecs.custom_id")
49
+ jecs.meta(replecs.networked, jecs.Name, "replecs.networked")
50
+ jecs.meta(replecs.reliable, jecs.Name, "replecs.reliable")
51
+ jecs.meta(replecs.unreliable, jecs.Name, "replecs.unreliable")
52
+ jecs.meta(replecs.pair, jecs.Name, "replecs.pair")
53
+ jecs.meta(replecs.shared, jecs.Name, "replecs.shared")
54
+
55
+ function replecs.create_server(world: jecs.World?): Server
56
+ return server.create(world, replecs)
57
+ end
58
+
59
+ function replecs.create_client(world: jecs.World?): Client
60
+ return client.create(world, replecs)
61
+ end
62
+
63
+ function replecs.create(world: jecs.World?): ReplecsLib
64
+ assert(game, "This is a Roblox specific function")
65
+
66
+ local RunService = game:GetService "RunService"
67
+ local lib = {} :: ReplecsLib
68
+
69
+ if RunService:IsServer() then
70
+ lib.server = server.create(world, replecs)
71
+ end
72
+ if RunService:IsClient() then
73
+ lib.client = client.create(world, replecs)
74
+ end
75
+
76
+ return setmetatable(lib, replecs) :: any
77
+ end
78
+
79
+ function replecs.after_replication(lib: ReplecsLib, callback: () -> ())
80
+ local lib_client = lib.client
81
+ if lib_client then
82
+ lib_client:after_replication(callback)
83
+ else
84
+ callback()
85
+ end
86
+ end
87
+
88
+ return replecs