unitytk 0.2.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unitytk-0.2.2/unitytk.egg-info → unitytk-0.4.0}/PKG-INFO +2 -2
- {unitytk-0.2.2 → unitytk-0.4.0}/pyproject.toml +7 -2
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_articulated_rig_runtime.py +18 -19
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_asset_delivery.py +5 -8
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_audio_events_integration.py +25 -21
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_base_test.py +140 -6
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_blender_render_effects_e2e.py +2 -6
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_blender_shadow_plane_integration.py +4 -8
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_blender_shot_metadata_integration.py +5 -11
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_clip_name_contract_integration.py +6 -10
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_controller_runtime_integration.py +2 -6
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_deploy_templates.py +249 -5
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_embedded_dependencies_integration.py +7 -9
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_emissive_groups_integration.py +2 -6
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_fade_window_preservation.py +2 -7
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_keyed_visibility.py +4 -12
- unitytk-0.4.0/test/test_lightmap_metadata_integration.py +2473 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_maya_surface_materials_integration.py +124 -69
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_multi_section_audio_integration.py +2 -15
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_render_effects_e2e.py +4 -4
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_render_opacity_controller.py +2 -7
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_render_opacity_e2e.py +6 -8
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_render_opacity_integration.py +2 -8
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_run_tests.py +17 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_shadow_plane_integration.py +6 -10
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_shadow_plane_runtime_integration.py +51 -16
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_shared_material_standalone.py +4 -12
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_shot_metadata_integration.py +100 -22
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_shots_audio_sidebyside_integration.py +16 -20
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_standalone_enduser.py +5 -12
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_temp_projects.py +143 -8
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/__init__.py +1 -1
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigController.cs +81 -249
- unitytk-0.4.0/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs +330 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/AudioEvent/AudioEventController.cs +112 -128
- unitytk-0.4.0/unitytk/templates/AudioEvent/AudioRecord.g.cs +260 -0
- unitytk-0.4.0/unitytk/templates/AudioEvent/AudioRecord.g.cs.meta +11 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupController.cs +28 -56
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupsLit.shader +36 -1
- unitytk-0.4.0/unitytk/templates/EmissiveGroup/EmissiveGroupsRecord.g.cs +268 -0
- unitytk-0.4.0/unitytk/templates/EmissiveGroup/EmissiveGroupsRecord.g.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableCubeUV.hlsl +119 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableCubeUV.hlsl.meta +7 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableLit.shader +391 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableLit.shader.meta +9 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverablePmrem.cs +307 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverablePmrem.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableShading.cs +570 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableShading.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableToneMap.shader +65 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableToneMap.shader.meta +9 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableToneMapFeature.cs +53 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/DeliverableToneMapFeature.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/HandoffBlock.g.cs +303 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/HandoffBlock.g.cs.meta +11 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/LightmapMetadataController.cs +678 -257
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/LightmapRecord.g.cs +466 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/LightmapRecord.g.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MapAbsence.g.cs +18 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MapAbsence.g.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.cs +81 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.g.cs +291 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.g.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/RenderingPolicy.g.cs +50 -0
- unitytk-0.4.0/unitytk/templates/LightmapMetadata/RenderingPolicy.g.cs.meta +11 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/M3trik.Unitytk.asmdef +8 -1
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/MayaSurface/MayaSurfaceMaterialImporter.cs +79 -28
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/README.md +97 -50
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlane.shader +12 -5
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneController.cs +128 -127
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneHorizon.hlsl +4 -2
- unitytk-0.4.0/unitytk/templates/ShadowPlane/ShadowRecord.g.cs +419 -0
- unitytk-0.4.0/unitytk/templates/ShadowPlane/ShadowRecord.g.cs.meta +11 -0
- unitytk-0.4.0/unitytk/templates/ShotMetadata/AnimationRecord.g.cs +272 -0
- unitytk-0.4.0/unitytk/templates/ShotMetadata/AnimationRecord.g.cs.meta +11 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShotMetadata/ShotMetadataController.cs +56 -55
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/UnitytkSettings.cs +411 -31
- {unitytk-0.2.2 → unitytk-0.4.0/unitytk.egg-info}/PKG-INFO +2 -2
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk.egg-info/SOURCES.txt +32 -0
- unitytk-0.4.0/unitytk.egg-info/requires.txt +1 -0
- unitytk-0.2.2/test/test_lightmap_metadata_integration.py +0 -1321
- unitytk-0.2.2/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs +0 -202
- unitytk-0.2.2/unitytk.egg-info/requires.txt +0 -1
- {unitytk-0.2.2 → unitytk-0.4.0}/LICENSE +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/MANIFEST.in +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/docs/README.md +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/setup.cfg +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_bool_to_fade_curve.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_launcher.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/test/test_scene_builder.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/asset_delivery.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/launcher.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/scene_builder.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/template_deployer.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigPointerGrab.cs +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigPointerGrab.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRGrab.cs +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRGrab.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRSetup.cs +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRSetup.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/M3trik.Unitytk.XR.asmdef +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/M3trik.Unitytk.XR.asmdef.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/AudioEvent/AudioEventController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/AudioEvent.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroups.hlsl +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroups.hlsl.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupsLit.shader.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/LightmapMetadataController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/M3trik.Unitytk.asmdef.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/MayaSurface/MayaSurfaceMaterialImporter.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/MayaSurface.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/README.md.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/RenderEffects/RenderEffectsController.cs +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/RenderEffects/RenderEffectsController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/RenderEffects.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlane.shader.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneHorizon.hlsl.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShadowPlane.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShotMetadata/ShotMetadataController.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/ShotMetadata.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/UnitytkSettings.cs.meta +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk/templates/__init__.py +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk.egg-info/dependency_links.txt +0 -0
- {unitytk-0.2.2 → unitytk-0.4.0}/unitytk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unitytk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A modular Python toolkit for Unity interaction.
|
|
5
5
|
Author-email: Ryan Simpson <m3trik@outlook.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,7 +13,7 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
13
13
|
Requires-Python: >=3.9
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: pythontk>=0.
|
|
16
|
+
Requires-Dist: pythontk>=0.17.0
|
|
17
17
|
Dynamic: license-file
|
|
18
18
|
|
|
19
19
|
[](../test/)
|
|
@@ -17,7 +17,12 @@ classifiers = [
|
|
|
17
17
|
]
|
|
18
18
|
# The floor is HAND-RATCHETED: unitytk is off-chain from m3trik/push.ps1, so no
|
|
19
19
|
# release cascade bumps it.
|
|
20
|
-
# pythontk 0.
|
|
20
|
+
# pythontk 0.17.0, the release this one ships and was tested with: the
|
|
21
|
+
# templates read the scene records by their renamed keys alone (`animation`,
|
|
22
|
+
# `audio`, `lightmaps`, `shadows`, `materials`, `handoff` v3 -- was
|
|
23
|
+
# `shot_metadata`, `audio_manifest`, `lightmap_metadata`, `shadow_metadata`),
|
|
24
|
+
# and only pythontk 0.17.0 writes them; an older one's FBX imports with no
|
|
25
|
+
# shots, audio, lightmaps or shadows. Before it, pythontk 0.13.1: an FBX
|
|
21
26
|
# deliverable carries the files its records name through
|
|
22
27
|
# `FbxMedia.embed_dependencies` (new in 0.13.1; on 0.13.0 the copy deliverer
|
|
23
28
|
# ships the FBX without its maps), and the suite holds the templates to its
|
|
@@ -27,7 +32,7 @@ classifiers = [
|
|
|
27
32
|
# needs 0.8.84: it scans through `AppLauncher.scan_install_dirs` (new in
|
|
28
33
|
# 0.8.72) and needs its pattern order to be a priority (0.8.84), so the Hub's
|
|
29
34
|
# chosen install location wins over the default.
|
|
30
|
-
dependencies = ["pythontk>=0.
|
|
35
|
+
dependencies = ["pythontk>=0.17.0"]
|
|
31
36
|
|
|
32
37
|
[project.urls]
|
|
33
38
|
Homepage = "https://github.com/m3trik/unitytk"
|
|
@@ -857,7 +857,9 @@ class LiveExport:
|
|
|
857
857
|
|
|
858
858
|
|
|
859
859
|
def _invalid_rigs():
|
|
860
|
-
"""Rigs the reference refuses (ValueError); the port must refuse them too.
|
|
860
|
+
"""Rigs the reference refuses (ValueError); the port must refuse them too.
|
|
861
|
+
Each is a rig as the record states it -- every key its shape requires --
|
|
862
|
+
so each is refused for its own fault, not a key left out."""
|
|
861
863
|
base = {"name": "bad", "joints": [], "grab": []}
|
|
862
864
|
|
|
863
865
|
def rig(*joints):
|
|
@@ -865,6 +867,9 @@ def _invalid_rigs():
|
|
|
865
867
|
out["joints"] = list(joints)
|
|
866
868
|
return out
|
|
867
869
|
|
|
870
|
+
def channel(name, lo=None, hi=None):
|
|
871
|
+
return {"channel": name, "min": lo, "max": hi, "weight": 1.0}
|
|
872
|
+
|
|
868
873
|
ok = {
|
|
869
874
|
"name": "a",
|
|
870
875
|
"parent": None,
|
|
@@ -876,10 +881,10 @@ def _invalid_rigs():
|
|
|
876
881
|
return [
|
|
877
882
|
rig(ok, dict(ok, name="b", parent=1)), # parent not earlier
|
|
878
883
|
rig(dict(ok, rotate_order="xxy")), # unknown order
|
|
879
|
-
rig(dict(ok, channels=[
|
|
880
|
-
rig(dict(ok, channels=[
|
|
881
|
-
rig(dict(ok, channels=[
|
|
882
|
-
rig(ok, dict(ok, name="b", parent=0, channels=[
|
|
884
|
+
rig(dict(ok, channels=[channel("sx")])), # unknown channel
|
|
885
|
+
rig(dict(ok, channels=[channel("rx"), channel("rx")])), # twice
|
|
886
|
+
rig(dict(ok, channels=[channel("rz", lo=10, hi=-10)])), # reversed
|
|
887
|
+
rig(ok, dict(ok, name="b", parent=0, channels=[channel("tx", hi=3)])), # valid
|
|
883
888
|
] # fmt: skip
|
|
884
889
|
|
|
885
890
|
|
|
@@ -915,7 +920,7 @@ public class ArticulatedRigVerifier
|
|
|
915
920
|
static M.Frame[] Frames(object o) => L(o).Select(f => new M.Frame(Vec(L(f)[0]), Qt(L(f)[1]))).ToArray();
|
|
916
921
|
|
|
917
922
|
// ---- JSON out ---------------------------------------------------------
|
|
918
|
-
static string N(double v) =>
|
|
923
|
+
static string N(double v) => UnitytkJson.Number(v);
|
|
919
924
|
static string B(bool b) => b ? "true" : "false";
|
|
920
925
|
static string S(string s) => "\"" + (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n").Replace("\r", "") + "\"";
|
|
921
926
|
static string A(double[] a) => a == null ? "null" : "[" + string.Join(",", a.Select(N)) + "]";
|
|
@@ -934,7 +939,7 @@ public class ArticulatedRigVerifier
|
|
|
934
939
|
try
|
|
935
940
|
{
|
|
936
941
|
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
|
937
|
-
inputs = O(
|
|
942
|
+
inputs = O(UnitytkJson.Parse(File.ReadAllText(INPUTS)));
|
|
938
943
|
}
|
|
939
944
|
catch (Exception e) { Put("inputs_error", S(e.ToString())); }
|
|
940
945
|
if (inputs != null)
|
|
@@ -1671,7 +1676,7 @@ def _run_unity(test, temp_dir, execute_method, prepare, timeout=600):
|
|
|
1671
1676
|
verifier; returns the parsed results (or skips on the license wall)."""
|
|
1672
1677
|
editor = os.environ.get("UNITYTK_TEST_EDITOR")
|
|
1673
1678
|
launcher = UnityLauncher(editor) if editor else UnityLauncher()
|
|
1674
|
-
project_path =
|
|
1679
|
+
project_path = TempProjects.project(temp_dir)
|
|
1675
1680
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
1676
1681
|
test.skipTest(UnityEnv.project_creation_reason())
|
|
1677
1682
|
results_path = os.path.join(temp_dir, "unity_results.json")
|
|
@@ -1720,7 +1725,7 @@ class TestArticulatedRigRuntime(unittest.TestCase):
|
|
|
1720
1725
|
|
|
1721
1726
|
@classmethod
|
|
1722
1727
|
def setUpClass(cls):
|
|
1723
|
-
cls.temp_dir = TempProjects.allocate("articulated_rig_runtime")
|
|
1728
|
+
cls.temp_dir = TempProjects.allocate("articulated_rig_runtime", cls)
|
|
1724
1729
|
cls.unity = None
|
|
1725
1730
|
cls.doc = ptk.ArticulationConformance.cases(seed=SEED, per_rig=PER_RIG)
|
|
1726
1731
|
cls.scenario = ControllerScenario(cls.doc)
|
|
@@ -1756,10 +1761,6 @@ class TestArticulatedRigRuntime(unittest.TestCase):
|
|
|
1756
1761
|
}
|
|
1757
1762
|
logger.info(f"Temp dir: {cls.temp_dir}")
|
|
1758
1763
|
|
|
1759
|
-
@classmethod
|
|
1760
|
-
def tearDownClass(cls):
|
|
1761
|
-
logger.info(f"Results preserved in: {cls.temp_dir}")
|
|
1762
|
-
|
|
1763
1764
|
def _results(self):
|
|
1764
1765
|
unity = self.__class__.unity
|
|
1765
1766
|
if not unity:
|
|
@@ -1865,9 +1866,7 @@ class TestArticulatedRigRuntime(unittest.TestCase):
|
|
|
1865
1866
|
for name in _bundle_assets()
|
|
1866
1867
|
}
|
|
1867
1868
|
self.assertEqual(got, expected, "Unity named a deployed asset differently")
|
|
1868
|
-
package = TemplateDeployer.package_dir(
|
|
1869
|
-
os.path.join(self.temp_dir, "UnityProject")
|
|
1870
|
-
)
|
|
1869
|
+
package = TemplateDeployer.package_dir(TempProjects.project(self.temp_dir))
|
|
1871
1870
|
rewritten = []
|
|
1872
1871
|
for name in _bundle_assets():
|
|
1873
1872
|
path = os.path.join(package, *name.split("/")) + ".meta"
|
|
@@ -2703,7 +2702,7 @@ public class ArticulatedRigXRVerifier
|
|
|
2703
2702
|
const string INPUTS = @"__INPUTS_PATH__";
|
|
2704
2703
|
|
|
2705
2704
|
static string B(bool b) => b ? "true" : "false";
|
|
2706
|
-
static string N(double v) =>
|
|
2705
|
+
static string N(double v) => UnitytkJson.Number(v);
|
|
2707
2706
|
static IList<object> L(object o) => (IList<object>)o;
|
|
2708
2707
|
static float F(object o) => (float)(double)o;
|
|
2709
2708
|
|
|
@@ -2712,7 +2711,7 @@ public class ArticulatedRigXRVerifier
|
|
|
2712
2711
|
var sb = new StringBuilder("{\n");
|
|
2713
2712
|
try
|
|
2714
2713
|
{
|
|
2715
|
-
var inputs = (IDictionary<string, object>)
|
|
2714
|
+
var inputs = (IDictionary<string, object>)UnitytkJson.Parse(File.ReadAllText(INPUTS));
|
|
2716
2715
|
var names = L(inputs["names"]);
|
|
2717
2716
|
var parents = L(inputs["parents"]);
|
|
2718
2717
|
var locals = L(inputs["locals"]);
|
|
@@ -2778,7 +2777,7 @@ class TestArticulatedRigXRI(unittest.TestCase):
|
|
|
2778
2777
|
|
|
2779
2778
|
@classmethod
|
|
2780
2779
|
def setUpClass(cls):
|
|
2781
|
-
cls.temp_dir = TempProjects.allocate("articulated_rig_xri")
|
|
2780
|
+
cls.temp_dir = TempProjects.allocate("articulated_rig_xri", cls)
|
|
2782
2781
|
cls.unity = None
|
|
2783
2782
|
|
|
2784
2783
|
@EnvSkip.unless(_unity_available(), "no Unity editor found")
|
|
@@ -394,16 +394,13 @@ class SelfContainedDeliveryTest(unittest.TestCase):
|
|
|
394
394
|
decision of 2026-10-05: every dependency embedded, zero sidecar files)."""
|
|
395
395
|
|
|
396
396
|
RECORDS = {
|
|
397
|
-
"
|
|
398
|
-
"version":
|
|
397
|
+
"lightmaps": {
|
|
398
|
+
"version": 2,
|
|
399
|
+
"unit_scale": 0.01,
|
|
399
400
|
"objects": [{"name": "Crate", "map": "Crate_Lightmap.exr", "uvIndex": 1}],
|
|
400
|
-
"probe": {
|
|
401
|
-
"map": "Room_Probe.exr",
|
|
402
|
-
"position": [0, 0, 0],
|
|
403
|
-
"unit_scale": 0.01,
|
|
404
|
-
},
|
|
401
|
+
"probe": {"map": "Room_Probe.exr", "position": [0, 0, 0], "box": None},
|
|
405
402
|
},
|
|
406
|
-
"
|
|
403
|
+
"shadows": {
|
|
407
404
|
"version": 2,
|
|
408
405
|
"planes": [
|
|
409
406
|
{
|
|
@@ -6,13 +6,13 @@ Validates the new single-carrier audio events pipeline end-to-end:
|
|
|
6
6
|
1. Maya (mayapy): Author audio tracks on the canonical ``data_internal``
|
|
7
7
|
carrier via :class:`mayatk.audio_utils.AudioUtils`, then call
|
|
8
8
|
:meth:`mayatk.audio_utils.audio_clips.AudioClips.prepare_for_export`
|
|
9
|
-
to bake ``
|
|
9
|
+
to bake the ``audio`` record as a plain string channel on ``data_export``
|
|
10
10
|
(the authoring state stays keyed on ``data_internal`` and never exports).
|
|
11
11
|
Animate a cube so the FBX contains at least one ``AnimationClip``
|
|
12
12
|
for the audio events to bind to. Export FBX.
|
|
13
13
|
2. Unity (batchmode): Import FBX with the real
|
|
14
14
|
``AudioEventController.cs`` deployed. Verify:
|
|
15
|
-
a. the ``
|
|
15
|
+
a. the ``audio`` record arrives on the ``data_export``
|
|
16
16
|
GameObject (raw user-property),
|
|
17
17
|
b. the importer auto-attaches an ``AudioEventController`` to the
|
|
18
18
|
prefab **root** (and explicitly NOT to the ``data_export``
|
|
@@ -414,17 +414,13 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
414
414
|
|
|
415
415
|
@classmethod
|
|
416
416
|
def setUpClass(cls):
|
|
417
|
-
cls.temp_dir = TempProjects.allocate("audio_events_integ")
|
|
417
|
+
cls.temp_dir = TempProjects.allocate("audio_events_integ", cls)
|
|
418
418
|
cls.fbx_path = None
|
|
419
419
|
cls.maya_results = None
|
|
420
420
|
cls.unity_results = None
|
|
421
421
|
cls.postproc = None
|
|
422
422
|
logger.info(f"Temp dir: {cls.temp_dir}")
|
|
423
423
|
|
|
424
|
-
@classmethod
|
|
425
|
-
def tearDownClass(cls):
|
|
426
|
-
logger.info(f"Results preserved in: {cls.temp_dir}")
|
|
427
|
-
|
|
428
424
|
# ------------------------------------------------------------------
|
|
429
425
|
# Step 1: Maya export via AudioClips.prepare_for_export
|
|
430
426
|
# ------------------------------------------------------------------
|
|
@@ -469,7 +465,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
469
465
|
self.__class__.fbx_path = r["fbx_path"]
|
|
470
466
|
self.assertTrue(r["fbx_exists"])
|
|
471
467
|
self.assertEqual(r["carrier"], "data_internal")
|
|
472
|
-
self.assertEqual(r["manifest_attr"], "
|
|
468
|
+
self.assertEqual(r["manifest_attr"], "audio")
|
|
473
469
|
# v2 manifest: versioned JSON. No shots in this scene, so events are
|
|
474
470
|
# unscoped (clip "") with frames RELATIVE to Maya's playback min
|
|
475
471
|
# (= 1 here) — Unity's clip clock maps Maya frame `min` to time 0.
|
|
@@ -499,7 +495,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
499
495
|
# as the sibling integration tests.
|
|
500
496
|
editor = os.environ.get("UNITYTK_TEST_EDITOR")
|
|
501
497
|
launcher = UnityLauncher(editor) if editor else UnityLauncher()
|
|
502
|
-
project_path =
|
|
498
|
+
project_path = TempProjects.project(self.temp_dir)
|
|
503
499
|
|
|
504
500
|
logger.info(f"Creating Unity project: {project_path}")
|
|
505
501
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
@@ -623,11 +619,11 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
623
619
|
f"in postprocessor results: {list(postproc)}",
|
|
624
620
|
)
|
|
625
621
|
self.assertIn(
|
|
626
|
-
"
|
|
622
|
+
"audio",
|
|
627
623
|
props,
|
|
628
|
-
f"
|
|
624
|
+
f"audio record missing on {name}; saw: {list(props)}",
|
|
629
625
|
)
|
|
630
|
-
manifest = props["
|
|
626
|
+
manifest = props["audio"]
|
|
631
627
|
for label in ("footstep", "jump", "land"):
|
|
632
628
|
self.assertIn(label, manifest)
|
|
633
629
|
|
|
@@ -648,7 +644,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
648
644
|
|
|
649
645
|
# (c) the real AudioEventImporter auto-attached the controller to
|
|
650
646
|
# the prefab ROOT (where the Animator will live), NOT to the GO
|
|
651
|
-
# carrying
|
|
647
|
+
# carrying the audio record — this is the runtime-dispatch invariant.
|
|
652
648
|
self.assertTrue(
|
|
653
649
|
unity.get("controller_on_root"),
|
|
654
650
|
"AudioEventController should live on the prefab root so "
|
|
@@ -739,7 +735,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
739
735
|
|
|
740
736
|
|
|
741
737
|
# ======================================================================
|
|
742
|
-
# Carrier precedence: one
|
|
738
|
+
# Carrier precedence: one audio record per model, the scene's own first
|
|
743
739
|
# ======================================================================
|
|
744
740
|
|
|
745
741
|
CARRIER_VERIFIER_CS = r"""
|
|
@@ -784,7 +780,7 @@ public class AudioCarrierVerifier
|
|
|
784
780
|
|
|
785
781
|
|
|
786
782
|
class TestAudioCarrierPrecedence(unittest.TestCase):
|
|
787
|
-
"""An FBX carrying ``
|
|
783
|
+
"""An FBX carrying the ``audio`` record on several carriers plays the
|
|
788
784
|
scene's own only.
|
|
789
785
|
|
|
790
786
|
An assembly ships a stray ``data_export1`` (and a module's
|
|
@@ -805,23 +801,31 @@ class TestAudioCarrierPrecedence(unittest.TestCase):
|
|
|
805
801
|
|
|
806
802
|
@classmethod
|
|
807
803
|
def setUpClass(cls):
|
|
808
|
-
cls.temp_dir = TempProjects.allocate("
|
|
804
|
+
cls.temp_dir = TempProjects.allocate("carrier_precedence", cls)
|
|
809
805
|
|
|
810
806
|
@BlenderEnv.skip_unless_available()
|
|
811
807
|
@EnvSkip.unless(_unity_available(), "no Unity editor found")
|
|
812
808
|
def test_the_scenes_own_carrier_wins(self):
|
|
813
|
-
own = {
|
|
814
|
-
|
|
809
|
+
own = {
|
|
810
|
+
"version": 2,
|
|
811
|
+
"fps": 24.0,
|
|
812
|
+
"events": [{"clip": "", "frame": 0, "name": "footstep"}],
|
|
813
|
+
}
|
|
814
|
+
stray = {
|
|
815
|
+
"version": 2,
|
|
816
|
+
"fps": 24.0,
|
|
817
|
+
"events": [{"clip": "", "frame": 3, "name": "door"}],
|
|
818
|
+
}
|
|
815
819
|
fixture = CarrierFbx.build(
|
|
816
820
|
os.path.join(self.temp_dir, "assembly.fbx"),
|
|
817
821
|
{
|
|
818
|
-
"data_export": {"
|
|
819
|
-
"data_export1": {"
|
|
822
|
+
"data_export": {"audio": own},
|
|
823
|
+
"data_export1": {"audio": stray},
|
|
820
824
|
},
|
|
821
825
|
)
|
|
822
826
|
|
|
823
827
|
launcher = UnityLauncher()
|
|
824
|
-
project =
|
|
828
|
+
project = TempProjects.project(self.temp_dir)
|
|
825
829
|
if not launcher.create_project(project, batch_mode=True):
|
|
826
830
|
self.skipTest(UnityEnv.project_creation_reason())
|
|
827
831
|
delivered = os.path.join(project, "Assets", "Delivered")
|
|
@@ -42,6 +42,7 @@ from base_test import (
|
|
|
42
42
|
MayaEnv,
|
|
43
43
|
SuiteOptions,
|
|
44
44
|
TemplateSources,
|
|
45
|
+
TempProjects,
|
|
45
46
|
TestAssets,
|
|
46
47
|
UnityEnv,
|
|
47
48
|
UserPropsProbe,
|
|
@@ -486,6 +487,83 @@ class UnityEnvTest(unittest.TestCase):
|
|
|
486
487
|
self.assertEqual(result.errors, [])
|
|
487
488
|
self.assertEqual(result.testsRun, 3)
|
|
488
489
|
|
|
490
|
+
def test_make_urp_fails_fast_on_a_project_too_deep_for_the_editor(self):
|
|
491
|
+
"""The editor is not long-path aware: past MAX_PATH its package imports
|
|
492
|
+
fail, URP's Autodesk Interactive graph resolves to nothing, and the
|
|
493
|
+
material suite read the fallback pick as a product bug (2026-10-19)."""
|
|
494
|
+
deep = "C:\\" + "d" * (260 - UnityEnv.URP_IMPORT_DEPTH - 3) # one past the limit
|
|
495
|
+
|
|
496
|
+
class Case(unittest.TestCase):
|
|
497
|
+
def test_deep(self):
|
|
498
|
+
UnityEnv.make_urp(self, None, deep, "unused.log")
|
|
499
|
+
|
|
500
|
+
result = _run_case(Case)
|
|
501
|
+
self.assertEqual(result.errors, [])
|
|
502
|
+
self.assertEqual(len(result.failures), 1)
|
|
503
|
+
self.assertIn("UNITYTK_TEMP_PROJECTS", result.failures[0][1])
|
|
504
|
+
|
|
505
|
+
def test_the_depth_gate_covers_every_shader_graph_urp_ships(self):
|
|
506
|
+
"""The gate measured the Autodesk Interactive graph; URP's Arnold
|
|
507
|
+
transparent graph sits 25 characters deeper, so a 107-character project
|
|
508
|
+
passed it, that graph failed to import, URP's Arnold mapper left
|
|
509
|
+
aiStandardSurface on plain Lit and the material suite failed on every
|
|
510
|
+
run from the in-repo base (2026-10-19). Measured against each installed
|
|
511
|
+
editor's bundled URP, not a list of the graphs the suites use today."""
|
|
512
|
+
from unitytk import UnityFinder
|
|
513
|
+
|
|
514
|
+
packages = [
|
|
515
|
+
p
|
|
516
|
+
for p in map(UnityEnv.bundled_urp, UnityFinder.find_editors().values())
|
|
517
|
+
if os.path.isdir(p)
|
|
518
|
+
]
|
|
519
|
+
if not packages:
|
|
520
|
+
self.skipTest(EnvSkip.reason(UnityEnv.NO_BUNDLED_URP))
|
|
521
|
+
deepest = UnityEnv.URP_IMPORT_DEPTH - len(UnityEnv.URP_PACKAGE_CACHE)
|
|
522
|
+
for package in packages:
|
|
523
|
+
for dirpath, dirnames, filenames in os.walk(package):
|
|
524
|
+
# A folder ending "~" (samples, docs) or hidden is never imported.
|
|
525
|
+
dirnames[:] = [d for d in dirnames if not d.endswith("~") and not d.startswith(".")]
|
|
526
|
+
for name in filenames:
|
|
527
|
+
if name.endswith((".shadergraph", ".shadersubgraph")):
|
|
528
|
+
below = os.path.join(dirpath, name)[len(package):]
|
|
529
|
+
self.assertLessEqual(len(below), deepest, below)
|
|
530
|
+
|
|
531
|
+
@unittest.skipUnless(
|
|
532
|
+
os.name == "nt", "MAX_PATH is the Windows editor's limit; no Unity runs here"
|
|
533
|
+
)
|
|
534
|
+
def test_every_suite_fits_a_urp_project_under_the_default_base(self):
|
|
535
|
+
"""A plain ``run_tests.py --all`` builds its projects under the in-repo
|
|
536
|
+
base, where ``<run>\\urp\\UnityProject`` put the material suite's URP
|
|
537
|
+
project at 107 characters: past the gate, so every URP suite failed at
|
|
538
|
+
once (2026-10-19). Every suite's prefix, not only today's URP suites:
|
|
539
|
+
any of them may call ``make_urp`` on its project, or add a ``"urp"`` one."""
|
|
540
|
+
prefixes = set()
|
|
541
|
+
# The allocator's own tests allocate into a sandboxed base, retired prefixes included.
|
|
542
|
+
for path in _source_files(".py", exclude=("test_temp_projects.py", "test_run_tests.py")):
|
|
543
|
+
with open(path, encoding="utf-8", errors="replace") as fh:
|
|
544
|
+
tree = ast.parse(fh.read(), filename=path)
|
|
545
|
+
for node in ast.walk(tree):
|
|
546
|
+
if (
|
|
547
|
+
isinstance(node, ast.Call)
|
|
548
|
+
and isinstance(node.func, ast.Attribute)
|
|
549
|
+
and node.func.attr == "allocate"
|
|
550
|
+
and getattr(node.func.value, "id", None) == "TempProjects"
|
|
551
|
+
and node.args
|
|
552
|
+
and isinstance(node.args[0], ast.Constant)
|
|
553
|
+
and isinstance(node.args[0].value, str)
|
|
554
|
+
):
|
|
555
|
+
prefixes.add(node.args[0].value)
|
|
556
|
+
self.assertGreater(len(prefixes), 10, "the suites' allocations were not found")
|
|
557
|
+
# TempArtifacts' tag: the clock (16 hex digits), the pid in hex (6: Linux's
|
|
558
|
+
# pid_max ceiling; Windows ids run below it) and 4 random digits.
|
|
559
|
+
tag = "f" * (16 + 6 + 4)
|
|
560
|
+
budget = 259 - UnityEnv.URP_IMPORT_DEPTH
|
|
561
|
+
for prefix in sorted(prefixes):
|
|
562
|
+
run = os.path.join(TempProjects.DEFAULT_BASE, f"{prefix}_{tag}")
|
|
563
|
+
for project in (TempProjects.project(run), TempProjects.project(run, "urp")):
|
|
564
|
+
with self.subTest(project=project):
|
|
565
|
+
self.assertLessEqual(len(project), budget, project)
|
|
566
|
+
|
|
489
567
|
|
|
490
568
|
class SuiteOptionsTest(unittest.TestCase):
|
|
491
569
|
"""The opt-in switches are named once, neutrally."""
|
|
@@ -578,6 +656,64 @@ class TemplateSourcesTest(unittest.TestCase):
|
|
|
578
656
|
with self.assertRaises(FileNotFoundError): # a bare, pre-move name
|
|
579
657
|
TemplateSources.copy_flat(["RenderEffectsController.cs"], dest)
|
|
580
658
|
|
|
659
|
+
def test_a_staged_set_must_carry_the_generated_records_it_reads(self):
|
|
660
|
+
"""AudioEventController.cs staged without AudioRecord.g.cs compiled to
|
|
661
|
+
CS0103 in Unity and only the batch editor said so (2026-10-23)."""
|
|
662
|
+
controller = "AudioEvent/AudioEventController.cs"
|
|
663
|
+
record = "AudioEvent/AudioRecord.g.cs"
|
|
664
|
+
self.assertEqual(TemplateSources.missing_records([controller]), [record])
|
|
665
|
+
self.assertEqual(TemplateSources.missing_records([controller, record]), [])
|
|
666
|
+
# A record named only in a comment is no dependency.
|
|
667
|
+
self.assertEqual(TemplateSources.missing_records(["UnitytkSettings.cs"]), [])
|
|
668
|
+
|
|
669
|
+
import pythontk as ptk
|
|
670
|
+
|
|
671
|
+
store = ptk.TempArtifacts("unitytk_template_sources", policy="scoped")
|
|
672
|
+
self.addCleanup(store.cleanup)
|
|
673
|
+
dest = os.path.join(store.dir_path(), "Scripts")
|
|
674
|
+
with self.assertRaises(ValueError) as ctx:
|
|
675
|
+
TemplateSources.copy_flat(["UnitytkSettings.cs", controller], dest)
|
|
676
|
+
self.assertIn(record, str(ctx.exception))
|
|
677
|
+
self.assertFalse(os.path.exists(dest), "a refused set copies nothing")
|
|
678
|
+
|
|
679
|
+
def test_every_suite_stages_a_compile_closed_set(self):
|
|
680
|
+
"""Each literal set a suite hands TemplateSources carries the records
|
|
681
|
+
its files read -- checked here, where no Unity is needed, because the
|
|
682
|
+
suites that stage them skip on every machine without one."""
|
|
683
|
+
calls = {"copy_flat", "available"}
|
|
684
|
+
offenders = []
|
|
685
|
+
for path in _source_files(".py", exclude=("base_test.py",)):
|
|
686
|
+
with open(path, encoding="utf-8", errors="replace") as fh:
|
|
687
|
+
tree = ast.parse(fh.read(), path)
|
|
688
|
+
consts = {
|
|
689
|
+
t.id: node.value
|
|
690
|
+
for node in tree.body
|
|
691
|
+
if isinstance(node, ast.Assign)
|
|
692
|
+
for t in node.targets
|
|
693
|
+
if isinstance(t, ast.Name)
|
|
694
|
+
}
|
|
695
|
+
for node in ast.walk(tree):
|
|
696
|
+
if not (
|
|
697
|
+
isinstance(node, ast.Call)
|
|
698
|
+
and isinstance(node.func, ast.Attribute)
|
|
699
|
+
and node.func.attr in calls
|
|
700
|
+
and isinstance(node.func.value, ast.Name)
|
|
701
|
+
and node.func.value.id == "TemplateSources"
|
|
702
|
+
and node.args
|
|
703
|
+
):
|
|
704
|
+
continue
|
|
705
|
+
arg = node.args[0]
|
|
706
|
+
arg = consts.get(arg.id, arg) if isinstance(arg, ast.Name) else arg
|
|
707
|
+
try:
|
|
708
|
+
names = ast.literal_eval(arg)
|
|
709
|
+
except ValueError:
|
|
710
|
+
continue # built at run time: copy_flat checks it then
|
|
711
|
+
missing = TemplateSources.missing_records(names)
|
|
712
|
+
if missing:
|
|
713
|
+
rel = os.path.relpath(path, REPO_ROOT)
|
|
714
|
+
offenders.append(f"{rel}:{node.lineno} lacks {missing}")
|
|
715
|
+
self.assertEqual(offenders, [], "\n".join(offenders))
|
|
716
|
+
|
|
581
717
|
def test_no_suite_joins_the_templates_dir_itself(self):
|
|
582
718
|
"""Five suites joined their own templates dir with a bare file name;
|
|
583
719
|
one of them silently skipped a copy that no longer resolved."""
|
|
@@ -601,10 +737,10 @@ class UserPropsProbeTest(unittest.TestCase):
|
|
|
601
737
|
self.assertFalse(UserPropsProbe.is_carrier(None))
|
|
602
738
|
|
|
603
739
|
def test_find_carrier_returns_the_matching_entry(self):
|
|
604
|
-
postproc = {"root": {}, "data_export 1": {"
|
|
740
|
+
postproc = {"root": {}, "data_export 1": {"animation": "{}"}}
|
|
605
741
|
name, props = UserPropsProbe.find_carrier(postproc)
|
|
606
742
|
self.assertEqual(name, "data_export 1")
|
|
607
|
-
self.assertEqual(props, {"
|
|
743
|
+
self.assertEqual(props, {"animation": "{}"})
|
|
608
744
|
|
|
609
745
|
def test_find_carrier_is_none_when_absent(self):
|
|
610
746
|
self.assertEqual(UserPropsProbe.find_carrier({"root": {}}), (None, None))
|
|
@@ -616,10 +752,8 @@ class UserPropsProbeTest(unittest.TestCase):
|
|
|
616
752
|
self.assertFalse(UserPropsProbe.is_carrier("root/data_export/child"))
|
|
617
753
|
|
|
618
754
|
def test_carrier_props_returns_just_the_props(self):
|
|
619
|
-
postproc = {"root": {}, "root/data_export": {"
|
|
620
|
-
self.assertEqual(
|
|
621
|
-
UserPropsProbe.carrier_props(postproc), {"shot_metadata": "{}"}
|
|
622
|
-
)
|
|
755
|
+
postproc = {"root": {}, "root/data_export": {"animation": "{}"}}
|
|
756
|
+
self.assertEqual(UserPropsProbe.carrier_props(postproc), {"animation": "{}"})
|
|
623
757
|
|
|
624
758
|
def test_carrier_props_is_none_when_absent(self):
|
|
625
759
|
self.assertIsNone(UserPropsProbe.carrier_props({"root": {}}))
|
|
@@ -306,15 +306,11 @@ class TestBlenderRenderEffectsE2E(unittest.TestCase):
|
|
|
306
306
|
|
|
307
307
|
@classmethod
|
|
308
308
|
def setUpClass(cls):
|
|
309
|
-
cls.temp_dir = TempProjects.allocate("blender_effects_e2e")
|
|
309
|
+
cls.temp_dir = TempProjects.allocate("blender_effects_e2e", cls)
|
|
310
310
|
cls.blender_results = None
|
|
311
311
|
cls.unity_results = None
|
|
312
312
|
logger.info(f"Temp dir: {cls.temp_dir}")
|
|
313
313
|
|
|
314
|
-
@classmethod
|
|
315
|
-
def tearDownClass(cls):
|
|
316
|
-
logger.info(f"Results preserved in: {cls.temp_dir}")
|
|
317
|
-
|
|
318
314
|
@BlenderEnv.skip_unless_available()
|
|
319
315
|
def test_01_blender_export(self):
|
|
320
316
|
"""Author both channels and the keyed visibility; write both ways."""
|
|
@@ -351,7 +347,7 @@ class TestBlenderRenderEffectsE2E(unittest.TestCase):
|
|
|
351
347
|
self.skipTest("Blender results not available -- test_01 must run first")
|
|
352
348
|
editor = os.environ.get("UNITYTK_TEST_EDITOR")
|
|
353
349
|
launcher = UnityLauncher(editor) if editor else UnityLauncher()
|
|
354
|
-
project_path =
|
|
350
|
+
project_path = TempProjects.project(self.temp_dir)
|
|
355
351
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
356
352
|
self.skipTest(UnityEnv.project_creation_reason())
|
|
357
353
|
assets_path = os.path.join(project_path, "Assets")
|
|
@@ -198,7 +198,7 @@ ok = exporter.perform_export(
|
|
|
198
198
|
tasks={"export_data_node": True},
|
|
199
199
|
)
|
|
200
200
|
fbx_path = os.path.join(output_dir, __FBX_NAME__ + ".fbx")
|
|
201
|
-
payload = btk.DataNodes.read(ptk.Scope.DELIVERABLE,
|
|
201
|
+
payload = btk.DataNodes.read(ptk.Scope.DELIVERABLE, ptk.SceneRecords.SHADOWS.key)
|
|
202
202
|
|
|
203
203
|
# The maps ship loose beside the FBX: the records name them by file name.
|
|
204
204
|
textures = []
|
|
@@ -542,15 +542,11 @@ class TestBlenderShadowPlaneIntegration(unittest.TestCase):
|
|
|
542
542
|
|
|
543
543
|
@classmethod
|
|
544
544
|
def setUpClass(cls):
|
|
545
|
-
cls.temp_dir = TempProjects.allocate("blender_shadow_integ")
|
|
545
|
+
cls.temp_dir = TempProjects.allocate("blender_shadow_integ", cls)
|
|
546
546
|
cls.blender_results = None
|
|
547
547
|
cls.unity_results = None
|
|
548
548
|
logger.info(f"Temp dir: {cls.temp_dir}")
|
|
549
549
|
|
|
550
|
-
@classmethod
|
|
551
|
-
def tearDownClass(cls):
|
|
552
|
-
logger.info(f"Results preserved in: {cls.temp_dir}")
|
|
553
|
-
|
|
554
550
|
def _blender(self):
|
|
555
551
|
blender = self.__class__.blender_results
|
|
556
552
|
if not blender:
|
|
@@ -590,7 +586,7 @@ class TestBlenderShadowPlaneIntegration(unittest.TestCase):
|
|
|
590
586
|
self.assertAlmostEqual(payload.get("unit_scale"), 1.0, places=6)
|
|
591
587
|
records = {p["name"]: p for p in payload.get("planes", [])}
|
|
592
588
|
for key, rig in r["rigs"].items():
|
|
593
|
-
self.assertIn(rig["plane"], records, f"{key}: no
|
|
589
|
+
self.assertIn(rig["plane"], records, f"{key}: no shadows record")
|
|
594
590
|
self.assertEqual(records[r["rigs"]["horizon"]["plane"]]["type"], "horizon")
|
|
595
591
|
self.assertEqual(
|
|
596
592
|
records[r["rigs"]["sun"]["plane"]]["source_type"], "directional"
|
|
@@ -606,7 +602,7 @@ class TestBlenderShadowPlaneIntegration(unittest.TestCase):
|
|
|
606
602
|
blender = self._blender()
|
|
607
603
|
editor = os.environ.get("UNITYTK_TEST_EDITOR")
|
|
608
604
|
launcher = UnityLauncher(editor) if editor else UnityLauncher()
|
|
609
|
-
project_path =
|
|
605
|
+
project_path = TempProjects.project(self.temp_dir)
|
|
610
606
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
611
607
|
self.skipTest(UnityEnv.project_creation_reason())
|
|
612
608
|
|
|
@@ -151,7 +151,7 @@ for name, mode in VARIANTS.items():
|
|
|
151
151
|
)
|
|
152
152
|
path = os.path.join(output_dir, name + ".fbx")
|
|
153
153
|
exists = bool(ok) and os.path.exists(path)
|
|
154
|
-
meta = btk.DataNodes.read(ptk.Scope.DELIVERABLE,
|
|
154
|
+
meta = btk.DataNodes.read(ptk.Scope.DELIVERABLE, ptk.SceneRecords.SHOTS.key)
|
|
155
155
|
variants[name] = {
|
|
156
156
|
"mode": mode,
|
|
157
157
|
"fbx_exists": exists,
|
|
@@ -181,16 +181,12 @@ class TestBlenderShotMetadataIntegration(unittest.TestCase):
|
|
|
181
181
|
|
|
182
182
|
@classmethod
|
|
183
183
|
def setUpClass(cls):
|
|
184
|
-
cls.temp_dir = TempProjects.allocate("blender_shot_meta_integ")
|
|
184
|
+
cls.temp_dir = TempProjects.allocate("blender_shot_meta_integ", cls)
|
|
185
185
|
cls.blender_results = None
|
|
186
186
|
cls.unity_results = None
|
|
187
187
|
cls.postproc = None
|
|
188
188
|
logger.info(f"Temp dir: {cls.temp_dir}")
|
|
189
189
|
|
|
190
|
-
@classmethod
|
|
191
|
-
def tearDownClass(cls):
|
|
192
|
-
logger.info(f"Results preserved in: {cls.temp_dir}")
|
|
193
|
-
|
|
194
190
|
# ---- Step 1: Blender export ----------------------------------------
|
|
195
191
|
|
|
196
192
|
@BlenderEnv.skip_unless_available()
|
|
@@ -217,7 +213,6 @@ class TestBlenderShotMetadataIntegration(unittest.TestCase):
|
|
|
217
213
|
{c: (s["start"], s["end"]) for c, s in shots.items()}, SHOTS, name
|
|
218
214
|
)
|
|
219
215
|
self.assertEqual(shots["A01"]["description"], "Open the hangar doors")
|
|
220
|
-
self.assertEqual(shots["A01"]["section"], "A")
|
|
221
216
|
# Shots Only ships the shots; Full Sequence Only ships one take.
|
|
222
217
|
self.assertEqual(r["variants"]["shot_clips_shots"]["takes"], sorted(SHOTS))
|
|
223
218
|
self.assertEqual(len(r["variants"]["shot_clips_full"]["takes"]), 1)
|
|
@@ -232,7 +227,7 @@ class TestBlenderShotMetadataIntegration(unittest.TestCase):
|
|
|
232
227
|
self.skipTest("Blender results not available -- test_01 must run first")
|
|
233
228
|
editor = os.environ.get("UNITYTK_TEST_EDITOR")
|
|
234
229
|
launcher = UnityLauncher(editor) if editor else UnityLauncher()
|
|
235
|
-
project_path =
|
|
230
|
+
project_path = TempProjects.project(self.temp_dir)
|
|
236
231
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
237
232
|
self.skipTest(UnityEnv.project_creation_reason())
|
|
238
233
|
|
|
@@ -313,8 +308,8 @@ class TestBlenderShotMetadataIntegration(unittest.TestCase):
|
|
|
313
308
|
self.assertTrue(unity.get("postprocessor_fired"))
|
|
314
309
|
carrier = UserPropsProbe.carrier_props(self.__class__.postproc or {})
|
|
315
310
|
self.assertIsNotNone(carrier, "no data_export carrier arrived")
|
|
316
|
-
self.assertIn("
|
|
317
|
-
self.assertIn("Open the hangar doors", carrier["
|
|
311
|
+
self.assertIn("animation", carrier)
|
|
312
|
+
self.assertIn("Open the hangar doors", carrier["animation"])
|
|
318
313
|
|
|
319
314
|
self.assertTrue(unity.get("prefab_loaded"))
|
|
320
315
|
self.assertTrue(unity.get("data_export_found"))
|
|
@@ -326,7 +321,6 @@ class TestBlenderShotMetadataIntegration(unittest.TestCase):
|
|
|
326
321
|
self.assertEqual(unity.get("record_count"), 2)
|
|
327
322
|
recs = {r.split("|")[0]: r.split("|") for r in unity.get("records", [])}
|
|
328
323
|
self.assertEqual(recs["A01"][1], "Open the hangar doors")
|
|
329
|
-
self.assertEqual(recs["A01"][2], "A")
|
|
330
324
|
self.assertEqual(recs["A02"][1], "Raise the platform")
|
|
331
325
|
clip_names = set(unity.get("clip_names", []))
|
|
332
326
|
for clip in recs: # every record's clip resolves to an imported clip
|