Skip to content

Commit 78a6d96

Browse files
committed
Cleaned code and now Unit test is working for remapping
1 parent ecbbacd commit 78a6d96

File tree

5 files changed

+107
-61
lines changed

5 files changed

+107
-61
lines changed

Assets/FbxExporters/Editor/FbxPrefabAutoUpdater.cs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ namespace FbxExporters
2424
/// </summary>
2525
public /*static*/ class FbxPrefabAutoUpdater : UnityEditor.AssetPostprocessor
2626
{
27-
public delegate string getFBXNameFn(string nodeName);
28-
29-
3027
#if UNITY_EDITOR
3128
public const string FBX_PREFAB_FILE = "/FbxPrefab.cs";
3229
#else
@@ -162,14 +159,14 @@ public FbxPrefabUtility(FbxPrefab fbxPrefab){
162159
m_fbxPrefab = fbxPrefab;
163160
}
164161

165-
// Check if the user has specified a new name in the inspector
162+
/// <summary>
163+
/// Utility function: check if the user has specified a matching Unity name in the inspector
164+
/// </summary>
166165
public string getUnityObjectName(string fbxObjectName)
167166
{
168167
string newNameInUnity = fbxObjectName;
169-
// UnityEngine.Assertions.Assert.IsTrue(m_fbxPrefab != null);
170-
//UnityEngine.Assertions.Assert.IsTrue(m_fbxPrefab.NameMapping != null);
171168
if (fbxObjectName != "" && m_fbxPrefab.NameMapping != null) {
172-
for (int i = 0; i < m_fbxPrefab.NameMapping.Length; i++)
169+
for (int i = 0; i < m_fbxPrefab.NameMapping.Count; i++)
173170
{
174171
if (fbxObjectName == m_fbxPrefab.NameMapping[i].FBXObjectName) {
175172
newNameInUnity = m_fbxPrefab.NameMapping[i].UnityObjectName;
@@ -179,13 +176,14 @@ public string getUnityObjectName(string fbxObjectName)
179176
}
180177
return newNameInUnity;
181178
}
182-
183-
// Check if the user has specified an old name in the inspector
179+
/// <summary>
180+
/// Utility function: check if the user has specified a matching FBX name in the inspector
181+
/// </summary>
184182
public string getFBXObjectName(string unityObjectName)
185183
{
186184
string oldNameInFBX = unityObjectName;
187185
if (unityObjectName != "" && m_fbxPrefab.NameMapping != null) {
188-
for (int i = 0; i < m_fbxPrefab.NameMapping.Length; i++)
186+
for (int i = 0; i < m_fbxPrefab.NameMapping.Count; i++)
189187
{
190188
if (unityObjectName == m_fbxPrefab.NameMapping[i].UnityObjectName) {
191189
oldNameInFBX = m_fbxPrefab.NameMapping[i].FBXObjectName;
@@ -340,12 +338,12 @@ public class FbxRepresentation
340338
/// <summary>
341339
/// Build a hierarchical representation based on a transform.
342340
/// </summary>
343-
public FbxRepresentation(Transform xfo, getFBXNameFn getFBXName, bool isRoot = true)
341+
public FbxRepresentation(Transform xfo, bool isRoot = true)
344342
{
345343
m_children = new Dictionary<string, FbxRepresentation>();
346344

347345
foreach (Transform child in xfo) {
348-
m_children.Add(child.name, new FbxRepresentation(child, getFBXName, isRoot: false));
346+
m_children.Add(child.name, new FbxRepresentation(child, isRoot: false));
349347
}
350348
foreach(var component in xfo.GetComponents<Component>()) {
351349
// ignore missing components
@@ -447,7 +445,7 @@ public static string EscapeString(string str) {
447445
return builder.ToString();
448446
}
449447

450-
void InitFromJson(string json, getFBXNameFn getFBXName, ref int index)
448+
void InitFromJson(string json, ref int index)
451449
{
452450
Consume('{', json, ref index);
453451
if (Consume('}', json, ref index, required: false)) {
@@ -464,7 +462,7 @@ void InitFromJson(string json, getFBXNameFn getFBXName, ref int index)
464462
// it's the name of a component, and we store its value as a string.
465463
bool isChild = (name.Length > 0) && (name[0] == '-');
466464
if (isChild) {
467-
var subrep = new FbxRepresentation(json, getFBXName, ref index);
465+
var subrep = new FbxRepresentation(json, ref index);
468466
Add(ref m_children, name.Substring(1), subrep);
469467
//Add(ref m_children, getFBXName(name.Substring(1)), subrep);
470468
} else {
@@ -476,14 +474,14 @@ void InitFromJson(string json, getFBXNameFn getFBXName, ref int index)
476474
}
477475
}
478476

479-
public FbxRepresentation(string json, getFBXNameFn fn, ref int index) {
480-
InitFromJson(json, fn, ref index);
477+
public FbxRepresentation(string json, ref int index) {
478+
InitFromJson(json, ref index);
481479
}
482480

483-
public FbxRepresentation(string json, getFBXNameFn fn) {
481+
public FbxRepresentation(string json) {
484482
if (string.IsNullOrEmpty(json)) { return; }
485483
int index = 0;
486-
InitFromJson(json, fn, ref index);
484+
InitFromJson(json, ref index);
487485
}
488486

489487
void ToJsonHelper(System.Text.StringBuilder builder) {
@@ -589,7 +587,7 @@ public Data(FbxRepresentation fbxrep) {
589587
InitHelper(fbxrep, "");
590588
}
591589

592-
public Data(Transform xfo, getFBXNameFn fn) : this(new FbxRepresentation(xfo, getFBXName: fn)) {
590+
public Data(Transform xfo) : this(new FbxRepresentation(xfo)) {
593591
}
594592

595593
/// <summary>
@@ -797,14 +795,11 @@ void ClassifyReparenting()
797795

798796
var prefabParent = m_prefabData.GetParent(prefabNodeName);
799797
var oldParent = m_oldFbxData.GetParent(prefabNodeName);
798+
// The newFbxData contains the fbx name, so we get the parent from the matching prefabNodeName equivalent
800799
var newParent = m_newFbxData.GetParent(m_fbxPrefabUtility.getFBXObjectName(prefabNodeName));
801800

802-
// If it's a name mapping, don't add a reparenting, we'll rename it later
803-
if (oldParent == m_fbxPrefabUtility.getUnityObjectName(newParent)) {
804-
continue;
805-
}
806-
807-
if (oldParent != newParent && prefabParent != newParent) {
801+
// If it's a name mapping, don't add a reparenting, we'll rename it later in ImplementUpdates()
802+
if (oldParent != newParent && prefabParent != newParent && oldParent != m_fbxPrefabUtility.getUnityObjectName(newParent)) {
808803
// Conflict in this case:
809804
// if (oldParent != prefabParent && !ShouldDestroy(prefabParent))
810805

@@ -862,27 +857,28 @@ void ClassifyComponents(Transform newFbx, Transform prefab)
862857
// about what components might be on it.
863858
foreach (var nodeNameInUpdatedPrefab in m_nodesInUpdatedPrefab)
864859
{
865-
if (!m_newFbxData.HasNode(m_fbxPrefabUtility.getFBXObjectName(nodeNameInUpdatedPrefab))) {
860+
// Get the matching name for the node in the m_newFbxData
861+
string nodeNameInFBX = m_fbxPrefabUtility.getFBXObjectName(nodeNameInUpdatedPrefab);
862+
863+
// The newFbxData contains the fbx name, so we check if the node is in it with the matching equivalent
864+
if (!m_newFbxData.HasNode(nodeNameInFBX)) {
866865
// It's not in the FBX, so clearly we're not updating any components.
867866
// We don't need to check if it's in m_prefab because
868867
// we're only iterating over those.
869868
continue;
870869
}
871-
// Get the matching name for the node in the m_newFbxData
872-
string nodeNameInFBX = m_fbxPrefabUtility.getFBXObjectName(nodeNameInUpdatedPrefab);
873870

874871
var allTypes = m_oldFbxData.GetComponentTypes(nodeNameInUpdatedPrefab).Union(
875872
m_newFbxData.GetComponentTypes(nodeNameInFBX));
876-
873+
874+
//Compare oldValues that have prefab unity names with new values that have fbx names.
877875
foreach(var typename in allTypes) {
878876
var oldValues = m_oldFbxData.GetComponentValues(nodeNameInUpdatedPrefab, typename);
879877
var newValues = m_newFbxData.GetComponentValues(nodeNameInFBX, typename);
880878
List<string> prefabValues = null; // get them only if we need them.
881879

882880
// If we have multiple identical-type components, match them up by index.
883881
for(int i = 0, n = System.Math.Max(oldValues.Count, newValues.Count); i < n; ++i) {
884-
Log(oldValues[i]);
885-
Log(newValues[i]);
886882
if (/* isNew */ i < newValues.Count) {
887883
var newValue = newValues[i];
888884

@@ -936,8 +932,8 @@ public UpdateList(
936932
m_fbxPrefabUtility = new FbxPrefabUtility(m_fbxPrefab);
937933

938934
m_oldFbxData = new Data(oldFbx);
939-
m_newFbxData = new Data(newFbx, m_fbxPrefabUtility.getFBXObjectName);
940-
m_prefabData = new Data(prefab.transform, a => a);
935+
m_newFbxData = new Data(newFbx);
936+
m_prefabData = new Data(prefab.transform);
941937

942938
ClassifyDestroyCreateNodes();
943939
ClassifyReparenting();
@@ -1055,7 +1051,6 @@ public HashSet<GameObject> ImplementUpdates(FbxPrefab prefabInstance)
10551051
// Rename old nodes (unity names) into new nodes (FBX names).
10561052
foreach (var FBXNodeNameToRename in m_nodesToRename)
10571053
{
1058-
string test = prefabNodes[m_fbxPrefabUtility.getUnityObjectName(FBXNodeNameToRename)].name;
10591054
prefabNodes[m_fbxPrefabUtility.getUnityObjectName(FBXNodeNameToRename)].name = FBXNodeNameToRename;
10601055
Log("Renamed {0} into {1}", m_fbxPrefabUtility.getUnityObjectName(FBXNodeNameToRename), FBXNodeNameToRename);
10611056
}
@@ -1166,7 +1161,6 @@ void CompareAndUpdate()
11661161
if (!m_fbxPrefab.FbxModel) {
11671162
return;
11681163
}
1169-
FbxPrefabUtility m_fbxPrefabUtility = new FbxPrefabUtility(m_fbxPrefab);
11701164

11711165
// First write down what we want to do.
11721166
var updates = new UpdateList(GetFbxHistory(), m_fbxPrefab.FbxModel.transform, m_fbxPrefab);
@@ -1197,7 +1191,7 @@ void CompareAndUpdate()
11971191
FbxPrefab.CallOnUpdate (fbxPrefabInstance, updatedObjects);
11981192

11991193
// Update the representation of the history to match the new fbx.
1200-
var newFbxRep = new FbxRepresentation(m_fbxPrefab.FbxModel.transform, m_fbxPrefabUtility.getFBXObjectName);
1194+
var newFbxRep = new FbxRepresentation(m_fbxPrefab.FbxModel.transform);
12011195
var newFbxRepString = newFbxRep.ToJson();
12021196
fbxPrefabInstance.FbxHistory = newFbxRepString;
12031197

@@ -1230,7 +1224,7 @@ public string GetFbxAssetPath()
12301224
/// </summary>
12311225
public FbxRepresentation GetFbxHistory()
12321226
{
1233-
return new FbxRepresentation(m_fbxPrefab.FbxHistory, getFBXObjectName);
1227+
return new FbxRepresentation(m_fbxPrefab.FbxHistory);
12341228
}
12351229

12361230
/// <summary>
@@ -1263,7 +1257,6 @@ public void SetSourceModel(GameObject fbxModel) {
12631257
}
12641258

12651259
m_fbxPrefab.FbxModel = fbxModel;
1266-
FbxPrefabUtility m_fbxPrefabUtility = new FbxPrefabUtility(m_fbxPrefab);
12671260

12681261
// Case 0: fbxModel is null and we have no history
12691262
// => not normal data flow, but doing nothing is
@@ -1288,7 +1281,7 @@ public void SetSourceModel(GameObject fbxModel) {
12881281
// This is the first time we've seen the FBX file. Assume that
12891282
// it's the original FBX. Further assume that the user is happy
12901283
// with the prefab as it is now, so don't update it to match the FBX.
1291-
m_fbxPrefab.FbxHistory = new FbxRepresentation(m_fbxPrefab.FbxModel.transform, m_fbxPrefabUtility.getFBXObjectName).ToJson();
1284+
m_fbxPrefab.FbxHistory = new FbxRepresentation(m_fbxPrefab.FbxModel.transform).ToJson();
12921285
} else {
12931286
// Case 3.
12941287
// User wants to reconnect or change the connection.

Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,21 @@ protected virtual GameObject ExportSelection(params Object[] selected)
233233
return fbxRoot;
234234
}
235235

236-
/// <summary>
237-
/// Compares two hierarchies, asserts that they match precisely.
238-
/// The root can be allowed to mismatch. That's normal with
239-
/// GameObject.Instantiate.
240-
/// </summary>
241-
public static void AssertSameHierarchy (
236+
protected virtual string ExportSelectedObjects(string filename, params Object[] selected)
237+
{
238+
var fbxFileName = FbxExporters.Editor.ModelExporter.ExportObjects(filename, selected) as string;
239+
240+
return fbxFileName;
241+
}
242+
243+
244+
245+
/// <summary>
246+
/// Compares two hierarchies, asserts that they match precisely.
247+
/// The root can be allowed to mismatch. That's normal with
248+
/// GameObject.Instantiate.
249+
/// </summary>
250+
public static void AssertSameHierarchy (
242251
GameObject expectedHierarchy, GameObject actualHierarchy,
243252
bool ignoreRootName = false, bool ignoreRootTransform = false)
244253
{

Assets/FbxExporters/Editor/UnitTests/FbxPrefabAutoUpdaterTest.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,58 @@ public void ReplaceTest ()
146146
}
147147

148148
}
149+
150+
public class FbxPrefabAutoUpdaterRemappingTest : ExporterTestBase
151+
{
152+
[Test]
153+
public void RemappingTest()
154+
{
155+
//Create a hierarchy of objects
156+
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
157+
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
158+
sphere.transform.SetParent(cube.transform);
159+
GameObject cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
160+
cylinder.transform.SetParent(sphere.transform);
161+
162+
// Convert to linked prefab instance (auto-updating prefab)
163+
GameObject cubePrefabInstance = ConvertToModel.Convert(cube);
164+
Object cubePrefabParent = PrefabUtility.GetPrefabParent(cubePrefabInstance);
165+
166+
// In FbxPrefab Component of Cube, add SphereFBX/Sphere name mapping
167+
FbxPrefab fbxPrefabScript = cubePrefabInstance.transform.GetComponent<FbxPrefab>();
168+
FbxPrefab.StringPair stringpair = new FbxPrefab.StringPair();
169+
stringpair.FBXObjectName = "SphereFBX";
170+
stringpair.UnityObjectName = "Sphere";
171+
fbxPrefabScript.NameMapping.Add(stringpair);
172+
PrefabUtility.ReplacePrefab(cubePrefabInstance, cubePrefabParent);
173+
string cubePrefabInstancePath = AssetDatabase.GetAssetPath(cubePrefabInstance);
174+
175+
//Create second FBX
176+
GameObject cube2 = GameObject.CreatePrimitive(PrimitiveType.Cube);
177+
GameObject sphere2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
178+
// Change name of Sphere to SphereFBX
179+
sphere2.transform.name = "SphereFBX";
180+
sphere2.transform.SetParent(cube2.transform);
181+
GameObject cylinder2 = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
182+
cylinder2.transform.SetParent(sphere2.transform);
183+
184+
//export our updated hierarchy to the same file path as the original
185+
SleepForFileTimestamp();
186+
// "Import" model to Unity (Exporting modified FBX to Unity to see if the remapping works)
187+
string fbxFileName = ExportSelectedObjects(Application.dataPath + "/Cube.fbx", cube2);
188+
AssetDatabase.Refresh();
189+
190+
// Assert Check Sphere = SphereFBX
191+
Assert.IsTrue(cubePrefabInstance != null);
192+
Assert.IsTrue(cubePrefabInstance.GetComponent<MeshFilter>().sharedMesh != null);
193+
Assert.IsTrue(cubePrefabInstance.transform.GetChild(0).name == "SphereFBX");
194+
Assert.IsTrue(cubePrefabInstance.transform.GetChild(0).GetComponent<MeshFilter>().sharedMesh != null);
195+
196+
// Destroy the objects
197+
GameObject.DestroyImmediate(cubePrefabInstance);
198+
//GameObject.DestroyImmediate(cube2);
199+
}
200+
}
149201
}
150202

151203
namespace FbxExporters.PerformanceTests {

Assets/FbxExporters/Editor/UnitTests/FbxPrefabTest.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ public class FbxPrefabTest : ExporterTestBase
1919
GameObject m_autoPrefab; // prefab that auto-updates
2020
GameObject m_manualPrefab; // prefab that doesn't auto-update
2121

22-
FbxPrefabAutoUpdater.FbxPrefabUtility m_fbxPrefabUtility;
23-
2422
class UpdateListener : System.IDisposable
2523
{
2624
public List<string> Updated { get ; private set; }
@@ -165,11 +163,10 @@ public void Init() {
165163
{
166164
var prefabInstance = GameObject.Instantiate(m_original);
167165
var fbxPrefab = prefabInstance.AddComponent<FbxPrefab>();
168-
//var fbxPrefabUtility = new FbxPrefabAutoUpdater.FbxPrefabUtility (fbxPrefab);
169-
m_fbxPrefabUtility = new FbxPrefabAutoUpdater.FbxPrefabUtility(fbxPrefab);
166+
var fbxPrefabUtility = new FbxPrefabAutoUpdater.FbxPrefabUtility (fbxPrefab);
170167

171-
m_fbxPrefabUtility.SetSourceModel(m_source);
172-
m_fbxPrefabUtility.SetAutoUpdate(true);
168+
fbxPrefabUtility.SetSourceModel(m_source);
169+
fbxPrefabUtility.SetAutoUpdate(true);
173170
m_autoPrefab = PrefabUtility.CreatePrefab(
174171
GetRandomPrefabAssetPath(),
175172
prefabInstance);
@@ -189,7 +186,7 @@ public void Init() {
189186
}
190187

191188
FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation Rep(GameObject go) {
192-
return new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(go.transform, m_fbxPrefabUtility.getFBXObjectName);
189+
return new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(go.transform);
193190
}
194191

195192
FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation History(GameObject go) {
@@ -689,17 +686,12 @@ public void TestFbxRepresentation()
689686
b.transform.localPosition = new Vector3(1,2,3);
690687
b.AddComponent<BoxCollider>();
691688

692-
// Empty Prefab but we only want to give the function
693-
var c = new GameObject("c");
694-
var fbxPrefab = c.AddComponent<FbxPrefab>();
695-
var fbxPrefabUtility = new FbxPrefabAutoUpdater.FbxPrefabUtility(fbxPrefab);
696-
697-
var repA = new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(a.transform, fbxPrefabUtility.getFBXObjectName);
689+
var repA = new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(a.transform);
698690
TestFbxRepresentationMatches(repA);
699691

700692
// Test that we can round-trip through a string.
701693
var json = repA.ToJson();
702-
var repAstring = new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(json, fbxPrefabUtility.getFBXObjectName);
694+
var repAstring = new FbxPrefabAutoUpdater.FbxPrefabUtility.FbxRepresentation(json);
703695
TestFbxRepresentationMatches(repAstring);
704696
}
705697
}

0 commit comments

Comments
 (0)