├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE.md ├── Oxide.Patcher.sln ├── README.md ├── nuget.config └── src ├── App.config ├── Common ├── AssemblyLoader.cs ├── Decompiler.cs ├── Extensions │ └── StringEx.cs ├── JsonHelpers │ ├── HookConverter.cs │ ├── HookRef.cs │ ├── HooksListConverter.cs │ └── JsonReaderEx.cs ├── MRUManager.cs ├── TextHighlighting │ └── HighlightGroup.cs ├── UserSettings.cs └── Utility.cs ├── Deobfuscation ├── Deobfuscator.cs ├── Deobfuscators.cs └── Deobfuscators │ └── UnityCodeGuard.cs ├── Dependencies ├── ICSharpCode.Decompiler.dll ├── ICSharpCode.NRefactory.CSharp.dll ├── ICSharpCode.NRefactory.dll ├── ICSharpCode.TextEditor.dll ├── LinqBridge.dll ├── Mono.Cecil.dll └── Newtonsoft.Json.dll ├── Docs ├── DocsData.cs ├── DocsGenerator.cs ├── DocsHook.cs ├── DocsMethodArgument.cs └── DocsMethodData.cs ├── Forms ├── ModifyForm.Designer.cs ├── ModifyForm.cs ├── ModifyForm.resx ├── NewProjectForm.Designer.cs ├── NewProjectForm.cs ├── NewProjectForm.resx ├── PatchProcessForm.Designer.cs ├── PatchProcessForm.cs └── PatchProcessForm.resx ├── OpjData ├── Enums.cs ├── Fields │ └── Field.cs ├── Hooks │ ├── Hook.cs │ ├── HookType.cs │ ├── InitOxide.cs │ ├── MethodSignature.cs │ ├── Modify.cs │ └── Simple.cs ├── Manifest.cs ├── Modifiers │ ├── Modifier.cs │ └── ModifierSignature.cs └── Project.cs ├── Oxide.Patcher.csproj ├── PatcherForm.Designer.cs ├── PatcherForm.cs ├── PatcherForm.resx ├── Patching ├── ILWeaver.cs ├── OxideDefinitions │ ├── OxideDefinitions.cs │ └── OxideTypeDefinition.cs ├── Patcher.cs └── PatcherAssemblyResolver.cs ├── Program.cs ├── Properties ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── Resources ├── Icons.Designer.cs ├── Icons.resx ├── book_add.png ├── book_go.png ├── cog_edit.png ├── cross.png ├── door_in.png ├── folder.png ├── folder_flagged.png ├── lightning.png ├── logo.ico └── wand.png └── Views ├── ClassViewControl.Designer.cs ├── ClassViewControl.cs ├── ClassViewControl.resx ├── FieldAndPropertyViewControl.Designer.cs ├── FieldAndPropertyViewControl.cs ├── FieldAndPropertyViewControl.resx ├── FieldSettingsControl.Designer.cs ├── FieldSettingsControl.cs ├── FieldSettingsControl.resx ├── FieldViewControl.Designer.cs ├── FieldViewControl.cs ├── FieldViewControl.resx ├── HookSettingsControl.cs ├── HookViewControl.Designer.cs ├── HookViewControl.cs ├── HookViewControl.resx ├── InitOxideHookSettingsControl.Designer.cs ├── InitOxideHookSettingsControl.cs ├── InitOxideHookSettingsControl.resx ├── InterfaceViewControl.Designer.cs ├── InterfaceViewControl.cs ├── InterfaceViewControl.resx ├── MethodViewControl.Designer.cs ├── MethodViewControl.cs ├── MethodViewControl.resx ├── ModifierSettingsControl.Designer.cs ├── ModifierSettingsControl.cs ├── ModifierSettingsControl.resx ├── ModifierViewControl.Designer.cs ├── ModifierViewControl.cs ├── ModifierViewControl.resx ├── ModifyHookSettingsControl.Designer.cs ├── ModifyHookSettingsControl.cs ├── ModifyHookSettingsControl.resx ├── ProjectSettingsControl.Designer.cs ├── ProjectSettingsControl.cs ├── ProjectSettingsControl.resx ├── SimpleHookSettingsControl.Designer.cs ├── SimpleHookSettingsControl.cs └── SimpleHookSettingsControl.resx /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://editorconfig.org 2 | root = true 3 | 4 | [*.cs] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | *.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.csproj merge=binary 26 | #*.dbproj merge=binary 27 | #*.fsproj merge=binary 28 | #*.lsproj merge=binary 29 | #*.modelproj merge=binary 30 | #*.sln merge=binary 31 | #*.sqlproj merge=binary 32 | #*.vbproj merge=binary 33 | #*.vcproj merge=binary 34 | #*.vcxproj merge=binary 35 | #*.wixproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # Behavior for image files 40 | # 41 | # Image files are treated as binary by default. 42 | ############################################################################### 43 | *.gif binary 44 | *.ico binary 45 | *.jpg binary 46 | *.png binary 47 | 48 | ############################################################################### 49 | # Custom 50 | ############################################################################### 51 | *.rc text 52 | *.c text 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ins. 3 | 4 | # Build output 5 | [Bb]in/ 6 | [Dd]ebug/ 7 | [Dd]ebugPublic/ 8 | [Oo]bj/ 9 | [Rr]elease/ 10 | [Rr]eleases/ 11 | build/ 12 | bld/ 13 | x64/ 14 | x86/ 15 | 16 | # Build testing 17 | ## MSTest 18 | [Tt]est[Rr]esult*/ 19 | [Bb]uild[Ll]og.* 20 | ## NUnit 21 | *.VisualState.xml 22 | TestResult.xml 23 | 24 | # NuGet packages 25 | *.nupkg 26 | **/packages/* 27 | !**/packages/build/ 28 | !**/packages/repositories.config 29 | 30 | # Project-specific files 31 | .deploy 32 | 33 | # Roslyn caches 34 | *.ide/ 35 | 36 | # User-specific files 37 | .idea/ 38 | *.sln.docstates 39 | *.suo 40 | *.user 41 | *.userosscache 42 | *.userprefs 43 | 44 | # Visual C++ cache files 45 | ipch/ 46 | *.aps 47 | *.ncb 48 | *.opensdf 49 | *.sdf 50 | *.cachefile 51 | 52 | # Visual Studio 53 | .vs/ 54 | *.psess 55 | *.vsp 56 | *.vspx 57 | 58 | # Visual Studio add-ins 59 | ## DotCover code coverage tool 60 | *.dotCover 61 | ## JustCode add-in 62 | .JustCode 63 | ## ReSharper add-in 64 | _ReSharper*/ 65 | *.[Rr]e[Ss]harper 66 | *.DotSettings.user 67 | ## TeamCity add-in 68 | _TeamCity* 69 | -------------------------------------------------------------------------------- /Oxide.Patcher.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 14 3 | VisualStudioVersion = 14.0.25123.0 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oxide.Patcher", "src\Oxide.Patcher.csproj", "{66ED76BE-D14B-4BDA-87FA-6254A28D58E1}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {66ED76BE-D14B-4BDA-87FA-6254A28D58E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {66ED76BE-D14B-4BDA-87FA-6254A28D58E1}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {66ED76BE-D14B-4BDA-87FA-6254A28D58E1}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {66ED76BE-D14B-4BDA-87FA-6254A28D58E1}.Release|Any CPU.Build.0 = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(SolutionProperties) = preSolution 19 | HideSolutionNode = FALSE 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Oxide Patcher [![Build Status](https://travis-ci.org/OxideMod/OxidePatcher.png)](https://travis-ci.org/OxideMod/OxidePatcher) 2 | =============== 3 | 4 | Oxide 2 is a complete rewrite of the popular, original Oxide mod for the game Rust. Oxide 2 has a focus on modularity and extensibility. The core is highly abstracted and loosely coupled, and could be used to mod any game that uses .NET such as 7 Days to Die, The Forest, Space Engineers, and more. The patcher is only needed for those who want to experiment with adding new hooks or modding other games. 5 | 6 | Patching Games 7 | -------------- 8 | 9 | 1. Navigate to your installation of Oxide and locate Oxide.Core.dll. Copy it and paste it next to the freshly compiled OxidePatcher.exe. 10 | 2. Navigate to .opj for the target game and open it in a plain text editor. It is formatted as a JSON file. 11 | 3. Find the "TargetDirectory" field in the json text and change the value to be the "Managed" folder of your target game server installation. 12 | 4. Launch the patcher. Go to File -> Open Project, and open the .opj. 13 | 5. If all goes well, the hooks and assembly list should appear on the tree view to the left. 14 | 6. To patch, click the wand icon on the toolbar. 15 | 7. To add a hook, navigate to the desired method from the desired assembly and click the "Hook this Method" button. 16 | 8. To include more assemblies, right click on any red-cross assembly and select "Add to Project". 17 | 18 | Notes 19 | ----- 20 | 21 | * You should work on a vanilla version of the target game. 22 | * The patcher will make copies of the original DLLs and append "_Original" to them, and it will use them as the input when patching. This means it's safe to make a few changes and patch over and over again. 23 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Common/Decompiler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Threading.Tasks; 4 | using ICSharpCode.Decompiler; 5 | using ICSharpCode.Decompiler.Ast; 6 | using Mono.Cecil; 7 | using Mono.Cecil.Cil; 8 | using Mono.Collections.Generic; 9 | using Oxide.Patcher.Patching; 10 | 11 | namespace Oxide.Patcher.Common 12 | { 13 | /// 14 | /// Contains code decompiling utility methods 15 | /// 16 | public static class Decompiler 17 | { 18 | /// 19 | /// Decompiles the specified method body to MSIL 20 | /// 21 | /// 22 | /// 23 | public static string DecompileToIL(MethodBody body) 24 | { 25 | StringBuilder sb = new StringBuilder(); 26 | if (body?.Instructions == null) 27 | { 28 | return null; 29 | } 30 | 31 | Collection instructions = body.Instructions; 32 | for (int i = 0; i < instructions.Count; i++) 33 | { 34 | Instruction inst = instructions[i]; 35 | sb.AppendLine(inst.ToString().Replace("\n", "\\n")); 36 | } 37 | return sb.ToString(); 38 | } 39 | 40 | public static async Task GetSourceCode(MethodDefinition methodDefinition, ILWeaver weaver = null) 41 | { 42 | return await Task.Run(() => 43 | { 44 | try 45 | { 46 | if (weaver != null) 47 | { 48 | weaver.Apply(methodDefinition.Body); 49 | } 50 | 51 | DecompilerSettings settings = new DecompilerSettings { UsingDeclarations = false }; 52 | DecompilerContext context = new DecompilerContext(methodDefinition.Module) 53 | { 54 | CurrentType = methodDefinition.DeclaringType, 55 | Settings = settings 56 | }; 57 | AstBuilder astBuilder = new AstBuilder(context); 58 | astBuilder.AddMethod(methodDefinition); 59 | PlainTextOutput textOutput = new PlainTextOutput(); 60 | astBuilder.GenerateCode(textOutput); 61 | return textOutput.ToString(); 62 | } 63 | catch (Exception ex) 64 | { 65 | return "Error in creating source code from IL: " + ex.Message + Environment.NewLine + ex.StackTrace; 66 | } 67 | finally 68 | { 69 | if (weaver != null) 70 | { 71 | methodDefinition.Body = null; 72 | } 73 | } 74 | }); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Common/Extensions/StringEx.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher.Common.Extensions 2 | { 3 | public static class StringEx 4 | { 5 | /// 6 | /// Get the string slice between the two indexes. 7 | /// Inclusive for start index, exclusive for end index. 8 | /// 9 | public static string Slice(this string source, int start, int end) 10 | { 11 | if (end < 0) // Keep this for negative end support 12 | { 13 | end = source.Length + end; 14 | } 15 | int len = end - start; // Calculate length 16 | return source.Substring(start, len); // Return Substring of length 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Common/JsonHelpers/HookConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Oxide.Patcher.Hooks; 4 | 5 | namespace Oxide.Patcher.Common.JsonHelpers 6 | { 7 | public class HookConverter : JsonConverter 8 | { 9 | public override bool CanWrite => false; 10 | 11 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | 16 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 17 | { 18 | string hookTypeName = reader.GetNextPropertyValue("Type"); 19 | if (string.IsNullOrEmpty(hookTypeName)) 20 | { 21 | throw new Exception("Could not read the hook type"); 22 | } 23 | 24 | Type hookType = Hook.GetHookType(hookTypeName); 25 | if (hookType == null) 26 | { 27 | throw new Exception($"Unknown hook type '{hookTypeName}'"); 28 | } 29 | 30 | if (!(Activator.CreateInstance(hookType) is Hook hookDefinition)) 31 | { 32 | throw new Exception("Failed to create instance of hook definition"); 33 | } 34 | 35 | reader.PopulateNextHookObj(serializer, hookDefinition); 36 | reader.ReadToNextTokenOfType(JsonToken.EndObject); 37 | 38 | return hookDefinition; 39 | } 40 | 41 | public override bool CanConvert(Type objectType) 42 | { 43 | return typeof(Hook).IsAssignableFrom(objectType); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Common/JsonHelpers/HookRef.cs: -------------------------------------------------------------------------------- 1 | using Oxide.Patcher.Hooks; 2 | 3 | namespace Oxide.Patcher.Common.JsonHelpers 4 | { 5 | public class HookRef 6 | { 7 | public string Type; 8 | public Hook Hook; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Common/JsonHelpers/HooksListConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json; 4 | using Oxide.Patcher.Hooks; 5 | 6 | namespace Oxide.Patcher.Common.JsonHelpers 7 | { 8 | /// 9 | /// Converter to handle the writing of hooks back into the json file 10 | /// 11 | public class HooksListConverter : JsonConverter 12 | { 13 | public override bool CanRead => false; 14 | 15 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 16 | { 17 | if (!(value is List hooks)) 18 | { 19 | throw new InvalidCastException("Could not cast object to List when writing hook list"); 20 | } 21 | 22 | HookRef[] refs = new HookRef[hooks.Count]; 23 | for (int i = 0; i < refs.Length; i++) 24 | { 25 | HookRef hookRef = refs[i] = new HookRef(); 26 | 27 | hookRef.Hook = hooks[i]; 28 | hookRef.Type = hookRef.Hook.GetType().Name; 29 | hookRef.Hook.BaseHookName = hookRef.Hook.BaseHook?.Name; 30 | } 31 | 32 | serializer.Serialize(writer, refs); 33 | } 34 | 35 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | 40 | public override bool CanConvert(Type objectType) 41 | { 42 | return typeof(Hook).IsAssignableFrom(objectType); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Common/JsonHelpers/JsonReaderEx.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Oxide.Patcher.Hooks; 3 | 4 | namespace Oxide.Patcher.Common.JsonHelpers 5 | { 6 | public static class JsonReaderEx 7 | { 8 | /// 9 | /// Move the reader to the next token that matches the target token type 10 | /// 11 | /// 12 | /// Target type of the token to read up to 13 | public static void ReadToNextTokenOfType(this JsonReader reader, JsonToken tokenType) 14 | { 15 | while (reader.Read()) 16 | { 17 | if (reader.TokenType == tokenType) 18 | { 19 | return; 20 | } 21 | } 22 | } 23 | 24 | /// 25 | /// Get the next value of the next property matching the target property name 26 | /// 27 | /// 28 | /// Target property name 29 | /// Type to cast to and return 30 | /// Value of the property casted to T 31 | public static T GetNextPropertyValue(this JsonReader reader, string propertyName) where T : class 32 | { 33 | while (reader.Read()) 34 | { 35 | //If it is a property and matches the name then move onto the value token and return 36 | if (reader.TokenType == JsonToken.PropertyName && reader.Value as string == propertyName && reader.Read()) 37 | { 38 | return reader.Value as T; 39 | } 40 | } 41 | 42 | return null; 43 | } 44 | 45 | /// 46 | /// Populate the next hook object with the hook data 47 | /// 48 | /// 49 | /// Current json serialiser in the read method 50 | /// Hook data to populate with 51 | public static void PopulateNextHookObj(this JsonReader reader, JsonSerializer serialiser, Hook hook) 52 | { 53 | while (reader.Read()) 54 | { 55 | //If it is the "Hook" property, move onto the next StartObject token and populate 56 | if (reader.TokenType == JsonToken.PropertyName && reader.Value as string == "Hook" && reader.Read()) 57 | { 58 | serialiser.Populate(reader, hook); 59 | return; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Common/TextHighlighting/HighlightGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using ICSharpCode.TextEditor; 5 | using ICSharpCode.TextEditor.Document; 6 | 7 | namespace Oxide.Patcher.Common.TextHighlighting 8 | { 9 | public class HighlightGroup : IDisposable 10 | { 11 | private readonly List _markers = new List(); 12 | private readonly TextEditorControl _editorControl; 13 | private readonly IDocument _document; 14 | 15 | public HighlightGroup(TextEditorControl editorControl) 16 | { 17 | _editorControl = editorControl; 18 | _document = _editorControl.Document; 19 | } 20 | 21 | public void AddMarker(TextMarker marker) 22 | { 23 | _markers.Add(marker); 24 | _document.MarkerStrategy.AddMarker(marker); 25 | } 26 | 27 | private void ClearMarkers() 28 | { 29 | foreach (TextMarker m in _markers) 30 | { 31 | _document.MarkerStrategy.RemoveMarker(m); 32 | } 33 | 34 | _markers.Clear(); 35 | _editorControl.Invoke(new Action(_editorControl.Refresh)); 36 | } 37 | 38 | public void Dispose() 39 | { 40 | ClearMarkers(); 41 | GC.SuppressFinalize(this); 42 | } 43 | 44 | ~HighlightGroup() 45 | { 46 | Dispose(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Common/UserSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.IO; 3 | using System.Windows.Forms; 4 | using Newtonsoft.Json; 5 | 6 | namespace Oxide.Patcher.Common 7 | { 8 | /// 9 | /// A set of persistent window settings 10 | /// 11 | public class UserSettings 12 | { 13 | /// 14 | /// Gets or sets the form position 15 | /// 16 | public Point FormPosition { get; set; } 17 | 18 | /// 19 | /// Gets or sets the form size 20 | /// 21 | public Size FormSize { get; set; } 22 | 23 | /// 24 | /// Gets or sets the window state 25 | /// 26 | public FormWindowState WindowState { get; set; } 27 | 28 | /// 29 | /// Gets or sets the last directory used to open or save a project 30 | /// 31 | public string LastProjectDirectory { get; set; } 32 | 33 | // The settings filename 34 | private const string FileName = "oxide-patcher-settings.json"; 35 | 36 | private UserSettings Initialise() 37 | { 38 | // Fill in defaults 39 | Rectangle workingarea = Screen.GetWorkingArea(new Point(0, 0)); 40 | FormPosition = new Point(workingarea.Left + workingarea.Width / 5, workingarea.Top + workingarea.Height / 5); 41 | FormSize = new Size(workingarea.Width * 3 / 5, workingarea.Height * 3 / 5); 42 | WindowState = FormWindowState.Normal; 43 | LastProjectDirectory = string.Empty; 44 | 45 | return this; 46 | } 47 | 48 | /// 49 | /// Saves these settings 50 | /// 51 | public void Save() 52 | { 53 | File.WriteAllText(FileName, JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })); 54 | } 55 | 56 | /// 57 | /// Loads the settings 58 | /// 59 | /// 60 | public static UserSettings Load() 61 | { 62 | if (!File.Exists(FileName)) 63 | { 64 | return new UserSettings().Initialise(); 65 | } 66 | 67 | string text = File.ReadAllText(FileName); 68 | return JsonConvert.DeserializeObject(text); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Deobfuscation/Deobfuscator.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | 3 | namespace Oxide.Patcher.Deobfuscation 4 | { 5 | /// 6 | /// Represents a deobfuscation method for a specific type of obfuscation 7 | /// 8 | public abstract class Deobfuscator 9 | { 10 | /// 11 | /// Gets the name of this deobfuscator 12 | /// 13 | public abstract string Name { get; } 14 | 15 | /// 16 | /// Gets the priority of this deobfuscator 17 | /// 18 | public abstract int Priority { get; } 19 | 20 | /// 21 | /// Returns if this deobfuscator is capable of deobfuscating the specified assembly 22 | /// 23 | /// 24 | /// 25 | public abstract bool CanDeobfuscate(AssemblyDefinition assembly); 26 | 27 | /// 28 | /// Deobfuscates the specified assembly, returning a success value 29 | /// 30 | /// 31 | /// 32 | public abstract bool Deobfuscate(AssemblyDefinition assembly); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Deobfuscation/Deobfuscators.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Oxide.Patcher.Deobfuscation 7 | { 8 | /// 9 | /// Contains methods for finding a deobfuscator 10 | /// 11 | public static class Deobfuscators 12 | { 13 | private static Deobfuscator[] deobfuscators; 14 | 15 | static Deobfuscators() 16 | { 17 | List list = new List(); 18 | Type deobfuscator = typeof(Deobfuscator); 19 | foreach (Type type in AppDomain.CurrentDomain.GetAssemblies() 20 | .SelectMany(a => a.GetTypes()) 21 | .Where(t => deobfuscator.IsAssignableFrom(t) && !t.IsAbstract)) 22 | { 23 | list.Add(Activator.CreateInstance(type) as Deobfuscator); 24 | } 25 | list.Sort((a, b) => Comparer.Default.Compare(a.Priority, b.Priority)); 26 | deobfuscators = list.ToArray(); 27 | } 28 | 29 | /// 30 | /// Finds a deobfuscator that can deobfuscate the specified assembly 31 | /// 32 | /// 33 | /// 34 | public static Deobfuscator Find(AssemblyDefinition assembly) 35 | { 36 | for (int i = 0; i < deobfuscators.Length; i++) 37 | { 38 | if (deobfuscators[i].CanDeobfuscate(assembly)) 39 | { 40 | return deobfuscators[i]; 41 | } 42 | } 43 | return null; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Dependencies/ICSharpCode.Decompiler.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/ICSharpCode.Decompiler.dll -------------------------------------------------------------------------------- /src/Dependencies/ICSharpCode.NRefactory.CSharp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/ICSharpCode.NRefactory.CSharp.dll -------------------------------------------------------------------------------- /src/Dependencies/ICSharpCode.NRefactory.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/ICSharpCode.NRefactory.dll -------------------------------------------------------------------------------- /src/Dependencies/ICSharpCode.TextEditor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/ICSharpCode.TextEditor.dll -------------------------------------------------------------------------------- /src/Dependencies/LinqBridge.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/LinqBridge.dll -------------------------------------------------------------------------------- /src/Dependencies/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/Mono.Cecil.dll -------------------------------------------------------------------------------- /src/Dependencies/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Dependencies/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /src/Docs/DocsData.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher.Docs 2 | { 3 | public class DocsData 4 | { 5 | public DocsHook[] Hooks { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Docs/DocsGenerator.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.Decompiler; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Windows.Forms; 7 | 8 | using Mono.Cecil; 9 | 10 | using Newtonsoft.Json; 11 | using Oxide.Patcher.Common; 12 | using Oxide.Patcher.Hooks; 13 | using Oxide.Patcher.Patching; 14 | 15 | namespace Oxide.Patcher.Docs 16 | { 17 | public static class DocsGenerator 18 | { 19 | internal static AssemblyLoader AssemblyLoader; 20 | 21 | public static void GenerateFile(Project project, AssemblyLoader assemblyLoader, string outputFile = "docs.json") 22 | { 23 | AssemblyLoader = PatcherForm.MainForm != null ? PatcherForm.MainForm.AssemblyLoader : new AssemblyLoader(project, string.Empty); 24 | DocsData docsData = new DocsData(); 25 | List hooks = new List(); 26 | 27 | foreach (Manifest manifest in project.Manifests) 28 | { 29 | foreach (Hook hook in manifest.Hooks) 30 | { 31 | try 32 | { 33 | MethodDefinition methodDef = assemblyLoader.GetMethod(hook.AssemblyName, hook.TypeName, hook.Signature); 34 | if (methodDef == null) 35 | { 36 | throw new Exception($"Failed to find method definition for hook {hook.Name}"); 37 | } 38 | 39 | ILWeaver weaver = new ILWeaver(methodDef.Body) { Module = methodDef.Module }; 40 | 41 | hook.PreparePatch(methodDef, weaver); 42 | hook.ApplyPatch(methodDef, weaver); 43 | 44 | weaver.Apply(methodDef.Body); 45 | 46 | DocsHook docsHook = new DocsHook(hook, methodDef, project.TargetDirectory); 47 | hooks.Add(docsHook); 48 | 49 | methodDef.Body = null; 50 | } 51 | catch (NotSupportedException) { } 52 | catch (DecompilerException) 53 | { 54 | Console.WriteLine($"Failed to decompile method for hook {hook.Name}"); 55 | } 56 | catch (Exception e) 57 | { 58 | if (PatcherForm.MainForm != null) 59 | { 60 | MessageBox.Show($"There was an error while generating docs data for '{hook.Name}'. ({e})", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 61 | } 62 | else 63 | { 64 | Console.WriteLine($"There was an error while generating docs data for '{hook.Name}'. ({e})"); 65 | } 66 | } 67 | } 68 | } 69 | 70 | docsData.Hooks = hooks.ToArray(); 71 | 72 | //Save file 73 | File.WriteAllText(outputFile, JsonConvert.SerializeObject(docsData, new JsonSerializerSettings 74 | { 75 | NullValueHandling = NullValueHandling.Ignore, 76 | Formatting = Formatting.Indented 77 | })); 78 | 79 | if (PatcherForm.MainForm != null) 80 | { 81 | MessageBox.Show("Successfully generated docs data file.", "Oxide Patcher", 82 | MessageBoxButtons.OK, MessageBoxIcon.Information); 83 | 84 | PatcherForm.MainForm.Invoke((MethodInvoker)delegate 85 | { 86 | PatcherForm.MainForm.SetDocsButtonEnabled(true); 87 | }); 88 | } 89 | } 90 | 91 | private static MethodDefinition GetMethod(AssemblyDefinition assemblyDefinition, string typeName, MethodSignature signature) 92 | { 93 | try 94 | { 95 | TypeDefinition type = assemblyDefinition.Modules.SelectMany(m => m.GetTypes()).Single(t => t.FullName == typeName); 96 | return type.Methods.Single(m => MethodSignatureMatches(Utility.GetMethodSignature(m), signature)); 97 | } 98 | catch (Exception e) 99 | { 100 | return null; 101 | } 102 | } 103 | 104 | // Ignore exposure for now 105 | private static bool MethodSignatureMatches(MethodSignature obj1, MethodSignature othersig) 106 | { 107 | if (obj1.Name != othersig.Name) 108 | { 109 | return false; 110 | } 111 | 112 | if (obj1.Parameters.Length != othersig.Parameters.Length) 113 | { 114 | return false; 115 | } 116 | 117 | for (int i = 0; i < obj1.Parameters.Length; i++) 118 | { 119 | if (obj1.Parameters[i] != othersig.Parameters[i]) 120 | { 121 | return false; 122 | } 123 | } 124 | 125 | return true; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Docs/DocsMethodArgument.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher.Docs 2 | { 3 | public class DocsMethodArgument 4 | { 5 | public string Type { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Docs/DocsMethodData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Mono.Cecil; 3 | using Oxide.Patcher.Common; 4 | 5 | namespace Oxide.Patcher.Docs 6 | { 7 | public class DocsMethodData 8 | { 9 | public string MethodName { get; set; } 10 | public string ReturnType { get; set; } 11 | public Dictionary Arguments { get; set; } = new Dictionary(); 12 | 13 | public DocsMethodData(MethodDefinition methodDef) 14 | { 15 | MethodName = methodDef.Name; 16 | ReturnType = Utility.TransformType(methodDef.ReturnType.FullName); 17 | 18 | foreach (ParameterDefinition parameterDef in methodDef.Parameters) 19 | { 20 | Arguments[parameterDef.Name] = Utility.TransformType(parameterDef.ParameterType.FullName); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Forms/ModifyForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Forms/NewProjectForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace Oxide.Patcher 7 | { 8 | public partial class NewProjectForm : Form 9 | { 10 | public NewProjectForm() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void NewProjectForm_Load(object sender, EventArgs e) 16 | { 17 | // PatcherForm owner = Owner as PatcherForm; 18 | // PatcherFormSettings settings = owner.CurrentSettings; 19 | 20 | // selectdirectorydialog.SelectedPath = settings.LastTargetDirectory; 21 | directorytextbox.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 22 | 23 | //selectfilenamedialog.FileName = settings.LastProjectDirectory; 24 | } 25 | 26 | private void selectdirectorybutton_Click(object sender, EventArgs e) 27 | { 28 | DialogResult result = selectdirectorydialog.ShowDialog(this); 29 | if (result == DialogResult.OK) 30 | { 31 | if (!Directory.EnumerateFiles(selectdirectorydialog.SelectedPath).Any(x => x.EndsWith(".dll") || x.EndsWith(".exe"))) 32 | { 33 | if (MessageBox.Show(this, "The specified directory does not contain any dll files. Continue anyway?", "Oxide Patcher", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) 34 | { 35 | return; 36 | } 37 | } 38 | 39 | //PatcherForm owner = Owner as PatcherForm; 40 | 41 | //PatcherFormSettings settings = owner.CurrentSettings; 42 | //settings.LastTargetDirectory = selectdirectorydialog.SelectedPath; 43 | //settings.Save(); 44 | 45 | directorytextbox.Text = selectdirectorydialog.SelectedPath; 46 | } 47 | } 48 | 49 | private void selectfilenamebutton_Click(object sender, EventArgs e) 50 | { 51 | DialogResult result = selectfilenamedialog.ShowDialog(this); 52 | if (result == DialogResult.OK) 53 | { 54 | //PatcherForm owner = Owner as PatcherForm; 55 | 56 | //PatcherFormSettings settings = owner.CurrentSettings; 57 | //settings.LastProjectDirectory = Path.GetDirectoryName(selectfilenamedialog.FileName); 58 | //settings.Save(); 59 | 60 | filenametextbox.Text = selectfilenamedialog.FileName; 61 | } 62 | } 63 | 64 | private void cancelbutton_Click(object sender, EventArgs e) 65 | { 66 | Close(); 67 | } 68 | 69 | private void createbutton_Click(object sender, EventArgs e) 70 | { 71 | // Verify 72 | if (!Directory.Exists(directorytextbox.Text)) 73 | { 74 | MessageBox.Show(this, "The target directory is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 75 | return; 76 | } 77 | 78 | if (!Directory.Exists(Path.GetDirectoryName(filenametextbox.Text))) 79 | { 80 | MessageBox.Show(this, "The filename is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 81 | return; 82 | } 83 | 84 | if (nametextbox.TextLength == 0) 85 | { 86 | MessageBox.Show(this, "The project name is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 87 | return; 88 | } 89 | 90 | // Create project 91 | Project newproj = new Project(); 92 | newproj.Name = nametextbox.Text; 93 | newproj.TargetDirectory = directorytextbox.Text; 94 | newproj.Save(filenametextbox.Text); 95 | 96 | // Set parent form to load it 97 | PatcherForm owner = Owner as PatcherForm; 98 | owner.OpenProject(filenametextbox.Text); 99 | 100 | // Close 101 | Close(); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Forms/PatchProcessForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace Oxide.Patcher 9 | { 10 | public partial class PatchProcessForm : Form 11 | { 12 | private delegate void WriteLogDelegate(string message); 13 | 14 | private delegate void WriteProgressDelegate(string message); 15 | 16 | /// 17 | /// Gets or sets the project to patch 18 | /// 19 | public Project PatchProject { get; set; } 20 | 21 | private Task thetask; 22 | 23 | private int errors; 24 | 25 | public PatchProcessForm() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | protected override void OnLoad(EventArgs e) 31 | { 32 | base.OnLoad(e); 33 | 34 | errors = 0; 35 | 36 | foreach (Manifest manifest in PatchProject.Manifests) 37 | { 38 | progressbar.Maximum += manifest.Hooks.Count(h => h.BaseHook == null || h.BaseHook != null && h.Flagged) + manifest.Modifiers.Count + manifest.Fields.Count + 2; 39 | } 40 | 41 | thetask = new Task(Worker); 42 | thetask.Start(); 43 | } 44 | 45 | protected override void OnFormClosing(FormClosingEventArgs e) 46 | { 47 | if (!thetask.IsCompleted) 48 | { 49 | e.Cancel = true; 50 | return; 51 | } 52 | base.OnFormClosing(e); 53 | } 54 | 55 | private void WriteLog(string message) 56 | { 57 | statuslabel.Text = message; 58 | patchlog.Items.Add(message); 59 | 60 | patchlog.SelectedIndex = patchlog.Items.Count - 1; 61 | } 62 | 63 | private void ReportProgress(string message) 64 | { 65 | if (message.Contains("Failed to apply")) 66 | { 67 | errors++; 68 | if (errors == 1) 69 | { 70 | progressbar.SetState(2); 71 | } 72 | } 73 | 74 | if (progressbar.Maximum != progressbar.Value) 75 | { 76 | progressbar.Value++; 77 | progressbar.Refresh(); 78 | } 79 | 80 | if (message.Contains(Environment.NewLine)) 81 | { 82 | string[] items = message.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); 83 | statuslabel.Text = items[0]; 84 | for (int i = 0; i < items.Length; i++) 85 | { 86 | patchlog.Items.Add(items[i]); 87 | } 88 | } 89 | else 90 | { 91 | statuslabel.Text = message; 92 | patchlog.Items.Add(message); 93 | } 94 | 95 | patchlog.SelectedIndex = patchlog.Items.Count - 1; 96 | } 97 | 98 | private void OnWorkComplete() 99 | { 100 | copybutton.Enabled = true; 101 | closebutton.Enabled = true; 102 | } 103 | 104 | #region Worker Thread 105 | 106 | private void WorkerWriteLog(string format, params object[] args) 107 | { 108 | Invoke(new WriteLogDelegate(WriteLog), string.Format(format, args)); 109 | } 110 | 111 | private void WorkerReportProgress(string format, params object[] args) 112 | { 113 | Invoke(new WriteProgressDelegate(ReportProgress), string.Format(format, args)); 114 | } 115 | 116 | private void WorkerCompleteWork() 117 | { 118 | Invoke(new Action(OnWorkComplete)); 119 | } 120 | 121 | private void Worker() 122 | { 123 | WorkerWriteLog("Started patching."); 124 | try 125 | { 126 | Patching.Patcher patcher = new Patching.Patcher(PatchProject); 127 | patcher.OnLogMessage += msg => WorkerReportProgress(msg); 128 | patcher.Patch(); 129 | } 130 | catch (Exception ex) 131 | { 132 | WorkerWriteLog("ERROR: {0}", ex.Message); 133 | } 134 | 135 | if (errors > 0) 136 | { 137 | WorkerWriteLog($"Failed to apply {errors} {(errors == 1 ? "hook" : "hooks")}"); 138 | } 139 | else 140 | { 141 | WorkerWriteLog("Patch complete."); 142 | } 143 | 144 | WorkerCompleteWork(); 145 | } 146 | 147 | #endregion Worker Thread 148 | 149 | private void closebutton_Click(object sender, EventArgs e) 150 | { 151 | Close(); 152 | } 153 | 154 | private void copybutton_Click(object sender, EventArgs e) 155 | { 156 | StringBuilder sb = new StringBuilder(); 157 | for (int i = 0; i < patchlog.Items.Count; i++) 158 | { 159 | sb.AppendLine((string)patchlog.Items[i]); 160 | } 161 | Clipboard.SetText(sb.ToString()); 162 | } 163 | } 164 | 165 | public static class ModifyProgressBarColor 166 | { 167 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)] 168 | private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l); 169 | public static void SetState(this ProgressBar pBar, int state) 170 | { 171 | SendMessage(pBar.Handle, 1040, (IntPtr)state, IntPtr.Zero); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Forms/PatchProcessForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/OpjData/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher 2 | { 3 | public enum MethodExposure 4 | { 5 | Private, 6 | Protected, 7 | Public, 8 | Internal 9 | } 10 | 11 | public enum Exposure 12 | { 13 | Private, 14 | Protected, 15 | Public, 16 | Internal, 17 | Static, 18 | Null 19 | } 20 | 21 | public enum ModifierType 22 | { 23 | Field, 24 | Method, 25 | Property, 26 | Type 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/OpjData/Fields/Field.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Oxide.Patcher.Patching.OxideDefinitions; 3 | using Oxide.Patcher.Views; 4 | using System; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Windows.Forms; 8 | 9 | namespace Oxide.Patcher.Fields 10 | { 11 | /// 12 | /// Represents a hook that is applied to single method and calls a single Oxide hook 13 | /// 14 | public class Field 15 | { 16 | /// 17 | /// Gets or sets a name for this field 18 | /// 19 | public string Name { get; set; } 20 | 21 | /// 22 | /// Gets or sets the name of the assembly in which the target resides 23 | /// 24 | public string AssemblyName { get; set; } 25 | 26 | /// 27 | /// Gets or sets the fully qualified name for the type in which the target resides 28 | /// 29 | public string TypeName { get; set; } 30 | 31 | /// 32 | /// Gets or sets the field to be added 33 | /// 34 | public string FieldType { get; set; } 35 | 36 | /// 37 | /// Gets or sets if this modifier has been flagged 38 | /// 39 | public bool Flagged { get; set; } 40 | 41 | public Field() 42 | { 43 | } 44 | 45 | public Field(TypeDefinition type, string assembly) 46 | { 47 | Name = "NewField"; 48 | TypeName = type.FullName; 49 | FieldType = string.Empty; 50 | AssemblyName = assembly; 51 | } 52 | 53 | private void ShowMessage(string message, string header, Patching.Patcher patcher = null) 54 | { 55 | if (patcher != null) 56 | { 57 | patcher.Log(message); 58 | } 59 | else if (PatcherForm.MainForm != null) 60 | { 61 | MessageBox.Show(message, header, MessageBoxButtons.OK, MessageBoxIcon.Error); 62 | } 63 | else 64 | { 65 | Console.WriteLine($"{header}: {message}"); 66 | } 67 | } 68 | 69 | /// 70 | /// Creates the settings view control for this hook 71 | /// 72 | /// 73 | public FieldSettingsControl CreateSettingsView() 74 | { 75 | return new FieldSettingsControl { Field = this }; 76 | } 77 | 78 | internal bool IsValid(Project project, bool warn = false, bool skipOriginal = false) 79 | { 80 | string assemblyName = $"{AssemblyName.Replace(".dll", "")}"; 81 | if (!skipOriginal) 82 | { 83 | assemblyName = $"{AssemblyName.Replace(".dll", "")}_Original"; 84 | } 85 | 86 | string targetAssemblyFile = Path.Combine(project.TargetDirectory, $"{assemblyName}.dll"); 87 | AssemblyDefinition targetAssembly = AssemblyDefinition.ReadAssembly(targetAssemblyFile); 88 | TypeDefinition target = targetAssembly.MainModule.GetType(TypeName); 89 | if (target == null) 90 | { 91 | if (warn) 92 | { 93 | ShowMessage($"The type '{TypeName}' in '{AssemblyName}' to add the field '{Name}' into could not be found!", "Target type missing"); 94 | } 95 | 96 | return false; 97 | } 98 | 99 | if (target.Fields.Any(x => x.Name == Name)) 100 | { 101 | if (warn) 102 | { 103 | ShowMessage($"A field with the name '{Name}' already exists in the targetted class!", "Duplicate name"); 104 | } 105 | 106 | return false; 107 | } 108 | 109 | foreach (Field field in project.Manifests.Find(x => x.AssemblyName == AssemblyName).Fields) 110 | { 111 | if (field == this || field.Name != Name) 112 | { 113 | continue; 114 | } 115 | 116 | if (warn) 117 | { 118 | ShowMessage($"A field with the name '{Name}' is already being added to the targetted class!", "Duplicate name"); 119 | } 120 | 121 | return false; 122 | } 123 | 124 | if (string.IsNullOrEmpty(FieldType)) 125 | { 126 | return true; 127 | } 128 | 129 | if (!OxideDefinitions.TryParseType(FieldType, out _, out string error)) 130 | { 131 | if (warn) 132 | { 133 | ShowMessage($"Couldn't resolve the field type: {error}", "Error resolving field type"); 134 | } 135 | 136 | return false; 137 | } 138 | 139 | return true; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/OpjData/Hooks/HookType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Oxide.Patcher.Hooks 4 | { 5 | /// 6 | /// Indicates details about the hook type for use with UI 7 | /// 8 | [AttributeUsage(AttributeTargets.Class, Inherited = false)] 9 | public sealed class HookType : Attribute 10 | { 11 | /// 12 | /// Gets a human-friendly name for this hook type 13 | /// 14 | public string Name { get; } 15 | 16 | /// 17 | /// Gets if this hook type should be used as the default 18 | /// 19 | public bool Default { get; set; } 20 | 21 | public HookType(string name) 22 | { 23 | Name = name; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/OpjData/Hooks/InitOxide.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Mono.Cecil.Cil; 3 | using Oxide.Patcher.Patching; 4 | using Oxide.Patcher.Views; 5 | using System; 6 | using System.Linq; 7 | 8 | namespace Oxide.Patcher.Hooks 9 | { 10 | /// 11 | /// The initialization hook that loads Oxide 12 | /// 13 | [HookType("Initialize Oxide")] 14 | public class InitOxide : Hook 15 | { 16 | /// 17 | /// Gets or sets the instruction index to inject the hook call at 18 | /// 19 | public int InjectionIndex { get; set; } 20 | 21 | public override bool ApplyPatch(MethodDefinition original, ILWeaver weaver, Patching.Patcher patcher = null) 22 | { 23 | MethodDefinition initoxidemethod = Program.OxideAssembly.MainModule.Types 24 | .Single(t => t.FullName == "Oxide.Core.Interface") 25 | .Methods.Single(m => m.IsStatic && m.Name == "Initialize"); 26 | 27 | // Start injecting where requested 28 | weaver.Pointer = InjectionIndex; 29 | weaver.OriginalPointer = InjectionIndex; 30 | 31 | // Get the existing instruction we're going to inject behind 32 | Instruction existing; 33 | try 34 | { 35 | existing = weaver.Instructions[weaver.Pointer]; 36 | } 37 | catch (ArgumentOutOfRangeException) 38 | { 39 | ShowMessage($"The injection index specified for {Name} is invalid!", "Invalid Index", patcher); 40 | return false; 41 | } 42 | 43 | // Load the hook name 44 | Instruction firstinjected = weaver.Add(Instruction.Create(OpCodes.Call, weaver.Module.Import(initoxidemethod))); 45 | 46 | // Find all instructions which pointed to the existing and redirect them 47 | for (int i = 0; i < weaver.Instructions.Count; i++) 48 | { 49 | Instruction ins = weaver.Instructions[i]; 50 | if (ins.Operand != null && ins.Operand.Equals(existing)) 51 | { 52 | // Check if the instruction lies within our injection range 53 | // If it does, it's an instruction we just injected so we don't want to edit it 54 | if (i < InjectionIndex || i > weaver.Pointer) 55 | { 56 | ins.Operand = firstinjected; 57 | } 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | public override IHookSettingsControl CreateSettingsView() 64 | { 65 | return new InitOxideHookSettingsControl { Hook = this }; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/OpjData/Hooks/MethodSignature.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Oxide.Patcher.Common; 3 | 4 | namespace Oxide.Patcher.Hooks 5 | { 6 | /// 7 | /// Represents the signature of a method 8 | /// 9 | public sealed class MethodSignature 10 | { 11 | /// 12 | /// Gets the method exposure 13 | /// 14 | public MethodExposure Exposure { get; } 15 | 16 | /// 17 | /// Gets the method name 18 | /// 19 | public string Name { get; } 20 | 21 | /// 22 | /// Gets the method return type as a fully qualified type name 23 | /// 24 | public string ReturnType { get; } 25 | 26 | /// 27 | /// Gets the parameter list as fully qualified type names 28 | /// 29 | public string[] Parameters { get; } 30 | 31 | /// 32 | /// Initializes a new instance of the MethodSignature class 33 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | public MethodSignature(MethodExposure exposure, string returntype, string name, string[] parameters) 39 | { 40 | Exposure = exposure; 41 | ReturnType = returntype; 42 | Name = name; 43 | Parameters = parameters; 44 | } 45 | 46 | public override bool Equals(object obj) 47 | { 48 | if (!(obj is MethodSignature othersig)) 49 | { 50 | return false; 51 | } 52 | 53 | if (Exposure != othersig.Exposure || Name != othersig.Name) 54 | { 55 | return false; 56 | } 57 | 58 | if (Parameters.Length != othersig.Parameters.Length) 59 | { 60 | return false; 61 | } 62 | 63 | for (int i = 0; i < Parameters.Length; i++) 64 | { 65 | if (Parameters[i] != othersig.Parameters[i]) 66 | { 67 | return false; 68 | } 69 | } 70 | 71 | return true; 72 | } 73 | 74 | public override int GetHashCode() 75 | { 76 | int total = Exposure.GetHashCode() + Name.GetHashCode(); 77 | foreach (string param in Parameters) 78 | { 79 | total += param.GetHashCode(); 80 | } 81 | 82 | return total; 83 | } 84 | 85 | public override string ToString() 86 | { 87 | StringBuilder sb = new StringBuilder(); 88 | sb.AppendFormat("{0} {1} {2}(", Exposure.ToString().ToLower(), Utility.TransformType(ReturnType), Name); 89 | for (int i = 0; i < Parameters.Length; i++) 90 | { 91 | if (i > 0) 92 | { 93 | sb.AppendFormat(", {0}", Parameters[i]); 94 | } 95 | else 96 | { 97 | sb.Append(Parameters[i]); 98 | } 99 | } 100 | 101 | sb.Append(")"); 102 | return sb.ToString(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/OpjData/Manifest.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Oxide.Patcher.Fields; 3 | using Oxide.Patcher.Hooks; 4 | using Oxide.Patcher.Modifiers; 5 | using System.Collections.Generic; 6 | using Oxide.Patcher.Common.JsonHelpers; 7 | 8 | namespace Oxide.Patcher 9 | { 10 | /// 11 | /// A set of changes to make to an assembly 12 | /// 13 | public class Manifest 14 | { 15 | /// 16 | /// Gets or sets the name of the assembly in the target directory 17 | /// 18 | public string AssemblyName { get; set; } 19 | 20 | /// 21 | /// Gets or sets the hooks contained in this project 22 | /// 23 | [JsonConverter(typeof(HooksListConverter))] 24 | public List Hooks { get; set; } = new List(); 25 | 26 | /// 27 | /// Gets or sets the changed modifiers in this project 28 | /// 29 | public List Modifiers { get; set; } = new List(); 30 | 31 | /// 32 | /// Gets or sets the additional fields in this project 33 | /// 34 | public List Fields { get; set; } = new List(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OpjData/Modifiers/Modifier.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | 3 | using Oxide.Patcher.Patching; 4 | using Oxide.Patcher.Views; 5 | 6 | using System.Linq; 7 | using Oxide.Patcher.Common; 8 | 9 | namespace Oxide.Patcher.Modifiers 10 | { 11 | /// 12 | /// Represents a hook that is applied to single method and calls a single Oxide hook 13 | /// 14 | public class Modifier 15 | { 16 | /// 17 | /// Gets or sets a name for this modifier 18 | /// 19 | public string Name { get; set; } 20 | 21 | /// 22 | /// Gets or sets the name of the assembly in which the target resides 23 | /// 24 | public string AssemblyName { get; set; } 25 | 26 | /// 27 | /// Gets or sets the fully qualified name for the type in which the target resides 28 | /// 29 | public string TypeName { get; set; } 30 | 31 | /// 32 | /// Gets or sets the type of the target 33 | /// 34 | public ModifierType Type { get; set; } 35 | 36 | /// 37 | /// Gets the target exposure 38 | /// 39 | public Exposure[] TargetExposure { get; set; } 40 | 41 | /// 42 | /// Gets or sets if this modifier has been flagged 43 | /// 44 | public bool Flagged { get; set; } 45 | 46 | /// 47 | /// Gets or sets the target signature 48 | /// 49 | public ModifierSignature Signature { get; set; } 50 | 51 | /// 52 | /// Gets or sets the MSIL hash of the target 53 | /// 54 | public string MSILHash { get; set; } = string.Empty; 55 | 56 | public Modifier() { } 57 | 58 | private Modifier(MemberReference memberRef, string assemblyName, string typeName) 59 | { 60 | Name = $"{memberRef.DeclaringType}::{memberRef.Name}"; 61 | TypeName = typeName; 62 | AssemblyName = assemblyName; 63 | Signature = Utility.GetModifierSignature(memberRef); 64 | TargetExposure = Signature.Exposure; 65 | } 66 | 67 | public Modifier(FieldDefinition field, string assembly) : this(field, assembly, field.DeclaringType.FullName) 68 | { 69 | Type = ModifierType.Field; 70 | 71 | if (field.IsStatic) 72 | { 73 | AddStaticExposure(); 74 | } 75 | } 76 | 77 | public Modifier(MethodDefinition method, string assembly) : this(method, assembly, method.DeclaringType.FullName) 78 | { 79 | Type = ModifierType.Method; 80 | 81 | if (method.IsStatic) 82 | { 83 | AddStaticExposure(); 84 | } 85 | 86 | MSILHash = new ILWeaver(method.Body).Hash; 87 | } 88 | 89 | public Modifier(PropertyDefinition property, string assembly) : this(property, assembly, property.DeclaringType.FullName) 90 | { 91 | Type = ModifierType.Property; 92 | 93 | if (property.GetMethod?.IsStatic != false && (property.SetMethod == null || property.SetMethod.IsStatic)) 94 | { 95 | AddStaticExposure(); 96 | } 97 | } 98 | 99 | public Modifier(TypeDefinition type, string assembly) : this(type, assembly, type.FullName) 100 | { 101 | Name = type.FullName; 102 | Type = ModifierType.Type; 103 | 104 | if (type.IsAbstract && type.IsSealed) 105 | { 106 | AddStaticExposure(); 107 | } 108 | } 109 | 110 | private void AddStaticExposure() 111 | { 112 | Exposure[] exposures = new Exposure[TargetExposure.Length + 1]; 113 | exposures[TargetExposure.Length] = Exposure.Static; 114 | 115 | for (int i = 0; i < TargetExposure.Length; i++) 116 | { 117 | exposures[i] = TargetExposure[i]; 118 | } 119 | 120 | TargetExposure = exposures; 121 | } 122 | 123 | public bool HasTargetExposure(Exposure exposure) 124 | { 125 | return TargetExposure?.Any(x => x == exposure) ?? false; 126 | } 127 | 128 | /// 129 | /// Creates the settings view control for this hook 130 | /// 131 | /// 132 | public ModifierSettingsControl CreateSettingsView() 133 | { 134 | return new ModifierSettingsControl { Modifier = this }; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/OpjData/Modifiers/ModifierSignature.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Newtonsoft.Json; 3 | using Oxide.Patcher.Common; 4 | 5 | namespace Oxide.Patcher.Modifiers 6 | { 7 | /// 8 | /// Represents the signature of a method, field or property 9 | /// 10 | public sealed class ModifierSignature 11 | { 12 | /// 13 | /// Gets the exposure 14 | /// 15 | public Exposure[] Exposure { get; } 16 | 17 | /// 18 | /// Gets the name 19 | /// 20 | public string Name { get; } 21 | 22 | /// 23 | /// Gets the method return type or the field or property type as a fully qualified type name 24 | /// 25 | public string FullTypeName { get; } 26 | 27 | /// 28 | /// Gets the parameter list for methods as fully qualified type names 29 | /// 30 | public string[] Parameters { get; } 31 | 32 | /// 33 | /// Initializes a new instance of the ModifierSignature class 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public ModifierSignature(Exposure exposure, string fulltypename, string name, string[] parameters) 40 | { 41 | Exposure = new[] { exposure }; 42 | FullTypeName = fulltypename; 43 | Name = name; 44 | Parameters = parameters; 45 | } 46 | 47 | [JsonConstructor] 48 | public ModifierSignature(Exposure[] exposure, string fulltypename, string name, string[] parameters) 49 | { 50 | Exposure = exposure; 51 | FullTypeName = fulltypename; 52 | Name = name; 53 | Parameters = parameters; 54 | } 55 | 56 | public override bool Equals(object obj) 57 | { 58 | if (!(obj is ModifierSignature othersig)) 59 | { 60 | return false; 61 | } 62 | 63 | if (Name != othersig.Name) 64 | { 65 | return false; 66 | } 67 | 68 | if (Exposure.Length != othersig.Exposure.Length) 69 | { 70 | return false; 71 | } 72 | 73 | for (int i = 0; i < Exposure.Length; i++) 74 | { 75 | if (Exposure[i] != othersig.Exposure[i]) 76 | { 77 | return false; 78 | } 79 | } 80 | 81 | if (Parameters.Length != othersig.Parameters.Length) 82 | { 83 | return false; 84 | } 85 | 86 | for (int i = 0; i < Parameters.Length; i++) 87 | { 88 | if (Parameters[i] != othersig.Parameters[i]) 89 | { 90 | return false; 91 | } 92 | } 93 | 94 | return true; 95 | } 96 | 97 | public override int GetHashCode() 98 | { 99 | int total = Name.GetHashCode(); 100 | foreach (Exposure exposure in Exposure) 101 | { 102 | total += exposure.GetHashCode(); 103 | } 104 | 105 | foreach (string param in Parameters) 106 | { 107 | total += param.GetHashCode(); 108 | } 109 | 110 | return total; 111 | } 112 | 113 | public override string ToString() 114 | { 115 | StringBuilder sb = new StringBuilder(); 116 | sb.AppendFormat("{0} {1} {2}(", Exposure.ToString().ToLower(), Utility.TransformType(FullTypeName), Name); 117 | for (int i = 0; i < Parameters.Length; i++) 118 | { 119 | if (i > 0) 120 | { 121 | sb.AppendFormat(", {0}", Parameters[i]); 122 | } 123 | else 124 | { 125 | sb.Append(Parameters[i]); 126 | } 127 | } 128 | 129 | sb.Append(")"); 130 | return sb.ToString(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/OpjData/Project.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Windows.Forms; 6 | using Oxide.Patcher.Hooks; 7 | 8 | namespace Oxide.Patcher 9 | { 10 | /// 11 | /// An Oxide patcher project 12 | /// 13 | public class Project 14 | { 15 | /// 16 | /// Gets or sets the project name 17 | /// 18 | public string Name { get; set; } 19 | 20 | /// 21 | /// Gets or sets the directory of the dlls 22 | /// 23 | public string TargetDirectory { get; set; } 24 | 25 | /// 26 | /// Gets or sets all the manifests contained in this project 27 | /// 28 | public List Manifests { get; set; } 29 | 30 | /// 31 | /// Initializes a new instance of the Project class with sensible defaults 32 | /// 33 | public Project() 34 | { 35 | // Fill in defaults 36 | Name = "Untitled Project"; 37 | TargetDirectory = ""; 38 | Manifests = new List(); 39 | } 40 | 41 | /// 42 | /// Saves this project to file 43 | /// 44 | public void Save(string filename) 45 | { 46 | File.WriteAllText(filename, JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })); 47 | } 48 | 49 | /// 50 | /// Loads this project from file 51 | /// 52 | /// 53 | public static Project Load(string filename, string overrideTarget = "") 54 | { 55 | if (!File.Exists(filename)) 56 | { 57 | return new Project(); 58 | } 59 | 60 | string text = File.ReadAllText(filename); 61 | try 62 | { 63 | Project project = JsonConvert.DeserializeObject(text); 64 | if (!string.IsNullOrWhiteSpace(overrideTarget)) 65 | { 66 | project.TargetDirectory = overrideTarget; 67 | } 68 | 69 | foreach (Manifest manifest in project.Manifests) 70 | { 71 | foreach (Hook hook in manifest.Hooks) 72 | { 73 | if (string.IsNullOrEmpty(hook.BaseHookName)) 74 | { 75 | continue; 76 | } 77 | 78 | Hook baseHook = manifest.Hooks.Find(x => x.Name == hook.BaseHookName); 79 | if (baseHook == null) 80 | { 81 | if (PatcherForm.MainForm != null) 82 | { 83 | MessageBox.Show($"Could not find base hook '{hook.BaseHookName}' for hook '{hook.Name}'", "Base hook missing!", 84 | MessageBoxButtons.OK, MessageBoxIcon.Error); 85 | } 86 | else 87 | { 88 | Console.WriteLine($"ERROR: Could not find base hook '{hook.BaseHookName}' for hook '{hook.Name}'"); 89 | } 90 | } 91 | else 92 | { 93 | hook.BaseHook = baseHook; 94 | baseHook.ChildHook = hook; 95 | } 96 | } 97 | } 98 | 99 | return project; 100 | } 101 | catch (JsonReaderException) 102 | { 103 | if (PatcherForm.MainForm != null) 104 | { 105 | MessageBox.Show("There was a problem loading the project file!\nAre all file paths properly escaped?", "JSON Exception", 106 | MessageBoxButtons.OK, MessageBoxIcon.Error); 107 | } 108 | else 109 | { 110 | Console.WriteLine("ERROR: There was a problem loading the project file! Are all file paths properly escaped?"); 111 | } 112 | 113 | return null; 114 | } 115 | } 116 | 117 | /// 118 | /// Adds an empty manifest with the given assembly name to the project 119 | /// 120 | /// 121 | public void AddManifest(string assemblyname) 122 | { 123 | Manifest manifest = new Manifest { AssemblyName = assemblyname }; 124 | Manifests.Add(manifest); 125 | } 126 | 127 | /// 128 | /// Removes the manifest that references the specified assembly name from the project 129 | /// 130 | /// 131 | public void RemoveManifest(string assemblyname) 132 | { 133 | Manifest manifest = GetManifest(assemblyname); 134 | if (manifest != null) 135 | { 136 | Manifests.Remove(manifest); 137 | } 138 | } 139 | 140 | /// 141 | /// Gets the manifest with the specified assembly name 142 | /// 143 | /// 144 | /// 145 | public Manifest GetManifest(string assemblyname) 146 | { 147 | foreach (Manifest manifest in Manifests) 148 | { 149 | if (manifest.AssemblyName == assemblyname) 150 | { 151 | return manifest; 152 | } 153 | } 154 | return null; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Patching/OxideDefinitions/OxideDefinitions.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace Oxide.Patcher.Patching.OxideDefinitions 8 | { 9 | public static class OxideDefinitions 10 | { 11 | private static readonly Regex TypeRegex = new Regex(@"\[(?>\[(?)|\](?<-DEPTH>)|.?)*(?(DEPTH)(?!))\]", RegexOptions.Compiled); 12 | 13 | public static bool TryParseType(string input, out OxideTypeDefinition result, out string error) 14 | { 15 | result = null; 16 | error = string.Empty; 17 | 18 | if (!TypeRegex.IsMatch(input)) 19 | { 20 | string[] typeData = input.Split('|'); 21 | if (typeData.Length < 2) 22 | { 23 | error = "OpType Type format: AssemblyName|TypeFullName"; 24 | return false; 25 | } 26 | 27 | AssemblyDefinition targetAssembly = GetAssembly(typeData[0]); 28 | if (targetAssembly == null) 29 | { 30 | error = $"Assembly '{typeData[0]}' not found"; 31 | return false; 32 | } 33 | 34 | TypeDefinition targetType = targetAssembly.MainModule.GetType(typeData[1].Trim()); 35 | if (targetType == null) 36 | { 37 | error = $"Type '{typeData[1]}' not found"; 38 | return false; 39 | } 40 | 41 | result = new OxideTypeDefinition(targetType); 42 | } 43 | else 44 | { 45 | Match genericTypeMatch = TypeRegex.Match(input); 46 | string genericType = genericTypeMatch.Value.Substring(1, genericTypeMatch.Value.Length - 2); 47 | List genericTypeInstances = GetGenericTypeInstances(genericType); 48 | string[] typeData = input.Split('[')[0].Split('|'); 49 | if (typeData.Length < 2) 50 | { 51 | error = "OpType Type format: AssemblyName|TypeFullName"; 52 | return false; 53 | } 54 | 55 | AssemblyDefinition targetAssembly = GetAssembly(typeData[0]); 56 | if (targetAssembly == null) 57 | { 58 | error = $"Assembly '{typeData[0]}' not found"; 59 | return false; 60 | } 61 | 62 | TypeDefinition targetType = targetAssembly.MainModule.GetType($"{typeData[1]}`{genericTypeInstances.Count}"); 63 | if (targetType == null) 64 | { 65 | error = $"Type '{typeData[1]}' not found"; 66 | return false; 67 | } 68 | 69 | result = new OxideTypeDefinition(targetType); 70 | 71 | foreach (string genericTypeInstanceName in genericTypeInstances) 72 | { 73 | if (TryParseType(genericTypeInstanceName, out OxideTypeDefinition genericTypeDefinition, out error)) 74 | { 75 | result.AddGenericTypeInstance(genericTypeDefinition); 76 | } 77 | else 78 | { 79 | result = null; 80 | return false; 81 | } 82 | } 83 | } 84 | 85 | return true; 86 | } 87 | 88 | private static List GetGenericTypeInstances(string typeName) 89 | { 90 | int depth = 0; 91 | int start = 0; 92 | List genericTypes = new List(); 93 | 94 | for (int i = 0; i < typeName.Length; i++) 95 | { 96 | if (typeName[i] == '[') 97 | { 98 | depth++; 99 | } 100 | else if (typeName[i] == ']') 101 | { 102 | depth--; 103 | } 104 | else if (typeName[i] == ',' && depth == 0) 105 | { 106 | genericTypes.Add(typeName.Substring(start, i - start).Trim()); 107 | start = i + 1; 108 | } 109 | } 110 | 111 | genericTypes.Add(typeName.Substring(start, typeName.Length - start).Trim()); 112 | 113 | return genericTypes; 114 | } 115 | 116 | private static AssemblyDefinition GetAssembly(string assemblyName) 117 | { 118 | Project project = PatcherForm.MainForm?.CurrentProject ?? Program.PatchProject; 119 | if (project == null) 120 | { 121 | throw new InvalidOperationException(); 122 | } 123 | 124 | var targetAssembly = Path.Combine(project.TargetDirectory, $"{assemblyName}.dll"); 125 | return AssemblyDefinition.ReadAssembly(targetAssembly); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Patching/OxideDefinitions/OxideTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using System.Collections.Generic; 3 | 4 | namespace Oxide.Patcher.Patching.OxideDefinitions 5 | { 6 | public class OxideTypeDefinition 7 | { 8 | private TypeDefinition type; 9 | private List genericTypeInstances; 10 | 11 | public OxideTypeDefinition(TypeDefinition type) 12 | { 13 | this.type = type; 14 | genericTypeInstances = new List(); 15 | } 16 | 17 | public void AddGenericTypeInstance(OxideTypeDefinition genericTypeInstance) 18 | { 19 | genericTypeInstances.Add(genericTypeInstance); 20 | } 21 | 22 | public TypeReference GetTypeReference() 23 | { 24 | if (type.HasGenericParameters) 25 | { 26 | GenericInstanceType generic = new GenericInstanceType(type); 27 | foreach (OxideTypeDefinition genericType in genericTypeInstances) 28 | { 29 | generic.GenericArguments.Add(genericType.GetTypeReference()); 30 | } 31 | 32 | return generic; 33 | } 34 | 35 | return type; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Patching/PatcherAssemblyResolver.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using System; 3 | using System.IO; 4 | 5 | namespace Oxide.Patcher.Patching 6 | { 7 | /// 8 | /// Allows Mono.Cecil to locate assemblies when trying to build references 9 | /// 10 | public class PatcherAssemblyResolver : DefaultAssemblyResolver 11 | { 12 | 13 | /// 14 | /// Initializes a new instance of the AssemblyResolver class 15 | /// 16 | public PatcherAssemblyResolver(string path) 17 | { 18 | if (path == null) throw new ArgumentNullException("path"); 19 | if (!Directory.Exists(path)) throw new DirectoryNotFoundException("Directory not found: " + path); 20 | AddSearchDirectory(path); 21 | } 22 | 23 | public override AssemblyDefinition Resolve(AssemblyNameReference assemblyName) 24 | { 25 | return base.Resolve(assemblyName); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Oxide.Patcher.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Oxide.Patcher.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap book_add { 67 | get { 68 | object obj = ResourceManager.GetObject("book_add", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap book_go { 77 | get { 78 | object obj = ResourceManager.GetObject("book_go", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap door_in { 87 | get { 88 | object obj = ResourceManager.GetObject("door_in", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap wand { 97 | get { 98 | object obj = ResourceManager.GetObject("wand", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18408 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Oxide.Patcher.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Resources/Icons.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Oxide.Patcher.Resources { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Icons { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Icons() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Oxide.Patcher.Resources.Icons", typeof(Icons).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap book_add { 67 | get { 68 | object obj = ResourceManager.GetObject("book_add", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap book_go { 77 | get { 78 | object obj = ResourceManager.GetObject("book_go", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap cog_edit { 87 | get { 88 | object obj = ResourceManager.GetObject("cog_edit", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap cross { 97 | get { 98 | object obj = ResourceManager.GetObject("cross", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Drawing.Bitmap. 105 | /// 106 | internal static System.Drawing.Bitmap door_in { 107 | get { 108 | object obj = ResourceManager.GetObject("door_in", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Looks up a localized resource of type System.Drawing.Bitmap. 115 | /// 116 | internal static System.Drawing.Bitmap folder { 117 | get { 118 | object obj = ResourceManager.GetObject("folder", resourceCulture); 119 | return ((System.Drawing.Bitmap)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Looks up a localized resource of type System.Drawing.Bitmap. 125 | /// 126 | internal static System.Drawing.Bitmap folder_flagged { 127 | get { 128 | object obj = ResourceManager.GetObject("folder_flagged", resourceCulture); 129 | return ((System.Drawing.Bitmap)(obj)); 130 | } 131 | } 132 | 133 | /// 134 | /// Looks up a localized resource of type System.Drawing.Bitmap. 135 | /// 136 | internal static System.Drawing.Bitmap lightning { 137 | get { 138 | object obj = ResourceManager.GetObject("lightning", resourceCulture); 139 | return ((System.Drawing.Bitmap)(obj)); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Resources/book_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/book_add.png -------------------------------------------------------------------------------- /src/Resources/book_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/book_go.png -------------------------------------------------------------------------------- /src/Resources/cog_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/cog_edit.png -------------------------------------------------------------------------------- /src/Resources/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/cross.png -------------------------------------------------------------------------------- /src/Resources/door_in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/door_in.png -------------------------------------------------------------------------------- /src/Resources/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/folder.png -------------------------------------------------------------------------------- /src/Resources/folder_flagged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/folder_flagged.png -------------------------------------------------------------------------------- /src/Resources/lightning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/lightning.png -------------------------------------------------------------------------------- /src/Resources/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/logo.ico -------------------------------------------------------------------------------- /src/Resources/wand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OxideMod/Oxide.Patcher/217a8f35ead41aa5fd5114f725c6a43ed8e77bd9/src/Resources/wand.png -------------------------------------------------------------------------------- /src/Views/FieldAndPropertyViewControl.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Oxide.Patcher.Modifiers; 3 | using System; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using Mono.CSharp; 7 | using Oxide.Patcher.Common; 8 | 9 | namespace Oxide.Patcher 10 | { 11 | public partial class FieldAndPropertyViewControl : UserControl 12 | { 13 | /// 14 | /// Gets or sets the property definition to use 15 | /// 16 | public PropertyDefinition PropertyDef { get; set; } 17 | 18 | /// 19 | /// Gets or sets the field definition to use 20 | /// 21 | public FieldDefinition FieldDef { get; set; } 22 | 23 | /// 24 | /// Gets or sets the main patcher form 25 | /// 26 | public PatcherForm MainForm { get; set; } 27 | 28 | private Modifier _modifierView; 29 | 30 | public FieldAndPropertyViewControl() 31 | { 32 | InitializeComponent(); 33 | } 34 | 35 | protected override void OnLoad(EventArgs e) 36 | { 37 | base.OnLoad(e); 38 | 39 | PopulateDetails(); 40 | 41 | bool modifierFound = (FieldDef != null || PropertyDef != null) && FindModifier(); 42 | 43 | editbutton.Enabled = !modifierFound; 44 | gotoeditbutton.Enabled = modifierFound; 45 | } 46 | 47 | private bool FindModifier() 48 | { 49 | foreach (Manifest manifest in MainForm.CurrentProject.Manifests) 50 | { 51 | foreach (Modifier modifier in manifest.Modifiers) 52 | { 53 | if (FieldDef != null && modifier.Signature.Equals(Utility.GetModifierSignature(FieldDef)) && modifier.TypeName == FieldDef.DeclaringType.FullName) 54 | { 55 | _modifierView = modifier; 56 | return true; 57 | } 58 | 59 | if (PropertyDef != null && modifier.Signature.Equals(Utility.GetModifierSignature(PropertyDef)) && modifier.TypeName == PropertyDef.DeclaringType.FullName) 60 | { 61 | _modifierView = modifier; 62 | return true; 63 | } 64 | } 65 | } 66 | 67 | return false; 68 | } 69 | 70 | private void PopulateDetails() 71 | { 72 | typenametextbox.Text = FieldDef?.FullName ?? PropertyDef?.FullName; 73 | 74 | if (FieldDef != null) 75 | { 76 | detailsgroup.Text = "Field Details"; 77 | string qualifier = FieldDef.IsPublic ? "public" : FieldDef.IsPrivate ? "private" : "protected"; 78 | declarationtextbox.Text = $"{qualifier} {Utility.TransformType(FieldDef.FieldType.Name)} {FieldDef.Name}"; 79 | editbutton.Text = "Edit Field Modifier"; 80 | gotoeditbutton.Text = "Goto Field Modifiers"; 81 | } 82 | else if (PropertyDef != null) 83 | { 84 | detailsgroup.Text = "Property Details"; 85 | StringBuilder sb = new StringBuilder(); 86 | 87 | sb.Append("("); 88 | 89 | MethodDefinition propertyGetMethod = PropertyDef.GetMethod; 90 | if (propertyGetMethod != null) 91 | { 92 | sb.Append(propertyGetMethod.IsPrivate ? "private " : propertyGetMethod.IsPublic ? "public " : "protected "); 93 | sb.Append("get, "); 94 | } 95 | 96 | MethodDefinition propertySetMethod = PropertyDef.SetMethod; 97 | if (propertySetMethod != null) 98 | { 99 | sb.Append(propertySetMethod.IsPrivate ? "private " : propertySetMethod.IsPublic ? "public " : "protected "); 100 | sb.Append("set"); 101 | } 102 | 103 | sb.Append(")"); 104 | 105 | declarationtextbox.Text = $"{Utility.TransformType(PropertyDef.PropertyType.Name)} {PropertyDef.Name} {sb.Replace(", )", ")")}"; 106 | editbutton.Text = "Edit Property Modifier"; 107 | gotoeditbutton.Text = "Goto Property Modifiers"; 108 | } 109 | } 110 | 111 | private void editbutton_Click(object sender, EventArgs e) 112 | { 113 | Modifier modifier = FieldDef != null 114 | ? new Modifier(FieldDef, MainForm.AssemblyLoader.rassemblydict[FieldDef.Module.Assembly]) 115 | : new Modifier(PropertyDef, MainForm.AssemblyLoader.rassemblydict[PropertyDef.Module.Assembly]); 116 | 117 | MainForm.AddModifier(modifier); 118 | MainForm.GotoModifier(modifier); 119 | 120 | _modifierView = modifier; 121 | editbutton.Enabled = false; 122 | gotoeditbutton.Enabled = true; 123 | } 124 | 125 | private void gotoeditbutton_Click(object sender, EventArgs e) 126 | { 127 | MainForm.GotoModifier(_modifierView); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Views/FieldAndPropertyViewControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/FieldSettingsControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher.Views 2 | { 3 | partial class FieldSettingsControl 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.TargetTypeText = new System.Windows.Forms.TextBox(); 34 | this.ModifyButton = new System.Windows.Forms.Button(); 35 | this.tableLayoutPanel1.SuspendLayout(); 36 | this.SuspendLayout(); 37 | // 38 | // tableLayoutPanel1 39 | // 40 | this.tableLayoutPanel1.ColumnCount = 3; 41 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 100F)); 42 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); 43 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F)); 44 | this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); 45 | this.tableLayoutPanel1.Controls.Add(this.TargetTypeText, 1, 0); 46 | this.tableLayoutPanel1.Controls.Add(this.ModifyButton, 2, 0); 47 | this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); 48 | this.tableLayoutPanel1.Name = "tableLayoutPanel1"; 49 | this.tableLayoutPanel1.RowCount = 1; 50 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 26F)); 51 | this.tableLayoutPanel1.Size = new System.Drawing.Size(409, 26); 52 | this.tableLayoutPanel1.TabIndex = 1; 53 | // 54 | // label1 55 | // 56 | this.label1.AutoSize = true; 57 | this.label1.Dock = System.Windows.Forms.DockStyle.Fill; 58 | this.label1.Location = new System.Drawing.Point(3, 0); 59 | this.label1.Name = "label1"; 60 | this.label1.Size = new System.Drawing.Size(94, 26); 61 | this.label1.TabIndex = 12; 62 | this.label1.Text = "Target Type:"; 63 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 64 | // 65 | // TargetTypeText 66 | // 67 | this.TargetTypeText.Dock = System.Windows.Forms.DockStyle.Fill; 68 | this.TargetTypeText.Location = new System.Drawing.Point(103, 3); 69 | this.TargetTypeText.Name = "TargetTypeText"; 70 | this.TargetTypeText.ReadOnly = true; 71 | this.TargetTypeText.Size = new System.Drawing.Size(223, 20); 72 | this.TargetTypeText.TabIndex = 13; 73 | // 74 | // ModifyButton 75 | // 76 | this.ModifyButton.Location = new System.Drawing.Point(332, 3); 77 | this.ModifyButton.Name = "ModifyButton"; 78 | this.ModifyButton.Size = new System.Drawing.Size(74, 20); 79 | this.ModifyButton.TabIndex = 14; 80 | this.ModifyButton.Text = "Modify"; 81 | this.ModifyButton.UseVisualStyleBackColor = true; 82 | this.ModifyButton.Click += new System.EventHandler(this.ModifyButton_Click); 83 | // 84 | // FieldSettingsControl 85 | // 86 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 87 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 88 | this.Controls.Add(this.tableLayoutPanel1); 89 | this.Name = "FieldSettingsControl"; 90 | this.Size = new System.Drawing.Size(415, 198); 91 | this.tableLayoutPanel1.ResumeLayout(false); 92 | this.tableLayoutPanel1.PerformLayout(); 93 | this.ResumeLayout(false); 94 | 95 | } 96 | 97 | #endregion 98 | 99 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; 100 | private System.Windows.Forms.Label label1; 101 | private System.Windows.Forms.TextBox TargetTypeText; 102 | private System.Windows.Forms.Button ModifyButton; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Views/FieldSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using Oxide.Patcher.Fields; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace Oxide.Patcher.Views 6 | { 7 | public partial class FieldSettingsControl : UserControl 8 | { 9 | internal FieldViewControl Controller; 10 | 11 | /// 12 | /// Gets or sets the hook to use 13 | /// 14 | public Field Field { get; set; } 15 | 16 | public FieldSettingsControl() 17 | { 18 | InitializeComponent(); 19 | } 20 | 21 | protected override void OnLoad(EventArgs e) 22 | { 23 | base.OnLoad(e); 24 | 25 | TargetTypeText.Text = Field.FieldType; 26 | } 27 | 28 | private void ModifyButton_Click(object sender, EventArgs e) 29 | { 30 | using (ModifyForm form = new ModifyForm(Field, TargetTypeText.Text)) 31 | { 32 | if (form.ShowDialog(PatcherForm.MainForm) != DialogResult.OK) 33 | { 34 | return; 35 | } 36 | 37 | if (form.Instruction == null) 38 | { 39 | return; 40 | } 41 | 42 | TargetTypeText.Text = form.Instruction.Operand.ToString(); 43 | 44 | Field.FieldType = TargetTypeText.Text; 45 | Controller.ApplyButton.Enabled = true; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Views/FieldSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/FieldViewControl.cs: -------------------------------------------------------------------------------- 1 | using Oxide.Patcher.Fields; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace Oxide.Patcher.Views 6 | { 7 | public partial class FieldViewControl : UserControl 8 | { 9 | /// 10 | /// Gets or sets the modifier to use 11 | /// 12 | public Field Field { get; set; } 13 | 14 | /// 15 | /// Gets or sets the main patcher form 16 | /// 17 | public PatcherForm MainForm { get; set; } 18 | 19 | public Button FlagButton { get; set; } 20 | 21 | public Button UnflagButton { get; set; } 22 | 23 | public Button ApplyButton { get; set; } 24 | 25 | private bool _loaded; 26 | 27 | public FieldViewControl() 28 | { 29 | InitializeComponent(); 30 | FlagButton = flagbutton; 31 | UnflagButton = unflagbutton; 32 | ApplyButton = applybutton; 33 | } 34 | 35 | protected override void OnLoad(EventArgs e) 36 | { 37 | base.OnLoad(e); 38 | 39 | FieldSettingsControl settingsview = Field.CreateSettingsView(); 40 | settingsview.Controller = this; 41 | settingsview.Dock = DockStyle.Fill; 42 | 43 | fieldsettingstab.Controls.Add(settingsview); 44 | 45 | assemblytextbox.Text = Field.AssemblyName; 46 | typenametextbox.Text = Field.TypeName; 47 | nametextbox.Text = Field.Name; 48 | 49 | flagbutton.Enabled = !Field.Flagged; 50 | unflagbutton.Enabled = Field.Flagged; 51 | 52 | _loaded = true; 53 | } 54 | 55 | private void deletebutton_Click(object sender, EventArgs e) 56 | { 57 | DialogResult result = MessageBox.Show(MainForm, "Are you sure you want to remove this field?", "Oxide Patcher", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); 58 | if (result == DialogResult.Yes) 59 | { 60 | MainForm.RemoveField(Field); 61 | } 62 | } 63 | 64 | private void flagbutton_Click(object sender, EventArgs e) 65 | { 66 | Field.Flagged = true; 67 | MainForm.UpdateField(Field, false); 68 | flagbutton.Enabled = false; 69 | unflagbutton.Enabled = true; 70 | } 71 | 72 | private void unflagbutton_Click(object sender, EventArgs e) 73 | { 74 | Field.Flagged = false; 75 | MainForm.UpdateField(Field, false); 76 | flagbutton.Enabled = true; 77 | unflagbutton.Enabled = false; 78 | } 79 | 80 | private void applybutton_Click(object sender, EventArgs e) 81 | { 82 | applybutton.Enabled = false; 83 | 84 | string previousName = Field.Name; 85 | Field.Name = nametextbox.Text; 86 | 87 | if (!Field.IsValid(MainForm.CurrentProject, true)) 88 | { 89 | nametextbox.Text = previousName; 90 | Field.Name = previousName; 91 | return; 92 | } 93 | 94 | MainForm.UpdateField(Field, false); 95 | } 96 | 97 | private void nametextbox_TextChanged(object sender, EventArgs e) 98 | { 99 | if (!_loaded) 100 | { 101 | return; 102 | } 103 | 104 | applybutton.Enabled = true; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Views/FieldViewControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/HookSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | using Oxide.Patcher.Hooks; 5 | 6 | namespace Oxide.Patcher.Views 7 | { 8 | public class HookSettingsControl : UserControl, IHookSettingsControl where T : Hook 9 | { 10 | /// 11 | /// Gets or sets the hook to use 12 | /// 13 | public T Hook { get; set; } 14 | 15 | /// 16 | /// Called when the settings have been changed by the user 17 | /// 18 | public event Action OnSettingsChanged; 19 | 20 | /// 21 | /// Raises the OnSettingsChanged event 22 | /// 23 | protected void NotifyChanges() 24 | { 25 | OnSettingsChanged?.Invoke(); 26 | } 27 | } 28 | 29 | public interface IHookSettingsControl 30 | { 31 | DockStyle Dock { get; set; } 32 | event Action OnSettingsChanged; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Views/HookViewControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/InitOxideHookSettingsControl.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Oxide.Patcher.Views 2 | { 3 | partial class InitOxideHookSettingsControl 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.injectionindex = new System.Windows.Forms.NumericUpDown(); 34 | this.tableLayoutPanel1.SuspendLayout(); 35 | ((System.ComponentModel.ISupportInitialize)(this.injectionindex)).BeginInit(); 36 | this.SuspendLayout(); 37 | // 38 | // tableLayoutPanel1 39 | // 40 | this.tableLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Top; 41 | this.tableLayoutPanel1.ColumnCount = 2; 42 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 120F)); 43 | this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); 44 | this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); 45 | this.tableLayoutPanel1.Controls.Add(this.injectionindex, 1, 0); 46 | this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); 47 | this.tableLayoutPanel1.Name = "tableLayoutPanel1"; 48 | this.tableLayoutPanel1.RowCount = 1; 49 | this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25.06266F)); 50 | this.tableLayoutPanel1.Size = new System.Drawing.Size(344, 26); 51 | this.tableLayoutPanel1.TabIndex = 0; 52 | // 53 | // label1 54 | // 55 | this.label1.Dock = System.Windows.Forms.DockStyle.Fill; 56 | this.label1.Location = new System.Drawing.Point(3, 0); 57 | this.label1.Name = "label1"; 58 | this.label1.Size = new System.Drawing.Size(114, 26); 59 | this.label1.TabIndex = 0; 60 | this.label1.Text = "Injection Index:"; 61 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 62 | // 63 | // injectionindex 64 | // 65 | this.injectionindex.Dock = System.Windows.Forms.DockStyle.Fill; 66 | this.injectionindex.Location = new System.Drawing.Point(123, 3); 67 | this.injectionindex.Maximum = new decimal(new int[] { 68 | 5000, 69 | 0, 70 | 0, 71 | 0}); 72 | this.injectionindex.Name = "injectionindex"; 73 | this.injectionindex.Size = new System.Drawing.Size(218, 20); 74 | this.injectionindex.TabIndex = 6; 75 | this.injectionindex.ValueChanged += new System.EventHandler(this.injectionindex_ValueChanged); 76 | // 77 | // InitOxideHookSettingsControl 78 | // 79 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 80 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 81 | this.Controls.Add(this.tableLayoutPanel1); 82 | this.Name = "InitOxideHookSettingsControl"; 83 | this.Size = new System.Drawing.Size(415, 198); 84 | this.tableLayoutPanel1.ResumeLayout(false); 85 | ((System.ComponentModel.ISupportInitialize)(this.injectionindex)).EndInit(); 86 | this.ResumeLayout(false); 87 | 88 | } 89 | 90 | #endregion 91 | 92 | private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; 93 | private System.Windows.Forms.Label label1; 94 | private System.Windows.Forms.NumericUpDown injectionindex; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Views/InitOxideHookSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Oxide.Patcher.Hooks; 3 | 4 | namespace Oxide.Patcher.Views 5 | { 6 | public partial class InitOxideHookSettingsControl : HookSettingsControl 7 | { 8 | private bool _loaded; 9 | 10 | public InitOxideHookSettingsControl() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | protected override void OnLoad(EventArgs e) 16 | { 17 | base.OnLoad(e); 18 | 19 | injectionindex.Value = Hook.InjectionIndex; 20 | 21 | _loaded = true; 22 | } 23 | 24 | private void injectionindex_ValueChanged(object sender, EventArgs e) 25 | { 26 | if (!_loaded) 27 | { 28 | return; 29 | } 30 | 31 | Hook.InjectionIndex = (int)injectionindex.Value; 32 | NotifyChanges(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Views/InitOxideHookSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/InterfaceViewControl.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Oxide.Patcher.Modifiers; 3 | using System; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using Oxide.Patcher.Common; 7 | 8 | namespace Oxide.Patcher.Views 9 | { 10 | public partial class InterfaceViewControl : UserControl 11 | { 12 | /// 13 | /// Gets or sets the type definition to use 14 | /// 15 | public TypeDefinition TypeDef { get; set; } 16 | 17 | /// 18 | /// Gets or sets the main patcher form 19 | /// 20 | public PatcherForm MainForm { get; set; } 21 | 22 | private Modifier _modifierView; 23 | 24 | public InterfaceViewControl() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | protected override void OnLoad(EventArgs e) 30 | { 31 | // Populate the details 32 | PopulateDetails(); 33 | 34 | bool modifierfound = FindModifier(); 35 | 36 | editbutton.Enabled = !modifierfound; 37 | gotoeditbutton.Enabled = modifierfound; 38 | } 39 | 40 | private bool FindModifier() 41 | { 42 | foreach (Manifest manifest in MainForm.CurrentProject.Manifests) 43 | { 44 | if (TypeDef == null) 45 | { 46 | continue; 47 | } 48 | 49 | foreach (Modifier modifier in manifest.Modifiers) 50 | { 51 | if (modifier.Signature.Equals(Utility.GetModifierSignature(TypeDef)) && modifier.TypeName == TypeDef.FullName) 52 | { 53 | _modifierView = modifier; 54 | return true; 55 | } 56 | } 57 | } 58 | 59 | return false; 60 | } 61 | 62 | private void PopulateDetails() 63 | { 64 | try 65 | { 66 | typenametextbox.Text = TypeDef.FullName; 67 | StringBuilder sb = new StringBuilder(); 68 | 69 | sb.Append(TypeDef.IsPublic ? "public " : "private "); 70 | 71 | if (TypeDef.IsSealed) 72 | { 73 | sb.Append("sealed "); 74 | } 75 | 76 | sb.Append("interface "); 77 | sb.Append(TypeDef.Name); 78 | 79 | declarationtextbox.Text = sb.ToString(); 80 | } 81 | catch (NullReferenceException) 82 | { 83 | MessageBox.Show(PatcherForm.MainForm, "Error loading details for a interface.", 84 | "Null Reference Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); 85 | } 86 | } 87 | 88 | private void editbutton_Click(object sender, EventArgs e) 89 | { 90 | Modifier modifier = new Modifier(TypeDef, MainForm.AssemblyLoader.rassemblydict[TypeDef.Module.Assembly]); 91 | 92 | MainForm.AddModifier(modifier); 93 | MainForm.GotoModifier(modifier); 94 | 95 | _modifierView = modifier; 96 | editbutton.Enabled = false; 97 | gotoeditbutton.Enabled = true; 98 | } 99 | 100 | private void gotoeditbutton_Click(object sender, EventArgs e) 101 | { 102 | MainForm.GotoModifier(_modifierView); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Views/MethodViewControl.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.TextEditor; 2 | using ICSharpCode.TextEditor.Document; 3 | using Mono.Cecil; 4 | using Oxide.Patcher.Hooks; 5 | using Oxide.Patcher.Modifiers; 6 | using Oxide.Patcher.Patching; 7 | using System; 8 | using System.Windows.Forms; 9 | using Oxide.Patcher.Common; 10 | 11 | namespace Oxide.Patcher 12 | { 13 | public partial class MethodViewControl : UserControl 14 | { 15 | /// 16 | /// Gets or sets the method definition to use 17 | /// 18 | public MethodDefinition MethodDef { get; set; } 19 | 20 | /// 21 | /// Gets or sets the main patcher form 22 | /// 23 | public PatcherForm MainForm { get; set; } 24 | 25 | private Hook _methodHook; 26 | 27 | private Modifier _methodModifier; 28 | 29 | public MethodViewControl() 30 | { 31 | InitializeComponent(); 32 | } 33 | 34 | protected override async void OnLoad(EventArgs e) 35 | { 36 | base.OnLoad(e); 37 | 38 | PopulateDetails(); 39 | 40 | msiltab.Controls.Add(new TextEditorControl 41 | { 42 | IsReadOnly = true, 43 | Dock = DockStyle.Fill, 44 | Text = Decompiler.DecompileToIL(MethodDef.Body) 45 | }); 46 | 47 | codetab.Controls.Add(new TextEditorControl 48 | { 49 | IsReadOnly = true, 50 | Dock = DockStyle.Fill, 51 | Text = await Decompiler.GetSourceCode(MethodDef), 52 | Document = { HighlightingStrategy = HighlightingManager.Manager.FindHighlighter("C#") } 53 | }); 54 | 55 | bool modifierFound = FindModifier(); 56 | 57 | editbutton.Enabled = !modifierFound; 58 | gotoeditbutton.Enabled = modifierFound; 59 | 60 | if (!MethodDef.HasBody) 61 | { 62 | hookbutton.Enabled = false; 63 | gotohookbutton.Enabled = false; 64 | return; 65 | } 66 | 67 | bool hookFound = FindHook(); 68 | 69 | hookbutton.Enabled = !hookFound; 70 | gotohookbutton.Enabled = hookFound; 71 | } 72 | 73 | private void PopulateDetails() 74 | { 75 | typenametextbox.Text = MethodDef.FullName; 76 | declarationtextbox.Text = Utility.GetMethodDeclaration(MethodDef); 77 | } 78 | 79 | private bool FindHook() 80 | { 81 | MethodSignature methodsig = Utility.GetMethodSignature(MethodDef); 82 | 83 | foreach (Manifest manifest in MainForm.CurrentProject.Manifests) 84 | { 85 | foreach (Hook hook in manifest.Hooks) 86 | { 87 | if (hook.Signature.Equals(methodsig) && hook.TypeName == MethodDef.DeclaringType.FullName) 88 | { 89 | _methodHook = hook; 90 | return true; 91 | } 92 | } 93 | } 94 | 95 | return false; 96 | } 97 | 98 | private bool FindModifier() 99 | { 100 | foreach (Manifest manifest in MainForm.CurrentProject.Manifests) 101 | { 102 | foreach (Modifier modifier in manifest.Modifiers) 103 | { 104 | if (modifier.Signature.Equals(Utility.GetModifierSignature(MethodDef)) && modifier.TypeName == MethodDef.DeclaringType.FullName) 105 | { 106 | _methodModifier = modifier; 107 | return true; 108 | } 109 | } 110 | } 111 | 112 | return false; 113 | } 114 | 115 | #region -Actions- 116 | 117 | private void hookbutton_Click(object sender, EventArgs e) 118 | { 119 | Type defaultHookType = Hook.DefaultHookType; 120 | if (defaultHookType == null) 121 | { 122 | return; 123 | } 124 | 125 | Hook hook = Activator.CreateInstance(defaultHookType) as Hook; 126 | hook.Name = MethodDef.Name; 127 | hook.HookName = hook.Name.StartsWith("On") ? hook.Name : $"On{hook.Name}"; 128 | hook.TypeName = MethodDef.DeclaringType.FullName; 129 | hook.AssemblyName = MainForm.AssemblyLoader.rassemblydict[MethodDef.Module.Assembly]; 130 | hook.Signature = Utility.GetMethodSignature(MethodDef); 131 | hook.MSILHash = new ILWeaver(MethodDef.Body).Hash; 132 | 133 | MainForm.AddHook(hook); 134 | MainForm.GotoHook(hook); 135 | 136 | _methodHook = hook; 137 | 138 | hookbutton.Enabled = false; 139 | gotohookbutton.Enabled = true; 140 | } 141 | 142 | private void gotohookbutton_Click(object sender, EventArgs e) 143 | { 144 | MainForm.GotoHook(_methodHook); 145 | } 146 | 147 | private void editbutton_Click(object sender, EventArgs e) 148 | { 149 | Modifier modifier = new Modifier(MethodDef, MainForm.AssemblyLoader.rassemblydict[MethodDef.Module.Assembly]); 150 | 151 | MainForm.AddModifier(modifier); 152 | MainForm.GotoModifier(modifier); 153 | 154 | editbutton.Enabled = false; 155 | gotoeditbutton.Enabled = true; 156 | } 157 | 158 | private void gotoeditbutton_Click(object sender, EventArgs e) 159 | { 160 | MainForm.GotoModifier(_methodModifier); 161 | } 162 | 163 | #endregion 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/Views/MethodViewControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/ModifierSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/ModifierViewControl.cs: -------------------------------------------------------------------------------- 1 | using Oxide.Patcher.Modifiers; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace Oxide.Patcher.Views 6 | { 7 | public partial class ModifierViewControl : UserControl 8 | { 9 | /// 10 | /// Gets or sets the modifier to use 11 | /// 12 | public Modifier Modifier { get; set; } 13 | 14 | /// 15 | /// Gets or sets the main patcher form 16 | /// 17 | public PatcherForm MainForm { get; set; } 18 | 19 | public Button FlagButton { get; set; } 20 | 21 | public Button UnflagButton { get; set; } 22 | 23 | public Button ApplyButton { get; set; } 24 | 25 | public ModifierViewControl() 26 | { 27 | InitializeComponent(); 28 | FlagButton = flagbutton; 29 | UnflagButton = unflagbutton; 30 | ApplyButton = applybutton; 31 | } 32 | 33 | protected override void OnLoad(EventArgs e) 34 | { 35 | base.OnLoad(e); 36 | 37 | ModifierSettingsControl settingsView = Modifier.CreateSettingsView(); 38 | settingsView.Controller = this; 39 | settingsView.Dock = DockStyle.Fill; 40 | 41 | switch (Modifier.Type) 42 | { 43 | case ModifierType.Field: 44 | detailsgroup.Text = "Field Details"; 45 | namelabel.Text = "Field Name:"; 46 | settingsView.FieldDef = MainForm.AssemblyLoader.GetField(Modifier.AssemblyName, Modifier.TypeName, Modifier.Name, Modifier.Signature); 47 | break; 48 | 49 | case ModifierType.Method: 50 | detailsgroup.Text = "Method Details"; 51 | namelabel.Text = "Method Name:"; 52 | settingsView.MethodDef = MainForm.AssemblyLoader.GetMethod(Modifier.AssemblyName, Modifier.TypeName, Modifier.Signature); 53 | break; 54 | 55 | case ModifierType.Property: 56 | detailsgroup.Text = "Property Details"; 57 | namelabel.Text = "Property Name:"; 58 | settingsView.PropertyDef = MainForm.AssemblyLoader.GetProperty(Modifier.AssemblyName, Modifier.TypeName, Modifier.Name, Modifier.Signature); 59 | break; 60 | 61 | case ModifierType.Type: 62 | detailsgroup.Text = "Type Details"; 63 | namelabel.Text = "Type Name:"; 64 | settingsView.TypeDef = MainForm.AssemblyLoader.GetType(Modifier.AssemblyName, Modifier.TypeName); 65 | break; 66 | } 67 | 68 | modifiersettingstab.Controls.Add(settingsView); 69 | 70 | assemblytextbox.Text = Modifier.AssemblyName; 71 | typenametextbox.Text = Modifier.TypeName; 72 | 73 | typenamelabel.Visible = Modifier.Type != ModifierType.Type; 74 | typenametextbox.Visible = Modifier.Type != ModifierType.Type; 75 | 76 | if (settingsView.FieldDef != null || settingsView.MethodDef != null || settingsView.PropertyDef != null) 77 | { 78 | nametextbox.Text = $"{Modifier.TypeName}::{Modifier.Name}"; 79 | } 80 | else if (settingsView.TypeDef != null) 81 | { 82 | nametextbox.Text = Modifier.TypeName; 83 | } 84 | else 85 | { 86 | nametextbox.Text = Modifier.Type != ModifierType.Type ? $"{Modifier.TypeName}::{Modifier.Name} (MISSING)" : $"{Modifier.TypeName} (MISSING)"; 87 | } 88 | 89 | flagbutton.Enabled = !Modifier.Flagged; 90 | unflagbutton.Enabled = Modifier.Flagged; 91 | } 92 | 93 | private void deletebutton_Click(object sender, EventArgs e) 94 | { 95 | DialogResult result = MessageBox.Show(MainForm, "Are you sure you want to remove these modifier changes?", "Oxide Patcher", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); 96 | if (result == DialogResult.Yes) 97 | { 98 | MainForm.RemoveModifier(Modifier); 99 | } 100 | } 101 | 102 | private void flagbutton_Click(object sender, EventArgs e) 103 | { 104 | Modifier.Flagged = true; 105 | MainForm.UpdateModifier(Modifier, false); 106 | flagbutton.Enabled = false; 107 | unflagbutton.Enabled = true; 108 | } 109 | 110 | private void unflagbutton_Click(object sender, EventArgs e) 111 | { 112 | Modifier.Flagged = false; 113 | MainForm.UpdateModifier(Modifier, false); 114 | flagbutton.Enabled = true; 115 | unflagbutton.Enabled = false; 116 | } 117 | 118 | private void applybutton_Click(object sender, EventArgs e) 119 | { 120 | MainForm.UpdateModifier(Modifier, false); 121 | applybutton.Enabled = false; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Views/ModifierViewControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/ModifyHookSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Oxide.Patcher.Hooks; 3 | using System; 4 | using System.Windows.Forms; 5 | 6 | namespace Oxide.Patcher.Views 7 | { 8 | public partial class ModifyHookSettingsControl : HookSettingsControl 9 | { 10 | private bool _loaded; 11 | 12 | private MethodDefinition method; 13 | 14 | public ModifyHookSettingsControl() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | protected override void OnLoad(EventArgs e) 20 | { 21 | base.OnLoad(e); 22 | 23 | method = PatcherForm.MainForm.AssemblyLoader.GetMethod(Hook.AssemblyName, Hook.TypeName, Hook.Signature); 24 | 25 | injectionindex.Value = Hook.InjectionIndex; 26 | removecount.Maximum = method.Body.Instructions.Count - 1; 27 | removecount.Value = Hook.RemoveCount; 28 | illist.DataSource = new BindingSource { DataSource = Hook.Instructions }; 29 | 30 | _loaded = true; 31 | } 32 | 33 | private void injectionindex_ValueChanged(object sender, EventArgs e) 34 | { 35 | if (!_loaded) 36 | { 37 | return; 38 | } 39 | 40 | Hook.InjectionIndex = (int)injectionindex.Value; 41 | NotifyChanges(); 42 | } 43 | 44 | private void removecount_ValueChanged(object sender, EventArgs e) 45 | { 46 | if (!_loaded) 47 | { 48 | return; 49 | } 50 | 51 | Hook.RemoveCount = (int)removecount.Value; 52 | NotifyChanges(); 53 | } 54 | 55 | private void illist_SelectedIndexChanged(object sender, EventArgs e) 56 | { 57 | EditToolStripMenuItem.Enabled = illist.SelectedIndex >= 0; 58 | RemoveToolStripMenuItem.Enabled = illist.SelectedIndex >= 0; 59 | } 60 | 61 | private void NewToolStripMenuItem_Click(object sender, EventArgs e) 62 | { 63 | using (ModifyForm form = new ModifyForm(Hook, method)) 64 | { 65 | if (form.ShowDialog(PatcherForm.MainForm) != DialogResult.OK || form.Instruction == null) 66 | { 67 | return; 68 | } 69 | 70 | int index = illist.SelectedIndex + form.Index; 71 | index = index >= 0 ? index > illist.Items.Count ? illist.Items.Count - 1 : index : 0; 72 | Hook.Instructions.Insert(index, form.Instruction); 73 | 74 | ((BindingSource)illist.DataSource).ResetBindings(false); 75 | NotifyChanges(); 76 | } 77 | } 78 | 79 | private void EditToolStripMenuItem_Click(object sender, EventArgs e) 80 | { 81 | Modify.InstructionData inst = (Modify.InstructionData)illist.SelectedItem; 82 | if (inst == null) 83 | { 84 | return; 85 | } 86 | 87 | using (ModifyForm form = new ModifyForm(Hook, method, inst)) 88 | { 89 | if (form.ShowDialog(PatcherForm.MainForm) != DialogResult.OK) 90 | { 91 | return; 92 | } 93 | 94 | ((BindingSource)illist.DataSource).ResetBindings(false); 95 | NotifyChanges(); 96 | } 97 | } 98 | 99 | private void RemoveToolStripMenuItem_Click(object sender, EventArgs e) 100 | { 101 | Hook.Instructions.RemoveAt(illist.SelectedIndex); 102 | ((BindingSource)illist.DataSource).ResetBindings(false); 103 | NotifyChanges(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Views/ModifyHookSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /src/Views/ProjectSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Windows.Forms; 4 | 5 | namespace Oxide.Patcher 6 | { 7 | public partial class ProjectSettingsControl : UserControl 8 | { 9 | public Project ProjectObject { get; set; } 10 | 11 | public string ProjectFilename { get; set; } 12 | 13 | public ProjectSettingsControl() 14 | { 15 | InitializeComponent(); 16 | } 17 | 18 | private void ProjectSettingsControl_Load(object sender, EventArgs e) 19 | { 20 | nametextbox.Text = ProjectObject.Name; 21 | directorytextbox.Text = ProjectObject.TargetDirectory; 22 | filenametextbox.Text = ProjectFilename; 23 | } 24 | 25 | private void savebutton_Click(object sender, EventArgs e) 26 | { 27 | // Verify 28 | if (!Directory.Exists(directorytextbox.Text)) 29 | { 30 | MessageBox.Show(this, "The target directory is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 31 | return; 32 | } 33 | 34 | if (!Directory.Exists(Path.GetDirectoryName(filenametextbox.Text))) 35 | { 36 | MessageBox.Show(this, "The filename is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 37 | return; 38 | } 39 | 40 | if (nametextbox.TextLength == 0) 41 | { 42 | MessageBox.Show(this, "The project name is invalid.", "Oxide Patcher", MessageBoxButtons.OK, MessageBoxIcon.Error); 43 | return; 44 | } 45 | 46 | // Save 47 | ProjectObject.Name = nametextbox.Text; 48 | ProjectObject.TargetDirectory = directorytextbox.Text; 49 | ProjectObject.Save(ProjectFilename); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Views/ProjectSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Views/SimpleHookSettingsControl.cs: -------------------------------------------------------------------------------- 1 | using Oxide.Patcher.Hooks; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace Oxide.Patcher.Views 6 | { 7 | public partial class SimpleHookSettingsControl : HookSettingsControl 8 | { 9 | private bool _ignoreChanges = true; 10 | 11 | private static readonly ReturnBehavior[] ReturnBehaviors; 12 | private static readonly ArgumentBehavior[] ArgumentBehaviors; 13 | 14 | static SimpleHookSettingsControl() 15 | { 16 | ReturnBehaviors = Enum.GetValues(typeof(ReturnBehavior)) as ReturnBehavior[]; 17 | Array.Sort(ReturnBehaviors, (a, b) => a.CompareTo(b)); 18 | 19 | ArgumentBehaviors = Enum.GetValues(typeof(ArgumentBehavior)) as ArgumentBehavior[]; 20 | Array.Sort(ArgumentBehaviors, (a, b) => a.CompareTo(b)); 21 | } 22 | 23 | public SimpleHookSettingsControl() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | protected override void OnLoad(EventArgs e) 29 | { 30 | base.OnLoad(e); 31 | 32 | foreach (ReturnBehavior behavior in ReturnBehaviors) 33 | { 34 | returnbehavior.Items.Add(behavior); 35 | } 36 | 37 | foreach (ArgumentBehavior behavior in ArgumentBehaviors) 38 | { 39 | argumentbehavior.Items.Add(behavior); 40 | } 41 | 42 | injectionindex.Value = Hook.InjectionIndex; 43 | returnbehavior.SelectedIndex = (int)Hook.ReturnBehavior; 44 | argumentbehavior.SelectedIndex = (int)Hook.ArgumentBehavior; 45 | argumentstring.Text = string.IsNullOrEmpty(Hook.ArgumentString) ? string.Empty : Hook.ArgumentString; 46 | 47 | if (Hook.Deprecation != null) 48 | { 49 | chkIsDeprecated.Checked = true; 50 | txtTargetHook.Text = Hook.Deprecation.ReplacementHook; 51 | dtpRemovalDate.Value = Hook.Deprecation.RemovalDate; 52 | HandleDeprecationFieldsVisibility(true); 53 | } 54 | 55 | _ignoreChanges = false; 56 | } 57 | 58 | private void injectionindex_ValueChanged(object sender, EventArgs e) 59 | { 60 | if (_ignoreChanges) 61 | { 62 | return; 63 | } 64 | 65 | Hook.InjectionIndex = (int)injectionindex.Value; 66 | NotifyChanges(); 67 | } 68 | 69 | private void returnbehavior_SelectedIndexChanged(object sender, EventArgs e) 70 | { 71 | if (_ignoreChanges) 72 | { 73 | return; 74 | } 75 | 76 | Hook.ReturnBehavior = (ReturnBehavior)returnbehavior.SelectedIndex; 77 | NotifyChanges(); 78 | } 79 | 80 | private void argumentbehavior_SelectedIndexChanged(object sender, EventArgs e) 81 | { 82 | if (_ignoreChanges) 83 | { 84 | return; 85 | } 86 | 87 | Hook.ArgumentBehavior = (ArgumentBehavior)argumentbehavior.SelectedIndex; 88 | NotifyChanges(); 89 | } 90 | 91 | private void argumentstring_TextChanged(object sender, EventArgs e) 92 | { 93 | if (_ignoreChanges) 94 | { 95 | return; 96 | } 97 | 98 | Hook.ArgumentString = argumentstring.Text; 99 | NotifyChanges(); 100 | } 101 | 102 | private void chkIsDeprecated_CheckedChanged(object sender, EventArgs e) 103 | { 104 | if (_ignoreChanges || !(sender is CheckBox checkBox)) 105 | { 106 | return; 107 | } 108 | 109 | _ignoreChanges = true; 110 | 111 | DateTime initialDeprecationDate = DateTime.Now.AddDays(60); 112 | dtpRemovalDate.Value = initialDeprecationDate; 113 | 114 | Hook.Deprecation = checkBox.Checked ? new Simple.DeprecatedStatus 115 | { 116 | RemovalDate = initialDeprecationDate, 117 | ReplacementHook = txtTargetHook.Text 118 | } : null; 119 | 120 | HandleDeprecationFieldsVisibility(checkBox.Checked); 121 | 122 | _ignoreChanges = false; 123 | 124 | NotifyChanges(); 125 | } 126 | 127 | private void HandleDeprecationFieldsVisibility(bool shouldShow) 128 | { 129 | lblTargetHook.Visible = shouldShow; 130 | txtTargetHook.Visible = shouldShow; 131 | lblRemovalDate.Visible = shouldShow; 132 | dtpRemovalDate.Visible = shouldShow; 133 | } 134 | 135 | private void txtTargetHook_TextChanged(object sender, EventArgs e) 136 | { 137 | if (_ignoreChanges) 138 | { 139 | return; 140 | } 141 | 142 | Hook.Deprecation.ReplacementHook = txtTargetHook.Text.Trim(); 143 | 144 | NotifyChanges(); 145 | } 146 | 147 | private void dtpRemovalDate_ValueChanged(object sender, EventArgs e) 148 | { 149 | if (_ignoreChanges) 150 | { 151 | return; 152 | } 153 | 154 | Hook.Deprecation.RemovalDate = dtpRemovalDate.Value; 155 | 156 | NotifyChanges(); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Views/SimpleHookSettingsControl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | --------------------------------------------------------------------------------