def Save(self) -> bool: """ Saves the currently stored persistent data to the file path specified when initiating this object. If the directory the save file is in doesn't exist one will be created. :return: True if this completed without incident, False if not. :rtype: bool """ operationSuccess = True # type: bool saveSuccessful, persistentDataContainerString = super().Save( ) # type: bool, str try: if not os.path.exists(os.path.dirname(self.FilePath)): os.makedirs(os.path.dirname(self.FilePath)) with open(self.FilePath, mode="w+") as persistentFile: persistentFile.write(persistentDataContainerString) except Exception: Debug.Log("Failed to write to '" + Paths.StripUserDataPath(self.FilePath) + "'.", self.HostNamespace, Debug.LogLevels.Error, group=self.HostNamespace, owner=__name__) operationSuccess = False if not saveSuccessful: return False return operationSuccess
def Load(self, *args) -> bool: """ Load persistent data from the file path specified when initiating this object, if it exists. :return: True if this completed without incident, False if not. :rtype: bool """ operationSuccess = True # type: bool persistentDataContainerString = "{}" # type: str if os.path.exists(self.FilePath): try: with open(self.FilePath) as persistentFile: persistentDataContainerString = persistentFile.read() except Exception: Debug.Log("Failed to read from '" + Paths.StripUserDataPath(self.FilePath) + "'.", self.HostNamespace, Debug.LogLevels.Error, group=self.HostNamespace, owner=__name__) operationSuccess = False loadSuccessful = super().Load( persistentDataContainerString) # type: bool if not loadSuccessful: return False return operationSuccess
def Commit (sourceDirectoryPath: str, commitSlotID: int) -> None: """ Copy the active directory in this slot to its actual save directory and backup old save directories. If the active directory doesn't exist nothing will happen. :param sourceDirectoryPath: The path of the mod save folder that will be copied to the slot. :type sourceDirectoryPath: str :param commitSlotID: The save slot id suppose to be committed. This must be greater than or equal to 0. :type commitSlotID: int """ global _loadedSlotID, _loadedDirectoryPath if not isinstance(sourceDirectoryPath, str): raise Exceptions.IncorrectTypeException(sourceDirectoryPath, "sourceDirectoryPath", (str,)) if not isinstance(commitSlotID, int): raise Exceptions.IncorrectTypeException(commitSlotID, "commitSlotID", (int,)) if commitSlotID < 0: raise Exception("commitSlotID values must be greater than or equal to 0.") Debug.Log("Committing the directory '%s' to the slot %s." % (Paths.StripUserDataPath(sourceDirectoryPath), commitSlotID), This.Mod.Namespace, Debug.LogLevels.Info, group = This.Mod.Namespace, owner = __name__) committingDirectoryPath = GetModSaveDirectoryPath(commitSlotID) # type: str currentTimestamp = datetime.datetime.now().timestamp() # type: float try: _ShiftBackupDirectories(commitSlotID) if os.path.exists(sourceDirectoryPath): shutil.copytree(sourceDirectoryPath, committingDirectoryPath) os.utime(committingDirectoryPath, (currentTimestamp, currentTimestamp)) else: Debug.Log("The commit source directory at '%s' does not exist." % Paths.StripUserDataPath(sourceDirectoryPath), This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__) except: Debug.Log("Failed to commit to save slot '" + str(commitSlotID) + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) _ShowCommitFailureDialog() return _loadedSlotID = commitSlotID _loadedDirectoryPath = committingDirectoryPath Debug.Log("Finished committing to save slot %s." % commitSlotID, This.Mod.Namespace, Debug.LogLevels.Info, group = This.Mod.Namespace, owner = __name__)
def Save(self, saveFilePath: str) -> bool: """ Write the loaded data to the active save file. This saving object must have save data loaded or this method will raise an exception. :param saveFilePath: The path to save the data to. :type saveFilePath: str :return: This method will return False if an error in saving any section occurred. Otherwise this method will return True if it behaved as expected. :rtype: bool """ if not isinstance(saveFilePath, str): raise Exceptions.IncorrectTypeException(saveFilePath, "saveFilePath", (str, )) operationInformation = "Save Identifier: %s" % (self.Identifier, ) operationStartTime = time.time() # type: float Debug.Log( "Save operation starting in a saving object.\nTarget File: %s\n" % Paths.StripUserDataPath(saveFilePath) + operationInformation, self.Host.Namespace, Debug.LogLevels.Info, group=self.Host.Namespace, owner=__name__) if not self.Enabled: Debug.Log( "Triggered save operation in a disabled saving object.\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) try: saveSuccessful = self._SaveInternal(saveFilePath) self._currentFilePath = saveFilePath except: self._currentFilePath = saveFilePath operationTime = time.time() - operationStartTime # type: float Debug.Log( "Save operation in a saving object aborted. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) return False operationTime = time.time() - operationStartTime # type: float if saveSuccessful: Debug.Log( "Save operation in a saving object finished without issue. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Info, group=self.Host.Namespace, owner=__name__) else: Debug.Log( "Save operation in a saving object at least partially failed. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) return saveSuccessful
def Load(self, saveFilePath: str) -> bool: """ Load a save file. If any data is already loaded it will be unloaded first. :param saveFilePath: The path of the save file to be loaded. If this doesn't exist the method 'LoadDefault' will be used instead. :type saveFilePath: str :return: This method will return False if an error occurred. Otherwise this method will return True if it behaved as expected. :rtype: bool """ if not isinstance(saveFilePath, str): raise Exceptions.IncorrectTypeException(saveFilePath, "saveFilePath", (str, )) operationInformation = "Save Identifier: %s" % (self.Identifier, ) operationStartTime = time.time() # type: float Debug.Log( "Load operation starting in a saving object.\nTarget File: %s\n" % Paths.StripUserDataPath(saveFilePath) + operationInformation, self.Host.Namespace, Debug.LogLevels.Info, group=self.Host.Namespace, owner=__name__) if not self.Enabled: Debug.Log( "Triggered load operation in a disabled saving object.\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) if self.Loaded: self.Unload() if not os.path.exists(saveFilePath): self.LoadDefault() loadSuccessful = True self._loadedFileExisted = False self._currentFilePath = saveFilePath else: try: loadSuccessful = self._LoadInternal(saveFilePath) self._loadedFileExisted = True self._currentFilePath = saveFilePath except Exception: operationTime = time.time() - operationStartTime # type: float Debug.Log( "Load operation in a saving object aborted, falling back to the default. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) self.LoadDefault() self._loadedFileExisted = True self._currentFilePath = saveFilePath return False operationTime = time.time() - operationStartTime # type: float if loadSuccessful: Debug.Log( "Load operation in a saving object finished without issue. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Info, group=self.Host.Namespace, owner=__name__) else: Debug.Log( "Load operation in a saving object at least partially failed. (Operation took " + str(operationTime) + " seconds)\n" + operationInformation, self.Host.Namespace, Debug.LogLevels.Warning, group=self.Host.Namespace, owner=__name__) return loadSuccessful
def Load (loadSlotID: int, loadingDirectoryPath: typing.Optional[str] = None, changingSave: bool = False) -> None: """ Load the specified slot in every registered and enabled saving object. :param loadSlotID: The save slot id of the game's loaded save file. This must be greater than or equal to 0. :type loadSlotID: int :param loadingDirectoryPath: This parameter allows you to load a specific directory. If this is not None, we will copy this directory into the slot's active path to load it. Anything already existing at the activated path will be lost unless the path is pointing to the activated path. activated instead. :type loadingDirectoryPath: str | None :param changingSave: Whether or not we are switching to another save. :type changingSave: bool """ global _loadedSlotID, _loadedDirectoryPath if not isinstance(loadSlotID, int): raise Exceptions.IncorrectTypeException(loadSlotID, "loadSlotID", (int,)) if loadSlotID < 0: raise Exception("loadSlotID values must be greater than or equal to 0.") if not isinstance(loadingDirectoryPath, str) and loadingDirectoryPath is not None: raise Exceptions.IncorrectTypeException(loadingDirectoryPath, "loadingDirectoryPath", (str, None)) if not isinstance(changingSave, bool): raise Exceptions.IncorrectTypeException(changingSave, "changingSave", (bool,)) if loadingDirectoryPath is not None: Debug.Log("Loading the directory '" + Paths.StripUserDataPath(loadingDirectoryPath) + "' in save slot %s for %s saving object(s)." % (loadSlotID, len(_registeredSavingObjects)), This.Mod.Namespace, Debug.LogLevels.Info, group = This.Mod.Namespace, owner = __name__) else: Debug.Log("Loading save slot %s for %s saving object(s)." % (loadSlotID, len(_registeredSavingObjects)), This.Mod.Namespace, Debug.LogLevels.Info, group = This.Mod.Namespace, owner = __name__) loadingFailure = False # type: bool failedSavingIdentifiers = list() # type: typing.List[str] mismatchGUIDSavingIdentifiers = list() # type: typing.List[str] mismatchGameTickSavingIdentifiers = list() # type: typing.List[str] if _loadedSlotID is None or _loadedDirectoryPath is None: changingSave = True if loadingDirectoryPath is not None: changingSave = True try: ActivateDirectoryToSlot(loadingDirectoryPath, loadSlotID) except: Debug.Log("Failed to activate the directory at %s in save slot %s" % (Paths.StripUserDataPath(loadingDirectoryPath), loadSlotID), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) loadingFailure = True else: loadingDirectoryPath = GetModSaveDirectoryPath(loadSlotID) # type: str if _activeSlotID != loadSlotID: try: ActivateDirectoryToSlot(loadingDirectoryPath, loadSlotID) except: Debug.Log("Failed to activate save slot %s" % (loadSlotID,), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) loadingFailure = True loadingActiveDirectoryPath = GetModSaveActiveDirectoryPath(loadSlotID) # type: str modSaveMetaDataFileName = GetModSaveMetaDataFileName() # type: str for savingObject in _registeredSavingObjects: # type: Saving.SaveBase try: if not savingObject.Enabled: continue savingObjectFileName = savingObject.GetSaveFileName() # type: str if savingObjectFileName == modSaveMetaDataFileName: Debug.Log("Had to skip a saving object with the identifier '" + savingObject.Identifier + "' because its file name was '" + modSaveMetaDataFileName + "' which conflicts with an important file.", This.Mod.Namespace, Debug.LogLevels.Error, group = This.Mod.Namespace, owner = __name__) continue loadingFilePath = os.path.abspath(os.path.join(loadingActiveDirectoryPath, savingObject.GetSaveFileName())) # type: str modLoadSuccessful = savingObject.Load(loadingFilePath) # type: bool except Exception: Debug.Log("Encountered an unhandled exception upon loading a saving object with the identifier '" + savingObject.Identifier + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) modLoadSuccessful = False if not modLoadSuccessful: failedSavingIdentifiers.append(savingObject.Identifier) if modLoadSuccessful: savingObjectGUID = savingObject.DataGUID # type: typing.Optional[int] if savingObjectGUID is not None: gameSaveGUID = services.get_persistence_service().get_save_slot_proto_guid() # type: int if savingObjectGUID != gameSaveGUID: mismatchGUIDSavingIdentifiers.append(savingObject.Identifier) continue savingObjectGameTick = savingObject.DataGameTick # type: typing.Optional[int] if savingObjectGameTick is not None: gameplaySaveSlotData = services.get_persistence_service().get_save_slot_proto_buff().gameplay_data if savingObjectGameTick != gameplaySaveSlotData.world_game_time: mismatchGameTickSavingIdentifiers.append(savingObject.Identifier) continue if changingSave: _loadedSlotID = loadSlotID _loadedDirectoryPath = loadingDirectoryPath if loadingFailure: _ShowLoadFailureDialog() if len(failedSavingIdentifiers) != 0: _ShowModLoadFailureDialog(failedSavingIdentifiers) if len(mismatchGUIDSavingIdentifiers) != 0: _ShowMismatchGUIDWarningDialog(mismatchGUIDSavingIdentifiers) if len(mismatchGameTickSavingIdentifiers) != 0: _ShowMismatchGameTickWarningDialog(mismatchGameTickSavingIdentifiers) Debug.Log("Finished loading %s saving object(s) with %s failing." % (len(_registeredSavingObjects), str(len(failedSavingIdentifiers))), This.Mod.Namespace, Debug.LogLevels.Info, group = This.Mod.Namespace, owner = __name__)
def PersistenceInformation(self) -> str: return "%s | File %s" % (self.__class__.__name__, Paths.StripUserDataPath(self.FilePath))