public void Start()
        {
            if (!EditorExtensions.validVersion)
            {
                return;
            }
            //log = new Log(this.GetType().Name);
            Log.Debug("Start");

//			var st_offset_tweak = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_offset_tweak");
            var st_offset_tweak = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_OFFSET_TWEAK);

            KFSMStateChange hookOffsetUpdateFn = (from) => {
                var p        = EditorLogic.SelectedPart;
                var parent   = p.parent;
                var symCount = p.symmetryCounterparts.Count;
                //var attachNode = Refl.GetValue(EditorLogic.fetch, "\u001B\u0002");
                //var attachNode = Refl.GetValue(EditorLogic.fetch, "symUpdateAttachNode");
                var symUpdateAttachNode = Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.SYMUPDATEATTACHNODE);

                //public static GizmoOffset Attach(Transform host, Quaternion rotOffset, Callback<Vector3> onMove, Callback<Vector3> onMoved, Camera refCamera = null);

                Quaternion rotOffset = p.attRotation;
                gizmo = GizmoOffset.Attach(EditorLogic.SelectedPart.transform,
                                           rotOffset,

                                           new Callback <Vector3>((offset) => {
                    p.transform.position = gizmo.transform.position;
                    p.attPos             = p.transform.localPosition - p.attPos0;

                    Log.Info("symCount: " + symCount.ToString());
                    if (symCount != 0)
                    {
//							Refl.Invoke(EditorLogic.fetch, "UpdateSymmetry", p, symCount, parent, symUpdateAttachNode);
                        Refl.Invoke(EditorLogic.fetch, EditorExtensions.c.UPDATESYMMETRY, p, symCount, parent, symUpdateAttachNode);
                    }

                    GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartOffsetting, EditorLogic.SelectedPart);
                }), new Callback <Vector3>((offset) => {
                    //Refl.Invoke(EditorLogic.fetch, "onOffsetGizmoUpdated", offset);
                    Refl.Invoke(EditorLogic.fetch, EditorExtensions.c.ONOFFSETGIZMOUPDATED, offset);
                }), EditorLogic.fetch.editorCamera);

                //((GizmoOffset)Refl.GetValue(EditorLogic.fetch, "\u0012")).Detach();
                //Refl.SetValue(EditorLogic.fetch, "\u0012", gizmo);
                //((GizmoOffset)Refl.GetValue(EditorLogic.fetch, "gizmoOffset")).Detach();
                ((GizmoOffset)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.GIZMOOFFSET)).Detach();
                //Refl.SetValue(EditorLogic.fetch, "gizmoOffset", gizmo);
                Refl.SetValue(EditorLogic.fetch, EditorExtensions.c.GIZMOOFFSET, gizmo);
            };

            st_offset_tweak.OnEnter += hookOffsetUpdateFn;
            OnCleanup += () => {
                st_offset_tweak.OnEnter -= hookOffsetUpdateFn;
            };
            Log.Debug("Installed.");
        }
        /**
         * The stock root selection has two states:
         *  - st_root_unselected: Active after switching to root mode. Waits for mouse up, picks part and sets SelectedPart.
         *  - st_root_select: The state after the first click.
         *
         * Skip straight to st_root state by adding an event to st_root_unselected with
         * always true condition that sets up SelectedPart and transitions to st_root.
         *
         * Needs to run after EditorLogic#Start() so the states are initialized.
         */
        public void Start()
        {
            Instance = this;
            if (!EditorExtensions.validVersion)
            {
                return;
            }

            //if (!EditorExtensions.Instance.ReRootActive || !EditorExtensions.Instance.cfg.ReRootEnabled)
            //    return;

            //log = new Log(this.GetType().Name);
            Log.Info("SelectRoot2 Start");

            // Oh god, so much dirty reflection. Please don't sue me, Squad :(
            //KerbalFSM editorFSM = (KerbalFSM)Refl.GetValue(EditorLogic.fetch, "\u0001");


            // Skip first click in root selection mode:
            KFSMEvent skipFirstClickEvent = new KFSMEvent("SelectRoot2_skipFirstClickEvent");

            skipFirstClickEvent.OnCheckCondition = (state) => {
                // Um about that always true condition... There is a funny sound glitch
                // if the root part doesn't have any ROOTABLE children so check for that.
                // Thanks Kerbas_ad_astra, http://forum.kerbalspaceprogram.com/threads/43208?p=1948755#post1948755
                return(EditorReRootUtil.GetRootCandidates(EditorLogic.RootPart.GetComponentsInChildren <Part>()).Any());
            };


            skipFirstClickEvent.OnEvent = () => {
                //Refl.SetValue(EditorLogic.fetch, "selectedPart", EditorLogic.RootPart); // SelectedPart
                Refl.SetValue(EditorLogic.fetch, EditorExtensions.c.SELECTEDPART, EditorLogic.RootPart); // SelectedPart
            };
            //KFSMState st_root_select = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_root_select");
            KFSMState st_root_select = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_ROOT_SELECT);

            skipFirstClickEvent.GoToStateOnEvent = st_root_select;

            //KFSMState st_root_unselected = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_root_unselected");
            KFSMState st_root_unselected = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_ROOT_UNSELECTED);

            InjectEvent(st_root_unselected, skipFirstClickEvent);

            // Fix ability to select if already hovering:
            KFSMStateChange fixAlreadyHoveringPartFn = (from) => {
                Part partUnderCursor = GetPartUnderCursor();
                var  selectors       = EditorLogic.SortedShipList;

                //EditorLogic.fetch.Lock (true, true, true, "SelectRoot2");

                var selectorUnderCursor = selectors.Find(x => (Part)x == partUnderCursor);
                if (selectorUnderCursor)
                {
//						Refl.Invoke(selectorUnderCursor, "OnMouseIsOver");
                    Refl.Invoke(selectorUnderCursor, EditorExtensions.c.ONMOUSEISOVER);
                }
            };

            st_root_select.OnEnter += fixAlreadyHoveringPartFn;
            OnCleanup += () => {
                st_root_select.OnEnter -= fixAlreadyHoveringPartFn;
            };

            // Provide a more meaningful message after our changes:
            KFSMStateChange postNewMessageFn = (from) => {
                //var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, "modeMsg");
                var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.MODEMSG);
                ScreenMessages.PostScreenMessage("Select a new root part", template);
            };

            st_root_select.OnEnter += postNewMessageFn;
            OnCleanup += () => {
                st_root_select.OnEnter -= postNewMessageFn;
            };

            // Drop the new root part after selection:

            KFSMEvent dropNewRootPartEvent = new KFSMEvent("SelectRoot2_dropNewRootPartEvent");

            dropNewRootPartEvent.OnCheckCondition = (state) => {
                return(EditorLogic.fetch.lastEventName.Equals("on_rootSelect"));
            };

            dropNewRootPartEvent.OnEvent = () => {
                // Normally the backup is triggered in on_partDropped#OnCheckCondition()
                // But we skip that, so do backup here instead.

                EditorLogic.fetch.SetBackup();
                // Normally triggered in on_partDropped#OnEvent().
                GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartDropped, EditorLogic.SelectedPart);
                //var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, "modeMsg");
                var template = (ScreenMessage)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.MODEMSG);
                //ScreenMessages.PostScreenMessage(String.Empty, template);
                if (template != null)
                {
                    ScreenMessages.PostScreenMessage("New Root selected and dropped", template);
                }
                else
                {
                    ScreenMessages.PostScreenMessage("New Root selected and dropped");
                }

                EditorLogic.SelectedPart.gameObject.SetLayerRecursive(0, 1 << 21);
#if false
                Part[] parts = EditorLogic.RootPart.GetComponentsInChildren <Part>();
                foreach (var p in parts)
                {
                    Log.Info(p.ToString() + "p.enabled: " + p.enabled.ToString());

                    //Log.Info(p.ToString() + "p.frozen: " + p.active .ToString());
                }
#endif
                //EditorLogic.fetch.Unlock("SelectRoot2");
            };

            // problem is with the following line
            //KFSMState st_idle = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_idle");
            KFSMState st_idle = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_IDLE);
            dropNewRootPartEvent.GoToStateOnEvent = st_idle;

            //KFSMState st_place = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_place");
            KFSMState st_place = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_PLACE);
            InjectEvent(st_place, dropNewRootPartEvent);


            Log.Info("Setup complete..");
        }
Exemple #3
0
 public Refl refl;    // reflection type (DIFFuse, SPECular, REFRactive)
 public Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl refl_)
 {
     rad = rad_; p = p_; e = e_; c = c_; refl = refl_;
 }
Exemple #4
0
        internal static string CheckReflections(Session IrSe)
        {
            StringBuilder Result = new StringBuilder();

            if (IrSe == null)
            {
                return(Result.ToString());
            }
            if (IrSe.Request == null)
            {
                return(Result.ToString());
            }
            if (IrSe.Response == null)
            {
                return(Result.ToString());
            }
            int TotalReflections = 0;

            List <Reflection> UrlReflections         = new List <Reflection>();
            List <Reflection> UrlPathPartReflections = new List <Reflection>();
            List <Reflection> QueryReflections       = new List <Reflection>();
            List <Reflection> BodyReflections        = new List <Reflection>();
            List <Reflection> CookieReflections      = new List <Reflection>();
            List <Reflection> HeaderReflections      = new List <Reflection>();

            string ResString = IrSe.Response.ToString();

            //Check if the URL is being reflected back
            if (IrSe.Request.Url.Length > 1)
            {
                Reflection RefResult = GetReflections(IrSe.Request.Url, ResString);
                if (RefResult.Count > 0)
                {
                    RefResult.Name    = "URL";
                    RefResult.Value   = IrSe.Request.Url;
                    RefResult.Section = "URL";
                    UrlReflections.Add(RefResult);
                }
            }

            //check if any URL path parts are being reflected. To be checked only when Querystring and File extension are absent (to handle URL rewriting)

            if ((IrSe.Request.Query.Count == 0) && (IrSe.Request.File.Length == 0) && IrSe.Request.UrlPathParts.Count > 0)
            {
                int PathCount = 0;
                foreach (string UrlPathPart in IrSe.Request.UrlPathParts)
                {
                    Reflection RefResult = GetReflections(UrlPathPart, ResString);
                    if (RefResult.Count > 0)
                    {
                        RefResult.Name    = "UrlPathPart : " + PathCount.ToString();
                        RefResult.Value   = UrlPathPart;
                        RefResult.Section = "UrlPathPart";
                        UrlPathPartReflections.Add(RefResult);
                    }
                    PathCount++;
                }
            }

            //check if any Query parameters are being reflected
            foreach (string Name in IrSe.Request.Query.GetNames())
            {
                List <string> SubParametervalues = IrSe.Request.Query.GetAll(Name);
                List <string> ParameterResults   = new List <string>();
                foreach (string Value in SubParametervalues)
                {
                    Reflection RefResult = GetReflections(Value, ResString);
                    if (RefResult.Count > 0)
                    {
                        RefResult.Name    = Name;
                        RefResult.Value   = Value;
                        RefResult.Section = "Query";
                        QueryReflections.Add(RefResult);
                    }
                }
            }

            //check if any Body parameters are being reflected
            foreach (string Name in IrSe.Request.Body.GetNames())
            {
                List <string> SubParametervalues = IrSe.Request.Body.GetAll(Name);
                List <string> ParameterResults   = new List <string>();
                foreach (string Value in SubParametervalues)
                {
                    Reflection RefResult = GetReflections(Value, ResString);
                    if (RefResult.Count > 0)
                    {
                        RefResult.Name    = Name;
                        RefResult.Value   = Value;
                        RefResult.Section = "Body";
                        BodyReflections.Add(RefResult);
                    }
                }
            }

            //check if any Cookie parameters are being reflected
            foreach (string Name in IrSe.Request.Cookie.GetNames())
            {
                List <string> SubParametervalues = IrSe.Request.Cookie.GetAll(Name);
                List <string> ParameterResults   = new List <string>();
                foreach (string Value in SubParametervalues)
                {
                    Reflection RefResult = GetReflections(Value, ResString);
                    if (RefResult.Count > 0)
                    {
                        RefResult.Name    = Name;
                        RefResult.Value   = Value;
                        RefResult.Section = "Cookie";
                        CookieReflections.Add(RefResult);
                    }
                }
            }

            //check if any Header parameters are being reflected
            foreach (string Name in IrSe.Request.Headers.GetNames())
            {
                List <string> SubParametervalues = IrSe.Request.Headers.GetAll(Name);
                List <string> ParameterResults   = new List <string>();
                foreach (string Value in SubParametervalues)
                {
                    Reflection RefResult = GetReflections(Value, ResString);
                    if (RefResult.Count > 0)
                    {
                        RefResult.Name    = Name;
                        RefResult.Value   = Value;
                        RefResult.Section = "Header";
                        HeaderReflections.Add(RefResult);
                    }
                }
            }

            TotalReflections = UrlReflections.Count + UrlPathPartReflections.Count + QueryReflections.Count + BodyReflections.Count + CookieReflections.Count + HeaderReflections.Count;

            Result.Append("<i<hh>>Total Reflections: "); Result.Append(TotalReflections.ToString()); Result.Append("<i</hh>> | ");

            if (UrlReflections.Count > 0)
            {
                Result.Append("<i<hh>> URL : "); Result.Append(UrlReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (UrlPathPartReflections.Count > 0)
            {
                Result.Append("<i<hh>> URL Path : "); Result.Append(UrlPathPartReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (QueryReflections.Count > 0)
            {
                Result.Append("<i<hh>> Query : "); Result.Append(QueryReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (BodyReflections.Count > 0)
            {
                Result.Append("<i<hh>> Body : "); Result.Append(BodyReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (CookieReflections.Count > 0)
            {
                Result.Append("<i<hh>> Cookie : "); Result.Append(CookieReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (HeaderReflections.Count > 0)
            {
                Result.Append("<i<hh>> Headers : "); Result.Append(HeaderReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }

            Result.Append("<i<br>>");

            Dictionary <int, List <Reflection> > OrderedReflections = new Dictionary <int, List <Reflection> >();
            List <List <Reflection> >            AllReflections     = new List <List <Reflection> >()
            {
                UrlReflections, UrlPathPartReflections, QueryReflections, BodyReflections, CookieReflections, HeaderReflections
            };

            foreach (List <Reflection> ReflectionList in AllReflections)
            {
                foreach (Reflection Refl in ReflectionList)
                {
                    if (OrderedReflections.ContainsKey(Refl.Length))
                    {
                        OrderedReflections[Refl.Length].Add(Refl);
                    }
                    else
                    {
                        OrderedReflections.Add(Refl.Length, new List <Reflection>()
                        {
                            Refl
                        });
                    }
                }
            }

            List <int> LengthOrder = new List <int>(OrderedReflections.Keys);

            LengthOrder.Sort();
            for (int i = LengthOrder.Count - 1; i >= 0; i--)
            {
                int Length = LengthOrder[i];
                foreach (Reflection Refl in OrderedReflections[Length])
                {
                    Result.Append("<i<br>><i<br>>");
                    Result.Append("<i<h>>Section:<i</h>> "); Result.Append(Refl.Section); Result.Append(" | <i<h>>Parameter:<i</h>> "); Result.Append(Refl.Name); Result.Append(" | <i<h>>Count:<i</h>> "); Result.Append(Refl.Count.ToString()); Result.Append(" | <i<h>>Value:<i</h>><i<hlo>> "); Result.Append(Refl.Value); Result.Append("<i</hlo>>");
                    foreach (string R in Refl.GetReflections())
                    {
                        Result.Append("<i<br>>    "); Result.Append(R.Replace(Refl.Value, "<i<hlo>>" + Refl.Value + "<i</hlo>>"));
                    }
                }
            }
            return(Result.ToString());
        }
Exemple #5
0
 public InvokeComplex(Refl a, testClass b)
 {
 }
Exemple #6
0
        public static string CheckReflections(Reflections AllReflections)
        {
            StringBuilder Result = new StringBuilder();

            if (AllReflections.Count == 0)
            {
                return(Result.ToString());
            }

            int TotalReflections = 0;

            List <Reflection> UrlReflections         = AllReflections.Url;
            List <Reflection> UrlPathPartReflections = AllReflections.UrlPathPart;
            List <Reflection> QueryReflections       = AllReflections.Query;
            List <Reflection> BodyReflections        = AllReflections.Body;
            List <Reflection> CookieReflections      = AllReflections.Cookie;
            List <Reflection> HeaderReflections      = AllReflections.Header;


            TotalReflections = UrlReflections.Count + UrlPathPartReflections.Count + QueryReflections.Count + BodyReflections.Count + CookieReflections.Count + HeaderReflections.Count;

            Result.Append("<i<hh>>Total Reflections: "); Result.Append(TotalReflections.ToString()); Result.Append("<i</hh>> | ");

            if (UrlReflections.Count > 0)
            {
                Result.Append("<i<hh>> URL : "); Result.Append(UrlReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (UrlPathPartReflections.Count > 0)
            {
                Result.Append("<i<hh>> URL Path : "); Result.Append(UrlPathPartReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (QueryReflections.Count > 0)
            {
                Result.Append("<i<hh>> Query : "); Result.Append(QueryReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (BodyReflections.Count > 0)
            {
                Result.Append("<i<hh>> Body : "); Result.Append(BodyReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (CookieReflections.Count > 0)
            {
                Result.Append("<i<hh>> Cookie : "); Result.Append(CookieReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }
            if (HeaderReflections.Count > 0)
            {
                Result.Append("<i<hh>> Headers : "); Result.Append(HeaderReflections.Count.ToString()); Result.Append("<i</hh>> | ");
            }

            Result.Append("<i<br>>");

            Dictionary <int, List <Reflection> > OrderedReflections = new Dictionary <int, List <Reflection> >();

            foreach (List <Reflection> ReflectionList in AllReflections.GetList())
            {
                foreach (Reflection Refl in ReflectionList)
                {
                    if (OrderedReflections.ContainsKey(Refl.Length))
                    {
                        OrderedReflections[Refl.Length].Add(Refl);
                    }
                    else
                    {
                        OrderedReflections.Add(Refl.Length, new List <Reflection>()
                        {
                            Refl
                        });
                    }
                }
            }

            List <int> LengthOrder = new List <int>(OrderedReflections.Keys);

            LengthOrder.Sort();
            for (int i = LengthOrder.Count - 1; i >= 0; i--)
            {
                int Length = LengthOrder[i];
                foreach (Reflection Refl in OrderedReflections[Length])
                {
                    Result.Append("<i<br>><i<br>>");
                    Result.Append("<i<h>>Section:<i</h>> "); Result.Append(Refl.Section); Result.Append(" | <i<h>>Parameter:<i</h>> "); Result.Append(Refl.Name); Result.Append(" | <i<h>>Count:<i</h>> "); Result.Append(Refl.Count.ToString()); Result.Append(" | <i<h>>Value:<i</h>><i<hlo>> "); Result.Append(Refl.Value); Result.Append("<i</hlo>>");
                    foreach (string R in Refl.GetReflections())
                    {
                        Result.Append("<i<br>>    "); Result.Append(R);
                    }
                }
            }
            return(Result.ToString());
        }
        public void Start()
        {
            Instance = this;
            if (!EditorExtensions.validVersion)
            {
                return;
            }

            //log = new Log(this.GetType().Name);
            Log.trace("FreeOffsetBehaviour.Start");

            //			var st_offset_tweak = (KFSMState)Refl.GetValue(EditorLogic.fetch, "st_offset_tweak");
            var st_offset_tweak = (KFSMState)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.ST_OFFSET_TWEAK);

            KFSMStateChange hookOffsetUpdateFn = (from) =>
            {
                var p = EditorLogic.SelectedPart;

                if (p != null && p.GetType() == typeof(CompoundPart))
                {
                    return;
                }

                p.onEditorStartTweak();
                var parent   = p.parent;
                var symCount = p.symmetryCounterparts.Count;
                //var attachNode = Refl.GetValue(EditorLogic.fetch, "\u001B\u0002");
                //var attachNode = Refl.GetValue(EditorLogic.fetch, "symUpdateAttachNode");
                var symUpdateAttachNode = Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.SYMUPDATEATTACHNODE);

                //public static GizmoOffset Attach(Transform host, Quaternion rotOffset, Callback<Vector3> onMove, Callback<Vector3> onMoved, Camera refCamera = null);



                Quaternion rotOffset = p.attRotation;

                //                this.gizmoOffset = GizmoOffset.Attach(this.selectedPart.transform,
                //                    new Callback<Vector3>(this.onOffsetGizmoUpdate),
                //                    new Callback<Vector3>(this.onOffsetGizmoUpdated),
                //                    this.editorCamera);

                // this.audioSource.PlayOneShot(this.tweakGrabClip);

                // gizmoRotate = (GizmoRotate)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.GIZMOROTATE);

                gizmoOffset = GizmoOffset.Attach(EditorLogic.SelectedPart.transform,
                                                 rotOffset,

                                                 new Callback <Vector3>((offset) =>
                {
                    if (gizmoOffset.CoordSpace == Space.Self)
                    {
                        gizmoOffset.transform.rotation = p.transform.rotation;
                    }
                    else
                    {
                        gizmoOffset.transform.rotation = Quaternion.identity;
                    }

                    p.transform.position = gizmoOffset.transform.position;
                    p.attPos             = p.transform.localPosition - p.attPos0;

                    Log.detail("symCount: {0}", symCount);
                    if (symCount != 0)
                    {
                        //	Refl.Invoke(EditorLogic.fetch, "UpdateSymmetry", p, symCount, parent, symUpdateAttachNode);
                        Refl.Invoke(EditorLogic.fetch, EditorExtensions.c.UPDATESYMMETRY, p, symCount, parent, symUpdateAttachNode);
                    }

                    GameEvents.onEditorPartEvent.Fire(ConstructionEventType.PartOffsetting, EditorLogic.SelectedPart);
                }),

                                                 new Callback <Vector3>((offset) =>
                {
                    //Refl.Invoke(EditorLogic.fetch, "onOffsetGizmoUpdated", offset);
                    Refl.Invoke(EditorLogic.fetch, EditorExtensions.c.ONOFFSETGIZMOUPDATED, offset);
                }), EditorLogic.fetch.editorCamera);


                //((GizmoOffset)Refl.GetValue(EditorLogic.fetch, "gizmoOffset")).Detach();
                ((GizmoOffset)Refl.GetValue(EditorLogic.fetch, EditorExtensions.c.GIZMOOFFSET)).Detach();
                //Refl.SetValue(EditorLogic.fetch, "gizmoOffset", gizmo);
                Refl.SetValue(EditorLogic.fetch, EditorExtensions.c.GIZMOOFFSET, gizmoOffset);
            };

            st_offset_tweak.OnEnter += hookOffsetUpdateFn;
            OnCleanup += () =>
            {
                st_offset_tweak.OnEnter -= hookOffsetUpdateFn;
            };
            Log.dbg("Installed.");
        }