@@ -603,11 +603,7 @@ void ClassifyReparenting()
603
603
continue ;
604
604
}
605
605
if ( m_nodesToDestroy . Contains ( name ) ) {
606
- // Reparent to the root. This is to avoid the nuisance of
607
- // trying to destroy objects that are already destroyed
608
- // because a parent got there first. Maybe there's a
609
- // faster way to do it, but performance seems OK.
610
- m_reparentings . Add ( name , "" ) ;
606
+ // Don't bother reparenting, we'll be destroying this anyway.
611
607
continue ;
612
608
}
613
609
@@ -754,17 +750,23 @@ public bool NeedsUpdates() {
754
750
/// 1. Create all the new nodes we need to create.
755
751
/// 2. Reparent as needed.
756
752
/// 3. Delete the nodes that are no longer needed.
757
- /// todo 4. Update the components:
753
+ /// 4. Update the components:
758
754
/// 4a. delete components no longer used
759
755
/// 4b. create new components
760
756
/// 4c. update component values
761
757
/// (A) and (B) are largely about meshfilter/meshrenderer,
762
758
/// (C) is about transforms (and materials?)
759
+ ///
760
+ /// Return the set of GameObject that were created or reparented
761
+ /// in 1 and 2; or that were updated in 4. Does not return the destroyed
762
+ /// GameObjects -- they've been destroyed!
763
763
/// </summary>
764
- public void ImplementUpdates ( FbxPrefab prefabInstance )
764
+ public HashSet < GameObject > ImplementUpdates ( FbxPrefab prefabInstance )
765
765
{
766
766
Log ( "{0}: performing updates" , prefabInstance . name ) ;
767
767
768
+ var updatedNodes = new HashSet < GameObject > ( ) ;
769
+
768
770
// Gather up all the nodes in the prefab so we can look up
769
771
// nodes. We use the empty string for the root node.
770
772
var prefabRoot = prefabInstance . transform ;
@@ -779,8 +781,11 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
779
781
780
782
// Create new nodes.
781
783
foreach ( var name in m_nodesToCreate ) {
782
- prefabNodes . Add ( name , new GameObject ( name ) . transform ) ;
784
+ var newNode = new GameObject ( name ) ;
785
+ prefabNodes . Add ( name , newNode . transform ) ;
786
+
783
787
Log ( "{0}: created new GameObject" , name ) ;
788
+ updatedNodes . Add ( newNode ) ;
784
789
}
785
790
786
791
// Implement the reparenting in two phases to avoid making loops, e.g.
@@ -803,14 +808,22 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
803
808
} else {
804
809
parentNode = prefabNodes [ parent ] ;
805
810
}
806
- prefabNodes [ name ] . parent = parentNode ;
811
+ var childNode = prefabNodes [ name ] ;
812
+ childNode . parent = parentNode ;
813
+
807
814
Log ( "changed {0} parent to {1}" , name , parentNode . name ) ;
815
+ updatedNodes . Add ( childNode . gameObject ) ;
808
816
}
809
817
810
- // Destroy the old nodes.
811
- foreach ( var toDestroy in m_nodesToDestroy ) {
812
- GameObject . DestroyImmediate ( prefabNodes [ toDestroy ] . gameObject ) ;
813
- Log ( "destroyed {0}" , toDestroy ) ;
818
+ // Destroy the old nodes. Remember that DestroyImmediate recursively
819
+ // destroys, so avoid errors.
820
+ foreach ( var nameToDestroy in m_nodesToDestroy ) {
821
+ var xfoToDestroy = prefabNodes [ nameToDestroy ] ;
822
+ if ( xfoToDestroy ) {
823
+ GameObject . DestroyImmediate ( xfoToDestroy . gameObject ) ;
824
+ }
825
+ Log ( "destroyed {0}" , nameToDestroy ) ;
826
+ prefabNodes . Remove ( nameToDestroy ) ;
814
827
}
815
828
816
829
// Destroy the old components.
@@ -819,6 +832,7 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
819
832
var nodeName = kvp . Key ;
820
833
var typesToDestroy = kvp . Value ;
821
834
var prefabXfo = prefabNodes [ nodeName ] ;
835
+ updatedNodes . Add ( prefabXfo . gameObject ) ;
822
836
823
837
foreach ( var componentType in typesToDestroy ) {
824
838
var component = prefabXfo . GetComponent ( componentType ) ;
@@ -834,6 +848,7 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
834
848
var nodeName = kvp . Key ;
835
849
var fbxComponents = kvp . Value ;
836
850
var prefabXfo = prefabNodes [ nodeName ] ;
851
+ updatedNodes . Add ( prefabXfo . gameObject ) ;
837
852
838
853
// Copy the components once so we can match them up even if there's multiple fbxComponents.
839
854
List < Component > prefabComponents = new List < Component > ( prefabXfo . GetComponents < Component > ( ) ) ;
@@ -856,7 +871,9 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
856
871
UnityEditor . EditorJsonUtility . FromJsonOverwrite ( fbxComponent . jsonValue , prefabComponent ) ;
857
872
}
858
873
}
874
+ return updatedNodes ;
859
875
}
876
+
860
877
}
861
878
862
879
/// <summary>
@@ -903,14 +920,20 @@ void CompareAndUpdate()
903
920
throw new System . Exception ( string . Format ( "Failed to instantiate {0}; is it really a prefab?" ,
904
921
this . gameObject ) ) ;
905
922
}
906
- var fbxPrefab = prefabInstance . GetComponent < FbxPrefab > ( ) ;
923
+ var fbxPrefabInstance = prefabInstance . GetComponent < FbxPrefab > ( ) ;
924
+
925
+ // Do ALL the things!
926
+ var updatedObjects = updates . ImplementUpdates ( fbxPrefabInstance ) ;
907
927
908
- updates . ImplementUpdates ( fbxPrefab ) ;
928
+ // Tell listeners about it. They're free to make adjustments now.
929
+ if ( OnUpdate != null ) {
930
+ OnUpdate ( fbxPrefabInstance , updatedObjects ) ;
931
+ }
909
932
910
933
// Update the representation of the history to match the new fbx.
911
934
var newFbxRep = new FbxRepresentation ( m_fbxModel . transform ) ;
912
935
var newFbxRepString = newFbxRep . ToJson ( ) ;
913
- fbxPrefab . m_fbxHistory = newFbxRepString ;
936
+ fbxPrefabInstance . m_fbxHistory = newFbxRepString ;
914
937
915
938
// Save the changes back to the prefab.
916
939
UnityEditor . PrefabUtility . ReplacePrefab ( prefabInstance , this . transform ) ;
@@ -1006,6 +1029,31 @@ public void SetSourceModel(GameObject fbxModel) {
1006
1029
CompareAndUpdate ( ) ;
1007
1030
}
1008
1031
}
1032
+
1033
+ //////////////////////////////////////////////////////////////////////////
1034
+ // Event handling for updates.
1035
+
1036
+ /// <summary>
1037
+ /// Handler for an OnUpdate event.
1038
+ ///
1039
+ /// The update is performed on a temporary instance, which, shortly after
1040
+ /// this handler is invoked, will be applied to the prefab.
1041
+ ///
1042
+ /// The event handler can make changes to any objects in the hierarchy rooted
1043
+ /// by the updatedInstance. Those changes will be applied to the prefab.
1044
+ ///
1045
+ /// The updatedObjects include all objects in the temporary instance
1046
+ /// that were created, plus all objects which had a component get
1047
+ /// created, destroyed, or updated. You get notification for objects
1048
+ /// that were destroyed.
1049
+ /// </summary>
1050
+ public delegate void HandleUpdate ( FbxPrefab updatedInstance , IEnumerable < GameObject > updatedObjects ) ;
1051
+
1052
+ /// <summary>
1053
+ /// OnUpdate is raised once when an FbxPrefab gets updated, after all the changes
1054
+ /// have been done.
1055
+ /// </summary>
1056
+ public static event HandleUpdate OnUpdate ;
1009
1057
#endif
1010
1058
}
1011
1059
}
0 commit comments