diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..faa091b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ + +[*] + +# Microsoft .NET properties +csharp_indent_braces = false +csharp_new_line_before_catch = false +csharp_new_line_before_else = false +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_open_brace = accessors,events,indexers,properties +csharp_preferred_modifier_order = private, protected, public, virtual, volatile, abstract, internal, override, sealed, new, static, extern, unsafe, readonly, async:suggestion +csharp_preserve_single_line_blocks = true + +# ReSharper properties +resharper_align_multiline_parameter = true +resharper_arguments_literal = positional +resharper_blank_lines_around_auto_property = 0 +resharper_braces_for_for = required +resharper_csharp_align_multiline_binary_expressions_chain = true +resharper_csharp_blank_lines_around_invocable = 0 +resharper_csharp_insert_final_newline = false +resharper_csharp_max_line_length = 286 +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_instance_members_qualify_declared_in = +resharper_keep_existing_embedded_block_arrangement = false +resharper_keep_existing_enum_arrangement = false +resharper_place_expr_property_on_single_line = true +resharper_remove_blank_lines_near_braces_in_declarations = false +resharper_space_within_single_line_array_initializer_braces = false +resharper_wrap_before_declaration_rpar = false +resharper_wrap_object_and_collection_initializer_style = wrap_if_long diff --git a/BrokenNodeDetector/BndResultHighlightManager.cs b/BrokenNodeDetector/BndResultHighlightManager.cs index a077a30..7b522d1 100644 --- a/BrokenNodeDetector/BndResultHighlightManager.cs +++ b/BrokenNodeDetector/BndResultHighlightManager.cs @@ -22,6 +22,7 @@ public class BndResultHighlightManager: SimulationManagerBase _highlightables = new Dictionary(); protected override void Awake() { base.Awake(); + name = "BND_ResultHighlightManager"; _mainCamera = Camera.main; _highlightables = new Dictionary { {HighlightType.Building, new BuildingHighlight()}, @@ -98,8 +99,10 @@ public class BndResultHighlightManager: SimulationManagerBase.instance.RayCast(ray, input.m_buildingService.m_service, input.m_buildingService.m_subService, input.m_buildingService.m_itemLayers, input.m_ignoreBuildingFlags, out hit, out output.m_building)) - { + Singleton.instance.RayCast(ray, input.m_buildingService.m_service, input.m_buildingService.m_subService, input.m_buildingService.m_itemLayers, input.m_ignoreBuildingFlags, out hit, out ushort buildingId)) { + + ushort parentBuilding = Building.FindParentBuilding(buildingId); + output.m_building = parentBuilding != 0 ? parentBuilding : buildingId; float distance = Vector3.Distance(hit, origin); if (distance < (double) len) { diff --git a/BrokenNodeDetector/BrokenNodeDetector.cs b/BrokenNodeDetector/BrokenNodeDetector.cs index ea573df..a653a1c 100644 --- a/BrokenNodeDetector/BrokenNodeDetector.cs +++ b/BrokenNodeDetector/BrokenNodeDetector.cs @@ -2,20 +2,22 @@ using BrokenNodeDetector.UI; using CitiesHarmony.API; using ColossalFramework.UI; +using JetBrains.Annotations; using UnityEngine; namespace BrokenNodeDetector { public class BrokenNodeDetector : IUserMod { - public static readonly string Version = "0.7.1"; + public static readonly string Version = "0.8.0"; public string Name => "Broken Node Detector " + Version; - public string Description => "Search for broken nodes when TM:PE vehicles despawn."; + public string Description => "Search for broken nodes when TM:PE vehicles despawn and more."; #if TEST_UI private MainUI _testUI; #endif + [UsedImplicitly] public void OnEnabled() { Debug.Log($"[BND] Broken Node Detector enabled. Version {Version}"); HarmonyHelper.EnsureHarmonyInstalled(); @@ -34,6 +36,7 @@ public class BrokenNodeDetector : IUserMod { #endif } + [UsedImplicitly] public void OnDisabled() { Debug.Log("[BND] Broken Node Detector disabled."); if (LoadingExtension.MainUi) { diff --git a/BrokenNodeDetector/BrokenNodeDetector.csproj b/BrokenNodeDetector/BrokenNodeDetector.csproj index 7de2585..33ecf8c 100644 --- a/BrokenNodeDetector/BrokenNodeDetector.csproj +++ b/BrokenNodeDetector/BrokenNodeDetector.csproj @@ -70,6 +70,7 @@ + @@ -87,10 +88,7 @@ ..\Dependencies\ColossalManaged.dll - - ..\Dependencies\EManagersLib.API.dll - - + ..\Dependencies\ICities.dll @@ -120,7 +118,6 @@ del /Q "%25DEPLOYDIR%25*" xcopy /y "$(TargetDir)BrokenNodeDetector.dll" "%25DEPLOYDIR%25" xcopy /y "$(TargetDir)CitiesHarmony.API.dll" "%25DEPLOYDIR%25" - xcopy /y "$(TargetDir)EManagersLib.API.dll" "%25DEPLOYDIR%25" set DEPLOYDIR= diff --git a/BrokenNodeDetector/Properties/AssemblyInfo.cs b/BrokenNodeDetector/Properties/AssemblyInfo.cs index 20fe451..23ff51c 100644 --- a/BrokenNodeDetector/Properties/AssemblyInfo.cs +++ b/BrokenNodeDetector/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BrokenNodeDetector")] -[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,4 +32,4 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.7.*")] +[assembly: AssemblyVersion("1.0.8.*")] diff --git a/BrokenNodeDetector/UI/MainPanel.cs b/BrokenNodeDetector/UI/MainPanel.cs index 7c68106..4b3cdf5 100644 --- a/BrokenNodeDetector/UI/MainPanel.cs +++ b/BrokenNodeDetector/UI/MainPanel.cs @@ -20,6 +20,7 @@ public class MainPanel : UIPanel { public override void Awake() { base.Awake(); + name = "BND_MainPanel"; autoLayout = false; width = PANEL_WIDTH; height = PANEL_HEIGHT; @@ -197,6 +198,8 @@ public class MainPanel : UIPanel { private void OnResultsClose(bool updateHeight = false) { _returnButton.Hide(); + _preparePanel.CancelPrepare(); + _preparePanel.Hide(); RunFadeInOutAnimations(_resultsPanel, _detectorsPanel); if (BndResultHighlightManager.instance) { BndResultHighlightManager.instance.enabled = false; diff --git a/BrokenNodeDetector/UI/MainUI.cs b/BrokenNodeDetector/UI/MainUI.cs index 08d1fcc..dd36b1f 100644 --- a/BrokenNodeDetector/UI/MainUI.cs +++ b/BrokenNodeDetector/UI/MainUI.cs @@ -16,6 +16,7 @@ public class MainUI : UIComponent { public override void Awake() { base.Awake(); + name = "BND_MainUI"; var uiView = UIView.GetAView(); MainPanel = (MainPanel) uiView.AddUIComponent(typeof(MainPanel)); MainPanel.Initialize(); diff --git a/BrokenNodeDetector/UI/PreparePanel.cs b/BrokenNodeDetector/UI/PreparePanel.cs index 89ab274..951cc22 100644 --- a/BrokenNodeDetector/UI/PreparePanel.cs +++ b/BrokenNodeDetector/UI/PreparePanel.cs @@ -48,6 +48,7 @@ public class PreparePanel : UIPanel { public void CancelPrepare() { if (_preparing && _prepareCoroutine != null) { StopCoroutine(_prepareCoroutine); + _preparing = false; } } diff --git a/BrokenNodeDetector/UI/SettingsUI.cs b/BrokenNodeDetector/UI/SettingsUI.cs index ff7fd9f..da4aeb8 100644 --- a/BrokenNodeDetector/UI/SettingsUI.cs +++ b/BrokenNodeDetector/UI/SettingsUI.cs @@ -1,7 +1,10 @@ using System; using ColossalFramework; using ColossalFramework.UI; +#if BROKEN_PROPS_SCANNER +using BrokenNodeDetector.UI.Tools.Utils; using EManagersLib.API; +#endif using ICities; using UnityEngine; @@ -13,7 +16,10 @@ namespace BrokenNodeDetector.UI { public class SettingsUI { private const float ROW_WIDTH = 744f - 15f; private const float ROW_HEIGHT = 34f; - +#if BROKEN_PROPS_SCANNER + private bool? _emlInstalled; +#endif + private SavedInputKey _currentlyEditingBinding; public void BuildUI(UIHelper helper) { @@ -25,7 +31,14 @@ public class SettingsUI { UIHelperBase group2 = helper.AddGroup("Other"); UIPanel panel2 = CreateRowPanel((UIPanel) ((UIHelper) group2).self); CreateResetMenuPosition(panel2); - CreateLabel(panel2, $"EML integration active: {(PropAPI.m_isEMLInstalled ? "Yes" : "No")}", 1f, true); + +#if BROKEN_PROPS_SCANNER + if (!_emlInstalled.HasValue) { + _emlInstalled = EmlUtils.IsEmlInstalled(); + } + CreateLabel(panel2, $"EML integration active: {(_emlInstalled.Value ? "Yes" : "No")}", 1f, true); +#endif + panel2.autoLayoutDirection = LayoutDirection.Vertical; panel2.autoLayoutPadding = new RectOffset(0, 0, 10, 10); panel2.autoSize = true; diff --git a/BrokenNodeDetector/UI/Tools/BndColorAnimator.cs b/BrokenNodeDetector/UI/Tools/BndColorAnimator.cs index 07d5601..e540347 100644 --- a/BrokenNodeDetector/UI/Tools/BndColorAnimator.cs +++ b/BrokenNodeDetector/UI/Tools/BndColorAnimator.cs @@ -7,6 +7,7 @@ namespace BrokenNodeDetector.UI.Tools { public class BndColorAnimator : Singleton { private readonly List _animatorInfos = new List(); + private readonly NameMatcher _matcher = new NameMatcher(); public static void Animate(Action target, AnimatedColor color) { instance.AnimateInternal(null, target, color, null); @@ -34,8 +35,8 @@ public class BndColorAnimator : Singleton { } private bool InternalIsAnimating(string animationName) { - AnimationInfo animationInfo = - this._animatorInfos.Find(info => info.AnimationName == animationName); + _matcher.name = animationName; + AnimationInfo animationInfo = this._animatorInfos.Find(_matcher.Match); return animationInfo != null; } @@ -43,7 +44,8 @@ public class BndColorAnimator : Singleton { Action target, AnimatedColor v, Action completed) { - AnimationInfo animationInfo = _animatorInfos.Find(info => info.AnimationName == animationName); + _matcher.name = animationName; + AnimationInfo animationInfo = _animatorInfos.Find(_matcher.Match); if (animationName != null && animationInfo != null) { animationInfo.Value = v; animationInfo.Completed = completed; @@ -97,6 +99,7 @@ public class BndColorAnimator : Singleton { } private void OnDestroy() { + _animatorInfos.Clear(); GetType().GetField("sInstance", BindingFlags.NonPublic | BindingFlags.Static) ?.SetValue(null, null); } @@ -110,5 +113,12 @@ private class AnimationInfo { public Action Completed; } + + private class NameMatcher { + public string name; + public bool Match(AnimationInfo info) { + return info.AnimationName == name; + } + } } } \ No newline at end of file diff --git a/BrokenNodeDetector/UI/Tools/BrokenNodesTool/BrokenNodes.cs b/BrokenNodeDetector/UI/Tools/BrokenNodesTool/BrokenNodes.cs index 588aaf2..550da04 100644 --- a/BrokenNodeDetector/UI/Tools/BrokenNodesTool/BrokenNodes.cs +++ b/BrokenNodeDetector/UI/Tools/BrokenNodesTool/BrokenNodes.cs @@ -62,6 +62,7 @@ public class BrokenNodes : Detector { private void BuildTemplate() { _template = new GameObject("BrokenNodesTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); diff --git a/BrokenNodeDetector/UI/Tools/BrokenPathTool/BrokenPaths.cs b/BrokenNodeDetector/UI/Tools/BrokenPathTool/BrokenPaths.cs index ab4d30f..400d0a0 100644 --- a/BrokenNodeDetector/UI/Tools/BrokenPathTool/BrokenPaths.cs +++ b/BrokenNodeDetector/UI/Tools/BrokenPathTool/BrokenPaths.cs @@ -161,6 +161,7 @@ public class BrokenPaths : Detector { private void BuildResultTemplate() { _template = new GameObject("BrokenPathsTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); @@ -190,6 +191,7 @@ public class BrokenPaths : Detector { private void BuildPrepareTemplate() { _templatePrepare = new GameObject("BrokenPathsPrepareTemplate").AddComponent(); + _templatePrepare.transform.SetParent(_defaultGameObject.transform, true); _templatePrepare.width = 400; _templatePrepare.height = 50; UILabel label = _templatePrepare.AddUIComponent(); @@ -203,6 +205,7 @@ public class BrokenPaths : Detector { private void BuildRowTemplate() { UIPanel resultRow = new GameObject("BrokenPathsRowTemplate").AddComponent(); + resultRow.gameObject.transform.SetParent(_defaultGameObject.transform, true); resultRow.name = RESULT_ROW; resultRow.width = 400; resultRow.height = 40; diff --git a/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenProps.cs b/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenProps.cs index 49c425f..651e359 100644 --- a/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenProps.cs +++ b/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenProps.cs @@ -1,3 +1,4 @@ +#if BROKEN_PROPS_SCANNER using System.Collections; using System.Collections.Generic; using System.Threading; @@ -145,4 +146,5 @@ public class BrokenProps : Detector { yield return null; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenPropsEML.cs b/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenPropsEML.cs index e143394..52b4727 100644 --- a/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenPropsEML.cs +++ b/BrokenNodeDetector/UI/Tools/BrokenPropsTool/BrokenPropsEML.cs @@ -1,3 +1,4 @@ +#if BROKEN_PROPS_SCANNER using System; using System.Collections; using System.Collections.Generic; @@ -169,4 +170,5 @@ public class BrokenPropsEML : Detector { yield return null; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/BrokenNodeDetector/UI/Tools/DetectorFactory.cs b/BrokenNodeDetector/UI/Tools/DetectorFactory.cs index 254ac1d..7e0cfda 100644 --- a/BrokenNodeDetector/UI/Tools/DetectorFactory.cs +++ b/BrokenNodeDetector/UI/Tools/DetectorFactory.cs @@ -3,13 +3,17 @@ using System.Collections.ObjectModel; using BrokenNodeDetector.UI.Tools.BrokenNodesTool; using BrokenNodeDetector.UI.Tools.BrokenPathTool; +#if BROKEN_PROPS_SCANNER using BrokenNodeDetector.UI.Tools.BrokenPropsTool; +#endif using BrokenNodeDetector.UI.Tools.DisconnectedBuildingsTool; using BrokenNodeDetector.UI.Tools.DisconnectedPublicTransportStopsTool; using BrokenNodeDetector.UI.Tools.StuckCimsTool; using BrokenNodeDetector.UI.Tools.GhostNodesTool; using BrokenNodeDetector.UI.Tools.ShortSegmentsTool; +#if BROKEN_PROPS_SCANNER using EManagersLib.API; +#endif #if SEGMENT_UPDATER using BrokenNodeDetector.UI.Tools.SegmentUpdateTool; #endif @@ -19,7 +23,10 @@ namespace BrokenNodeDetector.UI.Tools { public class DetectorFactory : IDisposable { private List _detectors; - public DetectorFactory() { + public DetectorFactory() { +#if BROKEN_PROPS_SCANNER + PropAPI.Initialize(); +#endif _detectors = new List { new BrokenNodes(), new GhostNodes(), @@ -29,7 +36,9 @@ public class DetectorFactory : IDisposable { #if SEGMENT_UPDATER // new SegmentUpdateRequest(), #endif +#if BROKEN_PROPS_SCANNER (PropAPI.m_isEMLInstalled ? (Detector)new BrokenPropsEML() : new BrokenProps()), +#endif new StuckCims(), new BrokenPaths(), }; @@ -46,6 +55,7 @@ public class DetectorFactory : IDisposable { } } _detectors.Clear(); + Detector.DisposeDefaultGameObject(); } } } \ No newline at end of file diff --git a/BrokenNodeDetector/UI/Tools/DisconnectedBuildingsTool/DisconnectedBuildings.cs b/BrokenNodeDetector/UI/Tools/DisconnectedBuildingsTool/DisconnectedBuildings.cs index eeccfa9..e55231e 100644 --- a/BrokenNodeDetector/UI/Tools/DisconnectedBuildingsTool/DisconnectedBuildings.cs +++ b/BrokenNodeDetector/UI/Tools/DisconnectedBuildingsTool/DisconnectedBuildings.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Text; using System.Threading; using ColossalFramework.UI; @@ -29,13 +28,19 @@ public class DisconnectedBuildings : Detector { ResetState(); _progress = 0f; - AsyncTask asyncTask = SimulationManager.instance.AddAction(ProcessInternal()); + AsyncTask asyncTask = SimulationManager.instance.AddAction(CheckRoadAccess()); while (!asyncTask.completed) { yield return _progress; } + + _progress = 0f; + AsyncTask asyncTask2 = SimulationManager.instance.AddAction(CollectDisconnectedBuildings()); + while (!asyncTask2.completed) { + yield return _progress; + } yield return 1.0f; - IsProcessing = true; + IsProcessing = false; } public override void InitResultsView(UIComponent component) { @@ -63,65 +68,75 @@ public class DisconnectedBuildings : Detector { templateInstance.Find("MoveNext").eventClick += MoveNextBuildingButtonClick; } - private IEnumerator ProcessInternal() { + private IEnumerator CheckRoadAccess() { BuildingManager bm = BuildingManager.instance; float searchStep = 1.0f / bm.m_buildings.m_size; + + ProgressMessage = $"Processing...0% Pass 1/2"; + Building[] mBuffer = bm.m_buildings.m_buffer; + for (int i = 1; i < mBuffer.Length; i++) { + + if ((mBuffer[i].m_flags & (Building.Flags.Created | Building.Flags.Deleted)) == Building.Flags.Created && + mBuffer[i].Info + ) { + mBuffer[i].Info.m_buildingAI.CheckRoadAccess((ushort)i, ref mBuffer[i]); + } + + float searchProgress = searchStep * i; + if (i % 64 == 0) { + ProgressMessage = $"Processing...{searchProgress * 100:F0}% Pass 1/2"; + Thread.Sleep(1); + _progress = searchProgress; + } + } + ProgressMessage = $"Processing...100% Pass 1/2"; + + yield return 1.0f; + } + + private IEnumerator CollectDisconnectedBuildings() { StringBuilder sb = new StringBuilder(); sb.AppendLine("[BND] Scanning for disconnected buildings"); sb.AppendLine("[BND] "); sb.AppendLine("[BND] =( Building ID )===( Location )="); sb.AppendLine(); - ProgressMessage = $"Processing...0%"; + BuildingManager bm = BuildingManager.instance; Building[] mBuffer = bm.m_buildings.m_buffer; + float searchStep = 1.0f / bm.m_buildings.m_size; + + ProgressMessage = "Processing...0% Pass 2/2"; + _progress = 0f; + int counter = 0; - MethodInfo findRoadAccess = typeof(PlayerBuildingAI).GetMethod("FindRoadAccess", BindingFlags.Instance | BindingFlags.NonPublic); - for (int i = 0; i < mBuffer.Length; i++) { - Building building = mBuffer[i]; + for (int i = 1; i < mBuffer.Length; i++) { + + if ((mBuffer[i].m_flags & (Building.Flags.Created | Building.Flags.Deleted)) == Building.Flags.Created && + mBuffer[i].Info + ) { + bool notConnected = ((mBuffer[i].m_flags & Building.Flags.RoadAccessFailed) != Building.Flags.None && + ((mBuffer[i].m_problems.m_Problems1 & (Notification.Problem1.RoadNotConnected | Notification.Problem1.PathNotConnected)) != Notification.Problem1.None || + (mBuffer[i].m_problems.m_Problems2 & (Notification.Problem2.NotInPedestrianZone | Notification.Problem2.CannotBeReached)) != Notification.Problem2.None)); - if ((building.m_flags & Building.Flags.Created) != 0 && building.Info) { - if (building.Info.m_buildingAI is PlayerBuildingAI) { + if (notConnected) { counter++; - PlayerBuildingAI buildingAI = building.Info.m_buildingAI as PlayerBuildingAI; - bool connected = true; - if ((building.m_flags & Building.Flags.Collapsed) == Building.Flags.None && buildingAI.RequireRoadAccess()) { - Vector3 position = buildingAI.m_info.m_zoningMode != BuildingInfo.ZoningMode.CornerLeft - ? (buildingAI.m_info.m_zoningMode != BuildingInfo.ZoningMode.CornerRight - ? building.CalculateSidewalkPosition(0.0f, 4f) - : building.CalculateSidewalkPosition(building.Width * -4f, 4f)) - : building.CalculateSidewalkPosition(building.Width * 4f, 4f); - object[] args = { (ushort)i, building, position, null, true, false }; - if (!(bool)findRoadAccess.Invoke(buildingAI, args)) - connected = false; - } - - if (!connected) { - _disconnectedBuildings.Add((ushort)i, building.m_position); - sb.AppendLine("==(" + i + ")===(" + building.m_position + ")="); - sb.Append("building ") - .Append(" " + (building.Info ? building.Info.m_class.name : "") + " ") - .Append(building.m_flags.ToString()) - .Append(" [name: ").Append(building.Info.name).Append("]"); - sb.AppendLine("---------------------------------------"); - } - } else if ((building.m_flags & Building.Flags.RoadAccessFailed) != 0 || (building.m_problems.m_Problems1 & Notification.Problem1.RoadNotConnected) != 0) { - _disconnectedBuildings.Add((ushort)i, building.m_position); - sb.AppendLine("==(" + i + ")===(" + building.m_position + ")="); - sb.Append("building ") - .Append(" " + (building.Info ? building.Info.m_class.name : "") + " ") - .Append(building.m_flags.ToString()) - .Append(" [name: ").Append(building.Info.name).Append("]"); + _disconnectedBuildings.Add((ushort)i, mBuffer[i].m_position); + sb.AppendLine("==(" + i + ")===" + mBuffer[i].m_position + "=="); + sb.Append("Building [ItemClass: ") + .Append((mBuffer[i].Info ? mBuffer[i].Info.m_class.name : "") + "] [Flags: ") + .Append(mBuffer[i].m_flags.ToString()).Append("] [Problems: ").Append(mBuffer[i].m_problems.ToString()) + .Append("] [Name: ").Append(mBuffer[i].Info.name).Append("]"); sb.AppendLine("---------------------------------------"); } } float searchProgress = searchStep * i; - if (i % 32 == 0) { - ProgressMessage = $"Processing...{searchProgress * 100:F0}%"; + if (i % 128 == 0) { + ProgressMessage = $"Processing...{searchProgress * 100:F0}% Pass 2/2"; Thread.Sleep(1); _progress = searchProgress; } } - ProgressMessage = $"Processing...100%"; + ProgressMessage = $"Processing...100% Pass 2/2"; Debug.Log("[BND] Disconnected building instances count: " + counter); Debug.Log("[BND] Scan report\n" + sb + "\n\n======================================================="); @@ -130,6 +145,7 @@ public class DisconnectedBuildings : Detector { private void BuildTemplate() { _template = new GameObject("DisconnectedBuildingTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); @@ -150,20 +166,22 @@ public class DisconnectedBuildings : Detector { UIPanel buildingPanel = _template.AddUIComponent(); buildingPanel.width = 400; buildingPanel.height = 40; - buildingPanel.relativePosition = new Vector2(10, 45); + buildingPanel.relativePosition = new Vector2(15, 45); buildingPanel.name = "BuildingPanel"; UILabel buildingId = buildingPanel.AddUIComponent(); + buildingId.processMarkup = true; buildingId.prefix = "Building ID: "; - buildingId.relativePosition = new Vector2(20, 10); + buildingId.relativePosition = new Vector2(0, 10); buildingId.name = "BuildingID"; - buildingId.textScale = 0.9f; + buildingId.textScale = 0.8f; UILabel buildingPos = buildingPanel.AddUIComponent(); + buildingPos.processMarkup = true; buildingPos.prefix = "Position: "; - buildingPos.relativePosition = new Vector2(200, 10); + buildingPos.relativePosition = new Vector2(150, 10); buildingPos.name = "BuildingPosition"; - buildingPos.textScale = 0.9f; + buildingPos.textScale = 0.8f; buildingPanel.Hide(); } @@ -215,6 +233,7 @@ public class DisconnectedBuildings : Detector { if (_disconnectedBuildings.Count == 0) { ResetState(); label.text = "Great! Nothing found :-)"; + label.textColor = new Color(0f, 0.81f, 0.05f); label.parent.height = 50; label.relativePosition = Vector3.zero; label.color = Color.white; @@ -226,16 +245,16 @@ public class DisconnectedBuildings : Detector { UILabel buildingId = buildingPanel.Find("BuildingID"); UILabel buildingPos = buildingPanel.Find("BuildingPosition"); if (_currentBuilding != 0 && _disconnectedBuildings.TryGetValue(_currentBuilding, out Vector3 position)) { - buildingId.text = _currentBuilding.ToString(); - buildingPos.text = position.ToString(); + buildingId.text = $"{_currentBuilding.ToString()}"; + buildingPos.text = $"{position.ToString()}"; } else { buildingId.text = " "; buildingPos.text = " "; } - label.relativePosition = new Vector3(20, 0); - label.text = $"{_disconnectedBuildings.Count} possibly disconnected building(s)"; - label.color = Color.yellow; + label.relativePosition = new Vector3(15, 0); + label.processMarkup = true; + label.text = $"{_disconnectedBuildings.Count} possibly disconnected building(s)"; } private void UpdateBuildingButtons(UIComponent moveNextButton) { diff --git a/BrokenNodeDetector/UI/Tools/DisconnectedPublicTransportStopsTool/DisconnectedPublicTransportStops.cs b/BrokenNodeDetector/UI/Tools/DisconnectedPublicTransportStopsTool/DisconnectedPublicTransportStops.cs index 09cc76c..6744d7b 100644 --- a/BrokenNodeDetector/UI/Tools/DisconnectedPublicTransportStopsTool/DisconnectedPublicTransportStops.cs +++ b/BrokenNodeDetector/UI/Tools/DisconnectedPublicTransportStopsTool/DisconnectedPublicTransportStops.cs @@ -173,6 +173,7 @@ public class DisconnectedPublicTransportStops : Detector { private void BuildTemplate() { _template = new GameObject("DisconnectedPTStopTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); diff --git a/BrokenNodeDetector/UI/Tools/IDetector.cs b/BrokenNodeDetector/UI/Tools/IDetector.cs index dabc57d..cd18128 100644 --- a/BrokenNodeDetector/UI/Tools/IDetector.cs +++ b/BrokenNodeDetector/UI/Tools/IDetector.cs @@ -7,6 +7,7 @@ namespace BrokenNodeDetector.UI.Tools { public abstract class Detector : IDetector, IDisposable { + internal static GameObject _defaultGameObject = new GameObject("BND_Detectors"); protected static UIComponent _defaultTemplate; protected UIComponent _template; protected UIComponent _templatePrepare; @@ -52,6 +53,8 @@ public abstract class Detector : IDetector, IDisposable { if (_defaultTemplate) return; UILabel label = new GameObject("Result Default UI").AddComponent(); + label.gameObject.transform.SetParent(_defaultGameObject.transform, true); + label.gameObject.transform.SetParent(_defaultGameObject.transform, true); label.autoSize = true; label.padding = new RectOffset(10, 10, 15, 15); _defaultTemplate = label; @@ -73,6 +76,13 @@ public abstract class Detector : IDetector, IDisposable { _defaultTemplate = null; } } + + internal static void DisposeDefaultGameObject() { + if (_defaultGameObject) { + UnityEngine.Object.Destroy(_defaultGameObject); + _defaultGameObject = null; + } + } } public interface IDetector { diff --git a/BrokenNodeDetector/UI/Tools/ShortSegmentsTool/ShortSegments.cs b/BrokenNodeDetector/UI/Tools/ShortSegmentsTool/ShortSegments.cs index 7eb3fa0..5a6b46a 100644 --- a/BrokenNodeDetector/UI/Tools/ShortSegmentsTool/ShortSegments.cs +++ b/BrokenNodeDetector/UI/Tools/ShortSegmentsTool/ShortSegments.cs @@ -130,6 +130,7 @@ public class ShortSegments : Detector { private void BuildTemplate() { _template = new GameObject("ShortSegmentsTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); diff --git a/BrokenNodeDetector/UI/Tools/StuckCimsTool/StuckCims.cs b/BrokenNodeDetector/UI/Tools/StuckCimsTool/StuckCims.cs index 7b82e29..a735bcc 100644 --- a/BrokenNodeDetector/UI/Tools/StuckCimsTool/StuckCims.cs +++ b/BrokenNodeDetector/UI/Tools/StuckCimsTool/StuckCims.cs @@ -116,6 +116,7 @@ public class StuckCims : Detector { private void BuildResultTemplate() { _template = new GameObject("StuckCimsTemplate").AddComponent(); + _template.transform.SetParent(_defaultGameObject.transform, true); _template.width = 400; _template.height = 50; UILabel label = _template.AddUIComponent(); @@ -145,6 +146,7 @@ public class StuckCims : Detector { private void BuildPrepareTemplate() { _templatePrepare = new GameObject("StuckCimsPrepareTemplate").AddComponent(); + _templatePrepare.gameObject.transform.SetParent(_defaultGameObject.transform, true); _templatePrepare.width = 400; _templatePrepare.height = 50; UILabel label = _templatePrepare.AddUIComponent(); @@ -158,6 +160,7 @@ public class StuckCims : Detector { private void BuildRowTemplate() { UIPanel resultRow = new GameObject("StuckCimsRowTemplate").AddComponent(); + resultRow.gameObject.transform.SetParent(_defaultGameObject.transform, true); resultRow.name = RESULT_ROW; resultRow.width = 400; resultRow.height = 40; diff --git a/BrokenNodeDetector/UI/Tools/Utils/EMLUtisl.cs b/BrokenNodeDetector/UI/Tools/Utils/EMLUtisl.cs new file mode 100644 index 0000000..6260dd5 --- /dev/null +++ b/BrokenNodeDetector/UI/Tools/Utils/EMLUtisl.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using ColossalFramework; +using ColossalFramework.Plugins; + +namespace BrokenNodeDetector.UI.Tools.Utils { +#if BROKEN_PROPS_SCANNER + public class EmlUtils { + internal static bool IsEmlInstalled() { + foreach (PluginManager.PluginInfo pluginInfo in Singleton.instance.GetPluginsInfo()) { + try { + foreach (Assembly assembly in pluginInfo.GetAssemblies()) { + bool flag = assembly.GetName().Name.ToLower().Equals("emanagerslib"); + if (flag) { + return pluginInfo.isEnabled; + } + } + } catch { + // ignore + } + } + return false; + } + } +#endif +} \ No newline at end of file