def SetTolerance(self, for_whom, who, tolerance): invalid_belongs = [] min_id = self.minID max_id = self.maxID for_whom = [int(belong) for belong in for_whom.split()] invalid_belongs.extend( [bel for bel in for_whom if bel > self.maxID or bel < self.minID]) who = [int(belong) for belong in who.split()] invalid_belongs.extend( [bel for bel in who if bel > self.maxID or bel < self.minID]) if invalid_belongs: for belong in invalid_belongs: logger.warning( f"Invalid belong {belong} listed in relationship map! " f"Belong should be between {self.minID} and {self.maxID}") for who_belong in who: for whom_belong in for_whom: if whom_belong != who_belong: # strange native way to store belong to belong tolerance mappings self.pTolerance[whom_belong + (who_belong - min_id) * (max_id - min_id + 1) - min_id] = tolerance self.pTolerance[who_belong + (whom_belong - min_id) * (max_id - min_id + 1) - min_id] = tolerance else: logger.warning( f"Belong {who_belong} is in both 'forwhom' and 'who' attribs of set!" )
def _LoadVehiclePartTypeToResourceXmlFile(self, some_other_int, fileName): vehiclePartTypesXmlNode = xml_to_objfy(fileName) if vehiclePartTypesXmlNode.tag == "VehiclePartTypes": if len(vehiclePartTypesXmlNode.getchildren()) > 0: check_mono_xml_node(vehiclePartTypesXmlNode, "VehiclePart") for vehicle_part in vehiclePartTypesXmlNode["VehiclePart"]: vehiclePartName = read_from_xml_node( vehicle_part, "PartName") resourceName = read_from_xml_node(vehicle_part, "ResourceName") if self.GetResourceId(resourceName) == -1: logger.warning( f"ResourceManager: warning - invalid resource name '{resourceName}' " f"is matched to vehicle part type '{vehiclePartName}'" ) else: if self.vehiclePart2Resource.get( vehiclePartName) is None: self.vehiclePart2Resource[ vehiclePartName] = resourceName else: raise NameError( f"ResourceManager: Can't add vehicle part with name {vehiclePartName} " f"to vehiclePart2Resource map. Already exist mapping with this name." ) else: raise FileNotFoundError("Can't load VehiclePartTypes from XML!")
def _ReadResourceFromXml(self, xmlFile, xmlNode, parent=0): resource = Resource(parent) resource.id = -1 resource.parentId = -1 resource.name = '' resource.geomSize_x = -1 resource.geomSize_y = -1 has_parent = parent != 0 if has_parent: resource.geomSize_x = parent.geomSize_x resource.geomSize_y = parent.geomSize_y resource.parentId = parent.id resource.LoadFromXML(xmlFile, xmlNode) if self.resourceMap.get(resource.name) is None: self.resourceMap[resource.name] = resource else: logger.warning(f"Error: duplicate resource name: {resource.name}") resourceVectorSize = len(self.resourceVector) resource.id = resourceVectorSize self.resourceVector.append(resource) if len(xmlNode.getchildren()) > 0: check_mono_xml_node(xmlNode, "Type") for child in xmlNode["Type"]: self._ReadResourceFromXml(xmlFile, child, resource)
def LoadFromXML(self, xmlFile, xmlNode): self.name = read_from_xml_node(xmlNode, "Name") self.damageCoeffForPlayerFromEnemies = float(read_from_xml_node(xmlNode, "EnemyWeaponCoeff")) self.enemiesShootingDelay = float(read_from_xml_node(xmlNode, "EnemyShootingDelay")) if self.damageCoeffForPlayerFromEnemies < 0.0: logger.warning("Invalid EnemyWeaponCoeff! Should be a positive float number!") if self.enemiesShootingDelay < 0.0 or self.enemiesShootingDelay > 3.0: logger.warning("Invalid EnemyShootingDelay! Should be a positive float number between 0.0 and 3.0")
def child_from_xml_node(xml_node: objectify.ObjectifiedElement, child_name: str, do_not_warn: bool = False): '''Get child from ObjectifiedElement by name''' try: return xml_node[child_name] except AttributeError: if not do_not_warn: logger.warning(f"There is no child with name {child_name} for xml node {xml_node.tag} in {xml_node.base}") return None
def AddAffix(self, affix: Affix): if self.GetAffixIdByNameAndResource( affix.name, affix.affixGroup.targetResourceId) != -1: logger.warning(f"Affix {affix.name} already exists for resource!") else: affix.affixId = len(self.affixes) self.affixes.append(affix) self.affix_map[affix.name] = affix
def GetResourceNameByVehiclePartName( self, vehiclePartName): # (self, *result, vehiclePartName) in original res_name = self.vehiclePart2Resource.get(vehiclePartName) if res_name is not None: return res_name else: logger.warning( f"ResourceManager: can't find ResourceName for given VehiclePartName : {vehiclePartName}" )
def ParseProto(string_in: str, paramsPos): if len(string_in) < 3: logger.warning(f"No protocol found for '{string_in}'") paramsPos = string_in.find(":") if paramsPos == -1: logger.warning(f"No protocol found for '{string_in}'") elif string_in.find("new") == 0: return 2 elif string_in.find("file") == 0: return 1
def LoadFormat(self, xmlFile, xmlNode, format_type: int = 0): for rel in xmlNode.iterchildren(): if rel.tag != "set": logger.warning( f"Invalid tag {rel.tag} in Relationship map {xmlNode.base}" ) else: tolerance = self.GetToleranceByName( read_from_xml_node(rel, "tolerance")) for_whom = read_from_xml_node(rel, "forwhom") who = read_from_xml_node(rel, "who") self.SetTolerance(for_whom, who, tolerance)
def LoadFromXML(self, fileName): xmlFile = xml_to_objfy(fileName) if xmlFile.tag == "Affixes": check_mono_xml_node(xmlFile, "ForResource") for resource_node in xmlFile["ForResource"]: resource_name = read_from_xml_node(resource_node, "Name") resource_id = self.theResourceManager.GetResourceId( resource_name) if resource_id == -1: logger.warning( f"Error loading affixes: invalid resource name: {resource_name}" ) else: prefixes = child_from_xml_node(resource_node, "Prefixes", do_not_warn=True) suffixes = child_from_xml_node(resource_node, "Suffixes", do_not_warn=True) if prefixes is not None: check_mono_xml_node(prefixes, "AffixGroup") for affix_group_node in child_from_xml_node( prefixes, "AffixGroup"): affix_group = AffixGroup(self) affix_group.affixType = 0 affix_group.LoadFromXML(xmlFile, affix_group_node) affix_groups_list_size = len(self.affixGroups) affix_group.affixGroupId = affix_groups_list_size affix_group.targetResourceId = resource_id self.affixGroups.append(affix_group) if suffixes is not None: check_mono_xml_node(suffixes, "AffixGroup") for affix_group_node in child_from_xml_node( suffixes, "AffixGroup"): affix_group = AffixGroup(self) affix_group.affixType = 1 affix_group.LoadFromXML(xmlFile, affix_group_node) affix_groups_list_size = len(self.affixGroups) affix_group.affixGroupId = affix_groups_list_size affix_group.targetResourceId = resource_id self.affixGroups.append(affix_group) if suffixes is None and prefixes is None: logger.warning( f"Affixes node for resource {resource_name} has no Prefixes and no Suffixes!" ) else: raise NameError("Affixes file should contain root Affixes tag")
def parse_str_to_bool(original_value, string: str, is_striped=False): if string is None: return original_value if string.lower() == "true" or string == "1" or string == "yes": return True elif string.lower() == "false" or string == "0" or string == "no": return False else: if not is_striped: logger.warning(f"Invalid str passed to parse to bool: '{string}'") return parse_str_to_bool(original_value, string.strip(), True) else: return False
def parse_config(xml_file): config = {} tree = xml_to_objfy(xml_file) if tree.tag == 'config': config_entries = tree.attrib for entry_name in config_entries: if config.get(entry_name) is None: config[entry_name] = config_entries[entry_name] else: logger.warning(f"There is a duplicate config value with name: {entry_name}, " f"will be using last available value for the name.") config[entry_name] = config_entries[entry_name] return config else: raise NameError("Config should contain config tag with config entries as attributes!")
def AddAllItems(self, filepath): '''Replacement to read all models from animmodels.xml''' xml_file_node = xml_to_objfy(filepath) if xml_file_node.tag == "AnimatedModels": for model_node in xml_file_node.iterchildren(tag="model"): anim_model = self.AnimatedModel() anim_model.model_id = safe_check_and_set( anim_model.model_id, model_node, "id") anim_model.file_name = safe_check_and_set( anim_model.file_name, model_node, "file") # ToDo: deprecate check on duplication if not needed if self.models.get(anim_model.model_id) is not None: logger.warning( f"Duplicate model found in animmodels.xml with id: '{anim_model.model_id}'" ) self.models[anim_model.model_id] = anim_model
def GetStringByStringId(self, str_id, localizationIndex: str = ''): '''Get localizied string by id, where id is the service name''' if len(localizationIndex) > 0: if localizationIndex in ["0", "1"]: localizationIndex = f"_localizedform_{localizationIndex}" else: logger.warning( "Invalid localization index, only empty, 0 and 1 available" ) string = self.strings.get(f"{str_id}{localizationIndex}") if string is not None: return string else: logger.warning( f"String name given is not in String Dictionary: {str_id}")
def LoadFromXML(self, xmlFile, copy_to_default: bool = True): xmlNode = xml_to_objfy(xmlFile) if xmlNode.tag != "relationship": raise ValueError( "Relationship XML should contain root tag 'relationship'!") formatType = 0 self.minID = int(read_from_xml_node(xmlNode, "MinPlayerID")) self.maxID = int(read_from_xml_node(xmlNode, "MaxPlayerID")) default_tolerance_name = read_from_xml_node(xmlNode, "DefaultTolerance") self.defaultTolerance = self.GetToleranceByName(default_tolerance_name) if self.minID <= self.maxID: if self.maxID - self.minID + 1 > 1000: self.maxID = self.minID + 1001 logger.warning( f"Tolerance range can't be more than 1001, for example 1000-2001 range is valid." f"Reseting max value to be {self.maxID}") self.pTolerance = {} tolerance_range_len = self.maxID - self.minID tolerance_id_range = range(0, tolerance_range_len**2) for tolerance_id in tolerance_id_range: self.pTolerance[tolerance_id] = self.defaultTolerance format_type_read = read_from_xml_node(xmlNode, "FormatType", do_not_warn=True) if format_type_read is not None: formatType = int(format_type_read) if formatType != 0: if formatType == 1: raise NotImplementedError( "Can't work with saves yet, do not load from currentmap.xml" ) self.LoadFormat( xmlFile, xmlNode, 1) # ??? do we even need this for format_type 1? else: raise ValueError( f"Invalid format type {formatType} for relationship") else: self.LoadFormat(xmlFile, xmlNode, 0) if copy_to_default: self.pDefaultTolerance = self.pTolerance else: raise ValueError( "Relationship MinPlayerID should be less than MaxPlayerID")
def read_from_xml_node(xml_node: objectify.ObjectifiedElement, attrib_name: str, do_not_warn: bool = False): attribs = xml_node.attrib if attribs: prot = attribs.get(attrib_name) if prot is not None: return prot else: if not do_not_warn: logger.warning(f"There is no attrib with the name: {attrib_name} " f"in a tag {xml_node.tag} of {xml_node.base}") return None else: logger.warning(f"Node {xml_node.tag} of {xml_node.base} is empty!") if xml_node.tag == "comment": log_comment(xml_node, xml_node.getparent()) return None
def ReadFromXmlNode(self, xmlFile, xmlNode, warn_on_duplication=True): if xmlNode is not None: check_mono_xml_node(xmlNode, "Item") for item_node in xmlNode.iterchildren(tag="Item"): item = self.ServerItem() item.id = safe_check_and_set(item.id, item_node, "id") item.params = safe_check_and_set(item.params, item_node, "params") item.filename = safe_check_and_set(item.filename, item_node, "file") if self.items_map.get(item.id) is None: self.items_list.append(item) self.items_map[item.id] = item elif warn_on_duplication: path = unquote(xmlFile.base) logger.warning( f"Duplicate server item with id: '{item.id}' encountered in '{path}'" )
def check_mono_xml_node(xml_node: objectify.ObjectifiedElement, expected_child_name: str, ignore_comments: bool = False): children = xml_node.getchildren() if len(children) > 0: for child in children: if child.tag != expected_child_name: if child.tag == "comment" and not ignore_comments: comment = unescape(str(etree.tostring(child))).strip("b'<!-- ").strip(" -->'") path = unquote(xml_node.base).replace(f'file:/{WORKING_DIRECTORY}', '') logger.debug(f"Comment '{comment}' " f"in tag: '{xml_node.tag}'' " f"in file: {path}.") else: logger.warning(f"Unexpected node with a name {child.tag} found " f"in xml node: {xml_node.tag} in {xml_node.base}!") else: logger.error(f"Empty node with a name {xml_node.tag} when expecting to find child " f"nodes with a name {expected_child_name} in {xml_node.base}")
def GetAffixGroupsByResourceId(self, resourceId): if not self.affixGroups: return -1 else: if resourceId != -1: valid_afx_gr = [ afx_gr for afx_gr in self.affixGroups if self.theResourceManager.ResourceIsKindOf( resourceId, afx_gr.targetResourceId) ] if len(valid_afx_gr) > 1: logger.warning( f"There is more than one available affixGroup for resource id {resourceId}!" ) return valid_afx_gr[0] else: raise ValueError( f"Invalid resourceId given, can't return AffixGroup!")
def IsKindOf(self, theResourceManager, resourceId): resourceVector = theResourceManager.resourceVector resourceVectorSize = len(resourceVector) if self.id == -1: return False if self.id == resourceId: return True if resourceVector: if self.id < 0 or self.id > resourceVectorSize: logger.warning( f"Resource id given is {self.id}, resourceVector size is {resourceVectorSize}" ) return False elif self.parentId == -1: return False elif self.parentId == resourceId: return True else: return False else: logger.error("theResourceManager doesn't have a resourceVector!") return False
def is_xml_node_contains(xml_node: objectify.ObjectifiedElement, attrib_name: str): attribs = xml_node.attrib if attribs: return attribs.get(attrib_name) is not None else: logger.warning(f"Asking for attributes of node without attributes: {xml_node.base}")
def LoadFromXML(self, xmlFile, xmlNode): namedBelongIds = read_from_xml_node(xmlNode["Belongs"], "Values") self.namedBelongIds = [int(belong) for belong in namedBelongIds.split()] self.namedBelongIdsVector = self.namedBelongIds # ??? are both needed? izvratRepositoryMaxSize = read_from_xml_node(xmlNode["IzvratRepository"], "MaxSize") self.izvratRepositoryMaxSize_x = int(izvratRepositoryMaxSize.split()[0]) self.izvratRepositoryMaxSize_y = int(izvratRepositoryMaxSize.split()[1]) groundRepositorySize = read_from_xml_node(xmlNode["GroundRepository"], "Size") self.groundRepositorySize_x = int(groundRepositorySize.split()[0]) self.groundRepositorySize_y = int(groundRepositorySize.split()[1]) self.gameTimeMult = float(read_from_xml_node(xmlNode["Mult"], "GameTimeMult")) if self.gameTimeMult <= 0.000099999997: logger.warning("GameTimeMult is too low! Set to 0.0001 or higher") self.vehicleAiFiringRangeMult = read_from_xml_node(xmlNode["Mult"], "VehicleAIFiringRangeMult") self.maxBurstTime = int(read_from_xml_node(xmlNode["BurstParameters"], "MaxBurstTime")) self.minBurstTime = int(read_from_xml_node(xmlNode["BurstParameters"], "MinBurstTime")) self.timeBetweenBursts = int(read_from_xml_node(xmlNode["BurstParameters"], "TimeBetweenBursts")) self.probabilityToGenerateDynamicQuestInTown = \ float(read_from_xml_node(xmlNode["DynamicQuest"], "ProbabilityToGenerateDynamicQuestInTown")) if self.probabilityToGenerateDynamicQuestInTown < 0.0 or self.probabilityToGenerateDynamicQuestInTown > 1.0: logger.warning("ProbabilityToGenerateDynamicQuestInTown value is invalid! Set between 0.0 and 1.0") self.pathToRelationship = read_from_xml_node(xmlNode["CommonPaths"], "Relationship") self.pathToGameObjects = read_from_xml_node(xmlNode["CommonPaths"], "GameObjects") self.pathToQuests = read_from_xml_node(xmlNode["CommonPaths"], "Quests") self.pathToResourceTypes = read_from_xml_node(xmlNode["CommonPaths"], "ResourceTypes") self.pathToAffixes = read_from_xml_node(xmlNode["CommonPaths"], "Affixes") self.pathToVehiclePartTypes = read_from_xml_node(xmlNode["CommonPaths"], "VehiclePartTypes") self.distToTurnOnPhysics = float(read_from_xml_node(xmlNode["Physics"], "DistToTurnOnPhysics")) self.distToTurnOffPhysics = float(read_from_xml_node(xmlNode["Physics"], "DistToTurnOffPhysics")) self.physicStepTime = float(read_from_xml_node(xmlNode["Physics"], "PhysicStepTime")) if self.distToTurnOffPhysics - 10.0 <= self.distToTurnOnPhysics: logger.error(f"Differenece between distToTurnOffPhysics {self.distToTurnOffPhysics} and " f"distToTurnOnPhysics {self.distToTurnOnPhysics} is too low: ! " "Set to be at least 10.0 appart") self.barmenModelName = read_from_xml_node(xmlNode["Npc"], "BarmenModelName") self.splintersAutoDisableLinearThreshold = \ float(read_from_xml_node(xmlNode["BreakableObjectSplinters"], "AutoDisableLinearThreshold")) self.splintersAutoDisableAngularThreshold = \ float(read_from_xml_node(xmlNode["BreakableObjectSplinters"], "AutoDisableAngularThreshold")) self.splintersAutoDisableNumSteps = \ int(read_from_xml_node(xmlNode["BreakableObjectSplinters"], "AutoDisableNumSteps")) self.vehiclesDropChests = parse_str_to_bool(self.vehiclesDropChests, read_from_xml_node(xmlNode["Vehicles"], "VehiclesDropChests")) maxSpeedWithNoFuel = float(read_from_xml_node(xmlNode["Vehicles"], "MaxSpeedWithNoFuel")) # ??? why? Is this working? self.maxSpeedWithNoFuel = maxSpeedWithNoFuel * 0.27777779 # 5/18 = 0.2(7) ??? self.infoAreaRadius = int(read_from_xml_node(xmlNode["SmartCursor"], "InfoAreaRadius")) self.lockTimeout = float(read_from_xml_node(xmlNode["SmartCursor"], "LockTimeout")) unlockRegion = read_from_xml_node(xmlNode["SmartCursor"], "UnlockRegion") self.unlockRegion_x = float(unlockRegion.split()[0]) self.unlockRegion_y = float(unlockRegion.split()[1]) # ??? unused in actual game globalproperties.cfg # self.infoObjUpdateTimeout = read_from_xml_node(xmlNode["SmartCursor"], "InfoObjUpdateTimeout") self.blastWaveCameraShakeRadiusCoeff = \ float(read_from_xml_node(xmlNode["CameraController"], "BlastWaveCameraShakeRadiusCoeff")) self.shakeDamageToDurationCoeff = \ float(read_from_xml_node(xmlNode["CameraController"], "ShakeDamageToDurationCoeff")) self.maxShakeDamage = float(read_from_xml_node(xmlNode["CameraController"], "MaxShakeDamage")) if self.maxShakeDamage <= 1.0: logger.warning("maxShakeDamage should be more than 1.0!") self.distanceFromPlayerToMoveout = int(read_from_xml_node(xmlNode["Caravans"], "DistanceFromPlayerToMoveout")) self.defaultLookBoxLength = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "DefaultLookBoxLength")) self.defaultTargetBoxLength = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "DefaultTargetBoxLength")) self.attractiveCoeff = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "AttractiveCoeff")) self.repulsiveCoeff = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "RepulsiveCoeff")) self.maxDistToAvoid = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "MaxDistToAvoid")) self.predictionTime = float(read_from_xml_node(xmlNode["ObstacleAvoidance"], "PredictionTime")) self.throwCoeff = float(read_from_xml_node(xmlNode["DeathProperties"], "ThrowCoeff")) self.flowVpVelocity = float(read_from_xml_node(xmlNode["DeathProperties"], "FlowVpVelocity")) self.flowWheelVelocity = float(read_from_xml_node(xmlNode["DeathProperties"], "FlowWheelVelocity")) self.energyBlowDeltaTime = float(read_from_xml_node(xmlNode["DeathProperties"], "EnergyBlowDeltaTime")) self.energyVpBlowProbability = int(read_from_xml_node(xmlNode["DeathProperties"], "EnergyVpBlowProbability")) self.energyWheelBlowProbability = \ int(read_from_xml_node(xmlNode["DeathProperties"], "EnergyWheelBlowProbability")) self.healthUnitPrice = float(read_from_xml_node(xmlNode["Repair"], "HealthUnitPrice")) self.defaultArticleRegenerationTime = \ float(read_from_xml_node(xmlNode["Articles"], "DefaultRegenerationTime")) self.probabilityToDropArticlesFromDeadVehicles = \ float(read_from_xml_node(xmlNode["Articles"], "ProbabilityToDropArticlesFromDeadVehicles")) self.probabilityToDropGunsFromDeadVehicles = \ float(read_from_xml_node(xmlNode["Articles"], "ProbabilityToDropGunsFromDeadVehicles")) self.zoneRespawnTimeOutIncreaseCoeff = \ float(read_from_xml_node(xmlNode["InfectionZones"], "ZoneRespawnTimeOutIncreaseCoeff")) self.zoneDefaultFirstSpawnTime = \ float(read_from_xml_node(xmlNode["InfectionZones"], "ZoneDefaultFirstSpawnTime")) self.colorFriend = read_from_xml_node(xmlNode["InterfaceStuff"], "ColorFriend") self.colorEnemy = read_from_xml_node(xmlNode["InterfaceStuff"], "ColorEnemy") self.colorTargetCaptured = read_from_xml_node(xmlNode["InterfaceStuff"], "ColorTargetCaptured") self.targetInfoContourWidth = float(read_from_xml_node(xmlNode["InterfaceStuff"], "TargetInfoContourWidth")) self.targetCapturedContourWidth = \ float(read_from_xml_node(xmlNode["InterfaceStuff"], "TargetCapturedContourWidth")) self.playerPassMapUnpassableMu = \ float(read_from_xml_node(xmlNode["PlayerPassmap"], "PlayerPassMapUnpassableMu")) self.playerPassMapUnpassableErp = \ float(read_from_xml_node(xmlNode["PlayerPassmap"], "PlayerPassMapUnpassableErp")) self.playerPassMapUnpassableCfm = \ float(read_from_xml_node(xmlNode["PlayerPassmap"], "PlayerPassMapUnpassableCfm")) fullGroupingAngleDegree = float(read_from_xml_node(xmlNode["Weapon"], "MaxGroupingAngle")) self.maxGroupingAngle = fullGroupingAngleDegree * 0.017453292 * 0.5 # pi/180 = 0.017453292 self.timeOutForReAimGuns = float(read_from_xml_node(xmlNode["Weapon"], "TimeOutForReAimGuns")) for diffLevel in xmlNode["DifficultyLevels"].iterchildren(): if diffLevel.tag == "Level": coeffs = CoeffsForDifficultyLevel() coeffs.LoadFromXML(xmlFile, diffLevel) self.difficultyLevelCoeffs.append(coeffs) else: logger.warning(f"Unexpected tag {diffLevel.tag} in DifficultyLevels enumeration") self.property2PriceCoeff = float(read_from_xml_node(xmlNode["Price"], "Property2PriceCoeff")) if not self.difficultyLevelCoeffs: raise ValueError("No difficulty levels in GlobalProperties!")