@@ -3,26 +3,40 @@ import { promisify } from "util";
33import { Request , Response } from "express" ;
44import { 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+
2640type 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