@dcl/sdk 7.3.15-6200631111.commit-2a2ff73 → 7.3.15-6201308535.commit-dd17bb7

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.
@@ -0,0 +1,2 @@
1
+ import { IEngine } from '@dcl/ecs';
2
+ export declare function serializeCrdtMessages(prefix: string, data: Uint8Array, engine: IEngine): Generator<string, void, unknown>;
@@ -0,0 +1,34 @@
1
+ import { CrdtMessageType } from '@dcl/ecs';
2
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
3
+ import { readMessage } from '@dcl/ecs/dist/serialization/crdt/message';
4
+ export function* serializeCrdtMessages(prefix, data, engine) {
5
+ const buffer = new ReadWriteByteBuffer(data);
6
+ let message;
7
+ while ((message = readMessage(buffer))) {
8
+ const ent = `0x${message.entityId.toString(16)}`;
9
+ const preface = `${prefix}: ${CrdtMessageType[message.type]} e=${ent}`;
10
+ if (message.type === CrdtMessageType.DELETE_ENTITY) {
11
+ yield `${preface}`;
12
+ }
13
+ if (message.type === CrdtMessageType.PUT_COMPONENT ||
14
+ message.type === CrdtMessageType.DELETE_COMPONENT ||
15
+ message.type === CrdtMessageType.APPEND_VALUE) {
16
+ const { componentId, timestamp } = message;
17
+ const data = 'data' in message ? message.data : undefined;
18
+ try {
19
+ const c = engine.getComponent(componentId);
20
+ yield `${preface} c=${c.componentName} t=${timestamp} data=${JSON.stringify((data && c.schema.deserialize(new ReadWriteByteBuffer(data))) || null)}`;
21
+ }
22
+ catch {
23
+ yield `${preface} c=${componentId} t=${timestamp} data=?`;
24
+ }
25
+ }
26
+ else if (message.type === CrdtMessageType.DELETE_ENTITY) {
27
+ yield preface;
28
+ }
29
+ else {
30
+ yield `${preface} Unknown CrdtMessageType`;
31
+ }
32
+ }
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludGVybmFsL3RyYW5zcG9ydHMvbG9nZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBd0IsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQ2hFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHdDQUF3QyxDQUFBO0FBQzVFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQTtBQUV0RSxNQUFNLFNBQVMsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLE1BQWMsRUFBRSxJQUFnQixFQUFFLE1BQWU7SUFDdEYsTUFBTSxNQUFNLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUU1QyxJQUFJLE9BQTJCLENBQUE7SUFFL0IsT0FBTyxDQUFDLE9BQU8sR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRTtRQUN0QyxNQUFNLEdBQUcsR0FBRyxLQUFLLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUE7UUFDaEQsTUFBTSxPQUFPLEdBQUcsR0FBRyxNQUFNLEtBQUssZUFBZSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQTtRQUN0RSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLGFBQWEsRUFBRTtZQUNsRCxNQUFNLEdBQUcsT0FBTyxFQUFFLENBQUE7U0FDbkI7UUFFRCxJQUNFLE9BQU8sQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLGFBQWE7WUFDOUMsT0FBTyxDQUFDLElBQUksS0FBSyxlQUFlLENBQUMsZ0JBQWdCO1lBQ2pELE9BQU8sQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLFlBQVksRUFDN0M7WUFDQSxNQUFNLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxHQUFHLE9BQU8sQ0FBQTtZQUMxQyxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUE7WUFFekQsSUFBSTtnQkFDRixNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFBO2dCQUUxQyxNQUFNLEdBQUcsT0FBTyxNQUFNLENBQUMsQ0FBQyxhQUFhLE1BQU0sU0FBUyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQ3pFLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FDdEUsRUFBRSxDQUFBO2FBQ0o7WUFBQyxNQUFNO2dCQUNOLE1BQU0sR0FBRyxPQUFPLE1BQU0sV0FBVyxNQUFNLFNBQVMsU0FBUyxDQUFBO2FBQzFEO1NBQ0Y7YUFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLGFBQWEsRUFBRTtZQUN6RCxNQUFNLE9BQU8sQ0FBQTtTQUNkO2FBQU07WUFDTCxNQUFNLEdBQUcsT0FBTywwQkFBMEIsQ0FBQTtTQUMzQztLQUNGO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElFbmdpbmUsIENyZHRNZXNzYWdlLCBDcmR0TWVzc2FnZVR5cGUgfSBmcm9tICdAZGNsL2VjcydcbmltcG9ydCB7IFJlYWRXcml0ZUJ5dGVCdWZmZXIgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vQnl0ZUJ1ZmZlcidcbmltcG9ydCB7IHJlYWRNZXNzYWdlIH0gZnJvbSAnQGRjbC9lY3MvZGlzdC9zZXJpYWxpemF0aW9uL2NyZHQvbWVzc2FnZSdcblxuZXhwb3J0IGZ1bmN0aW9uKiBzZXJpYWxpemVDcmR0TWVzc2FnZXMocHJlZml4OiBzdHJpbmcsIGRhdGE6IFVpbnQ4QXJyYXksIGVuZ2luZTogSUVuZ2luZSkge1xuICBjb25zdCBidWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcihkYXRhKVxuXG4gIGxldCBtZXNzYWdlOiBDcmR0TWVzc2FnZSB8IG51bGxcblxuICB3aGlsZSAoKG1lc3NhZ2UgPSByZWFkTWVzc2FnZShidWZmZXIpKSkge1xuICAgIGNvbnN0IGVudCA9IGAweCR7bWVzc2FnZS5lbnRpdHlJZC50b1N0cmluZygxNil9YFxuICAgIGNvbnN0IHByZWZhY2UgPSBgJHtwcmVmaXh9OiAke0NyZHRNZXNzYWdlVHlwZVttZXNzYWdlLnR5cGVdfSBlPSR7ZW50fWBcbiAgICBpZiAobWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0VOVElUWSkge1xuICAgICAgeWllbGQgYCR7cHJlZmFjZX1gXG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgbWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuUFVUX0NPTVBPTkVOVCB8fFxuICAgICAgbWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0NPTVBPTkVOVCB8fFxuICAgICAgbWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuQVBQRU5EX1ZBTFVFXG4gICAgKSB7XG4gICAgICBjb25zdCB7IGNvbXBvbmVudElkLCB0aW1lc3RhbXAgfSA9IG1lc3NhZ2VcbiAgICAgIGNvbnN0IGRhdGEgPSAnZGF0YScgaW4gbWVzc2FnZSA/IG1lc3NhZ2UuZGF0YSA6IHVuZGVmaW5lZFxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjID0gZW5naW5lLmdldENvbXBvbmVudChjb21wb25lbnRJZClcblxuICAgICAgICB5aWVsZCBgJHtwcmVmYWNlfSBjPSR7Yy5jb21wb25lbnROYW1lfSB0PSR7dGltZXN0YW1wfSBkYXRhPSR7SlNPTi5zdHJpbmdpZnkoXG4gICAgICAgICAgKGRhdGEgJiYgYy5zY2hlbWEuZGVzZXJpYWxpemUobmV3IFJlYWRXcml0ZUJ5dGVCdWZmZXIoZGF0YSkpKSB8fCBudWxsXG4gICAgICAgICl9YFxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHlpZWxkIGAke3ByZWZhY2V9IGM9JHtjb21wb25lbnRJZH0gdD0ke3RpbWVzdGFtcH0gZGF0YT0/YFxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobWVzc2FnZS50eXBlID09PSBDcmR0TWVzc2FnZVR5cGUuREVMRVRFX0VOVElUWSkge1xuICAgICAgeWllbGQgcHJlZmFjZVxuICAgIH0gZWxzZSB7XG4gICAgICB5aWVsZCBgJHtwcmVmYWNlfSBVbmtub3duIENyZHRNZXNzYWdlVHlwZWBcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,5 @@
1
+ import { NetworkManager } from './types';
2
+ export type ClientTransportConfig = {
3
+ serverUrl: string;
4
+ };
5
+ export declare function createClientTransport({ serverUrl }: ClientTransportConfig): Promise<NetworkManager>;
@@ -0,0 +1,65 @@
1
+ import { craftMessage, createNetworkManager, encodeString, syncFilter } from './utils';
2
+ import { engine } from '@dcl/ecs';
3
+ import { getHeaders } from '~system/SignedFetch';
4
+ import { MessageType } from './types';
5
+ export async function createClientTransport({ serverUrl }) {
6
+ const messagesToProcess = [];
7
+ return new Promise((resolve, reject) => {
8
+ try {
9
+ const ws = new WebSocket(serverUrl);
10
+ ws.binaryType = 'arraybuffer';
11
+ ws.onopen = async () => {
12
+ console.log('WS Server Sync connected');
13
+ const { headers } = await getHeaders({ url: serverUrl, init: { headers: {} } });
14
+ ws.send(craftMessage(MessageType.Auth, encodeString(JSON.stringify(headers))));
15
+ const transport = {
16
+ filter: syncFilter,
17
+ send: async (message) => {
18
+ if (ws.readyState === WebSocket.OPEN) {
19
+ ws.send(craftMessage(MessageType.Crdt, message));
20
+ }
21
+ if (messagesToProcess && messagesToProcess.length) {
22
+ if (transport.onmessage) {
23
+ for (const byteArray of messagesToProcess) {
24
+ transport.onmessage(byteArray);
25
+ }
26
+ }
27
+ }
28
+ messagesToProcess.length = 0;
29
+ }
30
+ };
31
+ engine.addTransport(transport);
32
+ };
33
+ ws.onmessage = (event) => {
34
+ if (event.data.byteLength) {
35
+ let offset = 0;
36
+ const r = new Uint8Array(event.data);
37
+ const view = new DataView(r.buffer);
38
+ const msgType = view.getUint8(offset);
39
+ offset += 1;
40
+ if (msgType === MessageType.Crdt) {
41
+ messagesToProcess.push(r.subarray(offset));
42
+ }
43
+ else if (msgType === MessageType.Init) {
44
+ const start = view.getUint32(offset);
45
+ offset += 4;
46
+ const size = view.getUint32(offset);
47
+ offset += 4;
48
+ const localEntitiesReserved = view.getUint32(offset);
49
+ offset += 4;
50
+ resolve(createNetworkManager(localEntitiesReserved, [start, start + size]));
51
+ messagesToProcess.push(r.subarray(offset));
52
+ }
53
+ }
54
+ };
55
+ ws.onerror = (e) => {
56
+ console.error(e);
57
+ reject(e);
58
+ };
59
+ }
60
+ catch (err) {
61
+ reject(err);
62
+ }
63
+ });
64
+ }
65
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL25ldHdvcmstdHJhbnNwb3J0L2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFDdEYsT0FBTyxFQUFhLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFaEQsT0FBTyxFQUFFLFdBQVcsRUFBMEIsTUFBTSxTQUFTLENBQUE7QUFNN0QsTUFBTSxDQUFDLEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxFQUFFLFNBQVMsRUFBeUI7SUFDOUUsTUFBTSxpQkFBaUIsR0FBaUIsRUFBRSxDQUFBO0lBRTFDLE9BQU8sSUFBSSxPQUFPLENBQWlCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JELElBQUk7WUFDRixNQUFNLEVBQUUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxTQUFTLENBQVcsQ0FBQTtZQUM3QyxFQUFFLENBQUMsVUFBVSxHQUFHLGFBQWEsQ0FBQTtZQUU3QixFQUFFLENBQUMsTUFBTSxHQUFHLEtBQUssSUFBSSxFQUFFO2dCQUNyQixPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixDQUFDLENBQUE7Z0JBQ3ZDLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQTtnQkFDL0UsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtnQkFFOUUsTUFBTSxTQUFTLEdBQWM7b0JBQzNCLE1BQU0sRUFBRSxVQUFVO29CQUNsQixJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQW1CLEVBQUUsRUFBRTt3QkFDbEMsSUFBSSxFQUFFLENBQUMsVUFBVSxLQUFLLFNBQVMsQ0FBQyxJQUFJLEVBQUU7NEJBQ3BDLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQTt5QkFDakQ7d0JBQ0QsSUFBSSxpQkFBaUIsSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEVBQUU7NEJBQ2pELElBQUksU0FBUyxDQUFDLFNBQVMsRUFBRTtnQ0FDdkIsS0FBSyxNQUFNLFNBQVMsSUFBSSxpQkFBaUIsRUFBRTtvQ0FDekMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQTtpQ0FDL0I7NkJBQ0Y7eUJBQ0Y7d0JBQ0QsaUJBQWlCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQTtvQkFDOUIsQ0FBQztpQkFDRixDQUFBO2dCQUNELE1BQU0sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUE7WUFDaEMsQ0FBQyxDQUFBO1lBRUQsRUFBRSxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUN2QixJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFO29CQUN6QixJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUE7b0JBQ2QsTUFBTSxDQUFDLEdBQUcsSUFBSSxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFBO29CQUNwQyxNQUFNLElBQUksR0FBRyxJQUFJLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUE7b0JBQ25DLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUE7b0JBQ3JDLE1BQU0sSUFBSSxDQUFDLENBQUE7b0JBRVgsSUFBSSxPQUFPLEtBQUssV0FBVyxDQUFDLElBQUksRUFBRTt3QkFDaEMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQTtxQkFDM0M7eUJBQU0sSUFBSSxPQUFPLEtBQUssV0FBVyxDQUFDLElBQUksRUFBRTt3QkFDdkMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTt3QkFDcEMsTUFBTSxJQUFJLENBQUMsQ0FBQTt3QkFDWCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFBO3dCQUNuQyxNQUFNLElBQUksQ0FBQyxDQUFBO3dCQUNYLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTt3QkFDcEQsTUFBTSxJQUFJLENBQUMsQ0FBQTt3QkFDWCxPQUFPLENBQUMsb0JBQW9CLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxLQUFLLEVBQUUsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTt3QkFDM0UsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQTtxQkFDM0M7aUJBQ0Y7WUFDSCxDQUFDLENBQUE7WUFFRCxFQUFFLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUU7Z0JBQ2pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQ2hCLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQTtZQUNYLENBQUMsQ0FBQTtTQUNGO1FBQUMsT0FBTyxHQUFHLEVBQUU7WUFDWixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7U0FDWjtJQUNILENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyYWZ0TWVzc2FnZSwgY3JlYXRlTmV0d29ya01hbmFnZXIsIGVuY29kZVN0cmluZywgc3luY0ZpbHRlciB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBUcmFuc3BvcnQsIGVuZ2luZSB9IGZyb20gJ0BkY2wvZWNzJ1xuaW1wb3J0IHsgZ2V0SGVhZGVycyB9IGZyb20gJ35zeXN0ZW0vU2lnbmVkRmV0Y2gnXG5cbmltcG9ydCB7IE1lc3NhZ2VUeXBlLCBOZXR3b3JrTWFuYWdlciwgU29ja2V0IH0gZnJvbSAnLi90eXBlcydcblxuZXhwb3J0IHR5cGUgQ2xpZW50VHJhbnNwb3J0Q29uZmlnID0ge1xuICBzZXJ2ZXJVcmw6IHN0cmluZ1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2xpZW50VHJhbnNwb3J0KHsgc2VydmVyVXJsIH06IENsaWVudFRyYW5zcG9ydENvbmZpZyk6IFByb21pc2U8TmV0d29ya01hbmFnZXI+IHtcbiAgY29uc3QgbWVzc2FnZXNUb1Byb2Nlc3M6IFVpbnQ4QXJyYXlbXSA9IFtdXG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlPE5ldHdvcmtNYW5hZ2VyPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHdzID0gbmV3IFdlYlNvY2tldChzZXJ2ZXJVcmwpIGFzIFNvY2tldFxuICAgICAgd3MuYmluYXJ5VHlwZSA9ICdhcnJheWJ1ZmZlcidcblxuICAgICAgd3Mub25vcGVuID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZygnV1MgU2VydmVyIFN5bmMgY29ubmVjdGVkJylcbiAgICAgICAgY29uc3QgeyBoZWFkZXJzIH0gPSBhd2FpdCBnZXRIZWFkZXJzKHsgdXJsOiBzZXJ2ZXJVcmwsIGluaXQ6IHsgaGVhZGVyczoge30gfSB9KVxuICAgICAgICB3cy5zZW5kKGNyYWZ0TWVzc2FnZShNZXNzYWdlVHlwZS5BdXRoLCBlbmNvZGVTdHJpbmcoSlNPTi5zdHJpbmdpZnkoaGVhZGVycykpKSlcblxuICAgICAgICBjb25zdCB0cmFuc3BvcnQ6IFRyYW5zcG9ydCA9IHtcbiAgICAgICAgICBmaWx0ZXI6IHN5bmNGaWx0ZXIsXG4gICAgICAgICAgc2VuZDogYXN5bmMgKG1lc3NhZ2U6IFVpbnQ4QXJyYXkpID0+IHtcbiAgICAgICAgICAgIGlmICh3cy5yZWFkeVN0YXRlID09PSBXZWJTb2NrZXQuT1BFTikge1xuICAgICAgICAgICAgICB3cy5zZW5kKGNyYWZ0TWVzc2FnZShNZXNzYWdlVHlwZS5DcmR0LCBtZXNzYWdlKSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtZXNzYWdlc1RvUHJvY2VzcyAmJiBtZXNzYWdlc1RvUHJvY2Vzcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgaWYgKHRyYW5zcG9ydC5vbm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGJ5dGVBcnJheSBvZiBtZXNzYWdlc1RvUHJvY2Vzcykge1xuICAgICAgICAgICAgICAgICAgdHJhbnNwb3J0Lm9ubWVzc2FnZShieXRlQXJyYXkpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtZXNzYWdlc1RvUHJvY2Vzcy5sZW5ndGggPSAwXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVuZ2luZS5hZGRUcmFuc3BvcnQodHJhbnNwb3J0KVxuICAgICAgfVxuXG4gICAgICB3cy5vbm1lc3NhZ2UgPSAoZXZlbnQpID0+IHtcbiAgICAgICAgaWYgKGV2ZW50LmRhdGEuYnl0ZUxlbmd0aCkge1xuICAgICAgICAgIGxldCBvZmZzZXQgPSAwXG4gICAgICAgICAgY29uc3QgciA9IG5ldyBVaW50OEFycmF5KGV2ZW50LmRhdGEpXG4gICAgICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhyLmJ1ZmZlcilcbiAgICAgICAgICBjb25zdCBtc2dUeXBlID0gdmlldy5nZXRVaW50OChvZmZzZXQpXG4gICAgICAgICAgb2Zmc2V0ICs9IDFcblxuICAgICAgICAgIGlmIChtc2dUeXBlID09PSBNZXNzYWdlVHlwZS5DcmR0KSB7XG4gICAgICAgICAgICBtZXNzYWdlc1RvUHJvY2Vzcy5wdXNoKHIuc3ViYXJyYXkob2Zmc2V0KSlcbiAgICAgICAgICB9IGVsc2UgaWYgKG1zZ1R5cGUgPT09IE1lc3NhZ2VUeXBlLkluaXQpIHtcbiAgICAgICAgICAgIGNvbnN0IHN0YXJ0ID0gdmlldy5nZXRVaW50MzIob2Zmc2V0KVxuICAgICAgICAgICAgb2Zmc2V0ICs9IDRcbiAgICAgICAgICAgIGNvbnN0IHNpemUgPSB2aWV3LmdldFVpbnQzMihvZmZzZXQpXG4gICAgICAgICAgICBvZmZzZXQgKz0gNFxuICAgICAgICAgICAgY29uc3QgbG9jYWxFbnRpdGllc1Jlc2VydmVkID0gdmlldy5nZXRVaW50MzIob2Zmc2V0KVxuICAgICAgICAgICAgb2Zmc2V0ICs9IDRcbiAgICAgICAgICAgIHJlc29sdmUoY3JlYXRlTmV0d29ya01hbmFnZXIobG9jYWxFbnRpdGllc1Jlc2VydmVkLCBbc3RhcnQsIHN0YXJ0ICsgc2l6ZV0pKVxuICAgICAgICAgICAgbWVzc2FnZXNUb1Byb2Nlc3MucHVzaChyLnN1YmFycmF5KG9mZnNldCkpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHdzLm9uZXJyb3IgPSAoZSkgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGUpXG4gICAgICAgIHJlamVjdChlKVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmVqZWN0KGVycilcbiAgICB9XG4gIH0pXG59XG4iXX0=
@@ -0,0 +1,10 @@
1
+ import { NetworkManager, ServerTransportConfig } from './types';
2
+ import { ClientTransportConfig } from './client';
3
+ export { NetworkManager } from './types';
4
+ export type NetworkTransportConfig = ClientTransportConfig & Partial<ServerTransportConfig>;
5
+ export declare let connected: boolean;
6
+ export declare let reservedLocalEntities: number;
7
+ export declare function createNetworkManager(config: NetworkTransportConfig): Promise<NetworkManager>;
8
+ export declare const PlayersConnected: import("@dcl/ecs").MapComponentDefinition<import("@dcl/ecs").MapResult<{
9
+ usersId: import("@dcl/ecs").ISchema<string[]>;
10
+ }>>;
@@ -0,0 +1,29 @@
1
+ import { isServer } from '~system/EngineApi';
2
+ import { Schemas, engine } from '@dcl/ecs';
3
+ import { createServerTransport } from './server';
4
+ import { createClientTransport } from './client';
5
+ export let connected = false;
6
+ const DEFAULT_NETWORK_ENTITY_LIMIT_SERVER = 512;
7
+ const DEFAULT_NETWORK_ENTITY_LIMIT_CLIENT = 100;
8
+ const DEFAULT_RESERVED_LOCAL_ENTITIES = 2560;
9
+ export let reservedLocalEntities;
10
+ export async function createNetworkManager(config) {
11
+ if (connected) {
12
+ throw new Error('Transport is already created');
13
+ }
14
+ const serverConfig = {
15
+ networkEntitiesLimit: config.networkEntitiesLimit ?? {
16
+ serverLimit: DEFAULT_NETWORK_ENTITY_LIMIT_SERVER,
17
+ clientLimit: DEFAULT_NETWORK_ENTITY_LIMIT_CLIENT
18
+ },
19
+ reservedLocalEntities: config.reservedLocalEntities || DEFAULT_RESERVED_LOCAL_ENTITIES
20
+ };
21
+ reservedLocalEntities = serverConfig.reservedLocalEntities;
22
+ const networkFactory = isServer && (await isServer({})).isServer ? createServerTransport(serverConfig) : createClientTransport(config);
23
+ connected = true;
24
+ return networkFactory;
25
+ }
26
+ export const PlayersConnected = engine.defineComponent('chore:network:players', {
27
+ usersId: Schemas.Array(Schemas.String)
28
+ });
29
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbmV0d29yay10cmFuc3BvcnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBRzVDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzFDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUNoRCxPQUFPLEVBQXlCLHFCQUFxQixFQUFFLE1BQU0sVUFBVSxDQUFBO0FBTXZFLE1BQU0sQ0FBQyxJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUE7QUFFNUIsTUFBTSxtQ0FBbUMsR0FBRyxHQUFHLENBQUE7QUFDL0MsTUFBTSxtQ0FBbUMsR0FBRyxHQUFHLENBQUE7QUFDL0MsTUFBTSwrQkFBK0IsR0FBRyxJQUFJLENBQUE7QUFFNUMsTUFBTSxDQUFDLElBQUkscUJBQTZCLENBQUE7QUFLeEMsTUFBTSxDQUFDLEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxNQUE4QjtJQUN2RSxJQUFJLFNBQVMsRUFBRTtRQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQTtLQUNoRDtJQUVELE1BQU0sWUFBWSxHQUFHO1FBQ25CLG9CQUFvQixFQUFFLE1BQU0sQ0FBQyxvQkFBb0IsSUFBSTtZQUNuRCxXQUFXLEVBQUUsbUNBQW1DO1lBQ2hELFdBQVcsRUFBRSxtQ0FBbUM7U0FDakQ7UUFDRCxxQkFBcUIsRUFBRSxNQUFNLENBQUMscUJBQXFCLElBQUksK0JBQStCO0tBQ3ZGLENBQUE7SUFDRCxxQkFBcUIsR0FBRyxZQUFZLENBQUMscUJBQXFCLENBQUE7SUFFMUQsTUFBTSxjQUFjLEdBQ2xCLFFBQVEsSUFBSSxDQUFDLE1BQU0sUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMscUJBQXFCLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDakgsU0FBUyxHQUFHLElBQUksQ0FBQTtJQUNoQixPQUFPLGNBQWMsQ0FBQTtBQUN2QixDQUFDO0FBRUQsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLGVBQWUsQ0FBQyx1QkFBdUIsRUFBRTtJQUM5RSxPQUFPLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO0NBQ3ZDLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzU2VydmVyIH0gZnJvbSAnfnN5c3RlbS9FbmdpbmVBcGknXG5cbmltcG9ydCB7IE5ldHdvcmtNYW5hZ2VyLCBTZXJ2ZXJUcmFuc3BvcnRDb25maWcgfSBmcm9tICcuL3R5cGVzJ1xuaW1wb3J0IHsgU2NoZW1hcywgZW5naW5lIH0gZnJvbSAnQGRjbC9lY3MnXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXJUcmFuc3BvcnQgfSBmcm9tICcuL3NlcnZlcidcbmltcG9ydCB7IENsaWVudFRyYW5zcG9ydENvbmZpZywgY3JlYXRlQ2xpZW50VHJhbnNwb3J0IH0gZnJvbSAnLi9jbGllbnQnXG5cbmV4cG9ydCB7IE5ldHdvcmtNYW5hZ2VyIH0gZnJvbSAnLi90eXBlcydcblxuZXhwb3J0IHR5cGUgTmV0d29ya1RyYW5zcG9ydENvbmZpZyA9IENsaWVudFRyYW5zcG9ydENvbmZpZyAmIFBhcnRpYWw8U2VydmVyVHJhbnNwb3J0Q29uZmlnPlxuXG5leHBvcnQgbGV0IGNvbm5lY3RlZCA9IGZhbHNlXG5cbmNvbnN0IERFRkFVTFRfTkVUV09SS19FTlRJVFlfTElNSVRfU0VSVkVSID0gNTEyXG5jb25zdCBERUZBVUxUX05FVFdPUktfRU5USVRZX0xJTUlUX0NMSUVOVCA9IDEwMFxuY29uc3QgREVGQVVMVF9SRVNFUlZFRF9MT0NBTF9FTlRJVElFUyA9IDI1NjBcblxuZXhwb3J0IGxldCByZXNlcnZlZExvY2FsRW50aXRpZXM6IG51bWJlclxuLyoqXG4gKiBAYWxwaGFcbiAqIENvbm5lY3QgdG8gQ1JEVCBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU5ldHdvcmtNYW5hZ2VyKGNvbmZpZzogTmV0d29ya1RyYW5zcG9ydENvbmZpZyk6IFByb21pc2U8TmV0d29ya01hbmFnZXI+IHtcbiAgaWYgKGNvbm5lY3RlZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGlzIGFscmVhZHkgY3JlYXRlZCcpXG4gIH1cblxuICBjb25zdCBzZXJ2ZXJDb25maWcgPSB7XG4gICAgbmV0d29ya0VudGl0aWVzTGltaXQ6IGNvbmZpZy5uZXR3b3JrRW50aXRpZXNMaW1pdCA/PyB7XG4gICAgICBzZXJ2ZXJMaW1pdDogREVGQVVMVF9ORVRXT1JLX0VOVElUWV9MSU1JVF9TRVJWRVIsXG4gICAgICBjbGllbnRMaW1pdDogREVGQVVMVF9ORVRXT1JLX0VOVElUWV9MSU1JVF9DTElFTlRcbiAgICB9LFxuICAgIHJlc2VydmVkTG9jYWxFbnRpdGllczogY29uZmlnLnJlc2VydmVkTG9jYWxFbnRpdGllcyB8fCBERUZBVUxUX1JFU0VSVkVEX0xPQ0FMX0VOVElUSUVTXG4gIH1cbiAgcmVzZXJ2ZWRMb2NhbEVudGl0aWVzID0gc2VydmVyQ29uZmlnLnJlc2VydmVkTG9jYWxFbnRpdGllc1xuXG4gIGNvbnN0IG5ldHdvcmtGYWN0b3J5ID1cbiAgICBpc1NlcnZlciAmJiAoYXdhaXQgaXNTZXJ2ZXIoe30pKS5pc1NlcnZlciA/IGNyZWF0ZVNlcnZlclRyYW5zcG9ydChzZXJ2ZXJDb25maWcpIDogY3JlYXRlQ2xpZW50VHJhbnNwb3J0KGNvbmZpZylcbiAgY29ubmVjdGVkID0gdHJ1ZVxuICByZXR1cm4gbmV0d29ya0ZhY3Rvcnlcbn1cblxuZXhwb3J0IGNvbnN0IFBsYXllcnNDb25uZWN0ZWQgPSBlbmdpbmUuZGVmaW5lQ29tcG9uZW50KCdjaG9yZTpuZXR3b3JrOnBsYXllcnMnLCB7XG4gIHVzZXJzSWQ6IFNjaGVtYXMuQXJyYXkoU2NoZW1hcy5TdHJpbmcpXG59KVxuIl19
@@ -0,0 +1,2 @@
1
+ import { NetworkManager, ServerTransportConfig } from './types';
2
+ export declare function createServerTransport(config: ServerTransportConfig): Promise<NetworkManager>;
@@ -0,0 +1,62 @@
1
+ import { engine, SyncComponents } from '@dcl/ecs';
2
+ import { engineToCrdt } from './state';
3
+ import { syncFilter, createNetworkManager } from './utils';
4
+ import { PlayersConnected } from '.';
5
+ export async function createServerTransport(config) {
6
+ const connectedClients = new Set();
7
+ engine.addTransport({
8
+ send: async (message) => {
9
+ if (message.byteLength) {
10
+ globalThis.updateCRDTState(engineToCrdt(engine));
11
+ }
12
+ },
13
+ filter: syncFilter
14
+ });
15
+ let time = 0;
16
+ function initialCrdtState(dt) {
17
+ time += dt;
18
+ if (time >= 1) {
19
+ globalThis.updateCRDTState(engineToCrdt(engine));
20
+ engine.removeSystem(initialCrdtState);
21
+ }
22
+ }
23
+ engine.addSystem(initialCrdtState);
24
+ globalThis.registerScene(config, (event) => {
25
+ const { type } = event;
26
+ if (type === 'open') {
27
+ const { clientId, client } = event;
28
+ const transport = {
29
+ filter: (message) => {
30
+ if (!connectedClients.has(clientId))
31
+ return false;
32
+ return syncFilter(message);
33
+ },
34
+ send: async (message) => {
35
+ if (message.byteLength > 0) {
36
+ await client.sendCrdtMessage(message);
37
+ }
38
+ if (transport.onmessage) {
39
+ const messages = client.getMessages();
40
+ for (const byteArray of messages) {
41
+ transport.onmessage(byteArray);
42
+ }
43
+ }
44
+ }
45
+ };
46
+ engine.addTransport(transport);
47
+ connectedClients.add(event.clientId);
48
+ }
49
+ else if (type === 'close') {
50
+ connectedClients.delete(event.clientId);
51
+ }
52
+ PlayersConnected.createOrReplace(players, { usersId: [...connectedClients.values()].map(String) });
53
+ });
54
+ const networkEntityFactory = createNetworkManager(config.reservedLocalEntities, [
55
+ config.reservedLocalEntities,
56
+ config.reservedLocalEntities + config.networkEntitiesLimit.serverLimit
57
+ ]);
58
+ const players = networkEntityFactory.addEntity();
59
+ SyncComponents.create(players, { componentIds: [PlayersConnected.componentId] });
60
+ return networkEntityFactory;
61
+ }
62
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL25ldHdvcmstdHJhbnNwb3J0L3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBYSxNQUFNLFVBQVUsQ0FBQTtBQUM1RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFFMUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sR0FBRyxDQUFBO0FBRXBDLE1BQU0sQ0FBQyxLQUFLLFVBQVUscUJBQXFCLENBQUMsTUFBNkI7SUFDdkUsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFBO0lBQzFDLE1BQU0sQ0FBQyxZQUFZLENBQUM7UUFDbEIsSUFBSSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtZQUN0QixJQUFJLE9BQU8sQ0FBQyxVQUFVLEVBQUU7Z0JBQ3RCLFVBQVUsQ0FBQyxlQUFlLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUE7YUFDakQ7UUFDSCxDQUFDO1FBQ0QsTUFBTSxFQUFFLFVBQVU7S0FDbkIsQ0FBQyxDQUFBO0lBRUYsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFBO0lBQ1osU0FBUyxnQkFBZ0IsQ0FBQyxFQUFVO1FBQ2xDLElBQUksSUFBSSxFQUFFLENBQUE7UUFDVixJQUFJLElBQUksSUFBSSxDQUFDLEVBQUU7WUFDYixVQUFVLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFBO1lBQ2hELE1BQU0sQ0FBQyxZQUFZLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtTQUN0QztJQUNILENBQUM7SUFFRCxNQUFNLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUE7SUFDbEMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUN6QyxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFBO1FBQ3RCLElBQUksSUFBSSxLQUFLLE1BQU0sRUFBRTtZQUNuQixNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQTtZQUNsQyxNQUFNLFNBQVMsR0FBYztnQkFDM0IsTUFBTSxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUU7b0JBQ2xCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO3dCQUFFLE9BQU8sS0FBSyxDQUFBO29CQUNqRCxPQUFPLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQTtnQkFDNUIsQ0FBQztnQkFDRCxJQUFJLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO29CQUN0QixJQUFJLE9BQU8sQ0FBQyxVQUFVLEdBQUcsQ0FBQyxFQUFFO3dCQUMxQixNQUFNLE1BQU0sQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUE7cUJBQ3RDO29CQUVELElBQUksU0FBUyxDQUFDLFNBQVMsRUFBRTt3QkFDdkIsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFBO3dCQUNyQyxLQUFLLE1BQU0sU0FBUyxJQUFJLFFBQVEsRUFBRTs0QkFDaEMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQTt5QkFDL0I7cUJBQ0Y7Z0JBQ0gsQ0FBQzthQUNGLENBQUE7WUFFRCxNQUFNLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1lBQzlCLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUE7U0FDckM7YUFBTSxJQUFJLElBQUksS0FBSyxPQUFPLEVBQUU7WUFDM0IsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQTtTQUN4QztRQUNELGdCQUFnQixDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxHQUFHLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQTtJQUNwRyxDQUFDLENBQUMsQ0FBQTtJQUVGLE1BQU0sb0JBQW9CLEdBQUcsb0JBQW9CLENBQUMsTUFBTSxDQUFDLHFCQUFxQixFQUFFO1FBQzlFLE1BQU0sQ0FBQyxxQkFBcUI7UUFDNUIsTUFBTSxDQUFDLHFCQUFxQixHQUFHLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXO0tBQ3ZFLENBQUMsQ0FBQTtJQUNGLE1BQU0sT0FBTyxHQUFHLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxDQUFBO0lBQ2hELGNBQWMsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0lBQ2hGLE9BQU8sb0JBQW9CLENBQUE7QUFDN0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGVuZ2luZSwgU3luY0NvbXBvbmVudHMsIFRyYW5zcG9ydCB9IGZyb20gJ0BkY2wvZWNzJ1xuaW1wb3J0IHsgZW5naW5lVG9DcmR0IH0gZnJvbSAnLi9zdGF0ZSdcbmltcG9ydCB7IHN5bmNGaWx0ZXIsIGNyZWF0ZU5ldHdvcmtNYW5hZ2VyIH0gZnJvbSAnLi91dGlscydcbmltcG9ydCB7IE5ldHdvcmtNYW5hZ2VyLCBTZXJ2ZXJUcmFuc3BvcnRDb25maWcgfSBmcm9tICcuL3R5cGVzJ1xuaW1wb3J0IHsgUGxheWVyc0Nvbm5lY3RlZCB9IGZyb20gJy4nXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVTZXJ2ZXJUcmFuc3BvcnQoY29uZmlnOiBTZXJ2ZXJUcmFuc3BvcnRDb25maWcpOiBQcm9taXNlPE5ldHdvcmtNYW5hZ2VyPiB7XG4gIGNvbnN0IGNvbm5lY3RlZENsaWVudHMgPSBuZXcgU2V0PHN0cmluZz4oKVxuICBlbmdpbmUuYWRkVHJhbnNwb3J0KHtcbiAgICBzZW5kOiBhc3luYyAobWVzc2FnZSkgPT4ge1xuICAgICAgaWYgKG1lc3NhZ2UuYnl0ZUxlbmd0aCkge1xuICAgICAgICBnbG9iYWxUaGlzLnVwZGF0ZUNSRFRTdGF0ZShlbmdpbmVUb0NyZHQoZW5naW5lKSlcbiAgICAgIH1cbiAgICB9LFxuICAgIGZpbHRlcjogc3luY0ZpbHRlclxuICB9KVxuXG4gIGxldCB0aW1lID0gMFxuICBmdW5jdGlvbiBpbml0aWFsQ3JkdFN0YXRlKGR0OiBudW1iZXIpIHtcbiAgICB0aW1lICs9IGR0XG4gICAgaWYgKHRpbWUgPj0gMSkge1xuICAgICAgZ2xvYmFsVGhpcy51cGRhdGVDUkRUU3RhdGUoZW5naW5lVG9DcmR0KGVuZ2luZSkpXG4gICAgICBlbmdpbmUucmVtb3ZlU3lzdGVtKGluaXRpYWxDcmR0U3RhdGUpXG4gICAgfVxuICB9XG5cbiAgZW5naW5lLmFkZFN5c3RlbShpbml0aWFsQ3JkdFN0YXRlKVxuICBnbG9iYWxUaGlzLnJlZ2lzdGVyU2NlbmUoY29uZmlnLCAoZXZlbnQpID0+IHtcbiAgICBjb25zdCB7IHR5cGUgfSA9IGV2ZW50XG4gICAgaWYgKHR5cGUgPT09ICdvcGVuJykge1xuICAgICAgY29uc3QgeyBjbGllbnRJZCwgY2xpZW50IH0gPSBldmVudFxuICAgICAgY29uc3QgdHJhbnNwb3J0OiBUcmFuc3BvcnQgPSB7XG4gICAgICAgIGZpbHRlcjogKG1lc3NhZ2UpID0+IHtcbiAgICAgICAgICBpZiAoIWNvbm5lY3RlZENsaWVudHMuaGFzKGNsaWVudElkKSkgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgcmV0dXJuIHN5bmNGaWx0ZXIobWVzc2FnZSlcbiAgICAgICAgfSxcbiAgICAgICAgc2VuZDogYXN5bmMgKG1lc3NhZ2UpID0+IHtcbiAgICAgICAgICBpZiAobWVzc2FnZS5ieXRlTGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYXdhaXQgY2xpZW50LnNlbmRDcmR0TWVzc2FnZShtZXNzYWdlKVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICh0cmFuc3BvcnQub25tZXNzYWdlKSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlcyA9IGNsaWVudC5nZXRNZXNzYWdlcygpXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGJ5dGVBcnJheSBvZiBtZXNzYWdlcykge1xuICAgICAgICAgICAgICB0cmFuc3BvcnQub25tZXNzYWdlKGJ5dGVBcnJheSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgZW5naW5lLmFkZFRyYW5zcG9ydCh0cmFuc3BvcnQpXG4gICAgICBjb25uZWN0ZWRDbGllbnRzLmFkZChldmVudC5jbGllbnRJZClcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT09ICdjbG9zZScpIHtcbiAgICAgIGNvbm5lY3RlZENsaWVudHMuZGVsZXRlKGV2ZW50LmNsaWVudElkKVxuICAgIH1cbiAgICBQbGF5ZXJzQ29ubmVjdGVkLmNyZWF0ZU9yUmVwbGFjZShwbGF5ZXJzLCB7IHVzZXJzSWQ6IFsuLi5jb25uZWN0ZWRDbGllbnRzLnZhbHVlcygpXS5tYXAoU3RyaW5nKSB9KVxuICB9KVxuXG4gIGNvbnN0IG5ldHdvcmtFbnRpdHlGYWN0b3J5ID0gY3JlYXRlTmV0d29ya01hbmFnZXIoY29uZmlnLnJlc2VydmVkTG9jYWxFbnRpdGllcywgW1xuICAgIGNvbmZpZy5yZXNlcnZlZExvY2FsRW50aXRpZXMsXG4gICAgY29uZmlnLnJlc2VydmVkTG9jYWxFbnRpdGllcyArIGNvbmZpZy5uZXR3b3JrRW50aXRpZXNMaW1pdC5zZXJ2ZXJMaW1pdFxuICBdKVxuICBjb25zdCBwbGF5ZXJzID0gbmV0d29ya0VudGl0eUZhY3RvcnkuYWRkRW50aXR5KClcbiAgU3luY0NvbXBvbmVudHMuY3JlYXRlKHBsYXllcnMsIHsgY29tcG9uZW50SWRzOiBbUGxheWVyc0Nvbm5lY3RlZC5jb21wb25lbnRJZF0gfSlcbiAgcmV0dXJuIG5ldHdvcmtFbnRpdHlGYWN0b3J5XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { IEngine } from '@dcl/ecs';
2
+ export declare function engineToCrdt(engine: IEngine): Uint8Array;
@@ -0,0 +1,11 @@
1
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
2
+ import { SyncComponents } from '@dcl/ecs';
3
+ export function engineToCrdt(engine) {
4
+ const crdtBuffer = new ReadWriteByteBuffer();
5
+ const syncEntities = new Set(Array.from(engine.getEntitiesWith(SyncComponents)).map(($) => $[0]));
6
+ for (const itComponentDefinition of engine.componentsIter()) {
7
+ itComponentDefinition.dumpCrdtStateToBuffer(crdtBuffer, (entity) => syncEntities.has(entity));
8
+ }
9
+ return crdtBuffer.toBinary();
10
+ }
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbmV0d29yay10cmFuc3BvcnQvc3RhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0NBQXdDLENBQUE7QUFDNUUsT0FBTyxFQUFXLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUVsRCxNQUFNLFVBQVUsWUFBWSxDQUFDLE1BQWU7SUFDMUMsTUFBTSxVQUFVLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxDQUFBO0lBQzVDLE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUVqRyxLQUFLLE1BQU0scUJBQXFCLElBQUksTUFBTSxDQUFDLGNBQWMsRUFBRSxFQUFFO1FBQzNELHFCQUFxQixDQUFDLHFCQUFxQixDQUFDLFVBQVUsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFBO0tBQzlGO0lBRUQsT0FBTyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUE7QUFDOUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlYWRXcml0ZUJ5dGVCdWZmZXIgfSBmcm9tICdAZGNsL2Vjcy9kaXN0L3NlcmlhbGl6YXRpb24vQnl0ZUJ1ZmZlcidcbmltcG9ydCB7IElFbmdpbmUsIFN5bmNDb21wb25lbnRzIH0gZnJvbSAnQGRjbC9lY3MnXG5cbmV4cG9ydCBmdW5jdGlvbiBlbmdpbmVUb0NyZHQoZW5naW5lOiBJRW5naW5lKTogVWludDhBcnJheSB7XG4gIGNvbnN0IGNyZHRCdWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcigpXG4gIGNvbnN0IHN5bmNFbnRpdGllcyA9IG5ldyBTZXQoQXJyYXkuZnJvbShlbmdpbmUuZ2V0RW50aXRpZXNXaXRoKFN5bmNDb21wb25lbnRzKSkubWFwKCgkKSA9PiAkWzBdKSlcblxuICBmb3IgKGNvbnN0IGl0Q29tcG9uZW50RGVmaW5pdGlvbiBvZiBlbmdpbmUuY29tcG9uZW50c0l0ZXIoKSkge1xuICAgIGl0Q29tcG9uZW50RGVmaW5pdGlvbi5kdW1wQ3JkdFN0YXRlVG9CdWZmZXIoY3JkdEJ1ZmZlciwgKGVudGl0eSkgPT4gc3luY0VudGl0aWVzLmhhcyhlbnRpdHkpKVxuICB9XG5cbiAgcmV0dXJuIGNyZHRCdWZmZXIudG9CaW5hcnkoKVxufVxuIl19
@@ -0,0 +1,36 @@
1
+ /// <reference types="@dcl/js-runtime" />
2
+ import { Entity, engine } from '@dcl/ecs';
3
+ export type Socket = WebSocket & {
4
+ binaryType: string;
5
+ send(data: string | Uint8Array): void;
6
+ };
7
+ export type NetworkManager = {
8
+ addEntity(theEngine: typeof engine): Entity;
9
+ };
10
+ export declare enum MessageType {
11
+ Auth = 1,
12
+ Init = 2,
13
+ Crdt = 3
14
+ }
15
+ export type ServerTransportConfig = {
16
+ reservedLocalEntities: number;
17
+ networkEntitiesLimit: {
18
+ serverLimit: number;
19
+ clientLimit: number;
20
+ };
21
+ };
22
+ declare global {
23
+ type ClientEvent = {
24
+ type: 'open';
25
+ clientId: string;
26
+ client: {
27
+ sendCrdtMessage(message: Uint8Array): Promise<void>;
28
+ getMessages(): Uint8Array[];
29
+ };
30
+ } | {
31
+ type: 'close';
32
+ clientId: string;
33
+ };
34
+ var updateCRDTState: (crdt: Uint8Array) => void;
35
+ var registerScene: (serverConfig: ServerTransportConfig, fn: (event: ClientEvent) => void) => void;
36
+ }
@@ -0,0 +1,7 @@
1
+ export var MessageType;
2
+ (function (MessageType) {
3
+ MessageType[MessageType["Auth"] = 1] = "Auth";
4
+ MessageType[MessageType["Init"] = 2] = "Init";
5
+ MessageType[MessageType["Crdt"] = 3] = "Crdt";
6
+ })(MessageType || (MessageType = {}));
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbmV0d29yay10cmFuc3BvcnQvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsTUFBTSxDQUFOLElBQVksV0FJWDtBQUpELFdBQVksV0FBVztJQUNyQiw2Q0FBUSxDQUFBO0lBQ1IsNkNBQVEsQ0FBQTtJQUNSLDZDQUFRLENBQUE7QUFDVixDQUFDLEVBSlcsV0FBVyxLQUFYLFdBQVcsUUFJdEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBFbnRpdHksIGVuZ2luZSB9IGZyb20gJ0BkY2wvZWNzJ1xuXG5leHBvcnQgdHlwZSBTb2NrZXQgPSBXZWJTb2NrZXQgJiB7XG4gIGJpbmFyeVR5cGU6IHN0cmluZ1xuICBzZW5kKGRhdGE6IHN0cmluZyB8IFVpbnQ4QXJyYXkpOiB2b2lkXG59XG5cbmV4cG9ydCB0eXBlIE5ldHdvcmtNYW5hZ2VyID0ge1xuICBhZGRFbnRpdHkodGhlRW5naW5lOiB0eXBlb2YgZW5naW5lKTogRW50aXR5XG59XG5cbmV4cG9ydCBlbnVtIE1lc3NhZ2VUeXBlIHtcbiAgQXV0aCA9IDEsXG4gIEluaXQgPSAyLFxuICBDcmR0ID0gM1xufVxuXG5leHBvcnQgdHlwZSBTZXJ2ZXJUcmFuc3BvcnRDb25maWcgPSB7XG4gIHJlc2VydmVkTG9jYWxFbnRpdGllczogbnVtYmVyXG4gIG5ldHdvcmtFbnRpdGllc0xpbWl0OiB7XG4gICAgc2VydmVyTGltaXQ6IG51bWJlclxuICAgIGNsaWVudExpbWl0OiBudW1iZXJcbiAgfVxufVxuXG5kZWNsYXJlIGdsb2JhbCB7XG4gIHR5cGUgQ2xpZW50RXZlbnQgPVxuICAgIHwge1xuICAgICAgICB0eXBlOiAnb3BlbidcbiAgICAgICAgY2xpZW50SWQ6IHN0cmluZ1xuICAgICAgICBjbGllbnQ6IHtcbiAgICAgICAgICBzZW5kQ3JkdE1lc3NhZ2UobWVzc2FnZTogVWludDhBcnJheSk6IFByb21pc2U8dm9pZD5cbiAgICAgICAgICBnZXRNZXNzYWdlcygpOiBVaW50OEFycmF5W11cbiAgICAgICAgfVxuICAgICAgfVxuICAgIHwgeyB0eXBlOiAnY2xvc2UnOyBjbGllbnRJZDogc3RyaW5nIH1cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXZhclxuICB2YXIgdXBkYXRlQ1JEVFN0YXRlOiAoY3JkdDogVWludDhBcnJheSkgPT4gdm9pZFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdmFyXG4gIHZhciByZWdpc3RlclNjZW5lOiAoc2VydmVyQ29uZmlnOiBTZXJ2ZXJUcmFuc3BvcnRDb25maWcsIGZuOiAoZXZlbnQ6IENsaWVudEV2ZW50KSA9PiB2b2lkKSA9PiB2b2lkXG59XG4iXX0=
@@ -0,0 +1,8 @@
1
+ import { TransportMessage } from '@dcl/ecs';
2
+ import { MessageType } from './types';
3
+ export declare function encodeString(s: string): Uint8Array;
4
+ export declare function craftMessage(msgType: MessageType, payload: Uint8Array): Uint8Array;
5
+ export declare function createNetworkManager(reservedLocalEntities: number, range: [number, number]): {
6
+ addEntity: () => import("@dcl/ecs").Entity;
7
+ };
8
+ export declare function syncFilter(message: Omit<TransportMessage, 'messageBuffer'>): boolean;
@@ -0,0 +1,46 @@
1
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer';
2
+ import { engine, PointerEventsResult, RESERVED_STATIC_ENTITIES, SyncComponents, CrdtMessageType, EntityUtils, GltfContainerLoadingState } from '@dcl/ecs';
3
+ import { connected, reservedLocalEntities } from '.';
4
+ export function encodeString(s) {
5
+ const buffer = new ReadWriteByteBuffer();
6
+ buffer.writeUtf8String(s);
7
+ return buffer.readBuffer();
8
+ }
9
+ export function craftMessage(msgType, payload) {
10
+ const msg = new Uint8Array(payload.byteLength + 1);
11
+ msg.set([msgType]);
12
+ msg.set(payload, 1);
13
+ return msg;
14
+ }
15
+ export function createNetworkManager(reservedLocalEntities, range) {
16
+ return engine.addNetworkManager(reservedLocalEntities, range);
17
+ }
18
+ export function syncFilter(message) {
19
+ if (!connected)
20
+ return false;
21
+ const componentId = message.componentId;
22
+ if ([PointerEventsResult.componentId, GltfContainerLoadingState.componentId].includes(componentId)) {
23
+ return false;
24
+ }
25
+ const [entityId] = EntityUtils.fromEntityId(message.entityId);
26
+ if (entityId < RESERVED_STATIC_ENTITIES) {
27
+ return false;
28
+ }
29
+ if (entityId < reservedLocalEntities) {
30
+ return false;
31
+ }
32
+ if (message.type === CrdtMessageType.DELETE_ENTITY) {
33
+ return true;
34
+ }
35
+ if (message.timestamp <= 1) {
36
+ return true;
37
+ }
38
+ const sync = SyncComponents.getOrNull(message.entityId);
39
+ if (!sync)
40
+ return false;
41
+ if (message.componentId && sync.componentIds.includes(message.componentId)) {
42
+ return true;
43
+ }
44
+ return false;
45
+ }
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbmV0d29yay10cmFuc3BvcnQvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0NBQXdDLENBQUE7QUFDNUUsT0FBTyxFQUNMLE1BQU0sRUFFTixtQkFBbUIsRUFDbkIsd0JBQXdCLEVBQ3hCLGNBQWMsRUFDZCxlQUFlLEVBQ2YsV0FBVyxFQUNYLHlCQUF5QixFQUMxQixNQUFNLFVBQVUsQ0FBQTtBQUVqQixPQUFPLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sR0FBRyxDQUFBO0FBRXBELE1BQU0sVUFBVSxZQUFZLENBQUMsQ0FBUztJQUNwQyxNQUFNLE1BQU0sR0FBRyxJQUFJLG1CQUFtQixFQUFFLENBQUE7SUFDeEMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN6QixPQUFPLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQTtBQUM1QixDQUFDO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBQyxPQUFvQixFQUFFLE9BQW1CO0lBQ3BFLE1BQU0sR0FBRyxHQUFHLElBQUksVUFBVSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUE7SUFDbEQsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7SUFDbEIsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDbkIsT0FBTyxHQUFHLENBQUE7QUFDWixDQUFDO0FBRUQsTUFBTSxVQUFVLG9CQUFvQixDQUFDLHFCQUE2QixFQUFFLEtBQXVCO0lBQ3pGLE9BQU8sTUFBTSxDQUFDLGlCQUFpQixDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQy9ELENBQUM7QUFFRCxNQUFNLFVBQVUsVUFBVSxDQUFDLE9BQWdEO0lBQ3pFLElBQUksQ0FBQyxTQUFTO1FBQUUsT0FBTyxLQUFLLENBQUE7SUFDNUIsTUFBTSxXQUFXLEdBQUksT0FBZSxDQUFDLFdBQVcsQ0FBQTtJQUNoRCxJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRTtRQUNsRyxPQUFPLEtBQUssQ0FBQTtLQUNiO0lBRUQsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBRTdELElBQUksUUFBUSxHQUFHLHdCQUF3QixFQUFFO1FBQ3ZDLE9BQU8sS0FBSyxDQUFBO0tBQ2I7SUFFRCxJQUFJLFFBQVEsR0FBRyxxQkFBcUIsRUFBRTtRQUNwQyxPQUFPLEtBQUssQ0FBQTtLQUNiO0lBR0QsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLGVBQWUsQ0FBQyxhQUFhLEVBQUU7UUFDbEQsT0FBTyxJQUFJLENBQUE7S0FDWjtJQUdELElBQUssT0FBZSxDQUFDLFNBQVMsSUFBSSxDQUFDLEVBQUU7UUFDbkMsT0FBTyxJQUFJLENBQUE7S0FDWjtJQUVELE1BQU0sSUFBSSxHQUFHLGNBQWMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQ3ZELElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTyxLQUFLLENBQUE7SUFFdkIsSUFBSyxPQUFlLENBQUMsV0FBVyxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFFLE9BQWUsQ0FBQyxXQUFXLENBQUMsRUFBRTtRQUM1RixPQUFPLElBQUksQ0FBQTtLQUNaO0lBRUQsT0FBTyxLQUFLLENBQUE7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVhZFdyaXRlQnl0ZUJ1ZmZlciB9IGZyb20gJ0BkY2wvZWNzL2Rpc3Qvc2VyaWFsaXphdGlvbi9CeXRlQnVmZmVyJ1xuaW1wb3J0IHtcbiAgZW5naW5lLFxuICBUcmFuc3BvcnRNZXNzYWdlLFxuICBQb2ludGVyRXZlbnRzUmVzdWx0LFxuICBSRVNFUlZFRF9TVEFUSUNfRU5USVRJRVMsXG4gIFN5bmNDb21wb25lbnRzLFxuICBDcmR0TWVzc2FnZVR5cGUsXG4gIEVudGl0eVV0aWxzLFxuICBHbHRmQ29udGFpbmVyTG9hZGluZ1N0YXRlXG59IGZyb20gJ0BkY2wvZWNzJ1xuaW1wb3J0IHsgTWVzc2FnZVR5cGUgfSBmcm9tICcuL3R5cGVzJ1xuaW1wb3J0IHsgY29ubmVjdGVkLCByZXNlcnZlZExvY2FsRW50aXRpZXMgfSBmcm9tICcuJ1xuXG5leHBvcnQgZnVuY3Rpb24gZW5jb2RlU3RyaW5nKHM6IHN0cmluZyk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBidWZmZXIgPSBuZXcgUmVhZFdyaXRlQnl0ZUJ1ZmZlcigpXG4gIGJ1ZmZlci53cml0ZVV0ZjhTdHJpbmcocylcbiAgcmV0dXJuIGJ1ZmZlci5yZWFkQnVmZmVyKClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyYWZ0TWVzc2FnZShtc2dUeXBlOiBNZXNzYWdlVHlwZSwgcGF5bG9hZDogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBtc2cgPSBuZXcgVWludDhBcnJheShwYXlsb2FkLmJ5dGVMZW5ndGggKyAxKVxuICBtc2cuc2V0KFttc2dUeXBlXSlcbiAgbXNnLnNldChwYXlsb2FkLCAxKVxuICByZXR1cm4gbXNnXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOZXR3b3JrTWFuYWdlcihyZXNlcnZlZExvY2FsRW50aXRpZXM6IG51bWJlciwgcmFuZ2U6IFtudW1iZXIsIG51bWJlcl0pIHtcbiAgcmV0dXJuIGVuZ2luZS5hZGROZXR3b3JrTWFuYWdlcihyZXNlcnZlZExvY2FsRW50aXRpZXMsIHJhbmdlKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc3luY0ZpbHRlcihtZXNzYWdlOiBPbWl0PFRyYW5zcG9ydE1lc3NhZ2UsICdtZXNzYWdlQnVmZmVyJz4pIHtcbiAgaWYgKCFjb25uZWN0ZWQpIHJldHVybiBmYWxzZVxuICBjb25zdCBjb21wb25lbnRJZCA9IChtZXNzYWdlIGFzIGFueSkuY29tcG9uZW50SWRcbiAgaWYgKFtQb2ludGVyRXZlbnRzUmVzdWx0LmNvbXBvbmVudElkLCBHbHRmQ29udGFpbmVyTG9hZGluZ1N0YXRlLmNvbXBvbmVudElkXS5pbmNsdWRlcyhjb21wb25lbnRJZCkpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGNvbnN0IFtlbnRpdHlJZF0gPSBFbnRpdHlVdGlscy5mcm9tRW50aXR5SWQobWVzc2FnZS5lbnRpdHlJZClcbiAgLy8gZmlsdGVyIG1lc3NhZ2VzIGZyb20gcmVzZXJ2ZWQgZW50aXRpZXMuXG4gIGlmIChlbnRpdHlJZCA8IFJFU0VSVkVEX1NUQVRJQ19FTlRJVElFUykge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG5cbiAgaWYgKGVudGl0eUlkIDwgcmVzZXJ2ZWRMb2NhbEVudGl0aWVzKSB7XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICAvLyBOZXR3b3JrIEVudGl0eSBBbHdheXNcbiAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gQ3JkdE1lc3NhZ2VUeXBlLkRFTEVURV9FTlRJVFkpIHtcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgLy8gVEJEOiBGaXJzdCBjb21wb25lbnRcbiAgaWYgKChtZXNzYWdlIGFzIGFueSkudGltZXN0YW1wIDw9IDEpIHtcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgY29uc3Qgc3luYyA9IFN5bmNDb21wb25lbnRzLmdldE9yTnVsbChtZXNzYWdlLmVudGl0eUlkKVxuICBpZiAoIXN5bmMpIHJldHVybiBmYWxzZVxuXG4gIGlmICgobWVzc2FnZSBhcyBhbnkpLmNvbXBvbmVudElkICYmIHN5bmMuY29tcG9uZW50SWRzLmluY2x1ZGVzKChtZXNzYWdlIGFzIGFueSkuY29tcG9uZW50SWQpKSB7XG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIHJldHVybiBmYWxzZVxufVxuIl19
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dcl/sdk",
3
3
  "description": "",
4
- "version": "7.3.15-6200631111.commit-2a2ff73",
4
+ "version": "7.3.15-6201308535.commit-dd17bb7",
5
5
  "author": "Decentraland",
6
6
  "dependencies": {
7
- "@dcl/ecs": "7.3.15-6200631111.commit-2a2ff73",
7
+ "@dcl/ecs": "7.3.15-6201308535.commit-dd17bb7",
8
8
  "@dcl/ecs-math": "2.0.2",
9
9
  "@dcl/explorer": "1.0.143989-20230907142850.commit-0c0a775",
10
- "@dcl/js-runtime": "7.3.15-6200631111.commit-2a2ff73",
11
- "@dcl/react-ecs": "7.3.15-6200631111.commit-2a2ff73",
12
- "@dcl/sdk-commands": "7.3.15-6200631111.commit-2a2ff73"
10
+ "@dcl/js-runtime": "7.3.15-6201308535.commit-dd17bb7",
11
+ "@dcl/react-ecs": "7.3.15-6201308535.commit-dd17bb7",
12
+ "@dcl/sdk-commands": "7.3.15-6201308535.commit-dd17bb7"
13
13
  },
14
14
  "keywords": [],
15
15
  "license": "Apache-2.0",
@@ -34,5 +34,5 @@
34
34
  },
35
35
  "types": "./index.d.ts",
36
36
  "typings": "./index.d.ts",
37
- "commit": "2a2ff73474b7ed4b42273a2b59bd94620668ca65"
37
+ "commit": "dd17bb77900cab91f1a031bffbc9e9e20697902a"
38
38
  }
@@ -0,0 +1,40 @@
1
+ import { IEngine, CrdtMessage, CrdtMessageType } from '@dcl/ecs'
2
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer'
3
+ import { readMessage } from '@dcl/ecs/dist/serialization/crdt/message'
4
+
5
+ export function* serializeCrdtMessages(prefix: string, data: Uint8Array, engine: IEngine) {
6
+ const buffer = new ReadWriteByteBuffer(data)
7
+
8
+ let message: CrdtMessage | null
9
+
10
+ while ((message = readMessage(buffer))) {
11
+ const ent = `0x${message.entityId.toString(16)}`
12
+ const preface = `${prefix}: ${CrdtMessageType[message.type]} e=${ent}`
13
+ if (message.type === CrdtMessageType.DELETE_ENTITY) {
14
+ yield `${preface}`
15
+ }
16
+
17
+ if (
18
+ message.type === CrdtMessageType.PUT_COMPONENT ||
19
+ message.type === CrdtMessageType.DELETE_COMPONENT ||
20
+ message.type === CrdtMessageType.APPEND_VALUE
21
+ ) {
22
+ const { componentId, timestamp } = message
23
+ const data = 'data' in message ? message.data : undefined
24
+
25
+ try {
26
+ const c = engine.getComponent(componentId)
27
+
28
+ yield `${preface} c=${c.componentName} t=${timestamp} data=${JSON.stringify(
29
+ (data && c.schema.deserialize(new ReadWriteByteBuffer(data))) || null
30
+ )}`
31
+ } catch {
32
+ yield `${preface} c=${componentId} t=${timestamp} data=?`
33
+ }
34
+ } else if (message.type === CrdtMessageType.DELETE_ENTITY) {
35
+ yield preface
36
+ } else {
37
+ yield `${preface} Unknown CrdtMessageType`
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,74 @@
1
+ import { craftMessage, createNetworkManager, encodeString, syncFilter } from './utils'
2
+ import { Transport, engine } from '@dcl/ecs'
3
+ import { getHeaders } from '~system/SignedFetch'
4
+
5
+ import { MessageType, NetworkManager, Socket } from './types'
6
+
7
+ export type ClientTransportConfig = {
8
+ serverUrl: string
9
+ }
10
+
11
+ export async function createClientTransport({ serverUrl }: ClientTransportConfig): Promise<NetworkManager> {
12
+ const messagesToProcess: Uint8Array[] = []
13
+
14
+ return new Promise<NetworkManager>((resolve, reject) => {
15
+ try {
16
+ const ws = new WebSocket(serverUrl) as Socket
17
+ ws.binaryType = 'arraybuffer'
18
+
19
+ ws.onopen = async () => {
20
+ console.log('WS Server Sync connected')
21
+ const { headers } = await getHeaders({ url: serverUrl, init: { headers: {} } })
22
+ ws.send(craftMessage(MessageType.Auth, encodeString(JSON.stringify(headers))))
23
+
24
+ const transport: Transport = {
25
+ filter: syncFilter,
26
+ send: async (message: Uint8Array) => {
27
+ if (ws.readyState === WebSocket.OPEN) {
28
+ ws.send(craftMessage(MessageType.Crdt, message))
29
+ }
30
+ if (messagesToProcess && messagesToProcess.length) {
31
+ if (transport.onmessage) {
32
+ for (const byteArray of messagesToProcess) {
33
+ transport.onmessage(byteArray)
34
+ }
35
+ }
36
+ }
37
+ messagesToProcess.length = 0
38
+ }
39
+ }
40
+ engine.addTransport(transport)
41
+ }
42
+
43
+ ws.onmessage = (event) => {
44
+ if (event.data.byteLength) {
45
+ let offset = 0
46
+ const r = new Uint8Array(event.data)
47
+ const view = new DataView(r.buffer)
48
+ const msgType = view.getUint8(offset)
49
+ offset += 1
50
+
51
+ if (msgType === MessageType.Crdt) {
52
+ messagesToProcess.push(r.subarray(offset))
53
+ } else if (msgType === MessageType.Init) {
54
+ const start = view.getUint32(offset)
55
+ offset += 4
56
+ const size = view.getUint32(offset)
57
+ offset += 4
58
+ const localEntitiesReserved = view.getUint32(offset)
59
+ offset += 4
60
+ resolve(createNetworkManager(localEntitiesReserved, [start, start + size]))
61
+ messagesToProcess.push(r.subarray(offset))
62
+ }
63
+ }
64
+ }
65
+
66
+ ws.onerror = (e) => {
67
+ console.error(e)
68
+ reject(e)
69
+ }
70
+ } catch (err) {
71
+ reject(err)
72
+ }
73
+ })
74
+ }
@@ -0,0 +1,45 @@
1
+ import { isServer } from '~system/EngineApi'
2
+
3
+ import { NetworkManager, ServerTransportConfig } from './types'
4
+ import { Schemas, engine } from '@dcl/ecs'
5
+ import { createServerTransport } from './server'
6
+ import { ClientTransportConfig, createClientTransport } from './client'
7
+
8
+ export { NetworkManager } from './types'
9
+
10
+ export type NetworkTransportConfig = ClientTransportConfig & Partial<ServerTransportConfig>
11
+
12
+ export let connected = false
13
+
14
+ const DEFAULT_NETWORK_ENTITY_LIMIT_SERVER = 512
15
+ const DEFAULT_NETWORK_ENTITY_LIMIT_CLIENT = 100
16
+ const DEFAULT_RESERVED_LOCAL_ENTITIES = 2560
17
+
18
+ export let reservedLocalEntities: number
19
+ /**
20
+ * @alpha
21
+ * Connect to CRDT server
22
+ */
23
+ export async function createNetworkManager(config: NetworkTransportConfig): Promise<NetworkManager> {
24
+ if (connected) {
25
+ throw new Error('Transport is already created')
26
+ }
27
+
28
+ const serverConfig = {
29
+ networkEntitiesLimit: config.networkEntitiesLimit ?? {
30
+ serverLimit: DEFAULT_NETWORK_ENTITY_LIMIT_SERVER,
31
+ clientLimit: DEFAULT_NETWORK_ENTITY_LIMIT_CLIENT
32
+ },
33
+ reservedLocalEntities: config.reservedLocalEntities || DEFAULT_RESERVED_LOCAL_ENTITIES
34
+ }
35
+ reservedLocalEntities = serverConfig.reservedLocalEntities
36
+
37
+ const networkFactory =
38
+ isServer && (await isServer({})).isServer ? createServerTransport(serverConfig) : createClientTransport(config)
39
+ connected = true
40
+ return networkFactory
41
+ }
42
+
43
+ export const PlayersConnected = engine.defineComponent('chore:network:players', {
44
+ usersId: Schemas.Array(Schemas.String)
45
+ })
@@ -0,0 +1,66 @@
1
+ import { engine, SyncComponents, Transport } from '@dcl/ecs'
2
+ import { engineToCrdt } from './state'
3
+ import { syncFilter, createNetworkManager } from './utils'
4
+ import { NetworkManager, ServerTransportConfig } from './types'
5
+ import { PlayersConnected } from '.'
6
+
7
+ export async function createServerTransport(config: ServerTransportConfig): Promise<NetworkManager> {
8
+ const connectedClients = new Set<string>()
9
+ engine.addTransport({
10
+ send: async (message) => {
11
+ if (message.byteLength) {
12
+ globalThis.updateCRDTState(engineToCrdt(engine))
13
+ }
14
+ },
15
+ filter: syncFilter
16
+ })
17
+
18
+ let time = 0
19
+ function initialCrdtState(dt: number) {
20
+ time += dt
21
+ if (time >= 1) {
22
+ globalThis.updateCRDTState(engineToCrdt(engine))
23
+ engine.removeSystem(initialCrdtState)
24
+ }
25
+ }
26
+
27
+ engine.addSystem(initialCrdtState)
28
+ globalThis.registerScene(config, (event) => {
29
+ const { type } = event
30
+ if (type === 'open') {
31
+ const { clientId, client } = event
32
+ const transport: Transport = {
33
+ filter: (message) => {
34
+ if (!connectedClients.has(clientId)) return false
35
+ return syncFilter(message)
36
+ },
37
+ send: async (message) => {
38
+ if (message.byteLength > 0) {
39
+ await client.sendCrdtMessage(message)
40
+ }
41
+
42
+ if (transport.onmessage) {
43
+ const messages = client.getMessages()
44
+ for (const byteArray of messages) {
45
+ transport.onmessage(byteArray)
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ engine.addTransport(transport)
52
+ connectedClients.add(event.clientId)
53
+ } else if (type === 'close') {
54
+ connectedClients.delete(event.clientId)
55
+ }
56
+ PlayersConnected.createOrReplace(players, { usersId: [...connectedClients.values()].map(String) })
57
+ })
58
+
59
+ const networkEntityFactory = createNetworkManager(config.reservedLocalEntities, [
60
+ config.reservedLocalEntities,
61
+ config.reservedLocalEntities + config.networkEntitiesLimit.serverLimit
62
+ ])
63
+ const players = networkEntityFactory.addEntity()
64
+ SyncComponents.create(players, { componentIds: [PlayersConnected.componentId] })
65
+ return networkEntityFactory
66
+ }
@@ -0,0 +1,13 @@
1
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer'
2
+ import { IEngine, SyncComponents } from '@dcl/ecs'
3
+
4
+ export function engineToCrdt(engine: IEngine): Uint8Array {
5
+ const crdtBuffer = new ReadWriteByteBuffer()
6
+ const syncEntities = new Set(Array.from(engine.getEntitiesWith(SyncComponents)).map(($) => $[0]))
7
+
8
+ for (const itComponentDefinition of engine.componentsIter()) {
9
+ itComponentDefinition.dumpCrdtStateToBuffer(crdtBuffer, (entity) => syncEntities.has(entity))
10
+ }
11
+
12
+ return crdtBuffer.toBinary()
13
+ }
@@ -0,0 +1,41 @@
1
+ import { Entity, engine } from '@dcl/ecs'
2
+
3
+ export type Socket = WebSocket & {
4
+ binaryType: string
5
+ send(data: string | Uint8Array): void
6
+ }
7
+
8
+ export type NetworkManager = {
9
+ addEntity(theEngine: typeof engine): Entity
10
+ }
11
+
12
+ export enum MessageType {
13
+ Auth = 1,
14
+ Init = 2,
15
+ Crdt = 3
16
+ }
17
+
18
+ export type ServerTransportConfig = {
19
+ reservedLocalEntities: number
20
+ networkEntitiesLimit: {
21
+ serverLimit: number
22
+ clientLimit: number
23
+ }
24
+ }
25
+
26
+ declare global {
27
+ type ClientEvent =
28
+ | {
29
+ type: 'open'
30
+ clientId: string
31
+ client: {
32
+ sendCrdtMessage(message: Uint8Array): Promise<void>
33
+ getMessages(): Uint8Array[]
34
+ }
35
+ }
36
+ | { type: 'close'; clientId: string }
37
+ // eslint-disable-next-line no-var
38
+ var updateCRDTState: (crdt: Uint8Array) => void
39
+ // eslint-disable-next-line no-var
40
+ var registerScene: (serverConfig: ServerTransportConfig, fn: (event: ClientEvent) => void) => void
41
+ }
@@ -0,0 +1,67 @@
1
+ import { ReadWriteByteBuffer } from '@dcl/ecs/dist/serialization/ByteBuffer'
2
+ import {
3
+ engine,
4
+ TransportMessage,
5
+ PointerEventsResult,
6
+ RESERVED_STATIC_ENTITIES,
7
+ SyncComponents,
8
+ CrdtMessageType,
9
+ EntityUtils,
10
+ GltfContainerLoadingState
11
+ } from '@dcl/ecs'
12
+ import { MessageType } from './types'
13
+ import { connected, reservedLocalEntities } from '.'
14
+
15
+ export function encodeString(s: string): Uint8Array {
16
+ const buffer = new ReadWriteByteBuffer()
17
+ buffer.writeUtf8String(s)
18
+ return buffer.readBuffer()
19
+ }
20
+
21
+ export function craftMessage(msgType: MessageType, payload: Uint8Array): Uint8Array {
22
+ const msg = new Uint8Array(payload.byteLength + 1)
23
+ msg.set([msgType])
24
+ msg.set(payload, 1)
25
+ return msg
26
+ }
27
+
28
+ export function createNetworkManager(reservedLocalEntities: number, range: [number, number]) {
29
+ return engine.addNetworkManager(reservedLocalEntities, range)
30
+ }
31
+
32
+ export function syncFilter(message: Omit<TransportMessage, 'messageBuffer'>) {
33
+ if (!connected) return false
34
+ const componentId = (message as any).componentId
35
+ if ([PointerEventsResult.componentId, GltfContainerLoadingState.componentId].includes(componentId)) {
36
+ return false
37
+ }
38
+
39
+ const [entityId] = EntityUtils.fromEntityId(message.entityId)
40
+ // filter messages from reserved entities.
41
+ if (entityId < RESERVED_STATIC_ENTITIES) {
42
+ return false
43
+ }
44
+
45
+ if (entityId < reservedLocalEntities) {
46
+ return false
47
+ }
48
+
49
+ // Network Entity Always
50
+ if (message.type === CrdtMessageType.DELETE_ENTITY) {
51
+ return true
52
+ }
53
+
54
+ // TBD: First component
55
+ if ((message as any).timestamp <= 1) {
56
+ return true
57
+ }
58
+
59
+ const sync = SyncComponents.getOrNull(message.entityId)
60
+ if (!sync) return false
61
+
62
+ if ((message as any).componentId && sync.componentIds.includes((message as any).componentId)) {
63
+ return true
64
+ }
65
+
66
+ return false
67
+ }