Skip to content

Commit eb079a6

Browse files
committed
add Shavit_AdditionalReplayPath, edit & rename Shavit_ShouldSaveReplayCopy to Shavit_AddAdditionalReplayPathsHere, edit Shavit_OnReplaySaved, edit WriteReplayFrames, and make compatible with srcwr💾 v4.0.0
1 parent 8ceacc4 commit eb079a6

File tree

6 files changed

+88
-111
lines changed

6 files changed

+88
-111
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ jobs:
3636
wget https://github.com/srcwr/eventqueuefixfix/releases/download/v1.0.1/eventqueuefixfix-v1.0.1-def5b0e-windows-x32.zip
3737
unzip eventqueuefixfix-v1.0.1-def5b0e-windows-x32.zip "addons/sourcemod/extensions/*"
3838
rm "addons/sourcemod/extensions/eventqueuefixfix.pdb"
39-
wget https://github.com/srcwr/srcwrfloppy/releases/download/v2.0.4/srcwrfloppy-v2.0.4.zip
40-
unzip -qO UTF-8 srcwrfloppy-v2.0.4.zip "addons/sourcemod/extensions/*"
39+
wget https://github.com/srcwr/srcwrfloppy/releases/download/v4.0.0/srcwrfloppy-v4.0.0.zip
40+
unzip -qO UTF-8 srcwrfloppy-v4.0.0.zip "addons/sourcemod/extensions/*"
4141
rm "addons/sourcemod/extensions/srcwr💾.pdb"
4242
4343
- name: Run compiler

addons/sourcemod/scripting/include/shavit/replay-file.inc

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,7 @@ stock int WriteReplayHeaderToBuffer(char[] buf, int style, int track, float time
390390
return pos;
391391
}
392392

393-
// file_a is usually used as the wr replay file.
394-
// file_b is usually used as the duplicate/backup replay file.
395-
stock void WriteReplayFrames(ArrayList playerrecording, int iSize, File file_a, File file_b)
393+
stock void WriteReplayFrames(ArrayList playerrecording, int iSize, File replayfile)
396394
{
397395
any aFrameData[sizeof(frame_t)];
398396
any aWriteData[sizeof(frame_t) * REPLAY_FRAMES_PER_WRITE];
@@ -409,16 +407,7 @@ stock void WriteReplayFrames(ArrayList playerrecording, int iSize, File file_a,
409407

410408
if(++iFramesWritten == REPLAY_FRAMES_PER_WRITE || i == iSize - 1)
411409
{
412-
if (file_a)
413-
{
414-
file_a.Write(aWriteData, sizeof(frame_t) * iFramesWritten, 4);
415-
}
416-
417-
if (file_b)
418-
{
419-
file_b.Write(aWriteData, sizeof(frame_t) * iFramesWritten, 4);
420-
}
421-
410+
replayfile.Write(aWriteData, sizeof(frame_t) * iFramesWritten, 4);
422411
iFramesWritten = 0;
423412
}
424413
}

addons/sourcemod/scripting/include/shavit/replay-recorder.inc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@
2424
#endif
2525
#define _shavit_replay_recorder_included
2626

27+
/**
28+
* If you want to save a replay to an additional path, then call this inside of `Shavit_AddAdditionalReplayPathsHere()`.
29+
*
30+
* @param path The additional path to save the replay to.
31+
*/
32+
native void Shavit_AdditionalReplayPath(const char[] path);
33+
2734
/**
2835
* Called when a player finishes a time. Allows you to save a replay even if the run is not a WR.
36+
* To save replay to additional paths, call `Shavit_AdditionalReplayPath()`
2937
*
3038
* @param client Client index.
3139
* @param style Style the record was done on.
@@ -42,9 +50,9 @@
4250
* @param isbestreplay If the time is the new replay.
4351
* @param istoolong If the time is too long to save a replay if the time is a WR. Note: replays WON'T be full length if this is true.
4452
*
45-
* @return Return Plugin_Changed (or higher) to cause a copy of the replay to be saved. Return Plugin_Continue otherwise.
53+
* @noreturn
4654
*/
47-
forward Action Shavit_ShouldSaveReplayCopy(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong);
55+
forward void Shavit_AddAdditionalReplayPathsHere(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong);
4856

4957
/**
5058
* Called when either a WR replay or a copy of a replay has been saved.
@@ -64,16 +72,15 @@ forward Action Shavit_ShouldSaveReplayCopy(int client, int style, float time, in
6472
* @param timestamp System time of when player finished.
6573
* @param isbestreplay If the time is the new replay.
6674
* @param istoolong If the time is too long to save a replay if the time is a WR. Note: replays WON'T be full length if this is true.
67-
* @param iscopy If the path points to a copy of the replay.
68-
* @param replaypath Path to the saved replay.
75+
* @param replaypaths ArrayList of the paths the replay was saved to. If isbestreplay&&!istoolong then the 0th index will be the WR path.
6976
* @param frames ArrayList of the player's frames in the replay.
7077
* @param preframes The number of preframes in the replay.
7178
* @param postframes The number of postframes in the replay.
7279
* @param name Player's name at the time of the replay.
7380
*
7481
* @noreturn
7582
*/
76-
forward void Shavit_OnReplaySaved(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong, bool iscopy, const char[] replaypath, ArrayList frames, int preframes, int postframes, const char[] name);
83+
forward void Shavit_OnReplaySaved(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong, ArrayList replaypaths, ArrayList frames, int preframes, int postframes, const char[] name);
7784

7885
/**
7986
* Retrieves a client's frame count.

addons/sourcemod/scripting/include/srcwr/floppy.inc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@
99

1010

1111
typeset ReplaySavedCallback {
12-
function void(bool saved, any value, char[] sPath);
12+
function void(bool saved, any value);
1313
}
1414

1515

1616
// Don't modify the `playerrecording` ArrayList until the ReplaySavedCallback is called... OR ELSE!!!!
1717
native void SRCWRFloppy_AsyncSaveReplay(
1818
ReplaySavedCallback callback // what to call when saved
1919
, any value // what to pass along to the callback
20-
, char[] wrpath
21-
, char[] copypath
20+
, ArrayList paths
2221
, char[] header
2322
, int headersize
2423
, ArrayList playerrecording

addons/sourcemod/scripting/shavit-replay-playback.sp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,7 +1696,7 @@ public void Shavit_OnStyleChanged(int client, int oldstyle, int newstyle, int tr
16961696
gI_TimeDifferenceStyle[client] = newstyle;
16971697
}
16981698

1699-
public void Shavit_OnReplaySaved(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong, bool iscopy, const char[] replaypath, ArrayList frames, int preframes, int postframes, const char[] name)
1699+
public void Shavit_OnReplaySaved(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong, ArrayList paths, ArrayList frames, int preframes, int postframes, const char[] name)
17001700
{
17011701
if (!isbestreplay || istoolong)
17021702
{
@@ -2763,7 +2763,7 @@ public void Player_Event(Event event, const char[] name, bool dontBroadcast)
27632763
KickReplay(gA_BotInfo[index]);
27642764
}
27652765
}
2766-
2766+
27672767
if(IsPlayerAlive(client) && gB_InReplayMenu[client])
27682768
{
27692769
CancelClientMenu(client);

addons/sourcemod/scripting/shavit-replay-recorder.sp

Lines changed: 68 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Convar gCV_PlaybackPreRunTime = null;
7777
Convar gCV_PreRunAlways = null;
7878
Convar gCV_TimeLimit = null;
7979

80-
Handle gH_ShouldSaveReplayCopy = null;
80+
Handle gH_AddAdditionalReplayPathsHere = null;
8181
Handle gH_OnReplaySaved = null;
8282

8383
bool 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];
100100
bool gB_ReplayPlayback = false;
101101
bool gB_Floppy = false;
102102

103+
ArrayList gA_PathsToSaveReplayTo = null;
104+
103105
//#include <TickRateControl>
104106
forward 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

141144
public 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+
725707
public int Native_GetReplayData(Handle plugin, int numParams)
726708
{
727709
int client = GetNativeCell(1);

0 commit comments

Comments
 (0)