428 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			428 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| #if UNITY_EDITOR
 | |
| #if MIRROR
 | |
| using UnityEditor;
 | |
| using UnityEngine;
 | |
| using FishNet.Object;
 | |
| using FishNet.Documenting;
 | |
| using System.Collections.Generic;
 | |
| using FNNetworkTransform = FishNet.Component.Transforming.NetworkTransform;
 | |
| using FNNetworkAnimator = FishNet.Component.Animating.NetworkAnimator;
 | |
| using FNNetworkObserver = FishNet.Observing.NetworkObserver;
 | |
| using FishNet.Observing;
 | |
| using FishNet.Component.Observing;
 | |
| using FishNet.Editing;
 | |
| using System.IO;
 | |
| using System.Collections;
 | |
| using Mirror;
 | |
| using MirrorNetworkTransformBase = Mirror.NetworkTransformBase;
 | |
| using MirrorNetworkTransformChild = Mirror.NetworkTransformChild;
 | |
| using MirrorNetworkAnimator = Mirror.NetworkAnimator;
 | |
| #if !MIRROR_57_0_OR_NEWER
 | |
| using MirrorNetworkProximityChecker = Mirror.NetworkProximityChecker;
 | |
| using MirrorNetworkSceneChecker = Mirror.NetworkSceneChecker;
 | |
| #endif
 | |
| 
 | |
| #if FGG_ASSETS
 | |
| using FlexNetworkAnimator = FirstGearGames.Mirrors.Assets.FlexNetworkAnimators.FlexNetworkAnimator;
 | |
| using FlexNetworkTransformBase = FirstGearGames.Mirrors.Assets.FlexNetworkTransforms.FlexNetworkTransformBase;
 | |
| using FastProximityChecker = FirstGearGames.Mirrors.Assets.NetworkProximities.FastProximityChecker;
 | |
| #endif
 | |
| 
 | |
| #if FGG_PROJECTS
 | |
| using FlexSceneChecker = FirstGearGames.FlexSceneManager.FlexSceneChecker;
 | |
| #endif
 | |
| 
 | |
| namespace FishNet.Upgrading.Mirror.Editing
 | |
| {
 | |
| 
 | |
|     /* IMPORTANT IMPORTANT IMPORTANT IMPORTANT 
 | |
|     * If you receive errors about missing Mirror components,
 | |
|     * such as NetworkIdentity, then remove MIRROR and any other
 | |
|     * MIRROR defines.
 | |
|     * Project Settings -> Player -> Other -> Scripting Define Symbols.
 | |
|     * 
 | |
|     * If you are also using my assets add FGG_ASSETS to the defines, and
 | |
|     * then remove it after running this script. */
 | |
|     [APIExclude]
 | |
|     [ExecuteInEditMode]
 | |
|     [InitializeOnLoad]
 | |
|     public class MirrorUpgrade : MonoBehaviour
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// SceneCondition within FishNet.
 | |
|         /// </summary>
 | |
|         private SceneCondition _sceneCondition = null;
 | |
|         /// <summary>
 | |
|         /// DistanceCondition created for the user.
 | |
|         /// </summary>
 | |
|         private DistanceCondition _distanceCondition = null;
 | |
|         /// <summary>
 | |
|         /// 
 | |
|         /// </summary>
 | |
|         private int _replacedNetworkTransforms;
 | |
|         /// <summary>
 | |
|         /// 
 | |
|         /// </summary>
 | |
|         private int _replacedNetworkAnimators;
 | |
|         /// <summary>
 | |
|         /// 
 | |
|         /// </summary>
 | |
|         private int _replacedNetworkIdentities;
 | |
|         /// <summary>
 | |
|         /// 
 | |
|         /// </summary>
 | |
|         private int _replacedSceneCheckers;
 | |
|         /// <summary>
 | |
|         /// 
 | |
|         /// </summary>
 | |
|         private int _replacedProximityCheckers;
 | |
|         /// <summary>
 | |
|         /// True if anything was changed.
 | |
|         /// </summary>
 | |
|         private bool _changed;
 | |
|         /// <summary>
 | |
|         /// Index in gameObjects to iterate.
 | |
|         /// </summary>
 | |
|         private int _goIndex = -1;
 | |
|         /// <summary>
 | |
|         /// Found gameObjects to iterate.
 | |
|         /// </summary>
 | |
|         private List<GameObject> _gameObjects = new List<GameObject>();
 | |
|         /// <summary>
 | |
|         /// True if initialized.
 | |
|         /// </summary>
 | |
|         private bool _initialized;
 | |
| 
 | |
| 
 | |
|         private const string OBJECT_NAME_PREFIX = "MirrorUpgrade";
 | |
| 
 | |
| 
 | |
|         private void Awake()
 | |
|         {
 | |
|             gameObject.name = OBJECT_NAME_PREFIX;
 | |
|             Debug.Log($"{gameObject.name} is working. Please wait until this object is removed from your hierarchy.");
 | |
|             EditorApplication.update += EditorUpdate;
 | |
|         }
 | |
| 
 | |
|         private void OnDestroy()
 | |
|         {
 | |
|             EditorApplication.update -= EditorUpdate;
 | |
|         }
 | |
| 
 | |
|         private void EditorUpdate()
 | |
|         {
 | |
|             if (!_initialized)
 | |
|             {
 | |
|                 FindConditions(true);
 | |
|                 _gameObjects = Finding.GetGameObjects(true, false, true, new string[] { "/Mirror/" });
 | |
|                 _goIndex = 0;
 | |
|                 _initialized = true;
 | |
|             }
 | |
| 
 | |
|             if (_goIndex == -1)
 | |
|                 return;
 | |
|             if (_goIndex >= _gameObjects.Count)
 | |
|             {
 | |
|                 gameObject.name = $"{OBJECT_NAME_PREFIX} - 100%";
 | |
|                 Debug.Log($"Switched {_replacedNetworkTransforms} NetworkTransforms.");
 | |
|                 Debug.Log($"Switched {_replacedNetworkAnimators} NetworkAnimators.");
 | |
|                 Debug.Log($"Switched {_replacedSceneCheckers} SceneCheckers.");
 | |
|                 Debug.Log($"Switched {_replacedProximityCheckers} ProximityCheckers.");
 | |
|                 Debug.Log($"Switched {_replacedNetworkIdentities} NetworkIdentities.");
 | |
| 
 | |
|                 if (_changed)
 | |
|                     PrintSaveWarning();
 | |
| 
 | |
|                 DestroyImmediate(gameObject);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             float percentFloat = ((float)_goIndex / (float)_gameObjects.Count) * 100f;
 | |
|             int percentInt = Mathf.FloorToInt(percentFloat);
 | |
|             gameObject.name = $"{OBJECT_NAME_PREFIX} - {percentInt}%";
 | |
| 
 | |
|             GameObject go = _gameObjects[_goIndex];
 | |
|             _goIndex++;
 | |
|             //Go went empty?
 | |
|             if (go == null)
 | |
|                 return;
 | |
| 
 | |
|             /* When a component is removed
 | |
|              * changed is set true and remove count is increased.
 | |
|              * _goIndex is also returned before exiting the method.
 | |
|              * This will cause the same gameObject to iterate
 | |
|              * next update. This is important because the components
 | |
|              * must be Switched in order, and I can only remove one
 | |
|              * component per frame without Unity throwing a fit and
 | |
|              * freezing. A while loop doesn't let Unity recognize the component
 | |
|              * is gone(weird right? maybe editor thing), and a coroutine
 | |
|              * doesn't show errors well, they just fail silently. */
 | |
| 
 | |
|             bool changedThisFrame = false;
 | |
|             if (IterateNetworkTransform(go))
 | |
|             {
 | |
|                 changedThisFrame = true;
 | |
|                 _changed = true;
 | |
|                 _replacedNetworkTransforms++;
 | |
|             }
 | |
|             if (IterateNetworkAnimator(go))
 | |
|             {
 | |
|                 changedThisFrame = true;
 | |
|                 _changed = true;
 | |
|                 _replacedNetworkAnimators++;
 | |
|             }
 | |
| 
 | |
|             if (IterateSceneChecker(go))
 | |
|             {
 | |
|                 changedThisFrame = true;
 | |
|                 _changed = true;
 | |
|                 _replacedSceneCheckers++;
 | |
|             }
 | |
|             if (IterateProximityChecker(go))
 | |
|             {
 | |
|                 changedThisFrame = true;
 | |
|                 _changed = true;
 | |
|                 _replacedProximityCheckers++;
 | |
|             }
 | |
|             if (changedThisFrame)
 | |
|             {
 | |
|                 _goIndex--;
 | |
|                 return;
 | |
|             }
 | |
|             //NetworkIdentity must be done last.
 | |
|             if (IterateNetworkIdentity(go))
 | |
|             {
 | |
|                 _changed = true;
 | |
|                 _replacedNetworkIdentities++;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Finds Condition scripts to be used with NetworkObserver.
 | |
|         /// </summary>
 | |
|         /// <param name="error"></param>
 | |
|         private void FindConditions(bool error)
 | |
|         {
 | |
|             List<UnityEngine.Object> scriptableObjects;
 | |
| 
 | |
|             if (_sceneCondition == null)
 | |
|             {
 | |
|                 scriptableObjects = Finding.GetScriptableObjects<SceneCondition>(true, true);
 | |
|                 //Use the first found scene condition, there should be only one.
 | |
|                 if (scriptableObjects.Count > 0)
 | |
|                     _sceneCondition = (SceneCondition)scriptableObjects[0];
 | |
| 
 | |
|                 if (_sceneCondition == null && error)
 | |
|                     Debug.LogError("SceneCondition could not be found. Upgrading scene checker components will not function.");
 | |
|             }
 | |
| 
 | |
|             if (_distanceCondition == null)
 | |
|             {
 | |
|                 scriptableObjects = Finding.GetScriptableObjects<DistanceCondition>(false, true);
 | |
|                 if (scriptableObjects.Count > 0)
 | |
|                 {
 | |
|                     _distanceCondition = (DistanceCondition)scriptableObjects[0];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     DistanceCondition dc = ScriptableObject.CreateInstance<DistanceCondition>();
 | |
|                     string savePath = "Assets";
 | |
|                     AssetDatabase.CreateAsset(dc, Path.Combine(savePath, $"CreatedDistanceCondition.asset"));
 | |
|                     Debug.LogWarning($"DistanceCondition has been created at {savePath}. Place this file somewhere within your project and change settings to your liking.");
 | |
|                 }
 | |
| 
 | |
|                 if (_distanceCondition == null && error)
 | |
|                     Debug.LogError("DistanceCondition could not be found. Upgrading proximity checker components will not function.");
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         private bool IterateNetworkTransform(GameObject go)
 | |
|         {
 | |
|             if (go.TryGetComponent(out MirrorNetworkTransformBase nt1))
 | |
|             {
 | |
|                 Transform target;
 | |
|                 if (nt1 is MirrorNetworkTransformChild mc1)
 | |
|                     target = mc1.target;
 | |
|                 else
 | |
|                     target = go.transform;
 | |
|                 Replace(nt1, target);
 | |
|                 return true;
 | |
|             }
 | |
| #if FGG_ASSETS
 | |
|             if (go.TryGetComponent(out FlexNetworkTransformBase fntb))
 | |
|             {
 | |
|                 Replace(fntb, fntb.TargetTransform);
 | |
|                 return true;
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             void Replace(UnityEngine.Component component, Transform target)
 | |
|             {
 | |
|                 EditorUtility.SetDirty(go);
 | |
|                 DestroyImmediate(component, true);
 | |
| 
 | |
|                 if (target != null && !target.TryGetComponent<FNNetworkTransform>(out _))
 | |
|                     target.gameObject.AddComponent<FNNetworkTransform>();
 | |
|             }
 | |
| 
 | |
|             //Fall through, nothing was replaced.
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private bool IterateNetworkAnimator(GameObject go)
 | |
|         {
 | |
|             if (go.TryGetComponent(out MirrorNetworkAnimator mna))
 | |
|             {
 | |
|                 Replace(mna, mna.transform);
 | |
|                 return true;
 | |
|             }
 | |
| #if FGG_ASSETS
 | |
|             if (go.TryGetComponent(out FlexNetworkAnimator fna))
 | |
|             {
 | |
|                 Replace(fna, fna.transform);
 | |
|                 return true;
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             void Replace(UnityEngine.Component component, Transform target)
 | |
|             {
 | |
|                 EditorUtility.SetDirty(go);
 | |
|                 DestroyImmediate(component, true);
 | |
| 
 | |
|                 if (target == null)
 | |
|                     return;
 | |
|                 if (!target.TryGetComponent<FNNetworkAnimator>(out _))
 | |
|                     target.gameObject.AddComponent<FNNetworkAnimator>();
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         private bool IterateSceneChecker(GameObject go)
 | |
|         {
 | |
| #if !MIRROR_57_0_OR_NEWER
 | |
|             if (_sceneCondition == null)
 | |
|                 return false;
 | |
| 
 | |
|             if (go.TryGetComponent(out MirrorNetworkSceneChecker msc))
 | |
|             {
 | |
|                 Replace(msc);
 | |
|                 return true;
 | |
|             }
 | |
| #if FGG_PROJECTS
 | |
|             if (go.TryGetComponent(out FlexSceneChecker fsc))
 | |
|             {
 | |
|                 Replace(fsc);
 | |
|                 return true;
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             void Replace(UnityEngine.Component component)
 | |
|             {
 | |
|                 EditorUtility.SetDirty(go);
 | |
|                 DestroyImmediate(component, true);
 | |
| 
 | |
|                 FNNetworkObserver networkObserver;
 | |
|                 if (!go.TryGetComponent(out networkObserver))
 | |
|                     networkObserver = go.AddComponent<FNNetworkObserver>();
 | |
| 
 | |
|                 bool conditionFound = false;
 | |
|                 foreach (ObserverCondition condition in networkObserver.ObserverConditions)
 | |
|                 {
 | |
|                     if (condition.GetType() == typeof(SceneCondition))
 | |
|                     {
 | |
|                         conditionFound = true;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //If not able to find scene condition then add one.
 | |
|                 if (!conditionFound)
 | |
|                     networkObserver.ObserverConditionsInternal.Add(_sceneCondition);
 | |
|             }
 | |
| 
 | |
| #endif
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
| 
 | |
| 
 | |
|         private bool IterateProximityChecker(GameObject go)
 | |
|         {
 | |
| #if !MIRROR_57_0_OR_NEWER
 | |
|             if (_distanceCondition == null)
 | |
|                 return false;
 | |
| 
 | |
|             if (go.TryGetComponent(out MirrorNetworkProximityChecker mnpc))
 | |
|             {
 | |
|                 Replace(mnpc);
 | |
|                 return true;
 | |
|             }
 | |
| #if FGG_PROJECTS
 | |
|             if (go.TryGetComponent(out FastProximityChecker fpc))
 | |
|             {
 | |
|                 Replace(fpc);
 | |
|                 return true;
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             void Replace(UnityEngine.Component component)
 | |
|             {
 | |
|                 EditorUtility.SetDirty(go);
 | |
|                 DestroyImmediate(component, true);
 | |
| 
 | |
|                 FNNetworkObserver networkObserver;
 | |
|                 if (!go.TryGetComponent(out networkObserver))
 | |
|                     networkObserver = go.AddComponent<FNNetworkObserver>();
 | |
| 
 | |
|                 bool conditionFound = false;
 | |
|                 foreach (ObserverCondition condition in networkObserver.ObserverConditions)
 | |
|                 {
 | |
|                     if (condition.GetType() == typeof(DistanceCondition))
 | |
|                     {
 | |
|                         conditionFound = true;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //If not able to find scene condition then add one.
 | |
|                 if (!conditionFound)
 | |
|                     networkObserver.ObserverConditionsInternal.Add(_distanceCondition);
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         private bool IterateNetworkIdentity(GameObject go)
 | |
|         {
 | |
|             if (go.TryGetComponent(out NetworkIdentity netIdentity))
 | |
|             {
 | |
|                 EditorUtility.SetDirty(go);
 | |
|                 DestroyImmediate(netIdentity, true);
 | |
| 
 | |
|                 //Add nob if doesn't exist.
 | |
|                 if (!go.TryGetComponent<NetworkObject>(out _))
 | |
|                     go.AddComponent<NetworkObject>();
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         private static void PrintSaveWarning()
 | |
|         {
 | |
|             Debug.LogWarning("You must File -> Save for changes to complete.");
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
| }
 | |
| #endif
 | |
| #endif |