diff --git a/src/RealTime/Core/RealTimeCore.cs b/src/RealTime/Core/RealTimeCore.cs index 86d7d421856645e58c4425f2b289bc46cef3fcea..6aefb1490aa3416dcd3029db4996db8f7d9d8316 100644 --- a/src/RealTime/Core/RealTimeCore.cs +++ b/src/RealTime/Core/RealTimeCore.cs @@ -167,11 +167,11 @@ namespace RealTime.Core AwakeSleepSimulation.Install(configProvider.Configuration); - RealTimeStorage.CurrentLevelStorage.GameSaving += result.GameSaving; result.storageData.Add(eventManager); result.storageData.Add(ResidentAIPatch.RealTimeAI.GetStorageService()); if (RealTimeStorage.CurrentLevelStorage != null) { + RealTimeStorage.CurrentLevelStorage.GameSaving += result.GameSaving; LoadStorageData(result.storageData, RealTimeStorage.CurrentLevelStorage); } diff --git a/src/RealTime/CustomAI/CitizenScheduleStorage.cs b/src/RealTime/CustomAI/CitizenScheduleStorage.cs index 227902deb35c44641b9efebb41c51848780e2b52..dd44a5eec9f66f03226685b72b3d1134ec5a7460 100644 --- a/src/RealTime/CustomAI/CitizenScheduleStorage.cs +++ b/src/RealTime/CustomAI/CitizenScheduleStorage.cs @@ -31,7 +31,7 @@ namespace RealTime.CustomAI /// have different length. public CitizenScheduleStorage(CitizenSchedule[] residentSchedules, Citizen[] citizens, ITimeInfo timeInfo) { - this.residentSchedules = residentSchedules ?? throw new System.ArgumentNullException(nameof(residentSchedules)); + this.residentSchedules = residentSchedules ?? throw new ArgumentNullException(nameof(residentSchedules)); this.citizens = citizens ?? throw new ArgumentNullException(nameof(citizens)); this.timeInfo = timeInfo ?? throw new ArgumentNullException(nameof(timeInfo)); if (residentSchedules.Length != citizens.Length) diff --git a/src/RealTime/CustomAI/RealTimeBuildingAI.cs b/src/RealTime/CustomAI/RealTimeBuildingAI.cs index 45a36c059a151e56adf873df474a610cd46f8fd0..295127ccf21c7e950671aa2e8572b06e0b9300e8 100644 --- a/src/RealTime/CustomAI/RealTimeBuildingAI.cs +++ b/src/RealTime/CustomAI/RealTimeBuildingAI.cs @@ -11,7 +11,7 @@ namespace RealTime.CustomAI using static Constants; /// - /// A class that incorporated the custom logic for the private buildings. + /// A class that incorporates the custom logic for the private buildings. /// internal sealed class RealTimeBuildingAI { @@ -152,7 +152,7 @@ namespace RealTime.CustomAI /// The simulation frame index to process. public void ProcessFrame(uint frameIndex) { - UpdateLightState(frameIndex); + UpdateLightState(); if ((frameIndex & StepMask) != 0) { @@ -258,7 +258,7 @@ namespace RealTime.CustomAI return false; } - private void UpdateLightState(uint frameIndex) + private void UpdateLightState() { if (lightStateCheckCounter > 0) { diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs b/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs index 0790181f8da75d4c476df8d108231b33139fd1fc..2a557853871a2d47929e661120909ae08b07a85f 100644 --- a/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs +++ b/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs @@ -142,7 +142,7 @@ namespace RealTime.CustomAI return false; } - private ScheduleAction UpdateCitizenState(uint citizenId, ref TCitizen citizen, ref CitizenSchedule schedule) + private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSchedule schedule) { if (schedule.CurrentState == ResidentState.Ignored) { diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.cs b/src/RealTime/CustomAI/RealTimeResidentAI.cs index 134bc02347245824006853506bec82ef52501ce8..3f0ff0395b9c7ec8ab70895d85e6217ebf6cbb5a 100644 --- a/src/RealTime/CustomAI/RealTimeResidentAI.cs +++ b/src/RealTime/CustomAI/RealTimeResidentAI.cs @@ -3,7 +3,6 @@ namespace RealTime.CustomAI { using System; - using System.IO; using RealTime.Config; using RealTime.Core; using RealTime.Events; @@ -83,7 +82,7 @@ namespace RealTime.CustomAI return; } - ScheduleAction actionType = UpdateCitizenState(citizenId, ref citizen, ref schedule); + ScheduleAction actionType = UpdateCitizenState(ref citizen, ref schedule); switch (actionType) { case ScheduleAction.Ignore: diff --git a/src/RealTime/CustomAI/RealTimeTouristAI.cs b/src/RealTime/CustomAI/RealTimeTouristAI.cs index 1974cec4d81040c047f3e3203cc2d28017bd76a1..a6e55af18ecb8fe9293925fceb315259201ec25c 100644 --- a/src/RealTime/CustomAI/RealTimeTouristAI.cs +++ b/src/RealTime/CustomAI/RealTimeTouristAI.cs @@ -171,7 +171,7 @@ namespace RealTime.CustomAI return; } - ushort hotel = FindHotel(ref citizen, targetBuildingId); + ushort hotel = FindHotel(targetBuildingId); if (hotel != 0) { Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} changes the target and moves to a hotel {hotel} because of time or weather"); @@ -288,7 +288,7 @@ namespace RealTime.CustomAI break; case TouristTarget.Hotel: - ushort hotel = FindHotel(ref citizen, currentBuilding); + ushort hotel = FindHotel(currentBuilding); if (hotel == 0) { goto case TouristTarget.LeaveCity; @@ -345,7 +345,7 @@ namespace RealTime.CustomAI } } - private ushort FindHotel(ref TCitizen citizen, ushort currentBuilding) + private ushort FindHotel(ushort currentBuilding) { if (!Random.ShouldOccur(FindHotelChance)) { diff --git a/src/RealTime/CustomAI/WeatherInfo.cs b/src/RealTime/CustomAI/WeatherInfo.cs index b845176ed8ccfff9057d3d54c25fb80a4a78b2ca..15fade0defc09c65c4cadfb925dcc17175d13ba5 100644 --- a/src/RealTime/CustomAI/WeatherInfo.cs +++ b/src/RealTime/CustomAI/WeatherInfo.cs @@ -44,9 +44,13 @@ namespace RealTime.CustomAI { float weatherFactor = weatherManager.GetRainIntensity() + (weatherManager.GetSnowIntensity() / 2f); - stayInsideChance = weatherFactor < BadWeatherPrecipitationThreshold - ? 0u - : MinimumStayInsideChanceOnPrecipitation + + if (weatherFactor < BadWeatherPrecipitationThreshold) + { + stayInsideChance = 0u; + return; + } + + stayInsideChance = MinimumStayInsideChanceOnPrecipitation + (uint)((weatherFactor - BadWeatherPrecipitationThreshold) * ((100u - MinimumStayInsideChanceOnPrecipitation) / (1f - BadWeatherPrecipitationThreshold))); diff --git a/src/RealTime/Events/RealTimeCityEvent.cs b/src/RealTime/Events/RealTimeCityEvent.cs index 0c8fc44e418b0bbe67d75685f9d3c34aef70618f..b5ba433c546bb35afd4da4145d8b9e856d11ce74 100644 --- a/src/RealTime/Events/RealTimeCityEvent.cs +++ b/src/RealTime/Events/RealTimeCityEvent.cs @@ -12,7 +12,6 @@ namespace RealTime.Events internal sealed class RealTimeCityEvent : CityEventBase { private readonly CityEventTemplate eventTemplate; - private readonly int attendChanceAdjustment; private int attendeesCount; @@ -26,10 +25,19 @@ namespace RealTime.Events { this.eventTemplate = eventTemplate ?? throw new ArgumentNullException(nameof(eventTemplate)); var incentives = eventTemplate.Incentives?.Where(i => i.ActiveWhenRandomEvent).ToList(); - if (incentives != null) + if (incentives == null) + { + return; + } + + try { attendChanceAdjustment = incentives.Sum(i => i.PositiveEffect) - incentives.Sum(i => i.NegativeEffect); } + catch (OverflowException) + { + attendChanceAdjustment = 0; + } } /// diff --git a/src/RealTime/Events/RealTimeEventManager.cs b/src/RealTime/Events/RealTimeEventManager.cs index 99e81a685c76c5620a1db6863f4fa82c2913666e..525c8286a44da9995dfd378433f6ab5563b8e3ff 100644 --- a/src/RealTime/Events/RealTimeEventManager.cs +++ b/src/RealTime/Events/RealTimeEventManager.cs @@ -26,7 +26,7 @@ namespace RealTime.Events private static readonly TimeSpan EventStartTimeGranularity = TimeSpan.FromMinutes(30); private static readonly TimeSpan EventProcessInterval = TimeSpan.FromMinutes(15); - private static readonly ItemClass.Service[] EventBuildingServices = new[] { ItemClass.Service.Monument, ItemClass.Service.Beautification }; + private static readonly ItemClass.Service[] EventBuildingServices = { ItemClass.Service.Monument, ItemClass.Service.Beautification }; private readonly LinkedList upcomingEvents; private readonly RealTimeConfig config; @@ -126,11 +126,13 @@ namespace RealTime.Events return CityEventState.None; } - else if ((vanillaEventState & EventData.Flags.Active) != 0) + + if ((vanillaEventState & EventData.Flags.Active) != 0) { return CityEventState.Ongoing; } - else if (vanillaEventState != EventData.Flags.None) + + if (vanillaEventState != EventData.Flags.None) { return CityEventState.Finished; } @@ -140,7 +142,8 @@ namespace RealTime.Events { return CityEventState.Ongoing; } - else if (lastActiveEvent != null && lastActiveEvent.BuildingId == buildingId) + + if (lastActiveEvent != null && lastActiveEvent.BuildingId == buildingId) { return CityEventState.Finished; } diff --git a/src/RealTime/Events/Storage/CityEventsLoader.cs b/src/RealTime/Events/Storage/CityEventsLoader.cs index 872e241f4b39260bd4ee20fa9b167730db543b00..04ef3ec5197fecca0b1b6e3e60b47cfeaa00840d 100644 --- a/src/RealTime/Events/Storage/CityEventsLoader.cs +++ b/src/RealTime/Events/Storage/CityEventsLoader.cs @@ -50,11 +50,19 @@ namespace RealTime.Events.Storage string searchPath = Path.Combine(dataPath, EventsFolder); if (!Directory.Exists(searchPath)) { - Log.Warning($"The 'Real Time' mod did not found any event templates, the directory '{searchPath}' doesn't exist"); + Log.Warning($"The 'Real Time' mod did not find any event templates, the directory '{searchPath}' doesn't exist"); return; } - LoadEvents(Directory.GetFiles(searchPath, EventFileSearchPattern)); + try + { + string[] files = Directory.GetFiles(searchPath, EventFileSearchPattern); + LoadEvents(files); + } + catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) + { + Log.Warning($"The 'Real Time' mod could not load event templates, error message: {ex}"); + } } /// Clears the currently loaded city events templates collection. diff --git a/src/RealTime/GameConnection/IBuildingManagerConnection.cs b/src/RealTime/GameConnection/IBuildingManagerConnection.cs index 1ccb3e4829a6498ad26fbce9d55206668acd64b2..87767b8820c50a3cb48bd24de3690bae6aa67170 100644 --- a/src/RealTime/GameConnection/IBuildingManagerConnection.cs +++ b/src/RealTime/GameConnection/IBuildingManagerConnection.cs @@ -87,7 +87,7 @@ namespace RealTime.GameConnection /// /// Gets an ID of a random building in the city that belongs to any of the specified . /// - /// Thrown when the argument is null. + /// Thrown when the argument is null. /// /// A collection of that specifies in which services to /// search the random building in. diff --git a/src/RealTime/Localization/ILocalizationProvider.cs b/src/RealTime/Localization/ILocalizationProvider.cs index 95f514a78783da015dee3478aac5dba645938c5e..1fccb71a17a3d647000439ce40f6375f7e05804c 100644 --- a/src/RealTime/Localization/ILocalizationProvider.cs +++ b/src/RealTime/Localization/ILocalizationProvider.cs @@ -24,7 +24,7 @@ namespace RealTime.Localization /// by this mod. Can return null. /// The overridden translations type string. /// A map of key-value pairs for translations to override, or null. - /// Thrown when the argument is null. + /// Thrown when the argument is null. IDictionary GetOverriddenTranslations(string type); } } \ No newline at end of file diff --git a/src/RealTime/Patching/FastDelegate.cs b/src/RealTime/Patching/FastDelegate.cs index f9bcee28d628b6327e96e318cf4155a56a54f302..e74b4071bf9c8b35b37962714d8070a15ae9e79d 100644 --- a/src/RealTime/Patching/FastDelegate.cs +++ b/src/RealTime/Patching/FastDelegate.cs @@ -22,21 +22,18 @@ namespace RealTime.Patching /// method, the first parameter of the signature must be a reference to a /// instance. /// - /// /// Thrown when is null or an empty string. /// Thrown when more than one method is found with the specified + /// Thrown when the caller does not have the permissions necessary to access the method. /// and matching the specified signature. /// Thrown when no method with the specified is found /// that matches the specified signature. - /// /// A class that holds the method to create a delegate for. /// A delegate type representing the method signature. - /// /// The method name to create a delegate instance for. /// True if the type represents an instance method. /// That means, the first parameter of the signature will be processed /// as a reference to a instance (this reference). Default is true. - /// /// An instance of the delegate that can be called directly. public static TDelegate Create(string name, bool instanceMethod = true) where TDelegate : Delegate diff --git a/src/RealTime/Tools/GitVersion.cs b/src/RealTime/Tools/GitVersion.cs index 211442fca2a40da5e3bbc4ef734e75a8e687397a..9969fe6c235446886e4325bff9386304f8bb86f9 100644 --- a/src/RealTime/Tools/GitVersion.cs +++ b/src/RealTime/Tools/GitVersion.cs @@ -48,14 +48,27 @@ namespace RealTime.Tools return "?"; } - string version = versionField.GetValue(null) as string; - if (string.IsNullOrEmpty(version)) + try { - Log.Warning($"The '{GitVersionTypeName}.{VersionFieldName}' value is empty."); + string version = versionField.GetValue(null) as string; + if (string.IsNullOrEmpty(version)) + { + Log.Warning($"The '{GitVersionTypeName}.{VersionFieldName}' value is empty."); + return "?"; + } + + return version; + } + catch (TargetException) + { + Log.Warning($"The API of GitVersion has changed: '{GitVersionTypeName}.{VersionFieldName}' is not static."); + return "?"; + } + catch (FieldAccessException) + { + Log.Warning($"We are in restricted security context, the field '{GitVersionTypeName}.{VersionFieldName}' cannot be accessed."); return "?"; } - - return version; } } } diff --git a/src/RealTime/UI/CitiesCheckBoxItem.cs b/src/RealTime/UI/CitiesCheckBoxItem.cs index 2197a5a605113e367393a849a8fda6fb4da1d074..08a0003084b565092ebee6eb3032e21ee5a8e302 100644 --- a/src/RealTime/UI/CitiesCheckBoxItem.cs +++ b/src/RealTime/UI/CitiesCheckBoxItem.cs @@ -20,8 +20,8 @@ namespace RealTime.UI /// The property description that specifies the target property where to store the value. /// /// A method that provides the configuration storage object for the value. - /// Thrown when any argument is null. - /// + /// Thrown when any argument is null. + /// /// thrown when the is an empty string. /// public CitiesCheckBoxItem(UIHelperBase uiHelper, string id, PropertyInfo property, Func configProvider) @@ -31,12 +31,12 @@ namespace RealTime.UI /// Translates this view item using the specified localization provider. /// The localization provider to use for translation. - /// Thrown when the argument is null. + /// Thrown when the argument is null. public override void Translate(ILocalizationProvider localizationProvider) { if (localizationProvider == null) { - throw new System.ArgumentNullException(nameof(localizationProvider)); + throw new ArgumentNullException(nameof(localizationProvider)); } UIComponent.text = localizationProvider.Translate(UIComponent.name); @@ -55,12 +55,12 @@ namespace RealTime.UI /// The UI helper to use for item creation. /// The item's default value. /// A newly created view item. - /// Thrown when the argument is null. + /// Thrown when the argument is null. protected override UICheckBox CreateItem(UIHelperBase uiHelper, bool defaultValue) { if (uiHelper == null) { - throw new System.ArgumentNullException(nameof(uiHelper)); + throw new ArgumentNullException(nameof(uiHelper)); } return (UICheckBox)uiHelper.AddCheckbox(Constants.Placeholder, defaultValue, ValueChanged); diff --git a/src/RealTime/UI/CitiesSliderItem.cs b/src/RealTime/UI/CitiesSliderItem.cs index afeb4458a8aac67eecf0a78d799835740bd8b594..5205cdf71837859354dff154e62a4094933ae6e0 100644 --- a/src/RealTime/UI/CitiesSliderItem.cs +++ b/src/RealTime/UI/CitiesSliderItem.cs @@ -158,7 +158,7 @@ namespace RealTime.UI break; default: - valueString = (value * displayMultiplier).ToString(); + valueString = (value * displayMultiplier).ToString(currentCulture ?? CultureInfo.CurrentCulture); break; } diff --git a/src/RealTime/UI/CitiesViewItem.cs b/src/RealTime/UI/CitiesViewItem.cs index c395e5218ee095c4137448da33833776340383ba..0448d3eb9dc8066ebd8c92edd0be26112dd41247 100644 --- a/src/RealTime/UI/CitiesViewItem.cs +++ b/src/RealTime/UI/CitiesViewItem.cs @@ -9,6 +9,7 @@ namespace RealTime.UI using ColossalFramework.UI; using ICities; using RealTime.Localization; + using RealTime.Tools; /// A base class for the view items that can be displayed via the game's UI. /// The type of the view item. @@ -64,13 +65,33 @@ namespace RealTime.UI /// Gets current configuration item value. protected TValue Value { - get => (TValue)Convert.ChangeType(property.GetValue(configProvider(), null), typeof(TValue)); + get + { + try + { + object currentValue = property.GetValue(configProvider(), null); + return (TValue)Convert.ChangeType(currentValue, typeof(TValue)); + } + catch (Exception ex) + { + Log.Error($"The 'Real Time' mod was unable to read a configuration value, error message: {ex}"); + return default; + } + } + private set { - object newValue = property.PropertyType.IsEnum - ? Enum.ToObject(property.PropertyType, value) - : Convert.ChangeType(value, property.PropertyType); - property.SetValue(configProvider(), newValue, null); + try + { + object newValue = property.PropertyType.IsEnum + ? Enum.ToObject(property.PropertyType, value) + : Convert.ChangeType(value, property.PropertyType); + property.SetValue(configProvider(), newValue, null); + } + catch (Exception ex) + { + Log.Error($"The 'Real Time' mod was unable to update a configuration value, error message: {ex}"); + } } } diff --git a/src/RealTime/UI/ConfigUI.cs b/src/RealTime/UI/ConfigUI.cs index 24a2ac2ca24841dbed42a387c1a4c59480afc27f..429ed62157d3c87d3664a4776784f4cbc769d4f6 100644 --- a/src/RealTime/UI/ConfigUI.cs +++ b/src/RealTime/UI/ConfigUI.cs @@ -54,12 +54,44 @@ namespace RealTime.UI throw new InvalidOperationException("The configuration provider has no configuration yet"); } + var viewItems = new List(); + CreateViewItems(configProvider, itemFactory, viewItems); + + var result = new ConfigUI(configProvider, viewItems); + + IContainerViewItem toolsTab = itemFactory.CreateTabItem(ToolsId); + viewItems.Add(toolsTab); + + IViewItem resetButton = itemFactory.CreateButton(toolsTab, ResetToDefaultsId, result.ResetToDefaults); + viewItems.Add(resetButton); + IViewItem newGameConfigButton = itemFactory.CreateButton(toolsTab, UseForNewGamesId, result.UseForNewGames); + viewItems.Add(newGameConfigButton); + + return result; + } + + /// Closes this instance. + public void Close() + { + configProvider.Changed -= ConfigProviderChanged; + } + + /// Translates the UI using the specified localization provider. + /// The localization provider to use for translation. + public void Translate(ILocalizationProvider localizationProvider) + { + foreach (IViewItem item in viewItems) + { + item.Translate(localizationProvider); + } + } + + private static void CreateViewItems(ConfigurationProvider configProvider, IViewItemFactory itemFactory, ICollection viewItems) + { var properties = configProvider.Configuration.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) .Select(p => new { Property = p, Attribute = GetCustomItemAttribute(p) }) .Where(v => v.Attribute != null); - var viewItems = new List(); - foreach (var tab in properties.GroupBy(p => p.Attribute.TabId).OrderBy(p => p.Key)) { IContainerViewItem tabItem = itemFactory.CreateTabItem(tab.Key); @@ -88,34 +120,6 @@ namespace RealTime.UI } } } - - var result = new ConfigUI(configProvider, viewItems); - - IContainerViewItem toolsTab = itemFactory.CreateTabItem(ToolsId); - viewItems.Add(toolsTab); - - IViewItem resetButton = itemFactory.CreateButton(toolsTab, ResetToDefaultsId, result.ResetToDefaults); - viewItems.Add(resetButton); - IViewItem newGameConfigButton = itemFactory.CreateButton(toolsTab, UseForNewGamesId, result.UseForNewGames); - viewItems.Add(newGameConfigButton); - - return result; - } - - /// Closes this instance. - public void Close() - { - configProvider.Changed -= ConfigProviderChanged; - } - - /// Translates the UI using the specified localization provider. - /// The localization provider to use for translation. - public void Translate(ILocalizationProvider localizationProvider) - { - foreach (IViewItem item in viewItems) - { - item.Translate(localizationProvider); - } } private static IViewItem CreateViewItem( @@ -124,7 +128,7 @@ namespace RealTime.UI ConfigurationProvider configProvider, IViewItemFactory itemFactory) { - object config() => configProvider.Configuration; + object Config() => configProvider.Configuration; switch (GetCustomItemAttribute(property)) { @@ -139,7 +143,7 @@ namespace RealTime.UI container, property.Name, property, - config, + Config, slider.Min, slider.Max, slider.Step, @@ -147,10 +151,10 @@ namespace RealTime.UI slider.DisplayMultiplier); case ConfigItemCheckBoxAttribute _ when property.PropertyType == typeof(bool): - return itemFactory.CreateCheckBox(container, property.Name, property, config); + return itemFactory.CreateCheckBox(container, property.Name, property, Config); case ConfigItemComboBoxAttribute _ when property.PropertyType.IsEnum: - return itemFactory.CreateComboBox(container, property.Name, property, config, Enum.GetNames(property.PropertyType)); + return itemFactory.CreateComboBox(container, property.Name, property, Config, Enum.GetNames(property.PropertyType)); default: return null; diff --git a/src/RealTime/UI/CustomTimeBar.cs b/src/RealTime/UI/CustomTimeBar.cs index 587fe26bd54c3bf8de3f914746cc5c6e91e9c7e5..b48ec36f1b2a900afdfe83ec811ac70b923684a0 100644 --- a/src/RealTime/UI/CustomTimeBar.cs +++ b/src/RealTime/UI/CustomTimeBar.cs @@ -84,7 +84,12 @@ namespace RealTime.UI DateTime todayStart = customDateTimeWrapper.CurrentValue.Date; DateTime todayEnd = todayStart.AddDays(1).AddMilliseconds(-1); - foreach (UISprite item in progressSprite.components.Where(c => c.name != null && c.name.StartsWith(UISpriteEvent, StringComparison.Ordinal))) + + IEnumerable sprites = progressSprite.components + .OfType() + .Where(c => c.name != null && c.name.StartsWith(UISpriteEvent, StringComparison.Ordinal)); + + foreach (UISprite item in sprites) { SetEventTooltip(item, todayStart, todayEnd); } diff --git a/src/RealTime/UI/Popup.cs b/src/RealTime/UI/Popup.cs index 41bb60b8f0969ef8e70dbd722fc5d6c0a36e8bec..7e4b75daffa2b54976de2207bd7d4beb83b0703f 100644 --- a/src/RealTime/UI/Popup.cs +++ b/src/RealTime/UI/Popup.cs @@ -4,6 +4,7 @@ namespace RealTime.UI { + using System; using ColossalFramework.UI; using UnityEngine; @@ -22,11 +23,16 @@ namespace RealTime.UI private string text; private Vector2 popupPosition; + /// Shows a pop-up with the specified and . + /// The parent UI component of the pop-up. + /// The caption of the pop-up. + /// The text to display. + /// Thrown when is null. public static void Show(UIComponent parent, string caption, string text) { if (parent == null) { - throw new System.ArgumentNullException(nameof(parent)); + throw new ArgumentNullException(nameof(parent)); } Popup popup = parent.AddUIComponent(); @@ -36,6 +42,7 @@ namespace RealTime.UI popup.eventVisibilityChanged += popup.PopupVisibilityChanged; } + /// Called by the Unity engine to start this instance. public override void Start() { base.Start();