def _InvokeOnUpdateWrapperEvent (changedSettings: typing.Set[str]) -> UpdateEventArguments: updateEventArguments = UpdateEventArguments(changedSettings) # type: UpdateEventArguments for updateCallback in _onUpdateWrapper: # type: typing.Callable[[types.ModuleType, Events.EventArguments], None] try: updateCallback(sys.modules[__name__], updateEventArguments) except: Debug.Log("Failed to run the 'OnUpdateWrapper' callback '" + Types.GetFullName(updateCallback) + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) return updateEventArguments
def _InvokeOnLoadWrapperEvent () -> Events.EventArguments: eventArguments = Events.EventArguments() # type: Events.EventArguments for updateCallback in _onUpdateWrapper: # type: typing.Callable[[types.ModuleType, Events.EventArguments], None] try: updateCallback(sys.modules[__name__], eventArguments) except: Debug.Log("Failed to run the 'OnLoadWrapper' callback '" + Types.GetFullName(updateCallback) + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__) return eventArguments
def DoBuffSelectionTesting (self) -> CycleEvents.MenstrualEffectBuffSelectionTestingArguments: eventArguments = CycleEvents.MenstrualEffectBuffSelectionTestingArguments(self.AffectingSystem.CurrentSeed, self.AffectingSystem.SimInfo) # type: CycleEvents.MenstrualEffectBuffSelectionTestingArguments for buffSelectionTestingCallback in self.BuffSelectionTestingEvent: try: buffSelectionTestingCallback(self, eventArguments) except: Debug.Log("Failed to call buff selection testing callback '" + Types.GetFullName(buffSelectionTestingCallback) + "'.\n" + self.AffectingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = buffSelectionTestingCallback) return eventArguments
def run(self) -> None: while True: if not self.isAlive( ) or self._parentTimer is None or not self._parentTimer.isAlive(): break if self.daemon != self._parentTimer.daemon: self.daemon = self._parentTimer.daemon currentlyQueued = len(self._queuedCallbacks) # type: int if currentlyQueued == 0: time.sleep(0.05) else: callback = self._queuedCallbacks[0][0] # type: typing.Callable callbackArguments = self._queuedCallbacks[0][1] # type: tuple callbackKeywordArguments = self._queuedCallbacks[0][ 2] # type: dict try: callback(*callbackArguments, **callbackKeywordArguments) except Exception: Debug.Log("Failed to call a timer callback. Callback '" + Types.GetFullName(callback) + "'", This.Mod.Namespace, level=Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) self._queuedCallbacks.pop(0) if currentlyQueued >= 10: if not self._reportedBacklog: Debug.Log( "A timer's callback thread has developed a backlog. This might mean callbacks are being added faster than they can be dealt with. Last Callback: '" + Types.GetFullName(callback) + "'", This.Mod.Namespace, level=Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) self._reportedBacklog = True
def _ScanForAllSnippets() -> None: if services.snippet_manager is None: raise Exception("Cannot look for snippets, the manager is None.") if len(_scanningSnippets) == 0: return operationStartTime = time.time() # type: float snippetsByType = dict( ) # type: typing.Dict[str, typing.List[snippets.SnippetInstanceMetaclass]] for snippetID, snippet in services.snippet_manager().types.items( ): # type: typing.Any, snippets.SnippetInstanceMetaclass if isinstance(snippet, snippets.SnippetInstanceMetaclass): snippetList = snippetsByType.get( snippet.snippet_type, None) # type: typing.List[snippets.SnippetInstanceMetaclass] if snippetList is None: snippetList = list() snippetsByType[snippet.snippet_type] = snippetList snippetList.append(snippet) for snippetType, snippetCallbacks in _scanningSnippets.items( ): # type: str, typing.List[typing.Callable] snippetList = snippetsByType.get(snippetType, None) if snippetList is None: snippetList = list() for snippetCallback in snippetCallbacks: # type: typing.Callable try: snippetCallback(snippetList) except: Debug.Log("Failed to trigger snippet scan callback at '%s'." % Types.GetFullName(snippetCallback), This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__) operationTime = time.time() - operationStartTime Debug.Log( "Finished scanning for %s types of snippet in %s seconds with %s snippets existing." % (len(_scanningSnippets), operationTime, len(services.snippet_manager().types)), This.Mod.Namespace, Debug.LogLevels.Info, group=This.Mod.Namespace, owner=__name__)
def _TriggerAnnouncement (self, announcementMethodName: str, preemptive: bool, *announcementArgs, **announcementKwargs) -> None: for announcer in Director.GetAllAnnouncers(): # type: typing.Type[Director.Announcer] readReportLockIdentifier = None # type: typing.Optional[str] readReportLockReference = None # type: typing.Any if self.LimitErrors: readReportLockIdentifier = __name__ + ":" + str(Python.GetLineNumber()) # type: str readReportLockReference = announcer try: if not announcer.Enabled: continue if not announcer.Host.IsLoaded() and not announcer.Reliable: continue if preemptive != announcer.Preemptive: continue announcementMethod = getattr(announcer, announcementMethodName) # type: typing.Callable except Exception: from NeonOcean.S4.Main import Debug Debug.Log("Failed to read the announcer at '" + Types.GetFullName(announcer) + "' when triggering the announcement '" + announcementMethodName + "'.", announcer.Host.Namespace, Debug.LogLevels.Exception, group = announcer.Host.Namespace, owner = __name__, lockIdentifier = readReportLockIdentifier, lockReference = readReportLockReference) return else: if readReportLockIdentifier is not None: from NeonOcean.S4.Main import Debug Debug.Unlock(readReportLockIdentifier, readReportLockReference) callReportLockIdentifier = None # type: typing.Optional[str] callReportLockReference = None # type: typing.Any if self.LimitErrors: callReportLockIdentifier = __name__ + ":" + str(Python.GetLineNumber()) # type: str callReportLockReference = announcer try: if self.AnnouncementCallWrapper is None: announcementMethod(*announcementArgs, **announcementKwargs) else: self.AnnouncementCallWrapper(announcementMethod, *announcementArgs, **announcementKwargs) except Exception: from NeonOcean.S4.Main import Debug Debug.Log("Failed to trigger the announcement '" + announcementMethodName + "' for '" + Types.GetFullName(announcer) + "'.", announcer.Host.Namespace, Debug.LogLevels.Exception, group = announcer.Host.Namespace, owner = __name__, lockIdentifier = callReportLockIdentifier, lockReference = callReportLockReference) return else: if callReportLockIdentifier is not None: from NeonOcean.S4.Main import Debug Debug.Unlock(callReportLockIdentifier, callReportLockReference)
def run(self) -> None: if self._repeat: lastInterval = self.Interval # type: float sleepStartTime = time.time() # type: float targetTime = sleepStartTime + lastInterval # type: float sleepTime = lastInterval # type: float while self.isAlive(): time.sleep(sleepTime) if self.isAlive(): self._CallCallback() sleepEndTime = time.time() # type: float sleepTimeOversleep = sleepEndTime - targetTime # type: float if self.Interval != lastInterval: sleepTimeOversleep = max( min(sleepTimeOversleep, self.Interval), -self.Interval) sleepTime = self.Interval - sleepTimeOversleep # type: float if sleepTime < 0: if not self._reportedMissedTick: actualSleepTime = sleepEndTime - sleepStartTime # type: float Debug.Log( "A timer slept over an interval. This will be the only warning though there may be more missed ticks. Interval: '" + str(self.Interval) + "' Actual Interval: '" + str(actualSleepTime) + "' Callback: '" + Types.GetFullName(self.Callback) + "'", This.Mod.Namespace, level=Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__) self._reportedMissedTick = True sleepTime = 0 lastInterval = self.Interval sleepStartTime = time.time() # type: float targetTime += lastInterval else: if self.isAlive(): time.sleep(self.Interval) if self.isAlive(): self._CallCallback()
def _InvokeOnLoadEvent(self) -> Events.EventArguments: eventArguments = Events.EventArguments() # type: Events.EventArguments for loadCallback in self.OnLoad: # type: typing.Callable[[PersistentBranched, Events.EventArguments], None] try: loadCallback(self, eventArguments) except: Debug.Log("Failed to run the 'OnLoad' callback '" + Types.GetFullName(loadCallback) + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__) return eventArguments
def NotifyBuffRemoved (self, removedBuff: BuffsMenstrual.MenstrualBuffBase) -> None: """ Notify the effect that a new buff was just added. """ if not isinstance(removedBuff, BuffsMenstrual.MenstrualBuffBase): raise Exceptions.IncorrectTypeException(removedBuff, "removedBuff", (BuffsMenstrual.MenstrualBuffBase,)) eventArguments = CycleEvents.MenstrualEffectBuffRemovedArguments(removedBuff) # type: CycleEvents.MenstrualEffectBuffRemovedArguments for buffRemovedCallback in self.BuffRemovedEvent: try: buffRemovedCallback(self, eventArguments) except: Debug.Log("Failed to call buff removed callback '" + Types.GetFullName(buffRemovedCallback) + "'.\n" + self.AffectingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = buffRemovedCallback)
def InvokeUnregisteredReproductiveSystemEvent( reproductiveSystem: ReproductionShared.ReproductiveSystem) -> None: thisModule = sys.modules[__name__] registeredArguments = RegistrationChangedArguments(reproductiveSystem) for unregisteredEventCallback in UnregisteredReproductiveSystemEvent: try: unregisteredEventCallback(thisModule, registeredArguments) except: Debug.Log( "Failed to run unregistered reproductive system event callback " + Types.GetFullName(unregisteredEventCallback), This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__)
def _TargetException (exception: BaseException) -> None: originalCallableFullName = Types.GetFullName(information.OriginalCallable) # type: str if originalCallableFullName == Types.GetFullName(log.exception): Debug.Log("Failed to call target function '" + Types.GetFullName(information.TargetFunction) + "'. Original callable: '" + originalCallableFullName + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, exception = exception, logToGame = False) information.OriginalCallable(This.Mod.Namespace, "Failed to call target function '" + Types.GetFullName(information.TargetFunction) + "'. Original callable: '" + originalCallableFullName + "'.", exc = exception) else: if originalCallableFullName == Types.GetFullName(log.Logger.exception): Debug.Log("Failed to call target function '" + Types.GetFullName(information.TargetFunction) + "'. Original callable: '" + originalCallableFullName + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, exception = exception, logToGame = False) information.OriginalCallable(log.Logger(This.Mod.Namespace), "Failed to call target function '" + Types.GetFullName(information.TargetFunction) + "'. Original callable: '" + originalCallableFullName + "'.", exc = exception) else: Debug.Log("Failed to call target function '" + Types.GetFullName(information.TargetFunction) + "'. Original callable: '" + originalCallableFullName + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, exception = exception)
def DoCycleAbortTesting (self) -> CycleEvents.CycleAbortTestingArguments: """ Test if the currently active cycle should abort. :return: Testing event arguments that carry information on whether or not the current cycle should abort. :rtype: EventsCycles.CycleAbortTestingArguments """ eventArguments = CycleEvents.CycleAbortTestingArguments() # type: CycleEvents.CycleAbortTestingArguments for cycleAbortTestingCallback in self.CycleAbortTestingEvent: try: cycleAbortTestingCallback(self, eventArguments) except: Debug.Log("Failed to call cycle abort testing callback '" + Types.GetFullName(cycleAbortTestingCallback) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = cycleAbortTestingCallback) return eventArguments
def _AddMissingEffects (self) -> None: activeTypeIdentifiers = set(effect.TypeIdentifier for effect in self.ActiveEffects) # type: typing.Set[str] allTypeIdentifiers = EffectsTypes.GetAllEffectTypeIdentifiers() # type: typing.Set[str] for typeIdentifier in allTypeIdentifiers: # type: str if not typeIdentifier in activeTypeIdentifiers: addingEffectType = EffectsTypes.GetEffectType(typeIdentifier) try: addingEffect = addingEffectType(self.TrackingSystem) # type: EffectsBase.EffectBase except: Debug.Log("Failed to create instance of the effect type '" + Types.GetFullName(addingEffectType) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":CreatingEffect", lockReference = addingEffectType) continue self._AddEffect(addingEffect)
def DoCycleReleaseOvumTesting (self, ovumRelease: CycleOvumRelease.OvumRelease) -> CycleEvents.CycleReleaseOvumTestingArguments: """ Test if the a cycle should release an ovum. :param ovumRelease: The object that has indicated to the cycle that an ovum should release. :type ovumRelease: CycleOvumRelease.OvumRelease :return: Testing event arguments that carry information on whether or not a cycle should release an ovum. :rtype: EventsCycles.CycleReleaseOvumTestingArguments """ eventArguments = CycleEvents.CycleReleaseOvumTestingArguments(ovumRelease) # type: CycleEvents.CycleReleaseOvumTestingArguments for cycleReleaseOvumTestingCallback in self.CycleReleaseOvumTestingEvent: try: cycleReleaseOvumTestingCallback(self, eventArguments) except: Debug.Log("Failed to call cycle release ovum testing callback '" + Types.GetFullName(cycleReleaseOvumTestingCallback) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = cycleReleaseOvumTestingCallback) return eventArguments
def _NotifyHandlerRemoved( self, removedHandler: HandlersBase.HandlerBase) -> None: eventArguments = CycleEvents.HandlerRemovedArguments( removedHandler) # type: CycleEvents.HandlerRemovedArguments for handlerRemovedCallback in self.HandlerRemovedEvent: try: handlerRemovedCallback(self, eventArguments) except: Debug.Log("Failed to call handler removed callback '" + Types.GetFullName(handlerRemovedCallback) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__, lockIdentifier=__name__ + ":" + str(Python.GetLineNumber()), lockReference=handlerRemovedCallback)
def GetDoesNotInheritExceptionText (valueName: str, correctParents: typing.Tuple[typing.Union[type, str], ...], *additional) -> str: if not isinstance(valueName, str): raise IncorrectTypeException(valueName, "valueName", (str,)) if not isinstance(correctParents, tuple): raise IncorrectTypeException(correctParents, "correctParents", (tuple,)) if len(correctParents) == 0: raise Exception("This exception must receive at least one correct type") for correctParentIndex in range(len(correctParents)): # type: int if isinstance(correctParents[correctParentIndex], type): continue if isinstance(correctParents[correctParentIndex], str): continue if correctParents[correctParentIndex] is None: continue raise IncorrectTypeException(correctParents[correctParentIndex], "correctParents[%d]" % correctParentIndex, (type, str, None)) correctString = "'{}'" + (", '{}'" * (len(correctParents) - 2) if len(correctParents) > 2 else "") + (" or '{}'" if len(correctParents) > 1 else "") formatList = list() formatList.append(valueName) for correctParentIndex in range(0, len(correctParents)): if isinstance(correctParents[correctParentIndex], type) or correctParents[correctParentIndex] is None: formatList.append(Types.GetFullName(correctParents[correctParentIndex])) elif isinstance(correctParents[correctParentIndex], str): formatList.append(correctParents[correctParentIndex]) else: formatList.append("") exceptionString = ("Expected '{}' to inherit " + correctString + "").format(*formatList) for additionalObject in additional: # type: typing.Any exceptionString += "\n" + str(additionalObject) return exceptionString
def _CurrentCycleCompletedCallback (self, completionReason: CycleShared.CompletionReasons) -> None: eventArguments = CycleEvents.CycleCompletedArguments(completionReason) # type: CycleEvents.CycleCompletedArguments for cycleCompletedCallback in self.CycleCompletedEvent: try: cycleCompletedCallback(self, eventArguments) except: Debug.Log("Failed to call cycle completed callback '" + Types.GetFullName(cycleCompletedCallback) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = cycleCompletedCallback) self.CurrentCycle = None self.CompletedInitialCycle = True self.CompletedFirstCycle = True self.TimeSinceLastCycle = None self.LastCycleCompletionReason = completionReason if completionReason == CycleShared.CompletionReasons.Finished: self.TimeSinceLastCycle = 0 # TODO this should be set only if the sim experiences any symptoms instead.
def DoCycleStartTesting (self) -> CycleEvents.CycleStartTestingArguments: """ Test for when the next cycle is to start and of what type it will be. :return: Testing event arguments that carry information on whether or not a cycle should start. :rtype: EventsCycles.CycleStartTestingArguments """ if self.CycleStartTestingSeed is None: self.CycleStartTestingSeed = self.TrackingSystem.CurrentSeed eventArguments = CycleEvents.CycleStartTestingArguments(self.CycleStartTestingSeed, self.TimeSinceLastCycle) # type: CycleEvents.CycleStartTestingArguments self.CycleStartTestingEvent.Invoke(self, eventArguments) for cycleStartTestingCallback in self.CycleStartTestingEvent: try: cycleStartTestingCallback(self, eventArguments) except: Debug.Log("Failed to call cycle start testing callback '" + Types.GetFullName(cycleStartTestingCallback) + "'.\n" + self.TrackingSystem.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = cycleStartTestingCallback) return eventArguments
def InvokeModLoadedEvent(mod: Mods.Mod) -> ModLoadedEventArguments: """ Invokes the mod loaded event. Should be triggered every time a mod is loaded. :param mod: A reference the mod in question. :type mod: Mods.Mod :rtype: None """ eventArguments = ModLoadedEventArguments( mod) # type: ModLoadedEventArguments for modLoadedCallback in ModLoadedEvent: try: modLoadedCallback(sys.modules[__name__], eventArguments) except: Debug.Log("Failed to invoke a mod loaded callback at '" + Types.GetFullName(modLoadedCallback) + "'.", This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__) return eventArguments
def _ActivateResetCallbacks(self) -> bool: operationInformation = "Save Identifier: %s | Section Identifier: %s" % ( self.SavingObject.Identifier, self.Identifier, ) operationSuccessful = True # type: bool for resetCallback in self._resetCallbacks: # type: typing.Callable[[Saving.SectionBase], bool] try: callbackSuccess = resetCallback(self) # type: bool if not callbackSuccess: operationSuccessful = False except: Debug.Log("Failed to activate reset callback at '" + Types.GetFullName(resetCallback) + "'.\n" + operationInformation, self.SavingObject.Host.Namespace, Debug.LogLevels.Exception, group=self.SavingObject.Host.Namespace, owner=__name__) operationSuccessful = False return operationSuccessful
def Save(self) -> typing.Tuple[bool, str]: """ Encodes the persistent data container to a json string. This method can handle cases in which any persistent data's key or value cannot be encoded. :return: The first value indicates if this method completed without incident. The second is the save data. :rtype: typing.Tuple[bool, dict] """ operationSuccess = True # type: bool saveSuccess, persistentDataContainer = super().Save( ) # type: bool, dict persistentDataBranches = persistentDataContainer[ self. _branchesKey] # type: typing.Dict[str, typing.Dict[str, typing.Any]] persistentDataBranchesValuesString = "" # type: str for branchKey, branchValue in persistentDataBranches.items( ): # type: str, dict branchInformation = "Branch: " + branchKey persistentDataValuesString = "" for persistentKey, persistentValue in branchValue.items( ): # type: str, typing.Any keyInformation = "Key: " + persistentKey # type: str try: assert isinstance(persistentKey, str) persistentKeyString = json.JSONEncoder(indent="\t").encode( persistentKey) # type: str assert "\n" not in persistentKeyString and "\r" not in persistentKeyString except Exception: Debug.Log( "Failed to encode a persistence key to a json string.\n" + branchInformation + "\n" + keyInformation, self.HostNamespace, Debug.LogLevels.Exception, group=self.HostNamespace, owner=__name__) operationSuccess = False continue valueInformation = "Value Type: " + Types.GetFullName( persistentKey ) + "\nValue Value: " + persistentKey # type: str try: persistentValueString = json.JSONEncoder( indent="\t").encode(persistentValue) # type: str except Exception: Debug.Log( "Failed to encode a persistence value to a json string.\n" + branchInformation + "\n" + keyInformation + "\n" + valueInformation, self.HostNamespace, Debug.LogLevels.Exception, group=self.HostNamespace, owner=__name__) operationSuccess = False continue persistentValueString = persistentValueString.replace( "\n", "\n\t\t\t") if persistentDataValuesString != "": persistentDataValuesString += ",\n" persistentDataValuesString += "\t\t\t" + persistentKeyString + ": " + persistentValueString if persistentDataBranchesValuesString != "": persistentDataBranchesValuesString += ",\n" persistentDataBranchesValuesString += "\t\t\"" + branchKey + "\": {" if persistentDataBranchesValuesString != "": persistentDataBranchesValuesString += "\n" + persistentDataValuesString + "\n\t\t}" else: persistentDataBranchesValuesString += "}" persistentDataBranchesString = "\t\"" + self._branchesKey + "\": {" # type: str if persistentDataBranchesString != "": persistentDataBranchesString += "\n" + persistentDataBranchesValuesString + "\n\t}" else: persistentDataBranchesString += "}" lastVersion = persistentDataContainer[ self._lastVersionKey] # type: str try: lastVersionString = json.JSONEncoder(indent="\t").encode( lastVersion) # type: str except Exception as e: raise Exception( "Failed to encode a persistence last version to a json string." ) from e lastVersionString = "\t\"" + self._lastVersionKey + "\": " + lastVersionString # type: str persistentDataContainerString = "{\n" + persistentDataBranchesString + ",\n" + lastVersionString + "\n}" # type: str if not saveSuccess: return False, persistentDataContainerString return operationSuccess, persistentDataContainerString
def Patch (originalObject: typing.Any, originalCallableName: str, targetFunction: typing.Callable, patchType: PatchTypes = PatchTypes.After, permanent: bool = False) -> None: """ Combine a function with another function or method, the original callable located in the original object will then be replaced by the patch automatically. :param originalObject: The object the original callable resides in. :type originalObject: typing.Any :param originalCallableName: The name of the callable to be combined, Can be a reference to a function, built in function, or method. :type originalCallableName: str :param targetFunction: The function object that will be combined with the original. This can only be a function or a built in function. :type targetFunction: typing.Callable :param patchType: Controls when the original callable is called. A value of PatchTypes.Custom requires that the target function take an extra argument in the first argument position. The extra argument will be a reference to the original callable. :type patchType: PatchTypes :param permanent: Whether or not the patch will be disabled if the module the patching function resides in is unloaded. :type permanent: bool """ if originalObject is None: raise TypeError("originalObject cannot be none.") if not isinstance(originalCallableName, str): raise Exceptions.IncorrectTypeException(originalCallableName, "originalCallableName", (str,)) originalCallable = getattr(originalObject, originalCallableName) # type: typing.Callable if originalCallable is None: raise Exception("Cannot find attribute named '" + originalCallableName + "' in '" + Types.GetFullName(originalObject) + "'.") patchedFunction = PatchDirectly(originalCallable, targetFunction, patchType = patchType, permanent = permanent) setattr(originalObject, originalCallableName, patchedFunction)
def Compare (cls, leftVersion, rightVersion) -> int: """ Compare two version objects together. :return: Less than zero, if the left version is less than the right version. Zero, If the left and right version are equal. Greater than zero, If the left version is greater than the right version. :rtype: int """ if not isinstance(leftVersion, Version) or not isinstance(rightVersion, Version): raise TypeError("Version compare operations are not supported between instances of '%s' and '%s'" % (Types.GetFullName(leftVersion), Types.GetFullName(rightVersion))) if leftVersion.Major != rightVersion.Major: if leftVersion.Major < rightVersion.Major: return -1 else: return 1 if leftVersion.Minor != rightVersion.Minor: if leftVersion.Minor < rightVersion.Minor: return -1 else: return 1 leftPatch = leftVersion.Patch if leftVersion.Patch >= 0 else 0 # type: int rightPatch = rightVersion.Patch if rightVersion.Patch >= 0 else 0 # type: int if leftPatch != rightPatch: if leftPatch < rightPatch: return -1 else: return 1 if len(leftVersion.PreRelease) != 0 and len(rightVersion.PreRelease) == 0: return -1 elif len(leftVersion.PreRelease) == 0 and len(rightVersion.PreRelease) != 0: return 1 for preReleaseIndex in range(len(leftVersion.PreRelease)): # type: int if len(rightVersion.PreRelease) - 1 < preReleaseIndex: break leftPreReleaseIdentifier = leftVersion.PreRelease[preReleaseIndex] # type: typing.Union[str, int] rightPreReleaseIdentifier = rightVersion.PreRelease[preReleaseIndex] # type: typing.Union[str, int] if leftPreReleaseIdentifier == rightPreReleaseIdentifier: continue if isinstance(leftPreReleaseIdentifier, int) and isinstance(rightPreReleaseIdentifier, str): return -1 elif isinstance(leftPreReleaseIdentifier, str) and isinstance(rightPreReleaseIdentifier, int): return 1 assert isinstance(leftPreReleaseIdentifier, int) and isinstance(rightPreReleaseIdentifier, int) or \ isinstance(leftPreReleaseIdentifier, str) and isinstance(rightPreReleaseIdentifier, str) if leftPreReleaseIdentifier < rightPreReleaseIdentifier: return -1 else: return 1 if len(leftVersion.PreRelease) < len(rightVersion.PreRelease): return -1 elif len(leftVersion.PreRelease) > len(rightVersion.PreRelease): return 1 return 0
def __str__ (self): if self.TargetFunction is not None: return "Failed to invoke the function at '" + Types.GetFullName(self.TargetFunction) + "' as it was already active in another thread." else: return "Failed to invoke a function as it was already active in another thread."
def FindGuideGroup (simInfo: sim_info.SimInfo) -> typing.Optional[GuideGroup]: """ Return the first guide group found that is appropriate for the specified sim. This will return None if no appropriate one is found. """ if not isinstance(simInfo, sim_info.SimInfo): raise Exceptions.IncorrectTypeException(simInfo, "simInfo", (sim_info.SimInfo,)) for guideGroup in _guideGroups: # type: GuideGroup try: if guideGroup.Matches(simInfo): return guideGroup except Exception as e: Debug.Log("Encountered an unhandled exception when checking if a guide group matches a sim. Matcher: " + Types.GetFullName(guideGroup.Matcher), This.Mod.Namespace, Debug.LogLevels.Exception, group = This.Mod.Namespace, owner = __name__, exception = e) return None
def _ResolveRegularTags (text: str, tokens: typing.Sequence, languageHandler: typing.Type[LanguageHandlers.LanguageHandlerBase]) -> typing.Optional[str]: # This doesn't completely replace the game's stbl formatting system. correctedText = "" # type: str uncorrectedTextStartPosition = None # type: typing.Optional[int] def doSpecialAdjustments (adjustingText: str, specialAdjustmentIdentifiers: typing.List[str]) -> str: adjustedText = adjustingText # type: str for specialAdjustmentIdentifier in specialAdjustmentIdentifiers: # type: str specialAdjustmentIdentifierLower = specialAdjustmentIdentifier.lower() # type: str # noinspection SpellCheckingInspection if specialAdjustmentIdentifierLower == "xxupper": adjustedText = adjustedText.upper() elif specialAdjustmentIdentifierLower == "xxlower": # I didn't actually test if this is actually possible in the base game. adjustedText = adjustedText.lower() for specialAdjustmentIdentifier in specialAdjustmentIdentifiers: # type: str specialAdjustmentIdentifierLower = specialAdjustmentIdentifier.lower() # type: str # noinspection SpellCheckingInspection if specialAdjustmentIdentifierLower == "enan": if adjustingText.startswith(("a", "e", "i", "o", "u")): adjustedText = "an " + adjustedText else: adjustedText = "a " + adjustedText elif specialAdjustmentIdentifierLower == "enhouseholdnameplural": adjustedText = adjustedText + " household" return adjustedText def addText (addingText: str) -> None: nonlocal correctedText if len(tagTextSpecialParts) != 0: addingText = doSpecialAdjustments(addingText, tagTextSpecialParts) correctedText += text[uncorrectedTextStartPosition: tagStartPosition] + addingText def addTokenText (addingLocalizationToken) -> None: nonlocal correctedText tokenTypeHandler = tokenTypeHandlers.get(addingLocalizationToken.type, None) if tokenTypeHandler is not None: tokenTypeHandler(addingLocalizationToken) def addSimTokenText (addingLocalizationToken) -> None: if tagText == "SimFirstName": addText(addingLocalizationToken.first_name) elif tagText == "SimLastName": addText(addingLocalizationToken.last_name) elif tagText == "SimName": simName = None # type: typing.Optional[str] if addingLocalizationToken.full_name_key != 0: simName = GetLocalizationStringText(addingLocalizationToken.full_name_key) # type: typing.Optional[str] if simName is None: simName = languageHandler.GetSimFullNameString(addingLocalizationToken.first_name, addingLocalizationToken.last_name) addText(simName) def addStringTokenText (addingLocalizationToken) -> None: if tagText == "String": resolvedStringToken = ResolveSTBLText(addingLocalizationToken.text_string, addingLocalizationToken.text_string.tokens) # type: typing.Optional[str] if resolvedStringToken is not None: addText(resolvedStringToken) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a localization string token." % tagText) def addRawTextTokenText (addingLocalizationToken) -> None: if tagText == "String": addText(addingLocalizationToken.raw_text) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a raw text token." % tagText) def addNumberTokenText (addingLocalizationToken) -> None: if tagText == "Number": addText(str(addingLocalizationToken.number)) elif tagText == "Money": addText(languageHandler.GetMoneyString(tagToken)) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a number token." % tagText) def addObjectTokenText (addingLocalizationToken) -> None: if tagText == "ObjectName": if addingLocalizationToken.custom_name != "": addingText = addingLocalizationToken.custom_name else: addingText = GetLocalizationStringText(addingLocalizationToken.catalog_name_key) elif tagText == "ObjectDescription": if addingLocalizationToken.custom_description != "": addingText = addingLocalizationToken.custom_description else: addingText = GetLocalizationStringText(addingLocalizationToken.catalog_description_key) elif tagText == "ObjectCatalogName": addingText = GetLocalizationStringText(addingLocalizationToken.catalog_name_key) elif tagText == "ObjectCatalogDescription": addingText = GetLocalizationStringText(addingLocalizationToken.catalog_description_key) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for an object token." % tagText) if addingText is not None: if len(tagTextSpecialParts) != 0: doSpecialAdjustments(addingText, tagTextSpecialParts) addText(addingText) # noinspection PyUnresolvedReferences tokenTypeHandlers = { Localization_pb2.LocalizedStringToken.SIM: addSimTokenText, Localization_pb2.LocalizedStringToken.STRING: addStringTokenText, Localization_pb2.LocalizedStringToken.RAW_TEXT: addRawTextTokenText, Localization_pb2.LocalizedStringToken.NUMBER: addNumberTokenText, Localization_pb2.LocalizedStringToken.OBJECT: addObjectTokenText } for regularTagMatch in re.finditer(SingleTagRegularPattern, text): tag, tagTokenIndexString, tagText = regularTagMatch.groups() # type: str tagTextParts = tagText.split("|") # type: typing.List[str] tagText = tagTextParts[0] # type: str tagTextSpecialParts = tagTextParts[1:] # type: typing.List[str] tagTokenIndex = int(tagTokenIndexString) # type: int tagStartPosition = regularTagMatch.start() # type: int tagEndPosition = regularTagMatch.end() # type: int nextUnfixedTextStartPosition = tagEndPosition # type: int try: tagToken = tokens[tagTokenIndex] except IndexError: pass else: if hasattr(tagToken, "populate_localization_token"): temporaryLocalizationToken = Localization_pb2.LocalizedStringToken() # noinspection PyUnresolvedReferences temporaryLocalizationToken.type = Localization_pb2.LocalizedStringToken.INVALID tagToken.populate_localization_token(temporaryLocalizationToken) # noinspection PyTypeChecker addTokenText(temporaryLocalizationToken) elif isinstance(tagToken, numbers.Number): if tagText == "Number": # Tags like these are case sensitive in the base game so they are here as well. addText(str(tagToken)) elif tagText == "Money": addText(languageHandler.GetMoneyString(tagToken)) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a number token." % tagText) elif isinstance(tagToken, str): if tagText == "String": addText(tagToken) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a raw text token." % tagText) elif isinstance(tagToken, Localization_pb2.LocalizedString): if tagText == "String": # noinspection PyUnresolvedReferences tagTokenText = GetLocalizationStringText(tagToken.hash) # type: typing.Optional[str] if tagTokenText is not None: # noinspection PyUnresolvedReferences correctedTagTokenText = ResolveSTBLText(tagTokenText, tuple(tagToken.tokens)) # Any gendered language tags would have already been resolved, it's fine that gendered tokens aren't handled. if correctedTagTokenText is not None: addText(correctedTagTokenText) else: raise _UnsupportedLocalizationStringException("The tag '%s' is an unknown tag for a localization string token." % tagText) elif isinstance(tagToken, Localization_pb2.LocalizedStringToken): # noinspection PyTypeChecker addTokenText(tagToken) else: raise _UnsupportedLocalizationStringException("Unsupported token type '%s'." % Types.GetFullName(tagToken)) uncorrectedTextStartPosition = nextUnfixedTextStartPosition correctedText += text[uncorrectedTextStartPosition:] return correctedText