unitytk 0.3.0__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.
Files changed (132) hide show
  1. {unitytk-0.3.0/unitytk.egg-info → unitytk-0.4.0}/PKG-INFO +2 -2
  2. {unitytk-0.3.0 → unitytk-0.4.0}/pyproject.toml +7 -2
  3. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_articulated_rig_runtime.py +16 -15
  4. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_asset_delivery.py +5 -8
  5. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_audio_events_integration.py +23 -19
  6. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_base_test.py +62 -6
  7. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_blender_render_effects_e2e.py +1 -5
  8. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_blender_shadow_plane_integration.py +3 -7
  9. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_blender_shot_metadata_integration.py +4 -10
  10. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_clip_name_contract_integration.py +5 -9
  11. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_controller_runtime_integration.py +1 -5
  12. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_deploy_templates.py +150 -5
  13. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_embedded_dependencies_integration.py +5 -7
  14. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_emissive_groups_integration.py +1 -5
  15. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_fade_window_preservation.py +1 -6
  16. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_keyed_visibility.py +3 -11
  17. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_lightmap_metadata_integration.py +382 -81
  18. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_maya_surface_materials_integration.py +4 -7
  19. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_multi_section_audio_integration.py +1 -14
  20. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_render_effects_e2e.py +2 -2
  21. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_render_opacity_controller.py +1 -6
  22. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_render_opacity_e2e.py +5 -7
  23. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_render_opacity_integration.py +1 -7
  24. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_run_tests.py +17 -0
  25. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_shadow_plane_integration.py +5 -9
  26. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_shadow_plane_runtime_integration.py +50 -15
  27. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_shared_material_standalone.py +3 -11
  28. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_shot_metadata_integration.py +99 -21
  29. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_shots_audio_sidebyside_integration.py +15 -19
  30. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_standalone_enduser.py +4 -11
  31. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_temp_projects.py +117 -5
  32. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/__init__.py +1 -1
  33. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigController.cs +81 -249
  34. unitytk-0.4.0/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs +330 -0
  35. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/AudioEvent/AudioEventController.cs +63 -124
  36. unitytk-0.4.0/unitytk/templates/AudioEvent/AudioRecord.g.cs +260 -0
  37. unitytk-0.4.0/unitytk/templates/AudioEvent/AudioRecord.g.cs.meta +11 -0
  38. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupController.cs +28 -56
  39. unitytk-0.4.0/unitytk/templates/EmissiveGroup/EmissiveGroupsRecord.g.cs +268 -0
  40. unitytk-0.4.0/unitytk/templates/EmissiveGroup/EmissiveGroupsRecord.g.cs.meta +11 -0
  41. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableLit.shader +20 -2
  42. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableShading.cs +134 -24
  43. unitytk-0.4.0/unitytk/templates/LightmapMetadata/HandoffBlock.g.cs +303 -0
  44. unitytk-0.4.0/unitytk/templates/LightmapMetadata/HandoffBlock.g.cs.meta +11 -0
  45. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/LightmapMetadataController.cs +224 -251
  46. unitytk-0.4.0/unitytk/templates/LightmapMetadata/LightmapRecord.g.cs +466 -0
  47. unitytk-0.4.0/unitytk/templates/LightmapMetadata/LightmapRecord.g.cs.meta +11 -0
  48. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MapAbsence.g.cs +18 -0
  49. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MapAbsence.g.cs.meta +11 -0
  50. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.cs +81 -0
  51. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.cs.meta +11 -0
  52. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.g.cs +291 -0
  53. unitytk-0.4.0/unitytk/templates/LightmapMetadata/MaterialRecord.g.cs.meta +11 -0
  54. unitytk-0.4.0/unitytk/templates/LightmapMetadata/RenderingPolicy.g.cs +50 -0
  55. unitytk-0.4.0/unitytk/templates/LightmapMetadata/RenderingPolicy.g.cs.meta +11 -0
  56. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/MayaSurface/MayaSurfaceMaterialImporter.cs +10 -12
  57. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/README.md +33 -28
  58. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlane.shader +12 -5
  59. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneController.cs +109 -111
  60. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneHorizon.hlsl +4 -2
  61. unitytk-0.4.0/unitytk/templates/ShadowPlane/ShadowRecord.g.cs +419 -0
  62. unitytk-0.4.0/unitytk/templates/ShadowPlane/ShadowRecord.g.cs.meta +11 -0
  63. unitytk-0.4.0/unitytk/templates/ShotMetadata/AnimationRecord.g.cs +272 -0
  64. unitytk-0.4.0/unitytk/templates/ShotMetadata/AnimationRecord.g.cs.meta +11 -0
  65. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShotMetadata/ShotMetadataController.cs +56 -55
  66. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/UnitytkSettings.cs +331 -16
  67. {unitytk-0.3.0 → unitytk-0.4.0/unitytk.egg-info}/PKG-INFO +2 -2
  68. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk.egg-info/SOURCES.txt +20 -0
  69. unitytk-0.4.0/unitytk.egg-info/requires.txt +1 -0
  70. unitytk-0.3.0/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs +0 -202
  71. unitytk-0.3.0/unitytk.egg-info/requires.txt +0 -1
  72. {unitytk-0.3.0 → unitytk-0.4.0}/LICENSE +0 -0
  73. {unitytk-0.3.0 → unitytk-0.4.0}/MANIFEST.in +0 -0
  74. {unitytk-0.3.0 → unitytk-0.4.0}/docs/README.md +0 -0
  75. {unitytk-0.3.0 → unitytk-0.4.0}/setup.cfg +0 -0
  76. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_bool_to_fade_curve.py +0 -0
  77. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_launcher.py +0 -0
  78. {unitytk-0.3.0 → unitytk-0.4.0}/test/test_scene_builder.py +0 -0
  79. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/asset_delivery.py +0 -0
  80. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/launcher.py +0 -0
  81. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/scene_builder.py +0 -0
  82. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/template_deployer.py +0 -0
  83. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigController.cs.meta +0 -0
  84. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigPointerGrab.cs +0 -0
  85. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulatedRigPointerGrab.cs.meta +0 -0
  86. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/ArticulationRecord.g.cs.meta +0 -0
  87. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRGrab.cs +0 -0
  88. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRGrab.cs.meta +0 -0
  89. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRSetup.cs +0 -0
  90. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/ArticulatedRigXRSetup.cs.meta +0 -0
  91. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/M3trik.Unitytk.XR.asmdef +0 -0
  92. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR/M3trik.Unitytk.XR.asmdef.meta +0 -0
  93. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig/XR.meta +0 -0
  94. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ArticulatedRig.meta +0 -0
  95. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/AudioEvent/AudioEventController.cs.meta +0 -0
  96. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/AudioEvent.meta +0 -0
  97. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupController.cs.meta +0 -0
  98. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroups.hlsl +0 -0
  99. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroups.hlsl.meta +0 -0
  100. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupsLit.shader +0 -0
  101. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup/EmissiveGroupsLit.shader.meta +0 -0
  102. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/EmissiveGroup.meta +0 -0
  103. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableCubeUV.hlsl +0 -0
  104. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableCubeUV.hlsl.meta +0 -0
  105. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableLit.shader.meta +0 -0
  106. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverablePmrem.cs +0 -0
  107. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverablePmrem.cs.meta +0 -0
  108. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableShading.cs.meta +0 -0
  109. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableToneMap.shader +0 -0
  110. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableToneMap.shader.meta +0 -0
  111. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableToneMapFeature.cs +0 -0
  112. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/DeliverableToneMapFeature.cs.meta +0 -0
  113. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata/LightmapMetadataController.cs.meta +0 -0
  114. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/LightmapMetadata.meta +0 -0
  115. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/M3trik.Unitytk.asmdef +0 -0
  116. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/M3trik.Unitytk.asmdef.meta +0 -0
  117. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/MayaSurface/MayaSurfaceMaterialImporter.cs.meta +0 -0
  118. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/MayaSurface.meta +0 -0
  119. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/README.md.meta +0 -0
  120. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/RenderEffects/RenderEffectsController.cs +0 -0
  121. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/RenderEffects/RenderEffectsController.cs.meta +0 -0
  122. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/RenderEffects.meta +0 -0
  123. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlane.shader.meta +0 -0
  124. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneController.cs.meta +0 -0
  125. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane/ShadowPlaneHorizon.hlsl.meta +0 -0
  126. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShadowPlane.meta +0 -0
  127. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShotMetadata/ShotMetadataController.cs.meta +0 -0
  128. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/ShotMetadata.meta +0 -0
  129. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/UnitytkSettings.cs.meta +0 -0
  130. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk/templates/__init__.py +0 -0
  131. {unitytk-0.3.0 → unitytk-0.4.0}/unitytk.egg-info/dependency_links.txt +0 -0
  132. {unitytk-0.3.0 → 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.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.13.1
16
+ Requires-Dist: pythontk>=0.17.0
17
17
  Dynamic: license-file
18
18
 
19
19
  [![Tests](https://img.shields.io/badge/Tests-146%20passed-brightgreen.svg)](../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.13.1, the release this one ships and was tested with: an FBX
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.13.1"]
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=[{"channel": "sx"}])), # unknown channel
880
- rig(dict(ok, channels=[{"channel": "rx"}, {"channel": "rx"}])), # twice
881
- rig(dict(ok, channels=[{"channel": "rz", "min": 10, "max": -10}])), # reversed
882
- rig(ok, dict(ok, name="b", parent=0, channels=[{"channel": "tx", "min": None, "max": 3}])), # valid
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) => ArticulationJson.Number(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(ArticulationJson.Parse(File.ReadAllText(INPUTS)));
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)
@@ -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:
@@ -2701,7 +2702,7 @@ public class ArticulatedRigXRVerifier
2701
2702
  const string INPUTS = @"__INPUTS_PATH__";
2702
2703
 
2703
2704
  static string B(bool b) => b ? "true" : "false";
2704
- static string N(double v) => ArticulationJson.Number(v);
2705
+ static string N(double v) => UnitytkJson.Number(v);
2705
2706
  static IList<object> L(object o) => (IList<object>)o;
2706
2707
  static float F(object o) => (float)(double)o;
2707
2708
 
@@ -2710,7 +2711,7 @@ public class ArticulatedRigXRVerifier
2710
2711
  var sb = new StringBuilder("{\n");
2711
2712
  try
2712
2713
  {
2713
- var inputs = (IDictionary<string, object>)ArticulationJson.Parse(File.ReadAllText(INPUTS));
2714
+ var inputs = (IDictionary<string, object>)UnitytkJson.Parse(File.ReadAllText(INPUTS));
2714
2715
  var names = L(inputs["names"]);
2715
2716
  var parents = L(inputs["parents"]);
2716
2717
  var locals = L(inputs["locals"]);
@@ -2776,7 +2777,7 @@ class TestArticulatedRigXRI(unittest.TestCase):
2776
2777
 
2777
2778
  @classmethod
2778
2779
  def setUpClass(cls):
2779
- cls.temp_dir = TempProjects.allocate("articulated_rig_xri")
2780
+ cls.temp_dir = TempProjects.allocate("articulated_rig_xri", cls)
2780
2781
  cls.unity = None
2781
2782
 
2782
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
- "lightmap_metadata": {
398
- "version": 1,
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
- "shadow_metadata": {
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 ``audio_manifest`` as a plain string channel on ``data_export``
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 ``audio_manifest`` string arrives on the ``data_export``
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"], "audio_manifest")
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.
@@ -623,11 +619,11 @@ class TestAudioEventsIntegration(unittest.TestCase):
623
619
  f"in postprocessor results: {list(postproc)}",
624
620
  )
625
621
  self.assertIn(
626
- "audio_manifest",
622
+ "audio",
627
623
  props,
628
- f"audio_manifest user-property missing on {name}; saw: {list(props)}",
624
+ f"audio record missing on {name}; saw: {list(props)}",
629
625
  )
630
- manifest = props["audio_manifest"]
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 audio_manifest — this is the runtime-dispatch invariant.
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 audio_manifest per model, the scene's own first
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 ``audio_manifest`` on several carriers plays the
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,18 +801,26 @@ class TestAudioCarrierPrecedence(unittest.TestCase):
805
801
 
806
802
  @classmethod
807
803
  def setUpClass(cls):
808
- cls.temp_dir = TempProjects.allocate("carrier_precedence")
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 = {"version": 2, "events": [{"clip": "", "frame": 0, "name": "footstep"}]}
814
- stray = {"version": 2, "events": [{"clip": "", "frame": 3, "name": "door"}]}
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": {"audio_manifest": own},
819
- "data_export1": {"audio_manifest": stray},
822
+ "data_export": {"audio": own},
823
+ "data_export1": {"audio": stray},
820
824
  },
821
825
  )
822
826
 
@@ -656,6 +656,64 @@ class TemplateSourcesTest(unittest.TestCase):
656
656
  with self.assertRaises(FileNotFoundError): # a bare, pre-move name
657
657
  TemplateSources.copy_flat(["RenderEffectsController.cs"], dest)
658
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
+
659
717
  def test_no_suite_joins_the_templates_dir_itself(self):
660
718
  """Five suites joined their own templates dir with a bare file name;
661
719
  one of them silently skipped a copy that no longer resolved."""
@@ -679,10 +737,10 @@ class UserPropsProbeTest(unittest.TestCase):
679
737
  self.assertFalse(UserPropsProbe.is_carrier(None))
680
738
 
681
739
  def test_find_carrier_returns_the_matching_entry(self):
682
- postproc = {"root": {}, "data_export 1": {"shot_metadata": "{}"}}
740
+ postproc = {"root": {}, "data_export 1": {"animation": "{}"}}
683
741
  name, props = UserPropsProbe.find_carrier(postproc)
684
742
  self.assertEqual(name, "data_export 1")
685
- self.assertEqual(props, {"shot_metadata": "{}"})
743
+ self.assertEqual(props, {"animation": "{}"})
686
744
 
687
745
  def test_find_carrier_is_none_when_absent(self):
688
746
  self.assertEqual(UserPropsProbe.find_carrier({"root": {}}), (None, None))
@@ -694,10 +752,8 @@ class UserPropsProbeTest(unittest.TestCase):
694
752
  self.assertFalse(UserPropsProbe.is_carrier("root/data_export/child"))
695
753
 
696
754
  def test_carrier_props_returns_just_the_props(self):
697
- postproc = {"root": {}, "root/data_export": {"shot_metadata": "{}"}}
698
- self.assertEqual(
699
- UserPropsProbe.carrier_props(postproc), {"shot_metadata": "{}"}
700
- )
755
+ postproc = {"root": {}, "root/data_export": {"animation": "{}"}}
756
+ self.assertEqual(UserPropsProbe.carrier_props(postproc), {"animation": "{}"})
701
757
 
702
758
  def test_carrier_props_is_none_when_absent(self):
703
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."""
@@ -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, ShadowRig.SHADOW_METADATA)
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 shadow_metadata record")
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"
@@ -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, btk.DataNodes.SHOT_METADATA)
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)
@@ -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("shot_metadata", carrier)
317
- self.assertIn("Open the hangar doors", carrier["shot_metadata"])
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
@@ -3,7 +3,7 @@
3
3
  """Integration test: the Maya→Unity clip-name JOIN contract under stress.
4
4
 
5
5
  The whole shots→Unity scheme hinges on one identity: the shot name == the FBX
6
- take name == the imported ``AnimationClip.name`` == the ``shot_metadata`` ``clip``
6
+ take name == the imported ``AnimationClip.name`` == the ``animation`` record's ``clip``
7
7
  join key. The store refuses any name outside ``ShotStore.NAME_PATTERN``
8
8
  (``[A-Za-z0-9_]``, unique ignoring case) instead of respelling it on export, so
9
9
  what the user typed is what ships. This test proves both halves end to end:
@@ -97,7 +97,7 @@ view = store.to_export_view()
97
97
  store.publish_export_view()
98
98
  n_takes = FbxUtils.apply_takes_from_node()
99
99
  # The take list the split realizes, read back off the carrier through the ONE
100
- # reader of it (each shot_metadata clip's own range).
100
+ # reader of it (each animation-record clip's own range).
101
101
  takes = ptk.SceneRecords.declared_takes(
102
102
  lambda key: ptk.SceneRecords.resolve(key).load(DataNodes)
103
103
  )
@@ -116,7 +116,7 @@ results = {
116
116
  "fbx_exists": os.path.exists(fbx_path),
117
117
  "n_takes": n_takes,
118
118
  "clip_keys": [t["name"] for t in takes],
119
- "meta_keys": [s["clip"] for s in view["shot_metadata"]["shots"]],
119
+ "meta_keys": [s["clip"] for s in view[ptk.SceneRecords.SHOTS.key]["shots"]],
120
120
  "refused": refused,
121
121
  }
122
122
  with open(os.path.join(output_dir, "maya_results.json"), "w") as f:
@@ -168,7 +168,7 @@ public class ClipNameContractVerifier
168
168
  .Select(c => c.name)
169
169
  .ToList();
170
170
 
171
- // shot_metadata clip keys, via the attached controller (reflection).
171
+ // The animation record's clip keys, via the attached controller (reflection).
172
172
  var clipKeys = new List<string>();
173
173
  var smcType = (Type.GetType("ShotMetadataController, M3trik.Unitytk") ?? Type.GetType("ShotMetadataController, Assembly-CSharp"));
174
174
  var recType = (Type.GetType("ShotRecord, M3trik.Unitytk") ?? Type.GetType("ShotRecord, Assembly-CSharp"));
@@ -214,16 +214,12 @@ class TestClipNameContract(unittest.TestCase):
214
214
 
215
215
  @classmethod
216
216
  def setUpClass(cls):
217
- cls.temp_dir = TempProjects.allocate("clip_name_contract")
217
+ cls.temp_dir = TempProjects.allocate("clip_name_contract", cls)
218
218
  cls.fbx_path = None
219
219
  cls.maya_results = None
220
220
  cls.unity_results = None
221
221
  logger.info(f"Temp dir: {cls.temp_dir}")
222
222
 
223
- @classmethod
224
- def tearDownClass(cls):
225
- logger.info(f"Results preserved in: {cls.temp_dir}")
226
-
227
223
  @MayaEnv.skip_unless_available()
228
224
  def test_01_maya_export(self):
229
225
  script_path = os.path.join(self.temp_dir, "maya_export.py")
@@ -168,14 +168,10 @@ class TestControllerRuntimeIntegration(unittest.TestCase):
168
168
 
169
169
  @classmethod
170
170
  def setUpClass(cls):
171
- cls.temp_dir = TempProjects.allocate("ctrl_runtime_integ")
171
+ cls.temp_dir = TempProjects.allocate("ctrl_runtime_integ", cls)
172
172
  cls.unity_results = None
173
173
  logger.info(f"Temp dir: {cls.temp_dir}")
174
174
 
175
- @classmethod
176
- def tearDownClass(cls):
177
- logger.info(f"Results preserved in: {cls.temp_dir}")
178
-
179
175
  @EnvSkip.unless(_unity_available(), "no Unity editor found")
180
176
  def test_01_unity_runtime(self):
181
177
  """Drive both controllers in a real Unity; capture the readback."""