public void TestExporterCallbacks() { var tree = CreateHierarchy(); var tester = new CallbackTester(tree.transform, GetRandomFbxFilePath()); var n = tree.GetComponentsInChildren <Transform>().Length; // No callbacks registered => no calls. tester.Verify(0, 0); ModelExporter.RegisterMeshObjectCallback(tester.CallbackForObject); ModelExporter.RegisterMeshCallback <FbxPrefab>(tester.CallbackForFbxPrefab); // No fbprefab => no component calls, but every object called. tester.Verify(0, n); // Add a fbxprefab, check every object called and the prefab called. tree.transform.Find("Parent1").gameObject.AddComponent <FbxPrefab>(); tester.Verify(1, n); // Make the object report it's replacing everything => no component calls. tester.Verify(0, n, objectResult: true); // Make sure we can't register for a component twice, but we can // for an object. Register twice for an object means two calls per // object. Assert.That(() => ModelExporter.RegisterMeshCallback <FbxPrefab>(tester.CallbackForFbxPrefab), Throws.Exception); ModelExporter.RegisterMeshObjectCallback(tester.CallbackForObject); tester.Verify(1, 2 * n); // Register twice but return true => only one call per object. tester.Verify(0, n, objectResult: true); // Unregister once => only one call per object, and no more for the prefab. ModelExporter.UnRegisterMeshCallback <FbxPrefab>(); ModelExporter.UnRegisterMeshObjectCallback(tester.CallbackForObject); tester.Verify(0, n); // Legal to unregister if already unregistered. ModelExporter.UnRegisterMeshCallback <FbxPrefab>(); tester.Verify(0, n); // Register same callback twice gets back to original state. ModelExporter.UnRegisterMeshObjectCallback(tester.CallbackForObject); tester.Verify(0, 0); // Legal to unregister if already unregistered. ModelExporter.UnRegisterMeshObjectCallback(tester.CallbackForObject); tester.Verify(0, 0); /////////////////////// // Test that the callbacks not only get called, but can replace // meshes. var sphere = GameObject.CreatePrimitive(PrimitiveType.Capsule); var sphereMesh = sphere.GetComponent <MeshFilter>().sharedMesh; var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); var cubeMesh = cube.GetComponent <MeshFilter>().sharedMesh; // Pick on the fbxprefab to output a sphere in place of the cube. // the fbxprefab is on parent1. string filename; GameObject asset; Mesh assetMesh; GetMeshForComponent <FbxPrefab> prefabCallback = (ModelExporter exporter, FbxPrefab component, FbxNode node) => { exporter.ExportMesh(sphereMesh, node); return(true); }; ModelExporter.RegisterMeshCallback(prefabCallback); filename = GetRandomFbxFilePath(); ModelExporter.ExportObject(filename, tree); ModelExporter.UnRegisterMeshCallback <FbxPrefab>(); asset = AssetDatabase.LoadMainAssetAtPath(filename) as GameObject; assetMesh = asset.transform.Find("Parent1").GetComponent <MeshFilter>().sharedMesh; Assert.AreEqual(sphereMesh.triangles.Length, assetMesh.triangles.Length); assetMesh = asset.transform.Find("Parent2").GetComponent <MeshFilter>().sharedMesh; Assert.AreEqual(cubeMesh.triangles.Length, assetMesh.triangles.Length); // Try again, but this time pick on Parent2 by name (different just // to make sure we don't pass if the previous pass didn't // actually unregister). filename = GetRandomFbxFilePath(); GetMeshForObject callback = (ModelExporter exporter, GameObject gameObject, FbxNode node) => { if (gameObject.name == "Parent2") { exporter.ExportMesh(sphereMesh, node); return(true); } else { return(false); } }; ModelExporter.RegisterMeshObjectCallback(callback); ModelExporter.ExportObject(filename, tree); ModelExporter.UnRegisterMeshObjectCallback(callback); asset = AssetDatabase.LoadMainAssetAtPath(filename) as GameObject; assetMesh = asset.transform.Find("Parent1").GetComponent <MeshFilter>().sharedMesh; Assert.AreEqual(cubeMesh.triangles.Length, assetMesh.triangles.Length); assetMesh = asset.transform.Find("Parent2").GetComponent <MeshFilter>().sharedMesh; Assert.AreEqual(sphereMesh.triangles.Length, assetMesh.triangles.Length); }