11 protected const string GAME_SESSION_STORAGE_FILE_NAME_TO_LOAD =
"SCR_SaveFileManager_FileNameToLoad";
12 protected const string GAME_SESSION_STORAGE_USED_CLI =
"SCR_SaveFileManager_UsedCLI";
13 protected const string CLI_PARAM =
"loadSessionSave";
16 protected ref array<ref SCR_DSSessionCallback> m_aCallbacks;
23 protected string m_sMissionSaveFileName;
31 protected bool m_bLoadedOnInit;
32 protected bool m_bDebugDelete;
53 Print(
string.Format(
"SCR_SaveManagerCore: Cannot save, no rules found for save type %1! Check configuration of SCR_SaveLoadComponent on game mode.",
typename.EnumToString(
ESaveType,
type)), LogLevel.WARNING);
57 return callback.SaveSession(m_sMissionSaveFileName, customName);
71 Print(
string.Format(
"SCR_SaveManagerCore: Cannot override current save, no rules found for save type %1! Check configuration of SCR_SaveLoadComponent on game mode.",
typename.EnumToString(
ESaveType,
type)), LogLevel.WARNING);
75 string customName =
callback.GetCurrentCustomName();
76 return customName &&
callback.SaveSession(m_sMissionSaveFileName, customName);
87 bool Load(
string fileName)
92 Print(
string.Format(
"SCR_SaveManagerCore: Cannot load save file '%1', no rules found for it!", fileName), LogLevel.WARNING);
96 return callback.LoadSession(fileName);
104 bool RestartAndLoad()
106 string latestSaveFileName;
107 return FindLatestSave(m_sMissionSaveFileName, latestSaveFileName) && RestartAndLoad(latestSaveFileName);
117 bool RestartAndLoad(
ESaveType type,
string customName =
string.Empty)
122 Print(
string.Format(
"SCR_SaveManagerCore: Cannot restart and load, no rules found for save type %1! Check configuration of SCR_SaveLoadComponent on game mode.",
typename.EnumToString(
ESaveType,
type)), LogLevel.WARNING);
126 string fileName =
callback.GetFileName(m_sMissionSaveFileName, customName);
127 return RestartAndLoad(fileName);
136 bool RestartAndLoad(
string fileName)
138 if (Replication.IsClient())
140 UploadToWorkshop(fileName);
146 if (!SetFileNameToLoad(fileName))
161 bool Delete(
ESaveType type,
string customName =
string.Empty)
166 Print(
string.Format(
"SCR_SaveManagerCore: Cannot delete, no rules found for save type %1! Check configuration of SCR_SaveLoadComponent on game mode.",
typename.EnumToString(
ESaveType,
type)), LogLevel.WARNING);
170 return callback.Delete(m_sMissionSaveFileName, customName);
179 bool Delete(
string fileName)
184 Print(
string.Format(
"SCR_SaveManagerCore: Cannot delete save file '%1', no rules found for it!", fileName), LogLevel.WARNING);
198 bool FileExists(
ESaveType type,
string customName =
string.Empty)
203 Print(
string.Format(
"SCR_SaveManagerCore: Cannot check if file exists, no rules found for save type %1! Check configuration of SCR_SaveLoadComponent on game mode.",
typename.EnumToString(
ESaveType,
type)), LogLevel.WARNING);
207 return callback.FileExists(m_sMissionSaveFileName, customName);
216 bool FileExists(
string fileName)
218 return GetGame().GetBackendApi().GetStorage().CheckFileID(fileName);
225 bool CanSaveToCloud()
227 return RplSession.Mode() == RplMode.Dedicated &&
GetGame().GetBackendApi().GetStorage().GetOnlineWritePrivilege();
241 Print(
string.Format(
"SCR_SaveManagerCore: Cannot load meta of save file '%1', no rules found for it!", fileName), LogLevel.WARNING);
260 int GetLocalSaveFiles(out notnull array<string> outLocalSaves,
ESaveType saveTypes,
bool currentMissionOnly)
262 string missionFileName;
263 if (currentMissionOnly)
264 missionFileName = m_sMissionSaveFileName;
266 return GetLocalSaveFiles(outLocalSaves, saveTypes, missionFileName);
275 int GetLocalSaveFiles(out notnull array<string> outLocalSaves,
ESaveType saveTypes,
string missionFileName =
string.Empty)
277 for (
int i =
GetGame().GetBackendApi().GetStorage().AvailableSaves(outLocalSaves) - 1; i >= 0; i--)
280 if (IsDownloaded(outLocalSaves[i]))
282 outLocalSaves.Remove(i);
287 if (!
callback || !(saveTypes &
callback.GetSaveType()) || (missionFileName &&
callback.GetMissionFileName(outLocalSaves[i]) != missionFileName))
288 outLocalSaves.Remove(i);
290 return outLocalSaves.Count();
294 protected bool IsDownloaded(
string fileName)
297 FilePath.StripExtension(fileName, ext);
298 return ext.Contains(
"_");
313 if (!m_sMissionSaveFileName || !FindCallback(
type))
357 string GetMissionFileName(
string fileName)
361 return callback.GetMissionFileName(fileName);
372 string GetCustomName(
string fileName)
376 return callback.GetCustomName(fileName);
413 if (
callback.IsCompatible(fileName))
422 void UploadToWorkshop(
string fileName)
432 void DownloadFromWorkshop()
437 m_DownloadPageParams.limit = 50;
439 GetGame().GetBackendApi().GetWorldSaveApi().RequestPage(m_DownloadCallback, m_DownloadPageParams,
true);
443 void OnDownloadFromWorkshop()
445 m_DownloadCallback =
null;
446 m_DownloadPageParams =
null;
449 array<WorldSaveItem> items = {};
450 int count =
GetGame().GetBackendApi().GetWorldSaveApi().GetPageItems(items);
451 foreach (
int i, WorldSaveItem item: items)
453 PrintFormat(
"%1: Id=%2, Name='%3', Description='%4'", i, item.Id(), item.Name(), item.Description());
456 item.DeleteOnline(
null);
476 string latestSaveFileName;
477 if (!FindLatestSave(missionHeader.GetSaveFileName(), latestSaveFileName))
480 return SetFileNameToLoad(latestSaveFileName);
489 bool SetFileNameToLoad(
string fileName)
491 if (!
GetGame().GetBackendApi().GetStorage().CheckFileID(fileName))
494 GameSessionStorage.s_Data.Insert(GAME_SESSION_STORAGE_FILE_NAME_TO_LOAD, fileName);
495 Print(
string.Format(
"'%1' set as a save file name to load after world start.", fileName), LogLevel.VERBOSE);
504 void ResetFileNameToLoad()
506 if (GameSessionStorage.s_Data.Contains(GAME_SESSION_STORAGE_FILE_NAME_TO_LOAD))
508 GameSessionStorage.s_Data.Remove(GAME_SESSION_STORAGE_FILE_NAME_TO_LOAD);
509 Print(
"Save file name to load after world start removed.", LogLevel.VERBOSE);
519 bool FindFileNameToLoad(out
string fileNameToLoad)
521 return GameSessionStorage.s_Data.Find(GAME_SESSION_STORAGE_FILE_NAME_TO_LOAD, fileNameToLoad);
534 void SetCurrentMissionLatestSave(
string saveFileName)
536 SetLatestSave(m_sMissionSaveFileName, saveFileName);
544 void RemoveCurrentMissionLatestSave()
546 RemoveLatestSave(m_sMissionSaveFileName);
554 bool FindCurrentMissionLatestSave(out
string outSaveFileName)
556 return FindLatestSave(m_sMissionSaveFileName, outSaveFileName);
565 void SetLatestSave(
string missionFileName,
string saveFileName)
567 m_LatestSaveCallback.SetFileName(missionFileName, saveFileName);
576 void RemoveLatestSave(
string missionFileName)
578 m_LatestSaveCallback.RemoveFileName(missionFileName);
587 bool FindLatestSave(
string missionFileName, out
string outSaveFileName)
589 return m_LatestSaveCallback.FindFileName(missionFileName, outSaveFileName);
600 return missionHeader && FindLatestSave(missionHeader.GetSaveFileName(), outSaveFileName);
608 bool HasLatestSave(
string missionFileName)
611 return FindLatestSave(missionFileName, saveFileName);
622 return missionHeader && FindLatestSave(missionHeader, saveFileName);
664 return m_OnLatestSave;
670 return m_UploadCallback;
684 if (m_bLoadedOnInit || !m_sMissionSaveFileName || !Replication.IsServer())
688 m_bLoadedOnInit =
true;
691 string fileNameToLoad;
692 if (System.IsConsoleApp())
697 if (!FindFileNameToLoad(fileNameToLoad))
700 if (GameSessionStorage.s_Data.Contains(GAME_SESSION_STORAGE_USED_CLI))
704 if (!System.GetCLIParam(CLI_PARAM, fileNameToLoad))
706 Print(
string.Format(
"SCR_SaveManagerCore: -%1 CLI param not used, no save file is loaded.", CLI_PARAM), LogLevel.VERBOSE);
711 if (fileNameToLoad.IsEmpty() && !FindLatestSave(m_sMissionSaveFileName, fileNameToLoad))
713 Print(
string.Format(
"SCR_SaveManagerCore: -%1 CLI param set to load the latest save, but none was defined for the mission '%2'!", CLI_PARAM, m_sMissionSaveFileName), LogLevel.WARNING);
717 GameSessionStorage.s_Data.Insert(GAME_SESSION_STORAGE_USED_CLI, fileNameToLoad);
725 if (System.IsCLIParam(CLI_PARAM))
726 Print(
string.Format(
"SCR_SaveManagerCore: -%1 CLI is intended for dedicated server only!", CLI_PARAM), LogLevel.WARNING);
729 if (!FindFileNameToLoad(fileNameToLoad))
734 Load(fileNameToLoad);
735 ResetFileNameToLoad();
742 if (!missionHeader && SCR_SaveLoadComponent.GetInstance())
745 m_WorkbenchMissionHeader.m_sSaveFileName = FilePath.StripPath(FilePath.StripExtension(
GetGame().GetWorldFile()));
746 m_WorkbenchMissionHeader.m_bIsSavingEnabled =
true;
747 missionHeader = m_WorkbenchMissionHeader;
754 override void OnUpdate(
float timeSlice)
756 if (m_sMissionSaveFileName && !System.IsConsoleApp() &&
GetGame().IsDev())
764 array<string> customNames = {
"Alpha",
"Kilo",
"Zulu"};
765 string customName = customNames.GetRandomElement();
766 Save(saveType, customName);
780 if (FindLatestSave(m_sMissionSaveFileName, fileName))
783 if (DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_SAVING_RESTART_AND_LOAD_LATEST))
785 DiagMenu.SetValue(
SCR_DebugMenuID.DEBUGUI_SAVING_RESTART_AND_LOAD_LATEST,
false);
792 string latestSaveFileName;
793 if (FindLatestSave(m_sMissionSaveFileName, latestSaveFileName))
794 PrintFormat(
"The latest save file name for mission '%1' is '%2'", m_sMissionSaveFileName, latestSaveFileName);
796 PrintFormat(
"There is no latest save file name for mission '%1'", latestSaveFileName);
800 DiagMenu.SetValue(
SCR_DebugMenuID.DEBUGUI_SAVING_UPLOAD_LATEST,
false);
803 if (FindLatestSave(m_sMissionSaveFileName, fileName))
804 UploadToWorkshop(fileName);
806 Print(
"SCR_SaveManagerCore: Cannot upload, latest save not found!", LogLevel.WARNING);
812 m_bDebugDelete =
false;
813 DownloadFromWorkshop();
819 m_bDebugDelete =
true;
820 DownloadFromWorkshop();
826 override void OnGameStart()
829 if (!SCR_SaveLoadComponent.GetInstance())
832 OnGameStorageInitialize();
834 if (m_LatestSaveCallback.IsLoaded())
839 m_SessionStorageCallback.GetOnInitialize().Insert(OnGameStorageInitialize);
840 GetGame().GetBackendApi().SetSessionCallback(m_SessionStorageCallback);
849 InitDebugMissionHeader(missionHeader);
852 #ifdef SAVE_MANAGER_DEBUG_HEADER
853 InitDebugMissionHeader(missionHeader);
857 if (missionHeader && missionHeader.m_bIsSavingEnabled)
858 m_sMissionSaveFileName = missionHeader.GetSaveFileName();
863 callback.OnGameStart(m_sMissionSaveFileName);
867 m_LatestSaveCallback.ReadFromFile();
870 if (
GetGame().IsDev() && Replication.IsServer() && !System.IsConsoleApp())
873 string categoryName =
"Save Manager";
874 DiagMenu.RegisterMenu(
SCR_DebugMenuID.DEBUGUI_SAVING, categoryName,
"Game");
875 DiagMenu.RegisterRange(
SCR_DebugMenuID.DEBUGUI_SAVING_TYPE,
"",
"Type", categoryName,
string.Format(
"0,%1,0,1", enumType.GetVariableCount() - 1));
876 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_LOG,
"",
"Log Struct By Type", categoryName);
877 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_SAVE,
"",
"Save By Type", categoryName);
879 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_LOAD_LATEST,
"",
"Load Latest Save", categoryName);
880 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_RESTART_AND_LOAD_LATEST,
"",
"Restart and Load Latest Save", categoryName);
881 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_LOG_LATEST,
"",
"Log Latest Save File Name", categoryName);
882 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_UPLOAD_LATEST,
"",
"Upload Latest Save", categoryName);
884 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_DOWNLOAD,
"",
"Download Workshop Saves", categoryName);
885 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_SAVING_DELETE,
"",
"Delete Workshop Saves", categoryName);
890 protected void OnGameStorageInitialize()
893 m_LatestSaveCallback.ReadFromFile();
895 if (m_SessionStorageCallback)
896 m_SessionStorageCallback.GetOnInitialize().Remove(OnGameStorageInitialize);
900 override void OnGameEnd()
904 callback.OnGameEnd(m_sMissionSaveFileName);
907 m_bLoadedOnInit =
false;
908 m_sMissionSaveFileName =
string.Empty;
909 m_WorkbenchMissionHeader =
null;
916 if (
GetGame().IsDev() && Replication.IsServer() && !System.IsConsoleApp())
923 DiagMenu.Unregister(
SCR_DebugMenuID.DEBUGUI_SAVING_RESTART_AND_LOAD_LATEST);
936 override void OnError(
int code,
int restCode,
int apiCode )
938 PrintFormat(
"[BackendCallback] OnError: code=%1 ('%4'), restCode=%2, apiCode=%3", code, restCode, apiCode,
GetGame().GetBackendApi().GetErrorCode(code));
940 override void OnSuccess(
int code )
942 PrintFormat(
"[BackendCallback] OnSuccess(): code=%1", code);
943 GetGame().GetSaveManager().OnDownloadFromWorkshop();
945 override void OnTimeout()
947 Print(
"[BackendCallback] OnTimeout");
952 override void OnPack()
954 StoreBoolean(
"owned",
true);
969 return m_OnInitialize;
973 override void OnInitialize()
975 super.OnInitialize();
976 m_OnInitialize.Invoke();