From 86141a61197564573f7053ebd6ef7c8cee0c840f Mon Sep 17 00:00:00 2001 From: Jonathan Bayer Date: Fri, 9 Oct 2020 15:29:30 -0400 Subject: [PATCH] Fixed performance issue in the editor when FocusFollowsMouse was active Two problems: GetComponent was being called on every part EditorActionGroups.Instance.ClearSelection was being called every time through Update() Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves --- Changelog.txt | 7 ++ ClickThroughBlocker.version | 2 +- ClickThroughBlocker/AssemblyVersion.cs | 2 +- ClickThroughBlocker/CBTMonitor.cs | 106 +++++++++++++----- ClickThroughBlocker/ClearInputLocks.cs | 3 + .../ClickThroughBlocker.csproj | 7 +- ClickThroughBlocker/OneTimePopup.cs | 44 +++++++- ClickThroughBlocker/RegisterToolbar.cs | 29 ++++- ClickThroughBlocker/Settings.cs | 2 +- .../ClickThroughBlocker.version | 2 +- .../000_ClickThroughBlocker/changelog.cfg | 16 ++- buildRelease.bat | 1 + changelog.cfg | 14 ++- deploy.bat | 6 +- 14 files changed, 191 insertions(+), 50 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index d63cf02..c55455b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,12 @@ ChangeLog +0.1.10.14 + Fixed performance issue in the editor when FocusFollowsMouse was active + Two problems: + GetComponent was being called on every part + EditorActionGroups.Instance.ClearSelection was being called every time through Update() + Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves + 0.1.10.13 Fixed inputlocks not being cleared when canceling the window Added mode toggle on new button to allow toggling between different modes during the game diff --git a/ClickThroughBlocker.version b/ClickThroughBlocker.version index 439eb7e..919f5a3 100644 --- a/ClickThroughBlocker.version +++ b/ClickThroughBlocker.version @@ -10,7 +10,7 @@ "MAJOR": 0, "MINOR": 1, "PATCH": 10, - "BUILD": 13 + "BUILD": 14 }, "KSP_VERSION_MIN": { "MAJOR": 1, diff --git a/ClickThroughBlocker/AssemblyVersion.cs b/ClickThroughBlocker/AssemblyVersion.cs index aad370f..b5b7c63 100644 --- a/ClickThroughBlocker/AssemblyVersion.cs +++ b/ClickThroughBlocker/AssemblyVersion.cs @@ -5,4 +5,4 @@ using System.Reflection; - [assembly: AssemblyVersion("0.1.10.12")] + [assembly: AssemblyVersion("0.1.10.14")] diff --git a/ClickThroughBlocker/CBTMonitor.cs b/ClickThroughBlocker/CBTMonitor.cs index 506aadc..9460217 100644 --- a/ClickThroughBlocker/CBTMonitor.cs +++ b/ClickThroughBlocker/CBTMonitor.cs @@ -1,67 +1,113 @@ using UnityEngine; +using System.Collections.Generic; using KSP.UI.Screens; + #if !DUMMY namespace ClickThroughFix { + internal class PartEAPS + { + + internal uint persistentId; + internal Part p; + internal EditorActionPartSelector eaps; + + internal PartEAPS(Part p) + { + this.persistentId = p.persistentId; + this.p = p; + this.eaps = p.GetComponent(); + } + } + [KSPAddon(KSPAddon.Startup.SpaceCentre, true)] class CBTMonitor : MonoBehaviour { + static internal Dictionary partEAPSDict; + void Start() { DontDestroyOnLoad(this); - GameEvents.onGameSceneLoadRequested.Add(onGameSceneLoadRequested); + GameEvents.onGameSceneLoadRequested.Add(onGameSceneLoadRequested); + GameEvents.onEditorShipModified.Add(_onEditorShipModified); + GameEvents.onLevelWasLoadedGUIReady.Add(onLevelWasLoadedGUIReady); + ClickThruBlocker.CTBWin.activeBlockerCnt = 0; + partEAPSDict = new Dictionary(); } void onGameSceneLoadRequested(GameScenes gs) { ClickThruBlocker.CTBWin.activeBlockerCnt = 0; + partEAPSDict.Clear(); + } + + void ScanParts(List parts) + { + for (int i = parts.Count - 1; i >= 0; i--) + { + if (!partEAPSDict.ContainsKey(parts[i].persistentId)) + { + partEAPSDict.Add(parts[i].persistentId, new PartEAPS(parts[i])); + } + } + } + void _onEditorShipModified(ShipConstruct sc) + { + if (sc != null && sc.parts != null) + { + ScanParts(sc.parts); + } + } + + void onLevelWasLoadedGUIReady(GameScenes gs) + { + if (HighLogic.LoadedSceneIsEditor) + { + if (EditorLogic.fetch != null && EditorLogic.fetch.ship != null && EditorLogic.fetch.ship.Parts != null) + ScanParts(EditorLogic.fetch.ship.Parts); + } } // this whole mess below is to work around a stock bug. - // The bug is that the editor ignores the lock when the Action Group pane is show. + // The bug is that the editor ignores the lock when the Action Group pane is shown. // So we have to each time, clear all locks and then reset those which were active when // the mouse moved over a protected window void Update() { - if (HighLogic.LoadedSceneIsEditor && ClearInputLocks.focusFollowsclick) // || - //(!HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick && !HighLogic.LoadedSceneIsEditor)) + if (HighLogic.LoadedSceneIsEditor && ClearInputLocks.focusFollowsclick) return; - + if (ClickThruBlocker.CTBWin.activeBlockerCnt > 0) { - if (ClickThruBlocker.CTBWin.activeBlockerCnt > 0) - { - //Log.Info("Setting Mouse.HoveredPart to null & deselecting all parts"); - Mouse.HoveredPart = null; + //Log.Info("Setting Mouse.HoveredPart to null & deselecting all parts"); + Mouse.HoveredPart = null; - if (EditorLogic.fetch == null) - { - return; - } + if (EditorLogic.fetch == null) + { + return; + } + for (int i = EditorLogic.fetch.ship.Parts.Count - 1; i >= 0; i--) + { + EditorActionPartSelector selector = partEAPSDict[EditorLogic.fetch.ship.Parts[i].persistentId].eaps; // EditorLogic.fetch.ship.Parts[i].GetComponent(); + if (selector != null) + selector.Deselect(); + } - for (int i = EditorLogic.fetch.ship.Parts.Count - 1; i >= 0; i--) - //for (int i = 0; i < EditorLogic.fetch.ship.Parts.Count; i++) + if (EditorActionGroups.Instance != null) + { + if (EditorActionGroups.Instance.HasSelectedParts()) + EditorActionGroups.Instance.ClearSelection(true); + for (int i = ClickThruBlocker.CTBWin.selectedParts.Count - 1; i >= 0; i--) + //for (int i = 0; i < ClickThruBlocker.CTBWin.selectedParts.Count; i++) { - EditorActionPartSelector selector = EditorLogic.fetch.ship.Parts[i].GetComponent(); + EditorActionPartSelector selector = partEAPSDict[ClickThruBlocker.CTBWin.selectedParts[i].persistentId].eaps; // ClickThruBlocker.CTBWin.selectedParts[i].GetComponent(); if (selector != null) - selector.Deselect(); - } - - if (EditorActionGroups.Instance != null) - { - EditorActionGroups.Instance.ClearSelection(true); - for (int i = ClickThruBlocker.CTBWin.selectedParts.Count - 1; i >= 0; i--) - //for (int i = 0; i < ClickThruBlocker.CTBWin.selectedParts.Count; i++) - { - EditorActionPartSelector selector = ClickThruBlocker.CTBWin.selectedParts[i].GetComponent(); - if (selector != null) - EditorActionGroups.Instance.AddToSelection(selector); - } + EditorActionGroups.Instance.AddToSelection(selector); } } - } + } //static internal long timeTics = 0; diff --git a/ClickThroughBlocker/ClearInputLocks.cs b/ClickThroughBlocker/ClearInputLocks.cs index b91021c..f9de452 100644 --- a/ClickThroughBlocker/ClearInputLocks.cs +++ b/ClickThroughBlocker/ClearInputLocks.cs @@ -100,7 +100,10 @@ void CallModeWindow() { //ClickThroughFix.Log.Info("CallModeWindow, modeWindow: " + (modeWindow != null)); if (modeWindow == null) + { + HighLogic.CurrentGame.Parameters.CustomParams().showPopup = true; modeWindow = gameObject.AddComponent(); + } else { Destroy(modeWindow); diff --git a/ClickThroughBlocker/ClickThroughBlocker.csproj b/ClickThroughBlocker/ClickThroughBlocker.csproj index 3f407d0..94152e1 100644 --- a/ClickThroughBlocker/ClickThroughBlocker.csproj +++ b/ClickThroughBlocker/ClickThroughBlocker.csproj @@ -93,11 +93,16 @@ start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT deploy.bat $(TargetDir) $(TargetFileName) + + if $(ConfigurationName) == Release ( - start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) + + start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) $(TargetName) + + ) diff --git a/ClickThroughBlocker/OneTimePopup.cs b/ClickThroughBlocker/OneTimePopup.cs index ba8c8b9..14e3dc1 100644 --- a/ClickThroughBlocker/OneTimePopup.cs +++ b/ClickThroughBlocker/OneTimePopup.cs @@ -16,13 +16,17 @@ public class OneTimePopup : MonoBehaviour const int HEIGHT = 350; Rect popupRect = new Rect(300, 50, WIDTH, HEIGHT); bool visible = false; - string popUpShownCfgPath; + static string popUpShownCfgPath { get { + return Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../PluginData/PopUpShown.cfg"); ; + } } + string cancelStr = "Cancel (window will open next startup)"; Game curGame; public void Awake() { - popUpShownCfgPath = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../PluginData/PopUpShown.cfg"); + //popUpShownCfgPath = Path.Combine( + // Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../PluginData/PopUpShown.cfg"); if (HighLogic.CurrentGame != curGame) { ClearInputLocks.focusFollowsclick = HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick; @@ -102,6 +106,10 @@ void PopUpWindow(int id) if (!focusFollowsClick && !focusFollowsMouse) GUI.enabled = false; GUILayout.BeginHorizontal(); + if (GUILayout.Button("Save as global default for all new saves")) + { + SaveGlobalDefault(); + } if (GUILayout.Button("Accept")) { HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick = focusFollowsClick; @@ -125,14 +133,38 @@ void PopUpWindow(int id) GUI.DragWindow(); } - - void CreatePopUpFlagFile() + static string GlobalDefaultFile + { + get + { + return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/../Global.cfg"; + } + } + void SaveGlobalDefault() + { + ConfigNode node = new ConfigNode(); + node.AddValue("focusFollowsClick", focusFollowsClick); + node.Save(GlobalDefaultFile); + } + static internal bool GetGlobalDefault(ref bool b) + { + if (System.IO.File.Exists(GlobalDefaultFile)) + { + ConfigNode node = ConfigNode.Load(GlobalDefaultFile); + if (node.TryGetValue("focusFollowsClick", ref b)) + { + return true; + } + } + return false; + } + static internal void CreatePopUpFlagFile() { RemovePopUpFlagFile(); // remove first to avoid any overwriting System.IO.File.WriteAllText(popUpShownCfgPath, "popupshown = true"); } - public void RemovePopUpFlagFile() + static public void RemovePopUpFlagFile() { System.IO.File.Delete(popUpShownCfgPath); } diff --git a/ClickThroughBlocker/RegisterToolbar.cs b/ClickThroughBlocker/RegisterToolbar.cs index 9071d2b..1a2e2d8 100644 --- a/ClickThroughBlocker/RegisterToolbar.cs +++ b/ClickThroughBlocker/RegisterToolbar.cs @@ -1,10 +1,4 @@ using ToolbarControl_NS; -using KSP.UI.Screens; -using KSP.Localization; -using System; -using System.IO; - -using KSP.IO; using UnityEngine; @@ -17,6 +11,29 @@ void Start() { ToolbarControl.RegisterMod(ClearInputLocks.MODID, ClearInputLocks.MODNAME); ToolbarControl.RegisterMod(ClearInputLocks.MODID2, ClearInputLocks.MODNAME2); + GameEvents.onGameNewStart.Add(OnGameNewStart); + GameEvents.onGameStateCreated.Add(OnGameStateCreated); + } + + void OnGameNewStart() + { + bool b = false ; + if (OneTimePopup.GetGlobalDefault(ref b)) + { + HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick = b; + HighLogic.CurrentGame.Parameters.CustomParams().showPopup = false; + OneTimePopup.CreatePopUpFlagFile(); + } + } + void OnGameStateCreated(Game g) + { + bool b = false; + if (OneTimePopup.GetGlobalDefault(ref b)) + { + g.Parameters.CustomParams().focusFollowsclick = b; + g.Parameters.CustomParams().showPopup = false; + OneTimePopup.CreatePopUpFlagFile(); + } } } } \ No newline at end of file diff --git a/ClickThroughBlocker/Settings.cs b/ClickThroughBlocker/Settings.cs index 7e43d1c..dbada74 100644 --- a/ClickThroughBlocker/Settings.cs +++ b/ClickThroughBlocker/Settings.cs @@ -59,7 +59,7 @@ public override bool Interactible(MemberInfo member, GameParameters parameters) showPopup = false; } if (showPopup && OneTimePopup.Instance != null) - OneTimePopup.Instance.RemovePopUpFlagFile(); + OneTimePopup.RemovePopUpFlagFile(); return true; } diff --git a/GameData/000_ClickThroughBlocker/ClickThroughBlocker.version b/GameData/000_ClickThroughBlocker/ClickThroughBlocker.version index 1d74686..919f5a3 100644 --- a/GameData/000_ClickThroughBlocker/ClickThroughBlocker.version +++ b/GameData/000_ClickThroughBlocker/ClickThroughBlocker.version @@ -10,7 +10,7 @@ "MAJOR": 0, "MINOR": 1, "PATCH": 10, - "BUILD": 12 + "BUILD": 14 }, "KSP_VERSION_MIN": { "MAJOR": 1, diff --git a/GameData/000_ClickThroughBlocker/changelog.cfg b/GameData/000_ClickThroughBlocker/changelog.cfg index 3dbfebf..78b2f4f 100644 --- a/GameData/000_ClickThroughBlocker/changelog.cfg +++ b/GameData/000_ClickThroughBlocker/changelog.cfg @@ -6,14 +6,28 @@ KERBALCHANGELOG author = Linuxgurugamer + VERSION + { + version = 0.1.10.14 + CHANGE + { + change = Fixed performance issue in the editor when FocusFollowsMouse was active + change = Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves + type = update + } + } VERSION { version = 0.1.10.13 CHANGE { - change = Fixed inputlogs not being cleared when canceling the window + change = Fixed inputlocks not being cleared when canceling the window + change = Added mode toggle on new button to allow toggling between different modes during the game + change = Updated settings to make it clear if popup will be shown next time in the space center + change = Added code to disable the ShowPopup flag if the focusFollowsClick is changed in the settings + change = Thanks to github user @SteveBenz for this: Make the configuration file not depend on Environment.CurrentDirectory and instead depend on the deployment location of the DLL type = update } } diff --git a/buildRelease.bat b/buildRelease.bat index 967b515..ccc64d1 100644 --- a/buildRelease.bat +++ b/buildRelease.bat @@ -36,6 +36,7 @@ rem Copy files to GameData locations copy /Y "%1%2" "%GAMEDATA%\%GAMEDIR%\Plugins" copy /Y %VERSIONFILE% %GAMEDATA%\%GAMEDIR% +copy /Y changelog.cfg %GAMEDATA%\%GAMEDIR% if "%LICENSE%" NEQ "" copy /y %LICENSE% %GAMEDATA%\%GAMEDIR% if "%README%" NEQ "" copy /Y %README% %GAMEDATA%\%GAMEDIR% diff --git a/changelog.cfg b/changelog.cfg index a1d4792..8ea3c16 100644 --- a/changelog.cfg +++ b/changelog.cfg @@ -6,7 +6,19 @@ KERBALCHANGELOG author = Linuxgurugamer - + VERSION + { + version = 0.1.10.14 + CHANGE + { + change = Fixed performance issue in the editor when FocusFollowsMouse was active + subchange = Two problems: + subchange = GetComponent was being called on every part + subchange = EditorActionGroups.Instance.ClearSelection was being called every time through Update() + change = Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves + type = update + } + } VERSION { diff --git a/deploy.bat b/deploy.bat index f2b40ae..29ed412 100644 --- a/deploy.bat +++ b/deploy.bat @@ -1,5 +1,5 @@ -@echo off +rem @echo off rem H is the destination game folder rem GAMEDIR is the name of the mod folder (usually the mod name) @@ -9,12 +9,16 @@ rem but not always set H=%KSPDIR% set H=R:\KSP_1.10.1_dev +set H=R:\dp0\kspdev set GAMEDIR=000_ClickThroughBlocker set GAMEDATA="GameData\" set VERSIONFILE=ClickThroughBlocker.version copy /Y "%1%2" "%GAMEDATA%\%GAMEDIR%\Plugins" +copy /Y "%1ClickThroughBlocker.pdb" "%GAMEDATA%\%GAMEDIR%\Plugins" + copy /Y %VERSIONFILE% %GAMEDATA%\%GAMEDIR% copy /y changelog.cfg %GAMEDATA%\%GAMEDIR% xcopy /y /s /I %GAMEDATA%\%GAMEDIR% "%H%\GameData\%GAMEDIR%" +pause \ No newline at end of file