@dcl/protocol 1.0.0-29286492043.commit-0010e70 → 1.0.0-29287211316.commit-e44c721
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/README.md +217 -0
- package/out-js/decentraland/kernel/comms/rfc4/comms.gen.d.ts +21 -0
- package/out-js/decentraland/kernel/comms/rfc4/comms.gen.js +124 -4
- package/out-js/decentraland/kernel/comms/rfc4/comms.gen.js.map +1 -1
- package/out-js/decentraland/sdk/components/avatar_shape.gen.d.ts +8 -0
- package/out-js/decentraland/sdk/components/avatar_shape.gen.js +35 -1
- package/out-js/decentraland/sdk/components/avatar_shape.gen.js.map +1 -1
- package/out-ts/decentraland/kernel/comms/rfc4/comms.gen.ts +166 -2
- package/out-ts/decentraland/sdk/components/avatar_shape.gen.ts +34 -0
- package/package.json +9 -6
- package/proto/decentraland/common/options.proto +51 -0
- package/proto/decentraland/common/quantization_example.proto +164 -0
- package/proto/decentraland/kernel/comms/rfc4/comms.proto +11 -0
- package/proto/decentraland/pulse/pulse_client.proto +79 -0
- package/proto/decentraland/pulse/pulse_server.proto +144 -0
- package/proto/decentraland/pulse/pulse_shared.proto +57 -0
- package/proto/decentraland/sdk/components/avatar_shape.proto +5 -0
- package/proto/decentraland/sdk/components/light_source.proto +1 -1
- package/proto/decentraland/sdk/components/virtual_camera.proto +2 -0
- package/protoc-gen-bitwise/generator_csharp.js +248 -0
- package/protoc-gen-bitwise/options.js +139 -0
- package/protoc-gen-bitwise/plugin.js +87 -0
- package/protoc-gen-bitwise/runtime/cs/Quantize.cs +70 -0
- package/protoc-gen-bitwise/wire.js +239 -0
- package/proto/buf.yaml +0 -47
- package/proto/google/LICENSE +0 -27
- package/proto/google/README.md +0 -1
- package/proto/google/api/annotations.json +0 -83
- package/proto/google/api/annotations.proto +0 -11
- package/proto/google/api/http.json +0 -86
- package/proto/google/api/http.proto +0 -31
- package/proto/google/protobuf/api.json +0 -118
- package/proto/google/protobuf/api.proto +0 -34
- package/proto/google/protobuf/descriptor.json +0 -739
- package/proto/google/protobuf/descriptor.proto +0 -286
- package/proto/google/protobuf/source_context.json +0 -20
- package/proto/google/protobuf/source_context.proto +0 -7
- package/proto/google/protobuf/type.json +0 -202
- package/proto/google/protobuf/type.proto +0 -89
|
@@ -137,6 +137,36 @@ export interface PlayerEmote {
|
|
|
137
137
|
incrementalId: number;
|
|
138
138
|
urn: string;
|
|
139
139
|
timestamp: number;
|
|
140
|
+
/** true means the emote has been stopped in the sender's client */
|
|
141
|
+
isStopping?:
|
|
142
|
+
| boolean
|
|
143
|
+
| undefined;
|
|
144
|
+
/** true when it is not the first time the looping animation plays */
|
|
145
|
+
isRepeating?:
|
|
146
|
+
| boolean
|
|
147
|
+
| undefined;
|
|
148
|
+
/** identifies an interaction univocaly, established when the start animation is triggered */
|
|
149
|
+
interactionId?:
|
|
150
|
+
| number
|
|
151
|
+
| undefined;
|
|
152
|
+
/** -1 means it does not use an outcome animation */
|
|
153
|
+
socialEmoteOutcome?:
|
|
154
|
+
| number
|
|
155
|
+
| undefined;
|
|
156
|
+
/** to a social emote started by other user */
|
|
157
|
+
isReacting?:
|
|
158
|
+
| boolean
|
|
159
|
+
| undefined;
|
|
160
|
+
/** wallet address of the user that initiated social emote */
|
|
161
|
+
socialEmoteInitiator?:
|
|
162
|
+
| string
|
|
163
|
+
| undefined;
|
|
164
|
+
/** wallet address of the user whose avatar is the target of a directed emote */
|
|
165
|
+
targetAvatar?:
|
|
166
|
+
| string
|
|
167
|
+
| undefined;
|
|
168
|
+
/** mask for which bones an animation applies to. */
|
|
169
|
+
mask?: number | undefined;
|
|
140
170
|
}
|
|
141
171
|
|
|
142
172
|
export interface SceneEmote {
|
|
@@ -161,6 +191,11 @@ export interface ProfileResponse {
|
|
|
161
191
|
export interface Chat {
|
|
162
192
|
message: string;
|
|
163
193
|
timestamp: number;
|
|
194
|
+
/**
|
|
195
|
+
* Extension: optional forwarded_from to identify the original sender when
|
|
196
|
+
* messages are forwarded through an SFU
|
|
197
|
+
*/
|
|
198
|
+
forwardedFrom?: string | undefined;
|
|
164
199
|
}
|
|
165
200
|
|
|
166
201
|
export interface Scene {
|
|
@@ -1287,7 +1322,19 @@ export namespace MovementCompressed {
|
|
|
1287
1322
|
}
|
|
1288
1323
|
|
|
1289
1324
|
function createBasePlayerEmote(): PlayerEmote {
|
|
1290
|
-
return {
|
|
1325
|
+
return {
|
|
1326
|
+
incrementalId: 0,
|
|
1327
|
+
urn: "",
|
|
1328
|
+
timestamp: 0,
|
|
1329
|
+
isStopping: undefined,
|
|
1330
|
+
isRepeating: undefined,
|
|
1331
|
+
interactionId: undefined,
|
|
1332
|
+
socialEmoteOutcome: undefined,
|
|
1333
|
+
isReacting: undefined,
|
|
1334
|
+
socialEmoteInitiator: undefined,
|
|
1335
|
+
targetAvatar: undefined,
|
|
1336
|
+
mask: undefined,
|
|
1337
|
+
};
|
|
1291
1338
|
}
|
|
1292
1339
|
|
|
1293
1340
|
export namespace PlayerEmote {
|
|
@@ -1301,6 +1348,30 @@ export namespace PlayerEmote {
|
|
|
1301
1348
|
if (message.timestamp !== 0) {
|
|
1302
1349
|
writer.uint32(29).float(message.timestamp);
|
|
1303
1350
|
}
|
|
1351
|
+
if (message.isStopping !== undefined) {
|
|
1352
|
+
writer.uint32(32).bool(message.isStopping);
|
|
1353
|
+
}
|
|
1354
|
+
if (message.isRepeating !== undefined) {
|
|
1355
|
+
writer.uint32(40).bool(message.isRepeating);
|
|
1356
|
+
}
|
|
1357
|
+
if (message.interactionId !== undefined) {
|
|
1358
|
+
writer.uint32(48).int32(message.interactionId);
|
|
1359
|
+
}
|
|
1360
|
+
if (message.socialEmoteOutcome !== undefined) {
|
|
1361
|
+
writer.uint32(56).int32(message.socialEmoteOutcome);
|
|
1362
|
+
}
|
|
1363
|
+
if (message.isReacting !== undefined) {
|
|
1364
|
+
writer.uint32(64).bool(message.isReacting);
|
|
1365
|
+
}
|
|
1366
|
+
if (message.socialEmoteInitiator !== undefined) {
|
|
1367
|
+
writer.uint32(74).string(message.socialEmoteInitiator);
|
|
1368
|
+
}
|
|
1369
|
+
if (message.targetAvatar !== undefined) {
|
|
1370
|
+
writer.uint32(82).string(message.targetAvatar);
|
|
1371
|
+
}
|
|
1372
|
+
if (message.mask !== undefined) {
|
|
1373
|
+
writer.uint32(88).uint32(message.mask);
|
|
1374
|
+
}
|
|
1304
1375
|
return writer;
|
|
1305
1376
|
}
|
|
1306
1377
|
|
|
@@ -1332,6 +1403,62 @@ export namespace PlayerEmote {
|
|
|
1332
1403
|
|
|
1333
1404
|
message.timestamp = reader.float();
|
|
1334
1405
|
continue;
|
|
1406
|
+
case 4:
|
|
1407
|
+
if (tag !== 32) {
|
|
1408
|
+
break;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
message.isStopping = reader.bool();
|
|
1412
|
+
continue;
|
|
1413
|
+
case 5:
|
|
1414
|
+
if (tag !== 40) {
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
message.isRepeating = reader.bool();
|
|
1419
|
+
continue;
|
|
1420
|
+
case 6:
|
|
1421
|
+
if (tag !== 48) {
|
|
1422
|
+
break;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
message.interactionId = reader.int32();
|
|
1426
|
+
continue;
|
|
1427
|
+
case 7:
|
|
1428
|
+
if (tag !== 56) {
|
|
1429
|
+
break;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
message.socialEmoteOutcome = reader.int32();
|
|
1433
|
+
continue;
|
|
1434
|
+
case 8:
|
|
1435
|
+
if (tag !== 64) {
|
|
1436
|
+
break;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
message.isReacting = reader.bool();
|
|
1440
|
+
continue;
|
|
1441
|
+
case 9:
|
|
1442
|
+
if (tag !== 74) {
|
|
1443
|
+
break;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
message.socialEmoteInitiator = reader.string();
|
|
1447
|
+
continue;
|
|
1448
|
+
case 10:
|
|
1449
|
+
if (tag !== 82) {
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
message.targetAvatar = reader.string();
|
|
1454
|
+
continue;
|
|
1455
|
+
case 11:
|
|
1456
|
+
if (tag !== 88) {
|
|
1457
|
+
break;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
message.mask = reader.uint32();
|
|
1461
|
+
continue;
|
|
1335
1462
|
}
|
|
1336
1463
|
if ((tag & 7) === 4 || tag === 0) {
|
|
1337
1464
|
break;
|
|
@@ -1346,6 +1473,14 @@ export namespace PlayerEmote {
|
|
|
1346
1473
|
incrementalId: isSet(object.incrementalId) ? Number(object.incrementalId) : 0,
|
|
1347
1474
|
urn: isSet(object.urn) ? String(object.urn) : "",
|
|
1348
1475
|
timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
|
|
1476
|
+
isStopping: isSet(object.isStopping) ? Boolean(object.isStopping) : undefined,
|
|
1477
|
+
isRepeating: isSet(object.isRepeating) ? Boolean(object.isRepeating) : undefined,
|
|
1478
|
+
interactionId: isSet(object.interactionId) ? Number(object.interactionId) : undefined,
|
|
1479
|
+
socialEmoteOutcome: isSet(object.socialEmoteOutcome) ? Number(object.socialEmoteOutcome) : undefined,
|
|
1480
|
+
isReacting: isSet(object.isReacting) ? Boolean(object.isReacting) : undefined,
|
|
1481
|
+
socialEmoteInitiator: isSet(object.socialEmoteInitiator) ? String(object.socialEmoteInitiator) : undefined,
|
|
1482
|
+
targetAvatar: isSet(object.targetAvatar) ? String(object.targetAvatar) : undefined,
|
|
1483
|
+
mask: isSet(object.mask) ? Number(object.mask) : undefined,
|
|
1349
1484
|
};
|
|
1350
1485
|
}
|
|
1351
1486
|
|
|
@@ -1354,6 +1489,14 @@ export namespace PlayerEmote {
|
|
|
1354
1489
|
message.incrementalId !== undefined && (obj.incrementalId = Math.round(message.incrementalId));
|
|
1355
1490
|
message.urn !== undefined && (obj.urn = message.urn);
|
|
1356
1491
|
message.timestamp !== undefined && (obj.timestamp = message.timestamp);
|
|
1492
|
+
message.isStopping !== undefined && (obj.isStopping = message.isStopping);
|
|
1493
|
+
message.isRepeating !== undefined && (obj.isRepeating = message.isRepeating);
|
|
1494
|
+
message.interactionId !== undefined && (obj.interactionId = Math.round(message.interactionId));
|
|
1495
|
+
message.socialEmoteOutcome !== undefined && (obj.socialEmoteOutcome = Math.round(message.socialEmoteOutcome));
|
|
1496
|
+
message.isReacting !== undefined && (obj.isReacting = message.isReacting);
|
|
1497
|
+
message.socialEmoteInitiator !== undefined && (obj.socialEmoteInitiator = message.socialEmoteInitiator);
|
|
1498
|
+
message.targetAvatar !== undefined && (obj.targetAvatar = message.targetAvatar);
|
|
1499
|
+
message.mask !== undefined && (obj.mask = Math.round(message.mask));
|
|
1357
1500
|
return obj;
|
|
1358
1501
|
}
|
|
1359
1502
|
|
|
@@ -1366,6 +1509,14 @@ export namespace PlayerEmote {
|
|
|
1366
1509
|
message.incrementalId = object.incrementalId ?? 0;
|
|
1367
1510
|
message.urn = object.urn ?? "";
|
|
1368
1511
|
message.timestamp = object.timestamp ?? 0;
|
|
1512
|
+
message.isStopping = object.isStopping ?? undefined;
|
|
1513
|
+
message.isRepeating = object.isRepeating ?? undefined;
|
|
1514
|
+
message.interactionId = object.interactionId ?? undefined;
|
|
1515
|
+
message.socialEmoteOutcome = object.socialEmoteOutcome ?? undefined;
|
|
1516
|
+
message.isReacting = object.isReacting ?? undefined;
|
|
1517
|
+
message.socialEmoteInitiator = object.socialEmoteInitiator ?? undefined;
|
|
1518
|
+
message.targetAvatar = object.targetAvatar ?? undefined;
|
|
1519
|
+
message.mask = object.mask ?? undefined;
|
|
1369
1520
|
return message;
|
|
1370
1521
|
}
|
|
1371
1522
|
}
|
|
@@ -1642,7 +1793,7 @@ export namespace ProfileResponse {
|
|
|
1642
1793
|
}
|
|
1643
1794
|
|
|
1644
1795
|
function createBaseChat(): Chat {
|
|
1645
|
-
return { message: "", timestamp: 0 };
|
|
1796
|
+
return { message: "", timestamp: 0, forwardedFrom: undefined };
|
|
1646
1797
|
}
|
|
1647
1798
|
|
|
1648
1799
|
export namespace Chat {
|
|
@@ -1653,6 +1804,9 @@ export namespace Chat {
|
|
|
1653
1804
|
if (message.timestamp !== 0) {
|
|
1654
1805
|
writer.uint32(17).double(message.timestamp);
|
|
1655
1806
|
}
|
|
1807
|
+
if (message.forwardedFrom !== undefined) {
|
|
1808
|
+
writer.uint32(26).string(message.forwardedFrom);
|
|
1809
|
+
}
|
|
1656
1810
|
return writer;
|
|
1657
1811
|
}
|
|
1658
1812
|
|
|
@@ -1677,6 +1831,13 @@ export namespace Chat {
|
|
|
1677
1831
|
|
|
1678
1832
|
message.timestamp = reader.double();
|
|
1679
1833
|
continue;
|
|
1834
|
+
case 3:
|
|
1835
|
+
if (tag !== 26) {
|
|
1836
|
+
break;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
message.forwardedFrom = reader.string();
|
|
1840
|
+
continue;
|
|
1680
1841
|
}
|
|
1681
1842
|
if ((tag & 7) === 4 || tag === 0) {
|
|
1682
1843
|
break;
|
|
@@ -1690,6 +1851,7 @@ export namespace Chat {
|
|
|
1690
1851
|
return {
|
|
1691
1852
|
message: isSet(object.message) ? String(object.message) : "",
|
|
1692
1853
|
timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
|
|
1854
|
+
forwardedFrom: isSet(object.forwardedFrom) ? String(object.forwardedFrom) : undefined,
|
|
1693
1855
|
};
|
|
1694
1856
|
}
|
|
1695
1857
|
|
|
@@ -1697,6 +1859,7 @@ export namespace Chat {
|
|
|
1697
1859
|
const obj: any = {};
|
|
1698
1860
|
message.message !== undefined && (obj.message = message.message);
|
|
1699
1861
|
message.timestamp !== undefined && (obj.timestamp = message.timestamp);
|
|
1862
|
+
message.forwardedFrom !== undefined && (obj.forwardedFrom = message.forwardedFrom);
|
|
1700
1863
|
return obj;
|
|
1701
1864
|
}
|
|
1702
1865
|
|
|
@@ -1708,6 +1871,7 @@ export namespace Chat {
|
|
|
1708
1871
|
const message = createBaseChat();
|
|
1709
1872
|
message.message = object.message ?? "";
|
|
1710
1873
|
message.timestamp = object.timestamp ?? 0;
|
|
1874
|
+
message.forwardedFrom = object.forwardedFrom ?? undefined;
|
|
1711
1875
|
return message;
|
|
1712
1876
|
}
|
|
1713
1877
|
}
|
|
@@ -5,6 +5,40 @@ import { Color3 } from "../../common/colors.gen";
|
|
|
5
5
|
|
|
6
6
|
export const protobufPackage = "decentraland.sdk.components";
|
|
7
7
|
|
|
8
|
+
/** Mask for which bones an animation applies to. */
|
|
9
|
+
export enum AvatarEmoteMask {
|
|
10
|
+
AEM_FULL_BODY = 0,
|
|
11
|
+
AEM_UPPER_BODY = 1,
|
|
12
|
+
UNRECOGNIZED = -1,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function avatarEmoteMaskFromJSON(object: any): AvatarEmoteMask {
|
|
16
|
+
switch (object) {
|
|
17
|
+
case 0:
|
|
18
|
+
case "AEM_FULL_BODY":
|
|
19
|
+
return AvatarEmoteMask.AEM_FULL_BODY;
|
|
20
|
+
case 1:
|
|
21
|
+
case "AEM_UPPER_BODY":
|
|
22
|
+
return AvatarEmoteMask.AEM_UPPER_BODY;
|
|
23
|
+
case -1:
|
|
24
|
+
case "UNRECOGNIZED":
|
|
25
|
+
default:
|
|
26
|
+
return AvatarEmoteMask.UNRECOGNIZED;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function avatarEmoteMaskToJSON(object: AvatarEmoteMask): string {
|
|
31
|
+
switch (object) {
|
|
32
|
+
case AvatarEmoteMask.AEM_FULL_BODY:
|
|
33
|
+
return "AEM_FULL_BODY";
|
|
34
|
+
case AvatarEmoteMask.AEM_UPPER_BODY:
|
|
35
|
+
return "AEM_UPPER_BODY";
|
|
36
|
+
case AvatarEmoteMask.UNRECOGNIZED:
|
|
37
|
+
default:
|
|
38
|
+
return "UNRECOGNIZED";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
8
42
|
/**
|
|
9
43
|
* The AvatarShape component contains the information required to draw and animate avatar, acting as
|
|
10
44
|
* a simplified GLTF container for this specific case.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/protocol",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-29287211316.commit-e44c721",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"main": "index.js",
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "./scripts/check-proto-compabitility.sh"
|
|
16
|
+
"test": "./scripts/check-proto-compabitility.sh",
|
|
17
|
+
"gen:test": "node protoc-gen-bitwise/test/generator.test.js"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@protobuf-ts/protoc": "^2.
|
|
20
|
+
"@protobuf-ts/protoc": "^2.11.0",
|
|
20
21
|
"proto-compatibility-tool": "^1.1.2-20220925163655.commit-25bd040",
|
|
21
22
|
"typescript": "^5.0.4"
|
|
22
23
|
},
|
|
@@ -28,10 +29,12 @@
|
|
|
28
29
|
"protobufjs": "7.2.4"
|
|
29
30
|
},
|
|
30
31
|
"files": [
|
|
31
|
-
"proto",
|
|
32
|
+
"proto/decentraland",
|
|
32
33
|
"out-ts",
|
|
33
34
|
"out-js",
|
|
34
|
-
"public"
|
|
35
|
+
"public",
|
|
36
|
+
"protoc-gen-bitwise/*.js",
|
|
37
|
+
"protoc-gen-bitwise/runtime"
|
|
35
38
|
],
|
|
36
|
-
"commit": "
|
|
39
|
+
"commit": "e44c721a034709fc47b820be81b5c977f9085ae6"
|
|
37
40
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package decentraland.common;
|
|
4
|
+
|
|
5
|
+
import "google/protobuf/descriptor.proto";
|
|
6
|
+
|
|
7
|
+
// Options for quantizing a float value stored as a uint32 field.
|
|
8
|
+
// The float is clamped to [min, max] and uniformly quantized to N bits;
|
|
9
|
+
// protobuf encodes the resulting uint32 as a varint on the wire.
|
|
10
|
+
// The generator emits a float {Name}Quantized accessor in the partial class.
|
|
11
|
+
message QuantizedFloatOptions {
|
|
12
|
+
float min = 1;
|
|
13
|
+
float max = 2;
|
|
14
|
+
uint32 bits = 3;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Options for quantizing a signed float with a power-law curve, stored as a uint32 field.
|
|
18
|
+
// The value is split into an (bits-1)-bit linear unorm magnitude `u in [0, 1]` plus a sign,
|
|
19
|
+
// and reconstructed as `value = sign * max * u^pow`. Because `u = 0` maps to exactly `0`, zero is
|
|
20
|
+
// representable (unlike the linear quantizer, whose codes straddle zero), and `pow > 1` concentrates
|
|
21
|
+
// resolution near zero — useful for fields like velocity that need fine detail at low magnitudes and
|
|
22
|
+
// only coarse detail near the extremes. The range is symmetric ([-max, max]); there is no `min`.
|
|
23
|
+
// The encoded layout puts the magnitude in the high bits and the sign in the LSB
|
|
24
|
+
// (`(magnitude << 1) | sign`), so the varint cost tracks magnitude, not direction: a small `|value|`
|
|
25
|
+
// of either sign stays in one varint byte. Zero canonicalizes to `0`, so proto3 omits a stopped field.
|
|
26
|
+
// The generator emits a float {Name}Quantized accessor, same as the linear option.
|
|
27
|
+
message QuantizedPowerFloatOptions {
|
|
28
|
+
float max = 1;
|
|
29
|
+
float pow = 2;
|
|
30
|
+
uint32 bits = 3;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Options for bit-packing an integer field into fewer than 32 bits.
|
|
34
|
+
message BitPackedOptions {
|
|
35
|
+
uint32 bits = 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
extend google.protobuf.FieldOptions {
|
|
39
|
+
// Apply to uint32 fields to enable quantized float encoding.
|
|
40
|
+
// Example: uint32 dx = 1 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
|
|
41
|
+
QuantizedFloatOptions quantized = 50001;
|
|
42
|
+
|
|
43
|
+
// Apply to uint32 fields to pack into fewer bits.
|
|
44
|
+
// Example: uint32 entity_id = 4 [(decentraland.common.bit_packed) = { bits: 20 }];
|
|
45
|
+
BitPackedOptions bit_packed = 50002;
|
|
46
|
+
|
|
47
|
+
// Apply to uint32 fields to enable power-law quantized float encoding (sign + magnitude curve).
|
|
48
|
+
// A field carries either `quantized` or `quantized_power`, not both.
|
|
49
|
+
// Example: uint32 velocity_x = 9 [(decentraland.common.quantized_power) = { max: 50.0, pow: 2.0, bits: 8 }];
|
|
50
|
+
QuantizedPowerFloatOptions quantized_power = 50003;
|
|
51
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package decentraland.common;
|
|
4
|
+
|
|
5
|
+
import "decentraland/common/options.proto";
|
|
6
|
+
|
|
7
|
+
// High-frequency player state messages sent on Channel 1 (unreliable sequenced).
|
|
8
|
+
//
|
|
9
|
+
// Every message below uses the protoc-gen-bitwise annotations to minimise
|
|
10
|
+
// wire size. Wire costs are listed per-message so the trade-offs are clear.
|
|
11
|
+
//
|
|
12
|
+
// Annotation cheat-sheet:
|
|
13
|
+
// [(decentraland.common.quantized) = { min: F, max: F, bits: N }]
|
|
14
|
+
// → stores a float as a uint32 quantized to N bits over [min, max].
|
|
15
|
+
// → protobuf encodes the uint32 as a varint: values ≤ 2^14-1 cost 2 bytes,
|
|
16
|
+
// values ≤ 2^21-1 cost 3 bytes; the generated partial class adds a
|
|
17
|
+
// float {Name}Quantized accessor that encodes/decodes transparently.
|
|
18
|
+
// [(decentraland.common.quantized_power) = { max: F, pow: F, bits: N }]
|
|
19
|
+
// → stores a signed float over [-max, max] as an (N-1)-bit linear unorm
|
|
20
|
+
// magnitude (high bits) plus a sign (LSB), reconstructed as sign·max·u^pow.
|
|
21
|
+
// Zero is exact, and pow>1 buys fine resolution near zero at the cost of
|
|
22
|
+
// coarse near ±max. Putting the sign in the LSB keeps a small |value| of
|
|
23
|
+
// either direction in one varint byte. Same generated float {Name}Quantized
|
|
24
|
+
// accessor as the linear option.
|
|
25
|
+
// [(decentraland.common.bit_packed) = { bits: N }]
|
|
26
|
+
// → documents that this uint32 uses at most N bits; protobuf encodes it
|
|
27
|
+
// as a varint (same savings, no generated accessor needed).
|
|
28
|
+
// (no annotation)
|
|
29
|
+
// → standard protobuf encoding (bool/double/etc. at natural width).
|
|
30
|
+
//
|
|
31
|
+
// Varint byte costs at worst-case (all bits set):
|
|
32
|
+
// ≤ 7 bits → 1 byte (max 127)
|
|
33
|
+
// ≤ 14 bits → 2 bytes (max 16 383)
|
|
34
|
+
// ≤ 21 bits → 3 bytes (max 2 097 151)
|
|
35
|
+
// Proto3 omits fields equal to their default value (0), so average cost is lower.
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// PositionDelta — Δ position relative to last acknowledged full snapshot.
|
|
39
|
+
//
|
|
40
|
+
// Sent every client tick (~10 Hz) on Channel 1.
|
|
41
|
+
//
|
|
42
|
+
// Field | Type | Range | Q bits | Wire worst-case
|
|
43
|
+
// ------------|--------|----------------|--------|-----------------------
|
|
44
|
+
// dx | uint32 | [-100, 100] | 16 | tag 1B + varint 3B = 4B
|
|
45
|
+
// dy | uint32 | [-100, 100] | 16 | tag 1B + varint 3B = 4B
|
|
46
|
+
// dz | uint32 | [-100, 100] | 16 | tag 1B + varint 3B = 4B
|
|
47
|
+
// entity_id | uint32 | [0, 1 048 575] | 20 | tag 1B + varint 3B = 4B
|
|
48
|
+
// sequence | uint32 | [0, 4 095] | 12 | tag 1B + varint 2B = 3B
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Worst-case: 19 B (vs. 20 B raw: 3×float + 2×uint32)
|
|
51
|
+
// Step: dx/dy/dz ≈ 0.003 units
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
message PositionDelta {
|
|
54
|
+
uint32 dx = 1 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
|
|
55
|
+
uint32 dy = 2 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
|
|
56
|
+
uint32 dz = 3 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
|
|
57
|
+
uint32 entity_id = 4 [(decentraland.common.bit_packed) = { bits: 20 }];
|
|
58
|
+
uint32 sequence = 5 [(decentraland.common.bit_packed) = { bits: 12 }];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// PlayerInput — client input snapshot for server-side reconciliation.
|
|
63
|
+
//
|
|
64
|
+
// Sent every client frame (~30 Hz) on Channel 1.
|
|
65
|
+
//
|
|
66
|
+
// Field | Type | Range | Q bits | Wire worst-case
|
|
67
|
+
// ------------|--------|----------------|--------|-----------------------
|
|
68
|
+
// move_x | uint32 | [-1, 1] | 8 | tag 1B + varint 2B = 3B
|
|
69
|
+
// move_z | uint32 | [-1, 1] | 8 | tag 1B + varint 2B = 3B
|
|
70
|
+
// yaw | uint32 | [-180, 180] | 12 | tag 1B + varint 2B = 3B
|
|
71
|
+
// buttons | uint32 | bitmask | 8 | tag 1B + varint 2B = 3B
|
|
72
|
+
// sequence | uint32 | [0, 4 095] | 12 | tag 1B + varint 2B = 3B
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Worst-case: 15 B (vs. 20 B raw: 3×float + 2×uint32)
|
|
75
|
+
// Step: move_x/move_z ≈ 0.008; yaw ≈ 0.088°
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
message PlayerInput {
|
|
78
|
+
// Normalised joystick axes in [-1, 1].
|
|
79
|
+
uint32 move_x = 1 [(decentraland.common.quantized) = { min: -1.0, max: 1.0, bits: 8 }];
|
|
80
|
+
uint32 move_z = 2 [(decentraland.common.quantized) = { min: -1.0, max: 1.0, bits: 8 }];
|
|
81
|
+
|
|
82
|
+
// Horizontal look direction in degrees.
|
|
83
|
+
uint32 yaw = 3 [(decentraland.common.quantized) = { min: -180.0, max: 180.0, bits: 12 }];
|
|
84
|
+
|
|
85
|
+
// Bitmask of active buttons (see ButtonFlags below).
|
|
86
|
+
uint32 buttons = 4 [(decentraland.common.bit_packed) = { bits: 8 }];
|
|
87
|
+
|
|
88
|
+
// Rolling input sequence number used by the server for reconciliation.
|
|
89
|
+
uint32 sequence = 5 [(decentraland.common.bit_packed) = { bits: 12 }];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// VelocityState — per-axis velocity, demonstrating the power-law quantizer.
|
|
94
|
+
//
|
|
95
|
+
// Velocity needs an exact zero (a stopped avatar must read 0, not a quantization
|
|
96
|
+
// residual, or it drifts) and fine resolution at locomotion speeds, but only
|
|
97
|
+
// coarse resolution near the ±50 m/s extremes. The linear quantizer can give
|
|
98
|
+
// none of these from 8 bits: its codes straddle zero (±0.196) and spend uniform
|
|
99
|
+
// resolution on speeds that never occur. quantized_power solves all three.
|
|
100
|
+
//
|
|
101
|
+
// Field | Type | Range | pow | bits | Wire worst-case
|
|
102
|
+
// -------|--------|------------|-----|------|-----------------------
|
|
103
|
+
// vx | uint32 | [-50, 50] | 2 | 8 | tag 1B + varint 1–2B = 2–3B
|
|
104
|
+
// vy | uint32 | [-50, 50] | 2 | 8 | tag 1B + varint 1–2B = 2–3B
|
|
105
|
+
// vz | uint32 | [-50, 50] | 2 | 8 | tag 1B + varint 1–2B = 2–3B
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Step: ≈ 0.003 m/s near zero, ≈ 0.78 m/s near ±50 (vs. 0.392 uniform linear)
|
|
108
|
+
// Wire: sign in the LSB, so |v| ≲ 12.5 m/s (magnitude code ≤ 63) costs a single
|
|
109
|
+
// varint byte regardless of direction; only faster axes spill to 2 bytes.
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
message VelocityState {
|
|
112
|
+
uint32 vx = 1 [(decentraland.common.quantized_power) = { max: 50.0, pow: 2.0, bits: 8 }];
|
|
113
|
+
uint32 vy = 2 [(decentraland.common.quantized_power) = { max: 50.0, pow: 2.0, bits: 8 }];
|
|
114
|
+
uint32 vz = 3 [(decentraland.common.quantized_power) = { max: 50.0, pow: 2.0, bits: 8 }];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Bitmask values for PlayerInput.buttons.
|
|
118
|
+
enum ButtonFlags {
|
|
119
|
+
BF_NONE = 0;
|
|
120
|
+
BF_JUMP = 1; // bit 0
|
|
121
|
+
BF_SPRINT = 2; // bit 1
|
|
122
|
+
BF_INTERACT = 4; // bit 2
|
|
123
|
+
BF_EMOTE = 8; // bit 3
|
|
124
|
+
BF_CROUCH = 16; // bit 4
|
|
125
|
+
// bits 5-7 reserved
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// AvatarStateSnapshot — full authoritative state, sent on Channel 0 (reliable)
|
|
130
|
+
// or on resync requests. Demonstrates wider ranges and mixed encodings.
|
|
131
|
+
//
|
|
132
|
+
// Field | Type | Range | Q bits | Wire worst-case
|
|
133
|
+
// -----------------|--------|------------------|--------|-----------------------
|
|
134
|
+
// x | uint32 | [-4096, 4096] | 16 | tag 1B + varint 3B = 4B
|
|
135
|
+
// y | uint32 | [-256, 256] | 14 | tag 1B + varint 2B = 3B
|
|
136
|
+
// z | uint32 | [-4096, 4096] | 16 | tag 1B + varint 3B = 4B
|
|
137
|
+
// pitch | uint32 | [-90, 90] | 10 | tag 1B + varint 2B = 3B
|
|
138
|
+
// yaw | uint32 | [-180, 180] | 12 | tag 1B + varint 2B = 3B
|
|
139
|
+
// entity_id | uint32 | [0, 1 048 575] | 20 | tag 1B + varint 3B = 4B
|
|
140
|
+
// animation_state | uint32 | [0, 63] | 6 | tag 1B + varint 1B = 2B
|
|
141
|
+
// is_grounded | bool | — | — | tag 1B + varint 1B = 2B
|
|
142
|
+
// timestamp | double | — | — | tag 1B + fixed64 8B = 9B
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Worst-case: 34 B (vs. 45 B raw: 5×float + 2×uint32 + bool + double)
|
|
145
|
+
// Step: x/z ≈ 0.125 units; y ≈ 0.031 units; pitch ≈ 0.176°; yaw ≈ 0.088°
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
message AvatarStateSnapshot {
|
|
148
|
+
// World-space position.
|
|
149
|
+
uint32 x = 1 [(decentraland.common.quantized) = { min: -4096.0, max: 4096.0, bits: 16 }];
|
|
150
|
+
uint32 y = 2 [(decentraland.common.quantized) = { min: -256.0, max: 256.0, bits: 14 }];
|
|
151
|
+
uint32 z = 3 [(decentraland.common.quantized) = { min: -4096.0, max: 4096.0, bits: 16 }];
|
|
152
|
+
|
|
153
|
+
// View angles.
|
|
154
|
+
uint32 pitch = 4 [(decentraland.common.quantized) = { min: -90.0, max: 90.0, bits: 10 }];
|
|
155
|
+
uint32 yaw = 5 [(decentraland.common.quantized) = { min: -180.0, max: 180.0, bits: 12 }];
|
|
156
|
+
|
|
157
|
+
// Identity and animation state.
|
|
158
|
+
uint32 entity_id = 6 [(decentraland.common.bit_packed) = { bits: 20 }];
|
|
159
|
+
uint32 animation_state = 7 [(decentraland.common.bit_packed) = { bits: 6 }];
|
|
160
|
+
|
|
161
|
+
// Un-annotated fields — encoded at their natural width.
|
|
162
|
+
bool is_grounded = 8;
|
|
163
|
+
double timestamp = 9; // server epoch milliseconds
|
|
164
|
+
}
|
|
@@ -94,6 +94,14 @@ message PlayerEmote {
|
|
|
94
94
|
uint32 incremental_id = 1;
|
|
95
95
|
string urn = 2;
|
|
96
96
|
float timestamp = 3;
|
|
97
|
+
optional bool is_stopping = 4; // true means the emote has been stopped in the sender's client
|
|
98
|
+
optional bool is_repeating = 5; // true when it is not the first time the looping animation plays
|
|
99
|
+
optional int32 interaction_id = 6; // identifies an interaction univocaly, established when the start animation is triggered
|
|
100
|
+
optional int32 social_emote_outcome = 7; // -1 means it does not use an outcome animation
|
|
101
|
+
optional bool is_reacting = 8; // to a social emote started by other user
|
|
102
|
+
optional string social_emote_initiator = 9; // wallet address of the user that initiated social emote
|
|
103
|
+
optional string target_avatar = 10; // wallet address of the user whose avatar is the target of a directed emote
|
|
104
|
+
optional uint32 mask = 11; // mask for which bones an animation applies to.
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
message SceneEmote {
|
|
@@ -126,6 +134,9 @@ message ProfileResponse {
|
|
|
126
134
|
message Chat {
|
|
127
135
|
string message = 1;
|
|
128
136
|
double timestamp = 2;
|
|
137
|
+
// Extension: optional forwarded_from to identify the original sender when
|
|
138
|
+
// messages are forwarded through an SFU
|
|
139
|
+
optional string forwarded_from = 3;
|
|
129
140
|
}
|
|
130
141
|
|
|
131
142
|
message Scene {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package decentraland.pulse;
|
|
4
|
+
|
|
5
|
+
import "decentraland/pulse/pulse_shared.proto";
|
|
6
|
+
import "decentraland/common/options.proto";
|
|
7
|
+
|
|
8
|
+
message HandshakeRequest {
|
|
9
|
+
bytes auth_chain = 1;
|
|
10
|
+
int32 profile_version = 2;
|
|
11
|
+
optional PlayerInitialState initial_state = 3;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Describes the initial state of the player if (re-)connected in the middle of the session
|
|
15
|
+
message PlayerInitialState {
|
|
16
|
+
PlayerState state = 1;
|
|
17
|
+
optional string emote_id = 2;
|
|
18
|
+
optional uint32 emote_duration_ms = 3;
|
|
19
|
+
// Indicates how many milliseconds ago the emote was started
|
|
20
|
+
optional uint32 emote_start_offset_ms = 4;
|
|
21
|
+
// Non-empty realm identifier. Rejected if empty.
|
|
22
|
+
string realm = 5;
|
|
23
|
+
optional int32 emote_mask = 6;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Similarly to the LiveKit pipeline, a peer announces the version of its profile but
|
|
27
|
+
// it only does it when it's changed as it's sent reliably and stored on the server for other peers
|
|
28
|
+
message ProfileVersionAnnouncement {
|
|
29
|
+
int32 version = 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Since the server doesn't simulate the scenes state, it trusts the values from the client
|
|
33
|
+
message PlayerStateInput {
|
|
34
|
+
PlayerState state = 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Client sends resync request if it has a gap in the known sequences and, thus, can't apply a delta.
|
|
38
|
+
// It's sent reliably to prevent further desynchronization
|
|
39
|
+
message ResyncRequest {
|
|
40
|
+
uint32 subject_id = 1;
|
|
41
|
+
// highest seq the client actually has for this subject
|
|
42
|
+
uint32 known_seq = 2;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Client → Server. Client requests to start an emote.
|
|
46
|
+
message EmoteStart {
|
|
47
|
+
string emote_id = 1;
|
|
48
|
+
optional uint32 duration_ms = 2;
|
|
49
|
+
PlayerState player_state = 3;
|
|
50
|
+
optional int32 mask = 4;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Client → Server. Client requests to stop a looping emote.
|
|
54
|
+
// One-shot emotes are terminated by the server timer.
|
|
55
|
+
message EmoteStop {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Client → Server. Also announces the peer's realm; peers in different realms never see each
|
|
59
|
+
// other. Must be the first gameplay message after handshake. Same-realm re-teleports are valid.
|
|
60
|
+
message TeleportRequest {
|
|
61
|
+
int32 parcel_index = 1;
|
|
62
|
+
uint32 position_x = 2 [(decentraland.common.quantized) = { min: 0, max: 16, bits: 8 }];
|
|
63
|
+
uint32 position_y = 3 [(decentraland.common.quantized) = { min: 0, max: 200, bits: 13 }];
|
|
64
|
+
uint32 position_z = 4 [(decentraland.common.quantized) = { min: 0, max: 16, bits: 8 }];
|
|
65
|
+
// Non-empty realm identifier. Rejected if empty.
|
|
66
|
+
string realm = 5;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
message ClientMessage {
|
|
70
|
+
oneof message {
|
|
71
|
+
HandshakeRequest handshake = 1;
|
|
72
|
+
PlayerStateInput input = 2;
|
|
73
|
+
ResyncRequest resync = 3;
|
|
74
|
+
ProfileVersionAnnouncement profile_announcement = 4;
|
|
75
|
+
EmoteStart emote_start = 5;
|
|
76
|
+
EmoteStop emote_stop = 6;
|
|
77
|
+
TeleportRequest teleport = 7;
|
|
78
|
+
}
|
|
79
|
+
}
|