using Pathfinding.Serialization; using UnityEngine; namespace Pathfinding { /// Exposes internal methods from public interface IVersionedMonoBehaviourInternal { void UpgradeFromUnityThread(); } namespace Util { /// Used by Pathfinding.Util.BatchedEvents public interface IEntityIndex { int EntityIndex { get; set; } } } /// Base class for all components in the package public abstract class VersionedMonoBehaviour : #if MODULE_BURST && MODULE_MATHEMATICS && MODULE_COLLECTIONS Drawing.MonoBehaviourGizmos #else MonoBehaviour #endif , ISerializationCallbackReceiver, IVersionedMonoBehaviourInternal, Util.IEntityIndex { /// Version of the serialized data. Used for script upgrades. [SerializeField] [HideInInspector] int version = 0; /// Internal entity index used by . Should never be modified by other scripts. int Util.IEntityIndex.EntityIndex { get; set; } protected virtual void Awake () { // Make sure the version field is up to date for components created during runtime. // Reset is not called when in play mode. // If the data had to be upgraded then OnAfterDeserialize would have been called earlier. if (Application.isPlaying) { if (version == 0) { // If version==0 then the component was created during runtime and has not been serialized previously. // We can mark all available migrations as finished. var m = new Migrations(int.MaxValue); OnUpgradeSerializedData(ref m, true); version = m.allMigrations; } else { // If version!=0 then the component may have to run migrations. (this as IVersionedMonoBehaviourInternal).UpgradeFromUnityThread(); } } } /// Handle serialization backwards compatibility protected virtual void Reset () { // Set initial version when adding the component for the first time var m = new Migrations(int.MaxValue); OnUpgradeSerializedData(ref m, true); version = m.allMigrations; DisableGizmosIcon(); } void DisableGizmosIcon () { #if UNITY_EDITOR && UNITY_2022_1_OR_NEWER // Disable the icon in the scene view by default for all scripts. // There's no way to set the actual default, so we have to do this instead. // We store the list of scripts that have been reset in the editor prefs, for each project. // Unity stores its gizmo preferences in the Library folder. So it will be per-user and per-project. // We won't be able to detect if the user deletes and then rebuilds their library folder, though. // Note: Unity may return false for TryGetGizmoInfo the first time it is called for a script. // But the second time a user adds a component (and thus resets it), this should work. if (UnityEditor.GizmoUtility.TryGetGizmoInfo(GetType(), out var gizmoInfo) && gizmoInfo.hasIcon) { var resetPaths = UnityEditor.EditorPrefs.GetString("AstarPathfindingProject.HasResetShowIconGizmos", ""); var splits = resetPaths.Split(','); var id = Application.productName.Replace(",", ";") + ":" + GetType().Name; if (System.Array.IndexOf(splits, id) == -1) { resetPaths += "," + id; UnityEditor.GizmoUtility.SetIconEnabled(GetType(), false); UnityEditor.EditorPrefs.SetString("AstarPathfindingProject.HasResetShowIconGizmos", resetPaths); } } #endif } /// Handle serialization backwards compatibility void ISerializationCallbackReceiver.OnBeforeSerialize () { } /// Handle serialization backwards compatibility void ISerializationCallbackReceiver.OnAfterDeserialize() => UpgradeSerializedData(false); protected void UpgradeSerializedData (bool isUnityThread) { var m = new Migrations(version); OnUpgradeSerializedData(ref m, isUnityThread); if (m.ignore) return; if (m.IsLegacyFormat) throw new System.Exception("Failed to migrate from the legacy format"); if ((m.finishedMigrations & ~m.allMigrations) != 0) throw new System.Exception("Run more migrations than there are migrations to run. Finished: " + m.finishedMigrations.ToString("X") + " all: " + m.allMigrations.ToString("X")); if (isUnityThread && ((m.allMigrations & ~m.finishedMigrations) != 0)) throw new System.Exception("Some migrations were registered, but they did not run. Finished: " + m.finishedMigrations.ToString("X") + " all: " + m.allMigrations.ToString("X")); this.version = m.finishedMigrations; } /// Handle serialization backwards compatibility protected virtual void OnUpgradeSerializedData (ref Migrations migrations, bool unityThread) { if (migrations.TryMigrateFromLegacyFormat(out var legacyVersion)) { if (legacyVersion > 1) throw new System.Exception("Reached base class without having migrated the legacy format, and the legacy version is not version 1."); } } void IVersionedMonoBehaviourInternal.UpgradeFromUnityThread() => UpgradeSerializedData(true); } }