Small config tweaks, removed cam/light check, code cleanup
This commit is contained in:
1 parent
4617c47ad0
commit
b800e5a68b
6 files changed
+148
-43
No files matched your search
+15
@@ -40,19 +40,34 @@ def _load_config_override():
|
||||
|
||||
# Register modules
|
||||
def register() -> None:
|
||||
# Register tool operators
|
||||
tools_ops.register()
|
||||
|
||||
# Load all the sanity checks into the sanity REGISTRY
|
||||
checks.load_all()
|
||||
|
||||
# Register the UI for all panels
|
||||
ui.register()
|
||||
|
||||
# Load the configuration for sanity checks
|
||||
_load_config_override()
|
||||
|
||||
# Load it natively
|
||||
bpy.app.handlers.load_post.append(_on_load_post)
|
||||
|
||||
|
||||
# Unregister modules
|
||||
def unregister() -> None:
|
||||
# Unregister tool operators
|
||||
tools_ops.unregister()
|
||||
|
||||
# Destroy the post loader
|
||||
if _on_load_post in bpy.app.handlers.load_post:
|
||||
bpy.app.handlers.load_post.remove(_on_load_post)
|
||||
|
||||
# Unregister all panels
|
||||
ui.unregister()
|
||||
|
||||
runner.clear()
|
||||
# The check registry is plain Python and is rebuilt with the modules on
|
||||
# re-import, so it is kept as is (enable/disable without re-import).
|
||||
+29
-19
@@ -35,7 +35,9 @@ class ModifiersCheck(Check):
|
||||
continue
|
||||
for name in issue.data["modifiers"]:
|
||||
try:
|
||||
with bpy.context.temp_override(object=ob, active_object=ob, selected_objects=[ob]):
|
||||
with bpy.context.temp_override(
|
||||
object=ob, active_object=ob, selected_objects=[ob]
|
||||
):
|
||||
bpy.ops.object.modifier_apply(modifier=name)
|
||||
except RuntimeError as exc:
|
||||
failed.append(f"{ob.name} / {name}: {str(exc).strip()}")
|
||||
@@ -58,7 +60,10 @@ class ApplyTransformCheck(Check):
|
||||
problems = []
|
||||
if channels.get("location") and loc.length > tolerance:
|
||||
problems.append("location")
|
||||
if channels.get("rotation") and min(rot.angle, math.tau - rot.angle) > tolerance:
|
||||
if (
|
||||
channels.get("rotation")
|
||||
and min(rot.angle, math.tau - rot.angle) > tolerance
|
||||
):
|
||||
problems.append("rotation")
|
||||
if channels.get("scale") and any(abs(s - 1.0) > tolerance for s in scale):
|
||||
problems.append("scale")
|
||||
@@ -73,11 +78,16 @@ class ApplyTransformCheck(Check):
|
||||
if ob is None:
|
||||
continue
|
||||
if ob.data is not None and ob.data.users > 1:
|
||||
failed.append(f"{ob.name}: data shared by {ob.data.users} users, apply by hand")
|
||||
failed.append(
|
||||
f"{ob.name}: data shared by {ob.data.users} users, apply by hand"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
with bpy.context.temp_override(
|
||||
object=ob, active_object=ob, selected_objects=[ob], selected_editable_objects=[ob]
|
||||
object=ob,
|
||||
active_object=ob,
|
||||
selected_objects=[ob],
|
||||
selected_editable_objects=[ob],
|
||||
):
|
||||
bpy.ops.object.transform_apply(
|
||||
location=bool(channels.get("location")),
|
||||
@@ -89,20 +99,20 @@ class ApplyTransformCheck(Check):
|
||||
return failed
|
||||
|
||||
|
||||
class LightCameraCheck(Check):
|
||||
id = "lights_cameras"
|
||||
label = "Lights & cameras"
|
||||
description = "Asset files contain no lights or cameras."
|
||||
category = "Objects"
|
||||
contexts = contexts.ASSET
|
||||
fix_description = "Delete the lights and cameras"
|
||||
# class LightCameraCheck(Check):
|
||||
# id = "lights_cameras"
|
||||
# label = "Lights & cameras"
|
||||
# description = "Asset files contain no lights or cameras."
|
||||
# category = "Objects"
|
||||
# contexts = contexts.ASSET
|
||||
# fix_description = "Delete the lights and cameras"
|
||||
|
||||
def run(self, ctx):
|
||||
for ob in ctx.objects(*config.FORBIDDEN_ASSET_OBJECT_TYPES):
|
||||
yield Issue.for_id(f"{ob.type.capitalize()} '{ob.name}' must be removed", ob)
|
||||
# def run(self, ctx):
|
||||
# for ob in ctx.objects(*config.FORBIDDEN_ASSET_OBJECT_TYPES):
|
||||
# yield Issue.for_id(f"{ob.type.capitalize()} '{ob.name}' must be removed", ob)
|
||||
|
||||
def fix(self, ctx, issues):
|
||||
for issue in issues:
|
||||
ob = issue.get_id()
|
||||
if ob is not None:
|
||||
bpy.data.objects.remove(ob, do_unlink=True)
|
||||
# def fix(self, ctx, issues):
|
||||
# for issue in issues:
|
||||
# ob = issue.get_id()
|
||||
# if ob is not None:
|
||||
# bpy.data.objects.remove(ob, do_unlink=True)
|
||||
@@ -82,16 +82,48 @@ MESH_DATA_MATCHES_OBJECT = True
|
||||
|
||||
# Blender default names that must never survive in a published file.
|
||||
DEFAULT_NAMES = {
|
||||
"cube", "plane", "sphere", "uvsphere", "icosphere", "cylinder", "cone",
|
||||
"torus", "circle", "grid", "suzanne", "monkey", "empty", "camera",
|
||||
"light", "lamp", "point", "sun", "spot", "area", "material", "collection",
|
||||
"beziercurve", "beziercircle", "nurbscurve", "nurbspath", "text",
|
||||
"armature", "lattice", "nodegroup", "geometrynodes", "stroke", "gpencil",
|
||||
"lineart", "scene", "world", "object", "mesh",
|
||||
"cube",
|
||||
"plane",
|
||||
"sphere",
|
||||
"uvsphere",
|
||||
"icosphere",
|
||||
"cylinder",
|
||||
"cone",
|
||||
"torus",
|
||||
"circle",
|
||||
"grid",
|
||||
"suzanne",
|
||||
"monkey",
|
||||
"empty",
|
||||
"camera",
|
||||
"light",
|
||||
"lamp",
|
||||
"point",
|
||||
"sun",
|
||||
"spot",
|
||||
"area",
|
||||
"material",
|
||||
"collection",
|
||||
"beziercurve",
|
||||
"beziercircle",
|
||||
"nurbscurve",
|
||||
"nurbspath",
|
||||
"text",
|
||||
"armature",
|
||||
"lattice",
|
||||
"nodegroup",
|
||||
"geometrynodes",
|
||||
"stroke",
|
||||
"gpencil",
|
||||
"lineart",
|
||||
"scene",
|
||||
"world",
|
||||
"object",
|
||||
"mesh",
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Structure (placeholder, real hierarchy to be defined)
|
||||
# Structure
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Collections that must exist. "{asset}" is replaced by the asset name.
|
||||
REQUIRED_COLLECTIONS = []
|
||||
@@ -111,7 +143,10 @@ UV_NEGATIVE_TOLERANCE = 1e-6
|
||||
# --------------------------------------------------------------------------- #
|
||||
ALLOWED_MODIFIERS = {"SUBSURF", "MULTIRES"}
|
||||
ALLOWED_MODIFIERS_LINEART = {
|
||||
"SUBSURF", "MULTIRES", "LINEART", "GREASE_PENCIL_THICKNESS",
|
||||
"SUBSURF",
|
||||
"MULTIRES",
|
||||
"LINEART",
|
||||
"GREASE_PENCIL_THICKNESS",
|
||||
}
|
||||
|
||||
# Which transform channels must be applied.
|
||||
@@ -135,8 +170,19 @@ CHAR_BODY_NAME = "GEO_{asset}_Body"
|
||||
|
||||
# Name keywords that identify inner mouth / eye parts (case-insensitive).
|
||||
CHAR_PART_KEYWORDS = [
|
||||
"eye", "iris", "pupil", "cornea", "sclera", "lid", "lash",
|
||||
"mouth", "teeth", "tooth", "tongue", "gum", "palate",
|
||||
"eye",
|
||||
"iris",
|
||||
"pupil",
|
||||
"cornea",
|
||||
"sclera",
|
||||
"lid",
|
||||
"lash",
|
||||
"mouth",
|
||||
"teeth",
|
||||
"tooth",
|
||||
"tongue",
|
||||
"gum",
|
||||
"palate",
|
||||
]
|
||||
|
||||
# Vertex groups the body mesh must have. TODO: real list.
|
||||
@@ -152,14 +198,32 @@ SET_COLLECTION_PATTERN = r"^(?:SET|ENV|set|env)[_-]"
|
||||
VERSION_PATTERN = r"(?<![A-Za-z0-9])v(\d{3,4})(?![0-9])"
|
||||
|
||||
# Datablock types scanned for ".001" duplicated names.
|
||||
DUPLICATE_NAME_TYPES = ["objects", "collections", "cameras", "materials", "actions", "node_groups"]
|
||||
DUPLICATE_NAME_TYPES = [
|
||||
"objects",
|
||||
"collections",
|
||||
"cameras",
|
||||
"materials",
|
||||
"actions",
|
||||
"node_groups",
|
||||
]
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# UI
|
||||
# --------------------------------------------------------------------------- #
|
||||
CATEGORY_ORDER = [
|
||||
"Scene", "File", "Naming", "Structure", "Geometry", "UVs", "Objects",
|
||||
"Shading", "Animation", "Character", "Lineart", "Shot", "Sound",
|
||||
"Scene",
|
||||
"File",
|
||||
"Naming",
|
||||
"Structure",
|
||||
"Geometry",
|
||||
"UVs",
|
||||
"Objects",
|
||||
"Shading",
|
||||
"Animation",
|
||||
"Character",
|
||||
"Lineart",
|
||||
"Shot",
|
||||
"Sound",
|
||||
]
|
||||
MAX_ISSUES_DRAWN = 30
|
||||
|
||||
@@ -175,7 +239,9 @@ def _snapshot():
|
||||
if _DEFAULTS is None:
|
||||
module = sys.modules[__name__]
|
||||
_DEFAULTS = {
|
||||
k: copy.deepcopy(v) for k, v in vars(module).items() if k.isupper() and not k.startswith("_")
|
||||
k: copy.deepcopy(v)
|
||||
for k, v in vars(module).items()
|
||||
if k.isupper() and not k.startswith("_")
|
||||
}
|
||||
return _DEFAULTS
|
||||
|
||||
|
||||
+14
-2
@@ -10,6 +10,7 @@ GENERAL = "GENERAL"
|
||||
CHAR_MOD = "CHAR_MOD"
|
||||
CHAR_LINEART = "CHAR_LINEART"
|
||||
LAYOUT = "LAYOUT"
|
||||
ANIMATION = "ANIMATION"
|
||||
|
||||
# Every asset context gets the general asset checks.
|
||||
ASSET = frozenset({GENERAL, CHAR_MOD, CHAR_LINEART})
|
||||
@@ -26,10 +27,21 @@ class Context:
|
||||
|
||||
|
||||
CONTEXTS = [
|
||||
Context(GENERAL, "Asset: General", "Props, sets and generic assets (modeling and lineart)", "MESH_CUBE"),
|
||||
Context(
|
||||
GENERAL,
|
||||
"Asset: General",
|
||||
"Props, sets and generic assets (modeling and lineart)",
|
||||
"MESH_CUBE",
|
||||
),
|
||||
Context(CHAR_MOD, "Character: Modeling", "Character modeling file", "USER"),
|
||||
Context(CHAR_LINEART, "Character: Lineart / Shading", "Character lineart and shading file", "OUTLINER_OB_GREASEPENCIL"),
|
||||
Context(
|
||||
CHAR_LINEART,
|
||||
"Character: Lineart / Shading",
|
||||
"Character lineart and shading file",
|
||||
"OUTLINER_OB_GREASEPENCIL",
|
||||
),
|
||||
Context(LAYOUT, "Shot: Layout", "Shot layout file", "SEQUENCE"),
|
||||
Context(ANIMATION, "Shot: Animation", "Shot animation file", "SEQUENCE"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
+8
-6
@@ -1,10 +1,11 @@
|
||||
"""Operators."""
|
||||
"""Operators for the individual tools."""
|
||||
|
||||
import bpy
|
||||
import json
|
||||
|
||||
class WTDGetOidForPath(bpy.types.Operator):
|
||||
import bpy
|
||||
|
||||
|
||||
class WTDGetOidForPath(bpy.types.Operator):
|
||||
bl_idname = "wtd_tools.getoidforpath"
|
||||
bl_label = "Get Oid For Open Scene"
|
||||
|
||||
@@ -14,10 +15,10 @@ class WTDGetOidForPath(bpy.types.Operator):
|
||||
actor_name="Flow",
|
||||
cmd_name="getoidforpath",
|
||||
args_json=json.dumps([]),
|
||||
kwargs_json=json.dumps({'path': bpy.data.filepath.replace('\\', '/')}),
|
||||
kwargs_json=json.dumps({"path": bpy.data.filepath.replace("\\", "/")}),
|
||||
) == {"FINISHED"}:
|
||||
result = json.loads(bpy.context.window_manager.kabaret_ipc_last_result)
|
||||
self.report({'INFO'}, str(result))
|
||||
self.report({"INFO"}, str(result))
|
||||
else:
|
||||
error = bpy.context.window_manager.kabaret_ipc_last_error
|
||||
return {"FINISHED"}
|
||||
@@ -26,5 +27,6 @@ class WTDGetOidForPath(bpy.types.Operator):
|
||||
def register() -> None:
|
||||
bpy.utils.register_class(WTDGetOidForPath)
|
||||
|
||||
|
||||
def unregister() -> None:
|
||||
bpy.utils.unregister_class(WTDGetOidForPath)
|
||||
bpy.utils.unregister_class(WTDGetOidForPath)
|
||||
+2
-2
@@ -32,7 +32,7 @@ def _wrapped_label(layout, context, text, icon="NONE", margin=0):
|
||||
col.label(text=line, icon=icon if index == 0 else "BLANK1")
|
||||
|
||||
|
||||
def draw_panel(self, context):
|
||||
def draw_sanity_checks_panel(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
settings = scene.wtd_sanity
|
||||
@@ -170,7 +170,7 @@ class _SanityPanel:
|
||||
bl_options = {"DEFAULT_CLOSED"} # panel starts collapsed
|
||||
|
||||
def draw(self, context):
|
||||
draw_panel(self, context)
|
||||
draw_sanity_checks_panel(self, context)
|
||||
|
||||
|
||||
class _ToolsPanel:
|
||||
|
||||
Reference in new issue
Block a user