// // /*===============================================================================
// // Copyright (C) 2020 PhantomsXR Ltd. All Rights Reserved.
// //
// // This file is part of the UnityFusion.Runtime.CodeHook.
// //
// // The ARMOD-SDK cannot be copied, distributed, or made available to
// // third-parties for commercial purposes without written permission of PhantomsXR Ltd.
// //
// // Contact nswell@phantomsxr.com for licensing requests.
// // ===============================================================================*/
using System;
using System.Linq;
using System.Reflection;
using Phantom.XRMOD.UnityFusion.Runtime.CodeHook;
using UnityFusion.CLR.Method;
using UnityFusion.CLR.TypeSystem;
using UnityFusion.CLRBinding.Adapter;
using UnityFusion.Runtime.Enviorment;
using UnityFusion.Runtime.Intepreter;
using UnityEngine;
using UnityEngine.Assertions;
using AppDomain = UnityFusion.Runtime.Enviorment.AppDomain;
using Extension = UnityFusion.CLR.Utils.Extensions;
using Object = UnityEngine.Object;
namespace Phantom.XRMOD.UnityFusion.Runtime
{
public static class Utility
{
internal const BindingFlags CONST_ALL_BINDING_FLAGS = BindingFlags.NonPublic | BindingFlags.Public
| BindingFlags.Instance |
BindingFlags.Static;
internal const string CONST_ADD_RUNTIME_CLASS = "AddRuntimeClass";
///
/// Checkout the GameObject and the type in the IL
///
///
///
///
public static void CheckoutIlTypeInstance(object _instance, out GameObject _gameObject, out ILType _returnType)
{
_returnType = null;
switch (_instance)
{
case GameObject tmp_GameObject:
_gameObject = tmp_GameObject;
break;
case ILTypeInstance tmp_TypeInstance:
_returnType = tmp_TypeInstance.Type;
_gameObject = FindGameFromILTypeInstance(tmp_TypeInstance);
Assert.IsNotNull(_gameObject);
break;
default:
_gameObject = (_instance as Component)?.gameObject;
break;
}
}
///
/// find ilrt gameObject
///
///
/// GameObject
public static GameObject FindGameFromILTypeInstance(ILTypeInstance _instance)
{
var tmp_ReturnType = _instance.Type;
if (tmp_ReturnType.ReflectionType == typeof(MonoBehaviour))
{
var tmp_PropertyInfo = tmp_ReturnType.ReflectionType.GetProperty("gameObject");
if (tmp_PropertyInfo != null)
return tmp_PropertyInfo.GetValue((_instance as ILTypeInstance).CLRInstance) as GameObject;
}
else if (tmp_ReturnType.ReflectionType.IsSubclassOf(typeof(MonoBehaviour)))
{
if (tmp_ReturnType.ReflectionType.BaseType == null) return null;
var tmp_PropertyInfo = tmp_ReturnType.ReflectionType.BaseType.GetProperty("gameObject");
if (tmp_PropertyInfo != null)
return tmp_PropertyInfo.GetValue((_instance as ILTypeInstance).CLRInstance) as GameObject;
}
return null;
}
///
/// 获取对象的gameObject
///
///
///
public static GameObject GetGameObject(this object ins)
{
GameObject tmp_Instance = ins switch
{
GameObject tmp_Go => tmp_Go,
ILTypeInstance ilt => FindGameFromILTypeInstance(ilt),
Transform t => t.gameObject,
Component c => c.gameObject,
_ => null
};
return tmp_Instance;
}
///
/// 获取热更对象
///
///
///
///
public static object[] GetILComponents(GameObject _gameObject, AppDomain _appDomain, string _typeName)
{
var tmp_ClrInstances = _gameObject.GetComponents();
var tmp_Type = _appDomain.GetType(_typeName);
object[] tmp_Ret = new object[tmp_ClrInstances.Length];
int tmp_Idx = 0;
foreach (var tmp_ClrInstance in tmp_ClrInstances)
{
if (tmp_ClrInstance.ILInstance != null && tmp_ClrInstance.ILInstance.Type.CanAssignTo(tmp_Type))
{
tmp_Ret[tmp_Idx] = tmp_ClrInstance.ILInstance;
tmp_Idx++;
}
}
Array.Resize(ref tmp_Ret, tmp_Idx);
return tmp_Ret;
}
///
/// 获取热更对象
///
///
///
///
public static object[] GetILComponents(GameObject _gameObject, ILType _type)
{
var tmp_ClrInstances = _gameObject.GetComponents();
object[] tmp_Ret = new object[tmp_ClrInstances.Length];
int tmp_Idx = 0;
foreach (var tmp_ClrInstance in tmp_ClrInstances)
{
if (tmp_ClrInstance.ILInstance != null && tmp_ClrInstance.ILInstance.Type.CanAssignTo(_type))
{
tmp_Ret[tmp_Idx] = tmp_ClrInstance.ILInstance;
tmp_Idx++;
}
}
Array.Resize(ref tmp_Ret, tmp_Idx);
return tmp_Ret;
}
///
/// 获取热更对象
///
///
///
///
public static object GetILComponent(GameObject _gameObject, AppDomain _appDomain, string _typeName)
{
var tmp_ClrInstances = _gameObject.GetComponents();
var tmp_Type = _appDomain.GetType(_typeName);
foreach (var tmp_ClrInstance in tmp_ClrInstances)
{
if (tmp_ClrInstance.ILInstance != null && tmp_ClrInstance.ILInstance.Type.CanAssignTo(tmp_Type))
{
return tmp_ClrInstance.ILInstance;
}
}
return null;
}
///
/// SendMessage
///
///
///
///
///
///
public static bool SendMessageWithILTypeInstance(AppDomain _appDomain, GameObject _go, string _methodName,
object _value = null,
SendMessageOptions _option = SendMessageOptions.RequireReceiver)
{
bool tmp_Found = false;
var tmp_ClrInstances = _go.GetComponents();
foreach (var tmp_ClrInstance in tmp_ClrInstances)
{
if (tmp_ClrInstance.ILInstance == null) continue;
IType tmp_T = tmp_ClrInstance.ILInstance.Type;
if (_value == null)
{
IMethod tmp_M = tmp_T.GetMethod(_methodName, 0);
if (tmp_M == null) continue;
_appDomain.Invoke(tmp_M, tmp_ClrInstance.ILInstance, null);
tmp_Found = true;
}
else
{
IMethod m = tmp_T.GetMethod(_methodName, 1);
if (m == null) continue;
_appDomain.Invoke(m, tmp_ClrInstance.ILInstance, _value);
tmp_Found = true;
}
}
return tmp_Found;
}
///
/// Instantiate GameObject
///
/// GameObject of prefab
/// GameObject of instanced in the scene
/// Script domain
///
/// Object
public static object DoBinding(GameObject _gameObjectInMemory, GameObject _instancedGameObject,
AppDomain _domain, IType _type = null)
{
// Check if the game object uses custom scripts (e.g.MonoBehaviour/XRMODBehaviour script).
if (_instancedGameObject.GetComponentsInChildren(true).Length == 0)
{
// Check if game object uses MonoBinder
if (_instancedGameObject.GetComponentsInChildren(true).Length > 0)
{
BinderManager.Instance.DoBind(_instancedGameObject.GetComponentsInChildren(true).ToList());
}
return _instancedGameObject;
}
bool tmp_NeedClassBind = false;
// Remove all MonoBinder after binding
foreach (var tmp_Transform in _instancedGameObject.GetComponentsInChildren())
{
var tmp_MonoBinder = tmp_Transform.GetComponent();
if (tmp_MonoBinder != null && tmp_Transform.GetComponent() != null)
{
Object.DestroyImmediate(tmp_MonoBinder);
}
}
if (_gameObjectInMemory.GetComponentsInChildren(true).Length > 0)
{
tmp_NeedClassBind = true;
}
var tmp_ClrInstances = _instancedGameObject.GetComponentsInChildren(true);
var tmp_ClrMemoryInstances = _gameObjectInMemory.GetComponentsInChildren(true);
ILTypeInstance tmp_Result = null;
for (int tmp_Idx = 0; tmp_Idx < tmp_ClrInstances.Length; tmp_Idx++)
{
var tmp_ClrInstance = tmp_ClrInstances[tmp_Idx];
var tmp_ClrMemoryInstance = tmp_ClrMemoryInstances[tmp_Idx];
ILTypeInstance tmp_ILInstance = tmp_ClrMemoryInstance.ILInstance.Clone();
var tmp_TypeInMemoryObject = tmp_ClrMemoryInstance.GetType();
if (tmp_ILInstance.Type == _type && tmp_Result == null)
{
tmp_Result = tmp_ILInstance;
}
if (tmp_ClrMemoryInstance is XRMODBehaviourAdapter.Adapter tmp_Adaptor)
{
tmp_Adaptor.Reset();
tmp_Adaptor.ILInstance = tmp_ILInstance;
tmp_Adaptor.AppDomain = _domain;
}
else
{
var tmp_IlInstance = tmp_TypeInMemoryObject.GetField("instance",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
var tmp_AppDomain = tmp_TypeInMemoryObject.GetField("appdomain",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
tmp_IlInstance?.SetValue(tmp_ClrInstance, tmp_ILInstance);
tmp_AppDomain?.SetValue(tmp_ClrInstance, _domain);
}
if (tmp_ClrMemoryInstance.ILInstance.CLRInstance == tmp_ClrMemoryInstance)
{
tmp_ILInstance.CLRInstance = tmp_ClrInstance;
}
else
{
tmp_ILInstance.CLRInstance = tmp_ILInstance;
}
var tmp_AwakeMethod =
(tmp_ClrInstance.GetType() != null ? tmp_ClrInstance.GetType() : tmp_TypeInMemoryObject).GetMethod(
"Awake",
BindingFlags.Default | BindingFlags.Public
| BindingFlags.Instance | BindingFlags.FlattenHierarchy |
BindingFlags.NonPublic | BindingFlags.Static);
if (tmp_AwakeMethod != null)
{
tmp_AwakeMethod.Invoke(tmp_ClrInstance, null);
}
// if (tmp_NeedClassBind)
// {
// BinderManager.DoBind();
// }
// else
// {
// if (_instancedGameObject.GetComponentInChildren(true))
// {
// BinderManager.DoBind(_instancedGameObject.GetComponentsInChildren(true).ToList());
// }
// }
BinderManager.Instance.DoBind(_instancedGameObject.GetComponentsInChildren(true).ToList());
}
if (_type != null)
{
return tmp_Result;
}
return _instancedGameObject;
}
internal static void GetCrossBindingAdaptorComponent(T _target, out object _result,
ILType _ilType, CrossBindingAdaptorType[] _crossBindingAdaptorArray) where T : UnityEngine.Object
{
object[] tmp_IlInstances = new object[_crossBindingAdaptorArray.Length];
int tmp_Idx = 0;
foreach (var tmp_ClrInstance in _crossBindingAdaptorArray)
{
if (tmp_ClrInstance.ILInstance != null &&
tmp_ClrInstance.ILInstance.Type.CanAssignTo(_ilType))
{
tmp_IlInstances[tmp_Idx] = tmp_ClrInstance.ILInstance;
tmp_Idx++;
}
}
Array.Resize(ref tmp_IlInstances, tmp_Idx);
int tmp_IlInstancesLength = tmp_IlInstances.Length;
_result = Array.CreateInstance(_ilType.TypeForCLR, tmp_IlInstancesLength);
for (int tmp_Indices = 0; tmp_Indices < tmp_IlInstancesLength; tmp_Indices++)
((Array) _result).SetValue(((ILTypeInstance) tmp_IlInstances[tmp_Indices]).CLRInstance, tmp_Indices);
}
public static GameObject ProcessPrefabMonoBinder(GameObject _prefab)
{
var tmp_MonoBinders = _prefab.GetComponentsInChildren(true);
bool tmp_NeedClassBind = tmp_MonoBinders.Length > 0;
if (!tmp_NeedClassBind)
return _prefab;
BinderManager.Instance.DoBind(tmp_MonoBinders.ToList());
return _prefab;
}
public static void InvokeConstructor(ILTypeInstance _instance, IType _ilType)
{
var tmp_Method = _ilType.GetConstructor(Extension.EmptyParamList);
if (tmp_Method != null && _instance != null)
{
CodesHook.GetAppDomain.Invoke(tmp_Method, _instance, null);
}
}
internal static void ProcessMonoBinder(AsyncInstantiateOperation _resultOfThisMethod)
where T : Object
{
_resultOfThisMethod.completed += _operation =>
{
foreach (var tmp_Go in (_resultOfThisMethod.Result as GameObject[])!)
{
var tmp_MonoBinders = tmp_Go.GetComponentsInChildren(true).Reverse();
foreach (MonoBinder tmp_MonoBinder in tmp_MonoBinders)
{
tmp_MonoBinder.ProcessMonoBinderTrigger(null);
}
}
};
}
}
}