using System; using UnityEngine; using System.Collections; using System.Collections.Generic; using SimpleJSON; using System.Linq; namespace Clownmug { internal class HandMirror : MVRScript { private Atom TargetAtom; private JSONStorableStringChooser MirrorMode; private JSONStorableBool MirrorLHand; private JSONStorableBool MirrorRHand; private JSONStorableBool AllowPositionReset; private JSONStorableFloat UpdateInterval; private UIDynamicToggle MirrorLHandToggle; private UIDynamicToggle MirrorRHandToggle; private string TargetHandControl; private string SourceHandControl; private FreeControllerV3 TargetHandController; private FreeControllerV3 SourceHandController; private FreeControllerV3.PositionState TargetHandPosState = FreeControllerV3.PositionState.On; private FreeControllerV3.RotationState TargetHandRotState = FreeControllerV3.RotationState.On; private Vector3 SourceLocalPos, TargetOrigPos, TempLocalPos, RootOrigPos; private Quaternion SourceLocalRot, TargetOrigRot, TempLocalRot, RootOrigRot; private bool RootWasDetached = false; private bool RootForced = false; private float Timer = 0.0f; private float UpdateTime = 0.0f; readonly List MirrorModeList = new List { "Normal Root","Hip Relative","Forced Hip Root" }; public override void Init() { try { TargetAtom = containingAtom; if (TargetAtom.category != "People") { SuperController.LogError("The plugin must be on a Person atom."); return; } MirrorMode = new JSONStorableStringChooser("Mirror Mode", MirrorModeList, "Hip Relative", "Mirror Mode"); MirrorLHand = new JSONStorableBool("Mirror Left Hand",false); MirrorRHand = new JSONStorableBool("Mirror Right Hand",false); AllowPositionReset = new JSONStorableBool("Allow Position Reset",true); UpdateInterval = new JSONStorableFloat("Relative Mode Update Interval", 0.15f, 0.01f, 1.0f, true, true); CreateScrollablePopup(MirrorMode, false); MirrorLHandToggle = CreateToggle(MirrorLHand); MirrorLHandToggle.label = MirrorLHand.name; MirrorLHandToggle.toggle.onValueChanged.AddListener(OnMirrorLHandToggle); MirrorRHandToggle = CreateToggle(MirrorRHand); MirrorRHandToggle.label = MirrorRHand.name; MirrorRHandToggle.toggle.onValueChanged.AddListener(OnMirrorRHandToggle); CreateToggle(AllowPositionReset); CreateSlider(UpdateInterval); RegisterStringChooser(MirrorMode); RegisterBool(MirrorLHand); RegisterBool(MirrorRHand); RegisterFloat(UpdateInterval); } catch (Exception e) { SuperController.LogError("Exception caught: " + e); } } private void OnMirrorLHandToggle(bool toggled) { if(toggled) { if(MirrorRHand.val == true) { Reset(); MirrorRHand.val = false; } TargetHandControl = "rHandControl"; SourceHandControl = "lHandControl"; Calibrate(); } else { Reset(); } } private void OnMirrorRHandToggle(bool toggled) { if(toggled) { if(MirrorLHand.val == true) { Reset(); MirrorLHand.val = false; } TargetHandControl = "lHandControl"; SourceHandControl = "rHandControl"; Calibrate(); } else { Reset(); } } private void RootToHip() { RootWasDetached = TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val; if(!RootForced) { RootOrigPos = TargetAtom.GetStorableByID("control").transform.position; RootOrigRot = TargetAtom.GetStorableByID("control").transform.rotation; } TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val = true; TargetAtom.GetStorableByID("control").transform.position = TargetAtom.GetStorableByID("hip").transform.position; TargetAtom.GetStorableByID("control").transform.rotation = TargetAtom.GetStorableByID("hip").transform.rotation; TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val = false; } private void ReturnRoot() { TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val = true; TargetAtom.GetStorableByID("control").transform.position = RootOrigPos; TargetAtom.GetStorableByID("control").transform.rotation = RootOrigRot; if(!RootWasDetached) TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val = false; } private void Reset() { TargetHandController.currentPositionState = TargetHandPosState; TargetHandController.currentRotationState = TargetHandRotState; if(RootForced) { RootForced = false; ReturnRoot(); } if(AllowPositionReset.val == true) { TargetHandController.transform.localPosition = TargetOrigPos; TargetHandController.transform.localRotation = TargetOrigRot; } } private void Calibrate() { TargetHandController = TargetAtom.GetStorableByID(TargetHandControl) as FreeControllerV3; SourceHandController = TargetAtom.GetStorableByID(SourceHandControl) as FreeControllerV3; TargetHandPosState = TargetHandController.currentPositionState; TargetHandRotState = TargetHandController.currentRotationState; TargetHandController.currentPositionState = FreeControllerV3.PositionState.On; TargetHandController.currentRotationState = FreeControllerV3.RotationState.On; TargetOrigPos = TargetHandController.transform.localPosition; TargetOrigRot = TargetHandController.transform.localRotation; } private void Recalibrate() { if(MirrorLHand.val == true) { TargetHandControl = "rHandControl"; SourceHandControl = "lHandControl"; Calibrate(); } else if(MirrorRHand.val == true) { TargetHandControl = "lHandControl"; SourceHandControl = "rHandControl"; Calibrate(); } } void MoveTargets() { SourceLocalPos = SourceHandController.transform.localPosition; SourceLocalRot = SourceHandController.transform.localRotation; TempLocalPos = TargetHandController.transform.localPosition; TempLocalRot = TargetHandController.transform.localRotation; TempLocalPos.x = SourceLocalPos.x * -1; TempLocalPos.y = SourceLocalPos.y; TempLocalPos.z = SourceLocalPos.z; TempLocalRot.x = SourceLocalRot.x; TempLocalRot.y = SourceLocalRot.y * -1; TempLocalRot.z = SourceLocalRot.z * -1; TempLocalRot.w = SourceLocalRot.w; TargetHandController.transform.localPosition = TempLocalPos; TargetHandController.transform.localRotation = TempLocalRot; } void Update() { if(MirrorLHandToggle.toggle.isOn || MirrorRHandToggle.toggle.isOn) { Timer += Time.deltaTime; TargetHandController.currentPositionState = FreeControllerV3.PositionState.On; TargetHandController.currentRotationState = FreeControllerV3.RotationState.On; if(MirrorMode.val == "Normal Root") { if(RootForced) { RootForced = false; ReturnRoot(); } MoveTargets(); } else if(MirrorMode.val == "Hip Relative") { if(RootForced) { RootForced = false; ReturnRoot(); } if(Timer > UpdateTime) { RootToHip(); MoveTargets(); ReturnRoot(); UpdateTime = Timer + UpdateInterval.val; } } else if(MirrorMode.val == "Forced Hip Root") { if(!RootForced) { RootForced = true; ReturnRoot(); RootToHip(); } if(TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val == true) TargetAtom.GetStorableByID("control").GetBoolJSONParam("detachControl").val = false; MoveTargets(); } } } void OnEnable() { if(MirrorLHandToggle.toggle.isOn || MirrorRHandToggle.toggle.isOn) Recalibrate(); } void OnDisable() { if(MirrorLHandToggle.toggle.isOn || MirrorRHandToggle.toggle.isOn) Reset(); } void OnDestroy() { if(MirrorLHandToggle.toggle.isOn || MirrorRHandToggle.toggle.isOn) Reset(); } } }