Skip to content

Commit a3a3e71

Browse files
committed
wip
1 parent 3483f42 commit a3a3e71

1 file changed

Lines changed: 79 additions & 39 deletions

File tree

src/matches/match-relay/match-relay.service.ts

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,40 @@ import { promisify } from "util";
33
import { Request, Response } from "express";
44
import { Injectable, Logger } from "@nestjs/common";
55

6-
type FieldData = {
6+
type StartFieldData = {
77
data?: Buffer;
88
gipped?: boolean;
9-
};
10-
11-
type Fragment = {
12-
start?: FieldData;
13-
full?: FieldData;
14-
delta?: FieldData;
15-
tick?: number;
16-
endtick?: number;
17-
timestamp?: number;
189
signup_fragment?: number;
10+
tick?: number;
1911
tps?: number;
20-
keyframe_interval?: number;
2112
map?: string;
13+
keyframe_interval?: number;
2214
protocol?: number;
2315
[key: string]: any;
2416
};
2517

18+
type FullFieldData = {
19+
data?: Buffer;
20+
gipped?: boolean;
21+
tick?: number;
22+
[key: string]: any;
23+
};
24+
25+
type DeltaFieldData = {
26+
data?: Buffer;
27+
gipped?: boolean;
28+
timestamp?: number;
29+
endtick?: number;
30+
[key: string]: any;
31+
};
32+
33+
type Fragment = {
34+
start?: StartFieldData;
35+
full?: FullFieldData;
36+
delta?: DeltaFieldData;
37+
[key: string]: any;
38+
};
39+
2640
type Broadcast = Fragment[];
2741

2842
@Injectable()
@@ -38,7 +52,7 @@ export class MatchRelayService {
3852

3953
if (
4054
broadcast?.[0] == null ||
41-
broadcast[0].signup_fragment != fragmentIndex
55+
broadcast[0].start?.signup_fragment != fragmentIndex
4256
) {
4357
return this.relayError(
4458
response,
@@ -114,7 +128,7 @@ export class MatchRelayService {
114128

115129
if (
116130
fragmentIndex >= 0 &&
117-
fragmentIndex >= match_field_0.signup_fragment
131+
fragmentIndex >= (match_field_0.start?.signup_fragment || 0)
118132
) {
119133
const _fragment = broadcast[fragmentIndex];
120134
if (this.isSyncReady(_fragment)) {
@@ -124,8 +138,8 @@ export class MatchRelayService {
124138
} else {
125139
fragmentIndex = parseInt(fragmentParam);
126140

127-
if (fragmentIndex < match_field_0.signup_fragment) {
128-
fragmentIndex = match_field_0.signup_fragment;
141+
if (fragmentIndex < (match_field_0.start?.signup_fragment || 0)) {
142+
fragmentIndex = match_field_0.start?.signup_fragment || 0;
129143
}
130144

131145
for (let i = fragmentIndex; i < broadcast.length; i++) {
@@ -145,25 +159,34 @@ export class MatchRelayService {
145159
}
146160

147161
response.writeHead(200, { "Content-Type": "application/json" });
148-
if (match_field_0.protocol == null) {
149-
match_field_0.protocol = 5;
162+
if (match_field_0.start?.protocol == null) {
163+
if (!match_field_0.start) {
164+
match_field_0.start = {};
165+
}
166+
match_field_0.start.protocol = 5;
150167
}
151168

169+
// Get tick/endtick from delta field (delta has endtick, full only has tick)
170+
const fragTick = frag.full?.tick;
171+
const fragEndtick = frag.delta?.endtick;
172+
const fragTimestamp = frag.delta?.timestamp;
173+
152174
response.end(
153175
JSON.stringify({
154-
tick: frag.tick,
155-
endtick: frag.endtick,
176+
tick: fragTick,
177+
endtick: fragEndtick,
156178
maxtick: this.getMatchBroadcastEndTick(broadcast),
157-
rtdelay: (nowMs - frag.timestamp) / 1000,
179+
rtdelay: (nowMs - (fragTimestamp || nowMs)) / 1000,
158180
rcvage:
159-
(nowMs - (broadcast[broadcast.length - 1]?.timestamp || nowMs)) /
181+
(nowMs -
182+
(broadcast[broadcast.length - 1]?.delta?.timestamp || nowMs)) /
160183
1000,
161184
fragment: fragmentIndex,
162-
signup_fragment: match_field_0.signup_fragment,
163-
tps: match_field_0.tps,
164-
keyframe_interval: match_field_0.keyframe_interval,
165-
map: match_field_0.map,
166-
protocol: match_field_0.protocol,
185+
signup_fragment: match_field_0.start?.signup_fragment,
186+
tps: match_field_0.start?.tps,
187+
keyframe_interval: match_field_0.start?.keyframe_interval,
188+
map: match_field_0.start?.map,
189+
protocol: match_field_0.start?.protocol,
167190
}),
168191
);
169192
}
@@ -175,7 +198,6 @@ export class MatchRelayService {
175198
matchId: string,
176199
fragmentIndex: number,
177200
): void {
178-
console.info(`${fragmentIndex} ${field}`);
179201
if (!this.broadcasts[matchId]) {
180202
this.logger.log(`Creating new match broadcast for matchId ${matchId}`);
181203
this.broadcasts[matchId] = [];
@@ -188,10 +210,13 @@ export class MatchRelayService {
188210
if (broadcast[0] == null) {
189211
broadcast[0] = {};
190212
}
213+
if (!broadcast[0].start) {
214+
broadcast[0].start = {};
215+
}
191216

192217
// Start fragments are always stored at index 0
193218
// Store the original fragment number in signup_fragment
194-
broadcast[0].signup_fragment = fragmentIndex;
219+
broadcast[0].start.signup_fragment = fragmentIndex;
195220
fragmentIndex = 0;
196221
} else {
197222
// For non-start fields, ensure start fragment exists at index 0
@@ -212,24 +237,31 @@ export class MatchRelayService {
212237
}
213238
}
214239

240+
// Initialize field data object if it doesn't exist (for start field)
241+
if (broadcast[fragmentIndex][field] == null) {
242+
broadcast[fragmentIndex][field] = {};
243+
}
244+
215245
Object.entries(request.query).forEach(([key, value]) => {
216246
const strValue = String(value);
217247
const numValue = Number(strValue);
218-
broadcast[fragmentIndex][key] =
248+
// Store query params directly in the field data object
249+
broadcast[fragmentIndex][field][key] =
219250
!isNaN(numValue) && strValue === String(numValue) ? numValue : value;
220251
});
221252

253+
console.info(`${fragmentIndex} ${field}`, broadcast[fragmentIndex][field]);
254+
222255
const body: Buffer[] = [];
223256
request.on("data", function (data: Buffer) {
224257
body.push(data);
225258
});
259+
226260
request.on("end", () => {
227261
const totalBuffer = Buffer.concat(body);
228262

229-
// Send response immediately (like old code)
230263
response.end();
231264

232-
// Initialize field data object if it doesn't exist
233265
if (broadcast[fragmentIndex][field] == null) {
234266
broadcast[fragmentIndex][field] = {};
235267
}
@@ -238,15 +270,18 @@ export class MatchRelayService {
238270
.then((compressedBlob: Buffer) => {
239271
broadcast[fragmentIndex][field].gipped = true;
240272
broadcast[fragmentIndex][field].data = compressedBlob;
241-
broadcast[fragmentIndex].timestamp = Date.now();
242273
})
243274
.catch((error: Error) => {
244275
this.logger.error(
245276
`Cannot gzip ${totalBuffer.length} bytes: ${error}`,
246277
);
247278
broadcast[fragmentIndex][field].gipped = false;
248279
broadcast[fragmentIndex][field].data = totalBuffer;
249-
broadcast[fragmentIndex].timestamp = Date.now();
280+
})
281+
.finally(() => {
282+
if (field === "delta") {
283+
broadcast[fragmentIndex][field].timestamp = Date.now();
284+
}
250285
});
251286
});
252287
}
@@ -265,17 +300,18 @@ export class MatchRelayService {
265300
fragment != null &&
266301
fragment.full?.data != null &&
267302
fragment.delta?.data != null &&
268-
fragment.tick != null &&
269-
fragment.endtick != null &&
270-
fragment.timestamp != null
303+
(fragment.full?.tick != null || fragment.delta?.tick != null) &&
304+
fragment.delta?.endtick != null &&
305+
fragment.delta?.timestamp != null
271306
);
272307
}
273308

274309
private getMatchBroadcastEndTick(broadcast: Broadcast): number {
310+
// Only delta fields have endtick, full fields don't
275311
for (let i = broadcast.length - 1; i >= 0; i--) {
276312
const fragment = broadcast[i];
277-
if (fragment?.endtick != null) {
278-
return fragment.endtick;
313+
if (fragment?.delta?.endtick != null) {
314+
return fragment.delta.endtick;
279315
}
280316
}
281317
return 0;
@@ -286,7 +322,11 @@ export class MatchRelayService {
286322
fragmentRec: Fragment | undefined,
287323
field: string,
288324
): void {
289-
const fieldData = fragmentRec?.[field] as FieldData | undefined;
325+
const fieldData = fragmentRec?.[field] as
326+
| StartFieldData
327+
| FullFieldData
328+
| DeltaFieldData
329+
| undefined;
290330
const blob = fieldData?.data;
291331

292332
if (!blob) {

0 commit comments

Comments
 (0)