Improve the validator.py script. Fix false positives with particles and variants. Use a logger instead.

This was SVN commit r26333.
This commit is contained in:
Stan 2022-02-09 22:07:36 +00:00
parent 0e1da6af7a
commit adcd1d105c

View File

@ -2,10 +2,9 @@
import argparse
import os
import re
import sys
import time
import xml.etree.ElementTree
from logging import getLogger, StreamHandler, INFO, Formatter
class Actor:
def __init__(self, mod_name, vfs_path):
@ -14,20 +13,45 @@ class Actor:
self.name = os.path.basename(vfs_path)
self.textures = []
self.material = ''
self.logger = getLogger(__name__)
def read(self, physical_path):
try:
tree = xml.etree.ElementTree.parse(physical_path)
except xml.etree.ElementTree.ParseError as err:
sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg))
self.logger.error('"%s": %s\n' % (physical_path, err.msg))
return False
root = tree.getroot()
# Special case: particles don't need a diffuse texture.
if len(root.findall('.//particles')) > 0:
self.textures.append("baseTex")
for element in root.findall('.//material'):
self.material = element.text
for element in root.findall('.//texture'):
self.textures.append(element.get('name'))
for element in root.findall('.//variant'):
file = element.get('file')
if file:
self.read_variant(physical_path, os.path.join('art', 'variants', file))
return True
def read_variant(self, actor_physical_path, relative_path):
physical_path = actor_physical_path.replace(self.vfs_path, relative_path)
try:
tree = xml.etree.ElementTree.parse(physical_path)
except xml.etree.ElementTree.ParseError as err:
self.logger.error('"%s": %s\n' % (physical_path, err.msg))
return False
root = tree.getroot()
file = root.get('file')
if file:
self.read_variant(actor_physical_path, os.path.join('art', 'variants', file))
for element in root.findall('.//texture'):
self.textures.append(element.get('name'))
class Material:
def __init__(self, mod_name, vfs_path):
@ -40,7 +64,7 @@ class Material:
try:
root = xml.etree.ElementTree.parse(physical_path).getroot()
except xml.etree.ElementTree.ParseError as err:
sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg))
self.logger.error('"%s": %s\n' % (physical_path, err.msg))
return False
for element in root.findall('.//required_texture'):
texture_name = element.get('name')
@ -58,6 +82,17 @@ class Validator:
self.materials = {}
self.invalid_materials = {}
self.actors = []
self.__init_logger
@property
def __init_logger(self):
logger = getLogger(__name__)
logger.setLevel(INFO)
ch = StreamHandler()
ch.setLevel(INFO)
ch.setFormatter(Formatter('%(levelname)s - %(message)s'))
logger.addHandler(ch)
self.logger = logger
def get_physical_path(self, mod_name, vfs_path):
return os.path.realpath(os.path.join(self.vfs_root, mod_name, vfs_path))
@ -109,7 +144,7 @@ class Validator:
def run(self):
start_time = time.time()
sys.stdout.write('Collecting list of files to check\n')
self.logger.info('Collecting list of files to check\n')
self.find_materials(os.path.join('art', 'materials'))
self.find_actors(os.path.join('art', 'actors'))
@ -118,32 +153,32 @@ class Validator:
if not actor.material:
continue
if actor.material not in self.materials and actor.material not in self.invalid_materials:
sys.stderr.write('Error in "%s": unknown material "%s"' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
self.logger.error('"%s": unknown material "%s"' % (
self.get_mod_path(actor.mod_name, actor.vfs_path),
actor.material
))
if actor.material not in self.materials:
continue
material = self.materials[actor.material]
for required_texture in material.required_textures:
if required_texture in actor.textures:
continue
sys.stderr.write('Error in "%s": actor does not contain required texture "%s" from "%s"\n' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
required_texture,
missing_textures = ', '.join(set([required_texture for required_texture in material.required_textures if required_texture not in actor.textures]))
if len(missing_textures) > 0:
self.logger.error('"%s": actor does not contain required texture(s) "%s" from "%s"' % (
self.get_mod_path(actor.mod_name, actor.vfs_path),
missing_textures,
material.name
))
for texture in actor.textures:
if texture in material.required_textures:
continue
sys.stderr.write('Warning in "%s": actor contains unnecessary texture "%s" from "%s"\n' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
texture,
extra_textures = ', '.join(set([extra_texture for extra_texture in actor.textures if extra_texture not in material.required_textures]))
if len(extra_textures) > 0:
self.logger.warning('"%s": actor contains unnecessary texture(s) "%s" from "%s"' % (
self.get_mod_path(actor.mod_name, actor.vfs_path),
extra_textures,
material.name
))
finish_time = time.time()
sys.stdout.write('Total execution time: %.3f seconds.\n' % (finish_time - start_time))
self.logger.info('Total execution time: %.3f seconds.\n' % (finish_time - start_time))
if __name__ == '__main__':
script_dir = os.path.dirname(os.path.realpath(__file__))