def LoadServers(self, file_name): anim_models_alias = "AnimatedModelsServer" # static_models_alias = "StaticModelsServer", # light_alias = "LightsServer" # sprite_alias = "SpritesServer" # particles_alias = "ParticlesServer" # sounds_alias = "SoundsServer" # music_alias = "MusicServer" # projectors_alias = "ProjectorsServer" # decals_alias = "DecalsServer" self.servers = {} # 9 servers total animated_models_server = self.ServerContainer( AnimatedModelsServer(), anim_models_alias, theWndStation.GetStringByStringId(anim_models_alias, "0")) self.servers[anim_models_alias] = animated_models_server animated_models_server.server.AddAllItems( os.path.join(WORKING_DIRECTORY, "data/models/animmodels.xml")) logger.info(f"Loading Servers: {file_name}") xml_file_node = xml_to_objfy(file_name) if xml_file_node is not None: for server_node in xml_file_node.iterchildren(): server_container = self.servers.get(server_node.tag) if server_container is not None: logger.info(f"Loading server :{server_container.name}") server_container.server.ReadFromXmlNode( xml_file_node, server_node) else: logger.info( f"Skipping loading unsupported server: {server_node.tag}" ) else: logger.error("Load servers: cannot find Servers")
def GetPrototypeId(self, prototypeName): prot_id = -1 prot_id_from_loaded = self.prototypeNamesToIds.get(prototypeName) if prot_id_from_loaded is None and prototypeName: logger.error( f"No prototype with name '{prototypeName}' registred by PrototypeManager!" ) else: prot_id = prot_id_from_loaded return prot_id
def parse_model_group_health(relative_path: str): logger.debug(f"Trying to parse ModelGroups from '{relative_path}'") group_health = {} with open(os.path.join(WORKING_DIRECTORY, relative_path), 'rb') as f: str_from_file = f.read() if VehicleGamStruct.GROUP_HEALTH_HEADER.value in str_from_file: main_header = VehicleGamStruct.GROUP_HEALTH_HEADER.value elif VehicleGamStruct.GROUP_HEALTH_HEADER_URAL_CARGO.value in str_from_file: main_header = VehicleGamStruct.GROUP_HEALTH_HEADER_URAL_CARGO.value else: logger.debug(f"Model file '{relative_path}' given doesn't contain known GroupHealth headers!") return None group_health["Main"] = {"id": None, "variants": None} if VehicleGamStruct.BREAKABLE_BSTR.value in str_from_file: main_breakable_raw = str_from_file.split(main_header) breakables_raw = main_breakable_raw[1][main_breakable_raw[1].index(VehicleGamStruct.BREAKABLE_BSTR.value):] current_index = 0 while True: if breakables_raw[current_index:current_index + 3] == b"\x49\x56\x52": # IVR break # finding amount of variants for groups which dictates chunk length variants = breakables_raw[current_index + 28] if variants == 2: chunk_size = 60 elif variants == 3: chunk_size = 72 else: logger.error(f"Tried to parse HealthGroups for model containing group with {variants} variants!" "Only 2 and 3 are supported by toolkit!") breakable_string = breakables_raw[current_index:current_index + chunk_size] if VehicleGamStruct.BREAKABLE_BSTR.value in breakable_string: breakable_name = breakable_string[:11].decode('latin-1').replace('\x00', '') breakable_id = int(breakable_string[11:][21:22].hex(), 16) group_health[breakable_name] = {"id": breakable_id, "variants": variants} current_index += chunk_size # for byte_str in breakables_list: # if VehicleGamStruct.BREAKABLE_BSTR.value in byte_str: # breakable_name = byte_str[:11].decode('latin-1').replace('\x00', '') # breakable_id = int(byte_str[11:][21:22].hex(), 16) # group_health[breakable_name] = breakable_id return group_health else: logger.debug(f"Model file '{relative_path}' doesn't contain any breakable health zones.") return group_health
def LoadAdditionalServers(self, file_name): xml_file_node = xml_to_objfy(file_name) if xml_file_node is not None: for server_node in xml_file_node.iterchildren(): server_container = self.servers.get(server_node.tag) if server_container is not None: logger.debug( f"Loading additional server :{server_container.name}") server_container.server.ReadFromXmlNode( xml_file_node, server_node, warn_on_duplication=False) else: logger.debug( f"Skipping loading unsupported server: {server_node.tag}" ) else: logger.error("Load servers: cannot find Servers")
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 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 ReadNewPrototype(self, xmlFile, xmlNode: objectify.ObjectifiedElement): class_name = read_from_xml_node(xmlNode, "Class") logger.debug(f"Loading {class_name} prototype from {xmlNode.base}") prototype_info = self.theServer.CreatePrototypeInfoByClassName( class_name)(self.theServer) if prototype_info: prototype_info.className.value = class_name parent_prot_name = read_from_xml_node(xmlNode, "ParentPrototype", do_not_warn=True) if parent_prot_name is not None: parent_prot_info = self.InternalGetPrototypeInfo( parent_prot_name) dummy = PrototypeInfo(self.theServer) if parent_prot_info is None: logger.error( f"Parent prototype of {class_name} is not loaded! Expected parent: {parent_prot_name}" ) parent_prot_info = dummy prototype_info.CopyFrom(parent_prot_info) prototypes_length = len(self.prototypes) prototype_info.prototypeId = prototypes_length if prototype_info.LoadFromXML(xmlFile, xmlNode) == STATUS_SUCCESS: if self.prototypeNamesToIds.get( prototype_info.prototypeName.value) is not None: logger.critical( f"Duplicate prototype in game objects: {prototype_info.prototypeName.value}" ) raise AttributeError( "Duplicate prototype, critical error!") else: self.prototypeNamesToIds[ prototype_info.prototypeName. value] = prototype_info.prototypeId self.prototypes.append(prototype_info) self.prototypesMap[ prototype_info.prototypeName.value] = prototype_info if prototype_info.className.value not in self.prototypeClasses: self.prototypeClasses.append( prototype_info.className.value) return 1 else: logger.error( f"Prototype {prototype_info.prototypeName.value} " f"of class {prototype_info.className.value} was not loaded!" ) return 0 else: logger.error("Invalid class name: <{class_name}>!") return 0
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!")