@@ -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,6 +871,7 @@ public void ImplementUpdates(FbxPrefab prefabInstance)
856
871
UnityEditor . EditorJsonUtility . FromJsonOverwrite ( fbxComponent . jsonValue , prefabComponent ) ;
857
872
}
858
873
}
874
+ return updatedNodes ;
859
875
}
860
876
}
861
877
@@ -903,14 +919,20 @@ void CompareAndUpdate()
903
919
throw new System . Exception ( string . Format ( "Failed to instantiate {0}; is it really a prefab?" ,
904
920
this . gameObject ) ) ;
905
921
}
906
- var fbxPrefab = prefabInstance . GetComponent < FbxPrefab > ( ) ;
922
+ var fbxPrefabInstance = prefabInstance . GetComponent < FbxPrefab > ( ) ;
907
923
908
- updates . ImplementUpdates ( fbxPrefab ) ;
924
+ // Do ALL the things!
925
+ var updatedObjects = updates . ImplementUpdates ( fbxPrefabInstance ) ;
926
+
927
+ // Tell listeners about it. They're free to make adjustments now.
928
+ if ( OnUpdate != null ) {
929
+ OnUpdate ( fbxPrefabInstance , updatedObjects ) ;
930
+ }
909
931
910
932
// Update the representation of the history to match the new fbx.
911
933
var newFbxRep = new FbxRepresentation ( m_fbxModel . transform ) ;
912
934
var newFbxRepString = newFbxRep . ToJson ( ) ;
913
- fbxPrefab . m_fbxHistory = newFbxRepString ;
935
+ fbxPrefabInstance . m_fbxHistory = newFbxRepString ;
914
936
915
937
// Save the changes back to the prefab.
916
938
UnityEditor . PrefabUtility . ReplacePrefab ( prefabInstance , this . transform ) ;
@@ -1006,6 +1028,33 @@ public void SetSourceModel(GameObject fbxModel) {
1006
1028
CompareAndUpdate ( ) ;
1007
1029
}
1008
1030
}
1031
+
1032
+ //////////////////////////////////////////////////////////////////////////
1033
+ // Event handling for updates.
1034
+
1035
+ /// <summary>
1036
+ /// Handler for an OnUpdate event.
1037
+ ///
1038
+ /// The update is performed on a temporary instance, which, shortly after
1039
+ /// this handler is invoked, will be applied to the prefab.
1040
+ ///
1041
+ /// The event handler can make changes to any objects in the hierarchy rooted
1042
+ /// by the updatedInstance. Those changes will be applied to the prefab.
1043
+ ///
1044
+ /// The updatedObjects include all objects in the temporary instance
1045
+ /// that were:
1046
+ /// - created, or
1047
+ /// - changed parent, or
1048
+ /// - had a component that was created, destroyed, or updated.
1049
+ /// There is no notification for entire objects that were destroyed.
1050
+ /// </summary>
1051
+ public delegate void HandleUpdate ( FbxPrefab updatedInstance , IEnumerable < GameObject > updatedObjects ) ;
1052
+
1053
+ /// <summary>
1054
+ /// OnUpdate is raised once when an FbxPrefab gets updated, after all the changes
1055
+ /// have been done.
1056
+ /// </summary>
1057
+ public static event HandleUpdate OnUpdate ;
1009
1058
#endif
1010
1059
}
1011
1060
}
0 commit comments