// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using UltimateXR.Core;
using UltimateXR.Core.Components;
using UltimateXR.Core.Settings;
using UltimateXR.Extensions.System.Collections;
using UltimateXR.Extensions.Unity;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UltimateXR.Networking
{
///
/// Component that stores added network components from different SDKs so that they can be tracked more easily.
/// They are mainly used by the UxrNetworkManagerEditor to delete added components.
///
public partial class UxrNetworkComponentReferences : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private Origin _origin;
[SerializeField] private List _addedGameObjects;
[SerializeField] private List _addedComponents;
#endregion
#region Public Types & Data
///
/// Gets the origin of the components.
///
public Origin ComponentOrigin => _origin;
///
/// Gets or sets the networking GameObjects that were registered by this component so that they can be deleted later
/// using .
///
public List AddedGameObjects
{
get => _addedGameObjects;
set => _addedGameObjects = value;
}
///
/// Gets or sets the networking components that were registered by this component so that they can be deleted later
/// using .
///
public List AddedComponents
{
get => _addedComponents;
set => _addedComponents = value;
}
#endregion
#region Public Methods
///
/// Creates a on a given GameObject that will keep track of all added
/// network components.
///
/// Object to process
/// Network GameObjects that were added
/// Network components that were added
/// The origin of the components
/// The created
public static UxrNetworkComponentReferences RegisterNetworkComponents(GameObject gameObject, IEnumerable addedGameObjects, IEnumerable addedComponents, Origin origin)
{
#if UNITY_EDITOR
UxrNetworkComponentReferences networkComponents = Undo.AddComponent(gameObject);
SerializedObject serializedObject = new SerializedObject(networkComponents);
serializedObject.FindProperty(UxrConstants.Editor.PropertyObjectHideFlags).enumValueFlag = (int)ComponentHideFlags;
serializedObject.FindProperty(nameof(_origin)).enumValueIndex = (int)origin;
SerializedProperty propAddedGameObjects = serializedObject.FindProperty(nameof(_addedGameObjects));
SerializedProperty propAddedComponents = serializedObject.FindProperty(nameof(_addedComponents));
propAddedGameObjects.arraySize = addedGameObjects.Count();
propAddedComponents.arraySize = addedComponents.Count();
int i = 0;
foreach (GameObject go in addedGameObjects)
{
propAddedGameObjects.GetArrayElementAtIndex(i++).objectReferenceValue = go;
}
i = 0;
foreach (Component component in addedComponents)
{
propAddedComponents.GetArrayElementAtIndex(i++).objectReferenceValue = component;
}
serializedObject.ApplyModifiedProperties();
return networkComponents;
#else
return null;
#endif
}
///
/// Destroys all added network components in a GameObject and any of its children.
///
/// GameObject to process
public static void DestroyNetworkComponentsRecursively(GameObject gameObject, Origin origin)
{
gameObject.GetComponentsInChildren(true).Where(c => c._origin == origin).ForEach(c => c.DestroyWithAddedComponents());
}
///
/// Destroys this component together with all the networking components that were added to this same GameObject.
///
public void DestroyWithAddedComponents()
{
if (Application.isPlaying)
{
if (_addedComponents != null)
{
foreach (Component c in _addedComponents.Where(c => c != null))
{
Destroy(c);
}
_addedComponents.Clear();
}
if (_addedGameObjects != null)
{
foreach (GameObject g in _addedGameObjects.Where(g => g != null))
{
Destroy(g);
}
_addedGameObjects.Clear();
}
Destroy(this);
return;
}
#if UNITY_EDITOR
for (int i = 0; i < _addedComponents.Count; ++i)
{
if (_addedComponents[i] != null)
{
if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.NetworkingModule} Destroying component {_addedComponents[i].GetType().Name} in {_addedComponents[i].GetPathUnderScene()}");
}
Undo.DestroyObjectImmediate(_addedComponents[i]);
}
else
{
if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.NetworkingModule} component {i} is null");
}
}
}
for (int i = 0; i < _addedGameObjects.Count; ++i)
{
if (_addedGameObjects[i] != null)
{
if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.NetworkingModule} Destroying GameObject {_addedGameObjects[i].GetPathUnderScene()}");
}
Undo.DestroyObjectImmediate(_addedGameObjects[i]);
}
else
{
if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant)
{
Debug.Log($"{UxrConstants.NetworkingModule} GameObject {i} is null");
}
}
}
_addedGameObjects.Clear();
_addedComponents.Clear();
Undo.DestroyObjectImmediate(this);
#endif
}
#endregion
#region Unity
///
/// Initializes the visibility.
///
protected override void Awake()
{
base.Awake();
hideFlags = ComponentHideFlags;
}
///
/// This is a workaround to make hideFlags work on prefabs. Maybe related:
/// https://forum.unity.com/threads/is-it-impossible-to-save-component-hideflags-in-a-prefab.976974/
///
protected override void OnValidate()
{
base.OnValidate();
hideFlags = ComponentHideFlags;
}
#endregion
#region Private Types & Data
///
/// Gets the required hide flags for this component.
///
private static HideFlags ComponentHideFlags => HideFlags.HideInInspector | HideFlags.HideInHierarchy | HideFlags.NotEditable;
#endregion
}
}