@@ -18,6 +18,7 @@ enum struct FileEnum
1818 any Data ;
1919
2020 int Id ;
21+ int Timeout ;
2122}
2223
2324Handle SDKGetPlayerNetInfo ;
@@ -39,7 +40,7 @@ char CurrentlySending[MAXPLAYERS+1][PLATFORM_MAX_PATH];
3940ArrayList RequestListing ;
4041Handle RequestingTimer [MAXPLAYERS +1 ];
4142int CurrentlyRequesting [MAXPLAYERS +1 ] = {- 1 , ...};
42- int StartedRequestingAt [MAXPLAYERS +1 ];
43+ int FailRequestingAt [MAXPLAYERS +1 ];
4344
4445methodmap CNetChan
4546{
@@ -211,8 +212,6 @@ public void OnPluginStart()
211212 failed = true ;
212213 }
213214
214- //THIS ONLY WORKS ON WINDOWS!!!!!!
215- //linux uses a different solution, timeout logic.
216215 detour = DynamicDetour .FromConf (gamedata , " CGameClient::FileDenied" );
217216 if (detour )
218217 {
@@ -349,121 +348,145 @@ public MRESReturn OnFileReceived(Address address, DHookParam param)
349348
350349 RequestListing .Erase (i );
351350 CallRequestFileFinish (info , true );
352-
353- if ( RequestingTimer [info .Client ])
354- TriggerTimer ( RequestingTimer [ info .Client ] );
351+
352+ delete RequestingTimer [info .Client ];
353+ SendNextRequest ( info .Client );
355354
356355 break ;
357356 }
358357 }
359358 return MRES_Ignored ;
360359}
361360
362- void StartRequestingClient (int client )
363- {
364- if (! RequestingTimer [client ])
365- {
366- RequestingTimer [client ] = CreateTimer (1.0 , Timer_RequestingClient , client , TIMER_REPEAT );
367- TriggerTimer (RequestingTimer [client ]);
368- }
369- }
370-
371- public Action Timer_RequestingClient (Handle timer , int client )
361+ public MRESReturn OnFileDenied (Address address , DHookParam param )
372362{
373- CNetChan chan = CNetChan (client );
374- if (! chan )
375- return Plugin_Continue ;
376-
377- static FileEnum info ;
378-
379- if (CurrentlyRequesting [client ] != - 1 )
380- {
381- // Client still giving this file
382- if ((StartedRequestingAt [client ] + TIMEOUT_PERIOD ) > GetTime ())
383- return Plugin_Continue ;
384-
385- // We timed out, this can be a case of the client getting stuck.
386- // Request a different file to unstuck the client then try again.
387- DeleteFile (" download/scripts/cheatcodes.txt" );
388-
389- info .Client = client ;
390- strcopy (info .Filename , sizeof (info .Filename ), " scripts/cheatcodes.txt" );
391- info .Func = INVALID_FUNCTION ;
392- info .Id = chan .RequestFile (info .Filename );
393- RequestListing .PushArray (info );
394-
395- CurrentlyRequesting [client ] = info .Id ;
396- StartedRequestingAt [client ] += 10 ;
397- return Plugin_Continue ;
398- }
363+ int id = param .Get (2 );
364+ CNetChan chan = SDKCall (SDKGetNetChannel , address );
399365
400366 int length = RequestListing .Length ;
401367 for (int i ; i < length ; i ++ )
402368 {
369+ static FileEnum info ;
403370 RequestListing .GetArray (i , info );
404- if (info .Client == client )
371+ if (info .Id == id && chan == CNetChan ( info . Client ) )
405372 {
406- info .Id = chan .RequestFile (info .Filename );
407- RequestListing .SetArray (i , info );
408-
409- CurrentlyRequesting [client ] = info .Id ;
410- StartedRequestingAt [client ] = GetTime ();
411- float CurrentClientPing = GetClientAvgLatency (client , NetFlow_Outgoing );
412- CurrentClientPing *= 2.0 ; //beacuse it has to go bothways.
413- CurrentClientPing += 0.2 ; //Little buffer for ping issues and differences
414- Handle pack ;
415- CreateDataTimer (CurrentClientPing , Timer_DeniedFileCheck , pack );
416- WritePackCell (pack , client ); //Client
417- WritePackCell (pack , info .Id ); //The id that we ask for
418- return Plugin_Continue ;
419- }
420- }
373+ if (CurrentlyRequesting [info .Client ] == id )
374+ CurrentlyRequesting [info .Client ] = - 1 ;
375+
376+ RequestListing .Erase (i );
377+ CallRequestFileFinish (info , false );
421378
422- // No more files to send
423- RequestingTimer [client ] = null ;
424- return Plugin_Stop ;
379+ delete RequestingTimer [info .Client ];
380+ SendNextRequest (info .Client );
381+
382+ break ;
383+ }
384+ }
385+ return MRES_Ignored ;
425386}
426387
427- public Action Timer_DeniedFileCheck ( Handle timer , DataPack pack )
388+ void StartRequestingClient ( int client )
428389{
429- pack .Reset ();
430- int client = pack .ReadCell ();
431- int id = pack .ReadCell ();
432- //We can presume the client didnt recieve the file if recieving didnt work out.
433- OnFileDeniedInternal (CNetChan (client ), id );
434- return Plugin_Stop ;
390+ // Small delay between requesting files, Linux Server issue
391+ if (! RequestingTimer [client ])
392+ RequestingTimer [client ] = CreateTimer (1.5 , Timer_RequestingClient , client , TIMER_REPEAT );
435393}
436394
437- public MRESReturn OnFileDenied ( Address address , DHookParam param )
395+ void SendNextRequest ( int client )
438396{
439- int id = param .Get (2 );
440- CNetChan chan = SDKCall (SDKGetNetChannel , address );
441- OnFileDeniedInternal (chan , id );
442- return MRES_Ignored ;
397+ if (CurrentlyRequesting [client ] == - 1 )
398+ {
399+ CNetChan chan = CNetChan (client );
400+ if (chan )
401+ {
402+ int length = RequestListing .Length ;
403+ for (int i ; i < length ; i ++ )
404+ {
405+ static FileEnum info ;
406+ RequestListing .GetArray (i , info );
407+ if (info .Client == client )
408+ {
409+ info .Id = chan .RequestFile (info .Filename );
410+ RequestListing .SetArray (i , info );
411+
412+ CurrentlyRequesting [client ] = info .Id ;
413+ FailRequestingAt [client ] = GetTime () + info .Timeout ;
414+ StartRequestingClient (client );
415+ break ;
416+ }
417+ }
418+ }
419+ }
420+ else
421+ {
422+ StartRequestingClient (client );
423+ }
443424}
444425
445- void OnFileDeniedInternal ( CNetChan chan , int id )
426+ public Action Timer_RequestingClient ( Handle timer , int client )
446427{
428+ if (CurrentlyRequesting [client ] == - 1 )
429+ {
430+ SendNextRequest (client );
431+ return Plugin_Continue ;
432+ }
433+
434+ // Client still giving this file
435+ if (FailRequestingAt [client ] > GetTime ())
436+ return Plugin_Continue ;
437+
438+ /*
439+ We timed out!
440+
441+ 1. This can be a case of the client getting stuck from too many missing file requests.
442+ 2. A Linux server may not get the notice that the file was missing on the client.
443+
444+ Request a different file that exists to fix issue 1,
445+ fail and return the callback to fix issue 2.
446+ */
447+
448+ CNetChan chan = CNetChan (client );
449+ if (! chan )
450+ return Plugin_Continue ;
451+
452+ static FileEnum info ;
447453 int length = RequestListing .Length ;
448454 for (int i ; i < length ; i ++ )
449455 {
450- static FileEnum info ;
451456 RequestListing .GetArray (i , info );
452- if (info .Id == id && chan == CNetChan ( info . Client ) )
457+ if (info .Id == CurrentlyRequesting [ client ] && info . Client == client )
453458 {
454- if (CurrentlyRequesting [info .Client ] == id )
455- CurrentlyRequesting [info .Client ] = - 1 ;
459+ CurrentlyRequesting [info .Client ] = - 1 ;
456460
457461 RequestListing .Erase (i );
458462 CallRequestFileFinish (info , false );
459-
460- if (RequestingTimer [info .Client ])
461- TriggerTimer (RequestingTimer [info .Client ]);
462-
463463 break ;
464464 }
465465 }
466+
467+ if (info .Plugin == null )
468+ {
469+ // We already tried unstucking with this method, don't try it again
470+ SendNextRequest (client );
471+ }
472+ else
473+ {
474+ DeleteFile (" download/scripts/cheatcodes.txt" );
475+
476+ info .Plugin = null ;
477+ info .Client = client ;
478+ strcopy (info .Filename , sizeof (info .Filename ), " scripts/cheatcodes.txt" );
479+ info .Func = INVALID_FUNCTION ;
480+ info .Id = chan .RequestFile (info .Filename );
481+ info .Timeout = 30 ;
482+ RequestListing .PushArray (info );
483+
484+ CurrentlyRequesting [client ] = info .Id ;
485+ FailRequestingAt [client ] = GetTime () + info .Timeout ;
486+ }
487+ return Plugin_Continue ;
466488}
489+
467490static void CallRequestFileFinish (const FileEnum info , bool success )
468491{
469492 if (info .Func && info .Func != INVALID_FUNCTION )
@@ -635,6 +658,7 @@ public any Native_RequestFile(Handle plugin, int params)
635658 info .Plugin = plugin ;
636659 info .Func = GetNativeFunction (3 );
637660 info .Data = GetNativeCell (4 );
661+ info .Timeout = params < 5 ? TIMEOUT_PERIOD : GetNativeCell (5 );
638662
639663 RequestListing .PushArray (info );
640664
0 commit comments