Skip to content

Commit 71bfa4f

Browse files
authored
Merge pull request #155 from Unity-Technologies/uni-23143-update-prefab-not-at-root
UNI-23143: handle an FbxPrefab that's not the root of its prefab
2 parents 0965581 + dd4570d commit 71bfa4f

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

Assets/FbxExporters/Editor/UnitTests/FbxPrefabTest.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,44 @@ public void TestTransformAndReparenting()
434434
Assert.That (original.transform.GetChild (0).GetChild (0).name, Is.EqualTo ("building3"));
435435
Assert.That (original.transform.GetChild (0).GetChild (0).localScale, Is.EqualTo (new Vector3 (.5f, .5f, .5f)));
436436
}
437+
438+
[Test]
439+
public void TestFbxPrefabNotAtRoot()
440+
{
441+
// UNI-23143: what happens if you have an FbxPrefab that's not at the root of its prefab?
442+
// Use case: table and chair are two separate fbx files, but we
443+
// combine them into one prefab.
444+
445+
// Create a cube fbx/prefab pair.
446+
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
447+
var cubeMesh = cube.GetComponent<MeshFilter>().sharedMesh;
448+
var cubePath = GetRandomFbxFilePath();
449+
var cubeInstance = ConvertToModel.Convert(cube, fbxFullPath: cubePath);
450+
var cubeName = cubeInstance.name;
451+
452+
// Create a prefab that has the cube as a child.
453+
// Test the test: make sure the structure is what we expect.
454+
var root = new GameObject("root");
455+
cubeInstance.transform.parent = root.transform;
456+
var rootPrefab = PrefabUtility.CreatePrefab(GetRandomPrefabAssetPath(), root);
457+
Assert.That(rootPrefab);
458+
Assert.That(rootPrefab.GetComponent<MeshFilter>(), Is.Null);
459+
Assert.That(rootPrefab.transform.GetChild(0).name == cubeName);
460+
Assert.AreEqual(24, rootPrefab.transform.GetChild(0).GetComponent<MeshFilter>().sharedMesh.vertexCount);
461+
462+
// Turn the cube into a quad by exporting over its fbx file.
463+
var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
464+
var quadMesh = quad.GetComponent<MeshFilter>().sharedMesh;
465+
ModelExporter.ExportObject(cubePath, quad);
466+
467+
// The actual test:
468+
// Make sure the rootPrefab has the structure we expect.
469+
// Before fixing the bug, the root of the prefab was destroyed and recreated, so the very first test here failed:
470+
Assert.That(rootPrefab);
471+
Assert.That(rootPrefab.GetComponent<MeshFilter>(), Is.Null);
472+
Assert.That(rootPrefab.transform.GetChild(0).name == cubeName);
473+
Assert.AreEqual(4, rootPrefab.transform.GetChild(0).GetComponent<MeshFilter>().sharedMesh.vertexCount);
474+
}
437475
}
438476

439477
public class FbxPrefabHelpersTest

Assets/FbxExporters/FbxPrefab.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -920,12 +920,20 @@ void CompareAndUpdate()
920920
// We could optimize this out if we had nothing to do, but then the
921921
// OnUpdate handler wouldn't always get called, and that makes for
922922
// confusing API.
923-
var prefabInstance = UnityEditor.PrefabUtility.InstantiatePrefab(this.gameObject) as GameObject;
924-
if (!prefabInstance) {
923+
924+
// This FbxPrefab may not be at the root of its prefab. We instantiate the root of the prefab, then
925+
// we find the corresponding FbxPrefab.
926+
var prefabRoot = UnityEditor.PrefabUtility.FindPrefabRoot(this.gameObject);
927+
var prefabInstanceRoot = UnityEditor.PrefabUtility.InstantiatePrefab(prefabRoot) as GameObject;
928+
if (!prefabInstanceRoot) {
925929
throw new System.Exception(string.Format("Failed to instantiate {0}; is it really a prefab?",
926930
this.gameObject));
927931
}
928-
var fbxPrefabInstance = prefabInstance.GetComponent<FbxPrefab>();
932+
var fbxPrefabInstance = prefabInstanceRoot.GetComponentsInChildren<FbxPrefab>().FirstOrDefault(
933+
fbxPrefab => UnityEditor.PrefabUtility.GetPrefabParent(fbxPrefab) == this);
934+
if (!fbxPrefabInstance) {
935+
throw new System.Exception(string.Format("Internal error: couldn't find the right FbxPrefab after instantiating."));
936+
}
929937

930938
// Do ALL the things (potentially nothing).
931939
var updatedObjects = updates.ImplementUpdates(fbxPrefabInstance);
@@ -941,10 +949,10 @@ void CompareAndUpdate()
941949
fbxPrefabInstance.m_fbxHistory = newFbxRepString;
942950

943951
// Save the changes back to the prefab.
944-
UnityEditor.PrefabUtility.ReplacePrefab(prefabInstance, this.transform);
952+
UnityEditor.PrefabUtility.ReplacePrefab(prefabInstanceRoot, prefabRoot);
945953

946954
// Destroy the prefabInstance.
947-
GameObject.DestroyImmediate(prefabInstance);
955+
GameObject.DestroyImmediate(prefabInstanceRoot);
948956
}
949957

950958
/// <summary>

0 commit comments

Comments
 (0)