// /*=============================================================================== // Copyright (C) 2020 PhantomsXR Ltd. All Rights Reserved. // // This file is part of the XR-MOD SDK. // // The XR-MOD 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.Collections.Generic; using System.Linq; using UnityEngine; using UnityFusion.CLR.TypeSystem; using UnityFusion.Runtime.Enviorment; using Phantom.XRMOD.ActionNotification.Runtime; namespace Phantom.XRMOD.UnityFusion.Runtime.CodeHook { /// /// Component responsible for binding runtime scripts to a GameObject and setting their field values. /// It acts as a bridge between the serialized script data and the live ILRuntime/CLR instances. /// public class MonoBinder : MonoBehaviour { /// /// List of script data to be instantiated and bound to this GameObject. /// public List ScriptList; /// /// The default render state for this GameObject when scripts are added. /// public RenderStateType DefaultRenderState = RenderStateType.None; private readonly RuntimeFieldHandlerFactory runtimeFieldHandlerFactory = new(new DbAssetProvider()); private readonly List scriptCreations = new() { new MultipleInheritanceCreation(), new UIMonoBehaviourCreation(), new XRMODBehaviourCreation(), }; private ScriptInstantiator scriptInstantiator; private IDataBinder dataBinder = new DataBinding(); private int addedScriptCounter = 0; private bool isConverting; private void Awake() { ActionNotificationCenter.DefaultCenter.AddObserver(ProcessMonoBinderTrigger, nameof(ActionParameterDataType.ProcessMonoBinder)); } private void OnDestroy() { addedScriptCounter = 0; ActionNotificationCenter.DefaultCenter.RemoveObserver(nameof(ActionParameterDataType.ProcessMonoBinder), ProcessMonoBinderTrigger); } /// /// Manually triggers the binding process for this MonoBinder. /// /// Notification data (optional). public void ProcessMonoBinderTrigger(BaseNotificationData _baseNotification) { if (isConverting) return; isConverting = true; BinderManager.Instance.DoBind(this); } internal void AddRuntimeScript(MonoData _data) { try { if (DefaultRenderState == RenderStateType.None) { DefaultRenderState = gameObject.activeSelf ? RenderStateType.Visiable : RenderStateType.Hiden; } if (addedScriptCounter >= ScriptList.Count) return; scriptInstantiator ??= new ScriptInstantiator(scriptCreations); scriptInstantiator.InstantiateScript(gameObject, _data); addedScriptCounter++; } catch (Exception tmp_Exception) { Debug.LogException(tmp_Exception); } } internal void SetValues(MonoData _monoData) { if (addedScriptCounter == 0) { Debug.Log($"{gameObject.name}'s {_monoData.ClassName} Script not added"); return; } if (gameObject.name.Contains("RefAssetsTest")) { } dataBinder.BindData(_monoData); } internal void ActiveScript(MonoData _data) { try { string tmp_FullClassName = $"{_data.ClassNamespace + (_data.ClassNamespace == "" ? "" : ".")}{_data.ClassName}"; IType tmp_LoadedType = CodesHook.GetAppDomain.LoadedTypes[tmp_FullClassName]; var tmp_ClrInstance = gameObject.GetComponents() .Last(_clr => _clr.ILInstance.Type == tmp_LoadedType as ILType); if (_data.BoundData == false && _data.Fields != null && _data.Fields.Count > 0) { Debug.LogWarning( $"[Convert Error]:The {tmp_FullClassName} script on {name} lost data.This may cause some bugs."); } if (tmp_ClrInstance.GetType().IsSubclassOf(typeof(MonoBehaviour))) { ((MonoBehaviour) tmp_ClrInstance).enabled = true; } _data.Activated = true; } catch (Exception tmp_Exception) { Debug.LogError($"Error at:{gameObject.name}.{_data.ClassName}"); Debug.LogException(tmp_Exception); throw; } } internal void Remove() { if (gameObject.scene.IsValid()) Destroy(this); else DestroyImmediate(this, true); } internal void SetupGameObjectRenderState(bool _render) { gameObject.SetActive(_render); } } }