diff --git a/src/RealTime/Config/RealTimeConfig.cs b/src/RealTime/Config/RealTimeConfig.cs
index eee14169..533e4ddb 100644
--- a/src/RealTime/Config/RealTimeConfig.cs
+++ b/src/RealTime/Config/RealTimeConfig.cs
@@ -283,6 +283,13 @@ public RealTimeConfig(bool latestVersion)
[ConfigItemCheckBox]
public bool ShowIncompatibilityNotifications { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the mod should use the English-US time and date formats, if the English language is selected.
+ ///
+ [ConfigItem("Tools", 1)]
+ [ConfigItemCheckBox]
+ public bool UseEnglishUSFormats { get; set; }
+
/// Checks the version of the deserialized object and migrates it to the latest version when necessary.
public void MigrateWhenNecessary()
{
diff --git a/src/RealTime/Core/RealTimeCore.cs b/src/RealTime/Core/RealTimeCore.cs
index 8b173400..5785c7e0 100644
--- a/src/RealTime/Core/RealTimeCore.cs
+++ b/src/RealTime/Core/RealTimeCore.cs
@@ -26,6 +26,7 @@ namespace RealTime.Core
/// The core component of the Real Time mod. Activates and deactivates
/// the different parts of the mod's logic.
///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "This is the entry point and needs to instantiate all parts")]
internal sealed class RealTimeCore
{
private const string HarmonyId = "com.cities_skylines.dymanoid.realtime";
@@ -117,6 +118,8 @@ public static RealTimeCore Run(
LoadStorageData(new[] { configProvider }, StorageBase.CurrentLevelStorage);
}
+ localizationProvider.SetEnglishUSFormatsState(configProvider.Configuration.UseEnglishUSFormats);
+
var timeInfo = new TimeInfo(configProvider.Configuration);
var buildingManager = new BuildingManagerConnection();
var randomizer = new GameRandomizer();
@@ -224,6 +227,22 @@ public void Stop()
return;
}
+ ResidentAIPatch.RealTimeAI = null;
+ TouristAIPatch.RealTimeAI = null;
+ BuildingAIPatches.RealTimeAI = null;
+ BuildingAIPatches.WeatherInfo = null;
+ TransferManagerPatch.RealTimeAI = null;
+ SimulationHandler.EventManager = null;
+ SimulationHandler.DayTimeSimulation = null;
+ SimulationHandler.TimeAdjustment = null;
+ SimulationHandler.WeatherInfo = null;
+ SimulationHandler.Buildings = null;
+ SimulationHandler.CitizenProcessor = null;
+ SimulationHandler.Statistics?.Close();
+ SimulationHandler.Statistics = null;
+ ParkPatches.SpareTimeBehavior = null;
+ OutsideConnectionAIPatch.SpareTimeBehavior = null;
+
Log.Info($"The 'Real Time' mod reverts method patches.");
patcher.Revert();
@@ -241,22 +260,6 @@ public void Stop()
StorageBase.CurrentLevelStorage.GameSaving -= GameSaving;
- ResidentAIPatch.RealTimeAI = null;
- TouristAIPatch.RealTimeAI = null;
- BuildingAIPatches.RealTimeAI = null;
- BuildingAIPatches.WeatherInfo = null;
- TransferManagerPatch.RealTimeAI = null;
- SimulationHandler.EventManager = null;
- SimulationHandler.DayTimeSimulation = null;
- SimulationHandler.TimeAdjustment = null;
- SimulationHandler.WeatherInfo = null;
- SimulationHandler.Buildings = null;
- SimulationHandler.CitizenProcessor = null;
- SimulationHandler.Statistics?.Close();
- SimulationHandler.Statistics = null;
- ParkPatches.SpareTimeBehavior = null;
- OutsideConnectionAIPatch.SpareTimeBehavior = null;
-
WorldInfoPanelPatches.CitizenInfoPanel?.Disable();
WorldInfoPanelPatches.CitizenInfoPanel = null;
diff --git a/src/RealTime/Core/RealTimeMod.cs b/src/RealTime/Core/RealTimeMod.cs
index 0dcaafb8..22775a3e 100644
--- a/src/RealTime/Core/RealTimeMod.cs
+++ b/src/RealTime/Core/RealTimeMod.cs
@@ -216,6 +216,7 @@ private void ApplyLanguage()
if (localizationProvider.LoadTranslation(LocaleManager.instance.language))
{
+ localizationProvider.SetEnglishUSFormatsState(configProvider.Configuration.UseEnglishUSFormats);
core?.Translate(localizationProvider);
}
diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs b/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
index e17e285d..dffd719a 100644
--- a/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
+++ b/src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
@@ -101,10 +101,12 @@ private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citiz
if (currentLocation == Citizen.Location.Visit)
{
- ItemClass.Service service = BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen));
- if (service == ItemClass.Service.HealthCare || service == ItemClass.Service.Disaster)
+ ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);
+ switch (BuildingMgr.GetBuildingService(visitBuilding))
{
- return true;
+ case ItemClass.Service.HealthCare:
+ case ItemClass.Service.Disaster when !BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading):
+ return true;
}
}
@@ -115,17 +117,16 @@ private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citiz
private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
{
+ schedule.Schedule(ResidentState.Unknown);
ushort building = CitizenProxy.GetCurrentBuilding(ref citizen);
if (building == 0)
{
- schedule.Schedule(ResidentState.AtHome);
- return;
+ Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from current position");
+ TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
}
-
- schedule.Schedule(ResidentState.InShelter);
- if (schedule.CurrentState != ResidentState.InShelter)
+ else
{
- Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find an evacuation place");
+ Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from {building}");
residentAI.FindEvacuationPlace(instance, citizenId, building, residentAI.GetEvacuationReason(instance, building));
}
}
@@ -133,13 +134,17 @@ private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, u
private bool ProcessCitizenInShelter(ref CitizenSchedule schedule, ref TCitizen citizen)
{
ushort shelter = CitizenProxy.GetVisitBuilding(ref citizen);
- if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading) && schedule.ScheduledState == ResidentState.InShelter)
+ if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading))
{
CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
- schedule.Schedule(ResidentState.Unknown);
return true;
}
+ if (schedule.ScheduledState != ResidentState.Unknown)
+ {
+ schedule.Schedule(ResidentState.Unknown);
+ }
+
return false;
}
@@ -165,11 +170,10 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
true))
{
// Guided tours are treated as visits
- schedule.CurrentState = ResidentState.Visiting;
schedule.Hint = ScheduleHint.OnTour;
- return ScheduleAction.ProcessState;
}
+ schedule.CurrentState = ResidentState.InTransition;
return ScheduleAction.ProcessTransition;
}
@@ -180,15 +184,13 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
return ScheduleAction.ProcessState;
}
- ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);
- if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating)
- && buildingService != ItemClass.Service.Disaster)
+ if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating))
{
schedule.CurrentState = ResidentState.Evacuation;
- schedule.Schedule(ResidentState.InShelter);
return ScheduleAction.ProcessState;
}
+ ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);
switch (location)
{
case Citizen.Location.Home:
@@ -196,12 +198,6 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
return ScheduleAction.ProcessState;
case Citizen.Location.Work:
- if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
- {
- schedule.CurrentState = ResidentState.InShelter;
- return ScheduleAction.ProcessState;
- }
-
if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working)
{
// A citizen may visit their own work building (e.g. shopping),
@@ -209,6 +205,23 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
goto case Citizen.Location.Visit;
}
+ switch (buildingService)
+ {
+ case ItemClass.Service.Electricity:
+ case ItemClass.Service.Water:
+ case ItemClass.Service.HealthCare:
+ case ItemClass.Service.PoliceDepartment:
+ case ItemClass.Service.FireDepartment:
+ case ItemClass.Service.Disaster:
+ if (BuildingMgr.IsAreaEvacuating(currentBuilding))
+ {
+ schedule.CurrentState = ResidentState.InShelter;
+ return ScheduleAction.ProcessState;
+ }
+
+ break;
+ }
+
schedule.CurrentState = ResidentState.AtSchoolOrWork;
return ScheduleAction.ProcessState;
@@ -229,7 +242,7 @@ when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.
schedule.CurrentState = ResidentState.Shopping;
return ScheduleAction.ProcessState;
- case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating):
+ case ItemClass.Service.Disaster:
schedule.CurrentState = ResidentState.InShelter;
return ScheduleAction.ProcessState;
}
@@ -356,7 +369,9 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
return;
}
- if (schedule.CurrentState == ResidentState.AtHome && IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen))
+ if (schedule.CurrentState == ResidentState.AtHome
+ && schedule.ScheduledState != ResidentState.InShelter
+ && IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen))
{
Log.Debug(LogCategory.Simulation, $" *** Citizen {citizenId} is virtual this time");
schedule.Schedule(ResidentState.Unknown);
@@ -368,18 +383,15 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
{
case ResidentState.AtHome:
DoScheduledHome(ref schedule, instance, citizenId, ref citizen);
- executed = true;
- break;
+ return;
case ResidentState.AtSchoolOrWork:
DoScheduledWork(ref schedule, instance, citizenId, ref citizen);
- executed = true;
- break;
+ return;
case ResidentState.Shopping when schedule.WorkStatus == WorkStatus.Working:
DoScheduledLunch(ref schedule, instance, citizenId, ref citizen);
- executed = true;
- break;
+ return;
case ResidentState.Shopping:
executed = DoScheduledShopping(ref schedule, instance, citizenId, ref citizen);
@@ -389,10 +401,9 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
executed = DoScheduledRelaxing(ref schedule, instance, citizenId, ref citizen);
break;
- case ResidentState.InShelter:
+ case ResidentState.InShelter when schedule.CurrentState != ResidentState.InShelter:
DoScheduledEvacuation(ref schedule, instance, citizenId, ref citizen);
- executed = true;
- break;
+ return;
default:
return;
diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs b/src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
index 7215ac9b..5e13653d 100644
--- a/src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
+++ b/src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
@@ -9,7 +9,7 @@ namespace RealTime.CustomAI
internal sealed partial class RealTimeResidentAI
{
- private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
+ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
ushort instanceId = CitizenProxy.GetInstance(ref citizen);
ushort vehicleId = CitizenProxy.GetVehicle(ref citizen);
@@ -39,15 +39,27 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
return true;
}
- if (vehicleId == 0 && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating) && CitizenMgr.IsAreaEvacuating(instanceId))
+ bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);
+ if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
- schedule.Schedule(ResidentState.Unknown);
- schedule.DepartureTime = default;
- TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
+ schedule.CurrentState = ResidentState.Evacuation;
+ return false;
+ }
+
+ if (isEvacuating)
+ {
return true;
}
+ if (schedule.Hint == ScheduleHint.OnTour)
+ {
+ Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a tour");
+ schedule.Schedule(ResidentState.Unknown);
+ schedule.Hint = ScheduleHint.None;
+ return false;
+ }
+
ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);
bool headingToWork = targetBuilding == CitizenProxy.GetWorkBuilding(ref citizen);
if (vehicleId != 0 && schedule.DepartureTime != default)
@@ -67,7 +79,6 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip because of traffic jam");
schedule.Schedule(ResidentState.Relaxing);
schedule.Hint = ScheduleHint.RelaxNearbyOnly;
- schedule.CurrentState = ResidentState.InTransition;
return false;
}
}
@@ -82,7 +93,6 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip to a park due to bad weather");
schedule.Schedule(ResidentState.AtHome);
- schedule.CurrentState = ResidentState.InTransition;
return false;
}
diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs b/src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
index 9a30a97f..0743751d 100644
--- a/src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
+++ b/src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
@@ -246,13 +246,6 @@ private bool ProcessCitizenShopping(ref CitizenSchedule schedule, uint citizenId
private bool ProcessCitizenVisit(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
- if (schedule.Hint == ScheduleHint.OnTour)
- {
- Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a tour");
- schedule.Schedule(ResidentState.Unknown);
- return true;
- }
-
return RescheduleVisit(ref schedule, citizenId, ref citizen, CitizenProxy.GetVisitBuilding(ref citizen));
}
diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.cs b/src/RealTime/CustomAI/RealTimeResidentAI.cs
index 8a991456..199932d7 100644
--- a/src/RealTime/CustomAI/RealTimeResidentAI.cs
+++ b/src/RealTime/CustomAI/RealTimeResidentAI.cs
@@ -97,15 +97,20 @@ public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen)
case ScheduleAction.Ignore:
return;
- case ScheduleAction.ProcessTransition when ProcessCitizenMoving(ref schedule, instance, citizenId, ref citizen):
+ case ScheduleAction.ProcessTransition when ProcessCitizenMoving(ref schedule, citizenId, ref citizen):
return;
}
- if (schedule.CurrentState == ResidentState.Unknown)
+ switch (schedule.CurrentState)
{
- Log.Debug(LogCategory.State, TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in an UNKNOWN state! Changing to 'moving'");
- CitizenProxy.SetLocation(ref citizen, Citizen.Location.Moving);
- return;
+ case ResidentState.Unknown:
+ Log.Debug(LogCategory.State, TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in an UNKNOWN state! Changing to 'moving'");
+ CitizenProxy.SetLocation(ref citizen, Citizen.Location.Moving);
+ return;
+
+ case ResidentState.Evacuation:
+ schedule.Schedule(ResidentState.InShelter);
+ break;
}
if (TimeInfo.Now < schedule.ScheduledStateTime)
@@ -113,7 +118,8 @@ public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen)
return;
}
- bool updated = UpdateCitizenSchedule(ref schedule, citizenId, ref citizen);
+ Log.Debug(LogCategory.State, TimeInfo.Now, $"Citizen {citizenId} is in state {schedule.CurrentState}");
+ bool updated = schedule.CurrentState != ResidentState.InShelter && UpdateCitizenSchedule(ref schedule, citizenId, ref citizen);
ExecuteCitizenSchedule(ref schedule, instance, citizenId, ref citizen, updated);
}
diff --git a/src/RealTime/CustomAI/RealTimeTouristAI.cs b/src/RealTime/CustomAI/RealTimeTouristAI.cs
index 0114133b..4c3f177d 100644
--- a/src/RealTime/CustomAI/RealTimeTouristAI.cs
+++ b/src/RealTime/CustomAI/RealTimeTouristAI.cs
@@ -109,10 +109,16 @@ private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)
return;
}
- if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
+ bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);
+ if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Searching for a shelter.");
- touristAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetCurrentBuilding(ref citizen), touristAI.GetEvacuationReason(instance, 0));
+ TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, touristAI.GetEvacuationReason(instance, 0));
+ return;
+ }
+
+ if (isEvacuating)
+ {
return;
}
diff --git a/src/RealTime/CustomAI/ResidentState.cs b/src/RealTime/CustomAI/ResidentState.cs
index 7c11686a..917afe0f 100644
--- a/src/RealTime/CustomAI/ResidentState.cs
+++ b/src/RealTime/CustomAI/ResidentState.cs
@@ -34,7 +34,7 @@ internal enum ResidentState : byte
/// The citizen is in a shelter building.
InShelter,
- /// The citizen was in transition from one state to another, but must change the decision.
+ /// The citizen was in transition from one state to another.
InTransition,
}
}
\ No newline at end of file
diff --git a/src/RealTime/GameConnection/BuildingManagerConnection.cs b/src/RealTime/GameConnection/BuildingManagerConnection.cs
index 0e42af78..f3e07dbb 100644
--- a/src/RealTime/GameConnection/BuildingManagerConnection.cs
+++ b/src/RealTime/GameConnection/BuildingManagerConnection.cs
@@ -418,6 +418,18 @@ public DistrictPolicies.Park GetParkPolicies(byte parkId)
: DistrictManager.instance.m_parks.m_buffer[parkId].m_parkPolicies;
}
+ ///
+ /// Determines whether the area around the building with specified ID is currently being evacuated.
+ ///
+ /// The building ID to check.
+ ///
+ /// true if the area around the building with specified ID is currently being evacuated.; otherwise, false.
+ ///
+ public bool IsAreaEvacuating(ushort buildingId)
+ {
+ return buildingId != 0 && DisasterManager.instance.IsEvacuating(BuildingManager.instance.m_buildings.m_buffer[buildingId].m_position);
+ }
+
private static bool BuildingCanBeVisited(ushort buildingId)
{
uint currentUnitId = BuildingManager.instance.m_buildings.m_buffer[buildingId].m_citizenUnits;
diff --git a/src/RealTime/GameConnection/IBuildingManagerConnection.cs b/src/RealTime/GameConnection/IBuildingManagerConnection.cs
index 57d9e4f0..81e73a66 100644
--- a/src/RealTime/GameConnection/IBuildingManagerConnection.cs
+++ b/src/RealTime/GameConnection/IBuildingManagerConnection.cs
@@ -178,5 +178,14 @@ ushort FindActiveBuilding(
/// The ID of the park to get policies of.
/// The policies of the park.
DistrictPolicies.Park GetParkPolicies(byte parkId);
+
+ ///
+ /// Determines whether the area around the building with specified ID is currently being evacuated.
+ ///
+ /// The building ID to check.
+ ///
+ /// true if the area around the building with specified ID is currently being evacuated.; otherwise, false.
+ ///
+ bool IsAreaEvacuating(ushort buildingId);
}
}
\ No newline at end of file
diff --git a/src/RealTime/Localization/Translations/de.xml b/src/RealTime/Localization/Translations/de.xml
index ae6a4eb8..d8dce311 100644
--- a/src/RealTime/Localization/Translations/de.xml
+++ b/src/RealTime/Localization/Translations/de.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/en.xml b/src/RealTime/Localization/Translations/en.xml
index 4a93a5a9..1916fc8f 100644
--- a/src/RealTime/Localization/Translations/en.xml
+++ b/src/RealTime/Localization/Translations/en.xml
@@ -8,7 +8,8 @@
-
+
+
diff --git a/src/RealTime/Localization/Translations/es.xml b/src/RealTime/Localization/Translations/es.xml
index 79fee0ab..9497720b 100644
--- a/src/RealTime/Localization/Translations/es.xml
+++ b/src/RealTime/Localization/Translations/es.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/fr.xml b/src/RealTime/Localization/Translations/fr.xml
index 65cfa0cb..b64c445d 100644
--- a/src/RealTime/Localization/Translations/fr.xml
+++ b/src/RealTime/Localization/Translations/fr.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/ko.xml b/src/RealTime/Localization/Translations/ko.xml
index f8062a62..c4ef1a75 100644
--- a/src/RealTime/Localization/Translations/ko.xml
+++ b/src/RealTime/Localization/Translations/ko.xml
@@ -5,9 +5,11 @@
-
+
+
+
diff --git a/src/RealTime/Localization/Translations/pl.xml b/src/RealTime/Localization/Translations/pl.xml
index c7d3282e..89266b05 100644
--- a/src/RealTime/Localization/Translations/pl.xml
+++ b/src/RealTime/Localization/Translations/pl.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/pt.xml b/src/RealTime/Localization/Translations/pt.xml
index 59b13e58..f45d4436 100644
--- a/src/RealTime/Localization/Translations/pt.xml
+++ b/src/RealTime/Localization/Translations/pt.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/ru.xml b/src/RealTime/Localization/Translations/ru.xml
index ddbd6436..17b51d63 100644
--- a/src/RealTime/Localization/Translations/ru.xml
+++ b/src/RealTime/Localization/Translations/ru.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Localization/Translations/zh.xml b/src/RealTime/Localization/Translations/zh.xml
index 9bd8fd27..c084ed2c 100644
--- a/src/RealTime/Localization/Translations/zh.xml
+++ b/src/RealTime/Localization/Translations/zh.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/RealTime/Simulation/TimeAdjustment.cs b/src/RealTime/Simulation/TimeAdjustment.cs
index ee6bd073..c197e6df 100644
--- a/src/RealTime/Simulation/TimeAdjustment.cs
+++ b/src/RealTime/Simulation/TimeAdjustment.cs
@@ -13,6 +13,7 @@ internal sealed class TimeAdjustment
{
private const int RealtimeSpeed = 23;
private readonly uint vanillaFramesPerDay;
+ private readonly TimeSpan vanillaTimePerFrame;
private readonly RealTimeConfig config;
private uint dayTimeSpeed;
@@ -29,6 +30,7 @@ public TimeAdjustment(RealTimeConfig config)
{
this.config = config ?? throw new ArgumentNullException(nameof(config));
vanillaFramesPerDay = SimulationManager.DAYTIME_FRAMES;
+ vanillaTimePerFrame = SimulationManager.instance.m_timePerFrame;
}
/// Enables the customized time adjustment.
@@ -39,16 +41,19 @@ public DateTime Enable(bool setDefaultTime)
{
dayTimeSpeed = config.DayTimeSpeed;
nightTimeSpeed = config.NightTimeSpeed;
- isNightTime = SimulationManager.instance.m_isNightTime;
isNightEnabled = SimulationManager.instance.m_enableDayNight;
+ DateTime now = SimulationManager.instance.m_ThreadingWrapper.simulationTime;
if (setDefaultTime)
{
- DateTime currentDate = SimulationManager.instance.m_ThreadingWrapper.simulationTime.Date;
- SetGameDateTime(currentDate.AddHours(config.WakeUpHour));
+ now = now.Date.AddHours(config.WakeUpHour);
+ SetGameDateTime(now);
}
- return UpdateTimeSimulationValues(CalculateFramesPerDay());
+ float currentHour = now.TimeOfDay.Hours;
+ isNightTime = currentHour < config.WakeUpHour || currentHour >= config.GoToSleepHour;
+
+ return UpdateTimeSimulationValues(CalculateFramesPerDay(), useCustomTimePerFrame: true);
}
/// Updates the time adjustment to be synchronized with the configuration and the daytime.
@@ -74,14 +79,14 @@ public bool Update(bool force)
uint currentFramesPerDay = SimulationManager.DAYTIME_FRAMES;
uint newFramesPerDay = CalculateFramesPerDay();
- UpdateTimeSimulationValues(newFramesPerDay);
+ UpdateTimeSimulationValues(newFramesPerDay, useCustomTimePerFrame: true);
return currentFramesPerDay != newFramesPerDay;
}
/// Disables the customized time adjustment restoring the default vanilla values.
public void Disable()
{
- UpdateTimeSimulationValues(vanillaFramesPerDay);
+ UpdateTimeSimulationValues(vanillaFramesPerDay, useCustomTimePerFrame: false);
}
/// Gets the original time represented by the frame index.
@@ -138,7 +143,7 @@ private static void SetGameDateTime(DateTime dateTime)
sm.m_dayTimeOffsetFrames = sm.m_dayTimeFrame - sm.m_currentFrameIndex & SimulationManager.DAYTIME_FRAMES - 1;
}
- private DateTime UpdateTimeSimulationValues(uint framesPerDay)
+ private DateTime UpdateTimeSimulationValues(uint framesPerDay, bool useCustomTimePerFrame)
{
SimulationManager.DAYTIME_FRAMES = framesPerDay;
SimulationManager.DAYTIME_FRAME_TO_HOUR = 24f / SimulationManager.DAYTIME_FRAMES;
@@ -150,7 +155,10 @@ private DateTime UpdateTimeSimulationValues(uint framesPerDay)
originalTimeOffsetTicks = sm.m_timeOffsetTicks;
DateTime originalDate = sm.m_ThreadingWrapper.simulationTime;
- sm.m_timePerFrame = new TimeSpan(24L * 3600L * 10_000_000L / framesPerDay);
+ sm.m_timePerFrame = useCustomTimePerFrame
+ ? new TimeSpan(24L * 3600L * 10_000_000L / framesPerDay)
+ : vanillaTimePerFrame;
+
SetGameDateTime(originalDate);
return sm.m_currentGameTime;
diff --git a/src/SkyTools b/src/SkyTools
index a0c6bf9c..dfc3a01f 160000
--- a/src/SkyTools
+++ b/src/SkyTools
@@ -1 +1 @@
-Subproject commit a0c6bf9cf2661b6c3361098f2e387c5caffcc842
+Subproject commit dfc3a01f272061790cd0f08b426668cc2c81ed60