def _UpdateCompatibility (self, informationDictionary: dict) -> bool: informationKey = "Compatibility" # type: str compatibilityLowestVersionKey = "LowestVersion" # type: str compatibilityHighestVersionKey = "HighestVersion" # type: str try: compatibility = informationDictionary.get(informationKey, dict()) # type: typing.Dict[str, dict] if not isinstance(compatibility, dict): raise Exceptions.IncorrectTypeException(compatibility, "Root[%s]" % informationKey, (dict,)) for namespace, modDictionary in compatibility.items(): # type: str, typing.Dict[str, str] if not isinstance(namespace, str): raise Exceptions.IncorrectTypeException(namespace, "Root[%s]<Key>" % informationKey, (str,)) if namespace == self.Mod.Namespace: raise Exception("A mod cannot have compatibility information for its self.") if not isinstance(modDictionary, dict): raise Exceptions.IncorrectTypeException(modDictionary, "Root[%s][%s]" % (informationKey, namespace), (dict,)) if not compatibilityLowestVersionKey in modDictionary: lowestVersion = None else: lowestVersion = modDictionary[compatibilityLowestVersionKey] if not isinstance(lowestVersion, str) and lowestVersion is not None: raise Exceptions.IncorrectTypeException(lowestVersion, "Root[%s][%s][%s]" % (informationKey, namespace, compatibilityLowestVersionKey), (str, "None")) if not compatibilityHighestVersionKey in modDictionary: highestVersion = None else: highestVersion = modDictionary[compatibilityHighestVersionKey] if not isinstance(highestVersion, str) and highestVersion is not None: raise Exceptions.IncorrectTypeException(highestVersion, "Root[%s][%s][%s]" % (informationKey, namespace, compatibilityHighestVersionKey), (str, "None")) lowestVersionObject = Version.Version(versionString = lowestVersion) if lowestVersion is not None else None # type: typing.Optional[Version.Version] highestVersionObject = Version.Version(versionString = highestVersion) if highestVersion is not None else None # type: typing.Optional[Version.Version] self.Mod.Compatibility.append(Mods.Compatibility(namespace, lowestVersionObject, highestVersionObject)) return True except Exception: Debug.Log("Failed to read mod information file value '%s' for '%s'." % (informationKey, self.Mod.Namespace), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) return False
def LoadedLastVersion(self) -> typing.Optional[Version.Version]: """ The last version the loaded data was loaded in. :return: """ if self._loadedLastVersion is None: return None return Version.Version(str(self._loadedLastVersion))
def _ReadVersionFile( versionsFileURL: str ) -> typing.Dict[str, typing.Dict[str, Version.Version]]: with request.urlopen( versionsFileURL) as versionsFile: # type: client.HTTPResponse versionsDictionaryString = versionsFile.read().decode( "utf-8") # type: str if not versionsDictionaryString or versionsDictionaryString.isspace(): raise Exception("Latest versions file at '" + versionsFileURL + "' is empty or whitespace.") try: versionDictionary = json.JSONDecoder().decode( versionsDictionaryString ) # type: typing.Dict[str, typing.Dict[str, typing.Any]] if not isinstance(versionDictionary, dict): raise Exceptions.IncorrectTypeException(versionDictionary, "Root", (dict, )) for mod, modLatest in versionDictionary.items( ): # type: str, typing.Dict[str, typing.Any] if not isinstance(mod, str): raise Exceptions.IncorrectTypeException( mod, "Root<Key>", (str, )) if not isinstance(modLatest, dict): raise Exceptions.IncorrectTypeException( mod, "Root[%s]" % mod, (dict, )) if "Release" in modLatest: modLatest["Release"] = Version.Version(modLatest["Release"]) if "Preview" in modLatest: modLatest["Preview"] = Version.Version(modLatest["Preview"]) except Exception as e: raise Exception("Failed to decode latest version file at '" + versionsFileURL + "'.") from e return versionDictionary
def _UpdateBuildGameVersion (self, informationDictionary: dict) -> bool: informationKey = "BuildGameVersion" # type: str try: buildGameVersion = informationDictionary.get(informationKey, None) if buildGameVersion is None: return True if not isinstance(buildGameVersion, str): raise Exceptions.IncorrectTypeException(buildGameVersion, "Root[%s]" % informationKey, (str,)) self.Mod.BuildGameVersion = Version.Version(buildGameVersion, translate = True) return True except Exception: Debug.Log("Failed to read mod information file value '%s' for '%s'." % (informationKey, self.Mod.Namespace), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) return False
def _UpdateVersion (self, informationDictionary: dict) -> bool: informationKey = "Version" # type: str try: if not "Version" in informationDictionary: raise Exception("Missing dictionary entry '%s' in 'Root'." % informationKey) version = informationDictionary["Version"] # type: str if not isinstance(version, str): raise Exceptions.IncorrectTypeException(version, "Root[%s]" % informationKey, (str,)) self.Mod.Version = Version.Version(version) return True except Exception: Debug.Log("Failed to read mod information file value '%s' for '%s'." % (informationKey, self.Mod.Namespace), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) return False
def _ResetInformation (self) -> None: self.Mod.Author = "" self.Mod.Version = Version.Version() self.Mod.VersionDisplay = "0.0.0" self.Mod.Distribution = Mods.Distribution(None, None, None, None) self.Mod.Rating = Mods.Rating.Normal self.Mod.ScriptPaths = list() self.Mod.Modules = list() self.Mod.RequiredMods = set() self.Mod.IncompatibleMods = set() self.Mod.LoadAfter = set() self.Mod.LoadBefore = set() self.Mod.Compatibility = list() self.Mod.BuildDate = None self.Mod.BuildGameVersion = None self.Mod.Additional = dict()
def __init__(self, namespace: str, name: str, loadController: str, informationFilePath: str): """ A container for mod information. :param namespace: The namespace of the mod, it should be the root of all the mod's modules. :type namespace: str :param name: The actual name of the mod. :type name: str :param loadController: The namespace of the mod that can load this mod. :type loadController: typing.Optional[str] :param informationFilePath: The file path of the mod information file. :type informationFilePath: str """ if not isinstance(namespace, str): raise Exceptions.IncorrectTypeException(namespace, "namespace", (str, )) if not isinstance(name, str): raise Exceptions.IncorrectTypeException(name, "name", (str, )) if not isinstance(loadController, str) and loadController is not None: raise Exceptions.IncorrectTypeException(loadController, "loadController", (str, "None")) if not isinstance(informationFilePath, str): raise Exceptions.IncorrectTypeException(informationFilePath, "informationFilePath", (str, )) self.InformationFilePath = informationFilePath # type: str self.InformationFileDirectoryPath = os.path.dirname( self.InformationFilePath) # type: str self._namespace = namespace # type: str self.Name = name # type: str self.LoadController = loadController # type: typing.Optional[str] self.Path = os.path.join(Paths.ModsPath, self.Namespace) # type: str self.PersistentPath = os.path.join(Paths.PersistentPath, self.Namespace) # type: str self.Author = "" # type: str self.Version = Version.Version() # type: Version.Version self.VersionDisplay = "0.0.0" # type: str self.Distribution = Distribution(None, None, None, None) # type: Distribution self.Rating = Rating.Normal # type: Rating self.ScriptPaths = list() # type: typing.List[str] self.Modules = list() # type: typing.List[str] self.RequiredMods = set() # type: typing.Set[str] self.IncompatibleMods = set() # type: typing.Set[str] self.LoadAfter = set() # type: typing.Set[str] self.LoadBefore = set() # type: typing.Set[str] self.Compatibility = list() # type: typing.List[Compatibility] self.BuildDate = None # type: typing.Optional[datetime.datetime] self.BuildGameVersion = None # type: typing.Optional[Version.Version] self.Additional = dict() # type: dict self.Blocked = False # type: bool self.Loading = False # type: bool self.ReadInformation = False # type: bool self.Imported = False # type: bool self.Initiated = False # type: bool self.Started = False # type: bool self.LoadTime = None # type: typing.Optional[float]
def Load(self, persistentDataContainer: dict) -> bool: """ Load persistent data from a persistent data container. :param persistentDataContainer: The persistent data container dictionary. :type persistentDataContainer: dict :rtype: None """ operationSuccess = True # type: bool persistenceInformation = self.PersistenceInformation # type: str if not isinstance(persistentDataContainer, dict): raise Exceptions.IncorrectTypeException(persistentDataContainer, "persistentDataContainer", (dict, )) persistentData = persistentDataContainer.get( self._valuesKey, dict()) # type: typing.Dict[str, typing.Any] if not isinstance(persistentData, dict): Debug.Log("Invalid type in persistent data container.\n" + Exceptions.GetIncorrectTypeExceptionText( persistentData, "PersistentDataContainer[%s]" % self._valuesKey, (dict, )) + "\n" + persistenceInformation, self.HostNamespace, Debug.LogLevels.Warning, group=self.HostNamespace, owner=__name__) persistentData = dict() operationSuccess = False lastVersionString = persistentDataContainer.get( self._lastVersionKey) # type: if lastVersionString is None: lastVersion = None else: if not isinstance(lastVersionString, str): Debug.Log( "Invalid type in persistent data container.\n" + Exceptions.GetIncorrectTypeExceptionText( lastVersionString, "PersistentDataContainer[%s]" % self._lastVersionKey, (dict, )) + "\n" + persistenceInformation, self.HostNamespace, Debug.LogLevels.Warning, group=self.HostNamespace, owner=__name__) lastVersion = None operationSuccess = False else: try: lastVersion = Version.Version(lastVersionString) except Exception: Debug.Log( "Cannot convert persistent data's last version value '" + lastVersionString + "' to a version number object.\n" + persistenceInformation, self.HostNamespace, Debug.LogLevels.Warning, group=self.HostNamespace, owner=__name__) lastVersion = None operationSuccess = False self.Reset(autoSave=False, autoUpdate=False) setDataSuccess = self._LoadSetData( persistentData, lastVersion=lastVersion) # type: bool self._InvokeOnLoadEvent() if not setDataSuccess: return False return operationSuccess
def _CheckUpdates() -> None: previewAvailableMods = list( ) # type: typing.List[typing.Tuple[Mods.Mod, Version.Version]] releaseAvailableMods = list( ) # type: typing.List[typing.Tuple[Mods.Mod, Version.Version]] distributeUpdates = Settings.CheckForUpdates.Get() # type: bool distributePreviewUpdates = Settings.CheckForPreviewUpdates.Get( ) # type: bool if not distributeUpdates: return latestURL = _distributionURL + "/mods/latest.json" # type: str try: latestDictionary = _ReadVersionFile( latestURL ) # type: typing.Dict[str, typing.Dict[str, Version.Version]] except Exception: Debug.Log("Failed to get mod versions.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) return for mod in Mods.GetAllMods(): # type: Mods.Mod if not mod.ReadInformation: continue if mod.Distribution.UpdatesController is None: continue if mod.Distribution.UpdatesController != Information.RootNamespace: continue modShownReleaseVersions = _shownReleaseVersions.get(mod) # type: list if modShownReleaseVersions is None: modShownReleaseVersions = list() _shownReleaseVersions[mod] = modShownReleaseVersions modShownPreviewVersions = _shownPreviewVersions.get(mod) # type: list if modShownPreviewVersions is None: modShownPreviewVersions = list() _shownPreviewVersions[mod] = modShownPreviewVersions try: modVersions = latestDictionary.get(mod.Namespace) # type: Version if modVersions is None: Debug.Log("Missing version data for '" + mod.Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) continue releaseVersion = modVersions.get( "Release") # type: Version.Version if releaseVersion is None: Debug.Log("Missing release version for '" + mod.Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) releaseVersion = Version.Version() if distributePreviewUpdates: previewVersion = modVersions.get( "Preview") # type: Version.Version if previewVersion is None: Debug.Log("Missing preview version for '" + mod.Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) previewVersion = Version.Version() if previewVersion <= releaseVersion: if not releaseVersion in modShownReleaseVersions: if mod.Version < releaseVersion: releaseAvailableMods.append((mod, releaseVersion)) continue else: if not previewVersion in modShownPreviewVersions: if mod.Version < previewVersion: previewAvailableMods.append((mod, previewVersion)) continue else: if not releaseVersion in modShownReleaseVersions: if mod.Version < releaseVersion: releaseAvailableMods.append((mod, releaseVersion)) continue except Exception: Debug.Log("Failed to get update information for '" + mod.Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) for releaseTuple in releaseAvailableMods: # type: typing.Tuple[Mods.Mod, Version.Version] try: _ShowReleaseUpdateNotification(releaseTuple[0], releaseTuple[1]) except Exception: Debug.Log("Failed to show release update notification for '" + releaseTuple[0].Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) for previewTuple in previewAvailableMods: # type: typing.Tuple[Mods.Mod, Version.Version] try: _ShowPreviewUpdateNotification(previewTuple[0], previewTuple[1]) except Exception: Debug.Log("Failed to show release update notification for '" + previewTuple[0].Namespace + "'.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__)