├── UnityInspector.GUI ├── icon.ico ├── packages.config ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Models │ ├── MonoProcess.cs │ ├── EnumMember.cs │ ├── Vector2.cs │ ├── Vector3.cs │ ├── ArrayMember.cs │ ├── Rect.cs │ ├── Component.cs │ ├── GameObject.cs │ ├── ObjectMember.cs │ └── CommunicatorClient.cs ├── App.xaml.cs ├── Converters │ ├── BooleanToVisibilityConverter.cs │ ├── ICollectionToBooleanConverter.cs │ ├── BooleanConverter.cs │ └── ObjectMemberTemplateSelector.cs ├── ViewModels │ ├── ViewModel.cs │ ├── RelayCommand.cs │ ├── ObjectMemberViewModel.cs │ ├── NumericTextBox.cs │ ├── ArrayMemberViewModel.cs │ ├── ComponentViewModel.cs │ ├── GameObjectViewModel.cs │ └── MainWindowViewModel.cs ├── App.xaml ├── MainWindow.xaml.cs ├── Utils.cs ├── UnityInspector.GUI.csproj ├── MainWindow.xaml └── UnityStyle.xaml ├── SharpMonoInjector ├── Properties │ ├── Settings.settings │ └── Settings.Designer.cs ├── MonoImageOpenStatus.cs ├── ExportedFunction.cs ├── InjectorException.cs ├── SharpMonoInjector.csproj ├── Assembler.cs ├── Memory.cs ├── ProcessUtils.cs ├── Native.cs └── Injector.cs ├── LICENSE ├── README.md ├── UnityInspector.Communicator ├── UnityInspector.Communicator.csproj └── Communicator.cs ├── .gitattributes ├── UnityInspector.sln ├── UnityInspector.Injector ├── UnityInspector.Injector.csproj ├── CommunicatorServer.cs └── Injector.cs └── .gitignore /UnityInspector.GUI/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohelm97/UnityInspector/HEAD/UnityInspector.GUI/icon.ico -------------------------------------------------------------------------------- /UnityInspector.GUI/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /UnityInspector.GUI/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SharpMonoInjector/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SharpMonoInjector/MonoImageOpenStatus.cs: -------------------------------------------------------------------------------- 1 | namespace SharpMonoInjector 2 | { 3 | public enum MonoImageOpenStatus 4 | { 5 | MONO_IMAGE_OK, 6 | MONO_IMAGE_ERROR_ERRNO, 7 | MONO_IMAGE_MISSING_ASSEMBLYREF, 8 | MONO_IMAGE_IMAGE_INVALID 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/MonoProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnityInspector.GUI.ViewModels 4 | { 5 | public class MonoProcess 6 | { 7 | public IntPtr MonoModule { get; set; } 8 | 9 | public string Name { get; set; } 10 | 11 | public int Id { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /SharpMonoInjector/ExportedFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpMonoInjector 4 | { 5 | public struct ExportedFunction 6 | { 7 | public string Name; 8 | 9 | public IntPtr Address; 10 | 11 | public ExportedFunction(string name, IntPtr address) 12 | { 13 | Name = name; 14 | Address = address; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SharpMonoInjector/InjectorException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpMonoInjector 4 | { 5 | public class InjectorException : Exception 6 | { 7 | public InjectorException(string message) : base(message) 8 | { 9 | } 10 | 11 | public InjectorException(string message, Exception innerException) : base(message, innerException) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /UnityInspector.GUI/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace UnityInspector.GUI 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Converters/BooleanToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace UnityInspector.GUI.Converters 9 | { 10 | public sealed class BooleanToVisibilityConverter : BooleanConverter 11 | { 12 | public BooleanToVisibilityConverter() : 13 | base(Visibility.Visible, Visibility.Collapsed) 14 | { } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/ViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnityInspector.GUI.ViewModels 9 | { 10 | public abstract class ViewModel : INotifyPropertyChanged 11 | { 12 | public event PropertyChangedEventHandler PropertyChanged; 13 | protected void RaisePropertyChanged(string name) 14 | { 15 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /UnityInspector.GUI/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Converters/ICollectionToBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Data; 9 | 10 | namespace UnityInspector.GUI.Converters 11 | { 12 | class ICollectionToBooleanConverter : IValueConverter 13 | { 14 | public object Convert (object value, Type targetType, object parameter, CultureInfo culture) 15 | { 16 | if (value == null) return false; 17 | return ((ICollection) value).Count > 0; 18 | } 19 | 20 | public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | throw new NotImplementedException (); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/EnumMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnityInspector.GUI.Models 8 | { 9 | class EnumMember 10 | { 11 | private string _value; 12 | 13 | public ObjectMember objectMember; 14 | public string[] Values { get; } 15 | public string Value { 16 | get 17 | { 18 | return _value; 19 | } 20 | set 21 | { 22 | _value = value; 23 | if (objectMember != null) 24 | objectMember.UpdateValue (); 25 | } 26 | } 27 | 28 | public EnumMember (string[] values, string value) 29 | { 30 | Values = values; 31 | _value = value; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/RelayCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Input; 7 | 8 | namespace UnityInspector.GUI.ViewModels 9 | { 10 | public class RelayCommand : ICommand 11 | { 12 | public event EventHandler CanExecuteChanged; 13 | 14 | private readonly Action _execute; 15 | 16 | private readonly Func _canExecute; 17 | 18 | public RelayCommand (Action execute, Func canExecute = null) 19 | { 20 | _execute = execute; 21 | _canExecute = canExecute; 22 | } 23 | 24 | public bool CanExecute (object parameter) => _canExecute == null || _canExecute (parameter); 25 | 26 | public void Execute (object parameter) => _execute (parameter); 27 | 28 | public void RaiseCanExecuteChanged () => CanExecuteChanged?.Invoke (this, EventArgs.Empty); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SharpMonoInjector/SharpMonoInjector.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net461 5 | AnyCPU 6 | 7 | 8 | 9 | ..\..\build\debug 10 | 11 | 12 | 13 | ..\..\build\release 14 | 15 | 16 | 17 | 18 | True 19 | True 20 | Settings.settings 21 | 22 | 23 | 24 | 25 | 26 | SettingsSingleFileGenerator 27 | Settings.Designer.cs 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Converters/BooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace UnityInspector.GUI.Converters 10 | { 11 | public class BooleanConverter : IValueConverter 12 | { 13 | public BooleanConverter(T trueValue, T falseValue) 14 | { 15 | True = trueValue; 16 | False = falseValue; 17 | } 18 | 19 | public T True { get; set; } 20 | public T False { get; set; } 21 | 22 | public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) 23 | { 24 | return value is bool && ((bool)value) ? True : False; 25 | } 26 | 27 | public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | return value is T && EqualityComparer.Default.Equals((T)value, True); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/Vector2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnityInspector.GUI.Models 8 | { 9 | class Vector2 10 | { 11 | public ObjectMember objectMember; 12 | private float _x, _y; 13 | public float X 14 | { 15 | get 16 | { 17 | return _x; 18 | } 19 | set 20 | { 21 | _x = value; 22 | if (objectMember != null) objectMember.UpdateValue (); 23 | } 24 | } 25 | public float Y 26 | { 27 | get 28 | { 29 | return _y; 30 | } 31 | set 32 | { 33 | _y = value; 34 | if (objectMember != null) objectMember.UpdateValue (); 35 | } 36 | } 37 | 38 | 39 | public Vector2 (float x, float y) 40 | { 41 | X = x; 42 | Y = y; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Mohammed ALMadhoun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SharpMonoInjector/Properties/Settings.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 SharpMonoInjector.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.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 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Properties/Settings.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 UnityInspector.GUI.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.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 | -------------------------------------------------------------------------------- /UnityInspector.GUI/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Controls.Primitives; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | using UnityInspector.GUI.Models; 18 | 19 | namespace UnityInspector.GUI 20 | { 21 | 22 | /// 23 | /// Interaction logic for MainWindow.xaml 24 | /// 25 | public partial class MainWindow : Window 26 | { 27 | 28 | public MainWindow () 29 | { 30 | InitializeComponent (); 31 | 32 | 33 | } 34 | 35 | private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 36 | { 37 | if (CommunicatorClient.Instance != null) 38 | CommunicatorClient.Instance.Close(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnityInspector.GUI 9 | { 10 | class Utils 11 | { 12 | public static void SyncObservableCollection (ObservableCollection collection, T[] array) 13 | { 14 | for (int i = 0; i < array.Length; i++) 15 | { 16 | int oldIndex = collection.IndexOf (array[i]); 17 | if (oldIndex == -1) 18 | { 19 | collection.Insert (i, array[i]); 20 | } 21 | else 22 | { 23 | T oldChild = collection[oldIndex]; 24 | if (oldIndex != i) 25 | collection.Move (oldIndex, i); 26 | } 27 | } 28 | // If we move all object to the correct order, 29 | // and add the new one in the correct position 30 | // then the deleted one will be after children.length 31 | int collectionCount = collection.Count; 32 | for (int i = array.Length; i < collectionCount; i++) 33 | { 34 | collection.RemoveAt (array.Length); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/Vector3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnityInspector.GUI.Models 8 | { 9 | class Vector3 10 | { 11 | public ObjectMember objectMember; 12 | private float _x, _y, _z; 13 | public float X 14 | { 15 | get 16 | { 17 | return _x; 18 | } 19 | set 20 | { 21 | _x = value; 22 | if (objectMember != null) objectMember.UpdateValue (); 23 | } 24 | } 25 | public float Y 26 | { 27 | get 28 | { 29 | return _y; 30 | } 31 | set 32 | { 33 | _y = value; 34 | if (objectMember != null) objectMember.UpdateValue (); 35 | } 36 | } 37 | public float Z 38 | { 39 | get 40 | { 41 | return _z; 42 | } 43 | set 44 | { 45 | _z = value; 46 | if (objectMember != null) objectMember.UpdateValue (); 47 | } 48 | } 49 | 50 | 51 | public Vector3 (float x, float y, float z) 52 | { 53 | X = x; 54 | Y = y; 55 | Z = z; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/ArrayMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnityInspector.Communicator; 7 | 8 | namespace UnityInspector.GUI.Models 9 | { 10 | public class ArrayMember 11 | { 12 | public ObjectMember objectMember; 13 | public int Length { get; } 14 | public CommunicatorClient.Types BaseType { get; } 15 | public ObjectMember[] Values 16 | { 17 | get 18 | { 19 | object[] values = (object[]) (Array) objectMember.GetValue (); 20 | ObjectMember[] valuesAsMember = new ObjectMember[values.Length]; 21 | for (int i = 0; i < values.Length; i++) 22 | { 23 | valuesAsMember[i] = new ObjectMember (objectMember, BaseType, "[" + i + "]", values[i]); 24 | } 25 | return valuesAsMember; 26 | } 27 | } 28 | 29 | public ArrayMember (int length, Communicator.Types baseType) 30 | { 31 | Length = length; 32 | BaseType = baseType; 33 | } 34 | 35 | public override bool Equals(object obj) 36 | { 37 | if (obj != null && obj is ArrayMember) 38 | return objectMember.Equals(((ArrayMember)obj).objectMember); 39 | return false; 40 | } 41 | public override int GetHashCode() 42 | { 43 | return objectMember.GetHashCode(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![UnityInspector Logo](https://user-images.githubusercontent.com/1688821/56691454-aba9f980-66e8-11e9-90b6-4fdf714404b2.png) UnityInspector 2 | 3 | A simple tool for inspecting and editing managed Unity3d games in real-time, using a simple layout you can see game objects in the active scene, and you can click at any game object to see its components, and click at any component to see its members and edit values. 4 | 5 |

6 | Screenshot 7 |

8 | 9 | ## How to build 10 | 1. Clone the project. 11 | 2. Add UnityEngine.dll refrence to UnityInspector.Inejctor. 12 | 3. Tadaaa. 13 | 14 | ## How UnityInspector works 15 | First I tried to build this using a direct memory read and write method and it works kinda well (I'm lying), but using the previous method will leave a lot of work to do for each unity3d engine version (but it works on managed and il2cpp games). 16 | So now this project is using the awesome [warbler/SharpMonoInjector](https://github.com/warbler/SharpMonoInjector) to inject a managed dll inside mono which communicates through TCP with the main program, well and some cool C# code. 17 |

18 | A diagram just to make it cool 19 |

20 | 21 | ## Todo 22 | - [ ] Add data locks 23 | - [ ] Some error handling 24 | - [ ] Support nested objects 25 | - [ ] Change GameObjects and components references 26 | - [ ] Browse prefabs and other GameObjects 27 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/Rect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UnityInspector.GUI.Models 8 | { 9 | class Rect 10 | { 11 | public ObjectMember objectMember; 12 | private float _x, _y, _w, _h; 13 | public float X 14 | { 15 | get 16 | { 17 | return _x; 18 | } 19 | set 20 | { 21 | _x = value; 22 | if (objectMember != null) objectMember.UpdateValue (); 23 | } 24 | } 25 | public float Y 26 | { 27 | get 28 | { 29 | return _y; 30 | } 31 | set 32 | { 33 | _y = value; 34 | if (objectMember != null) objectMember.UpdateValue (); 35 | } 36 | } 37 | public float W 38 | { 39 | get 40 | { 41 | return _w; 42 | } 43 | set 44 | { 45 | _w = value; 46 | if (objectMember != null) objectMember.UpdateValue (); 47 | } 48 | } 49 | public float H 50 | { 51 | get 52 | { 53 | return _h; 54 | } 55 | set 56 | { 57 | _h = value; 58 | if (objectMember != null) objectMember.UpdateValue (); 59 | } 60 | } 61 | 62 | 63 | public Rect (float x, float y, float w, float h) 64 | { 65 | X = x; 66 | Y = y; 67 | W = w; 68 | H = h; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/ObjectMemberViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnityInspector.GUI.Models; 8 | 9 | namespace UnityInspector.GUI.ViewModels 10 | { 11 | public class ObjectMemberViewModel : ViewModel 12 | { 13 | public ObjectMember objectMember; 14 | public CommunicatorClient.Types Type { get { return objectMember.Type; } } 15 | public string Name { get { return objectMember.Name; } } 16 | private object _value; 17 | public object Value { get { return _value; } set { objectMember.Value = value; _value = objectMember.Value; } } 18 | 19 | public ObjectMemberViewModel (ObjectMember objectMember) 20 | { 21 | this.objectMember = objectMember; 22 | _value = objectMember.Value; 23 | if (_value is ArrayMember arrayMember) 24 | { 25 | _value = new ArrayMemberViewModel (arrayMember); 26 | } 27 | } 28 | 29 | public void Update (ObjectMember newObjectMember) 30 | { 31 | objectMember = newObjectMember; 32 | if (_value is ArrayMemberViewModel valueViewModel) 33 | { 34 | valueViewModel.Update ((ArrayMember) objectMember.Value); 35 | } 36 | else 37 | { 38 | _value = objectMember.Value; 39 | RaisePropertyChanged("Value"); 40 | } 41 | } 42 | 43 | public override bool Equals (object obj) 44 | { 45 | if (obj != null && obj is ObjectMemberViewModel) 46 | return (objectMember.Equals (((ObjectMemberViewModel) obj).objectMember)); 47 | 48 | return false; 49 | } 50 | public override int GetHashCode () 51 | { 52 | return objectMember.GetHashCode (); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/Component.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UnityInspector.GUI.Models 9 | { 10 | public class Component 11 | { 12 | public GameObject Owner { get; } 13 | public string Name { get; } 14 | public bool IsBehaviour { get; } 15 | public int Index { get; } 16 | private bool _enabled; 17 | public bool Enabled 18 | { 19 | get 20 | { 21 | return _enabled; 22 | } 23 | set 24 | { 25 | if (!IsBehaviour) return; 26 | _enabled = value; 27 | CommunicatorClient.Instance.SetValueOfMember (Owner, Index + ":enabled", _enabled); 28 | } 29 | } 30 | 31 | public Component (GameObject gameObject, int index, string name, byte state) 32 | { 33 | Index = index; 34 | Owner = gameObject; 35 | Name = name; 36 | if (state == 0) 37 | { 38 | IsBehaviour = false; 39 | _enabled = true; 40 | } else 41 | { 42 | IsBehaviour = true; 43 | _enabled = (state == 0x01); 44 | } 45 | } 46 | 47 | public ObjectMember[] Members 48 | { 49 | get 50 | { 51 | return CommunicatorClient.Instance.GetComponentMembers (this); 52 | } 53 | } 54 | public override string ToString () 55 | { 56 | return Name; 57 | } 58 | 59 | public override bool Equals (object obj) 60 | { 61 | 62 | if (obj != null && obj is Component) { 63 | return (Owner.Equals(((Component) obj).Owner) && Index == ((Component) obj).Index && Name == ((Component) obj).Name); 64 | } 65 | return false; 66 | } 67 | public override int GetHashCode () 68 | { 69 | return Owner.GetHashCode () + Index + Name.GetHashCode (); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/NumericTextBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Input; 11 | 12 | namespace UnityInspector.GUI.ViewModels 13 | { 14 | public class NumericTextBox : TextBox 15 | { 16 | bool isControlling; 17 | Point lastMousePosition; 18 | public double doubleValue; 19 | BindingExpression be; 20 | public NumericTextBox () : base () 21 | { 22 | Cursor = Cursors.SizeWE; 23 | 24 | } 25 | 26 | protected override void OnInitialized(EventArgs e) 27 | { 28 | base.OnInitialized(e); 29 | be = GetBindingExpression(TextProperty); 30 | } 31 | 32 | protected override void OnMouseMove (MouseEventArgs e) 33 | { 34 | if (isControlling) 35 | { 36 | Point currentMousePosition = e.GetPosition (this); 37 | float deltaMove = (float) (currentMousePosition.X - lastMousePosition.X) / 10; 38 | doubleValue += deltaMove; 39 | Text = doubleValue.ToString (); 40 | be.UpdateSource(); 41 | lastMousePosition = currentMousePosition; 42 | } 43 | } 44 | protected override void OnMouseUp (MouseButtonEventArgs e) 45 | { 46 | base.OnMouseUp (e); 47 | isControlling = false; 48 | } 49 | protected override void OnTextInput(TextCompositionEventArgs e) 50 | { 51 | base.OnTextInput(e); 52 | if (Text[Text.Length - 1] != '.') 53 | be.UpdateSource(); 54 | } 55 | 56 | protected override void OnMouseDown (MouseButtonEventArgs e) 57 | { 58 | base.OnMouseDown (e); 59 | doubleValue = 0; 60 | double.TryParse (Text, out doubleValue); 61 | isControlling = true; 62 | lastMousePosition = e.GetPosition (this); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/GameObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using UnityInspector.Communicator; 8 | 9 | namespace UnityInspector.GUI.Models 10 | { 11 | public class GameObject 12 | { 13 | private bool _active; 14 | public int Address { get; } 15 | public string Name { get; } 16 | public bool Active 17 | { 18 | get { return _active; } 19 | set 20 | { 21 | _active = value; 22 | CommunicatorClient.Instance.InvokeMethod (this, "SetActive", new object[] { _active }); 23 | } 24 | } 25 | public GameObject[] Children 26 | { 27 | get 28 | { 29 | if (CommunicatorClient.Instance == null || !CommunicatorClient.Instance.Connected) 30 | return new GameObject[0]; 31 | if (Address == 0) 32 | return CommunicatorClient.Instance.ReadHierarchy (); 33 | return CommunicatorClient.Instance.GetChildren (this); 34 | } 35 | } 36 | 37 | public Component[] Components 38 | { 39 | get 40 | { 41 | if (Address == 0 || CommunicatorClient.Instance == null || !CommunicatorClient.Instance.Connected) 42 | return new Component[0]; 43 | return CommunicatorClient.Instance.GetComponents (this); 44 | } 45 | } 46 | 47 | public GameObject (int address, string name, bool active) 48 | { 49 | Address = address; 50 | Name = name; 51 | _active = active; 52 | } 53 | 54 | public override string ToString () 55 | { 56 | return Name; 57 | } 58 | public override bool Equals (object obj) 59 | { 60 | if (obj is GameObject && obj != null) 61 | return Address == ((GameObject) obj).Address; 62 | return false; 63 | } 64 | public override int GetHashCode () 65 | { 66 | return Address; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /UnityInspector.Communicator/UnityInspector.Communicator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AF3B27C3-615E-46DD-80B0-76C6E106C64D} 8 | Library 9 | Properties 10 | UnityInspector.Communicator 11 | UnityInspector.Communicator 12 | v4.6.1 13 | 512 14 | true 15 | 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/ArrayMemberViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using UnityInspector.GUI.Models; 9 | 10 | namespace UnityInspector.GUI.ViewModels 11 | { 12 | public class ArrayMemberViewModel : ViewModel 13 | { 14 | public ArrayMember arrayMember; 15 | public int Length { get { return arrayMember.Length; } } 16 | public CommunicatorClient.Types BaseType { get { return arrayMember.BaseType; } } 17 | public bool IsExpanded { get; set; } 18 | public string StringType { get { return arrayMember.BaseType + "[" + arrayMember.Length + "]"; } } 19 | private ObservableCollection _values; 20 | 21 | public object Values 22 | { 23 | get 24 | { 25 | UpdateValues (); 26 | return _values; 27 | } 28 | } 29 | 30 | public ArrayMemberViewModel (ArrayMember arrayMember) 31 | { 32 | this.arrayMember = arrayMember; 33 | } 34 | public void Update (ArrayMember arrayMember) 35 | { 36 | this.arrayMember = arrayMember; 37 | RaisePropertyChanged("StringType"); 38 | if (IsExpanded) 39 | RaisePropertyChanged("Values"); 40 | } 41 | private void UpdateValues () 42 | { 43 | ObjectMemberViewModel[] values = Array.ConvertAll (arrayMember.Values, e => new ObjectMemberViewModel (e)); 44 | if (_values == null) 45 | { 46 | _values = new ObservableCollection (values); 47 | } 48 | else 49 | { 50 | Utils.SyncObservableCollection (_values, values); 51 | for (int i = 0; i < _values.Count; i++) 52 | _values[i].Update (values[i].objectMember); 53 | } 54 | } 55 | 56 | public override bool Equals(object obj) 57 | { 58 | if (obj != null && obj is ArrayMemberViewModel) 59 | return (arrayMember.Equals(((ArrayMemberViewModel)obj).arrayMember)); 60 | 61 | return false; 62 | } 63 | public override int GetHashCode() 64 | { 65 | return arrayMember.GetHashCode(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/ComponentViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using UnityInspector.GUI.Models; 10 | using Component = UnityInspector.GUI.Models.Component; 11 | 12 | namespace UnityInspector.GUI.ViewModels 13 | { 14 | public class ComponentViewModel : ViewModel 15 | { 16 | public Component component; 17 | public string Name { get { return component.Name; } } 18 | public bool IsBehaviour { get { return component.IsBehaviour; } } 19 | public Visibility Visibility { get { return IsBehaviour ? Visibility.Visible : Visibility.Hidden; } } 20 | public bool Enabled { get { return component.Enabled; } set { component.Enabled = value; } } 21 | public bool IsSelected { get; set; } 22 | 23 | private ObservableCollection _members; 24 | public ObservableCollection Members { 25 | get 26 | { 27 | UpdateMembers (); 28 | return _members; 29 | } 30 | } 31 | 32 | public ComponentViewModel (Component component) 33 | { 34 | this.component = component; 35 | } 36 | 37 | public void Update (Component newComponent) 38 | { 39 | component = newComponent; 40 | RaisePropertyChanged ("Enabled"); 41 | RaisePropertyChanged ("Members"); 42 | } 43 | 44 | private void UpdateMembers () 45 | { 46 | ObjectMemberViewModel[] members = Array.ConvertAll (component.Members, e => new ObjectMemberViewModel (e)); 47 | if (_members == null) 48 | { 49 | _members = new ObservableCollection (members); 50 | } 51 | else 52 | { 53 | Utils.SyncObservableCollection (_members, members); 54 | for (int i = 0; i < _members.Count; i++) 55 | _members[i].Update (members[i].objectMember); 56 | } 57 | } 58 | 59 | public override bool Equals (object obj) 60 | { 61 | if (obj != null && obj is ComponentViewModel) 62 | return (component.Equals (((ComponentViewModel) obj).component)); 63 | 64 | return false; 65 | } 66 | public override int GetHashCode () 67 | { 68 | return component.GetHashCode (); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle ("UnityInspector.GUI")] 11 | [assembly: AssemblyDescription ("A tool for inspecting and editing managed Unity3d game in real-time")] 12 | [assembly: AssemblyConfiguration ("")] 13 | [assembly: AssemblyCompany ("Mohelm97")] 14 | [assembly: AssemblyProduct ("UnityInspector")] 15 | [assembly: AssemblyCopyright ("Copyright (c) 2019 Mohammed ALMadhoun")] 16 | [assembly: AssemblyTrademark ("")] 17 | [assembly: AssemblyCulture ("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible (false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo ( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion ("1.0.0.0")] 55 | [assembly: AssemblyFileVersion ("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /.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 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj 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 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /UnityInspector.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.421 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityInspector.GUI", "UnityInspector.GUI\UnityInspector.GUI.csproj", "{71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityInspector.Injector", "UnityInspector.Injector\UnityInspector.Injector.csproj", "{4477ADED-191B-4D36-B4A4-C44F1E74292B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityInspector.Communicator", "UnityInspector.Communicator\UnityInspector.Communicator.csproj", "{AF3B27C3-615E-46DD-80B0-76C6E106C64D}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpMonoInjector", "SharpMonoInjector\SharpMonoInjector.csproj", "{500155A7-3C29-4944-9031-6994B56E1797}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {4477ADED-191B-4D36-B4A4-C44F1E74292B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {4477ADED-191B-4D36-B4A4-C44F1E74292B}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {4477ADED-191B-4D36-B4A4-C44F1E74292B}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {4477ADED-191B-4D36-B4A4-C44F1E74292B}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {AF3B27C3-615E-46DD-80B0-76C6E106C64D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {AF3B27C3-615E-46DD-80B0-76C6E106C64D}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {AF3B27C3-615E-46DD-80B0-76C6E106C64D}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {AF3B27C3-615E-46DD-80B0-76C6E106C64D}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {500155A7-3C29-4944-9031-6994B56E1797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {500155A7-3C29-4944-9031-6994B56E1797}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {500155A7-3C29-4944-9031-6994B56E1797}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {500155A7-3C29-4944-9031-6994B56E1797}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {8C06758D-F486-449B-A0B3-711AD966344F} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Converters/ObjectMemberTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using UnityInspector.GUI.Models; 9 | using UnityInspector.GUI.ViewModels; 10 | 11 | namespace UnityInspector.GUI.Converters 12 | { 13 | public class ObjectMemberTemplateSelector : DataTemplateSelector 14 | { 15 | public override DataTemplate SelectTemplate (object item, DependencyObject container) 16 | { 17 | FrameworkElement element = container as FrameworkElement; 18 | ObjectMemberViewModel member = item as ObjectMemberViewModel; 19 | if (member.Type == CommunicatorClient.Types.Bool) 20 | { 21 | return element.FindResource ("BoolMemberDataTemplate") as DataTemplate; 22 | } 23 | else if (member.Type > CommunicatorClient.Types.Bool && member.Type < CommunicatorClient.Types.String) 24 | { 25 | return element.FindResource ("NumericMemberDataTemplate") as DataTemplate; 26 | } 27 | else if (member.Type == CommunicatorClient.Types.Array) 28 | { 29 | return element.FindResource ("ArrayMemberDataTemplate") as DataTemplate; 30 | } 31 | else if (member.Type == CommunicatorClient.Types.Vector3) 32 | { 33 | return element.FindResource ("Vector3MemberDataTemplate") as DataTemplate; 34 | } 35 | else if (member.Type == CommunicatorClient.Types.Enum) 36 | { 37 | return element.FindResource ("EnumMemberDataTemplate") as DataTemplate; 38 | } 39 | else if (member.Type == CommunicatorClient.Types.Color) 40 | { 41 | return element.FindResource ("ColorMemberDataTemplate") as DataTemplate; 42 | } 43 | else if (member.Type == CommunicatorClient.Types.Vector2) 44 | { 45 | return element.FindResource ("Vector2MemberDataTemplate") as DataTemplate; 46 | } 47 | else if (member.Type == CommunicatorClient.Types.Rect) 48 | { 49 | return element.FindResource ("RectMemberDataTemplate") as DataTemplate; 50 | } 51 | else if(member.Type == CommunicatorClient.Types.GameObject) 52 | { 53 | return element.FindResource("GameObjectMemberDataTemplate") as DataTemplate; 54 | } 55 | else if(member.Type != CommunicatorClient.Types.Unknown) 56 | { 57 | return element.FindResource ("TextBoxMemberDataTemplate") as DataTemplate; 58 | } 59 | else 60 | { 61 | return element.FindResource ("UnknownMemberDataTemplate") as DataTemplate; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SharpMonoInjector/Assembler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SharpMonoInjector 5 | { 6 | public class Assembler 7 | { 8 | private readonly List _asm = new List(); 9 | 10 | public void MovRax(IntPtr arg) 11 | { 12 | _asm.AddRange(new byte[] {0x48, 0xB8}); 13 | _asm.AddRange(BitConverter.GetBytes((long)arg)); 14 | } 15 | 16 | public void MovRcx(IntPtr arg) 17 | { 18 | _asm.AddRange(new byte[] {0x48, 0xB9}); 19 | _asm.AddRange(BitConverter.GetBytes((long)arg)); 20 | } 21 | 22 | public void MovRdx(IntPtr arg) 23 | { 24 | _asm.AddRange(new byte[] {0x48, 0xBA}); 25 | _asm.AddRange(BitConverter.GetBytes((long)arg)); 26 | } 27 | 28 | public void MovR8(IntPtr arg) 29 | { 30 | _asm.AddRange(new byte[] {0x49, 0xB8}); 31 | _asm.AddRange(BitConverter.GetBytes((long)arg)); 32 | } 33 | 34 | public void MovR9(IntPtr arg) 35 | { 36 | _asm.AddRange(new byte[] {0x49, 0xB9}); 37 | _asm.AddRange(BitConverter.GetBytes((long)arg)); 38 | } 39 | 40 | public void SubRsp(byte arg) 41 | { 42 | _asm.AddRange(new byte[] {0x48, 0x83, 0xEC}); 43 | _asm.Add(arg); 44 | } 45 | 46 | public void CallRax() 47 | { 48 | _asm.AddRange(new byte[] {0xFF, 0xD0}); 49 | } 50 | 51 | public void AddRsp(byte arg) 52 | { 53 | _asm.AddRange(new byte[] {0x48, 0x83, 0xC4}); 54 | _asm.Add(arg); 55 | } 56 | 57 | public void MovRaxTo(IntPtr dest) 58 | { 59 | _asm.AddRange(new byte[] { 0x48, 0xA3 }); 60 | _asm.AddRange(BitConverter.GetBytes((long)dest)); 61 | } 62 | 63 | public void Push(IntPtr arg) 64 | { 65 | _asm.Add((int)arg < 128 ? (byte)0x6A : (byte)0x68); 66 | _asm.AddRange((int)arg <= 255 ? new[] {(byte)arg} : BitConverter.GetBytes((int)arg)); 67 | } 68 | 69 | public void MovEax(IntPtr arg) 70 | { 71 | _asm.Add(0xB8); 72 | _asm.AddRange(BitConverter.GetBytes((int)arg)); 73 | } 74 | 75 | public void CallEax() 76 | { 77 | _asm.AddRange(new byte[] {0xFF, 0xD0}); 78 | } 79 | 80 | public void AddEsp(byte arg) 81 | { 82 | _asm.AddRange(new byte[] {0x83, 0xC4}); 83 | _asm.Add(arg); 84 | } 85 | 86 | public void MovEaxTo(IntPtr dest) 87 | { 88 | _asm.Add(0xA3); 89 | _asm.AddRange(BitConverter.GetBytes((int)dest)); 90 | } 91 | 92 | public void Return() 93 | { 94 | _asm.Add(0xC3); 95 | } 96 | 97 | public byte[] ToByteArray() => _asm.ToArray(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /UnityInspector.GUI/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 UnityInspector.GUI.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", "15.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("UnityInspector.GUI.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 | -------------------------------------------------------------------------------- /UnityInspector.Injector/UnityInspector.Injector.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4477ADED-191B-4D36-B4A4-C44F1E74292B} 8 | Library 9 | Properties 10 | UnityInspectorInjector 11 | UnityInspector.Injector 12 | v3.5 13 | 512 14 | true 15 | Unity Subset v3.5 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | False 43 | ..\ExternalDlls\UnityEngine.dll 44 | 45 | 46 | 47 | 48 | Communicator.cs 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | xcopy "$(TargetDir)$(TargetFileName)" "$(SolutionDir)\UnityInspector.GUI\$(OutDir)" /Y 67 | 68 | -------------------------------------------------------------------------------- /SharpMonoInjector/Memory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace SharpMonoInjector 8 | { 9 | public class Memory : IDisposable 10 | { 11 | private readonly IntPtr _handle; 12 | 13 | private readonly Dictionary _allocations = new Dictionary(); 14 | 15 | public Memory(IntPtr processHandle) 16 | { 17 | _handle = processHandle; 18 | } 19 | 20 | public string ReadString(IntPtr address, int length, Encoding encoding) 21 | { 22 | List bytes = new List(); 23 | 24 | for (int i = 0; i < length; i++) { 25 | byte read = ReadBytes(address + bytes.Count, 1)[0]; 26 | 27 | if (read == 0x00) 28 | break; 29 | 30 | bytes.Add(read); 31 | } 32 | 33 | return encoding.GetString(bytes.ToArray()); 34 | } 35 | 36 | public string ReadUnicodeString(IntPtr address, int length) 37 | { 38 | return Encoding.Unicode.GetString(ReadBytes(address, length)); 39 | } 40 | 41 | public short ReadShort(IntPtr address) 42 | { 43 | return BitConverter.ToInt16(ReadBytes(address, 2), 0); 44 | } 45 | 46 | public int ReadInt(IntPtr address) 47 | { 48 | return BitConverter.ToInt32(ReadBytes(address, 4), 0); 49 | } 50 | 51 | public long ReadLong(IntPtr address) 52 | { 53 | return BitConverter.ToInt64(ReadBytes(address, 8), 0); 54 | } 55 | 56 | public byte[] ReadBytes(IntPtr address, int size) 57 | { 58 | byte[] bytes = new byte[size]; 59 | 60 | if (!Native.ReadProcessMemory(_handle, address, bytes, size)) 61 | throw new InjectorException("Failed to read process memory", new Win32Exception(Marshal.GetLastWin32Error())); 62 | 63 | return bytes; 64 | } 65 | 66 | public IntPtr AllocateAndWrite(byte[] data) 67 | { 68 | IntPtr addr = Allocate(data.Length); 69 | Write(addr, data); 70 | return addr; 71 | } 72 | 73 | public IntPtr AllocateAndWrite(string data) => AllocateAndWrite(Encoding.UTF8.GetBytes(data)); 74 | 75 | public IntPtr AllocateAndWrite(int data) => AllocateAndWrite(BitConverter.GetBytes(data)); 76 | 77 | public IntPtr AllocateAndWrite(long data) => AllocateAndWrite(BitConverter.GetBytes(data)); 78 | 79 | public IntPtr Allocate(int size) 80 | { 81 | IntPtr addr = 82 | Native.VirtualAllocEx(_handle, IntPtr.Zero, size, 83 | AllocationType.MEM_COMMIT, MemoryProtection.PAGE_EXECUTE_READWRITE); 84 | 85 | if (addr == IntPtr.Zero) 86 | throw new InjectorException("Failed to allocate process memory", new Win32Exception(Marshal.GetLastWin32Error())); 87 | 88 | _allocations.Add(addr, size); 89 | return addr; 90 | } 91 | 92 | public void Write(IntPtr addr, byte[] data) 93 | { 94 | if (!Native.WriteProcessMemory(_handle, addr, data, data.Length)) 95 | throw new InjectorException("Failed to write process memory", new Win32Exception(Marshal.GetLastWin32Error())); 96 | } 97 | 98 | public void Dispose() 99 | { 100 | foreach (var kvp in _allocations) 101 | Native.VirtualFreeEx(_handle, kvp.Key, kvp.Value, MemoryFreeType.MEM_DECOMMIT); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /SharpMonoInjector/ProcessUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | 8 | namespace SharpMonoInjector 9 | { 10 | public static class ProcessUtils 11 | { 12 | public static IEnumerable GetExportedFunctions(IntPtr handle, IntPtr mod) 13 | { 14 | using (Memory memory = new Memory(handle)) { 15 | int e_lfanew = memory.ReadInt(mod + 0x3C); 16 | IntPtr ntHeaders = mod + e_lfanew; 17 | IntPtr optionalHeader = ntHeaders + 0x18; 18 | IntPtr dataDirectory = optionalHeader + (Is64BitProcess(handle) ? 0x70 : 0x60); 19 | IntPtr exportDirectory = mod + memory.ReadInt(dataDirectory); 20 | IntPtr names = mod + memory.ReadInt(exportDirectory + 0x20); 21 | IntPtr ordinals = mod + memory.ReadInt(exportDirectory + 0x24); 22 | IntPtr functions = mod + memory.ReadInt(exportDirectory + 0x1C); 23 | int count = memory.ReadInt(exportDirectory + 0x18); 24 | 25 | for (int i = 0; i < count; i++) { 26 | int offset = memory.ReadInt(names + i * 4); 27 | string name = memory.ReadString(mod + offset, 32, Encoding.ASCII); 28 | short ordinal = memory.ReadShort(ordinals + i * 2); 29 | IntPtr address = mod + memory.ReadInt(functions + ordinal * 4); 30 | 31 | if (address != IntPtr.Zero) 32 | yield return new ExportedFunction(name, address); 33 | } 34 | } 35 | } 36 | 37 | public static bool GetMonoModule(IntPtr handle, out IntPtr monoModule) 38 | { 39 | int size = Is64BitProcess(handle) ? 8 : 4; 40 | 41 | IntPtr[] ptrs = new IntPtr[0]; 42 | 43 | if (!Native.EnumProcessModulesEx( 44 | handle, ptrs, 0, out int bytesNeeded, ModuleFilter.LIST_MODULES_ALL)) { 45 | throw new InjectorException("Failed to enumerate process modules", new Win32Exception(Marshal.GetLastWin32Error())); 46 | } 47 | 48 | int count = bytesNeeded / size; 49 | ptrs = new IntPtr[count]; 50 | 51 | if (!Native.EnumProcessModulesEx( 52 | handle, ptrs, bytesNeeded, out bytesNeeded, ModuleFilter.LIST_MODULES_ALL)) { 53 | throw new InjectorException("Failed to enumerate process modules", new Win32Exception(Marshal.GetLastWin32Error())); 54 | } 55 | 56 | for (int i = 0; i < count; i++) { 57 | StringBuilder path = new StringBuilder(260); 58 | Native.GetModuleFileNameEx(handle, ptrs[i], path, 260); 59 | 60 | if (path.ToString().IndexOf("mono", StringComparison.OrdinalIgnoreCase) > -1) { 61 | if (!Native.GetModuleInformation(handle, ptrs[i], out MODULEINFO info, (uint)(size * ptrs.Length))) 62 | throw new InjectorException("Failed to get module information", new Win32Exception(Marshal.GetLastWin32Error())); 63 | 64 | var funcs = GetExportedFunctions(handle, info.lpBaseOfDll); 65 | 66 | if (funcs.Any(f => f.Name == "mono_get_root_domain")) { 67 | monoModule = info.lpBaseOfDll; 68 | return true; 69 | } 70 | } 71 | } 72 | 73 | monoModule = IntPtr.Zero; 74 | return false; 75 | } 76 | 77 | public static bool Is64BitProcess(IntPtr handle) 78 | { 79 | if (!Environment.Is64BitOperatingSystem) 80 | return false; 81 | 82 | if (!Native.IsWow64Process(handle, out bool isWow64)) 83 | return IntPtr.Size == 8; // assume it's the same as the current process 84 | 85 | return !isWow64; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/GameObjectViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using UnityInspector.GUI.Models; 10 | using Component = UnityInspector.GUI.Models.Component; 11 | 12 | namespace UnityInspector.GUI.ViewModels 13 | { 14 | public class GameObjectViewModel : ViewModel 15 | { 16 | public GameObject gameObject; 17 | public string Name { get { return gameObject.Name; } } 18 | public bool Active { get { return gameObject.Active; } 19 | set 20 | { 21 | gameObject.Active = value; 22 | RaisePropertyChanged ("Active"); 23 | } 24 | } 25 | public bool IsExpanded { get; set; } 26 | public bool IsSelected { get; set; } 27 | 28 | private ObservableCollection _children; 29 | public ObservableCollection Children 30 | { 31 | get 32 | { 33 | UpdateChildren (); 34 | return _children; 35 | } 36 | } 37 | 38 | private ObservableCollection _components; 39 | public ObservableCollection Components 40 | { 41 | get 42 | { 43 | UpdateComponents (); 44 | return _components; 45 | } 46 | } 47 | 48 | public GameObjectViewModel (GameObject gameObject) 49 | { 50 | this.gameObject = gameObject; 51 | } 52 | 53 | void UpdateChildren () 54 | { 55 | GameObjectViewModel[] children = Array.ConvertAll (gameObject.Children, e => new GameObjectViewModel (e)); 56 | if (_children == null) 57 | { 58 | _children = new ObservableCollection (children); 59 | } 60 | else 61 | { 62 | Utils.SyncObservableCollection (_children, children); 63 | for (int i = 0; i < _children.Count; i++) 64 | _children[i].Update (children[i].gameObject, IsExpanded); 65 | } 66 | } 67 | void UpdateComponents () 68 | { 69 | ComponentViewModel[] components = Array.ConvertAll (gameObject.Components, e => new ComponentViewModel (e)); 70 | if (_components == null) 71 | { 72 | _components = new ObservableCollection (components); 73 | } 74 | else 75 | { 76 | Utils.SyncObservableCollection (_components, components); 77 | for (int i = 0; i < _components.Count; i++) 78 | _components[i].Update (components[i].component); 79 | } 80 | } 81 | 82 | public void Update (GameObject newGameObject, bool parentIsExpanded) 83 | { 84 | if (newGameObject != null) 85 | gameObject = newGameObject; 86 | RaisePropertyChanged ("Name"); 87 | RaisePropertyChanged ("Active"); 88 | if (parentIsExpanded) 89 | RaisePropertyChanged ("Children"); 90 | RaisePropertyChanged ("Components"); 91 | } 92 | public void Update () 93 | { 94 | Update (null, true); 95 | } 96 | 97 | public override bool Equals (object obj) 98 | { 99 | if (obj != null && obj is GameObjectViewModel) 100 | return (gameObject.Equals(((GameObjectViewModel) obj).gameObject)); 101 | 102 | return false; 103 | } 104 | public override int GetHashCode () 105 | { 106 | return gameObject.GetHashCode (); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/ObjectMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnityInspector.Communicator; 7 | 8 | namespace UnityInspector.GUI.Models 9 | { 10 | public class ObjectMember 11 | { 12 | private object _value; 13 | 14 | public Component Owner { get; } 15 | public ObjectMember Parent { get; } 16 | public CommunicatorClient.Types Type { get; } 17 | public string Name { get; } 18 | public object Value { 19 | get { 20 | return _value; 21 | } 22 | set 23 | { 24 | object tempValue; 25 | if (value is string) 26 | tempValue = FromString ((string) value); 27 | else 28 | tempValue = value; 29 | if (!_value.Equals(tempValue) && tempValue != null) 30 | { 31 | _value = tempValue; 32 | UpdateValue (); 33 | } 34 | } 35 | } 36 | 37 | public ObjectMember (Component owner, Communicator.Types type, string name, object value) 38 | { 39 | Owner = owner; 40 | Type = type; 41 | Name = name; 42 | _value = value; 43 | if (_value is Vector3) 44 | ((Vector3) _value).objectMember = this; 45 | else if (_value is EnumMember) 46 | ((EnumMember) _value).objectMember = this; 47 | else if (_value is Vector2) 48 | ((Vector2) _value).objectMember = this; 49 | else if (_value is Rect) 50 | ((Rect) _value).objectMember = this; 51 | else if (_value is ArrayMember) 52 | ((ArrayMember) _value).objectMember = this; 53 | } 54 | public ObjectMember (ObjectMember parent, Communicator.Types type, string name, object value) : this (parent.Owner, type, name, value) 55 | { 56 | Parent = parent; 57 | } 58 | 59 | public object FromString (string value) 60 | { 61 | double valueDouble = 0; 62 | if (Type > CommunicatorClient.Types.Bool && Type < CommunicatorClient.Types.String) 63 | { 64 | bool isDouble = double.TryParse (value, out valueDouble); 65 | if (!isDouble) 66 | return null; 67 | } 68 | 69 | switch (Type) 70 | { 71 | case CommunicatorClient.Types.Bool: 72 | return value == "True"; 73 | case CommunicatorClient.Types.Byte: 74 | return (byte) valueDouble; 75 | case CommunicatorClient.Types.Short: 76 | return (short) valueDouble; 77 | case CommunicatorClient.Types.Int: 78 | return (int) valueDouble; 79 | case CommunicatorClient.Types.Long: 80 | return (long) valueDouble; 81 | case CommunicatorClient.Types.Float: 82 | return (float) valueDouble; 83 | case CommunicatorClient.Types.Double: 84 | return (double) valueDouble; 85 | case CommunicatorClient.Types.String: 86 | return value; 87 | case CommunicatorClient.Types.GameObject: 88 | return null; 89 | } 90 | 91 | return null; 92 | } 93 | public void UpdateValue () 94 | { 95 | CommunicatorClient.Instance.SetValueOfMember (Owner.Owner, GetPath (), _value); 96 | } 97 | public object GetValue () 98 | { 99 | return CommunicatorClient.Instance.GetValueOfMember (Owner.Owner, GetPath (), _value); 100 | } 101 | public string GetPath() 102 | { 103 | return (Parent == null) ? Owner.Index + ":" + Name : Parent.GetPath() + "." + Name; 104 | } 105 | 106 | public override bool Equals (object obj) 107 | { 108 | if (obj != null && obj is ObjectMember) 109 | return (Owner.Equals (((ObjectMember) obj).Owner) && Name == ((ObjectMember) obj).Name); 110 | return false; 111 | } 112 | public override int GetHashCode () 113 | { 114 | return Owner.GetHashCode () + Name.GetHashCode(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /UnityInspector.Injector/CommunicatorServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using UnityEngine; 7 | using UnityInspector.Communicator; 8 | 9 | namespace UnityInspectorInjector 10 | { 11 | class CommunicatorServer : Communicator 12 | { 13 | public new static CommunicatorServer Instance { get; set; } 14 | private Dictionary refDict = new Dictionary (); 15 | 16 | public CommunicatorServer() : base (CommunicatorType.Server) 17 | { 18 | Instance = this; 19 | } 20 | public override void Close() 21 | { 22 | Instance = null; 23 | server.Stop(); 24 | client.Close(); 25 | } 26 | 27 | public override GameObject ReadGameObject () 28 | { 29 | throw new NotImplementedException (); 30 | } 31 | public override GameObject ReadGameObjectByRef () 32 | { 33 | int gameObjectRef = ReadInt (); 34 | return refDict[gameObjectRef]; 35 | } 36 | 37 | public override void WriteGameObject (GameObject obj) 38 | { 39 | // The instance id of an object is always guaranteed to be unique. 40 | int gameObjectRef = obj.GetInstanceID (); 41 | if (!refDict.ContainsKey(gameObjectRef)) 42 | refDict.Add (gameObjectRef, obj); 43 | 44 | WriteInt (gameObjectRef); 45 | WriteString (obj.name); 46 | WriteBool (obj.activeSelf); 47 | } 48 | public void WriteGameObject (Transform obj) 49 | { 50 | WriteGameObject (obj.gameObject); 51 | } 52 | public override void WriteGameObjectRef (GameObject obj) 53 | { 54 | WriteInt (obj.GetInstanceID ()); 55 | } 56 | 57 | public override void WriteVector3 (object value) 58 | { 59 | Vector3 vector3 = (Vector3) value; 60 | WriteFloat (vector3.x); 61 | WriteFloat (vector3.y); 62 | WriteFloat (vector3.z); 63 | } 64 | public override object ReadVector3 () 65 | { 66 | return new Vector3 (ReadFloat (), ReadFloat (), ReadFloat ()); 67 | } 68 | 69 | public override void WriteVector2 (object value) 70 | { 71 | Vector2 vector2 = (Vector2) value; 72 | WriteFloat (vector2.x); 73 | WriteFloat (vector2.y); 74 | } 75 | public override object ReadVector2 () 76 | { 77 | return new Vector2 (ReadFloat (), ReadFloat ()); 78 | } 79 | 80 | public override void WriteRect (object value) 81 | { 82 | Rect rect = (Rect) value; 83 | WriteFloat (rect.x); 84 | WriteFloat (rect.y); 85 | WriteFloat (rect.width); 86 | WriteFloat (rect.height); 87 | } 88 | public override object ReadRect () 89 | { 90 | return new Rect (ReadFloat (), ReadFloat (), ReadFloat (), ReadFloat ()); 91 | } 92 | 93 | public override void WriteEnum (object value) 94 | { 95 | Array enumType = Enum.GetValues (value.GetType ()); 96 | WriteByte ((byte) enumType.Length); 97 | for (int i = 0; i < enumType.Length; i++) 98 | WriteString (enumType.GetValue (i).ToString ()); 99 | WriteString (value.ToString ()); 100 | } 101 | public override object ReadEnum () 102 | { 103 | return new EnumWrapper(ReadString ()); 104 | } 105 | 106 | public override void WriteColor (object value) 107 | { 108 | Color color = (Color) value; 109 | WriteByte ((byte) (color.r * 255)); 110 | WriteByte ((byte) (color.g * 255)); 111 | WriteByte ((byte) (color.b * 255)); 112 | WriteByte ((byte) (color.a * 255)); 113 | } 114 | public override object ReadColor () 115 | { 116 | return new Color (ReadByte() / 255f, ReadByte () / 255f, ReadByte () / 255f, ReadByte () / 255f); 117 | } 118 | 119 | public override object ReadArrayAsMember () 120 | { 121 | throw new NotImplementedException (); 122 | } 123 | } 124 | public class EnumWrapper 125 | { 126 | readonly string stringValue; 127 | public EnumWrapper (string value) 128 | { 129 | this.stringValue = value; 130 | } 131 | public object GetEnumValue (MemberInfo member) 132 | { 133 | Type enumType; 134 | if (member.MemberType == MemberTypes.Field) 135 | enumType = ((FieldInfo) member).FieldType; 136 | else 137 | enumType = ((PropertyInfo) member).PropertyType; 138 | return Enum.Parse (enumType, stringValue); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /SharpMonoInjector/Native.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | namespace SharpMonoInjector 6 | { 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct MODULEINFO 9 | { 10 | public IntPtr lpBaseOfDll; 11 | 12 | public int SizeOfImage; 13 | 14 | public IntPtr EntryPoint; 15 | } 16 | 17 | public enum ModuleFilter : uint 18 | { 19 | LIST_MODULES_DEFAULT = 0x0, 20 | LIST_MODULES_32BIT = 0x01, 21 | LIST_MODULES_64BIT = 0x02, 22 | LIST_MODULES_ALL = 0x03 23 | } 24 | 25 | [Flags] 26 | public enum AllocationType 27 | { 28 | MEM_COMMIT = 0x00001000, 29 | MEM_RESERVE = 0x00002000, 30 | MEM_RESET = 0x00080000, 31 | MEM_RESET_UNDO = 0x1000000, 32 | MEM_LARGE_PAGES = 0x20000000, 33 | MEM_PHYSICAL = 0x00400000, 34 | MEM_TOP_DOWN = 0x00100000 35 | } 36 | 37 | [Flags] 38 | public enum MemoryProtection 39 | { 40 | PAGE_EXECUTE = 0x10, 41 | PAGE_EXECUTE_READ = 0x20, 42 | PAGE_EXECUTE_READWRITE = 0x40, 43 | PAGE_EXECUTE_WRITECOPY = 0x80, 44 | PAGE_NOACCESS = 0x01, 45 | PAGE_READONLY = 0x02, 46 | PAGE_READWRITE = 0x4, 47 | PAGE_WRITECOPY = 0x8, 48 | PAGE_TARGETS_INVALID = 0x40000000, 49 | PAGE_TARGETS_NO_UPDATE = 0x40000000, 50 | PAGE_GUARD = 0x100, 51 | PAGE_NOCACHE = 0x200, 52 | PAGE_WRITECOMBINE = 0x400 53 | } 54 | 55 | [Flags] 56 | public enum MemoryFreeType 57 | { 58 | MEM_DECOMMIT = 0x4000, 59 | MEM_RELEASE = 0x8000 60 | } 61 | 62 | [Flags] 63 | public enum ThreadCreationFlags 64 | { 65 | None = 0, 66 | CREATE_SUSPENDED = 0x00000004, 67 | STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 68 | } 69 | 70 | public enum WaitResult : uint 71 | { 72 | WAIT_ABANDONED = 0x00000080, 73 | WAIT_OBJECT_0 = 0x00000000, 74 | WAIT_TIMEOUT = 0x00000102, 75 | WAIT_FAILED = 0xFFFFFFFF 76 | } 77 | 78 | [Flags] 79 | public enum ProcessAccessRights : uint 80 | { 81 | PROCESS_ALL_ACCESS = 0x1FFFFF, 82 | PROCESS_CREATE_PROCESS = 0x0080, 83 | PROCESS_CREATE_THREAD = 0x0002, 84 | PROCESS_DUP_HANDLE = 0x0040, 85 | PROCESS_QUERY_INFORMATION = 0x0400, 86 | PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, 87 | PROCESS_SET_INFORMATION = 0x0200, 88 | PROCESS_SET_QUOTA = 0x0100, 89 | PROCESS_SUSPEND_RESUME = 0x0800, 90 | PROCESS_TERMINATE = 0x0001, 91 | PROCESS_VM_OPERATION = 0x0008, 92 | PROCESS_VM_READ = 0x0010, 93 | PROCESS_VM_WRITE = 0x0020, 94 | SYNCHRONIZE = 0x00100000 95 | } 96 | 97 | public static class Native 98 | { 99 | [DllImport("kernel32.dll", SetLastError = true)] 100 | public static extern IntPtr OpenProcess(ProcessAccessRights dwDesiredAccess, bool bInheritHandle, int processId); 101 | 102 | [DllImport("kernel32.dll", SetLastError = true)] 103 | public static extern bool CloseHandle(IntPtr handle); 104 | 105 | [DllImport("kernel32.dll")] 106 | [return: MarshalAs(UnmanagedType.Bool)] 107 | public static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process); 108 | 109 | [DllImport("psapi.dll", SetLastError = true)] 110 | public static extern bool EnumProcessModulesEx(IntPtr hProcess, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] [In][Out] IntPtr[] lphModule, int cb, [MarshalAs(UnmanagedType.U4)] out int lpcbNeeded, ModuleFilter dwFilterFlag); 111 | 112 | [DllImport("psapi.dll")] 113 | public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] uint nSize); 114 | 115 | [DllImport("psapi.dll", SetLastError = true)] 116 | public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, uint cb); 117 | 118 | [DllImport("kernel32.dll", SetLastError = true)] 119 | [return: MarshalAs(UnmanagedType.Bool)] 120 | public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, int lpNumberOfBytesWritten = 0); 121 | 122 | [DllImport("kernel32.dll", SetLastError = true)] 123 | [return: MarshalAs(UnmanagedType.Bool)] 124 | public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, int lpNumberOfBytesRead = 0); 125 | 126 | [DllImport("kernel32.dll", SetLastError = true)] 127 | public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType flAllocationType, MemoryProtection flProtect); 128 | 129 | [DllImport("kernel32.dll", SetLastError = true)] 130 | [return: MarshalAs(UnmanagedType.Bool)] 131 | public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, MemoryFreeType dwFreeType); 132 | 133 | [DllImport("kernel32.dll", SetLastError = true)] 134 | public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, int dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, ThreadCreationFlags dwCreationFlags, out int lpThreadId); 135 | 136 | [DllImport("kernel32.dll", SetLastError = true)] 137 | public static extern WaitResult WaitForSingleObject(IntPtr hHandle, int dwMilliseconds); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | ExternalDlls/ 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | #*.pubxml 148 | *.publishproj 149 | 150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 151 | # checkin your Azure Web App publish settings, but sensitive information contained 152 | # in these scripts will be unencrypted 153 | PublishScripts/ 154 | 155 | # NuGet Packages 156 | *.nupkg 157 | # The packages folder can be ignored because of Package Restore 158 | **/packages/* 159 | # except build/, which is used as an MSBuild target. 160 | !**/packages/build/ 161 | # Uncomment if necessary however generally it will be regenerated when needed 162 | #!**/packages/repositories.config 163 | # NuGet v3's project.json files produces more ignoreable files 164 | *.nuget.props 165 | *.nuget.targets 166 | 167 | # Microsoft Azure Build Output 168 | csx/ 169 | *.build.csdef 170 | 171 | # Microsoft Azure Emulator 172 | ecf/ 173 | rcf/ 174 | 175 | # Windows Store app package directories and files 176 | AppPackages/ 177 | BundleArtifacts/ 178 | Package.StoreAssociation.xml 179 | _pkginfo.txt 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | ~$* 190 | *~ 191 | *.dbmdl 192 | *.dbproj.schemaview 193 | *.jfm 194 | *.pfx 195 | *.publishsettings 196 | node_modules/ 197 | orleans.codegen.cs 198 | 199 | # Since there are multiple workflows, uncomment next line to ignore bower_components 200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 201 | #bower_components/ 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | paket-files/ 249 | 250 | # FAKE - F# Make 251 | .fake/ 252 | 253 | # JetBrains Rider 254 | .idea/ 255 | *.sln.iml 256 | 257 | # CodeRush 258 | .cr/ 259 | 260 | # Python Tools for Visual Studio (PTVS) 261 | __pycache__/ 262 | *.pyc -------------------------------------------------------------------------------- /UnityInspector.GUI/Properties/Resources.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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /UnityInspector.GUI/Models/CommunicatorClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Media; 7 | using UnityInspector.Communicator; 8 | 9 | namespace UnityInspector.GUI.Models 10 | { 11 | class CommunicatorClient : Communicator 12 | { 13 | public new static CommunicatorClient Instance { get; set; } 14 | public CommunicatorClient() : base (CommunicatorType.Clinet) 15 | { 16 | Instance = this; 17 | } 18 | public override void Close() 19 | { 20 | WriteByte((byte)Commands.Destroy); 21 | Flush (); 22 | client.Close(); 23 | Instance = null; 24 | } 25 | 26 | public GameObject[] ReadHierarchy () 27 | { 28 | WriteByte ((byte) Commands.GetHierarchy); 29 | int len = ReadInt (); 30 | GameObject[] gameObjects = new GameObject[len]; 31 | for (int i = 0; i < len; i++) 32 | { 33 | gameObjects[i] = ReadGameObject (); 34 | } 35 | return gameObjects; 36 | } 37 | public GameObject[] GetChildren (GameObject gameObject) 38 | { 39 | WriteByte ((byte) Commands.GetChildren); 40 | WriteGameObjectRef (gameObject); 41 | int len = ReadInt (); 42 | GameObject[] gameObjects = new GameObject[len]; 43 | for (int i = 0; i < len; i++) 44 | { 45 | gameObjects[i] = ReadGameObject (); 46 | } 47 | return gameObjects; 48 | } 49 | public void InvokeMethod (GameObject gameObject, string method, object[] args) 50 | { 51 | WriteByte ((byte) Commands.InvokeMethod); 52 | WriteGameObjectRef (gameObject); 53 | WriteString (method); 54 | WriteObjects (args); 55 | } 56 | public Component[] GetComponents (GameObject gameObject) 57 | { 58 | WriteByte ((byte) Commands.GetComponents); 59 | WriteGameObjectRef (gameObject); 60 | int len = ReadInt (); 61 | Component[] components = new Component[len]; 62 | for (int i = 0; i < len; i++) 63 | { 64 | components[i] = new Component (gameObject, i, ReadString (), ReadByte ()); 65 | } 66 | return components; 67 | } 68 | public ObjectMember[] GetComponentMembers (Component component) 69 | { 70 | WriteByte ((byte) Commands.GetComponentMembers); 71 | WriteGameObjectRef (component.Owner); 72 | WriteInt (component.Index); 73 | int len = ReadInt (); 74 | ObjectMember[] members = new ObjectMember[len]; 75 | for (int i = 0; i < len; i++) 76 | { 77 | Types type = (Types)ReadByte(); 78 | string name = ReadString(); 79 | members[i] = new ObjectMember (component, 80 | type, 81 | name, 82 | ReadObject ()); 83 | } 84 | return members; 85 | } 86 | public object GetValueOfMember (GameObject gameObject, string member, object value) 87 | { 88 | WriteByte ((byte) Commands.GetValueOfMember); 89 | WriteGameObjectRef (gameObject); 90 | WriteString (member); 91 | return ReadObject (); 92 | } 93 | public void SetValueOfMember (GameObject gameObject, string member, object value) 94 | { 95 | WriteByte ((byte) Commands.SetValueOfMember); 96 | WriteGameObjectRef (gameObject); 97 | WriteString (member); 98 | WriteObject (value); 99 | } 100 | 101 | public override object ReadArrayAsMember () 102 | { 103 | ArrayMember ret = new ArrayMember (ReadInt (), (Types) ReadByte ()); 104 | return ret; 105 | } 106 | 107 | public override void WriteGameObject (GameObject obj) 108 | { 109 | throw new NotImplementedException (); 110 | } 111 | public override GameObject ReadGameObject () 112 | { 113 | return new GameObject (ReadInt (), ReadString (), ReadBool ()); 114 | } 115 | public override void WriteGameObjectRef (GameObject obj) 116 | { 117 | WriteInt (obj.Address); 118 | } 119 | public override GameObject ReadGameObjectByRef () 120 | { 121 | return ReadGameObject (); 122 | } 123 | 124 | public override void WriteVector3 (object value) 125 | { 126 | Vector3 vector3 = (Vector3) value; 127 | WriteFloat (vector3.X); 128 | WriteFloat (vector3.Y); 129 | WriteFloat (vector3.Z); 130 | } 131 | public override object ReadVector3 () 132 | { 133 | return new Vector3 (ReadFloat (), ReadFloat (), ReadFloat ()); 134 | } 135 | 136 | public override void WriteVector2 (object value) 137 | { 138 | Vector2 vector2 = (Vector2) value; 139 | WriteFloat (vector2.X); 140 | WriteFloat (vector2.Y); 141 | } 142 | public override object ReadVector2 () 143 | { 144 | return new Vector2 (ReadFloat (), ReadFloat ()); 145 | } 146 | 147 | public override void WriteRect(object value) 148 | { 149 | Rect rect = (Rect) value; 150 | WriteFloat (rect.X); 151 | WriteFloat (rect.Y); 152 | WriteFloat (rect.W); 153 | WriteFloat (rect.H); 154 | } 155 | public override object ReadRect () 156 | { 157 | return new Rect (ReadFloat (), ReadFloat (), ReadFloat (), ReadFloat ()); 158 | } 159 | 160 | public override void WriteEnum (object value) 161 | { 162 | WriteString (((EnumMember) value).Value); 163 | } 164 | public override object ReadEnum () 165 | { 166 | byte len = ReadByte (); 167 | string[] values = new string[len]; 168 | for (int i = 0; i < len; i++) 169 | { 170 | values[i] = ReadString (); 171 | } 172 | return new EnumMember (values, ReadString ()); 173 | } 174 | 175 | public override void WriteColor (object value) 176 | { 177 | Color color = ((Color) value); 178 | WriteByte (color.R); 179 | WriteByte (color.G); 180 | WriteByte (color.B); 181 | WriteByte (color.A); 182 | } 183 | public override object ReadColor () 184 | { 185 | Color color = new Color (); 186 | color.R = ReadByte (); 187 | color.G = ReadByte (); 188 | color.B = ReadByte (); 189 | color.A = ReadByte (); 190 | return color; 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /UnityInspector.GUI/ViewModels/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using SharpMonoInjector; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.ComponentModel; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Runtime.CompilerServices; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Windows; 13 | using System.Windows.Input; 14 | using System.Windows.Threading; 15 | using UnityInspector.GUI.Models; 16 | 17 | namespace UnityInspector.GUI.ViewModels 18 | { 19 | class MainWindowViewModel : ViewModel 20 | { 21 | private MonoProcess _selectedProcess; 22 | CommunicatorClient communicator; 23 | 24 | public ICollection Processes { get; set; } 25 | public ICommand RefreshCommand { get; set; } 26 | public ICommand InjectCommand { get; set; } 27 | public ICommand DisconnectCommand { get; set; } 28 | public ICommand RefreshTreeCommand { get; set; } 29 | private int _refreshRate; 30 | public int RefreshRate { 31 | get { 32 | return _refreshRate; 33 | } 34 | set { 35 | _refreshRate = value; 36 | if (refreshTimer == null && _refreshRate != 0) 37 | { 38 | refreshTimer = new DispatcherTimer (new TimeSpan (10000000 / _refreshRate), DispatcherPriority.Background, delegate 39 | { 40 | RefreshTree (null); 41 | }, Application.Current.MainWindow.Dispatcher); 42 | } 43 | else if (_refreshRate != 0) 44 | { 45 | refreshTimer.Interval = new TimeSpan (10000000 / _refreshRate); 46 | if (!refreshTimer.IsEnabled) refreshTimer.Start (); 47 | } 48 | else if (refreshTimer != null && _refreshRate == 0) 49 | { 50 | refreshTimer.Stop (); 51 | } 52 | } 53 | } 54 | private DispatcherTimer refreshTimer; 55 | public GameObjectViewModel MainSceneGameObject { get; set; } 56 | 57 | private string _status; 58 | public string Status { get { return _status; } set 59 | { 60 | _status = value; 61 | RaisePropertyChanged("Status"); 62 | } 63 | } 64 | public bool IsConnected { get { return CommunicatorClient.Instance != null && CommunicatorClient.Instance.Connected; } } 65 | public MonoProcess SelectedProcess 66 | { 67 | get { return _selectedProcess; } 68 | set 69 | { 70 | _selectedProcess = value; 71 | RaisePropertyChanged ("SelectedProcess"); 72 | } 73 | } 74 | 75 | public MainWindowViewModel () { 76 | RefreshCommand = new RelayCommand (GetProcesses); 77 | InjectCommand = new RelayCommand (Inject); 78 | DisconnectCommand = new RelayCommand (Disconnect); 79 | RefreshTreeCommand = new RelayCommand (RefreshTree); 80 | MainSceneGameObject = new GameObjectViewModel (new GameObject (0, "MainScene", true)); 81 | MainSceneGameObject.IsExpanded = true; 82 | Status = "Idle"; 83 | } 84 | private void RefreshTree (object parameter) 85 | { 86 | MainSceneGameObject.Update (null, true); 87 | } 88 | private async void Inject (object parameter) 89 | { 90 | Status = "Injecting"; 91 | await Task.Run (() => 92 | { 93 | Status = "Getting access"; 94 | IntPtr handle = Native.OpenProcess (ProcessAccessRights.PROCESS_ALL_ACCESS, false, SelectedProcess.Id); 95 | string AssemblyPath = @"UnityInspector.Injector.dll"; 96 | if (handle == IntPtr.Zero) 97 | { 98 | Status = "Access denied"; 99 | return; 100 | } 101 | 102 | byte[] file; 103 | 104 | try 105 | { 106 | Status = "Reading UnityInspector.Injector.dll"; 107 | file = File.ReadAllBytes (AssemblyPath); 108 | } 109 | catch (IOException) 110 | { 111 | Status = "Can't read UnityInspector.Injector.dll"; 112 | return; 113 | } 114 | 115 | using (Injector injector = new Injector (handle, SelectedProcess.MonoModule)) 116 | { 117 | try 118 | { 119 | Status = "Injecting"; 120 | IntPtr asm = injector.Inject (file, "UnityInspectorInjector", "Injector", "OnLoad"); 121 | } 122 | catch (InjectorException ie) 123 | { 124 | Status = ie.Message; 125 | return; 126 | } 127 | catch (Exception e) 128 | { 129 | Status = e.Message; 130 | return; 131 | } 132 | } 133 | StartCommunicator (); 134 | }); 135 | } 136 | 137 | private void StartCommunicator () 138 | { 139 | Status = "Starting Communicator"; 140 | communicator = new CommunicatorClient(); 141 | Status = "Connected"; 142 | RaisePropertyChanged ("IsConnected"); 143 | MainSceneGameObject.Update (); 144 | } 145 | private void Disconnect (object parameter) 146 | { 147 | RefreshRate = 0; 148 | if (communicator != null) 149 | communicator.Close (); 150 | RaisePropertyChanged("IsConnected"); 151 | RefreshTree (null); 152 | Status = "Idel"; 153 | } 154 | private async void GetProcesses (object parameter) 155 | { 156 | Collection processes = new Collection (); 157 | string prevStatus = Status; 158 | await Task.Run (() => 159 | { 160 | Status = "Getting Processes"; 161 | int cp = Process.GetCurrentProcess ().Id; 162 | foreach (Process p in Process.GetProcesses ()) 163 | { 164 | if (p.Id == cp || p.MainWindowHandle == IntPtr.Zero) 165 | continue; 166 | const ProcessAccessRights flags = ProcessAccessRights.PROCESS_QUERY_INFORMATION | ProcessAccessRights.PROCESS_VM_READ; 167 | IntPtr handle; 168 | 169 | if ((handle = Native.OpenProcess (flags, false, p.Id)) != IntPtr.Zero) 170 | { 171 | if (ProcessUtils.GetMonoModule (handle, out IntPtr mono)) 172 | { 173 | processes.Add (new MonoProcess 174 | { 175 | MonoModule = mono, 176 | Id = p.Id, 177 | Name = p.ProcessName 178 | }); 179 | } 180 | 181 | Native.CloseHandle (handle); 182 | } 183 | } 184 | }); 185 | Processes = processes; 186 | RaisePropertyChanged ("Processes"); 187 | Status = prevStatus; 188 | if (Processes.Count > 0) 189 | { 190 | SelectedProcess = Processes.First(); 191 | } 192 | 193 | } 194 | 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /UnityInspector.GUI/UnityInspector.GUI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {71B1ADBF-8B1E-4E92-B81E-0F3E512BE93D} 8 | WinExe 9 | UnityInspector.GUI 10 | UnityInspector 11 | v4.6.1 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | false 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | true 32 | 33 | 34 | AnyCPU 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | AnyCPU 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | false 53 | true 54 | 55 | 56 | icon.ico 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 4.0 69 | 70 | 71 | 72 | 73 | 74 | ..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.Toolkit.dll 75 | 76 | 77 | 78 | 79 | MSBuild:Compile 80 | Designer 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | MSBuild:Compile 105 | Designer 106 | 107 | 108 | App.xaml 109 | Code 110 | 111 | 112 | MainWindow.xaml 113 | Code 114 | 115 | 116 | Designer 117 | MSBuild:Compile 118 | 119 | 120 | 121 | 122 | 123 | 124 | Code 125 | 126 | 127 | True 128 | True 129 | Resources.resx 130 | 131 | 132 | True 133 | Settings.settings 134 | True 135 | 136 | 137 | ResXFileCodeGenerator 138 | Resources.Designer.cs 139 | 140 | 141 | 142 | SettingsSingleFileGenerator 143 | Settings.Designer.cs 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | {500155a7-3c29-4944-9031-6994b56e1797} 152 | SharpMonoInjector 153 | 154 | 155 | {af3b27c3-615e-46dd-80b0-76c6e106c64d} 156 | UnityInspector.Communicator 157 | 158 | 159 | 160 | 161 | False 162 | Microsoft .NET Framework 4.6.1 %28x86 and x64%29 163 | true 164 | 165 | 166 | False 167 | .NET Framework 3.5 SP1 168 | false 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /UnityInspector.Injector/Injector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.SceneManagement; 4 | using System.Reflection; 5 | using System.Collections; 6 | using Commands = UnityInspectorInjector.CommunicatorServer.Commands; 7 | namespace UnityInspectorInjector 8 | { 9 | public class Injector 10 | { 11 | public static GameObject test; 12 | public static void OnLoad () 13 | { 14 | if (test != null) 15 | MonoBehaviour.Destroy(test); 16 | if (CommunicatorServer.Instance != null) 17 | CommunicatorServer.Instance.Close(); 18 | test = new GameObject (); 19 | MonoBehaviour.DontDestroyOnLoad (test); 20 | 21 | test.AddComponent (); 22 | Application.runInBackground = true; 23 | } 24 | } 25 | public class InjectorComp : MonoBehaviour 26 | { 27 | CommunicatorServer communicator; 28 | void Start () 29 | { 30 | communicator = new CommunicatorServer(); 31 | StartCoroutine (Poll ()); 32 | } 33 | IEnumerator Poll () 34 | { 35 | while (true) 36 | { 37 | yield return null; 38 | int commandsExeced = 0; 39 | while (communicator.DataAvailable () && commandsExeced < 10) 40 | { 41 | commandsExeced++; 42 | Commands command = (Commands) communicator.ReadByte (); 43 | ExecuteCommand (command); 44 | } 45 | 46 | } 47 | } 48 | 49 | void ExecuteCommand (Commands command) 50 | { 51 | if (command == Commands.Destroy) 52 | { 53 | communicator.Close(); 54 | Destroy(gameObject); 55 | } 56 | else if (command == Commands.GetHierarchy) 57 | { 58 | // I don't use WriteArray in this method for speed prpouses 59 | GameObject[] gameObjects = SceneManager.GetActiveScene ().GetRootGameObjects (); 60 | communicator.WriteInt (gameObjects.Length); 61 | for (int i = 0; i < gameObjects.Length; i++) 62 | communicator.WriteGameObject (gameObjects[i]); 63 | } 64 | else if (command == Commands.GetChildren) 65 | { 66 | GameObject obj = communicator.ReadGameObjectByRef (); 67 | communicator.WriteInt (obj.transform.childCount); 68 | for (int i = 0; i < obj.transform.childCount; i++) 69 | communicator.WriteGameObject (obj.transform.GetChild (i)); 70 | } 71 | else if (command == Commands.InvokeMethod) 72 | { 73 | object obj = ReadNestedRef (out string methodName); 74 | 75 | MethodInfo methodInfo = obj.GetType ().GetMethod (methodName); 76 | methodInfo.Invoke (obj, communicator.ReadObjects ()); 77 | } 78 | else if (command == Commands.GetComponents) 79 | { 80 | GameObject obj = communicator.ReadGameObjectByRef (); 81 | Component[] comps = obj.GetComponents (); 82 | communicator.WriteInt (comps.Length); 83 | for (int i = 0; i < comps.Length; i++) 84 | { 85 | Type compType = comps[i].GetType (); 86 | communicator.WriteString (compType.Name); 87 | PropertyInfo enabledField = compType.GetProperty ("enabled"); 88 | if (enabledField != null) 89 | communicator.WriteByte ((Byte) ((bool) enabledField.GetValue (comps[i], null) ? 1 : 2)); 90 | else 91 | communicator.WriteByte (0); 92 | } 93 | } 94 | else if (command == Commands.GetComponentMembers) 95 | { 96 | GameObject obj = communicator.ReadGameObjectByRef (); 97 | int compIndex = communicator.ReadInt (); 98 | Component comp = obj.GetComponents ()[compIndex]; 99 | Type compType = comp.GetType (); 100 | MemberInfo[] members = GetFilteredMembers (compType); 101 | communicator.WriteInt (members.Length); 102 | for (int i = 0; i < members.Length; i++) 103 | { 104 | MemberInfo member = members[i]; 105 | 106 | object value; 107 | if (member.MemberType == MemberTypes.Field) 108 | value = ((FieldInfo) member).GetValue (comp); 109 | else 110 | value = ((PropertyInfo) member).GetValue (comp, null); 111 | 112 | if (value is Component) 113 | value = ((Component) value).gameObject; 114 | 115 | communicator.WriteByte ((byte) CommunicatorServer.GetObjectType (value)); 116 | communicator.WriteString (member.Name); 117 | communicator.WriteObject (value, true); 118 | 119 | } 120 | } 121 | else if (command == Commands.GetValueOfMember) 122 | { 123 | object obj = ReadNestedRef (out string memberName); 124 | 125 | MemberInfo member = obj.GetType ().GetMember (memberName)[0]; 126 | object value; 127 | if (memberName[0] != '[') 128 | { 129 | if (member.MemberType == MemberTypes.Field) 130 | value = ((FieldInfo)member).GetValue(obj); 131 | else 132 | value = ((PropertyInfo)member).GetValue(obj, null); 133 | } 134 | else 135 | { 136 | int index = int.Parse(memberName.Substring(1, memberName.Length - 2)); 137 | value = ((Array)obj).GetValue(index); 138 | } 139 | if (value is Component) 140 | value = ((Component)value).gameObject; 141 | CommunicatorServer.Instance.WriteObject (value); 142 | } 143 | else if (command == Commands.SetValueOfMember) 144 | { 145 | object obj = ReadNestedRef (out string memberName); 146 | object value = communicator.ReadObject(); 147 | //TODO: If value is gameobject but membertype is component we need to get the component of that gameobject 148 | 149 | if (memberName[0] != '[') 150 | { 151 | MemberInfo member = obj.GetType().GetMember(memberName)[0]; 152 | 153 | if (value is EnumWrapper) 154 | value = ((EnumWrapper)value).GetEnumValue(member); 155 | 156 | if (value != null) 157 | { 158 | if (member.MemberType == MemberTypes.Field) 159 | ((FieldInfo)member).SetValue(obj, value); 160 | else 161 | ((PropertyInfo)member).SetValue(obj, value, null); 162 | } 163 | } 164 | else 165 | { 166 | int index = int.Parse(memberName.Substring(1, memberName.Length - 2)); 167 | ((Array)obj).SetValue (value, index); 168 | } 169 | 170 | } 171 | } 172 | 173 | object ReadNestedRef (out string memberName) 174 | { 175 | object obj = communicator.ReadGameObjectByRef (); 176 | memberName = communicator.ReadString (); 177 | int colonLocation = memberName.IndexOf (':'); 178 | if (colonLocation != -1) 179 | { 180 | int compIndex = int.Parse (memberName.Substring (0, colonLocation)); 181 | obj = ((GameObject) obj).GetComponents ()[compIndex]; 182 | memberName = memberName.Substring (colonLocation + 1); 183 | } 184 | string[] path = memberName.Split('.'); 185 | for (int i=0; i < path.Length - 1; i++) 186 | { 187 | string point = path[i]; 188 | if (point[0] != '[') 189 | { 190 | MemberInfo member = obj.GetType().GetMember(path[i])[0]; 191 | if (member.MemberType == MemberTypes.Field) 192 | obj = ((FieldInfo)member).GetValue (obj); 193 | else 194 | obj = ((PropertyInfo)member).GetValue(obj, null); 195 | } else 196 | { 197 | //TODO 198 | } 199 | } 200 | memberName = path[path.Length - 1]; 201 | return obj; 202 | } 203 | public MemberInfo[] GetFilteredMembers (Type type) 204 | { 205 | return Array.FindAll (type.GetMembers (), m => 206 | { 207 | if (m.DeclaringType != type) 208 | return false; 209 | if (m.MemberType == MemberTypes.Property && !((PropertyInfo) m).CanWrite) 210 | return false; 211 | if (m.MemberType != MemberTypes.Field && m.MemberType != MemberTypes.Property) 212 | return false; 213 | return true; 214 | }); 215 | } 216 | 217 | private void OnDestroy() 218 | { 219 | communicator.Close(); 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /UnityInspector.GUI/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 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 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |