@@ -77,7 +77,7 @@ Convar gCV_PlaybackPreRunTime = null;
7777Convar gCV_PreRunAlways = null ;
7878Convar gCV_TimeLimit = null ;
7979
80- Handle gH_ShouldSaveReplayCopy = null ;
80+ Handle gH_AddAdditionalReplayPathsHere = null ;
8181Handle gH_OnReplaySaved = null ;
8282
8383bool gB_RecordingEnabled [MAXPLAYERS +1 ]; // just a simple thing to prevent plugin reloads from recording half-replays
@@ -100,6 +100,8 @@ bool gB_HijackFramesKeepOnStart[MAXPLAYERS+1];
100100bool gB_ReplayPlayback = false ;
101101bool gB_Floppy = false ;
102102
103+ ArrayList gA_PathsToSaveReplayTo = null ;
104+
103105//#include <TickRateControl>
104106forward void TickRate_OnTickRateChanged (float fOld , float fNew );
105107
@@ -111,6 +113,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
111113 CreateNative (" Shavit_HijackAngles" , Native_HijackAngles );
112114 CreateNative (" Shavit_SetReplayData" , Native_SetReplayData );
113115 CreateNative (" Shavit_SetPlayerPreFrames" , Native_SetPlayerPreFrames );
116+ CreateNative (" Shavit_AlsoSaveReplayTo" , Native_AlsoSaveReplayTo );
114117
115118 if (! FileExists (" cfg/sourcemod/plugin.shavit-replay-recorder.cfg" ) && FileExists (" cfg/sourcemod/plugin.shavit-replay.cfg" ))
116119 {
@@ -140,8 +143,8 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
140143
141144public void OnPluginStart ()
142145{
143- gH_ShouldSaveReplayCopy = CreateGlobalForward (" Shavit_ShouldSaveReplayCopy " , ET_Event , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell );
144- gH_OnReplaySaved = CreateGlobalForward (" Shavit_OnReplaySaved" , ET_Ignore , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_String , Param_Cell , Param_Cell , Param_Cell , Param_String );
146+ gH_AddAdditionalReplayPathsHere = CreateGlobalForward (" Shavit_AddAdditionalReplayPathsHere " , ET_Ignore , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell );
147+ gH_OnReplaySaved = CreateGlobalForward (" Shavit_OnReplaySaved" , ET_Ignore , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_Cell , Param_String );
145148
146149 gCV_Enabled = new Convar (" shavit_replay_recording_enabled" , " 1" , " Enable replay bot functionality?" , 0 , true , 0.0 , true , 1.0 );
147150 gCV_PlaybackPostRunTime = new Convar (" shavit_replay_postruntime" , " 1.5" , " Time (in seconds) to record after a player enters the end zone." , 0 , true , 0.0 , true , 2.0 );
@@ -360,8 +363,22 @@ void DoReplaySaverCallbacks(int iSteamID, int client, int style, float time, int
360363 float length = ExistingWrReplayLength (style , track );
361364 bool isBestReplay = (length == 0.0 || time < length );
362365
363- Action action = Plugin_Continue ;
364- Call_StartForward (gH_ShouldSaveReplayCopy );
366+ delete gA_PathsToSaveReplayTo ;
367+ ArrayList paths = gA_PathsToSaveReplayTo = new ArrayList (ByteCountToCells (PLATFORM_MAX_PATH ));
368+
369+ bool makeReplay = (isBestReplay && ! isTooLong );
370+
371+ if (makeReplay )
372+ {
373+ char wrpath [PLATFORM_MAX_PATH ];
374+ FormatEx (wrpath , sizeof (wrpath ),
375+ track > 0 ? " %s /%d /%s _%d .replay" : " %s /%d /%s .replay" ,
376+ gS_ReplayFolder , style , gS_Map , track
377+ );
378+ paths .PushString (wrpath );
379+ }
380+
381+ Call_StartForward (gH_AddAdditionalReplayPathsHere );
365382 Call_PushCell (client );
366383 Call_PushCell (style );
367384 Call_PushCell (time );
@@ -376,12 +393,11 @@ void DoReplaySaverCallbacks(int iSteamID, int client, int style, float time, int
376393 Call_PushCell (timestamp );
377394 Call_PushCell (isBestReplay );
378395 Call_PushCell (isTooLong );
379- Call_Finish (action );
396+ Call_Finish ();
380397
381- bool makeCopy = (action != Plugin_Continue );
382- bool makeReplay = (isBestReplay && ! isTooLong );
398+ gA_PathsToSaveReplayTo = null ;
383399
384- if (! makeCopy && ! makeReplay )
400+ if (paths . Length == 0 )
385401 {
386402 return ;
387403 }
@@ -409,48 +425,51 @@ void DoReplaySaverCallbacks(int iSteamID, int client, int style, float time, int
409425 dp .WriteCell (timestamp );
410426 dp .WriteCell (isBestReplay );
411427 dp .WriteCell (isTooLong );
412- dp .WriteCell (makeCopy );
428+ dp .WriteCell (paths );
413429 dp .WriteCell (playerrecording );
414430 dp .WriteCell (gI_PlayerPrerunFrames [client ]);
415431 dp .WriteCell (postframes );
416432 dp .WriteString (sName );
417433
418434 if (gB_Floppy )
419435 {
420- char buf [512 ];
421- int headersize = WriteReplayHeaderToBuffer (buf , style , track , time , iSteamID , gI_PlayerPrerunFrames [client ], postframes , fZoneOffset , gI_PlayerFrames [client ], gF_Tickrate , gS_Map );
422-
423- char wrpath [PLATFORM_MAX_PATH ], copypath [PLATFORM_MAX_PATH ];
424- if (makeReplay )
425- FormatEx (wrpath , sizeof (wrpath ),
426- track > 0 ? " %s /%d /%s _%d .replay" : " %s /%d /%s .replay" ,
427- gS_ReplayFolder , style , gS_Map , track
428- );
429- if (makeCopy )
430- FormatEx (copypath , sizeof (copypath ), " %s /copy/%d _%d _%s .replay" , gS_ReplayFolder , timestamp , iSteamID , gS_Map );
436+ char headerbuf [512 ];
437+ int headersize = WriteReplayHeaderToBuffer (headerbuf , style , track , time , iSteamID , gI_PlayerPrerunFrames [client ], postframes , fZoneOffset , gI_PlayerFrames [client ], gF_Tickrate , gS_Map );
431438
432439 SRCWRFloppy_AsyncSaveReplay (
433440 FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem
434441 , dp
435- , wrpath
436- , copypath
437- , buf
442+ , paths
443+ , headerbuf
438444 , headersize
439445 , playerrecording
440446 , gI_PlayerFrames [client ]
441447 );
442448 }
443449 else
444450 {
445- char sPath [PLATFORM_MAX_PATH ];
446- bool saved = SaveReplay (style , track , time , iSteamID , gI_PlayerPrerunFrames [client ], playerrecording , gI_PlayerFrames [client ], postframes , timestamp , fZoneOffset , makeCopy , makeReplay , sPath , sizeof (sPath ));
447- FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem (saved , dp , sPath )
451+ bool saved = false ;
452+
453+ for (int i = 0 , size = paths .Length ; i < size ; ++ i )
454+ {
455+ char path [PLATFORM_MAX_PATH ], tmp [PLATFORM_MAX_PATH ];
456+ paths .GetString (i , path , sizeof (path ));
457+ FormatEx (tmp , sizeof (tmp ), " %s .tmp" , path );
458+
459+ if (SaveReplay (style , track , time , iSteamID , gI_PlayerPrerunFrames [client ], playerrecording , gI_PlayerFrames [client ], postframes , fZoneOffset , tmp ))
460+ {
461+ saved = true ;
462+ RenameFile (path , tmp );
463+ }
464+ }
465+
466+ FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem (saved , dp )
448467 }
449468
450469 ClearFrames (client );
451470}
452471
453- void FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem (bool saved , any value , char [] sPath )
472+ void FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem (bool saved , any value )
454473{
455474 DataPack dp = value ;
456475 dp .Reset ();
@@ -469,7 +488,7 @@ void FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem(bool saved, any value,
469488 int timestamp = dp .ReadCell ();
470489 bool isBestReplay = dp .ReadCell ();
471490 bool isTooLong = dp .ReadCell ();
472- bool makeCopy = dp .ReadCell ();
491+ ArrayList paths = dp .ReadCell ();
473492 ArrayList playerrecording = dp .ReadCell ();
474493 int preframes = dp .ReadCell ();
475494 int postframes = dp .ReadCell ();
@@ -498,8 +517,7 @@ void FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem(bool saved, any value,
498517 Call_PushCell (timestamp );
499518 Call_PushCell (isBestReplay );
500519 Call_PushCell (isTooLong );
501- Call_PushCell (makeCopy );
502- Call_PushString (sPath );
520+ Call_PushCell (paths );
503521 Call_PushCell (playerrecording );
504522 Call_PushCell (preframes );
505523 Call_PushCell (postframes );
@@ -556,66 +574,19 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
556574 }
557575}
558576
559- bool SaveReplay (int style , int track , float time , int steamid , int preframes , ArrayList playerrecording , int iSize , int postframes , int timestamp , float fZoneOffset [2 ], bool saveCopy , bool saveWR , char [] sPath , int sPathLen )
577+ bool SaveReplay (int style , int track , float time , int steamid , int preframes , ArrayList playerrecording , int iSize , int postframes , float fZoneOffset [2 ], const char [] sPath )
560578{
561- char sTrack [4 ];
562- FormatEx (sTrack , 4 , " _%d " , track );
579+ File fReplay = null ;
563580
564- File fWR = null ;
565- File fCopy = null ;
566-
567- if (saveCopy )
568- {
569- FormatEx (sPath , sPathLen , " %s /copy/%d _%d _%s .replay" , gS_ReplayFolder , timestamp , steamid , gS_Map );
570-
571- if (! (fCopy = OpenFile (sPath , " wb+" )))
572- {
573- LogError (" Failed to open 'copy' replay file for writing. ('%s ')" , sPath );
574- }
581+ if (! (fReplay = OpenFile (sPath , " wb+" ))) {
582+ LogError (" Failed to open replay file for writing. ('%s ')" , sPath );
583+ return false ;
575584 }
576585
577- if (saveWR )
578- {
579- FormatEx (sPath , sPathLen , " %s /%d /%s%s .replay" , gS_ReplayFolder , style , gS_Map , (track > 0 )? sTrack : " " );
586+ WriteReplayHeader (fReplay , style , track , time , steamid , preframes , postframes , fZoneOffset , iSize , gF_Tickrate , gS_Map );
587+ WriteReplayFrames (playerrecording , iSize , fReplay );
580588
581- if (! (fWR = OpenFile (sPath , " wb+" )))
582- {
583- LogError (" Failed to open WR replay file for writing. ('%s ')" , sPath );
584- }
585- }
586-
587- if (! fWR && ! fCopy )
588- {
589- // I want to try and salvage the replay file so let's write it out to a random
590- // file and hope people read the error log to figure out what happened...
591- // I'm not really sure how we could reach this though as
592- // `Shavit_Replay_CreateDirectories` should have failed if it couldn't create
593- // a test file.
594- FormatEx (sPath , sPathLen , " %s /%d _%s%s _%d .replay" , gS_ReplayFolder , style , gS_Map , sTrack , iSize - preframes - postframes );
595-
596- if (! (fWR = OpenFile (sPath , " wb+" )))
597- {
598- LogError (" Couldn't open a WR, 'copy', or 'salvage' replay file...." );
599- return false ;
600- }
601-
602- LogError (" Couldn't open a WR or 'copy' replay file. Writing 'salvage' replay @ (style %d ) '%s '" , style , sPath );
603- }
604-
605- if (fWR )
606- {
607- WriteReplayHeader (fWR , style , track , time , steamid , preframes , postframes , fZoneOffset , iSize , gF_Tickrate , gS_Map );
608- }
609-
610- if (fCopy )
611- {
612- WriteReplayHeader (fCopy , style , track , time , steamid , preframes , postframes , fZoneOffset , iSize , gF_Tickrate , gS_Map );
613- }
614-
615- WriteReplayFrames (playerrecording , iSize , fWR , fCopy );
616-
617- delete fWR ;
618- delete fCopy ;
589+ delete fReplay ;
619590 return true ;
620591}
621592
@@ -722,6 +693,17 @@ public int Native_SetPlayerPreFrames(Handle handler, int numParams)
722693 return 1 ;
723694}
724695
696+ public int Native_AlsoSaveReplayTo (Handle plugin , int numParams )
697+ {
698+ if (gA_PathsToSaveReplayTo )
699+ {
700+ char path [PLATFORM_MAX_PATH ];
701+ GetNativeString (1 , path , sizeof (path ));
702+ gA_PathsToSaveReplayTo .PushString (path );
703+ }
704+ return 0 ; // native has void return so this value doesn't matter.
705+ }
706+
725707public int Native_GetReplayData (Handle plugin , int numParams )
726708{
727709 int client = GetNativeCell (1 );
0 commit comments