@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.
Files changed (39) hide show
  1. package/README.md +217 -0
  2. package/out-js/decentraland/kernel/comms/rfc4/comms.gen.d.ts +21 -0
  3. package/out-js/decentraland/kernel/comms/rfc4/comms.gen.js +124 -4
  4. package/out-js/decentraland/kernel/comms/rfc4/comms.gen.js.map +1 -1
  5. package/out-js/decentraland/sdk/components/avatar_shape.gen.d.ts +8 -0
  6. package/out-js/decentraland/sdk/components/avatar_shape.gen.js +35 -1
  7. package/out-js/decentraland/sdk/components/avatar_shape.gen.js.map +1 -1
  8. package/out-ts/decentraland/kernel/comms/rfc4/comms.gen.ts +166 -2
  9. package/out-ts/decentraland/sdk/components/avatar_shape.gen.ts +34 -0
  10. package/package.json +9 -6
  11. package/proto/decentraland/common/options.proto +51 -0
  12. package/proto/decentraland/common/quantization_example.proto +164 -0
  13. package/proto/decentraland/kernel/comms/rfc4/comms.proto +11 -0
  14. package/proto/decentraland/pulse/pulse_client.proto +79 -0
  15. package/proto/decentraland/pulse/pulse_server.proto +144 -0
  16. package/proto/decentraland/pulse/pulse_shared.proto +57 -0
  17. package/proto/decentraland/sdk/components/avatar_shape.proto +5 -0
  18. package/proto/decentraland/sdk/components/light_source.proto +1 -1
  19. package/proto/decentraland/sdk/components/virtual_camera.proto +2 -0
  20. package/protoc-gen-bitwise/generator_csharp.js +248 -0
  21. package/protoc-gen-bitwise/options.js +139 -0
  22. package/protoc-gen-bitwise/plugin.js +87 -0
  23. package/protoc-gen-bitwise/runtime/cs/Quantize.cs +70 -0
  24. package/protoc-gen-bitwise/wire.js +239 -0
  25. package/proto/buf.yaml +0 -47
  26. package/proto/google/LICENSE +0 -27
  27. package/proto/google/README.md +0 -1
  28. package/proto/google/api/annotations.json +0 -83
  29. package/proto/google/api/annotations.proto +0 -11
  30. package/proto/google/api/http.json +0 -86
  31. package/proto/google/api/http.proto +0 -31
  32. package/proto/google/protobuf/api.json +0 -118
  33. package/proto/google/protobuf/api.proto +0 -34
  34. package/proto/google/protobuf/descriptor.json +0 -739
  35. package/proto/google/protobuf/descriptor.proto +0 -286
  36. package/proto/google/protobuf/source_context.json +0 -20
  37. package/proto/google/protobuf/source_context.proto +0 -7
  38. package/proto/google/protobuf/type.json +0 -202
  39. package/proto/google/protobuf/type.proto +0 -89
package/README.md CHANGED
@@ -67,3 +67,220 @@ In this case, there is no problem with when each PR is merged. It's recommendabl
67
67
  ## Comms
68
68
 
69
69
  TODO
70
+
71
+ ---
72
+
73
+ # Bitwise Serialization Plugin (`protoc-gen-bitwise`)
74
+
75
+ A custom protoc plugin that generates C# partial classes with typed float
76
+ accessors for quantized `uint32` fields in high-frequency MMO networking
77
+ messages (position deltas, player input, etc.). It runs alongside
78
+ `--csharp_out` in the same protoc invocation; the two output files coexist
79
+ via C# `partial class`.
80
+
81
+ ## How it works
82
+
83
+ Protobuf encodes `uint32` values as varints, which are already compact for
84
+ small values: a value up to 2¹⁴−1 costs 2 bytes, up to 2²¹−1 costs 3 bytes.
85
+ Rather than a separate binary packing layer, the plugin leverages this:
86
+
87
+ 1. Declare quantized fields as `uint32` in the `.proto` schema and annotate
88
+ them with `[(decentraland.common.quantized)]` to specify the float range
89
+ and bit resolution.
90
+ 2. `--csharp_out` generates the standard protobuf class with the raw `uint32`
91
+ property (e.g. `PositionX`).
92
+ 3. `--bitwise_out` (this plugin) generates a `partial class` extension with a
93
+ computed float accessor (e.g. `PositionXQuantized`) that encodes/decodes
94
+ transparently via `Quantize.Encode` / `Quantize.Decode` on every access —
95
+ the raw `uint32` property remains the single source of truth (no cache to
96
+ go stale when the raw field is mutated directly).
97
+
98
+ The wire representation is a standard protobuf message — any protobuf-capable
99
+ client can read it without knowledge of the plugin.
100
+
101
+ ## Prerequisites
102
+
103
+ | Requirement | Version |
104
+ |---|---|
105
+ | Node.js | 16+ |
106
+ | `protoc` | 3.19+ |
107
+
108
+ The plugin is a dependency-free Node script — no `npm install` or extra
109
+ packages are required to run it.
110
+
111
+ ## Step 1 — Annotate your `.proto` file
112
+
113
+ Declare quantized fields as `uint32` and import `options.proto`:
114
+
115
+ ```protobuf
116
+ syntax = "proto3";
117
+
118
+ import "decentraland/common/options.proto";
119
+
120
+ package decentraland.kernel.comms.v3;
121
+
122
+ message PositionDelta {
123
+ // Float range [-100, 100] quantized to 16 bits ≈ 0.003-unit precision.
124
+ // Stored as uint32 on the wire; protobuf encodes it as a 3-byte varint.
125
+ uint32 dx = 1 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
126
+ uint32 dy = 2 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
127
+ uint32 dz = 3 [(decentraland.common.quantized) = { min: -100.0, max: 100.0, bits: 16 }];
128
+
129
+ // Unannotated uint32: protobuf varint encodes small values compactly by default.
130
+ uint32 entity_id = 4 [(decentraland.common.bit_packed) = { bits: 20 }];
131
+ }
132
+ ```
133
+
134
+ ### Annotation reference
135
+
136
+ | Annotation | Target type | Parameters | Effect |
137
+ |---|---|---|---|
138
+ | `[(decentraland.common.quantized)]` | `uint32` | `min`, `max`, `bits` | Plugin emits a `float {Name}Quantized` accessor and a `{Name}QuantizedStep` const |
139
+ | `[(decentraland.common.quantized_power)]` | `uint32` | `max`, `pow`, `bits` | Power-law quantizer over `[-max, max]`: `(bits-1)`-bit magnitude (high bits) + sign (LSB), decoded as `sign·max·u^pow`. Exact zero; `pow>1` gives fine resolution near zero, coarse near `±max`; sign in the LSB keeps small magnitudes one varint byte. `float {Name}Quantized` accessor (`Quantize.EncodePower`/`DecodePower`) |
140
+ | `[(decentraland.common.bit_packed)]` | `uint32` | `bits` | Documents the value range; protobuf handles varint compaction automatically |
141
+
142
+ ### Wire cost at worst-case (all bits set)
143
+
144
+ | Quantization bits | Max value | Varint bytes | Tag (field ≤ 15) | Total per field |
145
+ |---|---|---|---|---|
146
+ | 8 | 255 | 2 | 1 | 3 B |
147
+ | 12 | 4 095 | 2 | 1 | 3 B |
148
+ | 14 | 16 383 | 2 | 1 | 3 B |
149
+ | 16 | 65 535 | 3 | 1 | 4 B |
150
+ | 20 | 1 048 575 | 3 | 1 | 4 B |
151
+
152
+ Proto3 omits fields equal to their default value (0), so average cost is lower.
153
+
154
+ ## Step 2 — Run protoc
155
+
156
+ ```bash
157
+ protoc \
158
+ --proto_path=proto \
159
+ --proto_path=/path/to/google/protobuf/include \
160
+ --csharp_out=generated/cs \
161
+ --plugin=protoc-gen-bitwise=protoc-gen-bitwise/plugin.js \
162
+ --bitwise_out=generated/cs \
163
+ proto/decentraland/kernel/comms/v3/comms.proto
164
+ ```
165
+
166
+ > `plugin.js` carries a `#!/usr/bin/env node` shebang. On Windows, protoc
167
+ > cannot exec a `.js` directly, so point `--plugin` at a small `.cmd` wrapper
168
+ > that runs `node plugin.js`; on unix an equivalent shell script is used. Both
169
+ > consumer repos (Pulse, unity-explorer) generate this wrapper automatically.
170
+
171
+ The plugin emits one `*.Bitwise.cs` file (PascalCase, flat in the output
172
+ directory) for each `.proto` file that contains at least one `[(quantized)]`
173
+ field.
174
+
175
+ ## Step 3 — Copy the runtime
176
+
177
+ Copy `Quantize.cs` into your project:
178
+
179
+ ```
180
+ Assets/
181
+ └── Scripts/
182
+ └── Networking/
183
+ └── Bitwise/
184
+ └── Quantize.cs ← protoc-gen-bitwise/runtime/cs/Quantize.cs
185
+ ```
186
+
187
+ `Quantize.cs` lives in the `Decentraland.Networking.Bitwise` namespace and
188
+ provides the static encode/decode methods used by the generated accessors:
189
+
190
+ ```csharp
191
+ public static class Quantize
192
+ {
193
+ public static uint Encode(float value, float min, float max, int bits);
194
+ public static float Decode(uint encoded, float min, float max, int bits);
195
+ public static uint EncodePower(float value, float max, float pow, int bits);
196
+ public static float DecodePower(uint encoded, float max, float pow, int bits);
197
+ }
198
+ ```
199
+
200
+ ## Step 4 — Use the generated code
201
+
202
+ The plugin emits a `partial class` that adds float accessors on top of the
203
+ standard protobuf-generated `uint32` properties:
204
+
205
+ ```csharp
206
+ using Decentraland.Kernel.Comms.V3;
207
+
208
+ // --- Build and send ---
209
+ var delta = new PositionDelta();
210
+ delta.DxQuantized = 3.14f; // encodes to uint32, stored in delta.Dx
211
+ delta.DyQuantized = 0f;
212
+ delta.DzQuantized = -7.5f;
213
+ delta.EntityId = 42u;
214
+
215
+ byte[] bytes = delta.ToByteArray(); // standard protobuf serialization
216
+ SendOnChannel1(bytes);
217
+
218
+ // --- Receive and read ---
219
+ var received = PositionDelta.Parser.ParseFrom(receivedBytes);
220
+ if (!received.AreQuantizedFieldsInRange()) return; // reject malformed/hostile codes
221
+ float x = received.DxQuantized; // decoded from the stored uint32 on each access
222
+ float y = received.DyQuantized;
223
+ float z = received.DzQuantized;
224
+ ```
225
+
226
+ ## Generated file example
227
+
228
+ For the `comms.proto` file above the plugin emits `Comms.Bitwise.cs` (one file
229
+ per `.proto`, named after the proto file). Each quantized field gets a
230
+ `{Name}QuantizedStep` const and a float accessor; each message gets an
231
+ `AreQuantizedFieldsInRange()` guard for validating inbound wire codes:
232
+
233
+ ```csharp
234
+ // <auto-generated>
235
+ // Generated by protoc-gen-bitwise. DO NOT EDIT.
236
+ // Source: decentraland/kernel/comms/v3/comms.proto
237
+ // </auto-generated>
238
+
239
+ using Decentraland.Networking.Bitwise;
240
+
241
+ namespace Decentraland.Kernel.Comms.V3
242
+ {
243
+ public partial class PositionDelta
244
+ {
245
+ /// <summary>Coarsest quantization step of <see cref="DxQuantized"/>. Safe as an equality tolerance.</summary>
246
+ public const float DxQuantizedStep = 0.0030518044f;
247
+ /// <summary>Float accessor for <see cref="Dx"/>. Range [-100.0f, 100.0f], 16 bits, step ≈ 0.0030518.</summary>
248
+ public float DxQuantized
249
+ {
250
+ get => Quantize.Decode(Dx, -100.0f, 100.0f, 16);
251
+ set => Dx = Quantize.Encode(value, -100.0f, 100.0f, 16);
252
+ }
253
+
254
+ /// <summary>Coarsest quantization step of <see cref="DyQuantized"/>. Safe as an equality tolerance.</summary>
255
+ public const float DyQuantizedStep = 0.0030518044f;
256
+ /// <summary>Float accessor for <see cref="Dy"/>. Range [-100.0f, 100.0f], 16 bits, step ≈ 0.0030518.</summary>
257
+ public float DyQuantized
258
+ {
259
+ get => Quantize.Decode(Dy, -100.0f, 100.0f, 16);
260
+ set => Dy = Quantize.Encode(value, -100.0f, 100.0f, 16);
261
+ }
262
+
263
+ /// <summary>Coarsest quantization step of <see cref="DzQuantized"/>. Safe as an equality tolerance.</summary>
264
+ public const float DzQuantizedStep = 0.0030518044f;
265
+ /// <summary>Float accessor for <see cref="Dz"/>. Range [-100.0f, 100.0f], 16 bits, step ≈ 0.0030518.</summary>
266
+ public float DzQuantized
267
+ {
268
+ get => Quantize.Decode(Dz, -100.0f, 100.0f, 16);
269
+ set => Dz = Quantize.Encode(value, -100.0f, 100.0f, 16);
270
+ }
271
+
272
+ /// <summary>
273
+ /// True when every quantized field holds a wire code within its declared bit width
274
+ /// (<c>0 .. 2^bits-1</c>). The encoder never emits a code above this bound, so a larger
275
+ /// value is a malformed/hostile message: decoding it would land far outside the field's
276
+ /// <c>[min, max]</c> and, since the server relays raw codes verbatim, poison every observer.
277
+ /// Reject before storing or relaying. Pure integer comparison — no decode.
278
+ /// </summary>
279
+ public bool AreQuantizedFieldsInRange() =>
280
+ Dx <= 65535u
281
+ && Dy <= 65535u
282
+ && Dz <= 65535u;
283
+ }
284
+
285
+ } // namespace Decentraland.Kernel.Comms.V3
286
+ ```
@@ -120,6 +120,22 @@ export interface PlayerEmote {
120
120
  incrementalId: number;
121
121
  urn: string;
122
122
  timestamp: number;
123
+ /** true means the emote has been stopped in the sender's client */
124
+ isStopping?: boolean | undefined;
125
+ /** true when it is not the first time the looping animation plays */
126
+ isRepeating?: boolean | undefined;
127
+ /** identifies an interaction univocaly, established when the start animation is triggered */
128
+ interactionId?: number | undefined;
129
+ /** -1 means it does not use an outcome animation */
130
+ socialEmoteOutcome?: number | undefined;
131
+ /** to a social emote started by other user */
132
+ isReacting?: boolean | undefined;
133
+ /** wallet address of the user that initiated social emote */
134
+ socialEmoteInitiator?: string | undefined;
135
+ /** wallet address of the user whose avatar is the target of a directed emote */
136
+ targetAvatar?: string | undefined;
137
+ /** mask for which bones an animation applies to. */
138
+ mask?: number | undefined;
123
139
  }
124
140
  export interface SceneEmote {
125
141
  sceneEntityId: string;
@@ -139,6 +155,11 @@ export interface ProfileResponse {
139
155
  export interface Chat {
140
156
  message: string;
141
157
  timestamp: number;
158
+ /**
159
+ * Extension: optional forwarded_from to identify the original sender when
160
+ * messages are forwarded through an SFU
161
+ */
162
+ forwardedFrom?: string | undefined;
142
163
  }
143
164
  export interface Scene {
144
165
  sceneId: string;
@@ -1073,7 +1073,19 @@ var MovementCompressed;
1073
1073
  MovementCompressed.fromPartial = fromPartial;
1074
1074
  })(MovementCompressed || (exports.MovementCompressed = MovementCompressed = {}));
1075
1075
  function createBasePlayerEmote() {
1076
- return { incrementalId: 0, urn: "", timestamp: 0 };
1076
+ return {
1077
+ incrementalId: 0,
1078
+ urn: "",
1079
+ timestamp: 0,
1080
+ isStopping: undefined,
1081
+ isRepeating: undefined,
1082
+ interactionId: undefined,
1083
+ socialEmoteOutcome: undefined,
1084
+ isReacting: undefined,
1085
+ socialEmoteInitiator: undefined,
1086
+ targetAvatar: undefined,
1087
+ mask: undefined,
1088
+ };
1077
1089
  }
1078
1090
  var PlayerEmote;
1079
1091
  (function (PlayerEmote) {
@@ -1087,6 +1099,30 @@ var PlayerEmote;
1087
1099
  if (message.timestamp !== 0) {
1088
1100
  writer.uint32(29).float(message.timestamp);
1089
1101
  }
1102
+ if (message.isStopping !== undefined) {
1103
+ writer.uint32(32).bool(message.isStopping);
1104
+ }
1105
+ if (message.isRepeating !== undefined) {
1106
+ writer.uint32(40).bool(message.isRepeating);
1107
+ }
1108
+ if (message.interactionId !== undefined) {
1109
+ writer.uint32(48).int32(message.interactionId);
1110
+ }
1111
+ if (message.socialEmoteOutcome !== undefined) {
1112
+ writer.uint32(56).int32(message.socialEmoteOutcome);
1113
+ }
1114
+ if (message.isReacting !== undefined) {
1115
+ writer.uint32(64).bool(message.isReacting);
1116
+ }
1117
+ if (message.socialEmoteInitiator !== undefined) {
1118
+ writer.uint32(74).string(message.socialEmoteInitiator);
1119
+ }
1120
+ if (message.targetAvatar !== undefined) {
1121
+ writer.uint32(82).string(message.targetAvatar);
1122
+ }
1123
+ if (message.mask !== undefined) {
1124
+ writer.uint32(88).uint32(message.mask);
1125
+ }
1090
1126
  return writer;
1091
1127
  }
1092
1128
  PlayerEmote.encode = encode;
@@ -1115,6 +1151,54 @@ var PlayerEmote;
1115
1151
  }
1116
1152
  message.timestamp = reader.float();
1117
1153
  continue;
1154
+ case 4:
1155
+ if (tag !== 32) {
1156
+ break;
1157
+ }
1158
+ message.isStopping = reader.bool();
1159
+ continue;
1160
+ case 5:
1161
+ if (tag !== 40) {
1162
+ break;
1163
+ }
1164
+ message.isRepeating = reader.bool();
1165
+ continue;
1166
+ case 6:
1167
+ if (tag !== 48) {
1168
+ break;
1169
+ }
1170
+ message.interactionId = reader.int32();
1171
+ continue;
1172
+ case 7:
1173
+ if (tag !== 56) {
1174
+ break;
1175
+ }
1176
+ message.socialEmoteOutcome = reader.int32();
1177
+ continue;
1178
+ case 8:
1179
+ if (tag !== 64) {
1180
+ break;
1181
+ }
1182
+ message.isReacting = reader.bool();
1183
+ continue;
1184
+ case 9:
1185
+ if (tag !== 74) {
1186
+ break;
1187
+ }
1188
+ message.socialEmoteInitiator = reader.string();
1189
+ continue;
1190
+ case 10:
1191
+ if (tag !== 82) {
1192
+ break;
1193
+ }
1194
+ message.targetAvatar = reader.string();
1195
+ continue;
1196
+ case 11:
1197
+ if (tag !== 88) {
1198
+ break;
1199
+ }
1200
+ message.mask = reader.uint32();
1201
+ continue;
1118
1202
  }
1119
1203
  if ((tag & 7) === 4 || tag === 0) {
1120
1204
  break;
@@ -1129,6 +1213,14 @@ var PlayerEmote;
1129
1213
  incrementalId: isSet(object.incrementalId) ? Number(object.incrementalId) : 0,
1130
1214
  urn: isSet(object.urn) ? String(object.urn) : "",
1131
1215
  timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
1216
+ isStopping: isSet(object.isStopping) ? Boolean(object.isStopping) : undefined,
1217
+ isRepeating: isSet(object.isRepeating) ? Boolean(object.isRepeating) : undefined,
1218
+ interactionId: isSet(object.interactionId) ? Number(object.interactionId) : undefined,
1219
+ socialEmoteOutcome: isSet(object.socialEmoteOutcome) ? Number(object.socialEmoteOutcome) : undefined,
1220
+ isReacting: isSet(object.isReacting) ? Boolean(object.isReacting) : undefined,
1221
+ socialEmoteInitiator: isSet(object.socialEmoteInitiator) ? String(object.socialEmoteInitiator) : undefined,
1222
+ targetAvatar: isSet(object.targetAvatar) ? String(object.targetAvatar) : undefined,
1223
+ mask: isSet(object.mask) ? Number(object.mask) : undefined,
1132
1224
  };
1133
1225
  }
1134
1226
  PlayerEmote.fromJSON = fromJSON;
@@ -1137,6 +1229,14 @@ var PlayerEmote;
1137
1229
  message.incrementalId !== undefined && (obj.incrementalId = Math.round(message.incrementalId));
1138
1230
  message.urn !== undefined && (obj.urn = message.urn);
1139
1231
  message.timestamp !== undefined && (obj.timestamp = message.timestamp);
1232
+ message.isStopping !== undefined && (obj.isStopping = message.isStopping);
1233
+ message.isRepeating !== undefined && (obj.isRepeating = message.isRepeating);
1234
+ message.interactionId !== undefined && (obj.interactionId = Math.round(message.interactionId));
1235
+ message.socialEmoteOutcome !== undefined && (obj.socialEmoteOutcome = Math.round(message.socialEmoteOutcome));
1236
+ message.isReacting !== undefined && (obj.isReacting = message.isReacting);
1237
+ message.socialEmoteInitiator !== undefined && (obj.socialEmoteInitiator = message.socialEmoteInitiator);
1238
+ message.targetAvatar !== undefined && (obj.targetAvatar = message.targetAvatar);
1239
+ message.mask !== undefined && (obj.mask = Math.round(message.mask));
1140
1240
  return obj;
1141
1241
  }
1142
1242
  PlayerEmote.toJSON = toJSON;
@@ -1145,11 +1245,19 @@ var PlayerEmote;
1145
1245
  }
1146
1246
  PlayerEmote.create = create;
1147
1247
  function fromPartial(object) {
1148
- var _a, _b, _c;
1248
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1149
1249
  const message = createBasePlayerEmote();
1150
1250
  message.incrementalId = (_a = object.incrementalId) !== null && _a !== void 0 ? _a : 0;
1151
1251
  message.urn = (_b = object.urn) !== null && _b !== void 0 ? _b : "";
1152
1252
  message.timestamp = (_c = object.timestamp) !== null && _c !== void 0 ? _c : 0;
1253
+ message.isStopping = (_d = object.isStopping) !== null && _d !== void 0 ? _d : undefined;
1254
+ message.isRepeating = (_e = object.isRepeating) !== null && _e !== void 0 ? _e : undefined;
1255
+ message.interactionId = (_f = object.interactionId) !== null && _f !== void 0 ? _f : undefined;
1256
+ message.socialEmoteOutcome = (_g = object.socialEmoteOutcome) !== null && _g !== void 0 ? _g : undefined;
1257
+ message.isReacting = (_h = object.isReacting) !== null && _h !== void 0 ? _h : undefined;
1258
+ message.socialEmoteInitiator = (_j = object.socialEmoteInitiator) !== null && _j !== void 0 ? _j : undefined;
1259
+ message.targetAvatar = (_k = object.targetAvatar) !== null && _k !== void 0 ? _k : undefined;
1260
+ message.mask = (_l = object.mask) !== null && _l !== void 0 ? _l : undefined;
1153
1261
  return message;
1154
1262
  }
1155
1263
  PlayerEmote.fromPartial = fromPartial;
@@ -1421,7 +1529,7 @@ var ProfileResponse;
1421
1529
  ProfileResponse.fromPartial = fromPartial;
1422
1530
  })(ProfileResponse || (exports.ProfileResponse = ProfileResponse = {}));
1423
1531
  function createBaseChat() {
1424
- return { message: "", timestamp: 0 };
1532
+ return { message: "", timestamp: 0, forwardedFrom: undefined };
1425
1533
  }
1426
1534
  var Chat;
1427
1535
  (function (Chat) {
@@ -1432,6 +1540,9 @@ var Chat;
1432
1540
  if (message.timestamp !== 0) {
1433
1541
  writer.uint32(17).double(message.timestamp);
1434
1542
  }
1543
+ if (message.forwardedFrom !== undefined) {
1544
+ writer.uint32(26).string(message.forwardedFrom);
1545
+ }
1435
1546
  return writer;
1436
1547
  }
1437
1548
  Chat.encode = encode;
@@ -1454,6 +1565,12 @@ var Chat;
1454
1565
  }
1455
1566
  message.timestamp = reader.double();
1456
1567
  continue;
1568
+ case 3:
1569
+ if (tag !== 26) {
1570
+ break;
1571
+ }
1572
+ message.forwardedFrom = reader.string();
1573
+ continue;
1457
1574
  }
1458
1575
  if ((tag & 7) === 4 || tag === 0) {
1459
1576
  break;
@@ -1467,6 +1584,7 @@ var Chat;
1467
1584
  return {
1468
1585
  message: isSet(object.message) ? String(object.message) : "",
1469
1586
  timestamp: isSet(object.timestamp) ? Number(object.timestamp) : 0,
1587
+ forwardedFrom: isSet(object.forwardedFrom) ? String(object.forwardedFrom) : undefined,
1470
1588
  };
1471
1589
  }
1472
1590
  Chat.fromJSON = fromJSON;
@@ -1474,6 +1592,7 @@ var Chat;
1474
1592
  const obj = {};
1475
1593
  message.message !== undefined && (obj.message = message.message);
1476
1594
  message.timestamp !== undefined && (obj.timestamp = message.timestamp);
1595
+ message.forwardedFrom !== undefined && (obj.forwardedFrom = message.forwardedFrom);
1477
1596
  return obj;
1478
1597
  }
1479
1598
  Chat.toJSON = toJSON;
@@ -1482,10 +1601,11 @@ var Chat;
1482
1601
  }
1483
1602
  Chat.create = create;
1484
1603
  function fromPartial(object) {
1485
- var _a, _b;
1604
+ var _a, _b, _c;
1486
1605
  const message = createBaseChat();
1487
1606
  message.message = (_a = object.message) !== null && _a !== void 0 ? _a : "";
1488
1607
  message.timestamp = (_b = object.timestamp) !== null && _b !== void 0 ? _b : 0;
1608
+ message.forwardedFrom = (_c = object.forwardedFrom) !== null && _c !== void 0 ? _c : undefined;
1489
1609
  return message;
1490
1610
  }
1491
1611
  Chat.fromPartial = fromPartial;