Page MenuHomeWildfire Games
Paste P291

Actor to Quality levels
ActivePublic

Authored by Stan on Jan 5 2023, 12:24 AM.
#!/usr/bin/env python3
# -*- mode: python-mode; python-indent-offset: 4; -*-
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
from logging import getLogger, StreamHandler, INFO, WARNING, Formatter, Filter
from pathlib import Path
from sys import stdout, stderr
import xml.etree.ElementTree as ET
import os
import fileinput
class SingleLevelFilter(Filter):
def __init__(self, passlevel, reject):
self.passlevel = passlevel
self.reject = reject
def filter(self, record):
if self.reject:
return (record.levelno != self.passlevel)
else:
return (record.levelno == self.passlevel)
class BaseFixer():
def __init__(self, vfs_root, verbose=False):
self.logger = self.__init_logger()
self.vfs_root = Path(vfs_root)
self.verbose = verbose
self.files = []
def __init_logger(self):
logger = getLogger(__name__)
logger.setLevel(INFO)
# create a console handler, seems nicer to Windows and for future uses
ch = StreamHandler(stdout)
ch.setLevel(INFO)
ch.setFormatter(Formatter('%(levelname)s - %(message)s'))
f1 = SingleLevelFilter(INFO, False)
ch.addFilter(f1)
logger.addHandler(ch)
errorch = StreamHandler(stderr)
errorch.setLevel(WARNING)
errorch.setFormatter(Formatter('%(levelname)s - %(message)s'))
logger.addHandler(errorch)
return logger
def fix_style(self, xml_path):
changes = [
[' />', '/>'],
["version='1.0'", 'version="1.0"'],
["'utf-8'", '"utf-8"']
]
for line in fileinput.input(xml_path, inplace=True):
for change in changes:
line = line.replace(change[0], change[1])
print(line, end="")
with open(xml_path, 'a', encoding='utf-8') as file:
file.write('\n')
def indent(self, elem, level=0, more_sibs=False):
i = "\n"
if level:
i += (level-1) * ' '
num_kids = len(elem)
if num_kids:
if not elem.text or not elem.text.strip():
elem.text = i + " "
if level:
elem.text += ' '
count = 0
for kid in elem:
self.indent(kid, level+1, count < num_kids - 1)
count += 1
if not elem.tail or not elem.tail.strip():
elem.tail = i
if more_sibs:
elem.tail += ' '
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
if more_sibs:
elem.tail += ' '
def sort(self, root):
# sort the first layer
root[:] = sorted(root, key=lambda child: (child.tag,child.get('name')))
# sort the second layer
for c in root:
c[:] = sorted(c, key=lambda child: (child.tag,child.get('name')))
for cp in c:
cp[:] = sorted(cp, key=lambda child: (child.tag,child.get('name')))
for scp in cp:
scp[:] = sorted(scp, key=lambda child: (child.tag,child.get('name')))
def save_xml_file(self, tree, root, xml_file, sort=True):
if sort:
self.sort(root)
self.indent(root)
tree.write(xml_file, xml_declaration=True, encoding='utf-8')
self.fix_style(xml_file)
def add_files(self, path, extensions : tuple[str]):
self.files = []
if os.path.isfile(str(self.vfs_root)):
self.files.append(self.vfs_root)
elif os.path.isdir(str(self.vfs_root)):
for root, _, files in os.walk(str(self.vfs_root)):
for name in files:
file_path = os.path.join(root, name)
if os.path.isfile(file_path) and path in file_path and name.endswith(extensions):
self.files.append(file_path)
if self.verbose:
if len(self.files) > 0:
self.logger.info("Found" {len(self.files)} file(s).")
else:
self.logger.info(f"No files were found.")
class ActorToQualityLevel(BaseFixer):
def __init__(self, vfs_root, verbose=False):
BaseFixer.__init__(self, vfs_root, verbose)
self.add_files('', tuple(".xml"))
def process_actor(self, actorNode):
actorNode.tag = "qualitylevels"
tag1 = ET.Element("actor")
tag1.attrib['quality'] = 'low'
tag1.attrib['inline'] = ''
tag2 = ET.Element("actor")
tag2.attrib['quality'] = 'medium'
tag2.attrib['inline'] = ''
tag3 = ET.Element("actor")
tag3.attrib['inline'] = ''
tag = ET.Element("inline")
tag.attrib['version'] = '1'
groups = list()
for group in reversed(actorNode):
if group.tag == 'castshadow':
group.attrib['minquality'] = 'medium'
groups.append(group)
actorNode.remove(group)
actorNode.append(tag1)
actorNode.append(tag2)
actorNode.append(tag3)
for group in reversed(groups):
tag.append(group)
actorNode.append(tag)
meshGroup = ET.Element("group")
meshes = []
for group in tag:
if group.tag == 'group':
for variant in group:
cmpMesh = variant.find("mesh")
if cmpMesh == None:
continue
meshes.append(cmpMesh.text)
variant.remove(cmpMesh)
for mesh in meshes:
file_name = os.path.basename(mesh)
file_path = mesh.replace(os.path.basename(mesh), "")
# DEFAULT
meshVariant = ET.SubElement(meshGroup, "variant")
meshVariant.attrib['minquality'] = 'high'
meshVariant.attrib['frequency'] = '1'
meshVariant.attrib['name'] = 'mesh-variant'
cmpMesh = ET.SubElement(meshVariant, "mesh")
cmpMesh.text = mesh
# MEDIUM
meshVariant = ET.SubElement(meshGroup, "variant")
meshVariant.attrib['maxquality'] = 'high'
meshVariant.attrib['minquality'] = 'medium'
meshVariant.attrib['frequency'] = '1'
meshVariant.attrib['name'] = 'mesh-variant'
cmpMesh = ET.SubElement(meshVariant, "mesh")
cmpMesh.text = f"{file_path}medium/{file_name}"
# LOW
meshVariant = ET.SubElement(meshGroup, "variant")
meshVariant.attrib['maxquality'] = 'medium'
meshVariant.attrib['frequency'] = '1'
meshVariant.attrib['name'] = 'mesh-variant'
cmpMesh = ET.SubElement(meshVariant, "mesh")
cmpMesh.text = f"{file_path}low/{file_name}"
tag.insert(1 if tag.find('castshadow') is None else 0, meshGroup)
return True
def run(self):
count = 0
for file in self.files:
tree = ET.parse(file)
root = tree.getroot()
changed = False
if root.tag == 'actor':
changed = self.process_actor(root)
elif root.tag == 'qualitylevels':
continue
if changed:
self.save_xml_file(tree, root, file, False)
count = count + 1
self.logger.info(f"Fixed {count} file(s).")
if __name__ == '__main__':
script_dir = "."
mod_name = "public"
print(f"Running in {Path(script_dir) / mod_name}")
print("Converting to quality levels...")
template_fixer = ActorToQualityLevel(Path(script_dir) / mod_name, True)
template_fixer.run()

Event Timeline

Stan created this paste.Jan 5 2023, 12:24 AM
Stan created this object with visibility "Public (No Login Required)".