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