public static IEnumerable <CodeInstruction> Transpiler(MethodBase original, IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = new List <CodeInstruction>(instructions); var GetColorOriginal = typeof(PropInfo).GetMethod("GetColor", new Type[] { typeof(ColossalFramework.Math.Randomizer).MakeByRefType() }); var GetColorFix = typeof(PropPainterGetColorFix).GetMethod("GetColor"); var foundInstruction = false; var fixedInstructions = new[] { new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldloc_0), new CodeInstruction(OpCodes.Ldarg_2), new CodeInstruction(OpCodes.Ldloca_S, 3), new CodeInstruction(OpCodes.Callvirt, GetColorFix), new CodeInstruction(OpCodes.Stloc_S, 5) }; if (GetColorOriginal == null) { Db.e("Could not bind original GetColor. Aborting transpiler."); return(codes.AsEnumerable()); } if (GetColorFix == null) { Db.e("Could not bind custom GetColorFix. Aborting transpiler."); return(codes.AsEnumerable()); } for (int i = 0; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Callvirt) { if (codes[i].operand == GetColorOriginal) { foundInstruction = true; /** Original IL [Harmony]: * L_00bc: ldloc.0 * L_00bd: ldloca.s 3 (ColossalFramework.Math.Randomizer) * L_00bf: callvirt Color GetColor(Randomizer ByRef) [We target this line, so the first line is 2 before.] * L_00c4: stloc.s 5 (UnityEngine.Color) */ int FIRST = i - 2; // Workaround. Changing up this code significantly caused some errors that I do not have time to fix for the moment. List <Label> originalLabels = codes[FIRST].labels; codes.RemoveRange(FIRST, 4); /** Modified IL [dnSpy]: * IL_00A4: ldarg.0 * IL_00A5: ldloc.0 * IL_00A6: ldarg.2 * IL_00A7: ldloca.s randomizer [3] * IL_00A9: call instance valuetype[UnityEngine]UnityEngine.Color global::GetColorFix(class PropInfo, uint16, valuetype[ColossalManaged] ColossalFramework.Math.Randomizer&) * IL_00AE: stloc.s color [5] */ codes.InsertRange(FIRST, fixedInstructions); codes[FIRST].labels = originalLabels; break; } } } if (!foundInstruction) { Db.e("Did not find CodeInstruction, GetColor not patched."); } return(codes.AsEnumerable()); }
// Updated code thanks to TPB- @TODO implement! private static void CreateUI(UIComponent parent, string name) { UIColorField field = UITemplateManager.Get <UIPanel>("LineTemplate").Find <UIColorField>("LineColor"); field = UnityEngine.Object.Instantiate <UIColorField>(field); field.isVisible = false; field.name = "PropPickerColorField"; UIColorPicker picker = UnityEngine.Object.Instantiate <UIColorPicker>(field.colorPicker); picker.eventColorUpdated += ChangeSelectionColors; picker.color = Color.white; picker.component.color = Color.white; picker.name = name; UIPanel pickerPanel = picker.component as UIPanel; pickerPanel.backgroundSprite = "InfoPanelBack"; pickerPanel.isVisible = false; picker.component.size = new Vector2(254f, 226f); // ?/ parent.AttachUIComponent(picker.gameObject); pickerPanel.absolutePosition = UIToolOptionPanel.instance.m_viewOptions.absolutePosition - new Vector3(329, 147); Db.l("Prop Picker color picker instantiated"); FieldInfo f = typeof(UIToolOptionPanel).GetField("m_alignTools", BindingFlags.Instance | BindingFlags.NonPublic); UIButton AlignTools = f.GetValue(UIToolOptionPanel.instance) as UIButton; UIPanel AlignToolsPanel = UIToolOptionPanel.instance.m_alignToolsPanel; FieldInfo fa = typeof(UIToolOptionPanel).GetField("m_single", BindingFlags.Instance | BindingFlags.NonPublic); UIButton Single = fa.GetValue(UIToolOptionPanel.instance) as UIButton; FieldInfo fb = typeof(UIToolOptionPanel).GetField("m_marquee", BindingFlags.Instance | BindingFlags.NonPublic); UIButton Marquee = fb.GetValue(UIToolOptionPanel.instance) as UIButton; Single.zOrder = 7; Marquee.zOrder = 7; UIToolOptionPanel.instance.m_filtersPanelList.height = 240f; // @TODO - Make this modular, please! I need to put more buttons here later and I need to make a single singleton manager for all of my mods. UIPanel extraToolBackground = AlignToolsPanel.AddUIComponent <UIPanel>(); extraToolBackground.size = new Vector2(26, 70); extraToolBackground.clipChildren = true; extraToolBackground.relativePosition = new Vector3(5, -37); extraToolBackground.backgroundSprite = "InfoPanelBack"; extraToolBackground.name = "ElektrixModsMenu"; extraToolBackground.zOrder = 0; AlignTools.tooltip = "More Tools"; UIToolOptionPanel.instance.clipChildren = false; UIComponent[] t = UIToolOptionPanel.instance.GetComponentsInChildren <UIPanel>(); for (int i = 0; i < t.Length; i++) { t[i].clipChildren = false; } UIMultiStateButton propPickerButton = AlignToolsPanel.AddUIComponent <UIMultiStateButton>(); propPickerButton.name = "PropPickerButton"; propPickerButton.tooltip = "Prop Painter"; propPickerButton.spritePadding = new RectOffset(2, 2, 2, 2); propPickerButton.playAudioEvents = true; propPickerButton.relativePosition = new Vector3(0, -45); var GetIconsAtlas = typeof(UIToolOptionPanel).GetMethod("GetIconsAtlas", BindingFlags.Instance | BindingFlags.NonPublic); propPickerButton.atlas = GetIconsAtlas.Invoke(UIToolOptionPanel.instance, new object[] { }) as UITextureAtlas; propPickerButton.backgroundSprites.AddState(); propPickerButton.foregroundSprites.AddState(); propPickerButton.backgroundSprites[0].normal = "OptionBase"; propPickerButton.backgroundSprites[0].focused = "OptionBase"; propPickerButton.backgroundSprites[0].hovered = "OptionBaseHovered"; propPickerButton.backgroundSprites[0].pressed = "OptionBasePressed"; propPickerButton.backgroundSprites[0].disabled = "OptionBaseDisabled"; propPickerButton.foregroundSprites[0].normal = "EyeDropper"; propPickerButton.backgroundSprites[1].normal = "OptionBaseFocused"; propPickerButton.backgroundSprites[1].focused = "OptionBaseFocused"; propPickerButton.backgroundSprites[1].hovered = "OptionBaseHovered"; propPickerButton.backgroundSprites[1].pressed = "OptionBasePressed"; propPickerButton.backgroundSprites[1].disabled = "OptionBaseDisabled"; propPickerButton.foregroundSprites[1].normal = "EyeDropper"; propPickerButton.size = new Vector2(36, 36); propPickerButton.activeStateIndex = 0; propPickerButton.eventClicked += (component, eventParam) => { Db.l("Button state " + propPickerButton.activeStateIndex); pickerPanel.isVisible = propPickerButton.activeStateIndex == 1; UIToolOptionPanel.instance.m_filtersPanelList.height = 240f; Db.w("Tried to make color picker visible/invisible"); }; Db.l("Prop Picker button instantiated"); PropPainterManager.instance.colorField = field; PropPainterManager.instance.colorPicker = picker; PropPainterManager.instance.propPainterButton = propPickerButton; PropPainterManager.instance.colorPanel = pickerPanel; }