unitytk 0.0.2__tar.gz → 0.0.3__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 (50) hide show
  1. {unitytk-0.0.2 → unitytk-0.0.3}/MANIFEST.in +1 -1
  2. {unitytk-0.0.2/unitytk.egg-info → unitytk-0.0.3}/PKG-INFO +3 -3
  3. {unitytk-0.0.2 → unitytk-0.0.3}/docs/README.md +2 -2
  4. {unitytk-0.0.2 → unitytk-0.0.3}/pyproject.toml +1 -1
  5. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_audio_events_integration.py +4 -7
  6. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_c130_fcr_integration.py +5 -15
  7. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_c5m_visibility.py +12 -5
  8. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_clip_name_contract_integration.py +5 -5
  9. unitytk-0.0.3/test/test_deploy_templates.py +157 -0
  10. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_fade_window_preservation.py +1 -6
  11. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_lightmap_metadata_integration.py +5 -10
  12. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_render_opacity_controller.py +5 -3
  13. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_render_opacity_e2e.py +13 -8
  14. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_shadow_plane_integration.py +4 -9
  15. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_shared_material_standalone.py +7 -4
  16. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_shot_metadata_integration.py +5 -7
  17. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_shots_audio_sidebyside_integration.py +6 -11
  18. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_standalone_enduser.py +40 -37
  19. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/__init__.py +1 -1
  20. unitytk-0.0.3/unitytk/template_deployer.py +147 -0
  21. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/AudioEventController.cs +8 -6
  22. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/EmissiveGroupController.cs +10 -9
  23. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/LightmapMetadataController.cs +12 -14
  24. unitytk-0.0.3/unitytk/templates/M3trik.Unitytk.asmdef +14 -0
  25. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/README.md +46 -41
  26. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/RenderOpacityController.cs +10 -216
  27. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/ShadowPlaneController.cs +9 -8
  28. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/ShotMetadataController.cs +6 -8
  29. unitytk-0.0.3/unitytk/templates/UnitytkSettings.cs +349 -0
  30. {unitytk-0.0.2 → unitytk-0.0.3/unitytk.egg-info}/PKG-INFO +3 -3
  31. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk.egg-info/SOURCES.txt +3 -2
  32. unitytk-0.0.2/test/test_deploy_templates.py +0 -126
  33. unitytk-0.0.2/unitytk/template_deployer.py +0 -92
  34. unitytk-0.0.2/unitytk/templates/maya_fbx_import_config.json +0 -6
  35. {unitytk-0.0.2 → unitytk-0.0.3}/LICENSE +0 -0
  36. {unitytk-0.0.2 → unitytk-0.0.3}/setup.cfg +0 -0
  37. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_asset_delivery.py +0 -0
  38. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_bool_to_fade_curve.py +0 -0
  39. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_launcher.py +0 -0
  40. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_render_opacity_integration.py +0 -0
  41. {unitytk-0.0.2 → unitytk-0.0.3}/test/test_scene_builder.py +0 -0
  42. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/asset_delivery.py +0 -0
  43. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/launcher.py +0 -0
  44. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/scene_builder.py +0 -0
  45. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/EmissiveGroups.hlsl +0 -0
  46. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/EmissiveGroupsLit.shader +0 -0
  47. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk/templates/__init__.py +0 -0
  48. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk.egg-info/dependency_links.txt +0 -0
  49. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk.egg-info/requires.txt +0 -0
  50. {unitytk-0.0.2 → unitytk-0.0.3}/unitytk.egg-info/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
1
  include LICENSE
2
2
  include docs/README.md
3
3
  include pyproject.toml
4
- recursive-include unitytk *.ui *.gif *.png *.json *.txt *.cs *.hlsl *.shader
4
+ recursive-include unitytk *.ui *.gif *.png *.json *.txt *.cs *.hlsl *.shader *.asmdef
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unitytk
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: A modular Python toolkit for Unity interaction.
5
5
  Author-email: Ryan Simpson <m3trik@outlook.com>
6
6
  License: MIT
@@ -15,7 +15,7 @@ License-File: LICENSE
15
15
  Requires-Dist: pythontk>=0.7.71
16
16
  Dynamic: license-file
17
17
 
18
- [![Tests](https://img.shields.io/badge/Tests-111%20passed-brightgreen.svg)](../test/)
18
+ [![Tests](https://img.shields.io/badge/Tests-113%20passed-brightgreen.svg)](../test/)
19
19
 
20
20
  # unitytk
21
21
 
@@ -23,7 +23,7 @@ A modular Python toolkit for Unity interaction — Python-side helpers for prepa
23
23
 
24
24
  ## More
25
25
 
26
- - [`templates/README.md`](../unitytk/templates/README.md) — the C# template catalog (opacity, audio events, shot metadata, lightmaps), the FBX user-property import contract, and deployment (`TemplateDeployer.deploy_all`)
26
+ - [`templates/README.md`](../unitytk/templates/README.md) — the C# template catalog (opacity, audio events, shot metadata, lightmaps), the FBX user-property import contract, and deployment (`TemplateDeployer.deploy_package` — embedded UPM package)
27
27
  - [mayatk's `data_nodes.md`](../../mayatk/docs/data_nodes.md) — the DCC-side producer spec these templates consume (`data_export` carrier + channel registry)
28
28
  - [`CHANGELOG.md`](../CHANGELOG.md) — notable changes
29
29
  - [`CLAUDE.md`](../CLAUDE.md) — contributor / agent conventions
@@ -1,4 +1,4 @@
1
- [![Tests](https://img.shields.io/badge/Tests-111%20passed-brightgreen.svg)](../test/)
1
+ [![Tests](https://img.shields.io/badge/Tests-113%20passed-brightgreen.svg)](../test/)
2
2
 
3
3
  # unitytk
4
4
 
@@ -6,7 +6,7 @@ A modular Python toolkit for Unity interaction — Python-side helpers for prepa
6
6
 
7
7
  ## More
8
8
 
9
- - [`templates/README.md`](../unitytk/templates/README.md) — the C# template catalog (opacity, audio events, shot metadata, lightmaps), the FBX user-property import contract, and deployment (`TemplateDeployer.deploy_all`)
9
+ - [`templates/README.md`](../unitytk/templates/README.md) — the C# template catalog (opacity, audio events, shot metadata, lightmaps), the FBX user-property import contract, and deployment (`TemplateDeployer.deploy_package` — embedded UPM package)
10
10
  - [mayatk's `data_nodes.md`](../../mayatk/docs/data_nodes.md) — the DCC-side producer spec these templates consume (`data_export` carrier + channel registry)
11
11
  - [`CHANGELOG.md`](../CHANGELOG.md) — notable changes
12
12
  - [`CLAUDE.md`](../CLAUDE.md) — contributor / agent conventions
@@ -29,4 +29,4 @@ where = ["."]
29
29
  include = ["unitytk*"]
30
30
 
31
31
  [tool.setuptools.package-data]
32
- "*" = ["*.ui", "*.json", "*.txt", "*.md", "*.cs", "*.hlsl", "*.shader"]
32
+ "*" = ["*.ui", "*.json", "*.txt", "*.md", "*.cs", "*.hlsl", "*.shader", "*.asmdef"]
@@ -276,7 +276,7 @@ public class AudioEventTestVerifier
276
276
  // (c) Look for the auto-attached AudioEventController. The importer
277
277
  // attaches it to the prefab ROOT so it co-locates with the
278
278
  // user-added Animator at runtime (SendMessage dispatch invariant).
279
- var aecType = System.Type.GetType("AudioEventController, Assembly-CSharp");
279
+ var aecType = System.Type.GetType("AudioEventController, M3trik.Unitytk") ?? System.Type.GetType("AudioEventController, Assembly-CSharp");
280
280
  bool controllerOnRoot = false;
281
281
  bool controllerOnDataExport = false;
282
282
  int clipsListCount = 0;
@@ -558,12 +558,9 @@ class TestAudioEventsIntegration(unittest.TestCase):
558
558
  shutil.copy2(fbx_path, dest_fbx)
559
559
 
560
560
  # Deploy the real runtime controllers so the AudioEventImporter
561
- # fires alongside the test postprocessor. RenderOpacityController
562
- # is required because AudioEventController references its
563
- # ImportAllowlist helper.
564
- scripts_path = os.path.join(assets_path, "Scripts")
565
- for cs_name in ("RenderOpacityController.cs", "AudioEventController.cs"):
566
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
561
+ # fires alongside the test postprocessor -- the full embedded UPM
562
+ # package (ImportGate/CarrierImport live in UnitytkSettings.cs).
563
+ TemplateDeployer.deploy_package(project_path)
567
564
 
568
565
  editor_path = os.path.join(assets_path, "Editor")
569
566
  os.makedirs(editor_path, exist_ok=True)
@@ -641,8 +641,8 @@ class TestC130FcrIntegration(unittest.TestCase):
641
641
 
642
642
  @classmethod
643
643
  def setUpClass(cls):
644
- # Use O: drive for temp dir — C: drive is often full
645
- _temp_base = r"O:\Cloud\Code\_scripts\test\temp_tests"
644
+ # Repo-local temp_tests (already on O:); temp dir — C: drive is often full
645
+ _temp_base = os.path.join(os.path.dirname(__file__), "temp_tests")
646
646
  os.makedirs(_temp_base, exist_ok=True)
647
647
  cls.temp_dir = tempfile.mkdtemp(prefix="c130_fcr_integ_", dir=_temp_base)
648
648
  cls.project_path = os.path.join(cls.temp_dir, "UnityProject")
@@ -755,19 +755,9 @@ class TestC130FcrIntegration(unittest.TestCase):
755
755
  assets_dir = os.path.join(self.project_path, "Assets")
756
756
  self.assertTrue(os.path.isdir(assets_dir))
757
757
 
758
- # --- Deploy C# templates (NOT in Editor/ runtime MonoBehaviours) ---
759
- scripts_dst = os.path.join(assets_dir, "Scripts")
760
- os.makedirs(scripts_dst, exist_ok=True)
761
-
762
- TemplateDeployer.deploy(
763
- "RenderOpacityController.cs",
764
- os.path.join(scripts_dst, "RenderOpacityController.cs"),
765
- )
766
- TemplateDeployer.deploy(
767
- "AudioEventController.cs",
768
- os.path.join(scripts_dst, "AudioEventController.cs"),
769
- )
770
- logger.info("Deployed RenderOpacityController.cs + AudioEventController.cs")
758
+ # --- Deploy the C# templates as the embedded UPM package ---
759
+ TemplateDeployer.deploy_package(self.project_path)
760
+ logger.info("Deployed the com.m3trik.unitytk template package")
771
761
 
772
762
  # --- Copy FBX (731 MB — takes a moment) ---
773
763
  dest_fbx = os.path.join(assets_dir,
@@ -379,7 +379,7 @@ class TestC5MVisibility(unittest.TestCase):
379
379
 
380
380
  @classmethod
381
381
  def setUpClass(cls):
382
- _temp_base = r"O:\Cloud\Code\_scripts\test\temp_tests"
382
+ _temp_base = os.path.join(os.path.dirname(__file__), "temp_tests")
383
383
  os.makedirs(_temp_base, exist_ok=True)
384
384
  cls.temp_dir = tempfile.mkdtemp(prefix="c5m_vis_test_", dir=_temp_base)
385
385
  cls.project_path = os.path.join(cls.temp_dir, "UnityProject")
@@ -425,9 +425,15 @@ class TestC5MVisibility(unittest.TestCase):
425
425
  logger.info("Unity project created")
426
426
 
427
427
  # === Step 2: Copy CS templates (for opacity importer) ===
428
+ # UnitytkSettings.cs is the compile-coupled home of
429
+ # ImportGate/CarrierImport that both controllers reference.
428
430
  scripts_dir = os.path.join(assets, "Scripts")
429
431
  os.makedirs(scripts_dir, exist_ok=True)
430
- for cs_name in ["RenderOpacityController.cs", "AudioEventController.cs"]:
432
+ for cs_name in [
433
+ "UnitytkSettings.cs",
434
+ "RenderOpacityController.cs",
435
+ "AudioEventController.cs",
436
+ ]:
431
437
  src = os.path.join(TEMPLATE_DIR, cs_name)
432
438
  if os.path.isfile(src):
433
439
  shutil.copy2(src, os.path.join(scripts_dir, cs_name))
@@ -441,10 +447,11 @@ class TestC5MVisibility(unittest.TestCase):
441
447
  shutil.copy2(FBX_PATH, dest_fbx)
442
448
  self.assertTrue(os.path.isfile(dest_fbx))
443
449
 
444
- # === Step 4: Deploy allowlist so importer processes this FBX ===
450
+ # === Step 4: Write allowlist so the importers process this FBX ===
445
451
  config = {"allowed_fbx": ["C5M_FCR_SPEEDRUN.fbx"]}
446
- config_path = os.path.join(assets, "maya_fbx_import_config.json")
447
- with open(config_path, "w") as f:
452
+ settings_dir = os.path.join(self.project_path, "ProjectSettings")
453
+ os.makedirs(settings_dir, exist_ok=True)
454
+ with open(os.path.join(settings_dir, "UnitytkSettings.json"), "w") as f:
448
455
  json.dump(config, f)
449
456
 
450
457
  # === Step 5: Deploy C# verifier to Assets/Editor/ ===
@@ -154,8 +154,8 @@ public class ClipNameContractVerifier
154
154
 
155
155
  // shot_metadata clip keys, via the attached controller (reflection).
156
156
  var clipKeys = new List<string>();
157
- var smcType = Type.GetType("ShotMetadataController, Assembly-CSharp");
158
- var recType = Type.GetType("ShotRecord, Assembly-CSharp");
157
+ var smcType = (Type.GetType("ShotMetadataController, M3trik.Unitytk") ?? Type.GetType("ShotMetadataController, Assembly-CSharp"));
158
+ var recType = (Type.GetType("ShotRecord, M3trik.Unitytk") ?? Type.GetType("ShotRecord, Assembly-CSharp"));
159
159
  if (prefab != null && smcType != null && recType != null)
160
160
  {
161
161
  var ctrl = prefab.GetComponent(smcType);
@@ -253,9 +253,9 @@ class TestClipNameContract(unittest.TestCase):
253
253
  os.makedirs(assets_path, exist_ok=True)
254
254
  shutil.copy2(fbx_path, os.path.join(assets_path, "clip_name_contract.fbx"))
255
255
 
256
- scripts_path = os.path.join(assets_path, "Scripts")
257
- for cs_name in ("RenderOpacityController.cs", "ShotMetadataController.cs"):
258
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
256
+ # Compile-coupled set (ImportGate/CarrierImport live in
257
+ # UnitytkSettings.cs) -- deploy the full embedded UPM package.
258
+ TemplateDeployer.deploy_package(project_path)
259
259
 
260
260
  editor_path = os.path.join(assets_path, "Editor")
261
261
  os.makedirs(editor_path, exist_ok=True)
@@ -0,0 +1,157 @@
1
+ # !/usr/bin/python
2
+ # coding=utf-8
3
+ """Tests for the embedded-UPM-package template deployment (no Unity needed).
4
+
5
+ The C# controller templates are compile-coupled: every controller calls the
6
+ shared ``ImportGate`` and ``CarrierImport`` classes that only
7
+ ``UnitytkSettings.cs`` defines, so a Unity project must hold the full set to
8
+ compile. These tests pin that contract on the Python side — the only side
9
+ that can be tested without a licensed Unity install.
10
+ """
11
+ import json
12
+ import os
13
+ import shutil
14
+ import tempfile
15
+ import unittest
16
+
17
+ import unitytk
18
+ from unitytk import TemplateDeployer
19
+ from unitytk.template_deployer import UPM_PACKAGE_NAME
20
+
21
+
22
+ class DeployTemplateTest(unittest.TestCase):
23
+ def setUp(self):
24
+ self.tmp = tempfile.mkdtemp(prefix="unitytk_deploy_")
25
+ self.project = os.path.join(self.tmp, "Project")
26
+ os.makedirs(os.path.join(self.project, "Assets"))
27
+ self.package = os.path.join(self.project, "Packages", UPM_PACKAGE_NAME)
28
+
29
+ def tearDown(self):
30
+ shutil.rmtree(self.tmp, ignore_errors=True)
31
+
32
+ def test_single_template_round_trips(self):
33
+ dest = os.path.join(self.package, "UnitytkSettings.cs")
34
+ written = TemplateDeployer.deploy("UnitytkSettings.cs", dest)
35
+ self.assertTrue(os.path.isfile(written))
36
+ with open(written, encoding="utf-8") as fh:
37
+ self.assertIn("class ImportGate", fh.read())
38
+
39
+ def test_deploy_package_ships_the_full_coupled_set(self):
40
+ """Every bundled controller, shader asset, the asmdef, the catalog
41
+ README and a generated package.json land — no partial deploy."""
42
+ written = TemplateDeployer.deploy_package(self.project)
43
+ names = sorted(os.path.basename(p) for p in written)
44
+ self.assertEqual(
45
+ names,
46
+ [
47
+ "AudioEventController.cs",
48
+ "EmissiveGroupController.cs",
49
+ "EmissiveGroups.hlsl",
50
+ "EmissiveGroupsLit.shader",
51
+ "LightmapMetadataController.cs",
52
+ "M3trik.Unitytk.asmdef",
53
+ "README.md",
54
+ "RenderOpacityController.cs",
55
+ "ShadowPlaneController.cs",
56
+ "ShotMetadataController.cs",
57
+ "UnitytkSettings.cs",
58
+ "package.json",
59
+ ],
60
+ )
61
+ for p in written:
62
+ self.assertTrue(os.path.isfile(p))
63
+ self.assertGreater(os.path.getsize(p), 0)
64
+ self.assertTrue(
65
+ os.path.normcase(p).startswith(os.path.normcase(self.package)),
66
+ f"{p} escaped the package folder",
67
+ )
68
+
69
+ def test_package_manifest_matches_the_release(self):
70
+ """package.json carries the UPM identity + this unitytk version, so
71
+ the Package Manager row is truthful and updates version-bump cleanly."""
72
+ TemplateDeployer.deploy_package(self.project)
73
+ with open(os.path.join(self.package, "package.json"), encoding="utf-8") as fh:
74
+ manifest = json.load(fh)
75
+ self.assertEqual(manifest["name"], UPM_PACKAGE_NAME)
76
+ self.assertEqual(manifest["version"], unitytk.__version__)
77
+ self.assertTrue(manifest["displayName"])
78
+ self.assertTrue(manifest["unity"])
79
+
80
+ def test_deploy_package_rejects_a_non_unity_folder(self):
81
+ """Guards against scattering the package into a wrong path."""
82
+ with self.assertRaises(ValueError):
83
+ TemplateDeployer.deploy_package(self.tmp)
84
+
85
+ def test_shader_pair_travels_together(self):
86
+ """``EmissiveGroupsLit.shader`` includes the .hlsl by RELATIVE path, so
87
+ deploying one without the other is a shader compile error in Unity."""
88
+ written = TemplateDeployer.deploy_package(self.project)
89
+ names = {os.path.basename(p) for p in written}
90
+ self.assertIn("EmissiveGroups.hlsl", names)
91
+ shader = os.path.join(self.package, "EmissiveGroupsLit.shader")
92
+ with open(shader, encoding="utf-8") as fh:
93
+ self.assertIn('#include "EmissiveGroups.hlsl"', fh.read())
94
+
95
+ def test_deploy_package_never_writes_project_config(self):
96
+ """Per-project settings live in ProjectSettings/UnitytkSettings.json,
97
+ owned by the project — deploying must not create or clobber them."""
98
+ TemplateDeployer.deploy_package(self.project)
99
+ self.assertFalse(
100
+ os.path.isfile(
101
+ os.path.join(self.project, "ProjectSettings", "UnitytkSettings.json")
102
+ )
103
+ )
104
+
105
+ # Every shared class lives in UnitytkSettings.cs; the other controllers
106
+ # must reference it (definer set / referencer set per class). Shader
107
+ # assets (.hlsl/.shader) carry no C# and are excluded.
108
+ COUPLED_DEFINER = {"UnitytkSettings.cs"}
109
+ COUPLED_REFERENCERS = {
110
+ "AudioEventController.cs",
111
+ "EmissiveGroupController.cs",
112
+ "LightmapMetadataController.cs",
113
+ "RenderOpacityController.cs",
114
+ "ShadowPlaneController.cs",
115
+ "ShotMetadataController.cs",
116
+ }
117
+
118
+ def _coupling_surface(self, shared_class):
119
+ """Deploy the set; return ``(definers, referencers)`` of *shared_class*
120
+ across the C# templates only."""
121
+ written = [
122
+ p for p in TemplateDeployer.deploy_package(self.project)
123
+ if p.endswith(".cs")
124
+ ]
125
+ definers, referencers = set(), set()
126
+ for p in written:
127
+ with open(p, encoding="utf-8") as fh:
128
+ text = fh.read()
129
+ name = os.path.basename(p)
130
+ if f"class {shared_class}" in text:
131
+ definers.add(name)
132
+ elif shared_class in text:
133
+ referencers.add(name)
134
+ return definers, referencers
135
+
136
+ def test_exactly_one_import_gate_definition_in_the_set(self):
137
+ """One template defines ``ImportGate``; every other one references it.
138
+
139
+ Guards the compile-coupling as templates evolve: a second definition
140
+ would be a duplicate-class CS error, a dropped reference would mean a
141
+ controller stopped honoring the channel toggles + FBX allowlist.
142
+ """
143
+ definers, referencers = self._coupling_surface("ImportGate")
144
+ self.assertEqual(definers, self.COUPLED_DEFINER)
145
+ self.assertEqual(referencers, self.COUPLED_REFERENCERS)
146
+
147
+ def test_exactly_one_carrier_import_definition_in_the_set(self):
148
+ """One template defines ``CarrierImport``; every other one references
149
+ it — same coupling contract as ``ImportGate`` (both live in
150
+ ``UnitytkSettings.cs``)."""
151
+ definers, referencers = self._coupling_surface("CarrierImport")
152
+ self.assertEqual(definers, self.COUPLED_DEFINER)
153
+ self.assertEqual(referencers, self.COUPLED_REFERENCERS)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ unittest.main(verbosity=2)
@@ -248,12 +248,7 @@ class TestFadeWindowPreservation(unittest.TestCase):
248
248
  self.assertTrue(launcher.create_project(project_path, batch_mode=True))
249
249
 
250
250
  assets = os.path.join(project_path, "Assets")
251
- scripts_dir = os.path.join(assets, "Scripts")
252
- os.makedirs(scripts_dir, exist_ok=True)
253
- unitytk.TemplateDeployer.deploy(
254
- "RenderOpacityController.cs",
255
- os.path.join(scripts_dir, "RenderOpacityController.cs"),
256
- )
251
+ unitytk.TemplateDeployer.deploy_package(project_path)
257
252
  shutil.copy2(self.__class__.fbx_path,
258
253
  os.path.join(assets, "fade_window.fbx"))
259
254
 
@@ -240,8 +240,8 @@ public class LightmapMetaTestVerifier
240
240
  sb.AppendLine(prefabLoaded ? "true," : "false,");
241
241
 
242
242
  // LightmapMetadataController on the prefab root + its records (reflection).
243
- var ctrlType = Type.GetType("LightmapMetadataController, Assembly-CSharp");
244
- var recType = Type.GetType("LightmapRecord, Assembly-CSharp");
243
+ var ctrlType = (Type.GetType("LightmapMetadataController, M3trik.Unitytk") ?? Type.GetType("LightmapMetadataController, Assembly-CSharp"));
244
+ var recType = (Type.GetType("LightmapRecord, M3trik.Unitytk") ?? Type.GetType("LightmapRecord, Assembly-CSharp"));
245
245
  bool controllerOnRoot = false;
246
246
  int recordCount = 0;
247
247
  int metaVersion = -1;
@@ -447,14 +447,9 @@ class TestLightmapMetadataIntegration(unittest.TestCase):
447
447
  if os.path.exists(exr_path):
448
448
  shutil.copy2(exr_path, os.path.join(assets_path, "Crate_Lightmap.exr"))
449
449
 
450
- # Deploy the real templates. RenderOpacityController ships ImportAllowlist,
451
- # which LightmapMetadataImporter.ShouldProcess() gates on.
452
- scripts_path = os.path.join(assets_path, "Scripts")
453
- for cs_name in (
454
- "RenderOpacityController.cs",
455
- "LightmapMetadataController.cs",
456
- ):
457
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
450
+ # Deploy the real templates -- the full embedded UPM package
451
+ # (ImportGate/CarrierImport live in UnitytkSettings.cs).
452
+ TemplateDeployer.deploy_package(project_path)
458
453
 
459
454
  editor_path = os.path.join(assets_path, "Editor")
460
455
  os.makedirs(editor_path, exist_ok=True)
@@ -296,9 +296,11 @@ class TestRenderOpacityController(unittest.TestCase):
296
296
 
297
297
  assets_path = os.path.join(project_path, "Assets")
298
298
 
299
- # 2. Deploy Template Script (The subject of this test)
300
- script_dest = os.path.join(assets_path, "Scripts", "RenderOpacityController.cs")
301
- unitytk.TemplateDeployer.deploy("RenderOpacityController.cs", script_dest)
299
+ # 2. Deploy the template package (the subject of this test)
300
+ written = unitytk.TemplateDeployer.deploy_package(project_path)
301
+ script_dest = next(
302
+ p for p in written if p.endswith("RenderOpacityController.cs")
303
+ )
302
304
  self.assertTrue(
303
305
  os.path.exists(script_dest), "Failed to deploy RenderOpacityController.cs"
304
306
  )
@@ -13,10 +13,9 @@ Pipeline:
13
13
  4-key fade-in/hold/fade-out pattern, call
14
14
  :meth:`RenderOpacity.prepare_for_export` to dual-key visibility,
15
15
  export FBX.
16
- 2. Unity (batchmode): deploy ``RenderOpacityController.cs`` and
17
- ``AudioEventController.cs`` (the latter is needed because
18
- ``RenderOpacityController.cs`` references ``ImportAllowlist``,
19
- which is shared with the audio side). Import the FBX. Verify:
16
+ 2. Unity (batchmode): deploy ``UnitytkSettings.cs`` (the shared
17
+ ImportGate/CarrierImport home), ``RenderOpacityController.cs`` and
18
+ ``AudioEventController.cs``. Import the FBX. Verify:
20
19
  a. Per-Renderer ``RenderOpacityController`` auto-attached.
21
20
  b. The clip carries a curve bound to
22
21
  ``RenderOpacityController.opacity`` (not the useless
@@ -211,6 +210,8 @@ public class OpacityE2EVerifier
211
210
 
212
211
  // (b) RenderOpacityController attachment count + locations
213
212
  var rocType = System.Type.GetType(
213
+ "RenderOpacityController, M3trik.Unitytk")
214
+ ?? System.Type.GetType(
214
215
  "RenderOpacityController, Assembly-CSharp");
215
216
  var rocHosts = new List<string>();
216
217
  int rocCount = 0;
@@ -477,15 +478,19 @@ class TestRenderOpacityE2E(unittest.TestCase):
477
478
  dest_fbx = os.path.join(assets_path, "opacity_test.fbx")
478
479
  shutil.copy2(fbx_path, dest_fbx)
479
480
 
480
- # Deploy BOTH real templates — RenderOpacityController.cs hosts
481
- # the shared ImportAllowlist that AudioEventController.cs uses,
482
- # and vice versa. Both must compile for the importer to run.
481
+ # Deploy the real templates — UnitytkSettings.cs hosts the shared
482
+ # ImportGate/CarrierImport both controllers reference. All must
483
+ # compile for the importer to run.
483
484
  scripts_path = os.path.join(assets_path, "Scripts")
484
485
  os.makedirs(scripts_path, exist_ok=True)
485
486
  templates_dir = os.path.join(
486
487
  scripts_dir, "unitytk", "unitytk", "templates"
487
488
  )
488
- for cs_name in ("RenderOpacityController.cs", "AudioEventController.cs"):
489
+ for cs_name in (
490
+ "UnitytkSettings.cs",
491
+ "RenderOpacityController.cs",
492
+ "AudioEventController.cs",
493
+ ):
489
494
  src = os.path.join(templates_dir, cs_name)
490
495
  dst = os.path.join(scripts_path, cs_name)
491
496
  self.assertTrue(os.path.exists(src), f"Template missing: {src}")
@@ -180,7 +180,7 @@ public class ShadowPlaneTestVerifier
180
180
  hasTexture = tex != null;
181
181
  texName = tex != null ? tex.name : "";
182
182
  }
183
- var ctrlType = Type.GetType("ShadowPlaneController, Assembly-CSharp");
183
+ var ctrlType = (Type.GetType("ShadowPlaneController, M3trik.Unitytk") ?? Type.GetType("ShadowPlaneController, Assembly-CSharp"));
184
184
  if (ctrlType != null)
185
185
  {
186
186
  var ctrl = renderer.GetComponent(ctrlType);
@@ -330,14 +330,9 @@ class TestShadowPlaneIntegration(unittest.TestCase):
330
330
  os.path.join(assets_path, "Box_shadow.png"),
331
331
  )
332
332
 
333
- # Deploy the real templates. RenderOpacityController ships ImportAllowlist,
334
- # which ShadowPlaneImporter.ShouldProcess() gates on.
335
- scripts_path = os.path.join(assets_path, "Scripts")
336
- for cs_name in (
337
- "RenderOpacityController.cs",
338
- "ShadowPlaneController.cs",
339
- ):
340
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
333
+ # Deploy the real templates -- the full embedded UPM package
334
+ # (ImportGate/CarrierImport live in UnitytkSettings.cs).
335
+ TemplateDeployer.deploy_package(project_path)
341
336
 
342
337
  editor_path = os.path.join(assets_path, "Editor")
343
338
  os.makedirs(editor_path, exist_ok=True)
@@ -35,7 +35,8 @@ SCRIPTS_DIR = r"O:\Cloud\Code\_scripts"
35
35
  TEMPLATE_DIR = os.path.join(
36
36
  os.path.dirname(__file__), os.pardir, "unitytk", "templates"
37
37
  )
38
- CS_FILES = ["RenderOpacityController.cs"]
38
+ # UnitytkSettings.cs is the compile-coupled home of ImportGate/CarrierImport.
39
+ CS_FILES = ["UnitytkSettings.cs", "RenderOpacityController.cs"]
39
40
 
40
41
  # Object names used in the Maya scene
41
42
  OBJECT_NAMES = ["piece_A", "piece_B", "piece_C"]
@@ -402,7 +403,7 @@ class TestSharedMaterialStandalone(unittest.TestCase):
402
403
 
403
404
  @classmethod
404
405
  def setUpClass(cls):
405
- _temp_base = r"O:\Cloud\Code\_scripts\test\temp_tests"
406
+ _temp_base = os.path.join(os.path.dirname(__file__), "temp_tests")
406
407
  os.makedirs(_temp_base, exist_ok=True)
407
408
  cls.temp_dir = tempfile.mkdtemp(prefix="shared_mat_", dir=_temp_base)
408
409
  logger.info(f"Temp dir: {cls.temp_dir}")
@@ -531,9 +532,11 @@ class TestSharedMaterialStandalone(unittest.TestCase):
531
532
  shutil.copy2(fbx_path, dest_fbx)
532
533
  self.assertTrue(os.path.isfile(dest_fbx))
533
534
 
534
- # Deploy allowlist config (allow this FBX)
535
+ # Write the allowlist (allow this FBX) into the settings store.
535
536
  config = {"allowed_fbx": ["shared_mat_test.fbx"]}
536
- with open(os.path.join(assets, "maya_fbx_import_config.json"), "w") as f:
537
+ settings_dir = os.path.join(project_path, "ProjectSettings")
538
+ os.makedirs(settings_dir, exist_ok=True)
539
+ with open(os.path.join(settings_dir, "UnitytkSettings.json"), "w") as f:
537
540
  json.dump(config, f)
538
541
 
539
542
  logger.info("Copied CS template + FBX + config")
@@ -249,8 +249,8 @@ public class ShotMetaTestVerifier
249
249
  sb.AppendLine(dataExport != null ? "true," : "false,");
250
250
 
251
251
  // ShotMetadataController on the prefab root + its records (reflection).
252
- var smcType = Type.GetType("ShotMetadataController, Assembly-CSharp");
253
- var recType = Type.GetType("ShotRecord, Assembly-CSharp");
252
+ var smcType = (Type.GetType("ShotMetadataController, M3trik.Unitytk") ?? Type.GetType("ShotMetadataController, Assembly-CSharp"));
253
+ var recType = (Type.GetType("ShotRecord, M3trik.Unitytk") ?? Type.GetType("ShotRecord, Assembly-CSharp"));
254
254
  bool controllerOnRoot = false;
255
255
  int recordCount = 0;
256
256
  int metaVersion = -1;
@@ -410,11 +410,9 @@ class TestShotMetadataIntegration(unittest.TestCase):
410
410
  shutil.copy2(fbx_path, os.path.join(assets_path, "shot_metadata_test.fbx"))
411
411
 
412
412
  # Deploy the real templates via the package's own helper.
413
- # RenderOpacityController ships ImportAllowlist, which the
414
- # ShotMetadataImporter ShouldProcess() gate uses.
415
- scripts_path = os.path.join(assets_path, "Scripts")
416
- for cs_name in ("RenderOpacityController.cs", "ShotMetadataController.cs"):
417
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
413
+ # The templates are compile-coupled (ImportGate/CarrierImport live in
414
+ # UnitytkSettings.cs) -- deploy the full embedded UPM package.
415
+ TemplateDeployer.deploy_package(project_path)
418
416
 
419
417
  editor_path = os.path.join(assets_path, "Editor")
420
418
  os.makedirs(editor_path, exist_ok=True)
@@ -236,8 +236,8 @@ public class SideBySideVerifier
236
236
  sb.AppendLine(" \"data_export_found\": " + (dataExportFound ? "true," : "false,"));
237
237
 
238
238
  // --- ShotMetadataController (reflection) ---
239
- var smcType = Type.GetType("ShotMetadataController, Assembly-CSharp");
240
- var recType = Type.GetType("ShotRecord, Assembly-CSharp");
239
+ var smcType = (Type.GetType("ShotMetadataController, M3trik.Unitytk") ?? Type.GetType("ShotMetadataController, Assembly-CSharp"));
240
+ var recType = (Type.GetType("ShotRecord, M3trik.Unitytk") ?? Type.GetType("ShotRecord, Assembly-CSharp"));
241
241
  bool shotOnRoot = false; int shotCount = 0;
242
242
  var shotClips = new List<string>();
243
243
  if (prefabLoaded && smcType != null)
@@ -262,7 +262,7 @@ public class SideBySideVerifier
262
262
  + string.Join(",", shotClips.Select(s => "\"" + Esc(s) + "\"")) + "],");
263
263
 
264
264
  // --- AudioEventController (reflection) ---
265
- var aecType = Type.GetType("AudioEventController, Assembly-CSharp");
265
+ var aecType = (Type.GetType("AudioEventController, M3trik.Unitytk") ?? Type.GetType("AudioEventController, Assembly-CSharp"));
266
266
  bool audioOnRoot = false; int audioSlots = 0;
267
267
  if (prefabLoaded && aecType != null)
268
268
  {
@@ -417,14 +417,9 @@ class TestShotsAudioSideBySide(unittest.TestCase):
417
417
  os.makedirs(assets_path, exist_ok=True)
418
418
  shutil.copy2(fbx_path, os.path.join(assets_path, "sidebyside_test.fbx"))
419
419
 
420
- # Deploy BOTH real controllers + the shared ImportAllowlist.
421
- scripts_path = os.path.join(assets_path, "Scripts")
422
- for cs_name in (
423
- "RenderOpacityController.cs", # ships ImportAllowlist
424
- "ShotMetadataController.cs",
425
- "AudioEventController.cs",
426
- ):
427
- TemplateDeployer.deploy(cs_name, os.path.join(scripts_path, cs_name))
420
+ # Deploy the full embedded UPM package (ImportGate/CarrierImport
421
+ # live in UnitytkSettings.cs; the set is compile-coupled).
422
+ TemplateDeployer.deploy_package(project_path)
428
423
 
429
424
  editor_path = os.path.join(assets_path, "Editor")
430
425
  os.makedirs(editor_path, exist_ok=True)