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); } } } }
// Adding Selfie button private void addSelfie(KerbalEVA evaCtl) { Log.dbg("Adding Selfie to {0}", evaCtl.GUIName); BaseEventList pEvents = evaCtl.Events; BaseEventDelegate slf = new BaseEventDelegate(TakeSelfie); KSPEvent evt = new KSPEvent { active = true, externalToEVAOnly = true, guiActive = true, guiActiveEditor = false, guiActiveUnfocused = false, guiActiveUncommand = false, guiName = "Take Selfie", name = "TakeSelfie" }; BaseEvent selfie = new BaseEvent(pEvents, "Take Selfie", slf, evt); pEvents.Add(selfie); selfie.guiActive = true; selfie.active = true; }
private void reinitEvents(Vessel v) { printDebug("entered"); if (v.evaController == null) { return; } KerbalEVA evaCtl = v.evaController; ProtoCrewMember crew = v.GetVesselCrew() [0]; String kerbalName = crew.name; printDebug("evCtl found; checking name: " + kerbalName); Tourist t; if (!tourists.TryGetValue(kerbalName, out t)) { return; } printDebug("among tourists: " + kerbalName); t.smile = false; t.taken = false; if (!Tourist.isTourist(v.GetVesselCrew()[0])) { printDebug("...but is a crew"); return; // not a real tourist } // Change crew type right away to avoid them being crew after recovery crew.type = ProtoCrewMember.KerbalType.Tourist; BaseEventList pEvents = evaCtl.Events; foreach (BaseEvent e in pEvents) { printDebug("disabling event " + e.guiName); e.guiActive = false; e.guiActiveUnfocused = false; e.guiActiveUncommand = false; } // Adding Selfie button BaseEventDelegate slf = new BaseEventDelegate(TakeSelfie); KSPEvent evt = new KSPEvent(); evt.active = true; evt.externalToEVAOnly = true; evt.guiActive = true; evt.guiActiveEditor = false; evt.guiActiveUnfocused = false; evt.guiActiveUncommand = false; evt.guiName = "Take Selfie"; evt.name = "TakeSelfie"; BaseEvent selfie = new BaseEvent(pEvents, "Take Selfie", slf, evt); pEvents.Add(selfie); selfie.guiActive = true; selfie.active = true; foreach (PartModule m in evaCtl.part.Modules) { if (!m.ClassName.Equals("ModuleScienceExperiment")) { continue; } printDebug("science module id: " + ((ModuleScienceExperiment)m).experimentID); // Disable all science foreach (BaseEvent e in m.Events) { e.guiActive = false; e.guiActiveUnfocused = false; e.guiActiveUncommand = false; } foreach (BaseAction a in m.Actions) { a.active = false; } } printDebug("Initializing sound"); // Should we always invalidate cache??? fx = null; getOrCreateAudio(evaCtl.part.gameObject); }
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); } }