mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 13:53:57 -07:00
In the ruff config file added in #6954 explicitly selecting the ruff rules to check was missed, resulting in ruff only checking a very small subset of its available rules. That hasn't been desired, so this is the first of a series of commits enabling more rules. In this PR all rules whose violations can be either automatically fixed by ruff or are trivial to fix manually get enabled. For the follow up PRs it's intended to focus on one area of rules per PR to gradually improve the Python code quality.
160 lines
5 KiB
Python
Executable file
160 lines
5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
# ruff: noqa: F403, F405
|
|
|
|
import os
|
|
import xml.etree.ElementTree as ET
|
|
from ctypes import *
|
|
|
|
|
|
binaries = "../../../binaries"
|
|
|
|
# Work out the platform-dependent library filename
|
|
dll_filename = {
|
|
"posix": "./libCollada_dbg.so",
|
|
"nt": "Collada_dbg.dll",
|
|
}[os.name]
|
|
|
|
# The DLL may need other DLLs which are in its directory, so set the path to that
|
|
# (Don't care about clobbering the old PATH - it doesn't have anything important)
|
|
os.environ["PATH"] = f"{binaries}/system/"
|
|
|
|
# Load the actual library
|
|
library = cdll.LoadLibrary(f"{binaries}/system/{dll_filename}")
|
|
|
|
|
|
def log(severity, message):
|
|
print("[{}] {}".format(("INFO", "WARNING", "ERROR")[severity], message))
|
|
|
|
|
|
clog = CFUNCTYPE(None, c_int, c_char_p)(log)
|
|
# (the CFUNCTYPE must not be GC'd, so try to keep a reference)
|
|
library.set_logger(clog)
|
|
skeleton_definitions = open(f"{binaries}/data/tests/collada/skeletons.xml").read()
|
|
library.set_skeleton_definitions(skeleton_definitions, len(skeleton_definitions))
|
|
|
|
|
|
def _convert_dae(func, filename, expected_status=0):
|
|
output = []
|
|
|
|
def cb(cbdata, str, len):
|
|
output.append(string_at(str, len))
|
|
|
|
cbtype = CFUNCTYPE(None, POINTER(None), POINTER(c_char), c_uint)
|
|
status = func(filename, cbtype(cb), None)
|
|
assert status == expected_status
|
|
return "".join(output)
|
|
|
|
|
|
def convert_dae_to_pmd(*args, **kwargs):
|
|
return _convert_dae(library.convert_dae_to_pmd, *args, **kwargs)
|
|
|
|
|
|
def convert_dae_to_psa(*args, **kwargs):
|
|
return _convert_dae(library.convert_dae_to_psa, *args, **kwargs)
|
|
|
|
|
|
def clean_dir(path):
|
|
# Remove all files first
|
|
try:
|
|
for f in os.listdir(path):
|
|
os.remove(path + "/" + f)
|
|
os.rmdir(path)
|
|
except OSError:
|
|
pass # (ignore errors if files are in use)
|
|
# Make sure the directory exists
|
|
try:
|
|
os.makedirs(path)
|
|
except OSError:
|
|
pass # (ignore errors if it already exists)
|
|
|
|
|
|
def create_actor(mesh, texture, anims, props_):
|
|
actor = ET.Element("actor", version="1")
|
|
ET.SubElement(actor, "castshadow")
|
|
group = ET.SubElement(actor, "group")
|
|
variant = ET.SubElement(group, "variant", frequency="100", name="Base")
|
|
ET.SubElement(variant, "mesh").text = mesh + ".pmd"
|
|
ET.SubElement(variant, "texture").text = texture + ".dds"
|
|
|
|
animations = ET.SubElement(variant, "animations")
|
|
for name, file in anims:
|
|
ET.SubElement(animations, "animation", file=file + ".psa", name=name, speed="100")
|
|
|
|
props = ET.SubElement(variant, "props")
|
|
for name, file in props_:
|
|
ET.SubElement(props, "prop", actor=file + ".xml", attachpoint=name)
|
|
|
|
return ET.tostring(actor)
|
|
|
|
|
|
def create_actor_static(mesh, texture):
|
|
actor = ET.Element("actor", version="1")
|
|
ET.SubElement(actor, "castshadow")
|
|
group = ET.SubElement(actor, "group")
|
|
variant = ET.SubElement(group, "variant", frequency="100", name="Base")
|
|
ET.SubElement(variant, "mesh").text = mesh + ".pmd"
|
|
ET.SubElement(variant, "texture").text = texture + ".dds"
|
|
return ET.tostring(actor)
|
|
|
|
|
|
################################
|
|
|
|
# Error handling
|
|
|
|
if False:
|
|
convert_dae_to_pmd("This is not well-formed XML", expected_status=-2)
|
|
convert_dae_to_pmd("<html>This is not COLLADA</html>", expected_status=-2)
|
|
convert_dae_to_pmd("<COLLADA>This is still not valid COLLADA</COLLADA>", expected_status=-2)
|
|
|
|
# Do some real conversions, so the output can be tested in the Actor Viewer
|
|
|
|
test_data = binaries + "/data/tests/collada"
|
|
test_mod = binaries + "/data/mods/_test.collada"
|
|
|
|
clean_dir(test_mod + "/art/meshes")
|
|
clean_dir(test_mod + "/art/actors")
|
|
clean_dir(test_mod + "/art/animation")
|
|
|
|
# for test_file in ['cube', 'jav2', 'jav2b', 'teapot_basic', 'teapot_skin', 'plane_skin',
|
|
# 'dude_skin', 'mergenonbone', 'densemesh']:
|
|
# for test_file in ['teapot_basic', 'jav2b', 'jav2d']:
|
|
for test_file in ["xsitest3c", "xsitest3e", "jav2d", "jav2d2"]:
|
|
# for test_file in ['xsitest3']:
|
|
# for test_file in []:
|
|
print(f"* Converting PMD {test_file}")
|
|
|
|
input_filename = f"{test_data}/{test_file}.dae"
|
|
output_filename = f"{test_mod}/art/meshes/{test_file}.pmd"
|
|
|
|
input = open(input_filename).read()
|
|
output = convert_dae_to_pmd(input)
|
|
open(output_filename, "wb").write(output)
|
|
|
|
xml = create_actor(
|
|
test_file,
|
|
"male",
|
|
[
|
|
("Idle", "dudeidle"),
|
|
("Corpse", "dudecorpse"),
|
|
("attack1", test_file),
|
|
("attack2", "jav2d"),
|
|
],
|
|
[("helmet", "teapot_basic_static")],
|
|
)
|
|
open(f"{test_mod}/art/actors/{test_file}.xml", "w").write(xml)
|
|
|
|
xml = create_actor_static(test_file, "male")
|
|
open(f"{test_mod}/art/actors/{test_file}_static.xml", "w").write(xml)
|
|
|
|
# for test_file in ['jav2','jav2b', 'jav2d']:
|
|
for test_file in ["xsitest3c", "xsitest3e", "jav2d", "jav2d2"]:
|
|
# for test_file in []:
|
|
print(f"* Converting PSA {test_file}")
|
|
|
|
input_filename = f"{test_data}/{test_file}.dae"
|
|
output_filename = f"{test_mod}/art/animation/{test_file}.psa"
|
|
|
|
input = open(input_filename).read()
|
|
output = convert_dae_to_psa(input)
|
|
open(output_filename, "wb").write(output)
|