mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Check for broken animated meshes in checkrefs.
Added and integrated P293 by @trompetin17 and @Stan Addresses #6714
This commit is contained in:
parent
e218cfa170
commit
0e1c881fef
3 changed files with 96 additions and 3 deletions
|
|
@ -11,6 +11,8 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Add remote fork origin for LFS
|
||||
run: |
|
||||
PR_REPO="${{ gitea.event.pull_request.head.repo.full_name || gitea.repository }}"
|
||||
|
|
@ -31,9 +33,10 @@ jobs:
|
|||
- name: Download necessary LFS assets
|
||||
shell: sh {0}
|
||||
run: |
|
||||
git lfs pull -I binaries/data/mods/public/maps
|
||||
git lfs pull -I binaries/data/mods/public/art/meshes,binaries/data/mods/public/maps
|
||||
ORIGIN_LFS_PULL_RESULT=$?
|
||||
git lfs pull ${{ gitea.actor }} -I binaries/data/mods/public/maps
|
||||
git lfs pull ${{ gitea.actor }} \
|
||||
-I binaries/data/mods/public/art/meshes,binaries/data/mods/public/maps
|
||||
FORK_LFS_PULL_RESULT=$?
|
||||
|
||||
PR_REPO="${{ gitea.event.pull_request.head.repo.full_name || gitea.repository }}"
|
||||
|
|
@ -47,9 +50,12 @@ jobs:
|
|||
fi
|
||||
- name: Install lxml
|
||||
run: pip3 install lxml
|
||||
- name: Install collada
|
||||
run: pip3 install "pycollada>=0.9"
|
||||
- name: Check for missing references
|
||||
run: |
|
||||
./source/tools/entity/checkrefs.py \
|
||||
--check-map-xml \
|
||||
--validate-templates \
|
||||
--validate-actors
|
||||
--validate-actors \
|
||||
--validate-meshes
|
||||
|
|
|
|||
|
|
@ -119,6 +119,12 @@ class CheckRefs:
|
|||
default=["public"],
|
||||
help="specify which mods to check. Default to public.",
|
||||
)
|
||||
ap.add_argument(
|
||||
"-d",
|
||||
"--validate-meshes",
|
||||
action="store_true",
|
||||
help="check if meshes have vertices with no weight.",
|
||||
)
|
||||
args = ap.parse_args()
|
||||
# force check_map_xml if check_unused is used to avoid false positives.
|
||||
args.check_map_xml |= args.check_unused
|
||||
|
|
@ -161,6 +167,12 @@ class CheckRefs:
|
|||
if not validator.run():
|
||||
self.inError = True
|
||||
|
||||
if args.validate_meshes:
|
||||
from validate_dae import DaeValidator
|
||||
|
||||
dv = DaeValidator(self.vfs_root, self.mods)
|
||||
self.inError = not dv.run()
|
||||
|
||||
return not self.inError
|
||||
|
||||
def get_mod_dependencies(self, *mods):
|
||||
|
|
|
|||
75
source/tools/entity/validate_dae.py
Executable file
75
source/tools/entity/validate_dae.py
Executable file
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from logging import INFO, Formatter, StreamHandler, getLogger
|
||||
from pathlib import Path
|
||||
|
||||
from collada import Collada, DaeBrokenRefError, DaeError, common, controller
|
||||
from scriptlib import find_files
|
||||
|
||||
|
||||
def validate_vertex(path_dae, log=print):
|
||||
has_weightless = False
|
||||
had_exception = False
|
||||
dae = None
|
||||
try:
|
||||
dae = Collada(path_dae, ignore=[common.DaeUnsupportedError, DaeBrokenRefError])
|
||||
except DaeError as inst:
|
||||
log("Failed to load %s", path_dae)
|
||||
log(type(inst), inst)
|
||||
had_exception = True
|
||||
for ctr in dae.controllers:
|
||||
if type(ctr) is not controller.Skin:
|
||||
had_exception = True
|
||||
break
|
||||
totalv = len(ctr.vcounts)
|
||||
totalv_0 = len(ctr.vcounts[ctr.vcounts == 0])
|
||||
if totalv_0 > 0:
|
||||
log(
|
||||
"Mesh %s has %i (out of %i) vertices with no weight"
|
||||
" and no bone assigned. Use P294 to find them in Blender.",
|
||||
path_dae,
|
||||
totalv_0,
|
||||
totalv,
|
||||
)
|
||||
has_weightless = True
|
||||
return (int(has_weightless) << 1) | int(had_exception)
|
||||
|
||||
|
||||
class DaeValidator:
|
||||
def __init__(self, vfs_root, mods):
|
||||
self.has_weightless_vtx = []
|
||||
self.vfs_root = vfs_root
|
||||
self.mods = mods
|
||||
|
||||
self.log = getLogger()
|
||||
self.log.setLevel(INFO)
|
||||
sh = StreamHandler(sys.stdout)
|
||||
sh.setLevel(INFO)
|
||||
sh.setFormatter(Formatter("%(levelname)s - %(message)s"))
|
||||
self.log.addHandler(sh)
|
||||
|
||||
def run(self):
|
||||
is_ok = True
|
||||
files = find_files(self.vfs_root, self.mods, "art/meshes", "dae")
|
||||
self.log.info("Checking %i meshes for invalid weights.", len(files))
|
||||
for _, dae in files:
|
||||
status = validate_vertex(dae.as_posix(), self.log.warning)
|
||||
if status >= 1:
|
||||
is_ok = False
|
||||
if status >= 2:
|
||||
self.has_weightless_vtx.append(dae)
|
||||
self.log.info(
|
||||
"%i out of %i files have vertices with no weight or bones.",
|
||||
len(self.has_weightless_vtx),
|
||||
len(files),
|
||||
)
|
||||
return is_ok
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
vfsr = Path(__file__).resolve().parents[3] / "binaries" / "data" / "mods"
|
||||
mods = ["public"]
|
||||
dv = DaeValidator(vfsr, mods)
|
||||
print(f"DaeValidator returns {dv.run()}")
|
||||
print(dv.has_weightless_vtx)
|
||||
Loading…
Reference in a new issue