#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
{
///
/// SceneCondition within FishNet.
///
private SceneCondition _sceneCondition = null;
///
/// DistanceCondition created for the user.
///
private DistanceCondition _distanceCondition = null;
///
///
///
private int _replacedNetworkTransforms;
///
///
///
private int _replacedNetworkAnimators;
///
///
///
private int _replacedNetworkIdentities;
///
///
///
private int _replacedSceneCheckers;
///
///
///
private int _replacedProximityCheckers;
///
/// True if anything was changed.
///
private bool _changed;
///
/// Index in gameObjects to iterate.
///
private int _goIndex = -1;
///
/// Found gameObjects to iterate.
///
private List _gameObjects = new List();
///
/// True if initialized.
///
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++;
}
}
///
/// Finds Condition scripts to be used with NetworkObserver.
///
///
private void FindConditions(bool error)
{
List scriptableObjects;
if (_sceneCondition == null)
{
scriptableObjects = Finding.GetScriptableObjects(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(false, true);
if (scriptableObjects.Count > 0)
{
_distanceCondition = (DistanceCondition)scriptableObjects[0];
}
else
{
DistanceCondition dc = ScriptableObject.CreateInstance();
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(out _))
target.gameObject.AddComponent();
}
//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(out _))
target.gameObject.AddComponent();
}
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();
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();
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(out _))
go.AddComponent();
return true;
}
return false;
}
private static void PrintSaveWarning()
{
Debug.LogWarning("You must File -> Save for changes to complete.");
}
}
}
#endif
#endif