Skip to content

Commit ad24a96

Browse files
committed
code cleanup : greatly simplify the beginning of field wrapping.
1 parent 25dfd1a commit ad24a96

2 files changed

Lines changed: 92 additions & 105 deletions

File tree

src/RemoteTech/FlightComputer/UIPartActionMenuPatcher.cs

Lines changed: 81 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -11,123 +11,112 @@ namespace RemoteTech.FlightComputer
1111
public static class UIPartActionMenuPatcher
1212
{
1313
// UI types that we are actually hooking
14-
public static Type[] AllowedFieldTypes = { typeof(UIPartActionToggle), typeof(UIPartActionFloatRange), typeof(UIPartActionCycle) };
14+
public static Type[] UIPartActionFieldItemAllowedTypes = { typeof(UIPartActionToggle), typeof(UIPartActionFloatRange), typeof(UIPartActionCycle) };
1515

16-
public static List<string> parsedPartActions = new List<string>();
16+
public static List<string> ParsedPartActions = new List<string>();
1717

18-
public static void WrapEvent(Vessel parent, Action<BaseEvent, bool> passthrough)
18+
public static void WrapPartActionEventItem(Part part, Action<BaseEvent, bool> passthrough)
1919
{
20-
UIPartActionController controller = UIPartActionController.Instance;
21-
if (!controller) return;
20+
var controller = UIPartActionController.Instance;
21+
if (!controller)
22+
return;
2223

23-
// Get the open context menus
24-
FieldInfo listFieldInfo = controller.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
25-
.First(fi => fi.FieldType == typeof(List<UIPartActionWindow>));
24+
// get the part action window corresponding to the part
25+
var window = controller.GetItem(part);
26+
if (window == null)
27+
return;
2628

27-
List<UIPartActionWindow> openWindows = (List<UIPartActionWindow>)listFieldInfo.GetValue(controller);
29+
// get all the items that makes this window (toggle buttons, sliders, etc.)
30+
var partActionItems = window.ListItems;
2831

29-
foreach (UIPartActionWindow window in openWindows.Where(window => window.part.vessel == parent))
32+
// loop through all of those UI components
33+
for (var i = 0; i < partActionItems.Count(); i++)
3034
{
31-
// Get the list of all UIPartActionItem's
32-
FieldInfo itemsFieldInfo = typeof(UIPartActionWindow).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
33-
.First(fi => fi.FieldType == typeof(List<UIPartActionItem>));
34-
35-
List<UIPartActionItem> partActionItems = (List<UIPartActionItem>)itemsFieldInfo.GetValue(window);
36-
37-
// We only need the UIPartActionEventItem's
38-
UIPartActionItem[] actionEventButtons = partActionItems.Where(l => (l as UIPartActionEventItem) != null).ToArray();
39-
for (int i = 0; i < actionEventButtons.Count(); i++)
40-
{
41-
// get event from button
42-
UIPartActionEventItem button = (actionEventButtons[i] as UIPartActionEventItem);
43-
BaseEvent originalEvent = button.Evt;
44-
45-
// Search for the BaseEventDelegate (BaseEvent.onEvent) field defined for the current BaseEvent type.
46-
// Note that 'onEvent' is protected, so we have to go through reflection.
47-
FieldInfo partEventFieldInfo = typeof(BaseEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
48-
.First(fi => fi.FieldType == typeof(BaseEventDelegate));
49-
50-
// Get the actual value of the 'onEvent' field
51-
BaseEventDelegate partEvent = (BaseEventDelegate)partEventFieldInfo.GetValue(originalEvent);
52-
53-
// Gets the method represented by the delegate and from this method returns an array of custom attributes applied to this member.
54-
// Simply put, we want all [KSPEvent] attributes applied to the BaseEventDelegate.Method field.
55-
object[] customAttributes = partEvent.Method.GetCustomAttributes(typeof(KSPEvent), true);
56-
57-
// Look for the custom attribute skip_control
58-
bool skip_control = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_control"));
59-
if (!skip_control)
60-
{
61-
/*
62-
* Override the old BaseEvent with our BaseEvent to the button
63-
*/
35+
// check that the part action item is actually a UIPartActionFieldItem (it could be a UIPartActionEventItem)
36+
var uiPartActionEventItem = (partActionItems[i] as UIPartActionEventItem);
37+
if (uiPartActionEventItem == null)
38+
continue;
39+
40+
// get event from button
41+
BaseEvent originalEvent = uiPartActionEventItem.Evt;
42+
43+
// Search for the BaseEventDelegate (BaseEvent.onEvent) field defined for the current BaseEvent type.
44+
// Note that 'onEvent' is protected, so we have to go through reflection.
45+
FieldInfo partEventFieldInfo = typeof(BaseEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
46+
.First(fi => fi.FieldType == typeof(BaseEventDelegate));
47+
48+
// Get the actual value of the 'onEvent' field
49+
BaseEventDelegate partEvent = (BaseEventDelegate)partEventFieldInfo.GetValue(originalEvent);
50+
51+
// Gets the method represented by the delegate and from this method returns an array of custom attributes applied to this member.
52+
// Simply put, we want all [KSPEvent] attributes applied to the BaseEventDelegate.Method field.
53+
object[] customAttributes = partEvent.Method.GetCustomAttributes(typeof(KSPEvent), true);
54+
55+
// Look for the custom attribute skip_control
56+
bool skipControl = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_control"));
57+
if (skipControl)
58+
continue;
59+
60+
/*
61+
* Override the old BaseEvent with our BaseEvent to the button
62+
*/
6463

65-
// fix problems with other mods (behavior not seen with KSP) when the customAttributes list is empty.
66-
KSPEvent kspEvent = customAttributes.Count() == 0 ? WrappedEvent.KspEventFromBaseEvent(originalEvent) : (KSPEvent)customAttributes[0];
64+
// fix problems with other mods (behavior not seen with KSP) when the customAttributes list is empty.
65+
KSPEvent kspEvent = !customAttributes.Any() ? WrappedEvent.KspEventFromBaseEvent(originalEvent) : (KSPEvent)customAttributes[0];
6766

68-
// Look for the custom attribute skip_delay
69-
bool ignore_delay = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_delay"));
67+
// Look for the custom attribute skip_delay
68+
bool ignoreDelay = customAttributes.Any(a => ((KSPEvent)a).category.Contains("skip_delay"));
7069

71-
// create the new BaseEvent
72-
BaseEvent hookedEvent = EventWrapper.CreateWrapper(originalEvent, passthrough, ignore_delay, kspEvent);
70+
// create the new BaseEvent
71+
BaseEvent hookedEvent = EventWrapper.CreateWrapper(originalEvent, passthrough, ignoreDelay, kspEvent);
7372

74-
// get the original event index in the event list
75-
BaseEventList eventList = originalEvent.listParent;
76-
int listIndex = eventList.IndexOf(originalEvent);
73+
// get the original event index in the event list
74+
BaseEventList eventList = originalEvent.listParent;
75+
int listIndex = eventList.IndexOf(originalEvent);
7776

78-
// remove the original event in the event list and add our hooked event
79-
eventList.RemoveAt(listIndex);
80-
eventList.Add(hookedEvent);
77+
// remove the original event in the event list and add our hooked event
78+
eventList.RemoveAt(listIndex);
79+
eventList.Add(hookedEvent);
8180

82-
// get the baseEvent field from UIPartActionEventItem
83-
FieldInfo baseEventField = typeof(UIPartActionEventItem).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
84-
.First(fi => fi.FieldType == typeof(BaseEvent));
81+
// get the baseEvent field from UIPartActionEventItem (note: this is uiPartActionEventItem.Evt, but we can't set its value...)
82+
FieldInfo baseEventField = typeof(UIPartActionEventItem).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
83+
.First(fi => fi.FieldType == typeof(BaseEvent));
8584

86-
// replace the button baseEvent value with our hooked event
87-
baseEventField.SetValue(button, hookedEvent);
88-
}
89-
}
85+
// replace the button baseEvent value with our hooked event
86+
baseEventField.SetValue(uiPartActionEventItem, hookedEvent);
9087
}
9188
}
9289

93-
public static void WrapPartAction(Vessel parent, Action<BaseField, bool> passthrough)
90+
public static void WrapPartActionFieldItem(Part part, Action<BaseField, bool> passthrough)
9491
{
9592
var controller = UIPartActionController.Instance;
9693
if (!controller)
9794
return;
9895

99-
// Get the open context menus
100-
var listFieldInfo = controller.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
101-
.First(fi => fi.FieldType == typeof(List<UIPartActionWindow>));
96+
// get the part action window corresponding to the part
97+
var window = controller.GetItem(part);
98+
if (window == null)
99+
return;
102100

103-
var openWindows = (List<UIPartActionWindow>)listFieldInfo.GetValue(controller);
101+
// get all the items that makes this window (toggle buttons, sliders, etc.)
102+
var partActionItems = window.ListItems;
104103

105-
foreach (UIPartActionWindow window in openWindows.Where(window => window.part.vessel == parent))
104+
// loop through all of those UI components
105+
for (var i = 0; i < partActionItems.Count(); i++)
106106
{
107-
// Get the list of all UIPartActionItem's
108-
var itemsFieldInfo = typeof(UIPartActionWindow).GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
109-
.First(fi => fi.FieldType == typeof(List<UIPartActionItem>));
110-
111-
var partActionItems = (List<UIPartActionItem>)itemsFieldInfo.GetValue(window);
112-
113-
var actionToogleButtons = partActionItems.Where(l => AllowedFieldTypes.Any(t => l.GetType() == t) && (l as UIPartActionFieldItem) != null).ToArray();
114-
for (var i = 0; i < actionToogleButtons.Count(); i++)
115-
{
116-
var actionField = (actionToogleButtons[i] as UIPartActionFieldItem);
117-
if (actionField == null)
118-
continue;
119-
/*if (parsedPartActions.Contains(actionField.Field.name))
120-
continue;
121-
else
122-
parsedPartActions.Add(actionField.Field.name);*/
107+
// check that the part action item is actually a UIPartActionFieldItem (it could be a UIPartActionEventItem)
108+
var uiPartActionFieldItem = (partActionItems[i] as UIPartActionFieldItem);
109+
if (uiPartActionFieldItem == null)
110+
continue;
123111

124-
var customAttributes = actionField.Field.FieldInfo.GetCustomAttributes(typeof(KSPField), true);
112+
// now check that the UIPartActionFieldItem type (e.g UIPartActionToggle; UIPartActionCycle; UIPartActionFloatRange, etc.)
113+
// is actually something we can handle.
114+
if (UIPartActionFieldItemAllowedTypes.All(type => uiPartActionFieldItem.GetType() != type))
115+
continue;
125116

126-
var kspField = !customAttributes.Any() ? WrappedField.KspFieldFromBaseField(actionField.Field) : (KSPField)customAttributes[0];
127-
128-
var fieldWrapper = new FieldWrapper(actionField, kspField, passthrough, false);
129-
}
117+
var fieldWrapper = new FieldWrapper(uiPartActionFieldItem, passthrough, false);
130118
}
119+
131120
}
132121

133122
#region FieldWrapper
@@ -201,20 +190,14 @@ public class FieldWrapper
201190
private Action<float> _delayInvoke;
202191
private object _lastNewValue;
203192

204-
public FieldWrapper(UIPartActionFieldItem uiPartAction, KSPField kspField, Action<BaseField, bool> passthrough, bool ignoreDelay)
193+
public FieldWrapper(UIPartActionFieldItem uiPartAction, Action<BaseField, bool> passthrough, bool ignoreDelay)
205194
{
206195
_uiPartAction = uiPartAction;
207196
SetDefaultListener();
208-
209-
var baseField = uiPartAction.Field;
210-
if(kspField == null)
211-
{
212-
kspField = WrappedField.KspFieldFromBaseField(baseField);
213-
}
214-
197+
215198
_passthrough = passthrough;
216199
_ignoreDelay = ignoreDelay;
217-
_wrappedField = new WrappedField(baseField, kspField);
200+
_wrappedField = new WrappedField(uiPartAction.Field, WrappedField.KspFieldFromBaseField(uiPartAction.Field));
218201
}
219202

220203
public void Invoke()

src/RemoteTech/Modules/ModuleSPU.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ public override void OnStart(StartState state)
101101
Fields["GUI_Status"].guiActive = ShowGUI_Status;
102102
}
103103

104-
public void onPartActionUICreate(Part p)
104+
public void onPartActionUICreate(Part partForUi)
105105
{
106-
HookPartMenus();
106+
HookPartMenus(partForUi);
107107
}
108108

109-
public void onPartActionUIDismiss(Part part)
109+
public void onPartActionUIDismiss(Part partForUi)
110110
{
111-
UIPartActionMenuPatcher.parsedPartActions.Clear();
111+
UIPartActionMenuPatcher.ParsedPartActions.Clear();
112112
}
113113

114114
public void OnDestroy()
@@ -191,10 +191,14 @@ public void OnVesselModified(Vessel v)
191191
}
192192
}
193193

194-
public void HookPartMenus()
194+
public void HookPartMenus(Part partForUi)
195195
{
196-
UIPartActionMenuPatcher.WrapEvent(vessel, (e, ignoreDelay) => InvokeEvent(e, ignoreDelay));
197-
UIPartActionMenuPatcher.WrapPartAction(vessel, (f, ignoreDelay) => InvokePartAction(f, ignoreDelay));
196+
// check if the part is actually one from this vessel
197+
if (partForUi.vessel != vessel)
198+
return;
199+
200+
UIPartActionMenuPatcher.WrapPartActionEventItem(partForUi, InvokeEvent);
201+
UIPartActionMenuPatcher.WrapPartActionFieldItem(partForUi, InvokePartAction);
198202
}
199203

200204
private void InvokeEvent(BaseEvent baseEvent, bool ignoreDelay)

0 commit comments

Comments
 (0)