From 8f1da48e823b22a032cd5d5942759a2468dc1261 Mon Sep 17 00:00:00 2001 From: shavitush Date: Fri, 10 Jul 2020 19:44:16 +0300 Subject: [PATCH] Added saving checkpoints to disk for mappers (mostly for Lily). !savecps !loadcps --- addons/sourcemod/scripting/include/shavit.inc | 3 + addons/sourcemod/scripting/shavit-misc.sp | 193 ++++++++++++++++++ addons/sourcemod/scripting/shavit-replay.sp | 1 - 3 files changed, 196 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index 6c644520..01d3a4e6 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -44,6 +44,9 @@ #define HUD_NOSOUNDS (1 << 11) // disables sounds on personal best, world record etc #define HUD_NOPRACALERT (1 << 12) // hides practice mode chat alert +// replay +#define CELLS_PER_FRAME 8 // origin[3], angles[2], buttons, flags, movetype + // status enum TimerStatus { diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index fca940a5..92604b29 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -116,6 +116,10 @@ StringMap gSM_Checkpoints = null; ArrayList gA_Targetnames = null; ArrayList gA_Classnames = null; +// checkpoint files +char gS_CPData[PLATFORM_MAX_PATH]; +char gS_MapPath[PLATFORM_MAX_PATH]; + // save states bool gB_SaveStatesSegmented[MAXPLAYERS+1]; float gF_SaveStateData[MAXPLAYERS+1][3][3]; @@ -251,6 +255,8 @@ public void OnPluginStart() RegConsoleCmd("sm_checkpoints", Command_Checkpoints, "Opens the checkpoints menu. Alias for sm_cpmenu."); RegConsoleCmd("sm_save", Command_Save, "Saves checkpoint."); RegConsoleCmd("sm_tele", Command_Tele, "Teleports to checkpoint. Usage: sm_tele [number]"); + RegConsoleCmd("sm_savecps", Command_SaveCPs, "Saves all your checkpoints data on disk"); + RegConsoleCmd("sm_loadcps", Command_LoadCPs, "Loads your checkpoint data from disk"); gH_CheckpointsCookie = RegClientCookie("shavit_checkpoints", "Checkpoints settings", CookieAccess_Protected); gSM_Checkpoints = new StringMap(); gA_Targetnames = new ArrayList(ByteCountToCells(64)); @@ -395,6 +401,13 @@ public void OnPluginStart() gB_Rankings = LibraryExists("shavit-rankings"); gB_Replay = LibraryExists("shavit-replay"); gB_Zones = LibraryExists("shavit-zones"); + + BuildPath(Path_SM, gS_CPData, PLATFORM_MAX_PATH, "data/checkpoints"); + + if(!DirExists(gS_CPData)) + { + CreateDirectory(gS_CPData, 511); + } } public void OnClientCookiesCached(int client) @@ -547,6 +560,8 @@ public void OnMapStart() { CreateTimer(gCV_AdvertisementInterval.FloatValue, Timer_Advertisement, 0, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); } + + FormatEx(gS_MapPath, PLATFORM_MAX_PATH, "%s/%s.cp", gS_CPData, gS_CurrentMap); } public void OnMapEnd() @@ -1738,6 +1753,184 @@ public Action Command_Save(int client, int args) return Plugin_Handled; } +void WriteArrayToFile(File pFile, any[] aVec, int nSize) +{ + for(int i = 0; i < nSize; i++) + { + pFile.WriteInt32(view_as(aVec[i])); + } +} + +void WriteCheckpointToFile(File pFile, int client, int nCheckpoint) +{ + cp_cache_t aCache; + GetCheckpoint(client, nCheckpoint, aCache); + + WriteArrayToFile(pFile, aCache.fPosition, 3); + WriteArrayToFile(pFile, aCache.fAngles, 3); + WriteArrayToFile(pFile, aCache.fVelocity, 3); + WriteArrayToFile(pFile, aCache.fBaseVelocity, 3); + pFile.WriteInt32(view_as(aCache.iMoveType)); + pFile.WriteInt32(view_as(aCache.fGravity)); + pFile.WriteInt32(view_as(aCache.fSpeed)); + pFile.WriteInt32(view_as(aCache.fStamina)); + pFile.WriteInt8(view_as(aCache.bDucked)); + pFile.WriteInt8(view_as(aCache.bDucking)); + pFile.WriteInt32(view_as(aCache.fDucktime)); + pFile.WriteInt32(view_as(aCache.fDuckSpeed)); + pFile.WriteInt32(view_as(aCache.iFlags)); + pFile.WriteInt8(view_as(aCache.aSnapshot.bTimerEnabled)); + pFile.WriteInt32(view_as(aCache.aSnapshot.fCurrentTime)); + pFile.WriteInt8(view_as(aCache.aSnapshot.bClientPaused)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iJumps)); + pFile.WriteInt32(view_as(aCache.aSnapshot.bsStyle)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iStrafes)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iTotalMeasures)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iGoodGains)); + pFile.WriteInt32(view_as(aCache.aSnapshot.fServerTime)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iSHSWCombination)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iTimerTrack)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iMeasuredJumps)); + pFile.WriteInt32(view_as(aCache.aSnapshot.iPerfectJumps)); + pFile.WriteInt8(view_as(aCache.bSegmented)); + pFile.WriteInt8(view_as(aCache.bPractice)); + pFile.WriteInt32(view_as(aCache.iGroundEntity)); + + int nLength = aCache.aFrames != null ? aCache.aFrames.Length : 0; + pFile.WriteInt32(nLength); + + any aData[CELLS_PER_FRAME]; + + for(int i = 0; i < nLength; i++) + { + aCache.aFrames.GetArray(i, aData, CELLS_PER_FRAME); + pFile.Write(aData, CELLS_PER_FRAME, 4); + } +} + +public Action Command_SaveCPs(int client, int args) +{ + if(client == 0) + { + return Plugin_Handled; + } + + if(FileExists(gS_MapPath)) + { + DeleteFile(gS_MapPath); + } + + File fFile = OpenFile(gS_MapPath, "wb"); + fFile.WriteInt32(gA_CheckpointsCache[client].iCheckpoints); + + for(int i = 1; i <= gA_CheckpointsCache[client].iCheckpoints; i++) + { + WriteCheckpointToFile(fFile, client, i); + } + + delete fFile; + + ReplyToCommand(client, "Saved CPs to %s", gS_MapPath); + + return Plugin_Handled; +} + +void ReadArrayFromFile(File pFile, any[] aVec, int nSize) +{ + for(int i = 0; i < nSize; i++) + { + pFile.ReadInt32(aVec[i]); + } +} + +void ReadCheckpointFromFile(File pFile, int client, int nCheckpoint) +{ + cp_cache_t aCache; + ReadArrayFromFile(pFile, aCache.fPosition, 3); + ReadArrayFromFile(pFile, aCache.fAngles, 3); + ReadArrayFromFile(pFile, aCache.fVelocity, 3); + ReadArrayFromFile(pFile, aCache.fBaseVelocity, 3); + pFile.ReadInt32(view_as(aCache.iMoveType)); + pFile.ReadInt32(view_as(aCache.fGravity)); + pFile.ReadInt32(view_as(aCache.fSpeed)); + pFile.ReadInt32(view_as(aCache.fStamina)); + pFile.ReadInt8(aCache.bDucked); + pFile.ReadInt8(aCache.bDucking); + pFile.ReadInt32(view_as(aCache.fDucktime)); + pFile.ReadInt32(view_as(aCache.fDuckSpeed)); + pFile.ReadInt32(aCache.iFlags); + pFile.ReadInt8(aCache.aSnapshot.bTimerEnabled); + pFile.ReadInt32(view_as(aCache.aSnapshot.fCurrentTime)); + pFile.ReadInt8(aCache.aSnapshot.bClientPaused); + pFile.ReadInt32(aCache.aSnapshot.iJumps); + pFile.ReadInt32(aCache.aSnapshot.bsStyle); + pFile.ReadInt32(aCache.aSnapshot.iStrafes); + pFile.ReadInt32(aCache.aSnapshot.iTotalMeasures); + pFile.ReadInt32(aCache.aSnapshot.iGoodGains); + pFile.ReadInt32(view_as(aCache.aSnapshot.fServerTime)); + pFile.ReadInt32(aCache.aSnapshot.iSHSWCombination); + pFile.ReadInt32(aCache.aSnapshot.iTimerTrack); + pFile.ReadInt32(aCache.aSnapshot.iMeasuredJumps); + pFile.ReadInt32(aCache.aSnapshot.iPerfectJumps); + pFile.ReadInt8(aCache.bSegmented); + pFile.ReadInt8(aCache.bPractice); + pFile.ReadInt32(aCache.iGroundEntity); + + aCache.iTargetname = -1; + aCache.iClassname = -1; + aCache.iSerial = GetClientSerial(client); + aCache.aFrames = null; + + int nLength; + pFile.ReadInt32(nLength); + + if(nLength > 0) + { + aCache.aFrames = new ArrayList(CELLS_PER_FRAME, nLength); + any aData[CELLS_PER_FRAME]; + + for(int i = 0; i < nLength; i++) + { + pFile.Read(aData, CELLS_PER_FRAME, 4); + aCache.aFrames.SetArray(i, aData, CELLS_PER_FRAME); + } + } + + SetCheckpoint(client, nCheckpoint, aCache); +} + +public Action Command_LoadCPs(int client, int args) +{ + if(client == 0) + { + return Plugin_Handled; + } + + if(!FileExists(gS_MapPath)) + { + ReplyToCommand(client, "No CP data saved. Use !savecps"); + + return Plugin_Handled; + } + + ResetCheckpoints(client); + + File fFile = OpenFile(gS_MapPath, "rb"); + fFile.ReadInt32(gA_CheckpointsCache[client].iCheckpoints); + gA_CheckpointsCache[client].iCurrentCheckpoint = gA_CheckpointsCache[client].iCheckpoints; + + for(int i = 0; i < gA_CheckpointsCache[client].iCheckpoints; i++) + { + ReadCheckpointFromFile(fFile, client, i + 1); + } + + delete fFile; + + ReplyToCommand(client, "Loaded CP data uwu"); + + return OpenCheckpointsMenu(client); +} + public Action Command_Tele(int client, int args) { if(client == 0) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 99775691..e54a02e0 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -34,7 +34,6 @@ #define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}" #define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}" #define REPLAY_FORMAT_SUBVERSION 0x04 -#define CELLS_PER_FRAME 8 // origin[3], angles[2], buttons, flags, movetype #define FRAMES_PER_WRITE 100 // amounts of frames to write per read/write call // #define DEBUG