Skip to content

Commit

Permalink
Merge branch 'feature-time-speed'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Jul 1, 2018
2 parents e816b18 + 17274bc commit ae0711f
Show file tree
Hide file tree
Showing 16 changed files with 172 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/RealTime/Config/ConfigurationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private static RealTimeConfig Deserialize()
var serializer = new XmlSerializer(typeof(RealTimeConfig));
using (var sr = new StreamReader(SettingsFileName))
{
return (RealTimeConfig)serializer.Deserialize(sr);
return ((RealTimeConfig)serializer.Deserialize(sr)).Validate();
}
}

Expand Down
67 changes: 62 additions & 5 deletions src/RealTime/Config/RealTimeConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace RealTime.Config
{
using System.Collections.Generic;
using RealTime.UI;

/// <summary>
Expand All @@ -12,37 +13,51 @@ namespace RealTime.Config
public sealed class RealTimeConfig
{
/// <summary>
/// Gets or sets the virtual citizens mode.
/// Gets or sets the speed of the time flow on daytime. Valid values are 1..7.
/// </summary>
[ConfigItem("1General", 0)]
[ConfigItemSlider(1, 7, ValueType = SliderValueType.Default)]
public uint DayTimeSpeed { get; set; } = 5;

/// <summary>
/// Gets or sets the speed of the time flow on night time. Valid values are 1..7.
/// </summary>
[ConfigItem("1General", 1)]
[ConfigItemSlider(1, 7, ValueType = SliderValueType.Default)]
public uint NightTimeSpeed { get; set; } = 5;

/// <summary>
/// Gets or sets the virtual citizens mode.
/// </summary>
[ConfigItem("1General", 2)]
[ConfigItemComboBox]
public VirtualCitizensLevel VirtualCitizens { get; set; } = VirtualCitizensLevel.Few;

/// <summary>
/// Gets or sets a value indicating whether the weekends are enabled. Cims don't go to work on weekends.
/// </summary>
[ConfigItem("1General", 1)]
[ConfigItem("1General", 3)]
[ConfigItemCheckBox]
public bool IsWeekendEnabled { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether Cims should go out at lunch for food.
/// </summary>
[ConfigItem("1General", 2)]
[ConfigItem("1General", 4)]
[ConfigItemCheckBox]
public bool IsLunchtimeEnabled { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether the construction sites should pause at night time.
/// </summary>
[ConfigItem("1General", 3)]
[ConfigItem("1General", 5)]
[ConfigItemCheckBox]
public bool StopConstructionAtNight { get; set; } = true;

/// <summary>
/// Gets or sets the percentage value of the building construction speed. Valid values are 1..100.
/// </summary>
[ConfigItem("1General", 4)]
[ConfigItem("1General", 6)]
[ConfigItemSlider(1, 100)]
public uint ConstructionSpeed { get; set; } = 50;

Expand Down Expand Up @@ -149,5 +164,47 @@ public sealed class RealTimeConfig
[ConfigItem("4Time", 6)]
[ConfigItemSlider(11, 16, 0.25f, SliderValueType.Time)]
public float SchoolEnd { get; set; } = 14f;

/// <summary>Validates this instance and corrects possible invalid property values.</summary>
/// <returns>This instance.</returns>
public RealTimeConfig Validate()
{
DayTimeSpeed = Clamp(DayTimeSpeed, 1u, 7u);
NightTimeSpeed = Clamp(NightTimeSpeed, 1u, 7u);
VirtualCitizens = (VirtualCitizensLevel)Clamp((int)VirtualCitizens, (int)VirtualCitizensLevel.None, (int)VirtualCitizensLevel.Many);
ConstructionSpeed = Clamp(ConstructionSpeed, 0u, 100u);
LunchQuota = Clamp(LunchQuota, 0u, 100u);
LocalBuildingSearchQuota = Clamp(LocalBuildingSearchQuota, 0u, 100u);
OnTimeQuota = Clamp(OnTimeQuota, 0u, 100u);
EarliestHourEventStartWeekday = Clamp(EarliestHourEventStartWeekday, 0f, 23.75f);
LatestHourEventStartWeekday = Clamp(LatestHourEventStartWeekday, 0f, 23.75f);
EarliestHourEventStartWeekend = Clamp(EarliestHourEventStartWeekend, 0f, 23.75f);
LatestHourEventStartWeekend = Clamp(LatestHourEventStartWeekend, 0f, 23.75f);
WorkBegin = Clamp(WorkBegin, 4f, 11f);
WorkEnd = Clamp(WorkEnd, 12f, 20f);
LunchBegin = Clamp(LunchBegin, 11f, 13f);
LunchEnd = Clamp(LunchEnd, 13f, 15f);
SchoolBegin = Clamp(SchoolBegin, 4f, 10f);
SchoolEnd = Clamp(SchoolEnd, 11f, 16f);
MaxOvertime = Clamp(MaxOvertime, 0f, 4f);
return this;
}

private static T Clamp<T>(T value, T min, T max)
where T : struct
{
Comparer<T> comparer = Comparer<T>.Default;
if (comparer.Compare(value, min) < 0)
{
return min;
}

if (comparer.Compare(value, max) > 0)
{
return max;
}

return value;
}
}
}
4 changes: 3 additions & 1 deletion src/RealTime/Core/RealTimeCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ public static RealTimeCore Run(RealTimeConfig config, string rootPath, Localizat
return null;
}

var timeAdjustment = new TimeAdjustment();
var timeAdjustment = new TimeAdjustment(config);
DateTime gameDate = timeAdjustment.Enable();
SimulationHandler.TimeAdjustment = timeAdjustment;

var timeInfo = new TimeInfo();
var buildingManager = new BuildingManagerConnection();
Expand Down Expand Up @@ -155,6 +156,7 @@ public void Stop()
SimulationHandler.EventManager = null;
SimulationHandler.DayTimeSimulation = null;
SimulationHandler.CommercialAI = null;
SimulationHandler.TimeAdjustment = null;

try
{
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/de.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="de" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="Allgemein" />
<translation id="DayTimeSpeed" value="Zeitgeschw. (Tag)" />
<translation id="DayTimeSpeedTooltip" value="Die Zeitgeschwindigkeit am Tag. '1' ist sehr langsam - fast in Echtzeit!" />
<translation id="NightTimeSpeed" value="Zeitgeschw. (Nacht)" />
<translation id="NightTimeSpeedTooltip" value="Die Zeitgeschwindigkeit in der Nacht. '1' ist sehr langsam - fast in Echtzeit!" />
<translation id="VirtualCitizens" value="Simulation der Einwohner (real und virtuell)" />
<translation id="VirtualCitizensTooltip" value="Wählen sie 'Alle' aus für eine reale Stadt (aber max 65.535 Einw.) oder 'Original' / 'Mehr' bei schwachem PC" />
<translation id="VirtualCitizens.None" value="Alle Einwohner sind real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="en" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.535 citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/es.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="es" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.535 citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/fr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="fr" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="Général" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.53k citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/ko.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="ko" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.535 citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/pl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="pl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.535 citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/pt.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="pt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'All' for a real city (but max 65.535 citizens), select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/ru.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="ru" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="Основные" />
<translation id="DayTimeSpeed" value="Скорось времени (день)" />
<translation id="DayTimeSpeedTooltip" value="Скорость течения времени днём. '1' очень медленно - почти реальное время!" />
<translation id="NightTimeSpeed" value="Скорось времени (ночь)" />
<translation id="NightTimeSpeedTooltip" value="Скорость течения времени ночью. '1' очень медленно - почти реальное время!" />
<translation id="VirtualCitizens" value="Метод симуляции жителей (реальных и виртуальных)" />
<translation id="VirtualCitizensTooltip" value="Выберите 'Все' для реального города (но макс. 65.535 жителей или 'Оригинально' / 'Больше', если компьютер слаб" />
<translation id="VirtualCitizens.None" value="Все жители города реальные" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Localization/Translations/zh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<language id="zh" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<translation id="1General" value="General" />
<translation id="DayTimeSpeed" value="Time speed (day)" />
<translation id="DayTimeSpeedTooltip" value="The speed of the time flow on daytime. '1' is very slow - almost real time!" />
<translation id="NightTimeSpeed" value="Time speed (night)" />
<translation id="NightTimeSpeedTooltip" value="The speed of the time flow on night time. '1' is very slow - almost real time!" />
<translation id="VirtualCitizens" value="Citizens simulation mode (real and virtual)" />
<translation id="VirtualCitizensTooltip" value="Select 'None' for 100% real city, select 'Vanilla' or 'More' if your PC is weak" />
<translation id="VirtualCitizens.None" value="All citizens are real" />
Expand Down
4 changes: 4 additions & 0 deletions src/RealTime/Simulation/SimulationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,17 @@ public sealed class SimulationHandler : ThreadingExtensionBase
/// </summary>
internal static RealTimeCommercialBuildingAI CommercialAI { get; set; }

/// <summary>Gets or sets the time adjustment simulation class instance.</summary>
internal static TimeAdjustment TimeAdjustment { get; set; }

/// <summary>
/// Called after each game simulation tick. A tick contains multiple frames.
/// Performs the dispatching for this simulation phase.
/// </summary>
public override void OnAfterSimulationTick()
{
EventManager?.ProcessEvents();
TimeAdjustment?.Update();

DateTime currentDate = SimulationManager.instance.m_currentGameTime.Date;
if (currentDate != lastHandledDate)
Expand Down
68 changes: 40 additions & 28 deletions src/RealTime/Simulation/TimeAdjustment.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,62 @@
// <copyright file="TimeAdjustment.cs" company="dymanoid">
// Copyright (c) dymanoid. All rights reserved.
// </copyright>
// <copyright file="TimeAdjustment.cs" company="dymanoid">Copyright (c) dymanoid. All rights reserved.</copyright>

namespace RealTime.Simulation
{
using System;
using RealTime.Tools;
using RealTime.Config;

/// <summary>
/// Manages the customized time adjustment. This class depends on the <see cref="SimulationManager"/> class.
/// </summary>
internal sealed class TimeAdjustment
{
private const int CustomFramesPerDay = 1 << 17;
private static readonly TimeSpan CustomTimePerFrame = new TimeSpan(24L * 3600L * 10_000_000L / CustomFramesPerDay);

private const int RealtimeSpeed = 23;
private readonly uint vanillaFramesPerDay;
private readonly TimeSpan vanillaTimePerFrame;
private readonly RealTimeConfig config;
private uint lastDayTimeSpeed;
private uint lastNightTimeSpeed;
private bool isDayTime;

/// <summary>
/// Initializes a new instance of the <see cref="TimeAdjustment"/> class.
/// </summary>
public TimeAdjustment()
/// <summary>Initializes a new instance of the <see cref="TimeAdjustment"/> class.</summary>
/// <param name="config">The configuration to run with.</param>
/// <exception cref="ArgumentNullException">Thrown when the argument is null.</exception>
public TimeAdjustment(RealTimeConfig config)
{
this.config = config ?? throw new ArgumentNullException(nameof(config));
lastDayTimeSpeed = config.DayTimeSpeed;
lastNightTimeSpeed = config.NightTimeSpeed;
vanillaFramesPerDay = SimulationManager.DAYTIME_FRAMES;
vanillaTimePerFrame = SimulationManager.instance.m_timePerFrame;
}

/// <summary>
/// Enables the customized time adjustment.
/// </summary>
///
/// <summary>Enables the customized time adjustment.</summary>
/// <returns>The current game date and time.</returns>
public DateTime Enable()
{
if (vanillaTimePerFrame == CustomTimePerFrame)
isDayTime = !SimulationManager.instance.m_isNightTime;
return UpdateTimeSimulationValues(CalculateFramesPerDay());
}

/// <summary>Updates the time adjustment to be synchronized with the configuration and the daytime.</summary>
public void Update()
{
if (SimulationManager.instance.m_isNightTime == isDayTime
|| lastDayTimeSpeed != config.DayTimeSpeed
|| lastNightTimeSpeed != config.NightTimeSpeed)
{
Log.Warning("The 'Real Time' mod has not been properly deactivated! Check the TimeAdjustment.Disable() calls.");
isDayTime = !SimulationManager.instance.m_isNightTime;
lastDayTimeSpeed = config.DayTimeSpeed;
lastNightTimeSpeed = config.NightTimeSpeed;
UpdateTimeSimulationValues(CalculateFramesPerDay());
}

return UpdateTimeSimulationValues(CustomFramesPerDay, CustomTimePerFrame);
}

/// <summary>
/// Disables the customized time adjustment restoring the default vanilla values.
/// </summary>
/// <summary>Disables the customized time adjustment restoring the default vanilla values.</summary>
public void Disable()
{
UpdateTimeSimulationValues(vanillaFramesPerDay, vanillaTimePerFrame);
UpdateTimeSimulationValues(vanillaFramesPerDay);
}

private static DateTime UpdateTimeSimulationValues(uint framesPerDay, TimeSpan timePerFrame)
private static DateTime UpdateTimeSimulationValues(uint framesPerDay)
{
SimulationManager sm = SimulationManager.instance;
DateTime originalDate = sm.m_ThreadingWrapper.simulationTime;
Expand All @@ -59,7 +65,7 @@ private static DateTime UpdateTimeSimulationValues(uint framesPerDay, TimeSpan t
SimulationManager.DAYTIME_FRAME_TO_HOUR = 24f / SimulationManager.DAYTIME_FRAMES;
SimulationManager.DAYTIME_HOUR_TO_FRAME = SimulationManager.DAYTIME_FRAMES / 24f;

sm.m_timePerFrame = timePerFrame;
sm.m_timePerFrame = new TimeSpan(24L * 3600L * 10_000_000L / framesPerDay);
sm.m_timeOffsetTicks = originalDate.Ticks - (sm.m_currentFrameIndex * sm.m_timePerFrame.Ticks);
sm.m_currentGameTime = originalDate;

Expand All @@ -69,5 +75,11 @@ private static DateTime UpdateTimeSimulationValues(uint framesPerDay, TimeSpan t

return sm.m_currentGameTime;
}

private uint CalculateFramesPerDay()
{
uint offset = isDayTime ? lastDayTimeSpeed : lastNightTimeSpeed;
return 1u << (int)(RealtimeSpeed - offset);
}
}
}
}
Loading

0 comments on commit ae0711f

Please sign in to comment.