├── .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 [](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 |
--------------------------------------------------------------------------------