├── .gitattributes ├── .gitignore ├── .npmrc ├── Editor.meta ├── Editor ├── EditorUnplugged.Editor.asmdef ├── EditorUnplugged.Editor.asmdef.meta ├── EditorUnpluggedSceneUI.cs ├── EditorUnpluggedSceneUI.cs.meta ├── EditorUnpluggedUtil.cs └── EditorUnpluggedUtil.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | ## Unity ## 2 | 3 | *.cs diff=csharp text 4 | *.cginc text 5 | *.shader text 6 | 7 | # uncomment if/when unityyamlmerge is set up in git 8 | # *.mat merge=unityyamlmerge eol=lf 9 | # *.anim merge=unityyamlmerge eol=lf 10 | # *.unity merge=unityyamlmerge eol=lf 11 | # *.prefab merge=unityyamlmerge eol=lf 12 | # *.physicsMaterial2D merge=unityyamlmerge eol=lf 13 | # *.physicsMaterial merge=unityyamlmerge eol=lf 14 | # *.asset merge=unityyamlmerge eol=lf 15 | # *.meta merge=unityyamlmerge eol=lf 16 | # *.controller merge=unityyamlmerge eol=lf 17 | 18 | 19 | ## git-lfs ## 20 | 21 | #Image 22 | *.jpg filter=lfs diff=lfs merge=lfs -text 23 | *.jpeg filter=lfs diff=lfs merge=lfs -text 24 | *.png filter=lfs diff=lfs merge=lfs -text 25 | *.gif filter=lfs diff=lfs merge=lfs -text 26 | *.psd filter=lfs diff=lfs merge=lfs -text 27 | *.ai filter=lfs diff=lfs merge=lfs -text 28 | 29 | #Audio 30 | *.mp3 filter=lfs diff=lfs merge=lfs -text 31 | *.wav filter=lfs diff=lfs merge=lfs -text 32 | *.ogg filter=lfs diff=lfs merge=lfs -text 33 | 34 | #Video 35 | *.mp4 filter=lfs diff=lfs merge=lfs -text 36 | *.mov filter=lfs diff=lfs merge=lfs -text 37 | 38 | #3D Object 39 | *.FBX filter=lfs diff=lfs merge=lfs -text 40 | *.fbx filter=lfs diff=lfs merge=lfs -text 41 | *.blend filter=lfs diff=lfs merge=lfs -text 42 | *.obj filter=lfs diff=lfs merge=lfs -text 43 | 44 | #ETC 45 | *.a filter=lfs diff=lfs merge=lfs -text 46 | *.exr filter=lfs diff=lfs merge=lfs -text 47 | *.tga filter=lfs diff=lfs merge=lfs -text 48 | *.pdf filter=lfs diff=lfs merge=lfs -text 49 | *.zip filter=lfs diff=lfs merge=lfs -text 50 | *.dll filter=lfs diff=lfs merge=lfs -text 51 | *.unitypackage filter=lfs diff=lfs merge=lfs -text 52 | *.aif filter=lfs diff=lfs merge=lfs -text 53 | *.ttf filter=lfs diff=lfs merge=lfs -text 54 | *.rns filter=lfs diff=lfs merge=lfs -text 55 | *.reason filter=lfs diff=lfs merge=lfs -text 56 | *.lxo filter=lfs diff=lfs merge=lfs -text 57 | *.qbcl filter=lfs diff=lfs merge=lfs -text 58 | 59 | #Big assets 60 | *.large.asset filter=lfs diff=lfs merge=lfs -text 61 | 62 | #EOL 63 | *.sln eol=crlf 64 | *.csproj eol=crlf 65 | *.asset eol=lf 66 | *.meta eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | /[Nn]ode_modules/ 8 | 9 | # Visual Studio 2015 cache directory 10 | /.vs/ 11 | 12 | # Autogenerated VS/MD/Consulo solution and project files 13 | ExportedObj/ 14 | .consulo/ 15 | *.csproj* 16 | *.unityproj 17 | *.sln 18 | *.suo 19 | *.tmp 20 | *.user 21 | *.userprefs 22 | *.pidb 23 | *.booproj 24 | *.svd 25 | *.pdb 26 | *Cache.asset 27 | *Cache.asset.meta 28 | 29 | # Unity3D generated meta files 30 | *.pidb.meta 31 | 32 | # Unity3D Generated File On Crash Reports 33 | sysinfo.txt 34 | 35 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=http://upm.cratesmith.com:4873 -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 55eb19acfa03dfe44b54d8def075204b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/EditorUnplugged.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EditorUnplugged.Editor", 3 | "references": [], 4 | "includePlatforms": [ 5 | "Editor" 6 | ], 7 | "excludePlatforms": [], 8 | "allowUnsafeCode": false, 9 | "overrideReferences": false, 10 | "precompiledReferences": [], 11 | "autoReferenced": true, 12 | "defineConstraints": [], 13 | "versionDefines": [] 14 | } -------------------------------------------------------------------------------- /Editor/EditorUnplugged.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 49e60509da558754e8c41a7942d18afe 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/EditorUnpluggedSceneUI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEditor.Compilation; 4 | using UnityEngine; 5 | 6 | namespace EditorUnplugged 7 | { 8 | [InitializeOnLoad] 9 | public class EditorUnpluggedSceneUI 10 | { 11 | static GUIStyle s_LabelStyle; 12 | static GUIStyle s_ToggleStyle; 13 | static GUIStyle s_TextFieldStyle; 14 | static GUIStyle s_TimeLabelStyle; 15 | 16 | static double s_LastRepaint = -1; 17 | static bool s_MousePanning; 18 | 19 | static Texture2D s_TimeIcon; 20 | static Texture2D s_GreenLightIcon; 21 | static Texture2D s_YellowLightIcon; 22 | static Texture2D s_RedLightIcon; 23 | static Texture2D s_ScriptIcon; 24 | static Texture2D s_CompileIcon; 25 | static Texture2D s_TextureIcon; 26 | static Texture2D s_LightingIcon; 27 | 28 | static EditorUnpluggedSceneUI() 29 | { 30 | #if UNITY_2019_1_OR_NEWER 31 | SceneView.duringSceneGui += OnSceneGUI; 32 | #else 33 | SceneView.onSceneGUIDelegate += OnSceneGUI; 34 | #endif 35 | CompilationPipeline.assemblyCompilationStarted += OnCompileStart; 36 | EditorApplication.update += OnUpdate; 37 | } 38 | 39 | static void OnUpdate() 40 | { 41 | if (EditorApplication.timeSinceStartup - s_LastRepaint > 60) 42 | { 43 | SceneView.RepaintAll(); 44 | } 45 | } 46 | 47 | static void OnCompileStart(string _obj) 48 | { 49 | SceneView.RepaintAll(); 50 | } 51 | 52 | static void OnSceneGUI(SceneView _sceneview) 53 | { 54 | // don't repaint if we're panning 55 | if (Tools.current == Tool.View || Tools.current== Tool.Custom) 56 | { 57 | return; 58 | } 59 | 60 | if (Event.current.type == EventType.MouseDown && Event.current.button == 1) 61 | { 62 | s_MousePanning = true; 63 | } 64 | 65 | if (s_MousePanning) 66 | { 67 | if (Event.current.type == EventType.MouseLeaveWindow || Event.current.type==EventType.MouseUp && Event.current.button == 1) 68 | { 69 | EditorApplication.delayCall += () => s_MousePanning = false; // just to do this outside of gui events 70 | } 71 | return; 72 | } 73 | 74 | if (s_LabelStyle==null) 75 | { 76 | s_LabelStyle = new GUIStyle("Label"); 77 | } 78 | 79 | if (s_ToggleStyle == null) 80 | { 81 | s_ToggleStyle = new GUIStyle("Toggle"); 82 | } 83 | 84 | if (s_TextFieldStyle == null) 85 | { 86 | s_TextFieldStyle = new GUIStyle("MiniTextField"); 87 | } 88 | 89 | if (s_TimeLabelStyle == null) 90 | { 91 | s_TimeLabelStyle = new GUIStyle("helpbox"); 92 | s_TimeLabelStyle.alignment = TextAnchor.MiddleCenter; 93 | s_TimeLabelStyle.padding.top = 1; 94 | s_TimeLabelStyle.padding.bottom = 1; 95 | } 96 | 97 | if (s_TimeIcon == null) 98 | { 99 | s_TimeIcon = EditorGUIUtility.FindTexture("TestStopwatch"); 100 | } 101 | 102 | if (s_GreenLightIcon == null) 103 | { 104 | s_GreenLightIcon = EditorGUIUtility.FindTexture("winbtn_mac_max"); 105 | } 106 | 107 | if (s_YellowLightIcon == null) 108 | { 109 | s_YellowLightIcon = EditorGUIUtility.FindTexture("winbtn_mac_min"); 110 | } 111 | 112 | if (s_RedLightIcon == null) 113 | { 114 | s_RedLightIcon = EditorGUIUtility.FindTexture("winbtn_mac_close"); 115 | } 116 | 117 | if (s_ScriptIcon == null) 118 | { 119 | s_ScriptIcon = EditorGUIUtility.FindTexture("cs Script Icon"); 120 | } 121 | 122 | if (s_CompileIcon == null) 123 | { 124 | s_CompileIcon = EditorGUIUtility.FindTexture("WaitSpin00"); 125 | } 126 | 127 | if (s_TextureIcon == null) 128 | { 129 | s_TextureIcon = EditorGUIUtility.FindTexture("animationdopesheetkeyframe"); 130 | } 131 | 132 | if (s_LightingIcon == null) 133 | { 134 | s_LightingIcon = EditorGUIUtility.FindTexture("Main Light Gizmo"); 135 | } 136 | 137 | Handles.BeginGUI(); 138 | GUILayout.BeginArea(new Rect(5, 5, Screen.width, 22)); 139 | using (new GUILayout.HorizontalScope( GUILayout.ExpandWidth(false), GUILayout.Height(20))) 140 | { 141 | using (new GUILayout.HorizontalScope("HelpBox", GUILayout.ExpandWidth(false), GUILayout.Width(1))) 142 | { 143 | { 144 | var r = GUILayoutUtility.GetRect(12,12); 145 | GUI.Label(new Rect(r.xMin-4, r.yMin-1, r.height+8, r.height+8), new GUIContent(s_TimeIcon, "Session duration")); 146 | } 147 | var timespan = TimeSpan.FromSeconds(EditorApplication.timeSinceStartup); 148 | GUILayout.Label($"{timespan.Hours.ToString("00")}h {timespan.Minutes.ToString("00")}m", s_LabelStyle, GUILayout.ExpandWidth(false)); 149 | } 150 | 151 | if (SystemInfo.batteryStatus != BatteryStatus.Unknown) 152 | { 153 | using (new GUILayout.HorizontalScope("HelpBox", GUILayout.ExpandWidth(false), GUILayout.Width(1))) 154 | { 155 | { 156 | var r = GUILayoutUtility.GetRect(12,12); r.yMin = r.yMin + 4; 157 | if (SystemInfo.batteryLevel > .6f) 158 | { 159 | GUI.DrawTexture(r, s_GreenLightIcon, ScaleMode.ScaleToFit, true, 1); 160 | }else if (SystemInfo.batteryLevel > .3f) 161 | { 162 | GUI.DrawTexture(r, s_YellowLightIcon,ScaleMode.ScaleToFit, true, 1); 163 | } 164 | else 165 | { 166 | GUI.DrawTexture(r, s_RedLightIcon,ScaleMode.ScaleToFit, true, 1); 167 | } 168 | } 169 | var current = SystemInfo.batteryLevel * 100f; 170 | var used = EditorUnpluggedUtil.BatteryUsed * 100f; 171 | GUILayout.Label(SystemInfo.batteryStatus.ToString(), s_LabelStyle, GUILayout.ExpandWidth(false)); 172 | GUILayout.Label($"{current.ToString("F1")}%", s_LabelStyle, GUILayout.ExpandWidth(false)); 173 | GUILayout.Label(new GUIContent($"{(used < 0 ? "+" : "-")}{Mathf.Abs(used).ToString("F1")}%","Percent used this session"), s_TimeLabelStyle, GUILayout.Width(55)); 174 | 175 | var timeRemainingA = EditorUnpluggedUtil.BatteryTimeRemainingShortSample; 176 | var timeRemainingB = EditorUnpluggedUtil.BatteryTimeRemainingLongSample; 177 | var minRemaining = timeRemainingA < timeRemainingB ? timeRemainingA : timeRemainingB; 178 | var maxRemaining = timeRemainingA >= timeRemainingB ? timeRemainingA : timeRemainingB; 179 | 180 | if (!float.IsInfinity(minRemaining)) 181 | { 182 | var timespan = TimeSpan.FromSeconds(minRemaining); 183 | if(timespan.Days < 1) GUILayout.Label(new GUIContent($"{timespan.Hours.ToString("00")}h {timespan.Minutes.ToString("00")}m", "Estimated Remaining (Min)"), s_TimeLabelStyle, GUILayout.Width(60)); 184 | 185 | if (!float.IsInfinity(maxRemaining) && !Mathf.Approximately(maxRemaining, minRemaining)) 186 | { 187 | GUILayout.Label("->"); 188 | var maxtimespan = TimeSpan.FromSeconds(maxRemaining); 189 | if (maxtimespan.Days < 1) 190 | { 191 | GUILayout.Label(new GUIContent($"{maxtimespan.Hours.ToString("00")}h {maxtimespan.Minutes.ToString("00")}m","Estimated Remaining (Max)"), s_TimeLabelStyle, GUILayout.Width(60)); 192 | } 193 | } 194 | GUILayout.Label("@"); 195 | 196 | var rate1h = EditorUnpluggedUtil.BatteryRateShortSample*100f*60f*60f; 197 | if(rate1h < 1000f) GUILayout.Label(new GUIContent($"{rate1h.ToString("F1")}/h", "Recent usage percent per hour"), s_TimeLabelStyle, GUILayout.Width(55)); 198 | } 199 | } 200 | } 201 | 202 | using (new GUILayout.HorizontalScope("HelpBox",GUILayout.ExpandWidth(false), GUILayout.Width(1))) 203 | { 204 | EditorUnpluggedUtil.FrameLimiter = GUILayout.Toggle(EditorUnpluggedUtil.FrameLimiter, "Fps limit", s_ToggleStyle, GUILayout.ExpandWidth(false)); 205 | if (int.TryParse(EditorGUILayout.DelayedTextField(EditorUnpluggedUtil.FrameLimiterFPS.ToString(), s_TextFieldStyle, GUILayout.Width(20)), 206 | out var newTargetFps)) 207 | { 208 | EditorUnpluggedUtil.FrameLimiterFPS = newTargetFps; 209 | } 210 | } 211 | 212 | using (new GUILayout.HorizontalScope("HelpBox",GUILayout.ExpandWidth(false), GUILayout.Width(1))) 213 | { 214 | { 215 | var r = GUILayoutUtility.GetRect(12,12); 216 | GUI.Label(new Rect(r.xMin-4, r.yMin-1, r.height+8, r.height+8), new GUIContent(s_ScriptIcon, "Asset Reload/Script Compile")); 217 | } 218 | GUILayout.Label(EditorUnpluggedUtil.CompileCount.ToString(), s_LabelStyle, GUILayout.ExpandWidth(false)); 219 | EditorUnpluggedUtil.AutoRefresh = GUILayout.Toggle(EditorUnpluggedUtil.AutoRefresh, "Auto", s_ToggleStyle, GUILayout.ExpandWidth(false)); 220 | if (!EditorUnpluggedUtil.AutoRefresh) 221 | { 222 | if (GUILayout.Button(new GUIContent("Ctrl-R", "Reimport assets/compile"), "minibutton")) 223 | { 224 | AssetDatabase.Refresh(); 225 | } 226 | } 227 | 228 | if (EditorApplication.isCompiling) 229 | { 230 | var r = GUILayoutUtility.GetRect(12,12); 231 | GUI.Label(new Rect(r.xMin-4, r.yMin-1, r.height+8, r.height+8), new GUIContent(s_CompileIcon, "Compiling! (how did you see this tooltip!?)")); 232 | } 233 | 234 | if (EditorUnpluggedUtil.LastCompileDuration > 0 && EditorUnpluggedUtil.CompileCount > 0) 235 | { 236 | GUILayout.Label(new GUIContent($"{EditorUnpluggedUtil.LastCompileDuration.ToString("00.0")}s", "Last Script Reload Duration"), s_TimeLabelStyle, GUILayout.Width(40)); 237 | } 238 | } 239 | 240 | using (new GUILayout.HorizontalScope("HelpBox", GUILayout.ExpandWidth(false), GUILayout.Width(1))) 241 | { 242 | var r = GUILayoutUtility.GetRect(12,12); 243 | GUI.Label(new Rect(r.xMin-4, r.yMin-1, r.height+8, r.height+8), new GUIContent(s_TextureIcon, "When to compress assets")); 244 | EditorUnpluggedUtil.CompressOnImport = EditorGUILayout.Popup(EditorUnpluggedUtil.CompressOnImport ? 0 : 1, 245 | new[] {"On Build", "On Import"}, GUILayout.Width(70))==1; 246 | } 247 | 248 | using (new GUILayout.HorizontalScope("HelpBox", GUILayout.ExpandWidth(false), GUILayout.Width(1))) 249 | { 250 | var r = GUILayoutUtility.GetRect(12,12); 251 | GUI.Label(new Rect(r.xMin-4, r.yMin-1, r.height+8, r.height+8), new GUIContent(s_LightingIcon, "Lightmapping workflow")); 252 | Lightmapping.giWorkflowMode = (Lightmapping.GIWorkflowMode)EditorGUILayout.EnumPopup(Lightmapping.giWorkflowMode,GUILayout.Width(75)); 253 | if (Lightmapping.giWorkflowMode == Lightmapping.GIWorkflowMode.OnDemand) 254 | { 255 | if (GUILayout.Button(new GUIContent("Bake", "Bake lightmaps"), "minibutton")) 256 | { 257 | Lightmapping.BakeAsync(); 258 | } 259 | } 260 | } 261 | } 262 | GUILayout.EndArea(); 263 | Handles.EndGUI(); 264 | 265 | s_LastRepaint = EditorApplication.timeSinceStartup; 266 | } 267 | } 268 | } -------------------------------------------------------------------------------- /Editor/EditorUnpluggedSceneUI.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a4c64374e34b07a45a7c335e3e53487d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/EditorUnpluggedUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEditor.Callbacks; 5 | using UnityEditor.Compilation; 6 | using UnityEngine; 7 | 8 | namespace EditorUnplugged 9 | { 10 | public static class EditorUnpluggedUtil 11 | { 12 | public static double LastCompileDuration => LastCompileTimeEnd - LastCompileTimeStart; 13 | 14 | const string EditorPrefs_CrunchOnImport = "kCompressTexturesOnImport"; 15 | 16 | public static bool CompressOnImport 17 | { 18 | get => EditorPrefs.GetBool(EditorPrefs_CrunchOnImport, false); 19 | set => EditorPrefs.SetBool(EditorPrefs_CrunchOnImport, value); 20 | } 21 | 22 | const string EditorPrefs_AutoRefresh = "kAutoRefresh"; 23 | 24 | public static bool AutoRefresh 25 | { 26 | get => EditorPrefs.GetBool(EditorPrefs_AutoRefresh, false); 27 | set => EditorPrefs.SetBool(EditorPrefs_AutoRefresh, value); 28 | } 29 | 30 | const string EditorPrefs_CompileCount = "EditorUnpluggedUtil.CompileCount"; 31 | public static int CompileCount 32 | { 33 | get => EditorPrefs.GetInt(EditorPrefs_CompileCount, 0); 34 | private set => EditorPrefs.SetInt(EditorPrefs_CompileCount, value); 35 | } 36 | 37 | const string EditorPrefs_LastReloadTime = "EditorUnpluggedUtil.LastReloadTime"; 38 | public static double LastReloadTime 39 | { 40 | get => EditorPrefs_GetDouble(EditorPrefs_LastReloadTime, 0); 41 | private set => EditorPrefs_SetDouble(EditorPrefs_LastReloadTime, value); 42 | } 43 | 44 | static double EditorPrefs_GetDouble(string _editorPrefsLastReloadTime, int _default) 45 | { 46 | return double.TryParse(EditorPrefs.GetString(_editorPrefsLastReloadTime), out var result) 47 | ? result 48 | : _default; 49 | } 50 | 51 | static void EditorPrefs_SetDouble(string _editorPrefsLastReloadTime, double _value) 52 | { 53 | EditorPrefs.SetString(_editorPrefsLastReloadTime, _value.ToString()); 54 | } 55 | 56 | const string EDITORPREFS_LastCompileTimeStart = "ScriptExecutionOrder.LastCompileTimeStart"; 57 | public static double LastCompileTimeStart 58 | { 59 | get => EditorPrefs_GetDouble(EDITORPREFS_LastCompileTimeStart, 0); 60 | private set { EditorPrefs_SetDouble(EDITORPREFS_LastCompileTimeStart, value);} 61 | } 62 | 63 | const string EDITORPREFS_LastCompileTimeEnd = "ScriptExecutionOrder.LastCompileTimeEnd"; 64 | public static double LastCompileTimeEnd 65 | { 66 | get => EditorPrefs_GetDouble(EDITORPREFS_LastCompileTimeEnd, 0); 67 | private set { EditorPrefs_SetDouble(EDITORPREFS_LastCompileTimeEnd, value);} 68 | } 69 | 70 | const string EditorPrefs_BatterySample1Time = "EditorUnpluggedUtil.BatterySample1Time"; 71 | static double BatterySample1Time 72 | { 73 | get => EditorPrefs_GetDouble(EditorPrefs_BatterySample1Time, 0); 74 | set => EditorPrefs_SetDouble(EditorPrefs_BatterySample1Time, value); 75 | } 76 | 77 | const string EditorPrefs_BatterySample2Time = "EditorUnpluggedUtil.BatterySample2Time"; 78 | static double BatterySample2Time 79 | { 80 | get => EditorPrefs_GetDouble(EditorPrefs_BatterySample2Time, 0); 81 | set => EditorPrefs_SetDouble(EditorPrefs_BatterySample2Time, value); 82 | } 83 | 84 | const string EditorPrefs_BatterySample1 = "EditorUnpluggedUtil.BatterySample1"; 85 | static float BatterySample1 86 | { 87 | get => EditorPrefs.GetFloat(EditorPrefs_BatterySample1, 0); 88 | set => EditorPrefs.SetFloat(EditorPrefs_BatterySample1, value); 89 | } 90 | 91 | const string EditorPrefs_BatterySample2 = "EditorUnpluggedUtil.BatterySample2"; 92 | static float BatterySample2 93 | { 94 | get => EditorPrefs.GetFloat(EditorPrefs_BatterySample2, 0); 95 | set => EditorPrefs.SetFloat(EditorPrefs_BatterySample2, value); 96 | } 97 | 98 | const string EditorPrefs_BatteryRateLongSample = "EditorUnpluggedUtil.BatteryRateLongSample"; 99 | public static double BatteryRateLongSample 100 | { 101 | get => EditorPrefs_GetDouble(EditorPrefs_BatteryRateLongSample, 0); 102 | private set => EditorPrefs_SetDouble(EditorPrefs_BatteryRateLongSample, value); 103 | } 104 | 105 | const string EditorPrefs_StartBattery = "EditorUnpluggedUtil.StartBattery"; 106 | public static float StartBattery 107 | { 108 | get => EditorPrefs.GetFloat(EditorPrefs_StartBattery, 1); 109 | private set => EditorPrefs.SetFloat(EditorPrefs_StartBattery, value); 110 | } 111 | 112 | const string EditorPrefs_WasCompiling = "EditorUnpluggedUtil.WasCompiling"; 113 | public static bool WasCompiling 114 | { 115 | get => EditorPrefs.GetBool(EditorPrefs_WasCompiling, false); 116 | private set => EditorPrefs.SetBool(EditorPrefs_WasCompiling, value); 117 | } 118 | 119 | public static float CurrentBattery => SystemInfo.batteryLevel >= 0f ? SystemInfo.batteryLevel : 1f; 120 | public static float BatteryUsed => StartBattery - SystemInfo.batteryLevel; 121 | 122 | 123 | public static bool FrameLimiter 124 | { 125 | get => QualitySettings.vSyncCount == 0; 126 | set => QualitySettings.vSyncCount = value?0:1; 127 | } 128 | 129 | public static int FrameLimiterFPS 130 | { 131 | get => Application.targetFrameRate; 132 | set => Application.targetFrameRate = value; 133 | } 134 | 135 | public static double BatteryRateShortSample => (CurrentBattery - BatterySample2) / (EditorApplication.timeSinceStartup - BatterySample2Time); 136 | 137 | public static float BatteryTimeRemainingShortSample => BatteryRateShortSample < -0.00001 ? Mathf.Max(0,(float)(-SystemInfo.batteryLevel/BatteryRateShortSample)):float.PositiveInfinity; 138 | 139 | public static float BatteryTimeRemainingLongSample => BatteryRateLongSample < -0.00001 ? Mathf.Max(0,(float)(-SystemInfo.batteryLevel/BatteryRateLongSample)):float.PositiveInfinity; 140 | 141 | [InitializeOnLoadMethod()] 142 | static void InitializeOnLoad() 143 | { 144 | if (LastReloadTime > 0 && EditorApplication.timeSinceStartup < LastReloadTime) 145 | { 146 | OnEditorLaunch(); 147 | } 148 | LastReloadTime = EditorApplication.timeSinceStartup; 149 | 150 | EditorApplication.update += OnUpdate; 151 | } 152 | 153 | [DidReloadScripts(9999)] 154 | static void OnReloadScripts() 155 | { 156 | if (WasCompiling) 157 | { 158 | WasCompiling = false; 159 | ++CompileCount; 160 | LastCompileTimeEnd = EditorApplication.timeSinceStartup; 161 | // Debug.Log($"Complication ended at {EditorApplication.timeSinceStartup} duration={LastCompileDuration}"); 162 | } 163 | CompilationPipeline.assemblyCompilationStarted += OnCompileStarted; 164 | } 165 | 166 | const float BatterySampleDelay = 30f; 167 | 168 | static void OnUpdate() 169 | { 170 | if (EditorApplication.timeSinceStartup - BatterySample1Time >= BatterySampleDelay && !Mathf.Approximately(BatterySample1,CurrentBattery)) 171 | { 172 | BatterySample2Time = BatterySample1Time; 173 | BatterySample2 = BatterySample1; 174 | 175 | BatterySample1Time = EditorApplication.timeSinceStartup; 176 | BatterySample1 = CurrentBattery; 177 | 178 | BatteryRateLongSample = BatteryRateShortSample*0.9 + BatteryRateLongSample*0.1; 179 | } 180 | } 181 | 182 | static void OnCompileStarted(string _) 183 | { 184 | if (!WasCompiling) 185 | { 186 | LastCompileTimeStart = EditorApplication.timeSinceStartup; 187 | // Debug.Log($"Complication started at {EditorApplication.timeSinceStartup}"); 188 | WasCompiling = true; 189 | 190 | ClosePackageManagerWindows(); 191 | } 192 | } 193 | 194 | static void ClosePackageManagerWindows() 195 | { 196 | // close the package manager to save battery and 10s of compile time 197 | var pmwt = GetType("UnityEditor.PackageManager.UI.PackageManagerWindow"); 198 | var pmw = (EditorWindow[]) Resources.FindObjectsOfTypeAll(pmwt); 199 | if (pmw.Length <= 0) 200 | { 201 | return; 202 | } 203 | 204 | Debug.Log("Closing package manager windows to avoid excessive compile time"); 205 | foreach (var window in pmw) 206 | { 207 | window.Close(); 208 | } 209 | } 210 | 211 | static Type GetType(string name) 212 | { 213 | Type type = null; 214 | var assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); 215 | for (int i = 0; i < assemblies.Length; i++) 216 | { 217 | type = assemblies[i].GetType(name); 218 | if (type != null) break; 219 | } 220 | return type; 221 | } 222 | 223 | static void OnEditorLaunch() 224 | { 225 | Debug.Log("Editor Launch Detected"); 226 | CompileCount = 0; 227 | BatterySample1 = BatterySample2 = StartBattery = SystemInfo.batteryLevel; 228 | LastCompileTimeStart = LastCompileTimeStart = 0; 229 | BatterySample1Time = 0; 230 | FrameLimiterFPS = 30; 231 | Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand; 232 | Lightmapping.ForceStop(); 233 | } 234 | } 235 | } -------------------------------------------------------------------------------- /Editor/EditorUnpluggedUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dfaf0f4b74e426643b2f333d3a7c126e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Cratesmith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 578f303d30259fc429cfdf04f55ee17d 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Editor Unplugged 3 | ![image](https://user-images.githubusercontent.com/4616107/67143439-c8e20e00-f2ae-11e9-9853-6c1e900ae5f6.png)A battery saving toolkit to make the Unity3d editor more laptop battery friendly. 4 | 5 | 6 | ## Quick Start 7 | 8 | ### Installation 9 | 10 | 11 | Add the following lines to your project's `manifest.json` (in the packages folder of your project) 12 | 13 | "scopedRegistries": [ 14 | { 15 | "name": "Cratesmith", 16 | "scopes": [ 17 | "com.cratesmith" 18 | ], 19 | "url": "http://upm.cratesmith.com:4873" 20 | } 21 | ] 22 | 23 | Your `manifest.json` should look something like this 24 | 25 | { 26 | "scopedRegistries": [ 27 | { 28 | "name": "Cratesmith", 29 | "scopes": [ 30 | "com.cratesmith" 31 | ], 32 | "url": "http://upm.cratesmith.com:4873" 33 | } 34 | ], 35 | 36 | "dependencies": { 37 | "com.unity.2d.sprite": "1.0.0", 38 | "com.unity.2d.tilemap": "1.0.0", 39 | "com.unity.cinemachine": "2.3.4", 40 | ... etc .... 41 | } 42 | } 43 | 44 | Select **Window > Package Manager** from the menu 45 | 46 | Find **Cratesmith.Editor Unplugged** in the list (you may need to wait for it to refresh packages first) and click **Install** 47 | ![editorunplugged-packagewindow](https://user-images.githubusercontent.com/4616107/67143273-25442e00-f2ad-11e9-9fa5-6463a23cbd17.gif) 48 | ## What EditorUnplugged does 49 | It adds a nifty toolbar into your scene view that helps you track battery usage and control features that affect battery life! 50 | 51 | 52 | 53 | ### Session time counter 54 | ![image](https://user-images.githubusercontent.com/4616107/67143849-1f514b80-f2b3-11e9-84f2-b374db761419.png) 55 | This shows how long unity has been running since startup. 56 | 57 | 58 | 59 | ### Battery status 60 | ![editorunplugged-battery](https://user-images.githubusercontent.com/4616107/67143886-9b4b9380-f2b3-11e9-82ce-0935cc07e625.gif) 61 | Information about how the battery's current status and usage trends. 62 | Check the tooltips for detailed descriptions on each field. 63 | 64 | 65 | 66 | 67 | 68 | ### FPS limiter (recommended at all times!) 69 | ![image](https://user-images.githubusercontent.com/4616107/67143897-ccc45f00-f2b3-11e9-8073-6db5d8978efb.png) 70 | Restricts the game's framerate in the Unity editor if enabled. 71 | *(Setting this to 15 or 30 will significantly reduce GPU related battery use!)* 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | ### Manual Reload/Recompile (recommended when coding!) 80 | ![image](https://user-images.githubusercontent.com/4616107/67143917-f7aeb300-f2b3-11e9-8b90-757814a17357.png) 81 | Adds a toggle for easily switching Auto-Refresh assets on and off. It also shows how many times scripts have been reloaded this session, and how long the last script reload took. 82 | 83 | When auto is disabled press **ctrl-r** (or press the button) to recompile or load changed assets. 84 | 85 | *(Setting disabling auto significantly cuts down on CPU usage from unnecessary reloads when editing scripts)* 86 | 87 | ### Closes the package manager window when reloading scripts 88 | This is an odd one... but currently the package manager window in 2018/19 has a habit of making reload times much longer if it's open (even in a tab!). So just as a safety it'll now automatically be closed the moment a compile starts. 89 | 90 | 91 | 92 | ### When to compress assets ('On Build' recommended!) 93 | ![image](https://user-images.githubusercontent.com/4616107/67143932-2fb5f600-f2b4-11e9-8deb-3767f982b546.png) 94 | This drop down lets you easily control when assets get compressed for builds. 95 | *(Setting 'On Build' will make build times longer if there are new assets since the last build, but saves quite a lot of CPU usage)* 96 | 97 | 98 | 99 | 100 | 101 | 102 | ### Lightmapping ('On Demand' is strongly recommended!) 103 | ![image](https://user-images.githubusercontent.com/4616107/67143946-6b50c000-f2b4-11e9-9424-60f566b23259.png) 104 | This drop down allows you to quickly switch between different lightmapping behaviours. 105 | *(Setting 'On Demand' prevents the lightmapping engine recalculating Baked/Realtime GI when the scene is changed, which can be **very** GPU and CPU intensive)* 106 | 107 | 108 | ## What EditorUnplugged doesn't do 109 | ![windows-battery](https://user-images.githubusercontent.com/4616107/67144008-1ceff100-f2b5-11e9-8d42-f2bee71bb52b.gif) 110 | 111 | This plugin doesn't alter your power settings or other applications at all. To get any real savings you should close any programs you aren't using (especially anything using the GPU!) 112 | 113 | 114 | It also doesn't do anything at all outside of the editor. (Optimizing your game for battery is up to you!) 115 | 116 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0be99fd49f23b184d8a258300f6b19b9 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.cratesmith.editorunplugged", 3 | "displayName": "Cratesmith.EditorUnplugged", 4 | "description": "A battery saving toolkit to make the unity editor more laptop battery friendly.", 5 | "version": "0.0.2", 6 | "unity": "2018.3", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/Cratesmith/Cratesmith.EditorUnplugged.git" 11 | }, 12 | "src": "Packages/Cratesmith.EditorUnplugged", 13 | "author": "Kieran Lord (https://github.com/cratesmith)" 14 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3ed260e7317bcdc4bbcbeac121ef188a 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------