├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ ├── config.yml │ ├── enhancement.yaml │ └── other.yaml └── workflows │ └── dotnet.yml ├── .gitignore ├── CHANGELOG.md ├── ECSExtension ├── BufferView.cs ├── CacheComponent.cs ├── ECSExtension.csproj ├── Extension.cs ├── ExtensionPlugin.cs ├── Inspectors │ ├── ButtonNativeListHandler.cs │ ├── ECSComponentCell.cs │ ├── ECSComponentList.cs │ └── EntityInspector.cs ├── Panels │ ├── EntityCell.cs │ ├── EntityTree.cs │ ├── QueryComponentCell.cs │ ├── QueryComponentList.cs │ └── WorldExplorer.cs ├── Patch │ └── GameObjectConversionMappingSystem_Patch.cs └── Widgets │ └── EntityInfoPanel.cs ├── LICENSE ├── README.md ├── THIRDPARTY_LICENSES.md ├── UnityEditorPackage ├── LICENSE.md ├── README.md ├── Runtime │ ├── 0Harmony.dll │ ├── Mono.Cecil.Mdb.dll │ ├── Mono.Cecil.Pdb.dll │ ├── Mono.Cecil.Rocks.dll │ ├── Mono.Cecil.dll │ ├── MonoMod.RuntimeDetour.dll │ ├── MonoMod.Utils.dll │ ├── Tomlet.dll │ ├── UnityExplorer.STANDALONE.Mono.dll │ ├── UnityExplorer.prefab │ ├── UniverseLib.Mono.dll │ └── mcs.dll ├── Third Party Notices.md └── package.json ├── build.ps1 ├── buildBIE5.ps1 ├── buildBIE6.ps1 ├── buildCLR.ps1 ├── img ├── icon.png └── preview.png ├── lib ├── ILRepack.exe ├── interop │ ├── CoreLib.dll │ ├── ECS │ │ ├── Unity.Burst.Unsafe.dll │ │ ├── Unity.Burst.dll │ │ ├── Unity.Collections.LowLevel.ILSupport.dll │ │ ├── Unity.Collections.dll │ │ ├── Unity.Entities.Hybrid.HybridComponents.dll │ │ ├── Unity.Entities.Hybrid.dll │ │ ├── Unity.Entities.dll │ │ ├── Unity.Mathematics.Extensions.dll │ │ ├── Unity.Mathematics.dll │ │ ├── Unity.NetCode.Authoring.Hybrid.dll │ │ ├── Unity.NetCode.Physics.dll │ │ ├── Unity.NetCode.dll │ │ ├── Unity.Networking.Transport.dll │ │ ├── Unity.Physics.Hybrid.dll │ │ └── Unity.Physics.dll │ ├── Il2CppSystem.Core.dll │ ├── Il2Cppmscorlib.dll │ ├── UnityEngine.AssetBundleModule.dll │ ├── UnityEngine.AudioModule.dll │ ├── UnityEngine.CoreModule.dll │ ├── UnityEngine.IMGUIModule.dll │ ├── UnityEngine.PhysicsModule.dll │ ├── UnityEngine.TextRenderingModule.dll │ ├── UnityEngine.UI.dll │ ├── UnityEngine.UIModule.dll │ └── UnityEngine.dll ├── net35 │ ├── BepInEx.Core.dll │ ├── BepInEx.Unity.Common.dll │ ├── BepInEx.Unity.Mono.dll │ ├── BepInEx.Unity.dll │ ├── BepInEx.dll │ ├── ECS │ │ ├── Unity.Burst.Unsafe.dll │ │ ├── Unity.Burst.dll │ │ ├── Unity.Collections.LowLevel.ILSupport.dll │ │ ├── Unity.Collections.dll │ │ ├── Unity.Entities.Hybrid.HybridComponents.dll │ │ ├── Unity.Entities.Hybrid.dll │ │ ├── Unity.Entities.dll │ │ ├── Unity.Mathematics.Extensions.dll │ │ ├── Unity.Mathematics.dll │ │ ├── Unity.NetCode.Authoring.Hybrid.dll │ │ ├── Unity.NetCode.Physics.dll │ │ ├── Unity.NetCode.dll │ │ ├── Unity.Networking.Transport.dll │ │ ├── Unity.Physics.Hybrid.dll │ │ └── Unity.Physics.dll │ ├── MelonLoader.dll │ ├── UnityEngine.AssetBundleModule_publicized.dll │ ├── UnityEngine.AudioModule.dll │ ├── UnityEngine.CoreModule_publicized.dll │ ├── UnityEngine.IMGUIModule_publicized.dll │ ├── UnityEngine.PhysicsModule_publicized.dll │ ├── UnityEngine.TextRenderingModule_publicized.dll │ ├── UnityEngine.UI.dll │ ├── UnityEngine.UIModule.dll │ ├── UnityEngine.dll │ └── mcs.dll ├── net472 │ ├── BepInEx.Core.dll │ └── BepInEx.Unity.IL2CPP.dll ├── net6 │ ├── MelonLoader.dll │ ├── System.Runtime.dll │ ├── UniverseLib.IL2CPP.Interop.dll │ └── mcs.dll └── unhollowed │ ├── ECS │ ├── Unity.Burst.Unsafe.dll │ ├── Unity.Burst.dll │ ├── Unity.Collections.LowLevel.ILSupport.dll │ ├── Unity.Collections.dll │ ├── Unity.Entities.Hybrid.dll │ ├── Unity.Entities.dll │ ├── Unity.Jobs.dll │ ├── Unity.Mathematics.Extensions.dll │ ├── Unity.Mathematics.dll │ ├── Unity.NetCode.Authoring.Hybrid.dll │ ├── Unity.NetCode.Generated.dll │ ├── Unity.NetCode.Physics.dll │ ├── Unity.NetCode.dll │ ├── Unity.Networking.Transport.dll │ ├── Unity.Physics.Hybrid.dll │ └── Unity.Physics.dll │ ├── Il2CppSystem.Core.dll │ ├── Il2Cppmscorlib.dll │ ├── UnityEngine.AssetBundleModule.dll │ ├── UnityEngine.AudioModule.dll │ ├── UnityEngine.CoreModule.dll │ ├── UnityEngine.IMGUIModule.dll │ ├── UnityEngine.PhysicsModule.dll │ ├── UnityEngine.TextRenderingModule.dll │ ├── UnityEngine.UI.dll │ ├── UnityEngine.UIModule.dll │ └── UnityEngine.dll └── src ├── CSConsole ├── CSAutoCompleter.cs ├── ConsoleController.cs ├── LexerBuilder.cs ├── Lexers │ ├── CommentLexer.cs │ ├── KeywordLexer.cs │ ├── Lexer.cs │ ├── NumberLexer.cs │ ├── StringLexer.cs │ └── SymbolLexer.cs ├── ScriptEvaluator.cs └── ScriptInteraction.cs ├── CacheObject ├── CacheConfigEntry.cs ├── CacheConstructor.cs ├── CacheField.cs ├── CacheKeyValuePair.cs ├── CacheListEntry.cs ├── CacheMember.cs ├── CacheMemberFactory.cs ├── CacheMethod.cs ├── CacheObjectBase.cs ├── CacheProperty.cs ├── ICacheObjectController.cs ├── IValues │ ├── InteractiveColor.cs │ ├── InteractiveDictionary.cs │ ├── InteractiveEnum.cs │ ├── InteractiveList.cs │ ├── InteractiveString.cs │ ├── InteractiveValue.cs │ └── InteractiveValueStruct.cs └── Views │ ├── CacheConfigCell.cs │ ├── CacheKeyValuePairCell.cs │ ├── CacheListEntryCell.cs │ ├── CacheMemberCell.cs │ └── CacheObjectCell.cs ├── Config ├── ConfigElement.cs ├── ConfigHandler.cs ├── ConfigManager.cs ├── IConfigElement.cs └── InternalConfigHandler.cs ├── ExplorerBehaviour.cs ├── ExplorerCore.cs ├── Hooks ├── AddHookCell.cs ├── HookCell.cs ├── HookCreator.cs ├── HookInstance.cs └── HookList.cs ├── Inspectors ├── GameObjectInspector.cs ├── InspectorBase.cs ├── InspectorManager.cs ├── InspectorTab.cs ├── MouseInspector.cs ├── MouseInspectors │ ├── MouseInspectorBase.cs │ ├── UiInspector.cs │ └── WorldInspector.cs └── ReflectionInspector.cs ├── Loader ├── BepInEx │ ├── BepInExConfigHandler.cs │ └── ExplorerBepInPlugin.cs ├── IExplorerLoader.cs ├── MelonLoader │ ├── ExplorerMelonMod.cs │ └── MelonLoaderConfigHandler.cs └── Standalone │ ├── Editor │ ├── ExplorerEditorBehaviour.cs │ └── ExplorerEditorLoader.cs │ ├── ExplorerStandalone.cs │ └── StandaloneConfigHandler.cs ├── ObjectExplorer ├── ObjectSearch.cs ├── SceneExplorer.cs ├── SceneHandler.cs ├── SearchProvider.cs └── UITabPanel.cs ├── Properties └── AssemblyInfo.cs ├── Runtime ├── Il2CppHelper.cs ├── MonoHelper.cs ├── UERuntimeHelper.cs └── UnityCrashPrevention.cs ├── Tests └── TestClass.cs ├── UI ├── DisplayManager.cs ├── ExplorerUIBase.cs ├── Notification.cs ├── Panels │ ├── AutoCompleteModal.cs │ ├── CSConsolePanel.cs │ ├── ClipboardPanel.cs │ ├── FreeCamPanel.cs │ ├── HookManagerPanel.cs │ ├── InspectorPanel.cs │ ├── LogPanel.cs │ ├── MouseInspectorResultsPanel.cs │ ├── ObjectExplorerPanel.cs │ ├── OptionsPanel.cs │ ├── UEPanel.cs │ └── UEPanelDragger.cs ├── UEPanelManager.cs ├── UIManager.cs └── Widgets │ ├── AutoComplete │ ├── EnumCompleter.cs │ ├── ISuggestionProvider.cs │ ├── Suggestion.cs │ └── TypeCompleter.cs │ ├── EvaluateWidget │ ├── BaseArgumentHandler.cs │ ├── EvaluateWidget.cs │ ├── GenericArgumentHandler.cs │ ├── GenericConstructorWidget.cs │ └── ParameterHandler.cs │ ├── GameObjects │ ├── AxisControl.cs │ ├── ComponentCell.cs │ ├── ComponentList.cs │ ├── GameObjectControls.cs │ ├── GameObjectInfoPanel.cs │ ├── TransformControls.cs │ ├── TransformType.cs │ └── Vector3Control.cs │ ├── TimeScaleWidget.cs │ └── UnityObjects │ ├── AudioClipWidget.cs │ ├── MaterialWidget.cs │ ├── Texture2DWidget.cs │ └── UnityObjectWidget.cs ├── UnityExplorer.csproj ├── UnityExplorer.sln └── nuget.config /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: sinaidev 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug or crash report 3 | title: "[Bug]: " 4 | labels: [bug] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for submitting a bug report, please fill out as much detail as possible. 10 | - type: checkboxes 11 | id: latestversion 12 | attributes: 13 | label: Are you on the latest version of UnityExplorer? 14 | description: If not, you must update first. 15 | options: 16 | - label: Yes, I'm on the latest version of UnityExplorer. 17 | required: true 18 | - type: dropdown 19 | id: version 20 | attributes: 21 | label: Which release are you using? 22 | description: Please select your environment for UnityExplorer. 23 | options: 24 | - BepInEx IL2CPP 25 | - BepInEx 6.X Mono 26 | - BepInEx 5.X Mono 27 | - MelonLoader IL2CPP 28 | - MelonLoader Mono 29 | - Standalone IL2CPP 30 | - Standalone Mono 31 | validations: 32 | required: true 33 | - type: textarea 34 | id: game 35 | attributes: 36 | label: Which game did this occur on? 37 | description: Please tell us the name of the game. If it's a personal or private project, just let us know the Unity version. 38 | validations: 39 | required: true 40 | - type: textarea 41 | id: what-happened 42 | attributes: 43 | label: Describe the issue. 44 | description: What happened? Should something else have happened instead? Please provide steps to reproduce the issue if possible. 45 | placeholder: Tell us what you see! 46 | validations: 47 | required: true 48 | - type: textarea 49 | id: logs 50 | attributes: 51 | label: Relevant log output 52 | description: | 53 | Please copy and paste any relevant logs and stack traces. 54 | * Unity log: `%userprofile%\AppData\LocalLow\{Company}\{Game}\Player.log` or `output_log.txt` 55 | * BepInEx: `BepInEx\LogOutput.log` 56 | * MelonLoader: `MelonLoader\latest.log` 57 | * Standalone: `{DLL_Location}\UnityExplorer\Logs\` (pick the most recent one) 58 | render: shell 59 | validations: 60 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.yaml: -------------------------------------------------------------------------------- 1 | name: New feature or enhancement 2 | description: Suggest or discuss a feature or enhancement for UnityExplorer 3 | title: "[Enhancement]: " 4 | labels: [enhancement] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to discuss UnityExplorer, please provide as much detail as possible. 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: Describe the new feature or enhancement 14 | description: | 15 | Please go into as much detail as necessary in describing the new feature or enhancement. 16 | If providing examples or suggestions for the required C# code, please use syntax-highlighted code blocks. 17 | validations: 18 | required: true 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other.yaml: -------------------------------------------------------------------------------- 1 | name: Other 2 | description: Something else? 3 | title: "[Other]: " 4 | labels: [Other] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Describe the issue 10 | description: | 11 | Please describe the issue in as much detail as possible. 12 | validations: 13 | required: true 14 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: Build UnityExplorer 2 | 3 | # Controls when the action will run. 4 | on: 5 | push: 6 | branches: [master] 7 | # Allows you to run this workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: windows-latest 13 | if: "!contains(github.event.head_commit.message, '-noci')" 14 | 15 | steps: 16 | # Setup 17 | 18 | - name: Checkout latest 19 | uses: actions/checkout@v2 20 | 21 | - name: Setup dotnet 22 | uses: actions/setup-dotnet@v2 23 | with: 24 | dotnet-version: '6.0.x' 25 | include-prerelease: true 26 | 27 | # Run build script 28 | - run: | 29 | ./build.ps1 30 | 31 | # Upload artifacts 32 | 33 | # BepInEx IL2CPP 34 | - uses: actions/upload-artifact@v2 35 | with: 36 | name: UnityExplorer.BepInEx.IL2CPP.zip 37 | path: ./Release/UnityExplorer.BepInEx.IL2CPP/ 38 | 39 | # BepInEx IL2CPP CoreCLR 40 | - uses: actions/upload-artifact@v2 41 | with: 42 | name: UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip 43 | path: ./Release/UnityExplorer.BepInEx.IL2CPP.CoreCLR/ 44 | 45 | # BepInEx 5 Mono 46 | - uses: actions/upload-artifact@v2 47 | with: 48 | name: UnityExplorer.BepInEx5.Mono.zip 49 | path: ./Release/UnityExplorer.BepInEx5.Mono/ 50 | 51 | # BepInEx 6 Mono 52 | - uses: actions/upload-artifact@v2 53 | with: 54 | name: UnityExplorer.BepInEx6.Mono.zip 55 | path: ./Release/UnityExplorer.BepInEx6.Mono/ 56 | 57 | # Editor 58 | - uses: actions/upload-artifact@v2 59 | with: 60 | name: UnityExplorer.Editor.zip 61 | path: ./UnityEditorPackage/ 62 | 63 | # MelonLoader IL2CPP net6preview 64 | - uses: actions/upload-artifact@v2 65 | with: 66 | name: UnityExplorer.MelonLoader.IL2CPP.net6preview.zip 67 | path: ./Release/UnityExplorer.MelonLoader.IL2CPP.net6preview/ 68 | 69 | # MelonLoader IL2CPP net472 70 | - uses: actions/upload-artifact@v2 71 | with: 72 | name: UnityExplorer.MelonLoader.IL2CPP.zip 73 | path: ./Release/UnityExplorer.MelonLoader.IL2CPP/ 74 | 75 | # MelonLoader Mono 76 | - uses: actions/upload-artifact@v2 77 | with: 78 | name: UnityExplorer.MelonLoader.Mono.zip 79 | path: ./Release/UnityExplorer.MelonLoader.Mono/ 80 | 81 | # Standalone Il2Cpp 82 | - uses: actions/upload-artifact@v2 83 | with: 84 | name: UnityExplorer.Standalone.IL2CPP.zip 85 | path: ./Release/UnityExplorer.Standalone.IL2CPP/ 86 | 87 | # Standalone Mono 88 | - uses: actions/upload-artifact@v2 89 | with: 90 | name: UnityExplorer.Standalone.Mono.zip 91 | path: ./Release/UnityExplorer.Standalone.Mono/ 92 | 93 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | ### 4.10.5 4 | - Add ECS Unity Explorer to VRising community 5 | 6 |
7 | All changes 8 | 9 | ### 4.10.4 10 | - Add support for ECS v0.17. Some features might not work on it, like name system. 11 | 12 | ### 4.10.3 13 | - Fix issues when `GetName` or `SetName` are stripped 14 | 15 | ### 4.10.2 16 | - Allow inspecting Buffer components 17 | - Add more filters for World Explorer 18 | - Fixed that reflection inspector always refreshed 19 | - Fixed that new tabs were opened for existing entities 20 | 21 | ### 4.10.1 22 | - Fixed issue where Entity Inspector Tabs did not have [ECS] in their name. 23 | 24 | ### 4.10.0 25 | - Released ECS Unity Explorer Extension 26 | 27 | * Previous versions skipped * 28 |
29 | -------------------------------------------------------------------------------- /ECSExtension/BufferView.cs: -------------------------------------------------------------------------------- 1 | using ECSExtension.Util; 2 | 3 | namespace ECSExtension 4 | { 5 | public class BufferView where T : unmanaged 6 | { 7 | public readonly ModDynamicBuffer buffer; 8 | 9 | public BufferView(ModDynamicBuffer buffer) 10 | { 11 | this.buffer = buffer; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ECSExtension/CacheComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ECSExtension.Util; 3 | using Unity.Entities; 4 | using UnityExplorer; 5 | using UnityExplorer.CacheObject; 6 | using UnityExplorer.CacheObject.Views; 7 | using UniverseLib.Runtime; 8 | 9 | namespace ECSExtension 10 | { 11 | public sealed class CacheComponent : CacheObjectBase where T : unmanaged 12 | { 13 | private EntityManager entityManager; 14 | private Entity entity; 15 | 16 | public CacheComponent(EntityInspector inspector) 17 | { 18 | Owner = inspector; 19 | entityManager = inspector.currentWorld.EntityManager; 20 | entity = inspector.currentEntity; 21 | SetFallbackType(typeof(T)); 22 | } 23 | 24 | public override bool ShouldAutoEvaluate => true; 25 | public override bool HasArguments => false; 26 | public override bool CanWrite => true; 27 | public override bool RefreshFromSource => true; 28 | 29 | 30 | public override void TrySetUserValue(object value) 31 | { 32 | if (value is T component) 33 | { 34 | entityManager.SetModComponentData(entity, component); 35 | } 36 | } 37 | 38 | protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell) 39 | { 40 | CacheMemberCell cell = objectcell as CacheMemberCell; 41 | cell.EvaluateHolder.SetActive(false); 42 | 43 | if (State == ValueState.NotEvaluated) 44 | SetValueFromSource(TryEvaluate()); 45 | 46 | return true; 47 | } 48 | 49 | public override object TryEvaluate() 50 | { 51 | try 52 | { 53 | return entityManager.GetModComponentData(entity); 54 | } 55 | catch (Exception e) 56 | { 57 | ExplorerCore.LogWarning(e); 58 | } 59 | 60 | return null; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /ECSExtension/Extension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using BepInEx.Logging; 4 | using ECSExtension.Panels; 5 | using ECSExtension.Patch; 6 | using ECSExtension.Util; 7 | using HarmonyLib; 8 | using Unity.Entities; 9 | using UnityExplorer; 10 | using UnityExplorer.Inspectors; 11 | using UnityExplorer.UI; 12 | using UnityExplorer.UI.Panels; 13 | using UniverseLib.Runtime; 14 | 15 | namespace ECSExtension 16 | { 17 | public static class Extension 18 | { 19 | public const string PLUGIN_NAME = "ECS Inspector Extension"; 20 | 21 | public const string PLUGIN_GUID = "org.kremnev8.plugin.ecs-inspector-extension"; 22 | 23 | public const string VERSION = "1.0.2"; 24 | 25 | public static Harmony Harmony; 26 | public static ManualLogSource logger; 27 | 28 | public static void Load(ManualLogSource log) 29 | { 30 | logger = log; 31 | if (ECSInitialize.CurrentECSVersion == ECSInitialize.ECSVersion.NOT_USED) return; 32 | 33 | Harmony = new Harmony(PLUGIN_GUID); 34 | Harmony.PatchAll(typeof(GameObjectConversionMappingSystem_Patch)); 35 | 36 | InspectorManager.customInspectors.Add(EntityAdder); 37 | InspectorManager.equalityCheckers.Add(typeof(Entity), EntityEqualityChecker); 38 | UIManager.onInit += UIManagerOnInit; 39 | logger.LogInfo("Added Entity Inspector"); 40 | } 41 | 42 | private static void UIManagerOnInit() 43 | { 44 | ObjectExplorerPanel explorerPanel = UIManager.GetPanel(UIManager.Panels.ObjectExplorer); 45 | explorerPanel.AddTab(new WorldExplorer(explorerPanel)); 46 | logger.LogInfo("Added World Explorer"); 47 | } 48 | 49 | private static bool EntityEqualityChecker(object o1, object o2) 50 | { 51 | if (o1 is Entity e1 && o2 is Entity e2) 52 | { 53 | return e1.Equals(e2); 54 | } 55 | 56 | return false; 57 | } 58 | 59 | private static Type EntityAdder(object o) 60 | { 61 | if (o is Entity) 62 | { 63 | return typeof(EntityInspector); 64 | } 65 | 66 | return null; 67 | } 68 | 69 | public static bool Unload() 70 | { 71 | if (ECSInitialize.CurrentECSVersion == ECSInitialize.ECSVersion.NOT_USED) return true; 72 | Harmony.UnpatchSelf(); 73 | List entityInspectors = new List(); 74 | foreach (InspectorBase inspector in InspectorManager.Inspectors) 75 | { 76 | if (inspector is EntityInspector) 77 | { 78 | entityInspectors.Add(inspector); 79 | } 80 | } 81 | 82 | foreach (InspectorBase inspector in entityInspectors) 83 | { 84 | inspector.CloseInspector(); 85 | } 86 | 87 | InspectorManager.customInspectors.Remove(EntityAdder); 88 | InspectorManager.equalityCheckers.Remove(typeof(Entity)); 89 | logger.LogInfo("Removed Entity Inspector"); 90 | return true; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /ECSExtension/ExtensionPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using BepInEx; 3 | using BepInEx.Unity.Mono; 4 | using UnityExplorer; 5 | 6 | #if CPP 7 | using BepInEx.Unity.IL2CPP; 8 | #endif 9 | 10 | namespace ECSExtension 11 | { 12 | [BepInPlugin(Extension.PLUGIN_GUID, Extension.PLUGIN_NAME, Extension.VERSION)] 13 | [BepInDependency(ExplorerCore.GUID)] 14 | #if CPP 15 | public class ExtensionPlugin : BasePlugin 16 | { 17 | public override void Load() 18 | { 19 | Extension.Load(Log); 20 | } 21 | 22 | public override bool Unload() 23 | { 24 | return Extension.Unload(); 25 | } 26 | } 27 | #else 28 | public class ExtensionPlugin : BaseUnityPlugin 29 | { 30 | public void Awake() 31 | { 32 | Extension.Load(Logger); 33 | } 34 | 35 | private void OnDestroy() 36 | { 37 | Extension.Unload(); 38 | } 39 | } 40 | #endif 41 | } -------------------------------------------------------------------------------- /ECSExtension/Inspectors/ButtonNativeListHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Unity.Collections; 4 | using UniverseLib.UI.Widgets.ButtonList; 5 | using UniverseLib.UI.Widgets.ScrollView; 6 | 7 | namespace ECSExtension 8 | { 9 | public class ButtonNativeListHandler : ICellPoolDataSource where TCell : ButtonCell where TData : unmanaged 10 | { 11 | protected Func> GetEntries; 12 | protected Action SetICell; 13 | protected Func ShouldDisplay; 14 | protected Action OnCellClicked; 15 | private string currentFilter; 16 | 17 | public ScrollPool ScrollPool { get; private set; } 18 | 19 | public int ItemCount => CurrentEntries.Count; 20 | 21 | public List CurrentEntries { get; } = new List(); 22 | 23 | public string CurrentFilter 24 | { 25 | get => currentFilter; 26 | set => currentFilter = value ?? ""; 27 | } 28 | 29 | /// Create a wrapper to handle your Button ScrollPool. 30 | /// The ScrollPool<ButtonCell> you have already created. 31 | /// A method which should return your current data values. 32 | /// A method which should set the data at the int index to the cell. 33 | /// A method which should determine if the data at the index should be displayed, with an optional string filter from CurrentFilter. 34 | /// A method invoked when a cell is clicked, containing the data index assigned to the cell. 35 | public ButtonNativeListHandler( 36 | ScrollPool scrollPool, 37 | Func> getEntriesMethod, 38 | Action setICellMethod, 39 | Func shouldDisplayMethod, 40 | Action onCellClickedMethod) 41 | { 42 | ScrollPool = scrollPool; 43 | GetEntries = getEntriesMethod; 44 | SetICell = setICellMethod; 45 | ShouldDisplay = shouldDisplayMethod; 46 | OnCellClicked = onCellClickedMethod; 47 | } 48 | 49 | public void RefreshData() 50 | { 51 | NativeArray dataList = GetEntries(); 52 | CurrentEntries.Clear(); 53 | foreach (TData data in dataList) 54 | { 55 | if (!string.IsNullOrEmpty(currentFilter)) 56 | { 57 | if (ShouldDisplay(data, currentFilter)) 58 | CurrentEntries.Add(data); 59 | } 60 | else 61 | CurrentEntries.Add(data); 62 | } 63 | } 64 | 65 | public virtual void OnCellBorrowed(TCell cell) 66 | { 67 | cell.OnClick += OnCellClicked; 68 | } 69 | 70 | public virtual void SetCell(TCell cell, int index) 71 | { 72 | if (CurrentEntries == null) 73 | RefreshData(); 74 | if (index < 0 || index >= CurrentEntries.Count) 75 | { 76 | cell.Disable(); 77 | } 78 | else 79 | { 80 | cell.Enable(); 81 | cell.CurrentDataIndex = index; 82 | SetICell(cell, index); 83 | } 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /ECSExtension/Inspectors/ECSComponentCell.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ECSExtension.Util; 3 | using Unity.Entities; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | using UniverseLib.Runtime; 7 | using UniverseLib.UI; 8 | using UniverseLib.UI.Models; 9 | using UniverseLib.UI.Widgets.ButtonList; 10 | 11 | #if CPP 12 | using Type = Il2CppSystem.Type; 13 | #endif 14 | 15 | namespace ECSExtension 16 | { 17 | public class ECSComponentCell : ButtonCell 18 | { 19 | public ButtonRef DestroyButton; 20 | public Text typeLabel; 21 | 22 | public Action OnDestroyClicked; 23 | 24 | public void ConfigureCell(ComponentType type) 25 | { 26 | Type monoType = type.GetManagedType(); 27 | TypeManager.TypeInfo typeInfo = ECSHelper.GetTypeInfo(type.TypeIndex); 28 | 29 | Button.ButtonText.text = monoType.ToString(); 30 | typeLabel.text = GetCategoryText(typeInfo.Category); 31 | 32 | } 33 | 34 | private string GetCategoryText(TypeManager.TypeCategory category) 35 | { 36 | switch (category) 37 | { 38 | case TypeManager.TypeCategory.ComponentData: 39 | return "Component"; 40 | case TypeManager.TypeCategory.BufferData: 41 | return "Buffer"; 42 | case TypeManager.TypeCategory.ISharedComponentData: 43 | return "Shared"; 44 | case TypeManager.TypeCategory.EntityData: 45 | return "Entity"; 46 | case TypeManager.TypeCategory.UnityEngineObject: 47 | return "UObject"; 48 | default: 49 | return ""; 50 | } 51 | } 52 | 53 | private void DestroyClicked() 54 | { 55 | OnDestroyClicked?.Invoke(CurrentDataIndex); 56 | } 57 | 58 | public override GameObject CreateContent(GameObject parent) 59 | { 60 | var root = base.CreateContent(parent); 61 | 62 | // Add mask to button so text doesnt overlap on Close button 63 | //this.Button.Component.gameObject.AddComponent().showMaskGraphic = true; 64 | this.Button.ButtonText.horizontalOverflow = HorizontalWrapMode.Wrap; 65 | 66 | typeLabel = UIFactory.CreateLabel(UIRoot, "TypeLabel", "Component", TextAnchor.MiddleCenter); 67 | UIFactory.SetLayoutElement(typeLabel.gameObject, minHeight: 21, minWidth: 100); 68 | 69 | DestroyButton = UIFactory.CreateButton(UIRoot, "DestroyButton", "X", new Color(0.3f, 0.2f, 0.2f)); 70 | UIFactory.SetLayoutElement(DestroyButton.Component.gameObject, minHeight: 21, minWidth: 25); 71 | DestroyButton.OnClick += DestroyClicked; 72 | 73 | return root; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /ECSExtension/Inspectors/ECSComponentList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using ECSExtension.Util; 4 | using HarmonyLib; 5 | using Unity.Collections; 6 | using Unity.Entities; 7 | using UnityExplorer; 8 | using UniverseLib; 9 | using UniverseLib.Runtime; 10 | using UniverseLib.UI.Widgets.ScrollView; 11 | 12 | #if CPP 13 | using Type = Il2CppSystem.Type; 14 | #endif 15 | 16 | namespace ECSExtension 17 | { 18 | public class ECSComponentList : ButtonNativeListHandler 19 | { 20 | public EntityInspector Parent; 21 | 22 | public ECSComponentList(ScrollPool scrollPool, Func> getEntriesMethod) 23 | : base(scrollPool, getEntriesMethod, null, null, null) 24 | { 25 | SetICell = SetComponentCell; 26 | ShouldDisplay = CheckShouldDisplay; 27 | OnCellClicked = OnComponentClicked; 28 | } 29 | 30 | public void Clear() 31 | { 32 | RefreshData(); 33 | ScrollPool.Refresh(true, true); 34 | } 35 | 36 | private bool CheckShouldDisplay(ComponentType _, string __) => true; 37 | 38 | public override void OnCellBorrowed(ECSComponentCell cell) 39 | { 40 | base.OnCellBorrowed(cell); 41 | 42 | cell.OnDestroyClicked += OnDestroyClicked; 43 | } 44 | 45 | private void OnComponentClicked(int index) 46 | { 47 | var entries = GetEntries(); 48 | 49 | if (index < 0 || index >= entries.Length) 50 | return; 51 | 52 | ComponentType comp = entries[index]; 53 | InvokeForComponent(comp, nameof(InspectComponent)); 54 | } 55 | 56 | private void InvokeForComponent(ComponentType comp, string methodName) 57 | { 58 | Type componentType = comp.GetManagedType(); 59 | #if CPP 60 | System.Type monoType = Il2CppReflection.GetUnhollowedType(componentType); 61 | #else 62 | Type monoType = componentType; 63 | #endif 64 | var method = typeof(ECSComponentList).GetMethod(methodName, AccessTools.all); 65 | method.MakeGenericMethod(monoType) 66 | .Invoke(this, Array.Empty()); 67 | } 68 | 69 | private void InspectComponent() where T : unmanaged 70 | { 71 | ComponentType type = ECSHelper.ReadOnly(); 72 | var category = ECSHelper.GetTypeInfo(type.TypeIndex).Category; 73 | 74 | if (category == TypeManager.TypeCategory.BufferData) 75 | { 76 | ModDynamicBuffer dynamicBuffer = Parent.GetDynamicBuffer(); 77 | InspectorManager.Inspect(new BufferView(dynamicBuffer)); 78 | } 79 | else 80 | { 81 | CacheComponent data = Parent.GetComponentData(); 82 | InspectorManager.Inspect(data.TryEvaluate(), data); 83 | } 84 | } 85 | 86 | private void OnDestroyClicked(int index) 87 | { 88 | try 89 | { 90 | var entries = GetEntries(); 91 | var comp = entries[index]; 92 | 93 | Parent.RemoveComponent(comp); 94 | Parent.UpdateComponents(); 95 | } 96 | catch (Exception ex) 97 | { 98 | ExplorerCore.LogWarning($"Exception destroying Component: {ex.ReflectionExToString()}"); 99 | } 100 | } 101 | 102 | private static readonly Dictionary compToStringCache = new Dictionary(); 103 | 104 | // Called from ButtonListHandler.SetCell, will be valid 105 | private void SetComponentCell(ECSComponentCell cell, int index) 106 | { 107 | var entries = GetEntries(); 108 | cell.Enable(); 109 | 110 | try 111 | { 112 | cell.ConfigureCell(entries[index]); 113 | } 114 | catch (Exception e) 115 | { 116 | ExplorerCore.Log($"Error setting component name: {e.Message}, stacktrace: {e.StackTrace}"); 117 | } 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /ECSExtension/Panels/EntityCell.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ECSExtension.Util; 3 | using Unity.Entities; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | using UniverseLib; 7 | using UniverseLib.Runtime; 8 | using UniverseLib.UI; 9 | using UniverseLib.UI.Models; 10 | using UniverseLib.UI.ObjectPool; 11 | using UniverseLib.UI.Widgets.ScrollView; 12 | 13 | namespace ECSExtension 14 | { 15 | public class EntityCell : ICell, IPooledObject 16 | { 17 | public float DefaultHeight => 25f; 18 | public GameObject UIRoot { get; set; } 19 | public RectTransform Rect { get; set; } 20 | 21 | public bool Enabled => UIRoot.activeSelf; 22 | public void Enable() => UIRoot.SetActive(true); 23 | public void Disable() => UIRoot.SetActive(false); 24 | 25 | public Entity entity; 26 | 27 | public Action OnEntityClicked; 28 | public Action onEnableClicked; 29 | private Toggle EnabledToggle; 30 | private ButtonRef NameButton; 31 | 32 | 33 | public void ConfigureCell(Entity entity, EntityManager entityManager) 34 | { 35 | this.entity = entity; 36 | NameButton.ButtonText.text = ECSHelper.GetName(entityManager, entity); 37 | EnabledToggle.Set(ECSHelper.IsEntityEnabled(entityManager, entity), false); 38 | } 39 | 40 | private void MainButtonClicked() 41 | { 42 | OnEntityClicked?.Invoke(entity); 43 | } 44 | 45 | private void OnEnableClicked(bool value) 46 | { 47 | onEnableClicked?.Invoke(entity, value); 48 | } 49 | 50 | public GameObject CreateContent(GameObject parent) 51 | { 52 | UIRoot = UIFactory.CreateUIObject("TransformCell", parent); 53 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 2, childAlignment: TextAnchor.MiddleCenter); 54 | Rect = UIRoot.GetComponent(); 55 | Rect.anchorMin = new Vector2(0, 1); 56 | Rect.anchorMax = new Vector2(0, 1); 57 | Rect.pivot = new Vector2(0.5f, 1); 58 | Rect.sizeDelta = new Vector2(25, 25); 59 | UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0); 60 | 61 | GameObject spacerObj = UIFactory.CreateUIObject("Spacer", UIRoot, new Vector2(0, 0)); 62 | UIFactory.SetLayoutElement(spacerObj, minWidth: 0, flexibleWidth: 0, minHeight: 0, flexibleHeight: 0); 63 | 64 | // Expand arrow 65 | 66 | var label =UIFactory.CreateLabel(UIRoot, "DotObj", "▪"); 67 | UIFactory.SetLayoutElement(label.gameObject, minWidth: 15, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); 68 | 69 | // Enabled toggle 70 | 71 | GameObject toggleObj = UIFactory.CreateToggle(UIRoot, "BehaviourToggle", out EnabledToggle, out Text behavText, default, 17, 17); 72 | UIFactory.SetLayoutElement(toggleObj, minHeight: 17, flexibleHeight: 0, minWidth: 17); 73 | EnabledToggle.onValueChanged.AddListener(OnEnableClicked); 74 | 75 | // Name button 76 | 77 | GameObject nameBtnHolder = UIFactory.CreateHorizontalGroup(UIRoot, "NameButtonHolder", 78 | false, false, true, true, childAlignment: TextAnchor.MiddleLeft); 79 | UIFactory.SetLayoutElement(nameBtnHolder, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0); 80 | nameBtnHolder.AddComponent().showMaskGraphic = false; 81 | 82 | NameButton = UIFactory.CreateButton(nameBtnHolder, "NameButton", "Name"); 83 | UIFactory.SetLayoutElement(NameButton.Component.gameObject, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0); 84 | Text nameLabel = NameButton.Component.GetComponentInChildren(); 85 | nameLabel.horizontalOverflow = HorizontalWrapMode.Overflow; 86 | nameLabel.alignment = TextAnchor.MiddleLeft; 87 | 88 | // Setup selectables 89 | 90 | Color normal = new Color(0.11f, 0.11f, 0.11f); 91 | Color highlight = new Color(0.25f, 0.25f, 0.25f); 92 | Color pressed = new Color(0.05f, 0.05f, 0.05f); 93 | Color disabled = new Color(1, 1, 1, 0); 94 | RuntimeHelper.SetColorBlock(NameButton.Component, normal, highlight, pressed, disabled); 95 | 96 | NameButton.OnClick += MainButtonClicked; 97 | 98 | UIRoot.SetActive(false); 99 | 100 | return UIRoot; 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /ECSExtension/Panels/EntityTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using ECSExtension.Util; 6 | using Unity.Collections; 7 | using Unity.Entities; 8 | using Unity.Jobs; 9 | using UnityEngine; 10 | using UniverseLib; 11 | using UniverseLib.Runtime; 12 | using UniverseLib.UI.Widgets.ScrollView; 13 | 14 | namespace ECSExtension.Panels 15 | { 16 | public class EntityTree : ICellPoolDataSource 17 | { 18 | private World world; 19 | private EntityQuery query; 20 | private JobHandle queryHandle; 21 | private ModNativeArray nativeArray; 22 | private IList entities; 23 | private string currentFilter; 24 | 25 | public ScrollPool ScrollPool; 26 | 27 | private Coroutine refreshCoroutine; 28 | 29 | public int ItemCount => currentCount; 30 | private int currentCount; 31 | 32 | public Action OnClickHandler; 33 | 34 | public EntityTree(ScrollPool scrollPool, Action onCellClicked) 35 | { 36 | ScrollPool = scrollPool; 37 | OnClickHandler = onCellClicked; 38 | ScrollPool.Initialize(this); 39 | } 40 | 41 | public void SetWorld(World world) 42 | { 43 | this.world = world; 44 | query = world.EntityManager.UniversalQuery; 45 | } 46 | 47 | public void UseQuery(ComponentType[] include, ComponentType[] exclude, bool includeDisabled) 48 | { 49 | query = world.EntityManager.CreateEntityQuery(new EntityQueryDesc() 50 | { 51 | All = include, 52 | None = exclude, 53 | Options = includeDisabled ? EntityQueryOptions.IncludeDisabled : EntityQueryOptions.Default 54 | }); 55 | } 56 | 57 | public void SetFilter(string filter) 58 | { 59 | currentFilter = filter; 60 | ApplyFilter(true); 61 | } 62 | 63 | private void ApplyFilter(bool refresh) 64 | { 65 | if (string.IsNullOrEmpty(currentFilter)) 66 | entities = nativeArray; 67 | else 68 | entities = nativeArray.Where(entity => ECSHelper.GetName(world.EntityManager, entity).Contains(currentFilter, StringComparison.InvariantCultureIgnoreCase)).ToList(); 69 | 70 | if (refresh) 71 | ScrollPool.Refresh(true, true); 72 | } 73 | 74 | 75 | public void RefreshData(bool jumpToTop) 76 | { 77 | if (refreshCoroutine != null || world == null) 78 | return; 79 | 80 | if (nativeArray.IsCreated) 81 | nativeArray.Dispose(); 82 | 83 | nativeArray = new ModNativeArray(query.ToEntityArrayAsync(Allocator.Persistent, out queryHandle)); 84 | entities = nativeArray; 85 | 86 | refreshCoroutine = RuntimeHelper.StartCoroutine(RefreshCoroutine(jumpToTop)); 87 | } 88 | 89 | private IEnumerator RefreshCoroutine(bool jumpToTop) 90 | { 91 | while (!queryHandle.IsCompleted) 92 | yield return null; 93 | 94 | queryHandle.Complete(); 95 | currentCount = nativeArray.Count; 96 | ApplyFilter(false); 97 | 98 | ScrollPool.Refresh(true, jumpToTop); 99 | refreshCoroutine = null; 100 | } 101 | 102 | public void SetCell(EntityCell cell, int index) 103 | { 104 | if (index < entities.Count) 105 | { 106 | cell.ConfigureCell(entities[index], world.EntityManager); 107 | } 108 | else 109 | cell.Disable(); 110 | } 111 | 112 | public void OnCellBorrowed(EntityCell cell) 113 | { 114 | cell.OnEntityClicked += OnEntityClicked; 115 | cell.onEnableClicked += OnEnableClicked; 116 | } 117 | 118 | private void OnEnableClicked(Entity entity, bool value) 119 | { 120 | if (world.EntityManager.Exists(entity)) 121 | { 122 | world.EntityManager.SetEnabled(entity, value); 123 | } 124 | } 125 | 126 | private void OnEntityClicked(Entity obj) 127 | { 128 | Action onClickHandler = OnClickHandler; 129 | if (onClickHandler == null) 130 | return; 131 | onClickHandler(obj); 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /ECSExtension/Panels/QueryComponentCell.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | using UnityExplorer.UI.Widgets.AutoComplete; 5 | using UniverseLib.UI; 6 | using UniverseLib.UI.Models; 7 | using UniverseLib.UI.Widgets.ScrollView; 8 | 9 | namespace ECSExtension.Panels 10 | { 11 | public class QueryComponentCell : ICell 12 | { 13 | public GameObject UIRoot { get; set; } 14 | public float DefaultHeight => 25; 15 | 16 | public bool Enabled => UIRoot.activeSelf; 17 | public void Enable() => UIRoot.SetActive(true); 18 | public void Disable() => UIRoot.SetActive(false); 19 | 20 | public RectTransform Rect { get; set; } 21 | private TypeCompleter typeCompleter; 22 | private InputFieldRef componentInputField; 23 | private Dropdown searchTypeDropdown; 24 | private int cellIndex; 25 | 26 | private static readonly String[] options = 27 | { 28 | "Include", 29 | "Exclude" 30 | }; 31 | 32 | public Action OnTextChanged; 33 | public Action OnSearchTypeChanged; 34 | 35 | public void ConfigureCell(int index, QueryComponentList.SearchData currentValue) 36 | { 37 | cellIndex = index; 38 | componentInputField.Text = currentValue.componentName; 39 | searchTypeDropdown.value = (int)currentValue.searchType; 40 | } 41 | 42 | public void SetCellToDefault(int index) 43 | { 44 | cellIndex = index; 45 | componentInputField.Text = ""; 46 | searchTypeDropdown.value = 0; 47 | } 48 | 49 | private void OnInputChanged(string text) 50 | { 51 | OnTextChanged?.Invoke(cellIndex, text); 52 | } 53 | 54 | public GameObject CreateContent(GameObject parent) 55 | { 56 | UIRoot = UIFactory.CreateUIObject("TransformCell", parent); 57 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 2, childAlignment: TextAnchor.MiddleCenter); 58 | Rect = UIRoot.GetComponent(); 59 | Rect.anchorMin = new Vector2(0, 1); 60 | Rect.anchorMax = new Vector2(0, 1); 61 | Rect.pivot = new Vector2(0.5f, 1); 62 | Rect.sizeDelta = new Vector2(25, 25); 63 | UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0); 64 | // Class input 65 | 66 | Text unityClassLbl = UIFactory.CreateLabel(UIRoot, "ComponentLabel", "Component:", TextAnchor.MiddleLeft); 67 | UIFactory.SetLayoutElement(unityClassLbl.gameObject, minWidth: 90, flexibleWidth: 0); 68 | 69 | componentInputField = UIFactory.CreateInputField(UIRoot, "CComponentInput", "..."); 70 | UIFactory.SetLayoutElement(componentInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); 71 | componentInputField.OnValueChanged += OnInputChanged; 72 | 73 | GameObject layerDrop = UIFactory.CreateDropdown(UIRoot, "SearchTypeDropDown", out searchTypeDropdown, "Include", 14, OnSearchDropdownChanged, options); 74 | UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 100); 75 | 76 | typeCompleter = new TypeCompleter(typeof(ValueType), componentInputField, false, false, false); 77 | return UIRoot; 78 | } 79 | 80 | private void OnSearchDropdownChanged(int searchType) 81 | { 82 | OnSearchTypeChanged?.Invoke(cellIndex, searchType); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /ECSExtension/Panels/QueryComponentList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Unity.Entities; 4 | using UnityEngine.UI; 5 | using UniverseLib; 6 | using UniverseLib.UI.Widgets.ScrollView; 7 | 8 | #if CPP 9 | using Il2CppInterop.Runtime; 10 | #endif 11 | 12 | namespace ECSExtension.Panels 13 | { 14 | public class QueryComponentList : ICellPoolDataSource 15 | { 16 | private List componentNames = new List(); 17 | private ScrollPool scrollPool; 18 | public int ItemCount => componentNames.Count + 1; 19 | private LayoutElement viewportLayout; 20 | 21 | public QueryComponentList(ScrollPool scrollPool, LayoutElement viewportLayout) 22 | { 23 | this.scrollPool = scrollPool; 24 | this.viewportLayout = viewportLayout; 25 | scrollPool.Initialize(this); 26 | var sliderContainer = this.scrollPool.UIRoot.transform.Find("SliderContainer").gameObject; 27 | sliderContainer.SetActive(false); 28 | scrollPool.Refresh(true, true); 29 | } 30 | 31 | public ComponentType[] GetComponents(SearchType searchType) 32 | { 33 | return componentNames 34 | .Where(data => data.searchType == searchType) 35 | .Select(data => ReflectionUtility.GetTypeByName(data.componentName)) 36 | .Where(type => type != null) 37 | .Select(type => 38 | { 39 | #if CPP 40 | var il2cppType = Il2CppType.From(type); 41 | return TypeManager.GetTypeIndex(il2cppType); 42 | #else 43 | return TypeManager.GetTypeIndex(type); 44 | #endif 45 | }) 46 | .Where(index => index >= 0) 47 | .Select(ComponentType.FromTypeIndex).ToArray(); 48 | } 49 | 50 | public void OnCellBorrowed(QueryComponentCell cell) 51 | { 52 | cell.OnTextChanged += OnTextChanged; 53 | cell.OnSearchTypeChanged += OnSearchTypeChanged; 54 | } 55 | 56 | private void OnSearchTypeChanged(int index, int type) 57 | { 58 | if (index >= 0 && index < componentNames.Count) 59 | { 60 | componentNames[index].searchType = (SearchType)type; 61 | } 62 | 63 | viewportLayout.preferredHeight = ItemCount * 25; 64 | scrollPool.Refresh(true, true); 65 | } 66 | 67 | private void OnTextChanged(int index, string text) 68 | { 69 | if (index >= 0 && index < componentNames.Count) 70 | { 71 | if (string.IsNullOrEmpty(text)) 72 | componentNames.RemoveAt(index); 73 | else 74 | componentNames[index].componentName = text; 75 | } 76 | else 77 | { 78 | componentNames.Add(new SearchData(text)); 79 | } 80 | 81 | viewportLayout.preferredHeight = ItemCount * 25; 82 | scrollPool.Refresh(true, true); 83 | } 84 | 85 | public void SetCell(QueryComponentCell cell, int index) 86 | { 87 | if (index >= 0 && index < componentNames.Count) 88 | cell.ConfigureCell(index, componentNames[index]); 89 | else if (index < componentNames.Count + 1) 90 | cell.SetCellToDefault(index); 91 | else 92 | cell.Disable(); 93 | } 94 | 95 | public class SearchData 96 | { 97 | public string componentName; 98 | public SearchType searchType; 99 | 100 | public SearchData(string componentName) 101 | { 102 | this.componentName = componentName; 103 | } 104 | } 105 | 106 | public enum SearchType 107 | { 108 | Include, 109 | Exclude 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /ECSExtension/Patch/GameObjectConversionMappingSystem_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using Unity.Entities; 3 | using Unity.Entities.Conversion; 4 | 5 | namespace ECSExtension.Patch 6 | { 7 | public class GameObjectConversionMappingSystem_Patch 8 | { 9 | [HarmonyPatch(typeof(GameObjectConversionMappingSystem), nameof(GameObjectConversionMappingSystem.InitArchetypes))] 10 | [HarmonyPostfix] 11 | public static void OnCreate(GameObjectConversionMappingSystem __instance) 12 | { 13 | __instance.Settings.ConversionFlags |= GameObjectConversionUtility.ConversionFlags.AssignName; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/0Harmony.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/0Harmony.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/Mono.Cecil.Mdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/Mono.Cecil.Mdb.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/Mono.Cecil.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/MonoMod.RuntimeDetour.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/MonoMod.RuntimeDetour.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/MonoMod.Utils.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/MonoMod.Utils.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/Tomlet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/Tomlet.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/UnityExplorer.STANDALONE.Mono.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/UnityExplorer.STANDALONE.Mono.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/UnityExplorer.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &2342243352467007562 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 2342243352467007560} 12 | - component: {fileID: 2342243352467007563} 13 | m_Layer: 0 14 | m_Name: UnityExplorer 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &2342243352467007560 21 | Transform: 22 | m_ObjectHideFlags: 0 23 | m_CorrespondingSourceObject: {fileID: 0} 24 | m_PrefabInstance: {fileID: 0} 25 | m_PrefabAsset: {fileID: 0} 26 | m_GameObject: {fileID: 2342243352467007562} 27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 28 | m_LocalPosition: {x: 0, y: 0, z: 0} 29 | m_LocalScale: {x: 1, y: 1, z: 1} 30 | m_Children: [] 31 | m_Father: {fileID: 0} 32 | m_RootOrder: 0 33 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 34 | --- !u!114 &2342243352467007563 35 | MonoBehaviour: 36 | m_ObjectHideFlags: 0 37 | m_CorrespondingSourceObject: {fileID: 0} 38 | m_PrefabInstance: {fileID: 0} 39 | m_PrefabAsset: {fileID: 0} 40 | m_GameObject: {fileID: 2342243352467007562} 41 | m_Enabled: 1 42 | m_EditorHideFlags: 0 43 | m_Script: {fileID: 255528132, guid: 7e940c577136f52428020c8e128f06f3, type: 3} 44 | m_Name: 45 | m_EditorClassIdentifier: 46 | -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/UniverseLib.Mono.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/UniverseLib.Mono.dll -------------------------------------------------------------------------------- /UnityEditorPackage/Runtime/mcs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/UnityEditorPackage/Runtime/mcs.dll -------------------------------------------------------------------------------- /UnityEditorPackage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.sinai-dev.unityexplorer", 3 | "version": "4.7.12", 4 | "displayName": "UnityExplorer", 5 | "description": "An in-game UI for exploring, debugging and modifying Unity games.", 6 | "unity": "2017.1", 7 | "documentationUrl": "https://github.com/sinai-dev/UnityExplorer", 8 | "changelogUrl": "https://github.com/sinai-dev/UnityExplorer/releases", 9 | "licensesUrl": "https://github.com/sinai-dev/UnityExplorer/blob/master/LICENSE", 10 | "keywords": [ 11 | "inspector", 12 | "debug", 13 | "runtime" 14 | ], 15 | "author": { 16 | "name": "Sinai", 17 | "url": "https://github.com/sinai-dev" 18 | } 19 | } -------------------------------------------------------------------------------- /buildBIE5.ps1: -------------------------------------------------------------------------------- 1 | # ----------- BepInEx 5 Mono ----------- 2 | dotnet build src/UnityExplorer.sln -c Release_BIE5_Mono 3 | $Path = "Release/UnityExplorer.BepInEx5.Mono" 4 | # ILRepack 5 | lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.BIE5.Mono.dll $Path/UnityExplorer.BIE5.Mono.dll $Path/mcs.dll $Path/Tomlet.dll 6 | # (cleanup and move files) 7 | Remove-Item $Path/Tomlet.dll 8 | Remove-Item $Path/mcs.dll 9 | New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force 10 | New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force 11 | Move-Item -Path $Path/UnityExplorer.BIE5.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 12 | Move-Item -Path $Path/UniverseLib.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 13 | Move-Item -Path $Path/ECSExtension.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 14 | Move-Item -Path $Path/ECSExtension.pdb -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 15 | 16 | # (create zip archive) 17 | Remove-Item $Path/../UnityExplorer.BepInEx5.Mono.zip -ErrorAction SilentlyContinue 18 | 7z a $Path/../UnityExplorer.BepInEx5.Mono.zip .\$Path\* -------------------------------------------------------------------------------- /buildBIE6.ps1: -------------------------------------------------------------------------------- 1 | # ----------- BepInEx 6 Mono ----------- 2 | dotnet build src/UnityExplorer.sln -c Release_BIE6_Mono 3 | $Path = "Release/UnityExplorer.BepInEx6.Mono" 4 | # ILRepack 5 | lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.BIE6.Mono.dll $Path/UnityExplorer.BIE6.Mono.dll $Path/mcs.dll $Path/Tomlet.dll 6 | # (cleanup and move files) 7 | Remove-Item $Path/Tomlet.dll 8 | Remove-Item $Path/mcs.dll 9 | New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force 10 | New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force 11 | Move-Item -Path $Path/UnityExplorer.BIE6.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 12 | Move-Item -Path $Path/UniverseLib.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 13 | Move-Item -Path $Path/ECSExtension.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 14 | Move-Item -Path $Path/ECSExtension.pdb -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 15 | 16 | # (create zip archive) 17 | Remove-Item $Path/../UnityExplorer.BepInEx6.Mono.zip -ErrorAction SilentlyContinue 18 | 7z a $Path/../UnityExplorer.BepInEx6.Mono.zip .\$Path\* -------------------------------------------------------------------------------- /buildCLR.ps1: -------------------------------------------------------------------------------- 1 | # ----------- BepInEx IL2CPP CoreCLR ----------- 2 | dotnet build src/UnityExplorer.sln -c Release_BIE_CoreCLR 3 | $Path = "Release/UnityExplorer.BepInEx.IL2CPP.CoreCLR" 4 | # ILRepack 5 | lib/ILRepack.exe /target:library /lib:lib/net472 /lib:lib/net6/ /lib:lib/interop/ /lib:$Path /internalize /out:$Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll $Path/mcs.dll $Path/Tomlet.dll 6 | # (cleanup and move files) 7 | Remove-Item $Path/Tomlet.dll 8 | Remove-Item $Path/mcs.dll 9 | Remove-Item $Path/Iced.dll 10 | Remove-Item $Path/Il2CppInterop.Common.dll 11 | Remove-Item $Path/Il2CppInterop.Runtime.dll 12 | Remove-Item $Path/Microsoft.Extensions.Logging.Abstractions.dll 13 | Remove-Item $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.deps.json 14 | New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force 15 | New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force 16 | Move-Item -Path $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 17 | Move-Item -Path $Path/UniverseLib.IL2CPP.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 18 | Move-Item -Path $Path/ECSExtension.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 19 | Move-Item -Path $Path/ECSExtension.pdb -Destination $Path/plugins/sinai-dev-UnityExplorer -Force 20 | 21 | # (create zip archive) 22 | Remove-Item $Path/../UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip -ErrorAction SilentlyContinue 23 | 7z a $Path/../UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip .\$Path\* -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/img/icon.png -------------------------------------------------------------------------------- /img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/img/preview.png -------------------------------------------------------------------------------- /lib/ILRepack.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/ILRepack.exe -------------------------------------------------------------------------------- /lib/interop/CoreLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/CoreLib.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Burst.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Burst.Unsafe.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Burst.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Burst.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Collections.LowLevel.ILSupport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Collections.LowLevel.ILSupport.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Collections.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Entities.Hybrid.HybridComponents.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Entities.Hybrid.HybridComponents.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Entities.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Entities.Hybrid.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Entities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Entities.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Mathematics.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Mathematics.Extensions.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Mathematics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Mathematics.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.NetCode.Authoring.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.NetCode.Authoring.Hybrid.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.NetCode.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.NetCode.Physics.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.NetCode.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.NetCode.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Networking.Transport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Networking.Transport.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Physics.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Physics.Hybrid.dll -------------------------------------------------------------------------------- /lib/interop/ECS/Unity.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/ECS/Unity.Physics.dll -------------------------------------------------------------------------------- /lib/interop/Il2CppSystem.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/Il2CppSystem.Core.dll -------------------------------------------------------------------------------- /lib/interop/Il2Cppmscorlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/Il2Cppmscorlib.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.AssetBundleModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.AssetBundleModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.AudioModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.AudioModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.CoreModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.CoreModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.IMGUIModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.IMGUIModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.PhysicsModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.PhysicsModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.TextRenderingModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.TextRenderingModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.UI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.UI.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.UIModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.UIModule.dll -------------------------------------------------------------------------------- /lib/interop/UnityEngine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/interop/UnityEngine.dll -------------------------------------------------------------------------------- /lib/net35/BepInEx.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/BepInEx.Core.dll -------------------------------------------------------------------------------- /lib/net35/BepInEx.Unity.Common.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/BepInEx.Unity.Common.dll -------------------------------------------------------------------------------- /lib/net35/BepInEx.Unity.Mono.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/BepInEx.Unity.Mono.dll -------------------------------------------------------------------------------- /lib/net35/BepInEx.Unity.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/BepInEx.Unity.dll -------------------------------------------------------------------------------- /lib/net35/BepInEx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/BepInEx.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Burst.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Burst.Unsafe.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Burst.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Burst.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Collections.LowLevel.ILSupport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Collections.LowLevel.ILSupport.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Collections.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Entities.Hybrid.HybridComponents.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Entities.Hybrid.HybridComponents.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Entities.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Entities.Hybrid.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Entities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Entities.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Mathematics.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Mathematics.Extensions.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Mathematics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Mathematics.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.NetCode.Authoring.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.NetCode.Authoring.Hybrid.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.NetCode.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.NetCode.Physics.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.NetCode.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.NetCode.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Networking.Transport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Networking.Transport.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Physics.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Physics.Hybrid.dll -------------------------------------------------------------------------------- /lib/net35/ECS/Unity.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/ECS/Unity.Physics.dll -------------------------------------------------------------------------------- /lib/net35/MelonLoader.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/MelonLoader.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.AssetBundleModule_publicized.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.AssetBundleModule_publicized.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.AudioModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.AudioModule.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.CoreModule_publicized.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.CoreModule_publicized.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.IMGUIModule_publicized.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.IMGUIModule_publicized.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.PhysicsModule_publicized.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.PhysicsModule_publicized.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.TextRenderingModule_publicized.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.TextRenderingModule_publicized.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.UI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.UI.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.UIModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.UIModule.dll -------------------------------------------------------------------------------- /lib/net35/UnityEngine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/UnityEngine.dll -------------------------------------------------------------------------------- /lib/net35/mcs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net35/mcs.dll -------------------------------------------------------------------------------- /lib/net472/BepInEx.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net472/BepInEx.Core.dll -------------------------------------------------------------------------------- /lib/net472/BepInEx.Unity.IL2CPP.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net472/BepInEx.Unity.IL2CPP.dll -------------------------------------------------------------------------------- /lib/net6/MelonLoader.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net6/MelonLoader.dll -------------------------------------------------------------------------------- /lib/net6/System.Runtime.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net6/System.Runtime.dll -------------------------------------------------------------------------------- /lib/net6/UniverseLib.IL2CPP.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net6/UniverseLib.IL2CPP.Interop.dll -------------------------------------------------------------------------------- /lib/net6/mcs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/net6/mcs.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Burst.Unsafe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Burst.Unsafe.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Burst.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Burst.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Collections.LowLevel.ILSupport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Collections.LowLevel.ILSupport.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Collections.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Entities.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Entities.Hybrid.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Entities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Entities.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Jobs.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Jobs.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Mathematics.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Mathematics.Extensions.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Mathematics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Mathematics.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.NetCode.Authoring.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.NetCode.Authoring.Hybrid.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.NetCode.Generated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.NetCode.Generated.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.NetCode.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.NetCode.Physics.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.NetCode.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.NetCode.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Networking.Transport.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Networking.Transport.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Physics.Hybrid.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Physics.Hybrid.dll -------------------------------------------------------------------------------- /lib/unhollowed/ECS/Unity.Physics.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/ECS/Unity.Physics.dll -------------------------------------------------------------------------------- /lib/unhollowed/Il2CppSystem.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/Il2CppSystem.Core.dll -------------------------------------------------------------------------------- /lib/unhollowed/Il2Cppmscorlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/Il2Cppmscorlib.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.AssetBundleModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.AssetBundleModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.AudioModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.AudioModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.CoreModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.CoreModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.IMGUIModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.IMGUIModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.PhysicsModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.PhysicsModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.TextRenderingModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.TextRenderingModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.UI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.UI.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.UIModule.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.UIModule.dll -------------------------------------------------------------------------------- /lib/unhollowed/UnityEngine.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/limoka/UnityExplorer/66e7c64a6500765327339d4192dbf98d0c83046d/lib/unhollowed/UnityEngine.dll -------------------------------------------------------------------------------- /src/CSConsole/Lexers/CommentLexer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.CSConsole.Lexers 2 | { 3 | public class CommentLexer : Lexer 4 | { 5 | private enum CommentType 6 | { 7 | Line, 8 | Block 9 | } 10 | 11 | // forest green 12 | protected override Color HighlightColor => new(0.34f, 0.65f, 0.29f, 1.0f); 13 | 14 | public override bool TryMatchCurrent(LexerBuilder lexer) 15 | { 16 | if (lexer.Current == '/') 17 | { 18 | lexer.PeekNext(); 19 | if (lexer.Current == '/') 20 | { 21 | // line comment. read to end of line or file. 22 | do 23 | { 24 | lexer.Commit(); 25 | lexer.PeekNext(); 26 | } 27 | while (!lexer.EndOrNewLine); 28 | 29 | return true; 30 | } 31 | else if (lexer.Current == '*') 32 | { 33 | // block comment, read until end of file or closing '*/' 34 | lexer.PeekNext(); 35 | do 36 | { 37 | lexer.PeekNext(); 38 | lexer.Commit(); 39 | } 40 | while (!lexer.EndOfInput && !(lexer.Current == '/' && lexer.Previous == '*')); 41 | 42 | return true; 43 | } 44 | } 45 | 46 | return false; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/CSConsole/Lexers/KeywordLexer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace UnityExplorer.CSConsole.Lexers 4 | { 5 | public class KeywordLexer : Lexer 6 | { 7 | // system blue 8 | protected override Color HighlightColor => new(0.33f, 0.61f, 0.83f, 1.0f); 9 | 10 | public static readonly HashSet keywords = new() 11 | { 12 | // reserved keywords 13 | "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", 14 | "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", 15 | "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", 16 | "long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected", "public", 17 | "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", 18 | "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", 19 | "volatile", "while", 20 | // contextual keywords 21 | "add", "and", "alias", "ascending", "async", "await", "by", "descending", "dynamic", "equals", "from", "get", 22 | "global", "group", "init", "into", "join", "let", "managed", "nameof", "not", "notnull", "on", 23 | "or", "orderby", "partial", "record", "remove", "select", "set", "unmanaged", "value", "var", "when", "where", 24 | "where", "with", "yield", "nint", "nuint" 25 | }; 26 | 27 | public override bool TryMatchCurrent(LexerBuilder lexer) 28 | { 29 | char prev = lexer.Previous; 30 | char first = lexer.Current; 31 | 32 | // check for keywords 33 | if (lexer.IsDelimiter(prev, true) && char.IsLetter(first)) 34 | { 35 | // can be a keyword... 36 | 37 | StringBuilder sb = new(); 38 | sb.Append(lexer.Current); 39 | while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext())) 40 | sb.Append(lexer.Current); 41 | 42 | // next must be whitespace or delimiter 43 | if (!lexer.EndOfInput && !(char.IsWhiteSpace(lexer.Current) || lexer.IsDelimiter(lexer.Current))) 44 | return false; 45 | 46 | if (keywords.Contains(sb.ToString())) 47 | { 48 | if (!lexer.EndOfInput) 49 | lexer.RollbackBy(1); 50 | lexer.Commit(); 51 | return true; 52 | } 53 | 54 | return false; 55 | 56 | } 57 | else 58 | return false; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/CSConsole/Lexers/Lexer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.CSConsole.Lexers 2 | { 3 | public abstract class Lexer 4 | { 5 | public virtual IEnumerable Delimiters => Enumerable.Empty(); 6 | 7 | protected abstract Color HighlightColor { get; } 8 | 9 | public string ColorTag => colorTag ?? (colorTag = ""); 10 | private string colorTag; 11 | 12 | public abstract bool TryMatchCurrent(LexerBuilder lexer); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/CSConsole/Lexers/NumberLexer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.CSConsole.Lexers 2 | { 3 | public class NumberLexer : Lexer 4 | { 5 | // Maroon 6 | protected override Color HighlightColor => new(0.58f, 0.33f, 0.33f, 1.0f); 7 | 8 | private bool IsNumeric(char c) => char.IsNumber(c) || c == '.'; 9 | 10 | public override bool TryMatchCurrent(LexerBuilder lexer) 11 | { 12 | // previous character must be whitespace or delimiter 13 | if (!lexer.IsDelimiter(lexer.Previous, true)) 14 | return false; 15 | 16 | if (!IsNumeric(lexer.Current)) 17 | return false; 18 | 19 | while (!lexer.EndOfInput) 20 | { 21 | lexer.Commit(); 22 | if (!IsNumeric(lexer.PeekNext())) 23 | break; 24 | } 25 | 26 | return true; 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/CSConsole/Lexers/StringLexer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.CSConsole.Lexers 2 | { 3 | public class StringLexer : Lexer 4 | { 5 | public override IEnumerable Delimiters => new[] { '"', '\'', }; 6 | 7 | // orange 8 | protected override Color HighlightColor => new(0.79f, 0.52f, 0.32f, 1.0f); 9 | 10 | public override bool TryMatchCurrent(LexerBuilder lexer) 11 | { 12 | if (lexer.Current == '"') 13 | { 14 | if (lexer.Previous == '@') 15 | { 16 | // verbatim string, continue until un-escaped quote. 17 | while (!lexer.EndOfInput) 18 | { 19 | lexer.Commit(); 20 | if (lexer.PeekNext() == '"') 21 | { 22 | lexer.Commit(); 23 | // possibly the end, check for escaped quotes. 24 | // commit the character and flip the escape bool for each quote. 25 | bool escaped = false; 26 | while (lexer.PeekNext() == '"') 27 | { 28 | lexer.Commit(); 29 | escaped = !escaped; 30 | } 31 | // if the last quote wasnt escaped, that was the end of the string. 32 | if (!escaped) 33 | break; 34 | } 35 | } 36 | } 37 | else 38 | { 39 | // normal string 40 | // continue until a quote which is not escaped, or end of input 41 | 42 | while (!lexer.EndOfInput) 43 | { 44 | lexer.Commit(); 45 | lexer.PeekNext(); 46 | if ((lexer.Current == '"') && lexer.Previous != '\\') 47 | { 48 | lexer.Commit(); 49 | break; 50 | } 51 | } 52 | } 53 | 54 | return true; 55 | } 56 | else if (lexer.Current == '\'') 57 | { 58 | // char 59 | 60 | while (!lexer.EndOfInput) 61 | { 62 | lexer.Commit(); 63 | lexer.PeekNext(); 64 | if ((lexer.Current == '\'') && lexer.Previous != '\\') 65 | { 66 | lexer.Commit(); 67 | break; 68 | } 69 | } 70 | 71 | return true; 72 | } 73 | else 74 | return false; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/CSConsole/Lexers/SymbolLexer.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.CSConsole.Lexers 2 | { 3 | public class SymbolLexer : Lexer 4 | { 5 | // silver 6 | protected override Color HighlightColor => new(0.6f, 0.6f, 0.6f); 7 | 8 | // all symbols are delimiters 9 | public override IEnumerable Delimiters => symbols.Where(it => it != '.'); // '.' is not a delimiter, only a separator. 10 | 11 | public static bool IsSymbol(char c) => symbols.Contains(c); 12 | 13 | public static readonly HashSet symbols = new() 14 | { 15 | '[', '{', '(', // open 16 | ']', '}', ')', // close 17 | '.', ',', ';', ':', '?', '@', // special 18 | 19 | // operators 20 | '+', '-', '*', '/', '%', '&', '|', '^', '~', '=', '<', '>', '!', 21 | }; 22 | 23 | public override bool TryMatchCurrent(LexerBuilder lexer) 24 | { 25 | // previous character must be delimiter, whitespace, or alphanumeric. 26 | if (!lexer.IsDelimiter(lexer.Previous, true, true)) 27 | return false; 28 | 29 | if (IsSymbol(lexer.Current)) 30 | { 31 | lexer.Commit(); 32 | return true; 33 | } 34 | 35 | return false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CSConsole/ScriptEvaluator.cs: -------------------------------------------------------------------------------- 1 | using Mono.CSharp; 2 | using UnityExplorer.Config; 3 | 4 | // Thanks to ManlyMarco for this 5 | 6 | namespace UnityExplorer.CSConsole 7 | { 8 | public class ScriptEvaluator : Evaluator, IDisposable 9 | { 10 | internal TextWriter _textWriter; 11 | internal static StreamReportPrinter _reportPrinter; 12 | 13 | private static readonly HashSet StdLib = new(StringComparer.InvariantCultureIgnoreCase) 14 | { 15 | "mscorlib", 16 | "System.Core", 17 | "System", 18 | "System.Xml" 19 | }; 20 | 21 | public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw)) 22 | { 23 | _textWriter = tw; 24 | 25 | ImportAppdomainAssemblies(); 26 | AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; 27 | } 28 | 29 | public void Dispose() 30 | { 31 | AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad; 32 | _textWriter.Dispose(); 33 | } 34 | 35 | private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) 36 | { 37 | string name = args.LoadedAssembly.GetName().Name; 38 | 39 | if (StdLib.Contains(name)) 40 | return; 41 | 42 | Reference(args.LoadedAssembly); 43 | } 44 | 45 | private void Reference(Assembly asm) 46 | { 47 | string name = asm.GetName().Name; 48 | 49 | if (name == "completions") // ignore assemblies generated by mcs' autocomplete. 50 | return; 51 | 52 | foreach (string blacklisted in ConfigManager.CSConsole_Assembly_Blacklist.Value.Split(';')) 53 | { 54 | string bl = blacklisted; 55 | if (bl.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) 56 | bl = blacklisted.Substring(0, bl.Length - 4); 57 | if (string.Equals(bl, name, StringComparison.OrdinalIgnoreCase)) 58 | return; 59 | } 60 | 61 | ReferenceAssembly(asm); 62 | } 63 | 64 | private static CompilerContext BuildContext(TextWriter tw) 65 | { 66 | _reportPrinter = new StreamReportPrinter(tw); 67 | 68 | CompilerSettings settings = new() 69 | { 70 | Version = LanguageVersion.Experimental, 71 | GenerateDebugInfo = false, 72 | StdLib = true, 73 | Target = Target.Library, 74 | WarningLevel = 0, 75 | EnhancedWarnings = false 76 | }; 77 | 78 | return new CompilerContext(settings, _reportPrinter); 79 | } 80 | 81 | private void ImportAppdomainAssemblies() 82 | { 83 | foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 84 | { 85 | string name = assembly.GetName().Name; 86 | if (StdLib.Contains(name)) 87 | continue; 88 | 89 | try 90 | { 91 | Reference(assembly); 92 | } 93 | catch // (Exception ex) 94 | { 95 | //ExplorerCore.LogWarning($"Excepting referencing '{name}': {ex.GetType()}.{ex.Message}"); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/CSConsole/ScriptInteraction.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using Mono.CSharp; 3 | using System.Collections; 4 | using System.Text; 5 | using UnityExplorer.UI.Panels; 6 | 7 | namespace UnityExplorer.CSConsole 8 | { 9 | public class ScriptInteraction : InteractiveBase 10 | { 11 | public static object CurrentTarget 12 | => InspectorManager.ActiveInspector?.Target; 13 | 14 | public static object[] AllTargets 15 | => InspectorManager.Inspectors.Select(it => it.Target).ToArray(); 16 | 17 | public static void Log(object message) 18 | => ExplorerCore.Log(message); 19 | 20 | public static void Inspect(object obj) 21 | => InspectorManager.Inspect(obj); 22 | 23 | public static void Inspect(Type type) 24 | => InspectorManager.Inspect(type); 25 | 26 | public static Coroutine Start(IEnumerator ienumerator) 27 | => RuntimeHelper.StartCoroutine(ienumerator); 28 | 29 | public static void Stop(Coroutine coro) 30 | => RuntimeHelper.StopCoroutine(coro); 31 | 32 | public static void Copy(object obj) 33 | => ClipboardPanel.Copy(obj); 34 | 35 | public static object Paste() 36 | => ClipboardPanel.Current; 37 | 38 | public static void GetUsing() 39 | => Log(Evaluator.GetUsing()); 40 | 41 | public static void GetVars() 42 | { 43 | string vars = Evaluator.GetVars()?.Trim(); 44 | if (string.IsNullOrEmpty(vars)) 45 | ExplorerCore.LogWarning("No variables seem to be defined!"); 46 | else 47 | Log(vars); 48 | } 49 | 50 | public static void GetClasses() 51 | { 52 | if (AccessTools.Field(typeof(Evaluator), "source_file") 53 | .GetValue(Evaluator) is CompilationSourceFile sourceFile 54 | && sourceFile.Containers.Any()) 55 | { 56 | StringBuilder sb = new(); 57 | sb.Append($"There are {sourceFile.Containers.Count} defined classes:"); 58 | foreach (TypeDefinition type in sourceFile.Containers.Where(it => it is TypeDefinition)) 59 | { 60 | sb.Append($"\n\n{type.MemberName.Name}:"); 61 | foreach (MemberCore member in type.Members) 62 | sb.Append($"\n\t- {member.AttributeTargets}: \"{member.MemberName.Name}\" ({member.ModFlags})"); 63 | } 64 | Log(sb.ToString()); 65 | } 66 | else 67 | ExplorerCore.LogWarning("No classes seem to be defined."); 68 | 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/CacheObject/CacheConfigEntry.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject.Views; 2 | using UnityExplorer.Config; 3 | 4 | namespace UnityExplorer.CacheObject 5 | { 6 | public class CacheConfigEntry : CacheObjectBase 7 | { 8 | public CacheConfigEntry(IConfigElement configElement) 9 | { 10 | this.RefConfigElement = configElement; 11 | this.FallbackType = configElement.ElementType; 12 | 13 | this.NameLabelText = $"{configElement.Name}" + 14 | $"\r\n{configElement.Description}"; 15 | this.NameLabelTextRaw = string.Empty; 16 | 17 | configElement.OnValueChangedNotify += UpdateValueFromSource; 18 | } 19 | 20 | public IConfigElement RefConfigElement; 21 | 22 | public override bool ShouldAutoEvaluate => true; 23 | public override bool HasArguments => false; 24 | public override bool CanWrite => true; 25 | public override bool RefreshFromSource => false; 26 | 27 | 28 | public void UpdateValueFromSource() 29 | { 30 | //if (RefConfigElement.BoxedValue.Equals(this.Value)) 31 | // return; 32 | 33 | SetValueFromSource(RefConfigElement.BoxedValue); 34 | 35 | if (this.CellView != null) 36 | this.SetDataToCell(CellView); 37 | } 38 | 39 | public override void TrySetUserValue(object value) 40 | { 41 | this.Value = value; 42 | RefConfigElement.BoxedValue = value; 43 | } 44 | 45 | public override object TryEvaluate() 46 | { 47 | return null; 48 | } 49 | 50 | protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/CacheObject/CacheConstructor.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | 3 | namespace UnityExplorer.CacheObject 4 | { 5 | public class CacheConstructor : CacheMember 6 | { 7 | public ConstructorInfo CtorInfo { get; } 8 | readonly Type typeForStructConstructor; 9 | 10 | public override Type DeclaringType => typeForStructConstructor ?? CtorInfo.DeclaringType; 11 | public override bool IsStatic => true; 12 | public override bool ShouldAutoEvaluate => false; 13 | public override bool CanWrite => false; 14 | public override bool RefreshFromSource => false; 15 | 16 | 17 | public CacheConstructor(ConstructorInfo ci) 18 | { 19 | this.CtorInfo = ci; 20 | } 21 | 22 | public CacheConstructor(Type typeForStructConstructor) 23 | { 24 | this.typeForStructConstructor = typeForStructConstructor; 25 | } 26 | 27 | public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member) 28 | { 29 | Type ctorReturnType; 30 | // if is parameterless struct ctor 31 | if (typeForStructConstructor != null) 32 | { 33 | ctorReturnType = typeForStructConstructor; 34 | this.Owner = inspector; 35 | 36 | // eg. Vector3.Vector3() 37 | this.NameLabelText = SignatureHighlighter.Parse(typeForStructConstructor, false); 38 | NameLabelText += $".{NameLabelText}()"; 39 | 40 | this.NameForFiltering = SignatureHighlighter.RemoveHighlighting(NameLabelText); 41 | this.NameLabelTextRaw = NameForFiltering; 42 | return; 43 | } 44 | else 45 | { 46 | base.SetInspectorOwner(inspector, member); 47 | 48 | Arguments = CtorInfo.GetParameters(); 49 | ctorReturnType = CtorInfo.DeclaringType; 50 | } 51 | 52 | if (ctorReturnType.IsGenericTypeDefinition) 53 | GenericArguments = ctorReturnType.GetGenericArguments(); 54 | } 55 | 56 | public override object TryEvaluate() 57 | { 58 | try 59 | { 60 | Type returnType = DeclaringType; 61 | 62 | if (returnType.IsGenericTypeDefinition) 63 | returnType = DeclaringType.MakeGenericType(Evaluator.TryParseGenericArguments()); 64 | 65 | object ret; 66 | if (HasArguments) 67 | ret = Activator.CreateInstance(returnType, Evaluator.TryParseArguments()); 68 | else 69 | ret = Activator.CreateInstance(returnType, ArgumentUtility.EmptyArgs); 70 | 71 | LastException = null; 72 | return ret; 73 | } 74 | catch (Exception ex) 75 | { 76 | LastException = ex; 77 | return null; 78 | } 79 | } 80 | 81 | protected override void TrySetValue(object value) => throw new NotImplementedException("You can't set a constructor"); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/CacheObject/CacheField.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | 3 | namespace UnityExplorer.CacheObject 4 | { 5 | public class CacheField : CacheMember 6 | { 7 | public FieldInfo FieldInfo { get; internal set; } 8 | public override Type DeclaringType => FieldInfo.DeclaringType; 9 | public override bool IsStatic => FieldInfo.IsStatic; 10 | public override bool CanWrite => m_canWrite ?? (bool)(m_canWrite = !(FieldInfo.IsLiteral && !FieldInfo.IsInitOnly)); 11 | private bool? m_canWrite; 12 | 13 | public override bool ShouldAutoEvaluate => true; 14 | public override bool RefreshFromSource => FieldInfo.FieldType.IsValueType; 15 | 16 | 17 | public CacheField(FieldInfo fi) 18 | { 19 | this.FieldInfo = fi; 20 | } 21 | 22 | public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member) 23 | { 24 | base.SetInspectorOwner(inspector, member); 25 | } 26 | 27 | public override object TryEvaluate() 28 | { 29 | try 30 | { 31 | object ret = FieldInfo.GetValue(DeclaringInstance); 32 | LastException = null; 33 | return ret; 34 | } 35 | catch (Exception ex) 36 | { 37 | LastException = ex; 38 | return null; 39 | } 40 | } 41 | 42 | protected override void TrySetValue(object value) 43 | { 44 | try 45 | { 46 | FieldInfo.SetValue(DeclaringInstance, value); 47 | } 48 | catch (Exception ex) 49 | { 50 | ExplorerCore.LogWarning(ex); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/CacheObject/CacheKeyValuePair.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject.IValues; 2 | using UnityExplorer.CacheObject.Views; 3 | 4 | namespace UnityExplorer.CacheObject 5 | { 6 | public class CacheKeyValuePair : CacheObjectBase 7 | { 8 | //public InteractiveList CurrentList { get; set; } 9 | 10 | public int DictIndex; 11 | public object DictKey; 12 | public object DisplayedKey; 13 | 14 | public bool KeyInputWanted; 15 | public bool InspectWanted; 16 | public string KeyLabelText; 17 | public string KeyInputText; 18 | public string KeyInputTypeText; 19 | 20 | public float DesiredKeyWidth; 21 | public float DesiredValueWidth; 22 | 23 | public override bool ShouldAutoEvaluate => true; 24 | public override bool HasArguments => false; 25 | public override bool CanWrite => Owner.CanWrite; 26 | public override bool RefreshFromSource => false; 27 | 28 | 29 | public void SetDictOwner(InteractiveDictionary dict, int index) 30 | { 31 | this.Owner = dict; 32 | this.DictIndex = index; 33 | } 34 | 35 | public void SetKey(object key) 36 | { 37 | this.DictKey = key; 38 | this.DisplayedKey = key.TryCast(); 39 | 40 | Type type = DisplayedKey.GetType(); 41 | if (ParseUtility.CanParse(type)) 42 | { 43 | KeyInputWanted = true; 44 | KeyInputText = ParseUtility.ToStringForInput(DisplayedKey, type); 45 | KeyInputTypeText = SignatureHighlighter.Parse(type, false); 46 | } 47 | else 48 | { 49 | KeyInputWanted = false; 50 | InspectWanted = type != typeof(bool) && !type.IsEnum; 51 | KeyLabelText = ToStringUtility.ToStringWithType(DisplayedKey, type, true); 52 | } 53 | } 54 | 55 | public override void SetDataToCell(CacheObjectCell cell) 56 | { 57 | base.SetDataToCell(cell); 58 | 59 | CacheKeyValuePairCell kvpCell = cell as CacheKeyValuePairCell; 60 | 61 | kvpCell.NameLabel.text = $"{DictIndex}:"; 62 | kvpCell.HiddenNameLabel.Text = ""; 63 | kvpCell.Image.color = DictIndex % 2 == 0 ? CacheListEntryCell.EvenColor : CacheListEntryCell.OddColor; 64 | 65 | if (KeyInputWanted) 66 | { 67 | kvpCell.KeyInputField.UIRoot.SetActive(true); 68 | kvpCell.KeyInputTypeLabel.gameObject.SetActive(true); 69 | kvpCell.KeyLabel.gameObject.SetActive(false); 70 | kvpCell.KeyInspectButton.Component.gameObject.SetActive(false); 71 | 72 | kvpCell.KeyInputField.Text = KeyInputText; 73 | kvpCell.KeyInputTypeLabel.text = KeyInputTypeText; 74 | } 75 | else 76 | { 77 | kvpCell.KeyInputField.UIRoot.SetActive(false); 78 | kvpCell.KeyInputTypeLabel.gameObject.SetActive(false); 79 | kvpCell.KeyLabel.gameObject.SetActive(true); 80 | kvpCell.KeyInspectButton.Component.gameObject.SetActive(InspectWanted); 81 | 82 | kvpCell.KeyLabel.text = KeyLabelText; 83 | } 84 | } 85 | 86 | public override void TrySetUserValue(object value) 87 | { 88 | (Owner as InteractiveDictionary).TrySetValueToKey(DictKey, value, DictIndex); 89 | } 90 | 91 | public override object TryEvaluate() 92 | { 93 | return null; 94 | } 95 | 96 | 97 | protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/CacheObject/CacheListEntry.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject.IValues; 2 | using UnityExplorer.CacheObject.Views; 3 | 4 | namespace UnityExplorer.CacheObject 5 | { 6 | public class CacheListEntry : CacheObjectBase 7 | { 8 | public int ListIndex; 9 | 10 | public override bool ShouldAutoEvaluate => true; 11 | public override bool HasArguments => false; 12 | public override bool CanWrite => Owner?.CanWrite ?? false; 13 | public override bool RefreshFromSource => false; 14 | 15 | 16 | public void SetListOwner(InteractiveList list, int listIndex) 17 | { 18 | this.Owner = list; 19 | this.ListIndex = listIndex; 20 | } 21 | 22 | public override void SetDataToCell(CacheObjectCell cell) 23 | { 24 | base.SetDataToCell(cell); 25 | 26 | CacheListEntryCell listCell = cell as CacheListEntryCell; 27 | 28 | listCell.NameLabel.text = $"{ListIndex}:"; 29 | listCell.HiddenNameLabel.Text = ""; 30 | listCell.Image.color = ListIndex % 2 == 0 ? CacheListEntryCell.EvenColor : CacheListEntryCell.OddColor; 31 | } 32 | 33 | public override void TrySetUserValue(object value) 34 | { 35 | (Owner as InteractiveList).TrySetValueToIndex(value, this.ListIndex); 36 | } 37 | 38 | public override object TryEvaluate() 39 | { 40 | return null; 41 | } 42 | 43 | protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/CacheObject/CacheMethod.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | 3 | namespace UnityExplorer.CacheObject 4 | { 5 | public class CacheMethod : CacheMember 6 | { 7 | public MethodInfo MethodInfo { get; } 8 | public override Type DeclaringType => MethodInfo.DeclaringType; 9 | public override bool CanWrite => false; 10 | public override bool IsStatic => MethodInfo.IsStatic; 11 | 12 | public override bool ShouldAutoEvaluate => false; 13 | public override bool RefreshFromSource => false; 14 | 15 | 16 | public CacheMethod(MethodInfo mi) 17 | { 18 | this.MethodInfo = mi; 19 | } 20 | 21 | public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member) 22 | { 23 | base.SetInspectorOwner(inspector, member); 24 | 25 | Arguments = MethodInfo.GetParameters(); 26 | if (MethodInfo.IsGenericMethod) 27 | GenericArguments = MethodInfo.GetGenericArguments(); 28 | } 29 | 30 | public override object TryEvaluate() 31 | { 32 | try 33 | { 34 | MethodInfo methodInfo = MethodInfo; 35 | if (methodInfo.IsGenericMethod) 36 | methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments()); 37 | 38 | object ret; 39 | if (HasArguments) 40 | ret = methodInfo.Invoke(DeclaringInstance, Evaluator.TryParseArguments()); 41 | else 42 | ret = methodInfo.Invoke(DeclaringInstance, ArgumentUtility.EmptyArgs); 43 | LastException = null; 44 | return ret; 45 | } 46 | catch (Exception ex) 47 | { 48 | LastException = ex; 49 | return null; 50 | } 51 | } 52 | 53 | protected override void TrySetValue(object value) => throw new NotImplementedException("You can't set a method"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/CacheObject/CacheProperty.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | 3 | namespace UnityExplorer.CacheObject 4 | { 5 | public class CacheProperty : CacheMember 6 | { 7 | public PropertyInfo PropertyInfo { get; internal set; } 8 | public override Type DeclaringType => PropertyInfo.DeclaringType; 9 | public override bool CanWrite => PropertyInfo.CanWrite; 10 | public override bool IsStatic => m_isStatic ?? (bool)(m_isStatic = PropertyInfo.GetAccessors(true)[0].IsStatic); 11 | private bool? m_isStatic; 12 | 13 | public override bool RefreshFromSource => PropertyInfo.PropertyType.IsValueType; 14 | 15 | public override bool ShouldAutoEvaluate => !HasArguments; 16 | 17 | public CacheProperty(PropertyInfo pi) 18 | { 19 | this.PropertyInfo = pi; 20 | } 21 | 22 | public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member) 23 | { 24 | base.SetInspectorOwner(inspector, member); 25 | 26 | Arguments = PropertyInfo.GetIndexParameters(); 27 | } 28 | 29 | public override object TryEvaluate() 30 | { 31 | try 32 | { 33 | object ret; 34 | if (HasArguments) 35 | ret = PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments()); 36 | else 37 | ret = PropertyInfo.GetValue(DeclaringInstance, null); 38 | LastException = null; 39 | return ret; 40 | } 41 | catch (Exception ex) 42 | { 43 | LastException = ex; 44 | return null; 45 | } 46 | } 47 | 48 | protected override void TrySetValue(object value) 49 | { 50 | if (!CanWrite) 51 | return; 52 | 53 | try 54 | { 55 | bool _static = PropertyInfo.GetAccessors(true)[0].IsStatic; 56 | 57 | if (HasArguments) 58 | PropertyInfo.SetValue(DeclaringInstance, value, Evaluator.TryParseArguments()); 59 | else 60 | PropertyInfo.SetValue(DeclaringInstance, value, null); 61 | } 62 | catch (Exception ex) 63 | { 64 | ExplorerCore.LogWarning(ex); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/CacheObject/ICacheObjectController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityExplorer.CacheObject.Views; 3 | 4 | namespace UnityExplorer.CacheObject 5 | { 6 | public interface ICacheObjectController 7 | { 8 | CacheObjectBase ParentCacheObject { get; } 9 | 10 | object Target { get; } 11 | Type TargetType { get; } 12 | 13 | bool CanWrite { get; } 14 | } 15 | 16 | public static class CacheObjectControllerHelper 17 | { 18 | // Helper so that this doesn't need to be copy+pasted between each implementation of the interface 19 | 20 | public static void SetCell(CacheObjectCell cell, int index, IList cachedEntries, Action onDataSetToCell) 21 | { 22 | if (index < 0 || index >= cachedEntries.Count) 23 | { 24 | if (cell.Occupant != null) 25 | cell.Occupant.UnlinkFromView(); 26 | 27 | cell.Disable(); 28 | return; 29 | } 30 | 31 | CacheObjectBase entry = (CacheObjectBase)cachedEntries[index]; 32 | 33 | if (entry.CellView != null && entry.CellView != cell) 34 | entry.UnlinkFromView(); 35 | 36 | if (cell.Occupant != null && cell.Occupant != entry) 37 | cell.Occupant.UnlinkFromView(); 38 | 39 | if (entry.CellView != cell) 40 | entry.SetView(cell); 41 | 42 | entry.SetDataToCell(cell); 43 | 44 | onDataSetToCell?.Invoke(cell); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/CacheObject/IValues/InteractiveValue.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI.ObjectPool; 2 | 3 | namespace UnityExplorer.CacheObject.IValues 4 | { 5 | public abstract class InteractiveValue : IPooledObject 6 | { 7 | public static Type GetIValueTypeForState(ValueState state) 8 | { 9 | return state switch 10 | { 11 | ValueState.Exception or ValueState.String => typeof(InteractiveString), 12 | ValueState.Enum => typeof(InteractiveEnum), 13 | ValueState.Collection => typeof(InteractiveList), 14 | ValueState.Dictionary => typeof(InteractiveDictionary), 15 | ValueState.ValueStruct => typeof(InteractiveValueStruct), 16 | ValueState.Color => typeof(InteractiveColor), 17 | _ => null, 18 | }; 19 | } 20 | 21 | public GameObject UIRoot { get; set; } 22 | public float DefaultHeight => -1f; 23 | 24 | public virtual bool CanWrite => this.CurrentOwner.CanWrite; 25 | 26 | public CacheObjectBase CurrentOwner => owner; 27 | private CacheObjectBase owner; 28 | 29 | public bool PendingValueWanted; 30 | 31 | public virtual void OnBorrowed(CacheObjectBase owner) 32 | { 33 | if (this.owner != null) 34 | { 35 | ExplorerCore.LogWarning("Setting an IValue's owner but there is already one set. Maybe it wasn't cleaned up?"); 36 | ReleaseFromOwner(); 37 | } 38 | 39 | this.owner = owner; 40 | } 41 | 42 | public virtual void ReleaseFromOwner() 43 | { 44 | if (this.owner == null) 45 | return; 46 | 47 | this.owner = null; 48 | } 49 | 50 | public abstract void SetValue(object value); 51 | 52 | public virtual void SetLayout() { } 53 | 54 | public abstract GameObject CreateContent(GameObject parent); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/CacheObject/Views/CacheConfigCell.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | 3 | namespace UnityExplorer.CacheObject.Views 4 | { 5 | public class ConfigEntryCell : CacheObjectCell 6 | { 7 | public override GameObject CreateContent(GameObject parent) 8 | { 9 | // Main layout 10 | 11 | UIRoot = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30)); 12 | Rect = UIRoot.GetComponent(); 13 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 4, 4, 4, 4, 4, childAlignment: TextAnchor.UpperLeft); 14 | UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600); 15 | UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 16 | 17 | // Left label 18 | 19 | NameLabel = UIFactory.CreateLabel(UIRoot, "NameLabel", "", TextAnchor.MiddleLeft); 20 | NameLabel.horizontalOverflow = HorizontalWrapMode.Wrap; 21 | UIFactory.SetLayoutElement(NameLabel.gameObject, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 300); 22 | NameLayout = NameLabel.GetComponent(); 23 | 24 | // horizontal group 25 | 26 | GameObject horiGroup = UIFactory.CreateUIObject("RightHoriGroup", UIRoot); 27 | UIFactory.SetLayoutGroup(horiGroup, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft); 28 | UIFactory.SetLayoutElement(horiGroup, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800); 29 | 30 | SubContentButton = UIFactory.CreateButton(horiGroup, "SubContentButton", "▲", subInactiveColor); 31 | UIFactory.SetLayoutElement(SubContentButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); 32 | SubContentButton.OnClick += SubContentClicked; 33 | 34 | // Type label 35 | 36 | TypeLabel = UIFactory.CreateLabel(horiGroup, "TypeLabel", "", TextAnchor.MiddleLeft); 37 | TypeLabel.horizontalOverflow = HorizontalWrapMode.Wrap; 38 | UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 60, flexibleWidth: 0); 39 | 40 | // Bool and number value interaction 41 | 42 | GameObject toggleObj = UIFactory.CreateToggle(horiGroup, "Toggle", out Toggle, out ToggleText); 43 | UIFactory.SetLayoutElement(toggleObj, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); 44 | ToggleText.color = SignatureHighlighter.KeywordBlue; 45 | Toggle.onValueChanged.AddListener(ToggleClicked); 46 | 47 | InputField = UIFactory.CreateInputField(horiGroup, "InputField", "..."); 48 | UIFactory.SetLayoutElement(InputField.UIRoot, minWidth: 150, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); 49 | 50 | // Apply 51 | 52 | ApplyButton = UIFactory.CreateButton(horiGroup, "ApplyButton", "Apply", new Color(0.15f, 0.19f, 0.15f)); 53 | UIFactory.SetLayoutElement(ApplyButton.Component.gameObject, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); 54 | ApplyButton.OnClick += ApplyClicked; 55 | 56 | // Main value label 57 | 58 | ValueLabel = UIFactory.CreateLabel(horiGroup, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft); 59 | ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap; 60 | UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999); 61 | 62 | // Subcontent 63 | 64 | SubContentHolder = UIFactory.CreateUIObject("SubContent", UIRoot); 65 | UIFactory.SetLayoutElement(SubContentHolder.gameObject, minHeight: 30, flexibleHeight: 600, minWidth: 100, flexibleWidth: 9999); 66 | UIFactory.SetLayoutGroup(SubContentHolder, true, true, true, true, 2, childAlignment: TextAnchor.UpperLeft); 67 | //SubContentHolder.AddComponent().verticalFit = ContentSizeFitter.FitMode.MinSize; 68 | SubContentHolder.SetActive(false); 69 | 70 | // Bottom separator 71 | GameObject separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot); 72 | UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999); 73 | separator.AddComponent().color = Color.black; 74 | 75 | return UIRoot; 76 | } 77 | 78 | protected override void ConstructEvaluateHolder(GameObject parent) { } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/CacheObject/Views/CacheKeyValuePairCell.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject.IValues; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Models; 4 | 5 | namespace UnityExplorer.CacheObject.Views 6 | { 7 | public class CacheKeyValuePairCell : CacheObjectCell 8 | { 9 | public Image Image { get; private set; } 10 | public InteractiveDictionary DictOwner => Occupant.Owner as InteractiveDictionary; 11 | 12 | public LayoutElement KeyGroupLayout; 13 | public Text KeyLabel; 14 | public ButtonRef KeyInspectButton; 15 | public InputFieldRef KeyInputField; 16 | public Text KeyInputTypeLabel; 17 | 18 | public static Color EvenColor = new(0.07f, 0.07f, 0.07f); 19 | public static Color OddColor = new(0.063f, 0.063f, 0.063f); 20 | 21 | public int AdjustedWidth => (int)Rect.rect.width - 70; 22 | 23 | //public int HalfWidth => (int)(0.5f * Rect.rect.width) - 75; 24 | //public int AdjustedKeyWidth => HalfWidth - 50; 25 | //public int AdjustedRightWidth => HalfWidth; 26 | 27 | private void KeyInspectClicked() 28 | { 29 | InspectorManager.Inspect((Occupant as CacheKeyValuePair).DictKey, this.Occupant); 30 | } 31 | 32 | public override GameObject CreateContent(GameObject parent) 33 | { 34 | GameObject root = base.CreateContent(parent); 35 | 36 | Image = root.AddComponent(); 37 | 38 | this.NameLayout.minWidth = 70; 39 | this.NameLayout.flexibleWidth = 0; 40 | this.NameLayout.minHeight = 30; 41 | this.NameLayout.flexibleHeight = 0; 42 | this.NameLabel.alignment = TextAnchor.MiddleRight; 43 | 44 | this.RightGroupLayout.minWidth = AdjustedWidth * 0.55f; 45 | 46 | // Key area 47 | GameObject keyGroup = UIFactory.CreateUIObject("KeyHolder", root.transform.Find("HoriGroup").gameObject); 48 | UIFactory.SetLayoutGroup(keyGroup, false, false, true, true, 2, 0, 0, 4, 4, childAlignment: TextAnchor.MiddleLeft); 49 | KeyGroupLayout = UIFactory.SetLayoutElement(keyGroup, minHeight: 30, minWidth: (int)(AdjustedWidth * 0.44f), flexibleWidth: 0); 50 | 51 | // set to be after the NameLabel (our index label), and before the main horizontal group. 52 | keyGroup.transform.SetSiblingIndex(1); 53 | 54 | // key Inspect 55 | 56 | KeyInspectButton = UIFactory.CreateButton(keyGroup, "KeyInspectButton", "Inspect", new Color(0.15f, 0.15f, 0.15f)); 57 | UIFactory.SetLayoutElement(KeyInspectButton.Component.gameObject, minWidth: 60, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); 58 | KeyInspectButton.OnClick += KeyInspectClicked; 59 | 60 | // label 61 | 62 | KeyLabel = UIFactory.CreateLabel(keyGroup, "KeyLabel", "empty", TextAnchor.MiddleLeft); 63 | UIFactory.SetLayoutElement(KeyLabel.gameObject, minWidth: 50, flexibleWidth: 999, minHeight: 25); 64 | 65 | // Type label for input field 66 | 67 | KeyInputTypeLabel = UIFactory.CreateLabel(keyGroup, "InputTypeLabel", "null", TextAnchor.MiddleLeft); 68 | UIFactory.SetLayoutElement(KeyInputTypeLabel.gameObject, minWidth: 55, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); 69 | 70 | // input field 71 | 72 | KeyInputField = UIFactory.CreateInputField(keyGroup, "KeyInput", "empty"); 73 | UIFactory.SetLayoutElement(KeyInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 0, preferredWidth: 200); 74 | //KeyInputField.lineType = InputField.LineType.MultiLineNewline; 75 | KeyInputField.Component.readOnly = true; 76 | 77 | return root; 78 | } 79 | 80 | protected override void ConstructEvaluateHolder(GameObject parent) 81 | { 82 | // not used 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/CacheObject/Views/CacheListEntryCell.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject.IValues; 2 | 3 | namespace UnityExplorer.CacheObject.Views 4 | { 5 | public class CacheListEntryCell : CacheObjectCell 6 | { 7 | public Image Image { get; private set; } 8 | public InteractiveList ListOwner => Occupant.Owner as InteractiveList; 9 | 10 | public static Color EvenColor = new(0.12f, 0.12f, 0.12f); 11 | public static Color OddColor = new(0.1f, 0.1f, 0.1f); 12 | 13 | public override GameObject CreateContent(GameObject parent) 14 | { 15 | GameObject root = base.CreateContent(parent); 16 | 17 | Image = root.AddComponent(); 18 | 19 | this.NameLayout.minWidth = 40; 20 | this.NameLayout.flexibleWidth = 50; 21 | this.NameLayout.minHeight = 25; 22 | this.NameLayout.flexibleHeight = 0; 23 | this.NameLabel.alignment = TextAnchor.MiddleRight; 24 | 25 | return root; 26 | } 27 | 28 | protected override void ConstructEvaluateHolder(GameObject parent) 29 | { 30 | // not used 31 | } 32 | 33 | //protected override void ConstructUpdateToggle(GameObject parent) 34 | //{ 35 | // // not used 36 | //} 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CacheObject/Views/CacheMemberCell.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | 4 | namespace UnityExplorer.CacheObject.Views 5 | { 6 | public class CacheMemberCell : CacheObjectCell 7 | { 8 | public CacheMember MemberOccupant => Occupant as CacheMember; 9 | 10 | public GameObject EvaluateHolder; 11 | public ButtonRef EvaluateButton; 12 | 13 | protected virtual void EvaluateClicked() 14 | { 15 | this.MemberOccupant.OnEvaluateClicked(); 16 | } 17 | 18 | protected override void ConstructEvaluateHolder(GameObject parent) 19 | { 20 | // Evaluate vert group 21 | 22 | EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", parent); 23 | UIFactory.SetLayoutGroup(EvaluateHolder, false, false, true, true, 3); 24 | UIFactory.SetLayoutElement(EvaluateHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 775); 25 | 26 | EvaluateButton = UIFactory.CreateButton(EvaluateHolder, "EvaluateButton", "Evaluate", new Color(0.15f, 0.15f, 0.15f)); 27 | UIFactory.SetLayoutElement(EvaluateButton.Component.gameObject, minWidth: 100, minHeight: 25); 28 | EvaluateButton.OnClick += EvaluateClicked; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Config/ConfigElement.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Config 2 | { 3 | public class ConfigElement : IConfigElement 4 | { 5 | public string Name { get; } 6 | public string Description { get; } 7 | 8 | public bool IsInternal { get; } 9 | public Type ElementType => typeof(T); 10 | 11 | public Action OnValueChanged; 12 | public Action OnValueChangedNotify { get; set; } 13 | 14 | public object DefaultValue { get; } 15 | 16 | public ConfigHandler Handler => IsInternal 17 | ? ConfigManager.InternalHandler 18 | : ConfigManager.Handler; 19 | 20 | public T Value 21 | { 22 | get => m_value; 23 | set => SetValue(value); 24 | } 25 | private T m_value; 26 | 27 | object IConfigElement.BoxedValue 28 | { 29 | get => m_value; 30 | set => SetValue((T)value); 31 | } 32 | 33 | public ConfigElement(string name, string description, T defaultValue, bool isInternal = false) 34 | { 35 | Name = name; 36 | Description = description; 37 | 38 | m_value = defaultValue; 39 | DefaultValue = defaultValue; 40 | 41 | IsInternal = isInternal; 42 | 43 | ConfigManager.RegisterConfigElement(this); 44 | } 45 | 46 | private void SetValue(T value) 47 | { 48 | if ((m_value == null && value == null) || (m_value != null && m_value.Equals(value))) 49 | return; 50 | 51 | m_value = value; 52 | 53 | Handler.SetConfigValue(this, value); 54 | 55 | OnValueChanged?.Invoke(value); 56 | OnValueChangedNotify?.Invoke(); 57 | 58 | Handler.OnAnyConfigChanged(); 59 | } 60 | 61 | object IConfigElement.GetLoaderConfigValue() => GetLoaderConfigValue(); 62 | 63 | public T GetLoaderConfigValue() 64 | { 65 | return Handler.GetConfigValue(this); 66 | } 67 | 68 | public void RevertToDefaultValue() 69 | { 70 | Value = (T)DefaultValue; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Config/ConfigHandler.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Config 2 | { 3 | public abstract class ConfigHandler 4 | { 5 | public abstract void RegisterConfigElement(ConfigElement element); 6 | 7 | public abstract void SetConfigValue(ConfigElement element, T value); 8 | 9 | public abstract T GetConfigValue(ConfigElement element); 10 | 11 | public abstract void Init(); 12 | 13 | public abstract void LoadConfig(); 14 | 15 | public abstract void SaveConfig(); 16 | 17 | public virtual void OnAnyConfigChanged() { } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Config/IConfigElement.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Config 2 | { 3 | public interface IConfigElement 4 | { 5 | string Name { get; } 6 | string Description { get; } 7 | 8 | bool IsInternal { get; } 9 | Type ElementType { get; } 10 | 11 | object BoxedValue { get; set; } 12 | object DefaultValue { get; } 13 | 14 | object GetLoaderConfigValue(); 15 | 16 | void RevertToDefaultValue(); 17 | 18 | Action OnValueChangedNotify { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Config/InternalConfigHandler.cs: -------------------------------------------------------------------------------- 1 | using Tomlet; 2 | using Tomlet.Models; 3 | using UnityExplorer.UI; 4 | 5 | namespace UnityExplorer.Config 6 | { 7 | public class InternalConfigHandler : ConfigHandler 8 | { 9 | internal static string CONFIG_PATH; 10 | 11 | public override void Init() 12 | { 13 | CONFIG_PATH = Path.Combine(ExplorerCore.ExplorerFolder, "data.cfg"); 14 | } 15 | 16 | public override void LoadConfig() 17 | { 18 | if (!TryLoadConfig()) 19 | SaveConfig(); 20 | } 21 | 22 | public override void RegisterConfigElement(ConfigElement element) 23 | { 24 | // Not necessary 25 | } 26 | 27 | public override void SetConfigValue(ConfigElement element, T value) 28 | { 29 | // Not necessary 30 | } 31 | 32 | // Not necessary, just return the value. 33 | public override T GetConfigValue(ConfigElement element) => element.Value; 34 | 35 | // Always just auto-save. 36 | public override void OnAnyConfigChanged() => SaveConfig(); 37 | 38 | public bool TryLoadConfig() 39 | { 40 | try 41 | { 42 | if (!File.Exists(CONFIG_PATH)) 43 | return false; 44 | 45 | TomlDocument document = TomlParser.ParseFile(CONFIG_PATH); 46 | foreach (string key in document.Keys) 47 | { 48 | if (!Enum.IsDefined(typeof(UIManager.Panels), key)) 49 | continue; 50 | 51 | UIManager.Panels panelKey = (UIManager.Panels)Enum.Parse(typeof(UIManager.Panels), key); 52 | ConfigManager.GetPanelSaveData(panelKey).Value = document.GetString(key); 53 | } 54 | 55 | return true; 56 | } 57 | catch (Exception ex) 58 | { 59 | ExplorerCore.LogWarning("Error loading internal data: " + ex.ToString()); 60 | return false; 61 | } 62 | } 63 | 64 | public override void SaveConfig() 65 | { 66 | if (UIManager.Initializing) 67 | return; 68 | 69 | TomlDocument tomlDocument = TomlDocument.CreateEmpty(); 70 | foreach (KeyValuePair entry in ConfigManager.InternalConfigs) 71 | tomlDocument.Put(entry.Key, entry.Value.BoxedValue as string, false); 72 | 73 | File.WriteAllText(CONFIG_PATH, tomlDocument.SerializedValue); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/ExplorerBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.UI; 2 | #if CPP 3 | #if UNHOLLOWER 4 | using UnhollowerRuntimeLib; 5 | #else 6 | using Il2CppInterop.Runtime.Injection; 7 | #endif 8 | #endif 9 | 10 | namespace UnityExplorer 11 | { 12 | public class ExplorerBehaviour : MonoBehaviour 13 | { 14 | internal static ExplorerBehaviour Instance { get; private set; } 15 | 16 | #if CPP 17 | public ExplorerBehaviour(System.IntPtr ptr) : base(ptr) { } 18 | #endif 19 | 20 | internal static void Setup() 21 | { 22 | #if CPP 23 | ClassInjector.RegisterTypeInIl2Cpp(); 24 | #endif 25 | 26 | GameObject obj = new("ExplorerBehaviour"); 27 | DontDestroyOnLoad(obj); 28 | obj.hideFlags = HideFlags.HideAndDontSave; 29 | Instance = obj.AddComponent(); 30 | } 31 | 32 | internal void Update() 33 | { 34 | ExplorerCore.Update(); 35 | } 36 | 37 | // For editor, to clean up objects 38 | 39 | internal void OnDestroy() 40 | { 41 | OnApplicationQuit(); 42 | } 43 | 44 | internal bool quitting; 45 | 46 | internal void OnApplicationQuit() 47 | { 48 | if (quitting) return; 49 | quitting = true; 50 | 51 | TryDestroy(UIManager.UIRoot?.transform.root.gameObject); 52 | 53 | TryDestroy((typeof(Universe).Assembly.GetType("UniverseLib.UniversalBehaviour") 54 | .GetProperty("Instance", BindingFlags.Static | BindingFlags.NonPublic) 55 | .GetValue(null, null) 56 | as Component).gameObject); 57 | 58 | TryDestroy(this.gameObject); 59 | } 60 | 61 | internal void TryDestroy(GameObject obj) 62 | { 63 | try 64 | { 65 | if (obj) 66 | Destroy(obj); 67 | } 68 | catch { } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Hooks/AddHookCell.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | using UniverseLib.UI.Widgets.ScrollView; 4 | 5 | namespace UnityExplorer.Hooks 6 | { 7 | public class AddHookCell : ICell 8 | { 9 | public bool Enabled => UIRoot.activeSelf; 10 | 11 | public RectTransform Rect { get; set; } 12 | public GameObject UIRoot { get; set; } 13 | 14 | public float DefaultHeight => 30; 15 | 16 | public Text MethodNameLabel; 17 | public ButtonRef HookButton; 18 | 19 | public int CurrentDisplayedIndex; 20 | 21 | private void OnHookClicked() 22 | { 23 | HookCreator.AddHookClicked(CurrentDisplayedIndex); 24 | } 25 | 26 | public void Enable() 27 | { 28 | this.UIRoot.SetActive(true); 29 | } 30 | 31 | public void Disable() 32 | { 33 | this.UIRoot.SetActive(false); 34 | } 35 | 36 | public GameObject CreateContent(GameObject parent) 37 | { 38 | UIRoot = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30)); 39 | Rect = UIRoot.GetComponent(); 40 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 5, childAlignment: TextAnchor.UpperLeft); 41 | UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600); 42 | UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 43 | 44 | HookButton = UIFactory.CreateButton(UIRoot, "HookButton", "Hook", new Color(0.2f, 0.25f, 0.2f)); 45 | UIFactory.SetLayoutElement(HookButton.Component.gameObject, minHeight: 25, minWidth: 100); 46 | HookButton.OnClick += OnHookClicked; 47 | 48 | MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft); 49 | UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999); 50 | 51 | return UIRoot; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Hooks/HookCell.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | using UniverseLib.UI.Widgets.ScrollView; 4 | 5 | namespace UnityExplorer.Hooks 6 | { 7 | public class HookCell : ICell 8 | { 9 | public bool Enabled => UIRoot.activeSelf; 10 | 11 | public RectTransform Rect { get; set; } 12 | public GameObject UIRoot { get; set; } 13 | 14 | public float DefaultHeight => 30; 15 | 16 | public Text MethodNameLabel; 17 | public ButtonRef EditPatchButton; 18 | public ButtonRef ToggleActiveButton; 19 | public ButtonRef DeleteButton; 20 | 21 | public int CurrentDisplayedIndex; 22 | 23 | private void OnToggleActiveClicked() 24 | { 25 | HookList.EnableOrDisableHookClicked(CurrentDisplayedIndex); 26 | } 27 | 28 | private void OnDeleteClicked() 29 | { 30 | HookList.DeleteHookClicked(CurrentDisplayedIndex); 31 | HookCreator.AddHooksScrollPool.Refresh(true, false); 32 | } 33 | 34 | private void OnEditPatchClicked() 35 | { 36 | HookList.EditPatchClicked(CurrentDisplayedIndex); 37 | } 38 | 39 | public GameObject CreateContent(GameObject parent) 40 | { 41 | UIRoot = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30)); 42 | Rect = UIRoot.GetComponent(); 43 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft); 44 | UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600); 45 | UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 46 | 47 | MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft); 48 | UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999); 49 | 50 | ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "On", new Color(0.15f, 0.2f, 0.15f)); 51 | UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 35); 52 | ToggleActiveButton.OnClick += OnToggleActiveClicked; 53 | 54 | EditPatchButton = UIFactory.CreateButton(UIRoot, "EditButton", "Edit", new Color(0.15f, 0.15f, 0.15f)); 55 | UIFactory.SetLayoutElement(EditPatchButton.Component.gameObject, minHeight: 25, minWidth: 35); 56 | EditPatchButton.OnClick += OnEditPatchClicked; 57 | 58 | DeleteButton = UIFactory.CreateButton(UIRoot, "DeleteButton", "X", new Color(0.2f, 0.15f, 0.15f)); 59 | UIFactory.SetLayoutElement(DeleteButton.Component.gameObject, minHeight: 25, minWidth: 35); 60 | DeleteButton.OnClick += OnDeleteClicked; 61 | 62 | return UIRoot; 63 | } 64 | 65 | public void Disable() 66 | { 67 | UIRoot.SetActive(false); 68 | } 69 | 70 | public void Enable() 71 | { 72 | UIRoot.SetActive(true); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Hooks/HookList.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Specialized; 3 | using UnityExplorer.UI.Panels; 4 | using UniverseLib.UI; 5 | using UniverseLib.UI.Widgets.ScrollView; 6 | 7 | namespace UnityExplorer.Hooks 8 | { 9 | public class HookList : ICellPoolDataSource 10 | { 11 | public int ItemCount => currentHooks.Count; 12 | 13 | internal static readonly HashSet hookedSignatures = new(); 14 | internal static readonly OrderedDictionary currentHooks = new(); 15 | 16 | internal static GameObject UIRoot; 17 | internal static ScrollPool HooksScrollPool; 18 | 19 | public static void EnableOrDisableHookClicked(int index) 20 | { 21 | HookInstance hook = (HookInstance)currentHooks[index]; 22 | hook.TogglePatch(); 23 | 24 | HooksScrollPool.Refresh(true, false); 25 | } 26 | 27 | public static void DeleteHookClicked(int index) 28 | { 29 | HookInstance hook = (HookInstance)currentHooks[index]; 30 | 31 | if (HookCreator.CurrentEditedHook == hook) 32 | HookCreator.EditorInputCancel(); 33 | 34 | hook.Unpatch(); 35 | currentHooks.RemoveAt(index); 36 | hookedSignatures.Remove(hook.TargetMethod.FullDescription()); 37 | 38 | HooksScrollPool.Refresh(true, false); 39 | } 40 | 41 | public static void EditPatchClicked(int index) 42 | { 43 | if (HookCreator.PendingGeneric) 44 | HookManagerPanel.genericArgsHandler.Cancel(); 45 | 46 | HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.HookSourceEditor); 47 | HookInstance hook = (HookInstance)currentHooks[index]; 48 | HookCreator.SetEditedHook(hook); 49 | } 50 | 51 | // Set current hook cell 52 | 53 | public void OnCellBorrowed(HookCell cell) { } 54 | 55 | public void SetCell(HookCell cell, int index) 56 | { 57 | if (index >= currentHooks.Count) 58 | { 59 | cell.Disable(); 60 | return; 61 | } 62 | 63 | cell.CurrentDisplayedIndex = index; 64 | HookInstance hook = (HookInstance)currentHooks[index]; 65 | 66 | cell.MethodNameLabel.text = SignatureHighlighter.ParseMethod(hook.TargetMethod); 67 | 68 | cell.ToggleActiveButton.ButtonText.text = hook.Enabled ? "On" : "Off"; 69 | RuntimeHelper.SetColorBlockAuto(cell.ToggleActiveButton.Component, 70 | hook.Enabled ? new Color(0.15f, 0.2f, 0.15f) : new Color(0.2f, 0.2f, 0.15f)); 71 | } 72 | 73 | // UI 74 | 75 | internal void ConstructUI(GameObject leftGroup) 76 | { 77 | UIRoot = UIFactory.CreateUIObject("CurrentHooksPanel", leftGroup); 78 | UIFactory.SetLayoutElement(UIRoot, preferredHeight: 150, flexibleHeight: 0, flexibleWidth: 9999); 79 | UIFactory.SetLayoutGroup(UIRoot, true, true, true, true); 80 | 81 | Text hooksLabel = UIFactory.CreateLabel(UIRoot, "HooksLabel", "Current Hooks", TextAnchor.MiddleCenter); 82 | UIFactory.SetLayoutElement(hooksLabel.gameObject, minHeight: 30, flexibleWidth: 9999); 83 | 84 | HooksScrollPool = UIFactory.CreateScrollPool(UIRoot, "HooksScrollPool", 85 | out GameObject hooksScroll, out GameObject hooksContent); 86 | UIFactory.SetLayoutElement(hooksScroll, flexibleHeight: 9999); 87 | HooksScrollPool.Initialize(this); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Inspectors/InspectorBase.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.UI.Panels; 2 | using UniverseLib.UI.ObjectPool; 3 | 4 | namespace UnityExplorer.Inspectors 5 | { 6 | public abstract class InspectorBase : IPooledObject 7 | { 8 | public bool IsActive { get; internal set; } 9 | public object Target { get; set; } 10 | public Type TargetType { get; protected set; } 11 | 12 | public InspectorTab Tab { get; internal set; } 13 | 14 | public GameObject UIRoot { get; set; } 15 | 16 | public float DefaultHeight => -1f; 17 | public abstract GameObject CreateContent(GameObject parent); 18 | 19 | public abstract void Update(); 20 | 21 | public abstract void CloseInspector(); 22 | 23 | public virtual void OnBorrowedFromPool(object target) 24 | { 25 | this.Target = target; 26 | this.TargetType = target is Type type ? type : target.GetActualType(); 27 | 28 | Tab = Pool.Borrow(); 29 | Tab.UIRoot.transform.SetParent(InspectorPanel.Instance.NavbarHolder.transform, false); 30 | 31 | Tab.TabButton.OnClick += OnTabButtonClicked; 32 | Tab.CloseButton.OnClick += CloseInspector; 33 | } 34 | 35 | public virtual void OnReturnToPool() 36 | { 37 | Pool.Return(Tab); 38 | 39 | this.Target = null; 40 | 41 | Tab.TabButton.OnClick -= OnTabButtonClicked; 42 | Tab.CloseButton.OnClick -= CloseInspector; 43 | } 44 | 45 | public virtual void OnSetActive() 46 | { 47 | Tab.SetTabColor(true); 48 | UIRoot.SetActive(true); 49 | IsActive = true; 50 | LayoutRebuilder.ForceRebuildLayoutImmediate(UIRoot.GetComponent()); 51 | } 52 | 53 | public virtual void OnSetInactive() 54 | { 55 | Tab.SetTabColor(false); 56 | UIRoot.SetActive(false); 57 | IsActive = false; 58 | } 59 | 60 | private void OnTabButtonClicked() 61 | { 62 | InspectorManager.SetInspectorActive(this); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Inspectors/InspectorTab.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | using UniverseLib.UI.ObjectPool; 4 | 5 | namespace UnityExplorer.Inspectors 6 | { 7 | public class InspectorTab : IPooledObject 8 | { 9 | public GameObject UIRoot { get; set; } 10 | public float DefaultHeight => 25f; 11 | 12 | public ButtonRef TabButton; 13 | public Text TabText; 14 | public ButtonRef CloseButton; 15 | 16 | private static readonly Color enabledTabColor = new(0.15f, 0.22f, 0.15f); 17 | private static readonly Color disabledTabColor = new(0.13f, 0.13f, 0.13f); 18 | 19 | public void SetTabColor(bool active) 20 | { 21 | Color color = active ? enabledTabColor : disabledTabColor; 22 | RuntimeHelper.SetColorBlock(TabButton.Component, color, color * 1.2f); 23 | } 24 | 25 | public GameObject CreateContent(GameObject parent) 26 | { 27 | UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", false, true, true, true, 1, 28 | default, new Color(0.13f, 0.13f, 0.13f), childAlignment: TextAnchor.MiddleLeft); 29 | UIFactory.SetLayoutElement(UIRoot, minWidth: 200, flexibleWidth: 0); 30 | UIRoot.AddComponent(); 31 | UIRoot.AddComponent(); 32 | 33 | TabButton = UIFactory.CreateButton(UIRoot, "TabButton", ""); 34 | UIFactory.SetLayoutElement(TabButton.Component.gameObject, minWidth: 173, flexibleWidth: 0); 35 | UIFactory.SetLayoutGroup(TabButton.Component.gameObject, false, false, true, true, 0, 0, 0, 3); 36 | TabButton.GameObject.AddComponent(); 37 | 38 | TabText = TabButton.ButtonText; 39 | UIFactory.SetLayoutElement(TabText.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0); 40 | TabText.alignment = TextAnchor.MiddleLeft; 41 | TabText.fontSize = 12; 42 | TabText.horizontalOverflow = HorizontalWrapMode.Overflow; 43 | 44 | CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.15f, 0.15f, 0.15f, 1)); 45 | UIFactory.SetLayoutElement(CloseButton.Component.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0); 46 | CloseButton.ButtonText.color = Color.red; 47 | 48 | return UIRoot; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Inspectors/MouseInspectors/MouseInspectorBase.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Inspectors.MouseInspectors 2 | { 3 | public abstract class MouseInspectorBase 4 | { 5 | public abstract void OnBeginMouseInspect(); 6 | 7 | public abstract void UpdateMouseInspect(Vector2 mousePos); 8 | 9 | public abstract void OnSelectMouseInspect(); 10 | 11 | public abstract void ClearHitData(); 12 | 13 | public abstract void OnEndInspect(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Inspectors/MouseInspectors/WorldInspector.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Inspectors.MouseInspectors 2 | { 3 | public class WorldInspector : MouseInspectorBase 4 | { 5 | private static Camera MainCamera; 6 | private static GameObject lastHitObject; 7 | 8 | public override void OnBeginMouseInspect() 9 | { 10 | MainCamera = Camera.main; 11 | 12 | if (!MainCamera) 13 | { 14 | ExplorerCore.LogWarning("No MainCamera found! Cannot inspect world!"); 15 | return; 16 | } 17 | } 18 | 19 | public override void ClearHitData() 20 | { 21 | lastHitObject = null; 22 | } 23 | 24 | public override void OnSelectMouseInspect() 25 | { 26 | InspectorManager.Inspect(lastHitObject); 27 | } 28 | 29 | public override void UpdateMouseInspect(Vector2 mousePos) 30 | { 31 | if (!MainCamera) 32 | MainCamera = Camera.main; 33 | if (!MainCamera) 34 | { 35 | ExplorerCore.LogWarning("No Main Camera was found, unable to inspect world!"); 36 | MouseInspector.Instance.StopInspect(); 37 | return; 38 | } 39 | 40 | Ray ray = MainCamera.ScreenPointToRay(mousePos); 41 | Physics.Raycast(ray, out RaycastHit hit, 1000f); 42 | 43 | if (hit.transform) 44 | OnHitGameObject(hit.transform.gameObject); 45 | else if (lastHitObject) 46 | MouseInspector.Instance.ClearHitData(); 47 | } 48 | 49 | internal void OnHitGameObject(GameObject obj) 50 | { 51 | if (obj != lastHitObject) 52 | { 53 | lastHitObject = obj; 54 | MouseInspector.Instance.objNameLabel.text = $"Click to Inspect: {obj.name}"; 55 | MouseInspector.Instance.objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}"; 56 | } 57 | } 58 | 59 | public override void OnEndInspect() 60 | { 61 | // not needed 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Loader/BepInEx/BepInExConfigHandler.cs: -------------------------------------------------------------------------------- 1 | #if BIE 2 | using BepInEx.Configuration; 3 | using UnityExplorer.Config; 4 | 5 | namespace UnityExplorer.Loader.BIE 6 | { 7 | public class BepInExConfigHandler : ConfigHandler 8 | { 9 | private ConfigFile Config => ExplorerBepInPlugin.Instance.Config; 10 | 11 | private const string CTG_NAME = "UnityExplorer"; 12 | 13 | public override void Init() 14 | { 15 | // Not necessary 16 | } 17 | 18 | public override void RegisterConfigElement(ConfigElement config) 19 | { 20 | ConfigEntry entry = Config.Bind(CTG_NAME, config.Name, config.Value, config.Description); 21 | 22 | entry.SettingChanged += (object o, EventArgs e) => 23 | { 24 | config.Value = entry.Value; 25 | }; 26 | } 27 | 28 | public override T GetConfigValue(ConfigElement element) 29 | { 30 | if (Config.TryGetEntry(CTG_NAME, element.Name, out ConfigEntry configEntry)) 31 | return configEntry.Value; 32 | else 33 | throw new Exception("Could not get config entry '" + element.Name + "'"); 34 | } 35 | 36 | public override void SetConfigValue(ConfigElement element, T value) 37 | { 38 | if (Config.TryGetEntry(CTG_NAME, element.Name, out ConfigEntry configEntry)) 39 | configEntry.Value = value; 40 | else 41 | ExplorerCore.Log("Could not get config entry '" + element.Name + "'"); 42 | } 43 | 44 | public override void LoadConfig() 45 | { 46 | foreach (KeyValuePair entry in ConfigManager.ConfigElements) 47 | { 48 | string key = entry.Key; 49 | ConfigDefinition def = new(CTG_NAME, key); 50 | if (Config.ContainsKey(def) && Config[def] is ConfigEntryBase configEntry) 51 | { 52 | IConfigElement config = entry.Value; 53 | config.BoxedValue = configEntry.BoxedValue; 54 | } 55 | } 56 | } 57 | 58 | public override void SaveConfig() 59 | { 60 | Config.Save(); 61 | } 62 | } 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /src/Loader/BepInEx/ExplorerBepInPlugin.cs: -------------------------------------------------------------------------------- 1 | #if BIE 2 | using BepInEx; 3 | using BepInEx.Logging; 4 | using BepInEx.Unity.Mono; 5 | using HarmonyLib; 6 | using UnityExplorer.Config; 7 | using UnityExplorer.Loader.BIE; 8 | #if CPP 9 | using BepInEx.Unity.IL2CPP; 10 | #endif 11 | 12 | namespace UnityExplorer 13 | { 14 | [BepInPlugin(ExplorerCore.GUID, "UnityExplorer", ExplorerCore.VERSION)] 15 | 16 | public class ExplorerBepInPlugin : 17 | #if MONO 18 | BaseUnityPlugin 19 | #else 20 | BasePlugin 21 | #endif 22 | , IExplorerLoader 23 | { 24 | public static ExplorerBepInPlugin Instance; 25 | 26 | public ManualLogSource LogSource 27 | #if MONO 28 | => Logger; 29 | #else 30 | => Log; 31 | #endif 32 | const string IL2CPP_LIBS_FOLDER = 33 | #if UNHOLLOWER 34 | "unhollowed" 35 | #else 36 | "interop" 37 | #endif 38 | ; 39 | public string UnhollowedModulesFolder => Path.Combine(Paths.BepInExRootPath, IL2CPP_LIBS_FOLDER); 40 | 41 | public ConfigHandler ConfigHandler => _configHandler; 42 | private BepInExConfigHandler _configHandler; 43 | 44 | public Harmony HarmonyInstance => s_harmony; 45 | private static readonly Harmony s_harmony = new(ExplorerCore.GUID); 46 | 47 | public string ExplorerFolderName => ExplorerCore.DEFAULT_EXPLORER_FOLDER_NAME; 48 | public string ExplorerFolderDestination => Paths.PluginPath; 49 | 50 | public Action OnLogMessage => LogSource.LogMessage; 51 | public Action OnLogWarning => LogSource.LogWarning; 52 | public Action OnLogError => LogSource.LogError; 53 | 54 | private void Init() 55 | { 56 | Instance = this; 57 | _configHandler = new BepInExConfigHandler(); 58 | ExplorerCore.Init(this); 59 | } 60 | 61 | #if MONO // Mono 62 | internal void Awake() 63 | { 64 | Init(); 65 | } 66 | 67 | #else // Il2Cpp 68 | public override void Load() 69 | { 70 | Init(); 71 | } 72 | #endif 73 | } 74 | } 75 | #endif -------------------------------------------------------------------------------- /src/Loader/IExplorerLoader.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Config; 2 | 3 | namespace UnityExplorer 4 | { 5 | public interface IExplorerLoader 6 | { 7 | string ExplorerFolderDestination { get; } 8 | string ExplorerFolderName { get; } 9 | string UnhollowedModulesFolder { get; } 10 | 11 | ConfigHandler ConfigHandler { get; } 12 | 13 | Action OnLogMessage { get; } 14 | Action OnLogWarning { get; } 15 | Action OnLogError { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Loader/MelonLoader/ExplorerMelonMod.cs: -------------------------------------------------------------------------------- 1 | #if ML 2 | using System; 3 | using System.IO; 4 | using MelonLoader; 5 | using UnityExplorer; 6 | using UnityExplorer.Config; 7 | using UnityExplorer.Loader.ML; 8 | 9 | #if CPP 10 | [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.IL2CPP)] 11 | #else 12 | [assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)] 13 | #endif 14 | 15 | [assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)] 16 | [assembly: MelonGame(null, null)] 17 | [assembly: MelonColor(ConsoleColor.DarkCyan)] 18 | 19 | namespace UnityExplorer 20 | { 21 | public class ExplorerMelonMod : MelonMod, IExplorerLoader 22 | { 23 | public string ExplorerFolderName => ExplorerCore.DEFAULT_EXPLORER_FOLDER_NAME; 24 | public string ExplorerFolderDestination => MelonHandler.ModsDirectory; 25 | 26 | public string UnhollowedModulesFolder => Path.Combine( 27 | Path.GetDirectoryName(MelonHandler.ModsDirectory), 28 | Path.Combine("MelonLoader", "Managed")); 29 | 30 | public ConfigHandler ConfigHandler => _configHandler; 31 | public MelonLoaderConfigHandler _configHandler; 32 | 33 | public Action OnLogMessage => LoggerInstance.Msg; 34 | public Action OnLogWarning => LoggerInstance.Warning; 35 | public Action OnLogError => LoggerInstance.Error; 36 | 37 | public override void OnApplicationStart() 38 | { 39 | _configHandler = new MelonLoaderConfigHandler(); 40 | ExplorerCore.Init(this); 41 | } 42 | } 43 | } 44 | #endif -------------------------------------------------------------------------------- /src/Loader/MelonLoader/MelonLoaderConfigHandler.cs: -------------------------------------------------------------------------------- 1 | #if ML 2 | using MelonLoader; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using UnityEngine; 8 | using UnityExplorer.Config; 9 | 10 | namespace UnityExplorer.Loader.ML 11 | { 12 | public class MelonLoaderConfigHandler : ConfigHandler 13 | { 14 | internal const string CTG_NAME = "UnityExplorer"; 15 | 16 | internal MelonPreferences_Category prefCategory; 17 | 18 | public override void Init() 19 | { 20 | prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings", false, true); 21 | } 22 | 23 | public override void LoadConfig() 24 | { 25 | foreach (var entry in ConfigManager.ConfigElements) 26 | { 27 | var key = entry.Key; 28 | if (prefCategory.GetEntry(key) is MelonPreferences_Entry) 29 | { 30 | var config = entry.Value; 31 | config.BoxedValue = config.GetLoaderConfigValue(); 32 | } 33 | } 34 | } 35 | 36 | // This wrapper exists to handle the "LemonAction" delegates which ML now uses in 0.4.4+. 37 | // Reflection is required since the delegate type changed between 0.4.3 and 0.4.4. 38 | // A wrapper class is required to link the MelonPreferences_Entry and the delegate instance. 39 | public class EntryDelegateWrapper 40 | { 41 | public MelonPreferences_Entry entry; 42 | public ConfigElement config; 43 | 44 | public EntryDelegateWrapper(MelonPreferences_Entry entry, ConfigElement config) 45 | { 46 | this.entry = entry; 47 | this.config = config; 48 | var evt = entry.GetType().GetEvent("OnValueChangedUntyped"); 49 | evt.AddEventHandler(entry, Delegate.CreateDelegate(evt.EventHandlerType, this, GetType().GetMethod("OnChanged"))); 50 | } 51 | 52 | public void OnChanged() 53 | { 54 | if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value)) 55 | return; 56 | config.Value = entry.Value; 57 | } 58 | } 59 | 60 | public override void RegisterConfigElement(ConfigElement config) 61 | { 62 | var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.Description, config.IsInternal, false); 63 | new EntryDelegateWrapper(entry, config); 64 | } 65 | 66 | public override void SetConfigValue(ConfigElement config, T value) 67 | { 68 | if (prefCategory.GetEntry(config.Name) is MelonPreferences_Entry entry) 69 | { 70 | entry.Value = value; 71 | //entry.Save(); 72 | } 73 | } 74 | 75 | public override T GetConfigValue(ConfigElement config) 76 | { 77 | if (prefCategory.GetEntry(config.Name) is MelonPreferences_Entry entry) 78 | return entry.Value; 79 | 80 | return default; 81 | } 82 | 83 | public override void OnAnyConfigChanged() 84 | { 85 | } 86 | 87 | public override void SaveConfig() 88 | { 89 | MelonPreferences.Save(); 90 | } 91 | } 92 | } 93 | #endif -------------------------------------------------------------------------------- /src/Loader/Standalone/Editor/ExplorerEditorBehaviour.cs: -------------------------------------------------------------------------------- 1 | #if STANDALONE 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using UnityEngine; 9 | using UnityExplorer.Config; 10 | using UnityExplorer.UI; 11 | using UniverseLib; 12 | 13 | namespace UnityExplorer.Loader.Standalone 14 | { 15 | public class ExplorerEditorBehaviour : MonoBehaviour 16 | { 17 | internal static ExplorerEditorBehaviour Instance { get; private set; } 18 | 19 | public bool Hide_On_Startup = true; 20 | public KeyCode Master_Toggle_Key = KeyCode.F7; 21 | public UIManager.VerticalAnchor Main_Navbar_Anchor = UIManager.VerticalAnchor.Top; 22 | public bool Log_Unity_Debug = false; 23 | public float Startup_Delay_Time = 1f; 24 | public KeyCode World_MouseInspect_Keybind; 25 | public KeyCode UI_MouseInspect_Keybind; 26 | public bool Force_Unlock_Mouse = true; 27 | public KeyCode Force_Unlock_Toggle; 28 | public bool Disable_EventSystem_Override; 29 | 30 | internal void Awake() 31 | { 32 | Instance = this; 33 | 34 | ExplorerEditorLoader.Initialize(); 35 | DontDestroyOnLoad(this); 36 | this.gameObject.hideFlags = HideFlags.HideAndDontSave; 37 | } 38 | 39 | internal void OnApplicationQuit() 40 | { 41 | Destroy(this.gameObject); 42 | } 43 | 44 | internal void LoadConfigs() 45 | { 46 | ConfigManager.Hide_On_Startup.Value = this.Hide_On_Startup; 47 | ConfigManager.Master_Toggle.Value = this.Master_Toggle_Key; 48 | ConfigManager.Main_Navbar_Anchor.Value = this.Main_Navbar_Anchor; 49 | ConfigManager.Log_Unity_Debug.Value = this.Log_Unity_Debug; 50 | ConfigManager.Startup_Delay_Time.Value = this.Startup_Delay_Time; 51 | ConfigManager.World_MouseInspect_Keybind.Value = this.World_MouseInspect_Keybind; 52 | ConfigManager.UI_MouseInspect_Keybind.Value = this.UI_MouseInspect_Keybind; 53 | ConfigManager.Force_Unlock_Mouse.Value = this.Force_Unlock_Mouse; 54 | ConfigManager.Force_Unlock_Toggle.Value = this.Force_Unlock_Toggle; 55 | ConfigManager.Disable_EventSystem_Override.Value = this.Disable_EventSystem_Override; 56 | } 57 | } 58 | } 59 | #endif -------------------------------------------------------------------------------- /src/Loader/Standalone/Editor/ExplorerEditorLoader.cs: -------------------------------------------------------------------------------- 1 | #if STANDALONE 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using UnityEngine; 8 | 9 | namespace UnityExplorer.Loader.Standalone 10 | { 11 | public class ExplorerEditorLoader : ExplorerStandalone 12 | { 13 | public new string ExplorerFolderName => $"{ExplorerCore.DEFAULT_EXPLORER_FOLDER_NAME}~"; 14 | 15 | public static void Initialize() 16 | { 17 | Instance = new ExplorerEditorLoader(); 18 | OnLog += LogHandler; 19 | Instance.configHandler = new StandaloneConfigHandler(); 20 | 21 | ExplorerCore.Init(Instance); 22 | } 23 | 24 | static void LogHandler(string message, LogType logType) 25 | { 26 | switch (logType) 27 | { 28 | case LogType.Assert: Debug.LogError(message); break; 29 | case LogType.Error: Debug.LogError(message); break; 30 | case LogType.Exception: Debug.LogError(message); break; 31 | case LogType.Log: Debug.Log(message); break; 32 | case LogType.Warning: Debug.LogWarning(message); break; 33 | } 34 | } 35 | 36 | protected override void CheckExplorerFolder() 37 | { 38 | if (explorerFolderDest == null) 39 | explorerFolderDest = Path.GetDirectoryName(Application.dataPath); 40 | } 41 | } 42 | } 43 | #endif -------------------------------------------------------------------------------- /src/Loader/Standalone/StandaloneConfigHandler.cs: -------------------------------------------------------------------------------- 1 | #if STANDALONE 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityExplorer.Config; 7 | using System.IO; 8 | using UnityEngine; 9 | using Tomlet; 10 | using Tomlet.Models; 11 | 12 | namespace UnityExplorer.Loader.Standalone 13 | { 14 | public class StandaloneConfigHandler : ConfigHandler 15 | { 16 | internal static string CONFIG_PATH; 17 | 18 | public override void Init() 19 | { 20 | CONFIG_PATH = Path.Combine(ExplorerCore.ExplorerFolder, "config.cfg"); 21 | } 22 | 23 | public override void LoadConfig() 24 | { 25 | if (!TryLoadConfig()) 26 | SaveConfig(); 27 | } 28 | 29 | public override void RegisterConfigElement(ConfigElement element) 30 | { 31 | // Not necessary 32 | } 33 | 34 | public override void SetConfigValue(ConfigElement element, T value) 35 | { 36 | // Not necessary, just save. 37 | SaveConfig(); 38 | } 39 | 40 | public override T GetConfigValue(ConfigElement element) 41 | { 42 | // Not necessary, just return the value. 43 | return element.Value; 44 | } 45 | 46 | public bool TryLoadConfig() 47 | { 48 | try 49 | { 50 | if (!File.Exists(CONFIG_PATH)) 51 | return false; 52 | 53 | var document = TomlParser.ParseFile(CONFIG_PATH); 54 | foreach (var key in document.Keys) 55 | { 56 | var config = ConfigManager.ConfigElements[key]; 57 | config.BoxedValue = StringToConfigValue(document.GetValue(key).StringValue, config.ElementType); 58 | } 59 | 60 | return true; 61 | } 62 | catch 63 | { 64 | return false; 65 | } 66 | } 67 | 68 | public object StringToConfigValue(string value, Type elementType) 69 | { 70 | if (elementType == typeof(KeyCode)) 71 | return (KeyCode)Enum.Parse(typeof(KeyCode), value); 72 | else if (elementType == typeof(bool)) 73 | return bool.Parse(value); 74 | else if (elementType == typeof(int)) 75 | return int.Parse(value); 76 | else if (elementType == typeof(float)) 77 | return float.Parse(value); 78 | else if (elementType.IsEnum) 79 | return Enum.Parse(elementType, value); 80 | else 81 | return value; 82 | } 83 | 84 | public override void OnAnyConfigChanged() 85 | { 86 | SaveConfig(); 87 | } 88 | 89 | public override void SaveConfig() 90 | { 91 | var document = TomlDocument.CreateEmpty(); 92 | foreach (var config in ConfigManager.ConfigElements) 93 | document.Put(config.Key, config.Value.BoxedValue.ToString()); 94 | 95 | if (!Directory.Exists(ExplorerCore.ExplorerFolder)) 96 | Directory.CreateDirectory(ExplorerCore.ExplorerFolder); 97 | 98 | File.WriteAllText(CONFIG_PATH, document.SerializedValue); 99 | } 100 | } 101 | } 102 | 103 | #endif -------------------------------------------------------------------------------- /src/ObjectExplorer/UITabPanel.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI.Models; 2 | 3 | namespace UnityExplorer.ObjectExplorer 4 | { 5 | public abstract class UITabPanel : UIModel 6 | { 7 | public abstract string Name { get; } 8 | 9 | public abstract void Update(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using UnityExplorer; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle(ExplorerCore.NAME)] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany(ExplorerCore.AUTHOR)] 11 | [assembly: AssemblyProduct(ExplorerCore.NAME)] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("b21dbde3-5d6f-4726-93ab-cc3cc68bae7d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion(ExplorerCore.VERSION)] 35 | [assembly: AssemblyFileVersion(ExplorerCore.VERSION)] 36 | -------------------------------------------------------------------------------- /src/Runtime/MonoHelper.cs: -------------------------------------------------------------------------------- 1 | #if MONO 2 | 3 | namespace UnityExplorer.Runtime 4 | { 5 | public class MonoHelper : UERuntimeHelper 6 | { 7 | public override void SetupEvents() 8 | { 9 | Application.logMessageReceived += Application_logMessageReceived; 10 | } 11 | 12 | private void Application_logMessageReceived(string condition, string stackTrace, LogType type) 13 | => ExplorerCore.LogUnity(condition, type); 14 | } 15 | } 16 | 17 | #endif -------------------------------------------------------------------------------- /src/Runtime/UERuntimeHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Config; 2 | 3 | namespace UnityExplorer.Runtime 4 | { 5 | // Not really that necessary anymore, can eventually just be refactored away into the few classes that use this class. 6 | 7 | public abstract class UERuntimeHelper 8 | { 9 | public static UERuntimeHelper Instance; 10 | 11 | public static void Init() 12 | { 13 | #if CPP 14 | Instance = new Il2CppHelper(); 15 | #else 16 | Instance = new MonoHelper(); 17 | #endif 18 | Instance.SetupEvents(); 19 | 20 | LoadBlacklistString(ConfigManager.Reflection_Signature_Blacklist.Value); 21 | ConfigManager.Reflection_Signature_Blacklist.OnValueChanged += (string val) => 22 | { 23 | LoadBlacklistString(val); 24 | }; 25 | } 26 | 27 | public abstract void SetupEvents(); 28 | 29 | private static readonly HashSet currentBlacklist = new(); 30 | 31 | public virtual string[] DefaultReflectionBlacklist => new string[0]; 32 | 33 | public static void LoadBlacklistString(string blacklist) 34 | { 35 | try 36 | { 37 | if (string.IsNullOrEmpty(blacklist) && !Instance.DefaultReflectionBlacklist.Any()) 38 | return; 39 | 40 | try 41 | { 42 | string[] sigs = blacklist.Split(';'); 43 | foreach (string sig in sigs) 44 | { 45 | string s = sig.Trim(); 46 | if (string.IsNullOrEmpty(s)) 47 | continue; 48 | if (!currentBlacklist.Contains(s)) 49 | currentBlacklist.Add(s); 50 | } 51 | } 52 | catch (Exception ex) 53 | { 54 | ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}"); 55 | } 56 | 57 | foreach (string sig in Instance.DefaultReflectionBlacklist) 58 | { 59 | if (!currentBlacklist.Contains(sig)) 60 | currentBlacklist.Add(sig); 61 | } 62 | 63 | Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist; 64 | } 65 | catch (Exception ex) 66 | { 67 | ExplorerCore.LogWarning($"Exception setting up reflection blacklist: {ex.ReflectionExToString()}"); 68 | } 69 | } 70 | 71 | public static bool IsBlacklisted(MemberInfo member) 72 | { 73 | if (string.IsNullOrEmpty(member.DeclaringType?.Namespace)) 74 | return false; 75 | 76 | string sig = $"{member.DeclaringType.FullName}.{member.Name}"; 77 | 78 | return currentBlacklist.Contains(sig); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Runtime/UnityCrashPrevention.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.Runtime 2 | { 3 | internal static class UnityCrashPrevention 4 | { 5 | static readonly HarmonyLib.Harmony harmony = new($"{ExplorerCore.GUID}.crashprevention"); 6 | 7 | internal static void Init() 8 | { 9 | TryPatch("get_renderingDisplaySize", nameof(Canvas_renderingDisplaySize_Prefix)); 10 | 11 | IEnumerable patched = harmony.GetPatchedMethods(); 12 | if (patched.Any()) 13 | ExplorerCore.Log( 14 | $"Initialized UnityCrashPrevention for: {string.Join(", ", patched.Select(it => $"{it.DeclaringType.Name}.{it.Name}").ToArray())}"); 15 | } 16 | 17 | internal static void TryPatch(string orig, string prefix, Type[] argTypes = null) 18 | { 19 | try 20 | { 21 | harmony.Patch( 22 | HarmonyLib.AccessTools.Method(typeof(T), orig, argTypes), 23 | new HarmonyLib.HarmonyMethod(HarmonyLib.AccessTools.Method(typeof(UnityCrashPrevention), prefix))); 24 | } 25 | catch //(Exception ex) 26 | { 27 | //ExplorerCore.Log($"Exception patching {typeof(T).Name}.{orig}: {ex}"); 28 | } 29 | } 30 | 31 | // In Unity 2020 they introduced "Canvas.renderingDisplaySize". 32 | // If you try to get the value on a Canvas which has a renderMode value of WorldSpace and no worldCamera set, 33 | // the game will Crash (I think from Unity trying to read from null ptr). 34 | internal static void Canvas_renderingDisplaySize_Prefix(Canvas __instance) 35 | { 36 | if (__instance.renderMode == RenderMode.WorldSpace && !__instance.worldCamera) 37 | throw new InvalidOperationException("Canvas is set to RenderMode.WorldSpace but not worldCamera is set."); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/UI/DisplayManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityExplorer.Config; 3 | using UniverseLib.Input; 4 | 5 | namespace UnityExplorer.UI 6 | { 7 | public static class DisplayManager 8 | { 9 | public static int ActiveDisplayIndex { get; private set; } 10 | public static Display ActiveDisplay => Display.displays[ActiveDisplayIndex]; 11 | 12 | public static int Width => ActiveDisplay.renderingWidth; 13 | public static int Height => ActiveDisplay.renderingHeight; 14 | 15 | public static Vector3 MousePosition => Application.isEditor 16 | ? InputManager.MousePosition 17 | : Display.RelativeMouseAt(InputManager.MousePosition); 18 | 19 | public static bool MouseInTargetDisplay => MousePosition.z == ActiveDisplayIndex; 20 | 21 | private static Camera canvasCamera; 22 | 23 | internal static void Init() 24 | { 25 | SetDisplay(ConfigManager.Target_Display.Value); 26 | ConfigManager.Target_Display.OnValueChanged += SetDisplay; 27 | } 28 | 29 | public static void SetDisplay(int display) 30 | { 31 | if (ActiveDisplayIndex == display) 32 | return; 33 | 34 | if (Display.displays.Length <= display) 35 | { 36 | ExplorerCore.LogWarning($"Cannot set display index to {display} as there are not enough monitors connected!"); 37 | 38 | if (ConfigManager.Target_Display.Value == display) 39 | ConfigManager.Target_Display.Value = 0; 40 | 41 | return; 42 | } 43 | 44 | ActiveDisplayIndex = display; 45 | ActiveDisplay.Activate(); 46 | 47 | UIManager.UICanvas.targetDisplay = display; 48 | 49 | // ensure a camera is targeting the display 50 | if (!Camera.main || Camera.main.targetDisplay != display) 51 | { 52 | if (!canvasCamera) 53 | { 54 | canvasCamera = new GameObject("UnityExplorer_CanvasCamera").AddComponent(); 55 | GameObject.DontDestroyOnLoad(canvasCamera.gameObject); 56 | canvasCamera.hideFlags = HideFlags.HideAndDontSave; 57 | } 58 | canvasCamera.targetDisplay = display; 59 | } 60 | 61 | RuntimeHelper.StartCoroutine(FixPanels()); 62 | } 63 | 64 | private static IEnumerator FixPanels() 65 | { 66 | yield return null; 67 | yield return null; 68 | 69 | foreach (Panels.UEPanel panel in UIManager.UIPanels.Values) 70 | { 71 | panel.EnsureValidSize(); 72 | panel.EnsureValidPosition(); 73 | panel.Dragger.OnEndResize(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/UI/ExplorerUIBase.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Panels; 3 | 4 | namespace UnityExplorer.UI 5 | { 6 | internal class ExplorerUIBase : UIBase 7 | { 8 | public ExplorerUIBase(string id, Action updateMethod) : base(id, updateMethod) { } 9 | 10 | protected override PanelManager CreatePanelManager() 11 | { 12 | return new UEPanelManager(this); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/UI/Notification.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | 3 | namespace UnityExplorer.UI 4 | { 5 | public static class Notification 6 | { 7 | private static Text popupLabel; 8 | 9 | private static string _currentNotification; 10 | private static float _timeOfLastNotification; 11 | 12 | public static void Init() 13 | { 14 | ConstructUI(); 15 | } 16 | 17 | public static void ShowMessage(string message) 18 | { 19 | popupLabel.text = message; 20 | _currentNotification = message; 21 | _timeOfLastNotification = Time.realtimeSinceStartup; 22 | 23 | popupLabel.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(DisplayManager.MousePosition) + (Vector3.up * 25); 24 | } 25 | 26 | public static void Update() 27 | { 28 | if (_currentNotification != null) 29 | { 30 | if (Time.realtimeSinceStartup - _timeOfLastNotification > 2f) 31 | { 32 | _currentNotification = null; 33 | popupLabel.text = ""; 34 | } 35 | } 36 | } 37 | 38 | private static void ConstructUI() 39 | { 40 | popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter); 41 | popupLabel.rectTransform.sizeDelta = new(500, 100); 42 | popupLabel.gameObject.AddComponent(); 43 | CanvasGroup popupGroup = popupLabel.gameObject.AddComponent(); 44 | popupGroup.blocksRaycasts = false; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/UI/Panels/HookManagerPanel.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Hooks; 2 | using UnityExplorer.UI.Widgets; 3 | using UniverseLib.UI; 4 | 5 | namespace UnityExplorer.UI.Panels 6 | { 7 | public class HookManagerPanel : UEPanel 8 | { 9 | public static HookManagerPanel Instance { get; private set; } 10 | 11 | public enum Pages 12 | { 13 | ClassMethodSelector, 14 | HookSourceEditor, 15 | GenericArgsSelector, 16 | } 17 | 18 | public static HookCreator hookCreator; 19 | public static HookList hookList; 20 | public static GenericConstructorWidget genericArgsHandler; 21 | 22 | // Panel 23 | public override UIManager.Panels PanelType => UIManager.Panels.HookManager; 24 | public override string Name => "Hooks"; 25 | public override bool ShowByDefault => false; 26 | public override int MinWidth => 400; 27 | public override int MinHeight => 400; 28 | public override Vector2 DefaultAnchorMin => new(0.5f, 0.5f); 29 | public override Vector2 DefaultAnchorMax => new(0.5f, 0.5f); 30 | 31 | public Pages CurrentPage { get; private set; } = Pages.ClassMethodSelector; 32 | 33 | public HookManagerPanel(UIBase owner) : base(owner) 34 | { 35 | } 36 | 37 | public void SetPage(Pages page) 38 | { 39 | switch (page) 40 | { 41 | case Pages.ClassMethodSelector: 42 | HookCreator.AddHooksRoot.SetActive(true); 43 | HookCreator.EditorRoot.SetActive(false); 44 | genericArgsHandler.UIRoot.SetActive(false); 45 | break; 46 | 47 | case Pages.HookSourceEditor: 48 | HookCreator.AddHooksRoot.SetActive(false); 49 | HookCreator.EditorRoot.SetActive(true); 50 | genericArgsHandler.UIRoot.SetActive(false); 51 | break; 52 | 53 | case Pages.GenericArgsSelector: 54 | HookCreator.AddHooksRoot.SetActive(false); 55 | HookCreator.EditorRoot.SetActive(false); 56 | genericArgsHandler.UIRoot.SetActive(true); 57 | break; 58 | } 59 | } 60 | 61 | public override void SetDefaultSizeAndPosition() 62 | { 63 | base.SetDefaultSizeAndPosition(); 64 | 65 | this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth); 66 | this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight); 67 | } 68 | 69 | protected override void ConstructPanelContent() 70 | { 71 | Instance = this; 72 | hookList = new(); 73 | hookCreator = new(); 74 | genericArgsHandler = new(); 75 | 76 | UIFactory.SetLayoutGroup(ContentRoot, true, false); 77 | 78 | // GameObject baseHoriGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "HoriGroup", true, true, true, true); 79 | // UIFactory.SetLayoutElement(baseHoriGroup, flexibleWidth: 9999, flexibleHeight: 9999); 80 | 81 | // // Left Group 82 | 83 | //GameObject leftGroup = UIFactory.CreateVerticalGroup(ContentRoot, "LeftGroup", true, true, true, true); 84 | UIFactory.SetLayoutElement(ContentRoot.gameObject, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999); 85 | 86 | hookList.ConstructUI(ContentRoot); 87 | 88 | // // Right Group 89 | 90 | //GameObject rightGroup = UIFactory.CreateVerticalGroup(ContentRoot, "RightGroup", true, true, true, true); 91 | UIFactory.SetLayoutElement(ContentRoot, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999); 92 | 93 | hookCreator.ConstructAddHooksView(ContentRoot); 94 | 95 | hookCreator.ConstructEditor(ContentRoot); 96 | HookCreator.EditorRoot.SetActive(false); 97 | 98 | genericArgsHandler.ConstructUI(ContentRoot); 99 | genericArgsHandler.UIRoot.SetActive(false); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/UI/Panels/InspectorPanel.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | using UniverseLib.UI; 3 | 4 | namespace UnityExplorer.UI.Panels 5 | { 6 | public class InspectorPanel : UEPanel 7 | { 8 | public static InspectorPanel Instance { get; private set; } 9 | 10 | public override string Name => "Inspector"; 11 | public override UIManager.Panels PanelType => UIManager.Panels.Inspector; 12 | public override bool ShouldSaveActiveState => false; 13 | 14 | public override int MinWidth => 810; 15 | public override int MinHeight => 350; 16 | public override Vector2 DefaultAnchorMin => new(0.35f, 0.175f); 17 | public override Vector2 DefaultAnchorMax => new(0.8f, 0.925f); 18 | 19 | public GameObject NavbarHolder; 20 | public Dropdown MouseInspectDropdown; 21 | public GameObject ContentHolder; 22 | public RectTransform ContentRect; 23 | 24 | public static float CurrentPanelWidth => Instance.Rect.rect.width; 25 | public static float CurrentPanelHeight => Instance.Rect.rect.height; 26 | 27 | public InspectorPanel(UIBase owner) : base(owner) 28 | { 29 | Instance = this; 30 | } 31 | 32 | public override void Update() 33 | { 34 | InspectorManager.Update(); 35 | } 36 | 37 | public override void OnFinishResize() 38 | { 39 | base.OnFinishResize(); 40 | 41 | InspectorManager.PanelWidth = this.Rect.rect.width; 42 | InspectorManager.OnPanelResized(Rect.rect.width); 43 | } 44 | 45 | protected override void ConstructPanelContent() 46 | { 47 | GameObject closeHolder = this.TitleBar.transform.Find("CloseHolder").gameObject; 48 | 49 | // Inspect under mouse dropdown on title bar 50 | 51 | GameObject mouseDropdown = UIFactory.CreateDropdown(closeHolder, "MouseInspectDropdown", out MouseInspectDropdown, "Mouse Inspect", 14, 52 | MouseInspector.OnDropdownSelect); 53 | UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140); 54 | MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect")); 55 | MouseInspectDropdown.options.Add(new Dropdown.OptionData("World")); 56 | MouseInspectDropdown.options.Add(new Dropdown.OptionData("UI")); 57 | mouseDropdown.transform.SetSiblingIndex(0); 58 | 59 | // add close all button to titlebar 60 | 61 | UniverseLib.UI.Models.ButtonRef closeAllBtn = UIFactory.CreateButton(closeHolder.gameObject, "CloseAllBtn", "Close All", 62 | new Color(0.3f, 0.2f, 0.2f)); 63 | UIFactory.SetLayoutElement(closeAllBtn.Component.gameObject, minHeight: 25, minWidth: 80); 64 | closeAllBtn.Component.transform.SetSiblingIndex(closeAllBtn.Component.transform.GetSiblingIndex() - 1); 65 | closeAllBtn.OnClick += InspectorManager.CloseAllTabs; 66 | 67 | // this.UIRoot.GetComponent().enabled = false; 68 | 69 | UIFactory.SetLayoutGroup(this.ContentRoot, true, true, true, true, 4, padLeft: 5, padRight: 5); 70 | 71 | this.NavbarHolder = UIFactory.CreateGridGroup(this.ContentRoot, "Navbar", new Vector2(200, 22), new Vector2(4, 4), 72 | new Color(0.05f, 0.05f, 0.05f)); 73 | //UIFactory.SetLayoutElement(NavbarHolder, flexibleWidth: 9999, minHeight: 0, preferredHeight: 0, flexibleHeight: 9999); 74 | NavbarHolder.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 75 | 76 | this.ContentHolder = UIFactory.CreateVerticalGroup(this.ContentRoot, "ContentHolder", true, true, true, true, 0, default, 77 | new Color(0.1f, 0.1f, 0.1f)); 78 | UIFactory.SetLayoutElement(ContentHolder, flexibleHeight: 9999); 79 | ContentRect = ContentHolder.GetComponent(); 80 | 81 | this.SetActive(false); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/UI/Panels/MouseInspectorResultsPanel.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors.MouseInspectors; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Widgets.ButtonList; 4 | using UniverseLib.UI.Widgets.ScrollView; 5 | 6 | namespace UnityExplorer.UI.Panels 7 | { 8 | public class MouseInspectorResultsPanel : UEPanel 9 | { 10 | public override UIManager.Panels PanelType => UIManager.Panels.UIInspectorResults; 11 | 12 | public override string Name => "UI Inspector Results"; 13 | 14 | public override int MinWidth => 500; 15 | public override int MinHeight => 500; 16 | public override Vector2 DefaultAnchorMin => new(0.5f, 0.5f); 17 | public override Vector2 DefaultAnchorMax => new(0.5f, 0.5f); 18 | 19 | public override bool CanDragAndResize => true; 20 | public override bool NavButtonWanted => false; 21 | public override bool ShouldSaveActiveState => false; 22 | public override bool ShowByDefault => false; 23 | 24 | private ButtonListHandler dataHandler; 25 | private ScrollPool buttonScrollPool; 26 | 27 | public MouseInspectorResultsPanel(UIBase owner) : base(owner) 28 | { 29 | } 30 | 31 | public void ShowResults() 32 | { 33 | dataHandler.RefreshData(); 34 | buttonScrollPool.Refresh(true, true); 35 | } 36 | 37 | private List GetEntries() => UiInspector.LastHitObjects; 38 | 39 | private bool ShouldDisplayCell(object cell, string filter) => true; 40 | 41 | private void OnCellClicked(int index) 42 | { 43 | if (index >= UiInspector.LastHitObjects.Count) 44 | return; 45 | 46 | InspectorManager.Inspect(UiInspector.LastHitObjects[index]); 47 | } 48 | 49 | private void SetCell(ButtonCell cell, int index) 50 | { 51 | if (index >= UiInspector.LastHitObjects.Count) 52 | return; 53 | 54 | GameObject obj = UiInspector.LastHitObjects[index]; 55 | cell.Button.ButtonText.text = $"{obj.name} ({obj.transform.GetTransformPath(true)})"; 56 | } 57 | 58 | public override void SetDefaultSizeAndPosition() 59 | { 60 | base.SetDefaultSizeAndPosition(); 61 | 62 | this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 500f); 63 | this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 500f); 64 | } 65 | 66 | protected override void ConstructPanelContent() 67 | { 68 | dataHandler = new ButtonListHandler(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked); 69 | 70 | buttonScrollPool = UIFactory.CreateScrollPool(this.ContentRoot, "ResultsList", out GameObject scrollObj, 71 | out GameObject scrollContent); 72 | 73 | buttonScrollPool.Initialize(dataHandler); 74 | UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/UI/Panels/ObjectExplorerPanel.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.ObjectExplorer; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Models; 4 | using Object = UnityEngine.Object; 5 | 6 | namespace UnityExplorer.UI.Panels 7 | { 8 | public class ObjectExplorerPanel : UEPanel 9 | { 10 | public override string Name => "Object Explorer"; 11 | public override UIManager.Panels PanelType => UIManager.Panels.ObjectExplorer; 12 | 13 | public override int MinWidth => 350; 14 | public override int MinHeight => 200; 15 | public override Vector2 DefaultAnchorMin => new(0.125f, 0.175f); 16 | public override Vector2 DefaultAnchorMax => new(0.325f, 0.925f); 17 | 18 | public SceneExplorer SceneExplorer => tabPages[0] as SceneExplorer; 19 | 20 | public override bool ShowByDefault => true; 21 | public override bool ShouldSaveActiveState => true; 22 | 23 | public int SelectedTab = 0; 24 | private readonly List tabPages = new(); 25 | private readonly List tabButtons = new(); 26 | private GameObject tabGroup; 27 | 28 | public ObjectExplorerPanel(UIBase owner) : base(owner) { } 29 | 30 | public void AddTab(UITabPanel tab) 31 | { 32 | tab.ConstructUI(ContentRoot); 33 | tabPages.Add(tab); 34 | AddTabButton(tab.Name); 35 | } 36 | 37 | public void SetTab(int tabIndex) 38 | { 39 | if (SelectedTab != -1) 40 | DisableTab(SelectedTab); 41 | 42 | UIModel content = tabPages[tabIndex]; 43 | content.SetActive(true); 44 | 45 | ButtonRef button = tabButtons[tabIndex]; 46 | RuntimeHelper.SetColorBlock(button.Component, UniversalUI.EnabledButtonColor, UniversalUI.EnabledButtonColor * 1.2f); 47 | 48 | SelectedTab = tabIndex; 49 | SaveInternalData(); 50 | } 51 | 52 | private void DisableTab(int tabIndex) 53 | { 54 | tabPages[tabIndex].SetActive(false); 55 | RuntimeHelper.SetColorBlock(tabButtons[tabIndex].Component, UniversalUI.DisabledButtonColor, UniversalUI.DisabledButtonColor * 1.2f); 56 | } 57 | 58 | public override void Update() 59 | { 60 | if (SelectedTab >= 0 && SelectedTab < tabPages.Count) 61 | { 62 | tabPages[SelectedTab].Update(); 63 | } 64 | } 65 | 66 | public override string ToSaveData() 67 | { 68 | return string.Join("|", new string[] { base.ToSaveData(), SelectedTab.ToString() }); 69 | } 70 | 71 | protected override void ApplySaveData(string data) 72 | { 73 | base.ApplySaveData(data); 74 | 75 | try 76 | { 77 | int tab = int.Parse(data.Split('|').Last()); 78 | SelectedTab = tab; 79 | } 80 | catch 81 | { 82 | SelectedTab = 0; 83 | } 84 | 85 | SelectedTab = Math.Max(0, SelectedTab); 86 | SelectedTab = Math.Min(1, SelectedTab); 87 | 88 | SetTab(SelectedTab); 89 | } 90 | 91 | protected override void ConstructPanelContent() 92 | { 93 | // Tab bar 94 | tabGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "TabBar", true, true, true, true, 2, new Vector4(2, 2, 2, 2)); 95 | UIFactory.SetLayoutElement(tabGroup, minHeight: 25, flexibleHeight: 0); 96 | 97 | AddTab(new SceneExplorer(this)); 98 | AddTab(new ObjectSearch(this)); 99 | 100 | // default active state: Active 101 | this.SetActive(true); 102 | } 103 | 104 | private void AddTabButton(string label) 105 | { 106 | ButtonRef button = UIFactory.CreateButton(tabGroup, $"Button_{label}", label); 107 | 108 | int idx = tabButtons.Count; 109 | //button.onClick.AddListener(() => { SetTab(idx); }); 110 | button.OnClick += () => { SetTab(idx); }; 111 | 112 | tabButtons.Add(button); 113 | 114 | DisableTab(tabButtons.Count - 1); 115 | } 116 | 117 | private void RemoveTabButton(int index) 118 | { 119 | if (index >= 0 && index < tabButtons.Count) 120 | { 121 | ButtonRef button = tabButtons[index]; 122 | Object.Destroy(button.GameObject); 123 | tabButtons.RemoveAt(index); 124 | } 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /src/UI/Panels/OptionsPanel.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.CacheObject; 2 | using UnityExplorer.CacheObject.Views; 3 | using UnityExplorer.Config; 4 | using UniverseLib.UI; 5 | using UniverseLib.UI.Widgets.ScrollView; 6 | 7 | namespace UnityExplorer.UI.Panels 8 | { 9 | public class OptionsPanel : UEPanel, ICacheObjectController, ICellPoolDataSource 10 | { 11 | public override string Name => "Options"; 12 | public override UIManager.Panels PanelType => UIManager.Panels.Options; 13 | 14 | public override int MinWidth => 600; 15 | public override int MinHeight => 200; 16 | public override Vector2 DefaultAnchorMin => new(0.5f, 0.1f); 17 | public override Vector2 DefaultAnchorMax => new(0.5f, 0.85f); 18 | 19 | public override bool ShouldSaveActiveState => false; 20 | public override bool ShowByDefault => false; 21 | 22 | // Entry holders 23 | private readonly List configEntries = new(); 24 | 25 | // ICacheObjectController 26 | public CacheObjectBase ParentCacheObject => null; 27 | public object Target => null; 28 | public Type TargetType => null; 29 | public bool CanWrite => true; 30 | 31 | // ICellPoolDataSource 32 | public int ItemCount => configEntries.Count; 33 | 34 | public OptionsPanel(UIBase owner) : base(owner) 35 | { 36 | foreach (KeyValuePair entry in ConfigManager.ConfigElements) 37 | { 38 | CacheConfigEntry cache = new(entry.Value) 39 | { 40 | Owner = this 41 | }; 42 | configEntries.Add(cache); 43 | } 44 | 45 | foreach (CacheConfigEntry config in configEntries) 46 | config.UpdateValueFromSource(); 47 | } 48 | 49 | public void OnCellBorrowed(ConfigEntryCell cell) 50 | { 51 | } 52 | 53 | public void SetCell(ConfigEntryCell cell, int index) 54 | { 55 | CacheObjectControllerHelper.SetCell(cell, index, this.configEntries, null); 56 | } 57 | 58 | // UI Construction 59 | 60 | public override void SetDefaultSizeAndPosition() 61 | { 62 | base.SetDefaultSizeAndPosition(); 63 | 64 | Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f); 65 | } 66 | 67 | protected override void ConstructPanelContent() 68 | { 69 | // Save button 70 | 71 | UniverseLib.UI.Models.ButtonRef saveBtn = UIFactory.CreateButton(this.ContentRoot, "Save", "Save Options", new Color(0.2f, 0.3f, 0.2f)); 72 | UIFactory.SetLayoutElement(saveBtn.Component.gameObject, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 0); 73 | saveBtn.OnClick += ConfigManager.Handler.SaveConfig; 74 | 75 | // Config entries 76 | 77 | ScrollPool scrollPool = UIFactory.CreateScrollPool( 78 | this.ContentRoot, 79 | "ConfigEntries", 80 | out GameObject scrollObj, 81 | out GameObject scrollContent); 82 | 83 | scrollPool.Initialize(this); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/UI/Panels/UEPanelDragger.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI.Panels; 2 | 3 | namespace UnityExplorer.UI.Panels 4 | { 5 | public class UEPanelDragger : PanelDragger 6 | { 7 | public UEPanelDragger(PanelBase uiPanel) : base(uiPanel) { } 8 | 9 | protected override bool MouseInResizeArea(Vector2 mousePos) 10 | { 11 | return !UIManager.NavBarRect.rect.Contains(UIManager.NavBarRect.InverseTransformPoint(mousePos)) 12 | && base.MouseInResizeArea(mousePos); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/UI/UEPanelManager.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.UI.Panels; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Panels; 4 | 5 | namespace UnityExplorer.UI 6 | { 7 | public class UEPanelManager : PanelManager 8 | { 9 | public UEPanelManager(UIBase owner) : base(owner) { } 10 | 11 | protected override Vector3 MousePosition => DisplayManager.MousePosition; 12 | 13 | protected override Vector2 ScreenDimensions => new(DisplayManager.Width, DisplayManager.Height); 14 | 15 | protected override bool MouseInTargetDisplay => DisplayManager.MouseInTargetDisplay; 16 | 17 | internal void DoInvokeOnPanelsReordered() 18 | { 19 | InvokeOnPanelsReordered(); 20 | } 21 | 22 | protected override void SortDraggerHeirarchy() 23 | { 24 | base.SortDraggerHeirarchy(); 25 | 26 | // move AutoCompleter to first update 27 | if (!UIManager.Initializing && AutoCompleteModal.Instance != null) 28 | { 29 | this.draggerInstances.Remove(AutoCompleteModal.Instance.Dragger); 30 | this.draggerInstances.Insert(0, AutoCompleteModal.Instance.Dragger); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/UI/Widgets/AutoComplete/ISuggestionProvider.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI.Models; 2 | 3 | namespace UnityExplorer.UI.Widgets.AutoComplete 4 | { 5 | public interface ISuggestionProvider 6 | { 7 | InputFieldRef InputField { get; } 8 | bool AnchorToCaretPosition { get; } 9 | 10 | bool AllowNavigation { get; } 11 | 12 | void OnSuggestionClicked(Suggestion suggestion); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/UI/Widgets/AutoComplete/Suggestion.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.UI.Widgets.AutoComplete 2 | { 3 | public struct Suggestion 4 | { 5 | public readonly string DisplayText; 6 | public readonly string UnderlyingValue; 7 | 8 | public Suggestion(string displayText, string underlyingValue) 9 | { 10 | DisplayText = displayText; 11 | UnderlyingValue = underlyingValue; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/UI/Widgets/EvaluateWidget/BaseArgumentHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.UI.Widgets.AutoComplete; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Models; 4 | using UniverseLib.UI.ObjectPool; 5 | 6 | namespace UnityExplorer.UI.Widgets 7 | { 8 | public abstract class BaseArgumentHandler : IPooledObject 9 | { 10 | internal Text argNameLabel; 11 | internal InputFieldRef inputField; 12 | internal TypeCompleter typeCompleter; 13 | 14 | // IPooledObject 15 | public float DefaultHeight => 25f; 16 | public GameObject UIRoot { get; set; } 17 | 18 | public abstract void CreateSpecialContent(); 19 | 20 | public GameObject CreateContent(GameObject parent) 21 | { 22 | UIRoot = UIFactory.CreateUIObject("ArgRow", parent); 23 | UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999); 24 | UIFactory.SetLayoutGroup(UIRoot, false, false, true, true, 5); 25 | UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 26 | 27 | argNameLabel = UIFactory.CreateLabel(UIRoot, "ArgLabel", "not set", TextAnchor.MiddleLeft); 28 | UIFactory.SetLayoutElement(argNameLabel.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50); 29 | argNameLabel.horizontalOverflow = HorizontalWrapMode.Wrap; 30 | 31 | inputField = UIFactory.CreateInputField(UIRoot, "InputField", "..."); 32 | UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000); 33 | inputField.Component.lineType = InputField.LineType.MultiLineNewline; 34 | inputField.UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 35 | 36 | typeCompleter = new TypeCompleter(typeof(object), this.inputField) 37 | { 38 | Enabled = false 39 | }; 40 | 41 | CreateSpecialContent(); 42 | 43 | return UIRoot; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/UI/Widgets/EvaluateWidget/GenericArgumentHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace UnityExplorer.UI.Widgets 4 | { 5 | public class GenericArgumentHandler : BaseArgumentHandler 6 | { 7 | private Type genericArgument; 8 | 9 | public void OnBorrowed(Type genericArgument) 10 | { 11 | this.genericArgument = genericArgument; 12 | 13 | typeCompleter.Enabled = true; 14 | typeCompleter.BaseType = this.genericArgument; 15 | typeCompleter.CacheTypes(); 16 | 17 | Type[] constraints = this.genericArgument.GetGenericParameterConstraints(); 18 | 19 | StringBuilder sb = new($"{this.genericArgument.Name}"); 20 | 21 | for (int i = 0; i < constraints.Length; i++) 22 | { 23 | if (i == 0) sb.Append(' ').Append('('); 24 | else sb.Append(',').Append(' '); 25 | 26 | sb.Append(SignatureHighlighter.Parse(constraints[i], false)); 27 | 28 | if (i + 1 == constraints.Length) 29 | sb.Append(')'); 30 | } 31 | 32 | argNameLabel.text = sb.ToString(); 33 | } 34 | 35 | public void OnReturned() 36 | { 37 | this.genericArgument = null; 38 | 39 | this.typeCompleter.Enabled = false; 40 | 41 | this.inputField.Text = ""; 42 | } 43 | 44 | public Type Evaluate() 45 | { 46 | return ReflectionUtility.GetTypeByName(this.inputField.Text) 47 | ?? throw new Exception($"Could not find any type by name '{this.inputField.Text}'!"); 48 | } 49 | 50 | public override void CreateSpecialContent() 51 | { 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/UI/Widgets/GameObjects/AxisControl.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | 4 | namespace UnityExplorer.UI.Widgets 5 | { 6 | // Handles the slider and +/- buttons for a specific axis of a transform property. 7 | 8 | public class AxisControl 9 | { 10 | public readonly Vector3Control parent; 11 | 12 | public readonly int axis; 13 | public readonly Slider slider; 14 | 15 | public AxisControl(int axis, Slider slider, Vector3Control parentControl) 16 | { 17 | this.parent = parentControl; 18 | this.axis = axis; 19 | this.slider = slider; 20 | } 21 | 22 | void OnVectorSliderChanged(float value) 23 | { 24 | parent.Owner.CurrentSlidingAxisControl = value == 0f ? null : this; 25 | } 26 | 27 | void OnVectorMinusClicked() 28 | { 29 | parent.Owner.AxisControlOperation(-this.parent.Increment, this.parent, this.axis); 30 | } 31 | 32 | void OnVectorPlusClicked() 33 | { 34 | parent.Owner.AxisControlOperation(this.parent.Increment, this.parent, this.axis); 35 | } 36 | 37 | public static AxisControl Create(GameObject parent, string title, int axis, Vector3Control owner) 38 | { 39 | Text label = UIFactory.CreateLabel(parent, $"Label_{title}", $"{title}:", TextAnchor.MiddleRight, Color.grey); 40 | UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 30); 41 | 42 | GameObject sliderObj = UIFactory.CreateSlider(parent, $"Slider_{title}", out Slider slider); 43 | UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 75, flexibleWidth: 0); 44 | slider.m_FillImage.color = Color.clear; 45 | 46 | slider.minValue = -0.1f; 47 | slider.maxValue = 0.1f; 48 | 49 | AxisControl sliderControl = new(axis, slider, owner); 50 | 51 | slider.onValueChanged.AddListener(sliderControl.OnVectorSliderChanged); 52 | 53 | ButtonRef minusButton = UIFactory.CreateButton(parent, "MinusIncrementButton", "-"); 54 | UIFactory.SetLayoutElement(minusButton.GameObject, minWidth: 20, flexibleWidth: 0, minHeight: 25); 55 | minusButton.OnClick += sliderControl.OnVectorMinusClicked; 56 | 57 | ButtonRef plusButton = UIFactory.CreateButton(parent, "PlusIncrementButton", "+"); 58 | UIFactory.SetLayoutElement(plusButton.GameObject, minWidth: 20, flexibleWidth: 0, minHeight: 25); 59 | plusButton.OnClick += sliderControl.OnVectorPlusClicked; 60 | 61 | return sliderControl; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/UI/Widgets/GameObjects/ComponentCell.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.UI; 2 | using UniverseLib.UI.Models; 3 | using UniverseLib.UI.Widgets.ButtonList; 4 | 5 | namespace UnityExplorer.UI.Widgets 6 | { 7 | public class ComponentCell : ButtonCell 8 | { 9 | public Toggle BehaviourToggle; 10 | public ButtonRef DestroyButton; 11 | 12 | public Action OnBehaviourToggled; 13 | public Action OnDestroyClicked; 14 | 15 | private void BehaviourToggled(bool val) 16 | { 17 | OnBehaviourToggled?.Invoke(val, CurrentDataIndex); 18 | } 19 | 20 | private void DestroyClicked() 21 | { 22 | OnDestroyClicked?.Invoke(CurrentDataIndex); 23 | } 24 | 25 | public override GameObject CreateContent(GameObject parent) 26 | { 27 | GameObject root = base.CreateContent(parent); 28 | 29 | // Add mask to button so text doesnt overlap on Close button 30 | //this.Button.Component.gameObject.AddComponent().showMaskGraphic = true; 31 | this.Button.ButtonText.horizontalOverflow = HorizontalWrapMode.Wrap; 32 | 33 | // Behaviour toggle 34 | 35 | GameObject toggleObj = UIFactory.CreateToggle(UIRoot, "BehaviourToggle", out BehaviourToggle, out Text behavText); 36 | UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: 25); 37 | BehaviourToggle.onValueChanged.AddListener(BehaviourToggled); 38 | // put at first object 39 | toggleObj.transform.SetSiblingIndex(0); 40 | 41 | // Destroy button 42 | 43 | DestroyButton = UIFactory.CreateButton(UIRoot, "DestroyButton", "X", new Color(0.3f, 0.2f, 0.2f)); 44 | UIFactory.SetLayoutElement(DestroyButton.Component.gameObject, minHeight: 21, minWidth: 25); 45 | DestroyButton.OnClick += DestroyClicked; 46 | 47 | return root; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/UI/Widgets/GameObjects/GameObjectControls.cs: -------------------------------------------------------------------------------- 1 | using UnityExplorer.Inspectors; 2 | 3 | namespace UnityExplorer.UI.Widgets 4 | { 5 | // The base wrapper to hold a reference to the parent Inspector and the GameObjectInfo and TransformControls widgets. 6 | 7 | public class GameObjectControls 8 | { 9 | public GameObjectInspector Parent { get; } 10 | public GameObject Target => Parent.Target; 11 | 12 | public GameObjectInfoPanel GameObjectInfo { get; } 13 | 14 | public TransformControls TransformControl { get; } 15 | 16 | public GameObjectControls(GameObjectInspector parent) 17 | { 18 | this.Parent = parent; 19 | 20 | this.GameObjectInfo = new(this); 21 | this.TransformControl = new(this); 22 | } 23 | 24 | public void UpdateGameObjectInfo(bool firstUpdate, bool force) 25 | { 26 | GameObjectInfo.UpdateGameObjectInfo(firstUpdate, force); 27 | } 28 | 29 | public void UpdateVectorSlider() 30 | { 31 | TransformControl.UpdateVectorSlider(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/UI/Widgets/GameObjects/TransformControls.cs: -------------------------------------------------------------------------------- 1 | using UniverseLib.Input; 2 | using UniverseLib.UI; 3 | 4 | namespace UnityExplorer.UI.Widgets 5 | { 6 | // Handles axis change operations and holds references to the Vector3Controls for each transform property 7 | 8 | public class TransformControls 9 | { 10 | public GameObjectControls Owner { get; } 11 | GameObject Target => Owner.Target; 12 | 13 | public AxisControl CurrentSlidingAxisControl { get; set; } 14 | 15 | Vector3Control PositionControl; 16 | Vector3Control LocalPositionControl; 17 | Vector3Control RotationControl; 18 | Vector3Control ScaleControl; 19 | 20 | public TransformControls(GameObjectControls owner) 21 | { 22 | this.Owner = owner; 23 | Create(); 24 | } 25 | 26 | public void UpdateTransformControlValues(bool force) 27 | { 28 | PositionControl.Update(force); 29 | LocalPositionControl.Update(force); 30 | RotationControl.Update(force); 31 | ScaleControl.Update(force); 32 | } 33 | 34 | public void UpdateVectorSlider() 35 | { 36 | AxisControl control = CurrentSlidingAxisControl; 37 | 38 | if (control == null) 39 | return; 40 | 41 | if (!InputManager.GetMouseButton(0)) 42 | { 43 | control.slider.value = 0f; 44 | control = null; 45 | return; 46 | } 47 | 48 | AxisControlOperation(control.slider.value, control.parent, control.axis); 49 | } 50 | 51 | public void AxisControlOperation(float value, Vector3Control parent, int axis) 52 | { 53 | Transform transform = Target.transform; 54 | 55 | Vector3 vector = parent.Type switch 56 | { 57 | TransformType.Position => transform.position, 58 | TransformType.LocalPosition => transform.localPosition, 59 | TransformType.Rotation => transform.localEulerAngles, 60 | TransformType.Scale => transform.localScale, 61 | _ => throw new NotImplementedException() 62 | }; 63 | 64 | // apply vector value change 65 | switch (axis) 66 | { 67 | case 0: 68 | vector.x += value; break; 69 | case 1: 70 | vector.y += value; break; 71 | case 2: 72 | vector.z += value; break; 73 | } 74 | 75 | // set vector back to transform 76 | switch (parent.Type) 77 | { 78 | case TransformType.Position: 79 | transform.position = vector; break; 80 | case TransformType.LocalPosition: 81 | transform.localPosition = vector; break; 82 | case TransformType.Rotation: 83 | transform.localEulerAngles = vector; break; 84 | case TransformType.Scale: 85 | transform.localScale = vector; break; 86 | } 87 | 88 | UpdateTransformControlValues(false); 89 | } 90 | 91 | public void Create() 92 | { 93 | GameObject transformGroup = UIFactory.CreateVerticalGroup(Owner.Parent.Content, "TransformControls", false, false, true, true, 2, 94 | new Vector4(2, 2, 0, 0), new Color(0.1f, 0.1f, 0.1f)); 95 | UIFactory.SetLayoutElement(transformGroup, minHeight: 100, flexibleWidth: 9999); 96 | 97 | PositionControl = Vector3Control.Create(this, transformGroup, "Position:", TransformType.Position); 98 | LocalPositionControl = Vector3Control.Create(this, transformGroup, "Local Position:", TransformType.LocalPosition); 99 | RotationControl = Vector3Control.Create(this, transformGroup, "Rotation:", TransformType.Rotation); 100 | ScaleControl = Vector3Control.Create(this, transformGroup, "Scale:", TransformType.Scale); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/UI/Widgets/GameObjects/TransformType.cs: -------------------------------------------------------------------------------- 1 | namespace UnityExplorer.UI.Widgets 2 | { 3 | public enum TransformType { Position, LocalPosition, Rotation, Scale } 4 | } 5 | -------------------------------------------------------------------------------- /src/UI/Widgets/TimeScaleWidget.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using UniverseLib.UI; 3 | using UniverseLib.UI.Models; 4 | #if UNHOLLOWER 5 | using IL2CPPUtils = UnhollowerBaseLib.UnhollowerUtils; 6 | #endif 7 | #if INTEROP 8 | using IL2CPPUtils = Il2CppInterop.Common.Il2CppInteropUtils; 9 | #endif 10 | 11 | namespace UnityExplorer.UI.Widgets 12 | { 13 | internal class TimeScaleWidget 14 | { 15 | public TimeScaleWidget(GameObject parent) 16 | { 17 | Instance = this; 18 | 19 | ConstructUI(parent); 20 | 21 | InitPatch(); 22 | } 23 | 24 | static TimeScaleWidget Instance; 25 | 26 | ButtonRef lockBtn; 27 | bool locked; 28 | InputFieldRef timeInput; 29 | float desiredTime; 30 | bool settingTimeScale; 31 | 32 | public void Update() 33 | { 34 | // Fallback in case Time.timeScale patch failed for whatever reason 35 | if (locked) 36 | SetTimeScale(desiredTime); 37 | 38 | if (!timeInput.Component.isFocused) 39 | timeInput.Text = Time.timeScale.ToString("F2"); 40 | } 41 | 42 | void SetTimeScale(float time) 43 | { 44 | settingTimeScale = true; 45 | Time.timeScale = time; 46 | settingTimeScale = false; 47 | } 48 | 49 | // UI event listeners 50 | 51 | void OnTimeInputEndEdit(string val) 52 | { 53 | if (float.TryParse(val, out float f)) 54 | { 55 | SetTimeScale(f); 56 | desiredTime = f; 57 | } 58 | } 59 | 60 | void OnPauseButtonClicked() 61 | { 62 | OnTimeInputEndEdit(timeInput.Text); 63 | 64 | locked = !locked; 65 | 66 | Color color = locked ? new Color(0.3f, 0.3f, 0.2f) : new Color(0.2f, 0.2f, 0.2f); 67 | RuntimeHelper.SetColorBlock(lockBtn.Component, color, color * 1.2f, color * 0.7f); 68 | lockBtn.ButtonText.text = locked ? "Unlock" : "Lock"; 69 | } 70 | 71 | // UI Construction 72 | 73 | void ConstructUI(GameObject parent) 74 | { 75 | Text timeLabel = UIFactory.CreateLabel(parent, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey); 76 | UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 35); 77 | 78 | timeInput = UIFactory.CreateInputField(parent, "TimeInput", "timeScale"); 79 | UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40); 80 | timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit); 81 | 82 | timeInput.Text = string.Empty; 83 | timeInput.Text = Time.timeScale.ToString(); 84 | 85 | lockBtn = UIFactory.CreateButton(parent, "PauseButton", "Lock", new Color(0.2f, 0.2f, 0.2f)); 86 | UIFactory.SetLayoutElement(lockBtn.Component.gameObject, minHeight: 25, minWidth: 50); 87 | lockBtn.OnClick += OnPauseButtonClicked; 88 | } 89 | 90 | // Only allow Time.timeScale to be set if the user hasn't "locked" it or if we are setting the value internally. 91 | 92 | static void InitPatch() 93 | { 94 | 95 | try 96 | { 97 | MethodInfo target = typeof(Time).GetProperty("timeScale").GetSetMethod(); 98 | #if CPP 99 | if (IL2CPPUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(target) == null) 100 | return; 101 | #endif 102 | ExplorerCore.Harmony.Patch(target, 103 | prefix: new(AccessTools.Method(typeof(TimeScaleWidget), nameof(Prefix_Time_set_timeScale)))); 104 | } 105 | catch { } 106 | } 107 | 108 | static bool Prefix_Time_set_timeScale() 109 | { 110 | return !Instance.locked || Instance.settingTimeScale; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | --------------------------------------------------------------------------------