public static void Wrap(Vessel parent, Action <BaseEvent, bool> pass) { UIPartActionController controller = UIPartActionController.Instance; if (!controller) { return; } // Get the open context menus FieldInfo listFieldInfo = controller.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(List <UIPartActionWindow>)); List <UIPartActionWindow> openWindows = (List <UIPartActionWindow>)listFieldInfo.GetValue(controller); foreach (UIPartActionWindow window in openWindows.Where(l => l.part.vessel == parent)) { // Get the list of all UIPartActionItem's FieldInfo itemsFieldInfo = typeof(UIPartActionWindow).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(List <UIPartActionItem>)); List <UIPartActionItem> item = (List <UIPartActionItem>)itemsFieldInfo.GetValue(window); // We only need the UIPartActionEventItem's IEnumerable <UIPartActionItem> actionEventButtons = item.Where(l => (l as UIPartActionEventItem) != null); foreach (UIPartActionEventItem button in actionEventButtons) { BaseEvent originalEvent = button.Evt; // Get the BaseEventDelegate object from the button FieldInfo partEventFieldInfo = typeof(BaseEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEventDelegate)); BaseEventDelegate partEvent = (BaseEventDelegate)partEventFieldInfo.GetValue(originalEvent); object[] customAttributes = partEvent.Method.GetCustomAttributes(typeof(KSPEvent), true); // Look for the custom attribute skip_control bool skip_control = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_control")); if (!skip_control) { // Look for the custom attribute skip_delay bool ignore_delay = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_delay")); // Override the old BaseEvent with our BaseEvent to the button FieldInfo eventField = typeof(UIPartActionEventItem).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEvent)); BaseEventList eventList = originalEvent.listParent; int listIndex = eventList.IndexOf(originalEvent); // create the new BaseEvent BaseEvent hookedEvent = Wrapper.CreateWrapper(originalEvent, pass, ignore_delay); eventList.RemoveAt(listIndex); eventList.Add(hookedEvent); eventField.SetValue(button, hookedEvent); } } } }
public static void WrapPartActionEventItem(Part part, Action <BaseEvent, bool> passthrough) { var controller = UIPartActionController.Instance; if (!controller) { return; } // get the part action window corresponding to the part var window = controller.GetItem(part); if (window == null) { return; } // get all the items that makes this window (toggle buttons, sliders, etc.) var partActionItems = window.ListItems; // loop through all of those UI components for (var i = 0; i < partActionItems.Count(); i++) { // check that the part action item is actually a UIPartActionFieldItem (it could be a UIPartActionEventItem) var uiPartActionEventItem = (partActionItems[i] as UIPartActionEventItem); if (uiPartActionEventItem == null) { continue; } // get event from button BaseEvent originalEvent = uiPartActionEventItem.Evt; // Search for the BaseEventDelegate (BaseEvent.onEvent) field defined for the current BaseEvent type. // Note that 'onEvent' is protected, so we have to go through reflection. FieldInfo partEventFieldInfo = typeof(BaseEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEventDelegate)); // Get the actual value of the 'onEvent' field BaseEventDelegate partEvent = (BaseEventDelegate)partEventFieldInfo.GetValue(originalEvent); // Gets the method represented by the delegate and from this method returns an array of custom attributes applied to this member. // Simply put, we want all [KSPEvent] attributes applied to the BaseEventDelegate.Method field. object[] customAttributes = partEvent.Method.GetCustomAttributes(typeof(KSPEvent), true); // Look for the custom attribute skip_control bool skipControl = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_control")); if (skipControl) { continue; } /* * Override the old BaseEvent with our BaseEvent to the button */ // fix problems with other mods (behavior not seen with KSP) when the customAttributes list is empty. KSPEvent kspEvent = !customAttributes.Any() ? WrappedEvent.KspEventFromBaseEvent(originalEvent) : (KSPEvent)customAttributes[0]; // Look for the custom attribute skip_delay bool ignoreDelay = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_delay")); // create the new BaseEvent BaseEvent hookedEvent = EventWrapper.CreateWrapper(originalEvent, passthrough, ignoreDelay, kspEvent); // get the original event index in the event list BaseEventList eventList = originalEvent.listParent; int listIndex = eventList.IndexOf(originalEvent); // remove the original event in the event list and add our hooked event eventList.RemoveAt(listIndex); eventList.Add(hookedEvent); // get the baseEvent field from UIPartActionEventItem (note: this is uiPartActionEventItem.Evt, but we can't set its value...) FieldInfo baseEventField = typeof(UIPartActionEventItem).GetFields(BindingFlags.Instance | BindingFlags.NonPublic) .First(fi => fi.FieldType == typeof(BaseEvent)); // replace the button baseEvent value with our hooked event baseEventField.SetValue(uiPartActionEventItem, hookedEvent); } }