Added sanity check baseline made by claude.
Also changed the location to a panel in VIEW_3D instead of menu.
This commit is contained in:
1 parent
71b1a61b5c
commit
4617c47ad0
33 files changed
+2771
-52
No files matched your search
@@ -0,0 +1,214 @@
|
||||
"""Production specs used by the checks.
|
||||
|
||||
Every UPPERCASE value can be overridden by a studio JSON file, see
|
||||
``apply_overrides`` (path set in the add-on preferences or through the
|
||||
``WTD_SANITY_CONFIG`` environment variable). Checks must read values at run
|
||||
time (``config.FPS``), never copy them at import time, so overrides apply.
|
||||
|
||||
Values marked TODO are placeholders waiting for the real production specs.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Scene / render
|
||||
# --------------------------------------------------------------------------- #
|
||||
FPS = 24
|
||||
FPS_BASE = 1.0
|
||||
RESOLUTION = (2048, 858)
|
||||
RESOLUTION_PERCENTAGE = 100
|
||||
PIXEL_ASPECT = (1.0, 1.0)
|
||||
|
||||
# Units. TODO: confirm with production (metric/meters assumed).
|
||||
UNIT_SYSTEM = "METRIC"
|
||||
UNIT_SCALE_LENGTH = 1.0
|
||||
UNIT_LENGTH = "METERS"
|
||||
|
||||
# Color management. TODO: colorspace still to be determined by production.
|
||||
# A value of None means "not checked".
|
||||
COLOR_MANAGEMENT = {
|
||||
"display_device": "sRGB",
|
||||
"view_transform": "Standard",
|
||||
"look": "None",
|
||||
"exposure": 0.0,
|
||||
"gamma": 1.0,
|
||||
"sequencer_colorspace": "sRGB",
|
||||
"working_space": None, # e.g. "Linear Rec.709" (Blender 5+). Check only, never auto-fixed.
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# File names. TODO: replace with the real Libreflow/Kitsu naming.
|
||||
# Named group "asset" is used to guess the asset/character name.
|
||||
# --------------------------------------------------------------------------- #
|
||||
FILENAME_PATTERNS = {
|
||||
"GENERAL": r"^(?:prp|set|chr)_(?P<asset>[A-Za-z0-9]+)_(?:mod|lineart|shading)(?:_v\d{3})?\.blend$",
|
||||
"CHAR_MOD": r"^chr_(?P<asset>[A-Za-z0-9]+)_mod(?:_v\d{3})?\.blend$",
|
||||
"CHAR_LINEART": r"^chr_(?P<asset>[A-Za-z0-9]+)_(?:lineart|shading)(?:_v\d{3})?\.blend$",
|
||||
"LAYOUT": r"^(?P<sequence>sq\d{3})_(?P<shot>sh\d{4})_layout(?:_v\d{3})?\.blend$",
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Naming
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Body of a name after its prefix: snake_case or PascalCase tokens joined by "_".
|
||||
NAME_BODY_PATTERN = r"[A-Za-z0-9]+(?:_[A-Za-z0-9]+)*"
|
||||
|
||||
# Object prefix per object type. Types not listed are not checked.
|
||||
OBJECT_PREFIXES = {
|
||||
"MESH": "GEO_",
|
||||
"CURVE": "CRV_",
|
||||
"SURFACE": "SRF_",
|
||||
"FONT": "TXT_",
|
||||
"EMPTY": "NUL_",
|
||||
"ARMATURE": "RIG_",
|
||||
"LATTICE": "LAT_",
|
||||
"GREASEPENCIL": "LA_",
|
||||
"CAMERA": "CAM_",
|
||||
"LIGHT": "LGT_",
|
||||
}
|
||||
|
||||
# Prefix per bpy.data collection.
|
||||
DATABLOCK_PREFIXES = {
|
||||
"collections": "COL_",
|
||||
"materials": "MAT_",
|
||||
"node_groups": "NG_",
|
||||
}
|
||||
|
||||
# Mesh datablocks must carry the same name as their (single) object.
|
||||
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",
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Structure (placeholder, real hierarchy to be defined)
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Collections that must exist. "{asset}" is replaced by the asset name.
|
||||
REQUIRED_COLLECTIONS = []
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Geometry
|
||||
# --------------------------------------------------------------------------- #
|
||||
MAX_FACE_SIDES = 4
|
||||
# sin() of the reflex angle above which a corner counts as concave.
|
||||
CONCAVE_TOLERANCE = 1e-4
|
||||
# Open borders are reported as non-manifold unless this is True.
|
||||
NON_MANIFOLD_ALLOW_BOUNDARY = False
|
||||
UV_NEGATIVE_TOLERANCE = 1e-6
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Objects
|
||||
# --------------------------------------------------------------------------- #
|
||||
ALLOWED_MODIFIERS = {"SUBSURF", "MULTIRES"}
|
||||
ALLOWED_MODIFIERS_LINEART = {
|
||||
"SUBSURF", "MULTIRES", "LINEART", "GREASE_PENCIL_THICKNESS",
|
||||
}
|
||||
|
||||
# Which transform channels must be applied.
|
||||
APPLY_TRANSFORM = {"location": False, "rotation": True, "scale": True}
|
||||
APPLY_TRANSFORM_TYPES = {"MESH", "CURVE", "SURFACE", "FONT", "META"}
|
||||
TRANSFORM_TOLERANCE = 1e-5
|
||||
|
||||
# Object types that must not be present in asset files.
|
||||
FORBIDDEN_ASSET_OBJECT_TYPES = {"LIGHT", "CAMERA"}
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Characters
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Reference JSON exported from the master character (see panel > Export
|
||||
# Character Reference). Overridden by the add-on preferences or by the
|
||||
# WTD_CHAR_REFERENCE environment variable.
|
||||
CHAR_REFERENCE_PATH = ""
|
||||
|
||||
# Name of the character body object. "{asset}" is the character name.
|
||||
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",
|
||||
]
|
||||
|
||||
# Vertex groups the body mesh must have. TODO: real list.
|
||||
CHAR_BODY_VERTEX_GROUPS = []
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Layout
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Instanced collections matching this pattern are sets that must sit at the origin.
|
||||
SET_COLLECTION_PATTERN = r"^(?:SET|ENV|set|env)[_-]"
|
||||
|
||||
# Version token in a file or folder name (Libreflow stores v001/ folders).
|
||||
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"]
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# UI
|
||||
# --------------------------------------------------------------------------- #
|
||||
CATEGORY_ORDER = [
|
||||
"Scene", "File", "Naming", "Structure", "Geometry", "UVs", "Objects",
|
||||
"Shading", "Animation", "Character", "Lineart", "Shot", "Sound",
|
||||
]
|
||||
MAX_ISSUES_DRAWN = 30
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Overrides
|
||||
# --------------------------------------------------------------------------- #
|
||||
_DEFAULTS = None
|
||||
|
||||
|
||||
def _snapshot():
|
||||
global _DEFAULTS
|
||||
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("_")
|
||||
}
|
||||
return _DEFAULTS
|
||||
|
||||
|
||||
def apply_overrides(path=""):
|
||||
"""Reset to defaults, then apply a JSON file of {"NAME": value} overrides.
|
||||
|
||||
``path`` falls back to the WTD_SANITY_CONFIG environment variable.
|
||||
Returns the list of keys that were overridden.
|
||||
"""
|
||||
module = sys.modules[__name__]
|
||||
defaults = _snapshot()
|
||||
for key, value in defaults.items():
|
||||
setattr(module, key, copy.deepcopy(value))
|
||||
|
||||
path = path or os.environ.get("WTD_SANITY_CONFIG", "")
|
||||
if not path:
|
||||
return []
|
||||
with open(path, encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
applied = []
|
||||
for key, value in data.items():
|
||||
if key not in defaults:
|
||||
print(f"[WTD Sanity] Unknown config key ignored: {key}")
|
||||
continue
|
||||
default = defaults[key]
|
||||
if isinstance(default, (set, frozenset)):
|
||||
value = set(value)
|
||||
elif isinstance(default, tuple):
|
||||
value = tuple(value)
|
||||
elif isinstance(default, dict) and isinstance(value, dict):
|
||||
value = {**default, **value}
|
||||
setattr(module, key, value)
|
||||
applied.append(key)
|
||||
return applied
|
||||
Reference in new issue
Block a user