Cesium for Unity 1.15.2
Loading...
Searching...
No Matches
CesiumBackwardCompatibility.cs
Go to the documentation of this file.
1using UnityEngine;
2using System;
3using System.Collections.Generic;
4using UnityEngine.SceneManagement;
5
6#if UNITY_EDITOR
7using UnityEditor;
8using UnityEditorInternal;
9#endif
10
11namespace CesiumForUnity
12{
13 public interface IBackwardCompatibilityComponent<TNew>
14 {
15 public string VersionToBeUpgraded { get; }
16 public void Upgrade(GameObject gameObject, TNew newComponent);
17 }
18
19 public static class CesiumBackwardCompatibility<TNew>
20 where TNew : MonoBehaviour
21 {
22#if UNITY_EDITOR
23 private static Dictionary<MonoBehaviour, MonoBehaviour> _instanceMap = null;
24
25 public static TNew Upgrade<TOld>(TOld oldComponent)
26 where TOld : MonoBehaviour, IBackwardCompatibilityComponent<TNew>
27 {
28 GameObject go = oldComponent.gameObject;
29
30 Debug.Log("Upgrading " + typeof(TNew).Name + " on game object \"" + go.name + "\" from Cesium for Unity " + oldComponent.VersionToBeUpgraded + ".");
31
32 TNew newComponent = go.AddComponent<TNew>();
33
34 try
35 {
36 oldComponent.Upgrade(go, newComponent);
37
38 if (_instanceMap == null)
39 {
40 _instanceMap = new Dictionary<MonoBehaviour, MonoBehaviour>();
41 EditorApplication.update += UpdateScene;
42 }
43
44 _instanceMap.Add(oldComponent, newComponent);
45 }
46 catch (Exception e)
47 {
48 Debug.LogError("Upgrading failed with an exception: " + e.ToString());
49 }
50
51 return newComponent;
52 }
53
54 private static void UpdateScene()
55 {
56 // Search all scenes for instances of the old object (dictionary key), and replace it
57 // with the new object (dictionary value).
58 for (int i = 0; i < SceneManager.sceneCount; ++i)
59 {
60 Scene scene = SceneManager.GetSceneAt(i);
61 ReplaceReferencesInScene(scene);
62 }
63
64 foreach (var kvp in _instanceMap)
65 {
66 MonoBehaviour oldComponent = kvp.Key;
67 MonoBehaviour newComponent = kvp.Value;
68 GameObject go = newComponent.gameObject;
69
70 // Unity seems to ignore SetDirty from within OnEnable, so we do it here.
71 EditorUtility.SetDirty(go);
72
73 // Destroy the old component and move the new one where the old
74 // one used to be.
75 Component[] components = go.GetComponents<Component>();
76 int indexOfOriginal = Array.IndexOf(components, oldComponent);
77 int indexOfUpgraded = Array.IndexOf(components, newComponent);
78
79 UnityEngine.Object.DestroyImmediate(oldComponent, true);
80
81 if (indexOfOriginal >= 0 && indexOfUpgraded >= 0)
82 {
83 if (indexOfUpgraded > indexOfOriginal)
84 --indexOfUpgraded;
85 while (indexOfUpgraded > indexOfOriginal)
86 {
87 ComponentUtility.MoveComponentUp(newComponent);
88 --indexOfUpgraded;
89 }
90 }
91
92 }
93
94 _instanceMap = null;
95 EditorApplication.update -= UpdateScene;
96 }
97
98 private static void ReplaceReferencesInScene(Scene scene)
99 {
100 GameObject[] gameObjects = scene.GetRootGameObjects();
101 foreach (GameObject go in gameObjects)
102 {
103 ReplaceReferencesInGameObject(go);
104 }
105 }
106
107 private static List<Component> _componentList = new List<Component>();
108
109 private static void ReplaceReferencesInGameObject(GameObject go)
110 {
111 go.GetComponents<Component>(_componentList);
112 foreach (Component component in _componentList)
113 {
114 // Skip the components that are about to be removed.
115 if (component is MonoBehaviour m && _instanceMap.ContainsKey(m))
116 continue;
117
118 ReplaceReferencesInComponent(component);
119 }
120
121 Transform transform = go.transform;
122 for (int i = 0; i < transform.childCount; ++i)
123 {
124 Transform childTransform = transform.GetChild(i);
125 ReplaceReferencesInGameObject(childTransform.gameObject);
126 }
127 }
128
129 private static void ReplaceReferencesInComponent(Component component)
130 {
131 SerializedObject so = new SerializedObject(component);
132 SerializedProperty property = so.GetIterator();
133 while (property.NextVisible(true))
134 {
135 if (property.propertyType == SerializedPropertyType.ExposedReference)
136 {
137 UnityEngine.Object value = property.exposedReferenceValue;
138
139 MonoBehaviour replacement;
140 if (value is MonoBehaviour m && _instanceMap.TryGetValue(m, out replacement))
141 {
142 Debug.Log("Updating property " + property.propertyPath + " with upgraded component.");
143 property.exposedReferenceValue = replacement;
144 }
145 }
146 else if (property.propertyType == SerializedPropertyType.ObjectReference)
147 {
148 UnityEngine.Object value = property.objectReferenceValue;
149
150 MonoBehaviour replacement;
151 if (value is MonoBehaviour m && _instanceMap.TryGetValue(m, out replacement))
152 {
153 Debug.Log("Updating property \"" + property.propertyPath + "\" on component \"" + component.name + "\" with upgraded component.");
154 property.objectReferenceValue = replacement;
155 }
156 }
157 }
158 so.ApplyModifiedProperties();
159 }
160
161#endif
162 }
163}
void Upgrade(GameObject gameObject, TNew newComponent)