static private void Setup_SceneDescriptor()
        {
            var comps = Object.FindObjectsOfType(typeof(VRCSDK2.VRC_SceneDescriptor));

            VRCSDK2.VRC_SceneDescriptor descriptor;
            switch (comps.Length)
            {
            case 0:
                Iwlog.Warn("VRC_SceneDescriptor not found. Create temporary");
                var go = new GameObject("VRC_SceneDescriptor holder");
                descriptor = go.AddComponent <VRCSDK2.VRC_SceneDescriptor>();
                var scene = EditorSceneManager.GetActiveScene();
                EditorSceneManager.MoveGameObjectToScene(go, scene);
                break;

            case 1:
                descriptor = (VRCSDK2.VRC_SceneDescriptor)comps[0];
                break;

            default:
                Iwlog.Warn("Too many VRC_SceneDescriptor found.");
                descriptor = (VRCSDK2.VRC_SceneDescriptor)comps[0];
                break;
            }

            LocalPlayerContext.SceneDescriptor = descriptor;
        }
        static private bool SpawnPlayerObject()
        {
            var playerInstance = SpawnFromPrefab(playerPrefabPath);

            if (!playerInstance)
            {
                return(false);
            }

            var playerCtrl = playerInstance.GetComponent <PlayerControl>();

            if (!playerCtrl)
            {
                Iwlog.Error("PlayerPrefab must have PlayerControl component");
                return(false);
            }
            LocalPlayerContext.SetLocalPlayer(playerCtrl);

            Setup_VRC_UiShape(playerCtrl.PlayerCamera.GetComponent <Camera>());

            SetupQuickMenu(playerCtrl);

            LocalPlayerContext.MovePlayerToSpawnLocation();

            return(true);
        }
        static private bool SetupQuickMenu(PlayerControl playerCtrl)
        {
            var quickMenu = SpawnFromPrefab(quickMenuPrefabPath);

            if (!quickMenu)
            {
                return(false);
            }

            var canvasObj = quickMenu.transform.Find("Canvas");

            if (!canvasObj)
            {
                Iwlog.Error("QuickMenu Canvas object not found.");
                return(false);
            }
            var canvas = canvasObj.GetComponent <UnityEngine.Canvas>();

            if (!canvas)
            {
                Iwlog.Error("QuickMenu Canvas component not found.");
                return(false);
            }

            var camera = playerCtrl.PlayerCamera.GetComponent <Camera>();

            canvas.worldCamera = camera;

            playerCtrl.QuickMenu = quickMenu;

            // initial state is inactive
            quickMenu.SetActive(false);

            return(true);
        }
        private void DoDorop(VRCSDK2.VRC_Pickup pickupComp)
        {
            if (pickupComp != holdingPickup)
            {
                return;
            }

            var rigidbodyComp = pickupComp.GetComponent <Rigidbody>();

            if (rigidbodyComp == null)
            {
                Iwlog.Error(gameObject, "Rigidbody not found.");
                return;
            }

            rigidbodyComp.isKinematic = originalIsKinematic;
            holdingPickup             = null;

            var triggerComp = pickupComp.GetComponent <Emu_Trigger>();

            if (triggerComp != null)
            {
                triggerComp.ExecuteTriggers(VRCSDK2.VRC_Trigger.TriggerType.OnDrop);
            }
        }
        private void DoPickup(VRCSDK2.VRC_Pickup pickupComp)
        {
            var rigidbodyComp = pickupComp.GetComponent <Rigidbody>();

            if (rigidbodyComp == null)
            {
                Iwlog.Error(gameObject, "Rigidbody not found.");
                return;
            }

            originalIsKinematic       = rigidbodyComp.isKinematic;
            rigidbodyComp.isKinematic = true;

            // TODO adjust AutoDetect case
            AutoHold = pickupComp.AutoHold;

            holdingPickup = pickupComp;

            var triggerComp = pickupComp.GetComponent <Emu_Trigger>();

            if (triggerComp != null)
            {
                triggerComp.ExecuteTriggers(VRCSDK2.VRC_Trigger.TriggerType.OnPickup);
            }
        }
        void Start()
        {
            if (character == null)
            {
                character = this.transform.parent.gameObject;
            }

            if (playerCamera == null)
            {
                playerCamera = GetComponent <Camera>();
                if (playerCamera == null)
                {
                    Iwlog.Error(gameObject, "Camera not found.");
                }
            }

            if (hoverAnchor == null)
            {
                var tmp = this.transform.Find("HoverAnchor");
                if (tmp == null)
                {
                    Iwlog.Error(gameObject, "HoverAnchor not found.");
                }
                else
                {
                    hoverAnchor = tmp.gameObject;
                }
            }

            // move mouse cursor to center
            Cursor.lockState = CursorLockMode.Locked;
            // Cursor.lockState = CursorLockMode.None;
        }
        static private void Setup_ReplaceTriggerRefference()
        {
            int procCount = 0;

            procCount += ReplaceTriggerRefferenceInUIEvent(typeof(UnityEngine.UI.Button), "m_OnClick");
            procCount += ReplaceTriggerRefferenceInUIEvent(typeof(UnityEngine.UI.InputField), "m_OnValueChanged");
            procCount += ReplaceTriggerRefferenceInUIEvent(typeof(UnityEngine.UI.InputField), "m_OnEndEdit");
            Iwlog.Debug("VRC_Trigger references in UIEvents replaced for runtime. Count=" + procCount);
        }
        ////////////////////////////////////////////////////////////

        static private GameObject SpawnFromPrefab(string path)
        {
            var prefab = Resources.Load <GameObject>(path);

            if (prefab == null)
            {
                Iwlog.Error("Prefab not found. path='" + path + "'");
                return(null);
            }

            var instance = Object.Instantiate(prefab);
            var scene    = EditorSceneManager.GetActiveScene();

            EditorSceneManager.MoveGameObjectToScene(instance, scene);

            return(instance);
        }
        private void DoUseDownUp(bool doDown)
        {
            if (holdingPickup == null)
            {
                Iwlog.Error(gameObject, "pickupComp == null");
                return;
            }

            var triggerComp = holdingPickup.GetComponent <Emu_Trigger>();

            if (triggerComp != null)
            {
                triggerComp.ExecuteTriggers(doDown?
                                            VRCSDK2.VRC_Trigger.TriggerType.OnPickupUseDown
                                            : VRCSDK2.VRC_Trigger.TriggerType.OnPickupUseUp);
            }
        }
        private void SetupCamera()
        {
            var orgMainCam = GameObject.FindWithTag("MainCamera");

            if (orgMainCam != null)
            {
                orgMainCam.SetActive(false);
            }

            // TODO use VRC_SceneDescriptor.ReferenceCamera as template
            if (PlayerCamera == null)
            {
                Iwlog.Error(gameObject, "PlayerCamera not specified.");
            }
            else
            {
                PlayerCamera.SetActive(true);
            }
        }
        static private bool ReplaceTriggerRefferenceInUIEvent(Component comp, string EventPropName)
        {
            if (IsInPrefab(comp)) // CHECK Do I have to skip ? see. Setup_TriggersComponents
            {
                return(false);
            }

            int procCount = 0;

            // To modify persistent part of UnityEventBase, we must use persistent API.
            var sComp = new SerializedObject(comp);

            var uiEvent           = sComp.FindProperty(EventPropName);
            var m_PersistentCalls = uiEvent.FindPropertyRelative("m_PersistentCalls");
            var m_Calls           = m_PersistentCalls.FindPropertyRelative("m_Calls");

            for (int idx = m_Calls.arraySize - 1; 0 <= idx; idx--)
            {
                var persCall = m_Calls.GetArrayElementAtIndex(idx);
                var m_Target = persCall.FindPropertyRelative("m_Target");
                UnityEngine.Object targetObj = m_Target.objectReferenceValue;

                if ((targetObj != null) && (targetObj.GetType() == typeof(VRCSDK2.VRC_Trigger)))
                {
                    var emuTrigger = ((Component)targetObj).GetComponent(typeof(Emu_Trigger));
                    if (emuTrigger == null)
                    {
                        Iwlog.Error("emuTrigger == null");
                    }
                    else
                    {
                        m_Target.objectReferenceValue = emuTrigger;
                        procCount++;
                    }
                }
            }
            if (0 < procCount)
            {
                sComp.ApplyModifiedPropertiesWithoutUndo();
            }

            return(0 < procCount);
        }
 // Toggle menu
 // "Cancel" is usually bind to ESC
 // Alternative bind : LeftShift + C
 // (In UnitEditor ESC activates cursor automatically. You can avoid this behavior by using alternative bind.)
 private void ToggleQuickMenuOperation()
 {
     if (Input.GetButtonUp("Cancel")
         #if UNITY_EDITOR
         || (Input.GetKey(KeyCode.LeftShift) && Input.GetKeyDown(KeyCode.C))
         #endif
         )
     {
         Iwlog.Trace("Toggle QuickMenu");
         if (QuickMenu.activeSelf)
         {
             QuickMenu.SetActive(false);
         }
         else
         {
             QuickMenu.transform.position = QuckMenuInitLoc.transform.position;
             QuickMenu.transform.rotation = QuckMenuInitLoc.transform.rotation;
             QuickMenu.SetActive(true);
         }
     }
 }
        void Start()
        {
            if (character == null)
            {
                character = this.transform.parent.gameObject;
            }

            if (playerCamera == null)
            {
                playerCamera = GetComponent <Camera>();
                if (playerCamera == null)
                {
                    Iwlog.Error(gameObject, "Camera not found.");
                }
                else if (refCameraObj != null)
                {
                    CopyCameraSettings(refCameraObj);

                    // There seems to be no necessaries to inactivate, but do it because VRChat client (w_2019.3.2 build 860) does.
                    refCameraObj.SetActive(false);
                }
            }

            if (hoverAnchor == null)
            {
                var tmp = this.transform.Find("HoverAnchor");
                if (tmp == null)
                {
                    Iwlog.Error(gameObject, "HoverAnchor not found.");
                }
                else
                {
                    hoverAnchor = tmp.gameObject;
                }
            }

            // move mouse cursor to center
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible   = false;
        }
        private void CopyPostProcessingV2(Camera srcCamera, Camera dstCamera)
        {
            var ppLayerType = Type.GetType("UnityEngine.Rendering.PostProcessing.PostProcessLayer, Unity.Postprocessing.Runtime");

            if (ppLayerType == null)
            {
                Iwlog.Trace("PostProcessing v2 not exists");
            }
            else
            {
                var srcPpLayerComp = srcCamera.GetComponent(ppLayerType);
                if (srcPpLayerComp != null)
                {
                    var dstPpLayerComp = dstCamera.GetComponent(ppLayerType);
                    if (dstPpLayerComp != null)
                    {
                        Iwlog.Warn(dstCamera.gameObject, "Unexpected PostProcessLayer exists.");
                    }
                    else
                    {
                        dstPpLayerComp = dstCamera.gameObject.AddComponent(ppLayerType);
                    }

                    #if UNITY_EDITOR
                    UnityEditor.EditorUtility.CopySerialized(srcPpLayerComp, dstPpLayerComp);
                    #else
                    Iwlog.Error("not implemented for runtime");
                    #endif

                    // replace volumeTrigger if camera itself. (That is usual case)
                    FieldInfo fldInfo = ppLayerType.GetField("volumeTrigger");
                    Assert.IsNotNull(fldInfo);
                    if ((Transform)fldInfo.GetValue(srcPpLayerComp) == srcCamera.transform)
                    {
                        fldInfo.SetValue(dstPpLayerComp, dstCamera.transform);
                    }
                }
            }
        }
 // Toggle quick menu
 // "Cancel" is usually bind to ESC
 // Alternative bind : Q
 // (In UnitEditor ESC activates mouse cursor automatically. You can avoid this behavior by using alternative bind.)
 private void ToggleQuickMenuOperation()
 {
     if (Input.GetKeyDown(KeyCode.Tab))
     {
         Iwlog.Trace("Toggle QuickMenu");
         if (QuickMenu.activeSelf)
         {
             QuickMenu.SetActive(false);
         }
         else
         {
             QuickMenu.transform.position = QuckMenuInitLoc.transform.position;
             QuickMenu.transform.rotation = QuckMenuInitLoc.transform.rotation;
             QuickMenu.SetActive(true);
         }
     }
     if (Input.GetKeyDown(KeyCode.F12))
     {
         // For interactive print debug
         // Iwlog.Debug("Hi from F12");
         // Iwlog.Debug("Camera.main=" + Camera.main);
     }
 }
        private void CopyCameraSettings(GameObject refCameraObj)
        {
            Camera refCamera = refCameraObj.GetComponent <Camera>();

            if (refCamera == null)
            {
                // VRC_SceneDescriptor.ReferenceCamera is just a GameObject.
                // It could be possible without a Camera component.
                var mes = "Camera not found in VRC_SceneDescriptor.ReferenceCamera.";
                Iwlog.Warn(refCameraObj, mes);
                EditorEnvUtil.ShowNotificationOnGameView(mes);
                return;
            }

            Assert.IsNotNull(playerCamera);

            playerCamera.nearClipPlane   = refCamera.nearClipPlane;
            playerCamera.farClipPlane    = refCamera.farClipPlane;
            playerCamera.clearFlags      = refCamera.clearFlags;
            playerCamera.backgroundColor = refCamera.backgroundColor;
            playerCamera.allowHDR        = refCamera.allowHDR;

            CopyPostProcessingV2(refCamera, playerCamera);
        }