@dcl/ecs 7.0.6-3823801200.commit-32470bd → 7.0.6-3830539086.commit-6152fbd
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/dist/engine/entity.d.ts +35 -6
- package/dist/engine/entity.js +121 -32
- package/dist/engine/index.js +6 -9
- package/dist/engine/types.d.ts +8 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime/types.d.ts +0 -1
- package/dist/serialization/crdt/deleteComponent.d.ts +11 -0
- package/dist/serialization/crdt/deleteComponent.js +45 -0
- package/dist/serialization/crdt/deleteEntity.d.ts +8 -0
- package/dist/serialization/crdt/deleteEntity.js +28 -0
- package/dist/serialization/crdt/index.d.ts +32 -0
- package/dist/serialization/crdt/index.js +70 -0
- package/dist/serialization/crdt/message.d.ts +3 -0
- package/dist/serialization/crdt/message.js +17 -0
- package/dist/serialization/crdt/putComponent.d.ts +13 -0
- package/dist/serialization/crdt/putComponent.js +44 -0
- package/dist/serialization/crdt/types.d.ts +53 -0
- package/dist/serialization/crdt/types.js +10 -0
- package/dist/systems/crdt/index.d.ts +5 -5
- package/dist/systems/crdt/index.js +189 -72
- package/dist/systems/crdt/types.d.ts +2 -8
- package/dist/systems/events.js +2 -1
- package/package.json +3 -3
- package/dist/serialization/crdt/componentOperation.d.ts +0 -31
- package/dist/serialization/crdt/componentOperation.js +0 -47
- package/dist/serialization/wireMessage.d.ts +0 -41
- package/dist/serialization/wireMessage.js +0 -56
package/dist/engine/entity.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare const AMOUNT_VERSION_AVAILABLE: number;
|
|
|
17
17
|
* Convertion from its compound numbers to entity:
|
|
18
18
|
* entity = (entityNumber & MAX_U16) | ((entityVersion & MAX_U16) << 16)
|
|
19
19
|
*/
|
|
20
|
-
export declare type Entity =
|
|
20
|
+
export declare type Entity = number & {
|
|
21
21
|
__entity_type: '';
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
@@ -28,12 +28,41 @@ export declare const RESERVED_STATIC_ENTITIES = 512;
|
|
|
28
28
|
* @public
|
|
29
29
|
*/
|
|
30
30
|
export declare const MAX_ENTITY_NUMBER = 65535;
|
|
31
|
-
export declare
|
|
31
|
+
export declare namespace EntityUtils {
|
|
32
|
+
/**
|
|
33
|
+
* @returns [entityNumber, entityVersion]
|
|
34
|
+
*/
|
|
35
|
+
function fromEntityId(entityId: Entity): [number, number];
|
|
36
|
+
/**
|
|
37
|
+
* @returns compound number from entityNumber and entityVerison
|
|
38
|
+
*/
|
|
39
|
+
function toEntityId(entityNumber: number, entityVersion: number): Entity;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export declare enum EntityState {
|
|
45
|
+
Unknown = 0,
|
|
46
|
+
/**
|
|
47
|
+
* The entity was generated and added to the usedEntities set
|
|
48
|
+
*/
|
|
49
|
+
UsedEntity = 1,
|
|
50
|
+
/**
|
|
51
|
+
* The entity was removed from current engine or remotely
|
|
52
|
+
*/
|
|
53
|
+
Removed = 2,
|
|
54
|
+
/**
|
|
55
|
+
* The entity is reserved number.
|
|
56
|
+
*/
|
|
57
|
+
Reserved = 3
|
|
58
|
+
}
|
|
59
|
+
export declare type EntityContainer = {
|
|
32
60
|
generateEntity(): Entity;
|
|
33
61
|
removeEntity(entity: Entity): boolean;
|
|
34
|
-
|
|
62
|
+
getEntityState(entity: Entity): EntityState;
|
|
35
63
|
getExistingEntities(): Set<Entity>;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
64
|
+
releaseRemovedEntities(): Entity[];
|
|
65
|
+
updateRemovedEntity(entity: Entity): boolean;
|
|
66
|
+
updateUsedEntity(entity: Entity): boolean;
|
|
39
67
|
};
|
|
68
|
+
export declare function EntityContainer(): EntityContainer;
|
package/dist/engine/entity.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createGSet } from '@dcl/crdt/dist/gset';
|
|
1
2
|
export const MAX_U16 = 0xffff;
|
|
2
3
|
export const MASK_UPPER_16_ON_32 = 0xffff0000;
|
|
3
4
|
export const AMOUNT_VERSION_AVAILABLE = MAX_U16 + 1;
|
|
5
|
+
// This type matches with @dcl/crdt entity type.
|
|
4
6
|
/**
|
|
5
7
|
* @public This first 512 entities are reserved by the renderer
|
|
6
8
|
*/
|
|
@@ -9,64 +11,151 @@ export const RESERVED_STATIC_ENTITIES = 512;
|
|
|
9
11
|
* @public
|
|
10
12
|
*/
|
|
11
13
|
export const MAX_ENTITY_NUMBER = MAX_U16;
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
export var EntityUtils;
|
|
15
|
+
(function (EntityUtils) {
|
|
16
|
+
/**
|
|
17
|
+
* @returns [entityNumber, entityVersion]
|
|
18
|
+
*/
|
|
19
|
+
function fromEntityId(entityId) {
|
|
20
|
+
return [
|
|
21
|
+
(entityId & MAX_U16) >>> 0,
|
|
22
|
+
(((entityId & MASK_UPPER_16_ON_32) >> 16) & MAX_U16) >>> 0
|
|
23
|
+
];
|
|
21
24
|
}
|
|
22
|
-
|
|
25
|
+
EntityUtils.fromEntityId = fromEntityId;
|
|
26
|
+
/**
|
|
27
|
+
* @returns compound number from entityNumber and entityVerison
|
|
28
|
+
*/
|
|
29
|
+
function toEntityId(entityNumber, entityVersion) {
|
|
23
30
|
return (((entityNumber & MAX_U16) | ((entityVersion & MAX_U16) << 16)) >>>
|
|
24
31
|
0);
|
|
25
32
|
}
|
|
33
|
+
EntityUtils.toEntityId = toEntityId;
|
|
34
|
+
})(EntityUtils || (EntityUtils = {}));
|
|
35
|
+
/**
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export var EntityState;
|
|
39
|
+
(function (EntityState) {
|
|
40
|
+
EntityState[EntityState["Unknown"] = 0] = "Unknown";
|
|
41
|
+
/**
|
|
42
|
+
* The entity was generated and added to the usedEntities set
|
|
43
|
+
*/
|
|
44
|
+
EntityState[EntityState["UsedEntity"] = 1] = "UsedEntity";
|
|
45
|
+
/**
|
|
46
|
+
* The entity was removed from current engine or remotely
|
|
47
|
+
*/
|
|
48
|
+
EntityState[EntityState["Removed"] = 2] = "Removed";
|
|
49
|
+
/**
|
|
50
|
+
* The entity is reserved number.
|
|
51
|
+
*/
|
|
52
|
+
EntityState[EntityState["Reserved"] = 3] = "Reserved";
|
|
53
|
+
})(EntityState || (EntityState = {}));
|
|
54
|
+
export function EntityContainer() {
|
|
55
|
+
let entityCounter = RESERVED_STATIC_ENTITIES;
|
|
56
|
+
const usedEntities = new Set();
|
|
57
|
+
let toRemoveEntities = [];
|
|
58
|
+
const removedEntities = createGSet();
|
|
26
59
|
function generateNewEntity() {
|
|
27
60
|
if (entityCounter > MAX_ENTITY_NUMBER - 1) {
|
|
28
61
|
throw new Error(`It fails trying to generate an entity out of range ${MAX_ENTITY_NUMBER}.`);
|
|
29
62
|
}
|
|
30
|
-
const
|
|
63
|
+
const entityNumber = entityCounter++;
|
|
64
|
+
const entityVersion = removedEntities.getMap().has(entityNumber)
|
|
65
|
+
? removedEntities.getMap().get(entityNumber) + 1
|
|
66
|
+
: 0;
|
|
67
|
+
const entity = EntityUtils.toEntityId(entityNumber, entityVersion);
|
|
31
68
|
usedEntities.add(entity);
|
|
32
69
|
return entity;
|
|
33
70
|
}
|
|
34
71
|
function generateEntity() {
|
|
72
|
+
// If all entities until `entityCounter` are being used, we need to generate another one
|
|
35
73
|
if (usedEntities.size + RESERVED_STATIC_ENTITIES >= entityCounter) {
|
|
36
74
|
return generateNewEntity();
|
|
37
75
|
}
|
|
38
|
-
for (const [number, version] of removedEntities) {
|
|
76
|
+
for (const [number, version] of removedEntities.getMap()) {
|
|
39
77
|
if (version < MAX_U16) {
|
|
40
|
-
const entity =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
78
|
+
const entity = EntityUtils.toEntityId(number, version + 1);
|
|
79
|
+
// If the entity is not being used, we can re-use it
|
|
80
|
+
// If the entity was removed in this tick, we're not counting for the usedEntities, but we have it in the toRemoveEntityArray
|
|
81
|
+
if (!usedEntities.has(entity) && !toRemoveEntities.includes(entity)) {
|
|
82
|
+
usedEntities.add(entity);
|
|
83
|
+
return entity;
|
|
84
|
+
}
|
|
44
85
|
}
|
|
45
86
|
}
|
|
46
87
|
return generateNewEntity();
|
|
47
88
|
}
|
|
48
89
|
function removeEntity(entity) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
90
|
+
if (entity < RESERVED_STATIC_ENTITIES)
|
|
91
|
+
return false;
|
|
92
|
+
if (usedEntities.has(entity)) {
|
|
93
|
+
usedEntities.delete(entity);
|
|
94
|
+
toRemoveEntities.push(entity);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
updateRemovedEntity(entity);
|
|
52
98
|
}
|
|
53
|
-
return
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
function releaseRemovedEntities() {
|
|
102
|
+
const arr = toRemoveEntities;
|
|
103
|
+
toRemoveEntities = [];
|
|
104
|
+
for (const entity of arr) {
|
|
105
|
+
const [n, v] = EntityUtils.fromEntityId(entity);
|
|
106
|
+
removedEntities.addTo(n, v);
|
|
107
|
+
}
|
|
108
|
+
return arr;
|
|
109
|
+
}
|
|
110
|
+
function updateRemovedEntity(entity) {
|
|
111
|
+
const [n, v] = EntityUtils.fromEntityId(entity);
|
|
112
|
+
// Update the removed entities map
|
|
113
|
+
removedEntities.addTo(n, v);
|
|
114
|
+
// Remove the usedEntities if exist
|
|
115
|
+
for (let i = 0; i <= v; i++) {
|
|
116
|
+
usedEntities.delete(EntityUtils.toEntityId(n, i));
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
function updateUsedEntity(entity) {
|
|
121
|
+
const [n, v] = EntityUtils.fromEntityId(entity);
|
|
122
|
+
const removedVersion = removedEntities.getMap().get(n);
|
|
123
|
+
if (removedVersion !== undefined && removedVersion >= v) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
// Update
|
|
127
|
+
if (v > 0) {
|
|
128
|
+
for (let i = 0; i <= v - 1; i++) {
|
|
129
|
+
usedEntities.delete(EntityUtils.toEntityId(n, i));
|
|
130
|
+
}
|
|
131
|
+
removedEntities.addTo(n, v - 1);
|
|
132
|
+
}
|
|
133
|
+
usedEntities.add(entity);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
function getEntityState(entity) {
|
|
137
|
+
const [n, v] = EntityUtils.fromEntityId(entity);
|
|
138
|
+
if (n < RESERVED_STATIC_ENTITIES) {
|
|
139
|
+
return EntityState.Reserved;
|
|
140
|
+
}
|
|
141
|
+
if (usedEntities.has(entity)) {
|
|
142
|
+
return EntityState.UsedEntity;
|
|
143
|
+
}
|
|
144
|
+
const removedVersion = removedEntities.getMap().get(n);
|
|
145
|
+
if (removedVersion !== undefined && removedVersion >= v) {
|
|
146
|
+
return EntityState.Removed;
|
|
147
|
+
}
|
|
148
|
+
return EntityState.Unknown;
|
|
54
149
|
}
|
|
55
150
|
return {
|
|
56
|
-
generateEntity
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
removeEntity(entity) {
|
|
60
|
-
return removeEntity(entity);
|
|
61
|
-
},
|
|
62
|
-
entityExists(entity) {
|
|
63
|
-
return entity < RESERVED_STATIC_ENTITIES || usedEntities.has(entity);
|
|
64
|
-
},
|
|
151
|
+
generateEntity,
|
|
152
|
+
removeEntity,
|
|
65
153
|
getExistingEntities() {
|
|
66
154
|
return new Set(usedEntities);
|
|
67
155
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
156
|
+
getEntityState,
|
|
157
|
+
releaseRemovedEntities,
|
|
158
|
+
updateRemovedEntity,
|
|
159
|
+
updateUsedEntity
|
|
71
160
|
};
|
|
72
161
|
}
|
package/dist/engine/index.js
CHANGED
|
@@ -22,9 +22,6 @@ function preEngine() {
|
|
|
22
22
|
const entity = entityContainer.generateEntity();
|
|
23
23
|
return entity;
|
|
24
24
|
}
|
|
25
|
-
function entityExists(entity) {
|
|
26
|
-
return entityContainer.entityExists(entity);
|
|
27
|
-
}
|
|
28
25
|
function removeEntity(entity) {
|
|
29
26
|
for (const [, component] of componentsDefinition) {
|
|
30
27
|
if (component.has(entity)) {
|
|
@@ -131,8 +128,6 @@ function preEngine() {
|
|
|
131
128
|
}
|
|
132
129
|
}
|
|
133
130
|
return {
|
|
134
|
-
entityExists,
|
|
135
|
-
componentsDefinition,
|
|
136
131
|
addEntity,
|
|
137
132
|
removeEntity,
|
|
138
133
|
addSystem,
|
|
@@ -146,6 +141,7 @@ function preEngine() {
|
|
|
146
141
|
removeComponentDefinition,
|
|
147
142
|
removeEntityWithChildren,
|
|
148
143
|
registerCustomComponent,
|
|
144
|
+
entityContainer,
|
|
149
145
|
componentsIter
|
|
150
146
|
};
|
|
151
147
|
}
|
|
@@ -162,8 +158,9 @@ export function Engine(options) {
|
|
|
162
158
|
checkNotThenable(ret, `A system (${system.name || 'anonymous'}) returned a thenable. Systems cannot be async functions. Documentation: https://dcl.gg/sdk/sync-systems`);
|
|
163
159
|
}
|
|
164
160
|
const dirtyEntities = crdtSystem.updateState();
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
const deletedEntites = engine.entityContainer.releaseRemovedEntities();
|
|
162
|
+
await crdtSystem.sendMessages(dirtyEntities, deletedEntites);
|
|
163
|
+
for (const definition of engine.componentsIter()) {
|
|
167
164
|
definition.clearDirty();
|
|
168
165
|
}
|
|
169
166
|
}
|
|
@@ -185,9 +182,9 @@ export function Engine(options) {
|
|
|
185
182
|
RootEntity: 0,
|
|
186
183
|
PlayerEntity: 1,
|
|
187
184
|
CameraEntity: 2,
|
|
188
|
-
|
|
185
|
+
getEntityState: engine.entityContainer.getEntityState,
|
|
189
186
|
addTransport: crdtSystem.addTransport,
|
|
190
187
|
getCrdtState: crdtSystem.getCrdt,
|
|
191
|
-
|
|
188
|
+
entityContainer: engine.entityContainer
|
|
192
189
|
};
|
|
193
190
|
}
|
package/dist/engine/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ISchema } from '../schemas/ISchema';
|
|
|
2
2
|
import { MapResult, Spec } from '../schemas/Map';
|
|
3
3
|
import { Transport } from '../systems/crdt/types';
|
|
4
4
|
import { ComponentDefinition } from './component';
|
|
5
|
-
import { Entity } from './entity';
|
|
5
|
+
import { Entity, EntityContainer, EntityState } from './entity';
|
|
6
6
|
import { ReadonlyComponentSchema } from './readonly';
|
|
7
7
|
import { SystemFn } from './systems';
|
|
8
8
|
export { ISchema } from '../schemas/ISchema';
|
|
@@ -53,11 +53,11 @@ export declare type IEngine = {
|
|
|
53
53
|
*/
|
|
54
54
|
removeEntityWithChildren(firstEntity: Entity): void;
|
|
55
55
|
/**
|
|
56
|
-
* Check
|
|
56
|
+
* Check the state of an entityin the engine
|
|
57
57
|
* @param entity - the entity to validate
|
|
58
|
-
* @returns
|
|
58
|
+
* @returns known enum value
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
getEntityState(entity: Entity): EntityState;
|
|
61
61
|
/**
|
|
62
62
|
* Add the system to the engine. It will be called every tick updated.
|
|
63
63
|
* @param system - function that receives the delta time between last tick and current one.
|
|
@@ -173,6 +173,10 @@ export declare type IEngine = {
|
|
|
173
173
|
* @param transport - transport which changes its onmessage to process CRDT messages
|
|
174
174
|
*/
|
|
175
175
|
addTransport(transport: Transport): void;
|
|
176
|
+
/**
|
|
177
|
+
* Entity continaer
|
|
178
|
+
*/
|
|
179
|
+
entityContainer: EntityContainer;
|
|
176
180
|
/**
|
|
177
181
|
* Iterator of registered components
|
|
178
182
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export declare const MeshRenderer: import("./components/types").MeshRendererComp
|
|
|
14
14
|
export declare const MeshCollider: import("./components/types").MeshColliderComponentDefinitionExtended;
|
|
15
15
|
export * from './components/generated/global.gen';
|
|
16
16
|
export * from './components/generated/types.gen';
|
|
17
|
+
export * from './serialization/crdt';
|
package/dist/index.js
CHANGED
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export type { SystemFn } from '../engine/systems';
|
|
2
2
|
export type { TransportMessage, ReceiveMessage, Transport } from '../systems/crdt/types';
|
|
3
|
-
export type { WireMessage } from '../serialization/wireMessage';
|
|
4
3
|
export { TransformType, TransformComponent } from '../components/legacy/Transform';
|
|
5
4
|
export * from '../engine/component';
|
|
6
5
|
export * from '../schemas/typing';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Entity } from '../../engine/entity';
|
|
2
|
+
import { ByteBuffer } from '../ByteBuffer';
|
|
3
|
+
import { DeleteComponentMessage } from './types';
|
|
4
|
+
export declare namespace DeleteComponent {
|
|
5
|
+
const MESSAGE_HEADER_LENGTH = 20;
|
|
6
|
+
/**
|
|
7
|
+
* Write DeleteComponent message
|
|
8
|
+
*/
|
|
9
|
+
function write(entity: Entity, componentId: number, timestamp: number, buf: ByteBuffer): void;
|
|
10
|
+
function read(buf: ByteBuffer): DeleteComponentMessage | null;
|
|
11
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import CrdtMessageProtocol from '.';
|
|
2
|
+
import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
|
|
3
|
+
export var DeleteComponent;
|
|
4
|
+
(function (DeleteComponent) {
|
|
5
|
+
// TODO: change timestamp to 32 bit and remove buffer length (-8 bytes)
|
|
6
|
+
DeleteComponent.MESSAGE_HEADER_LENGTH = 20;
|
|
7
|
+
/**
|
|
8
|
+
* Write DeleteComponent message
|
|
9
|
+
*/
|
|
10
|
+
function write(entity, componentId, timestamp, buf) {
|
|
11
|
+
// reserve the beginning
|
|
12
|
+
const messageLength = CRDT_MESSAGE_HEADER_LENGTH + DeleteComponent.MESSAGE_HEADER_LENGTH;
|
|
13
|
+
const startMessageOffset = buf.incrementWriteOffset(messageLength);
|
|
14
|
+
// Write CrdtMessage header
|
|
15
|
+
buf.setUint32(startMessageOffset, messageLength);
|
|
16
|
+
buf.setUint32(startMessageOffset + 4, CrdtMessageType.DELETE_COMPONENT);
|
|
17
|
+
// Write ComponentOperation header
|
|
18
|
+
buf.setUint32(startMessageOffset + 8, entity);
|
|
19
|
+
buf.setUint32(startMessageOffset + 12, componentId);
|
|
20
|
+
// TODO: change timestamp to 32bit (-4 bytes)
|
|
21
|
+
buf.setUint64(startMessageOffset + 16, BigInt(timestamp));
|
|
22
|
+
// TODO: remove buffer length (-4 bytes)
|
|
23
|
+
buf.setUint32(startMessageOffset + 24, 0);
|
|
24
|
+
}
|
|
25
|
+
DeleteComponent.write = write;
|
|
26
|
+
function read(buf) {
|
|
27
|
+
const header = CrdtMessageProtocol.readHeader(buf);
|
|
28
|
+
if (!header) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (header.type !== CrdtMessageType.DELETE_COMPONENT) {
|
|
32
|
+
throw new Error('DeleteComponentOperation tried to read another message type.');
|
|
33
|
+
}
|
|
34
|
+
const msg = {
|
|
35
|
+
...header,
|
|
36
|
+
entityId: buf.readUint32(),
|
|
37
|
+
componentId: buf.readInt32(),
|
|
38
|
+
timestamp: Number(buf.readUint64())
|
|
39
|
+
};
|
|
40
|
+
// TODO: remove buffer length
|
|
41
|
+
buf.incrementReadOffset(4);
|
|
42
|
+
return msg;
|
|
43
|
+
}
|
|
44
|
+
DeleteComponent.read = read;
|
|
45
|
+
})(DeleteComponent || (DeleteComponent = {}));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Entity } from '../../engine/entity';
|
|
2
|
+
import { ByteBuffer } from '../ByteBuffer';
|
|
3
|
+
import { DeleteEntityMessage } from './types';
|
|
4
|
+
export declare namespace DeleteEntity {
|
|
5
|
+
const MESSAGE_HEADER_LENGTH = 4;
|
|
6
|
+
function write(entity: Entity, buf: ByteBuffer): void;
|
|
7
|
+
function read(buf: ByteBuffer): DeleteEntityMessage | null;
|
|
8
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import CrdtMessageProtocol from '.';
|
|
2
|
+
import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
|
|
3
|
+
export var DeleteEntity;
|
|
4
|
+
(function (DeleteEntity) {
|
|
5
|
+
DeleteEntity.MESSAGE_HEADER_LENGTH = 4;
|
|
6
|
+
function write(entity, buf) {
|
|
7
|
+
// Write CrdtMessage header
|
|
8
|
+
buf.writeUint32(CRDT_MESSAGE_HEADER_LENGTH + 4);
|
|
9
|
+
buf.writeUint32(CrdtMessageType.DELETE_ENTITY);
|
|
10
|
+
// body
|
|
11
|
+
buf.writeUint32(entity);
|
|
12
|
+
}
|
|
13
|
+
DeleteEntity.write = write;
|
|
14
|
+
function read(buf) {
|
|
15
|
+
const header = CrdtMessageProtocol.readHeader(buf);
|
|
16
|
+
if (!header) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
if (header.type !== CrdtMessageType.DELETE_ENTITY) {
|
|
20
|
+
throw new Error('DeleteComponentOperation tried to read another message type.');
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
...header,
|
|
24
|
+
entityId: buf.readUint32()
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
DeleteEntity.read = read;
|
|
28
|
+
})(DeleteEntity || (DeleteEntity = {}));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ByteBuffer } from '../ByteBuffer';
|
|
2
|
+
import { CrdtMessageHeader } from './types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
export * from './deleteComponent';
|
|
5
|
+
export * from './putComponent';
|
|
6
|
+
export * from './deleteEntity';
|
|
7
|
+
export declare namespace CrdtMessageProtocol {
|
|
8
|
+
/**
|
|
9
|
+
* Validate if the message incoming is completed
|
|
10
|
+
* @param buf - ByteBuffer
|
|
11
|
+
*/
|
|
12
|
+
function validate(buf: ByteBuffer): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Get the current header, consuming the bytes involved.
|
|
15
|
+
* @param buf - ByteBuffer
|
|
16
|
+
* @returns header or null if there is no validated message
|
|
17
|
+
*/
|
|
18
|
+
function readHeader(buf: ByteBuffer): CrdtMessageHeader | null;
|
|
19
|
+
/**
|
|
20
|
+
* Get the current header, without consuming the bytes involved.
|
|
21
|
+
* @param buf - ByteBuffer
|
|
22
|
+
* @returns header or null if there is no validated message
|
|
23
|
+
*/
|
|
24
|
+
function getHeader(buf: ByteBuffer): CrdtMessageHeader | null;
|
|
25
|
+
/**
|
|
26
|
+
* Consume the incoming message without processing it.
|
|
27
|
+
* @param buf - ByteBuffer
|
|
28
|
+
* @returns true in case of success or false if there is no valid message.
|
|
29
|
+
*/
|
|
30
|
+
function consumeMessage(buf: ByteBuffer): boolean;
|
|
31
|
+
}
|
|
32
|
+
export default CrdtMessageProtocol;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { CRDT_MESSAGE_HEADER_LENGTH } from './types';
|
|
2
|
+
export * from './types';
|
|
3
|
+
export * from './deleteComponent';
|
|
4
|
+
export * from './putComponent';
|
|
5
|
+
export * from './deleteEntity';
|
|
6
|
+
export var CrdtMessageProtocol;
|
|
7
|
+
(function (CrdtMessageProtocol) {
|
|
8
|
+
/**
|
|
9
|
+
* Validate if the message incoming is completed
|
|
10
|
+
* @param buf - ByteBuffer
|
|
11
|
+
*/
|
|
12
|
+
function validate(buf) {
|
|
13
|
+
const rem = buf.remainingBytes();
|
|
14
|
+
if (rem < CRDT_MESSAGE_HEADER_LENGTH) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const messageLength = buf.getUint32(buf.currentReadOffset());
|
|
18
|
+
if (rem < messageLength) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
CrdtMessageProtocol.validate = validate;
|
|
24
|
+
/**
|
|
25
|
+
* Get the current header, consuming the bytes involved.
|
|
26
|
+
* @param buf - ByteBuffer
|
|
27
|
+
* @returns header or null if there is no validated message
|
|
28
|
+
*/
|
|
29
|
+
function readHeader(buf) {
|
|
30
|
+
if (!validate(buf)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
length: buf.readUint32(),
|
|
35
|
+
type: buf.readUint32()
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
CrdtMessageProtocol.readHeader = readHeader;
|
|
39
|
+
/**
|
|
40
|
+
* Get the current header, without consuming the bytes involved.
|
|
41
|
+
* @param buf - ByteBuffer
|
|
42
|
+
* @returns header or null if there is no validated message
|
|
43
|
+
*/
|
|
44
|
+
function getHeader(buf) {
|
|
45
|
+
if (!validate(buf)) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const currentOffset = buf.currentReadOffset();
|
|
49
|
+
return {
|
|
50
|
+
length: buf.getUint32(currentOffset),
|
|
51
|
+
type: buf.getUint32(currentOffset + 4)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
CrdtMessageProtocol.getHeader = getHeader;
|
|
55
|
+
/**
|
|
56
|
+
* Consume the incoming message without processing it.
|
|
57
|
+
* @param buf - ByteBuffer
|
|
58
|
+
* @returns true in case of success or false if there is no valid message.
|
|
59
|
+
*/
|
|
60
|
+
function consumeMessage(buf) {
|
|
61
|
+
const header = getHeader(buf);
|
|
62
|
+
if (!header) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
buf.incrementReadOffset(header.length);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
CrdtMessageProtocol.consumeMessage = consumeMessage;
|
|
69
|
+
})(CrdtMessageProtocol || (CrdtMessageProtocol = {}));
|
|
70
|
+
export default CrdtMessageProtocol;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import CrdtMessageProtocol, { DeleteComponent, DeleteEntity, PutComponentOperation } from '.';
|
|
2
|
+
import { CrdtMessageType } from './types';
|
|
3
|
+
export function readMessage(buf) {
|
|
4
|
+
const header = CrdtMessageProtocol.getHeader(buf);
|
|
5
|
+
if (!header)
|
|
6
|
+
return null;
|
|
7
|
+
if (header.type === CrdtMessageType.PUT_COMPONENT) {
|
|
8
|
+
return PutComponentOperation.read(buf);
|
|
9
|
+
}
|
|
10
|
+
else if (header.type === CrdtMessageType.DELETE_COMPONENT) {
|
|
11
|
+
return DeleteComponent.read(buf);
|
|
12
|
+
}
|
|
13
|
+
else if (header.type === CrdtMessageType.DELETE_ENTITY) {
|
|
14
|
+
return DeleteEntity.read(buf);
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ComponentDefinition } from '../../engine/component';
|
|
2
|
+
import { Entity } from '../../engine/entity';
|
|
3
|
+
import { ByteBuffer } from '../ByteBuffer';
|
|
4
|
+
import { PutComponentMessage } from './types';
|
|
5
|
+
export declare namespace PutComponentOperation {
|
|
6
|
+
const MESSAGE_HEADER_LENGTH = 20;
|
|
7
|
+
/**
|
|
8
|
+
* Call this function for an optimal writing data passing the ByteBuffer
|
|
9
|
+
* already allocated
|
|
10
|
+
*/
|
|
11
|
+
function write(entity: Entity, timestamp: number, componentDefinition: ComponentDefinition<unknown>, buf: ByteBuffer): void;
|
|
12
|
+
function read(buf: ByteBuffer): PutComponentMessage | null;
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import CrdtMessageProtocol from '.';
|
|
2
|
+
import { CrdtMessageType, CRDT_MESSAGE_HEADER_LENGTH } from './types';
|
|
3
|
+
export var PutComponentOperation;
|
|
4
|
+
(function (PutComponentOperation) {
|
|
5
|
+
PutComponentOperation.MESSAGE_HEADER_LENGTH = 20;
|
|
6
|
+
/**
|
|
7
|
+
* Call this function for an optimal writing data passing the ByteBuffer
|
|
8
|
+
* already allocated
|
|
9
|
+
*/
|
|
10
|
+
function write(entity, timestamp, componentDefinition, buf) {
|
|
11
|
+
// reserve the beginning
|
|
12
|
+
const startMessageOffset = buf.incrementWriteOffset(CRDT_MESSAGE_HEADER_LENGTH + PutComponentOperation.MESSAGE_HEADER_LENGTH);
|
|
13
|
+
// write body
|
|
14
|
+
componentDefinition.writeToByteBuffer(entity, buf);
|
|
15
|
+
const messageLength = buf.size() - startMessageOffset;
|
|
16
|
+
// Write CrdtMessage header
|
|
17
|
+
buf.setUint32(startMessageOffset, messageLength);
|
|
18
|
+
buf.setUint32(startMessageOffset + 4, CrdtMessageType.PUT_COMPONENT);
|
|
19
|
+
// Write ComponentOperation header
|
|
20
|
+
buf.setUint32(startMessageOffset + 8, entity);
|
|
21
|
+
buf.setUint32(startMessageOffset + 12, componentDefinition._id);
|
|
22
|
+
buf.setUint64(startMessageOffset + 16, BigInt(timestamp));
|
|
23
|
+
const newLocal = messageLength - PutComponentOperation.MESSAGE_HEADER_LENGTH - CRDT_MESSAGE_HEADER_LENGTH;
|
|
24
|
+
buf.setUint32(startMessageOffset + 24, newLocal);
|
|
25
|
+
}
|
|
26
|
+
PutComponentOperation.write = write;
|
|
27
|
+
function read(buf) {
|
|
28
|
+
const header = CrdtMessageProtocol.readHeader(buf);
|
|
29
|
+
if (!header) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (header.type !== CrdtMessageType.PUT_COMPONENT) {
|
|
33
|
+
throw new Error('PutComponentOperation tried to read another message type.');
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
...header,
|
|
37
|
+
entityId: buf.readUint32(),
|
|
38
|
+
componentId: buf.readInt32(),
|
|
39
|
+
timestamp: Number(buf.readUint64()),
|
|
40
|
+
data: buf.readBuffer()
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
PutComponentOperation.read = read;
|
|
44
|
+
})(PutComponentOperation || (PutComponentOperation = {}));
|