Updated day cycle (#171)

* Updated day cycle

* Fixed DayCycleComponent attributes

* Added new commands, as well as synchronization

* Update cave-arena.yml

* Update alchemy_test.yml

---------

Co-authored-by: Ed <edwardxperia2000@gmail.com>
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
This commit is contained in:
Tornado Tech
2024-06-05 00:54:49 +10:00
committed by GitHub
parent fdf9413088
commit 95b726c0ff
10 changed files with 455 additions and 177 deletions

View File

@@ -0,0 +1,73 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.DayCycle;
/// <summary>
/// Stores all the necessary data for the day and night cycle system to work
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14DayCycleSystem))]
public sealed partial class CP14DayCycleComponent : Component
{
[ViewVariables]
public int NextTimeEntryIndex => CurrentTimeEntryIndex + 1 >= TimeEntries.Count ? 0 : CurrentTimeEntryIndex + 1;
[ViewVariables]
public DayCycleEntry CurrentTimeEntry => TimeEntries[CurrentTimeEntryIndex];
[ViewVariables]
public DayCycleEntry NextCurrentTimeEntry => TimeEntries[NextTimeEntryIndex];
[ViewVariables]
public Color StartColor => CurrentTimeEntry.Color;
[ViewVariables]
public Color EndColor => NextCurrentTimeEntry.Color;
[DataField(required: true), ViewVariables, AutoNetworkedField]
public List<DayCycleEntry> TimeEntries = new();
[DataField, ViewVariables, AutoNetworkedField]
public bool IsNight; // TODO: Rewrite this shit
[DataField, ViewVariables, AutoNetworkedField]
public int CurrentTimeEntryIndex;
[DataField, ViewVariables, AutoNetworkedField]
public TimeSpan EntryStartTime;
[DataField, ViewVariables, AutoNetworkedField]
public TimeSpan EntryEndTime;
}
[DataDefinition, NetSerializable, Serializable]
public readonly partial record struct DayCycleEntry()
{
/// <summary>
/// The color of the world's lights at the beginning of this time of day
/// </summary>
[DataField]
public Color Color { get; init; } = Color.White;
/// <summary>
/// Duration of color shift to the next time of day
/// </summary>
[DataField]
public TimeSpan Duration { get; init; } = TimeSpan.FromSeconds(60);
[DataField]
public bool IsNight { get; init; } = false;
}
/// <summary>
/// Event raised on map entity, wen night is started
/// </summary>
[ByRefEvent]
public readonly record struct DayCycleNightStartedEvent(EntityUid Map);
/// <summary>
/// Event raised on map entity, wen night is started
/// </summary>
[ByRefEvent]
public readonly record struct DayCycleDayStartedEvent(EntityUid Map);

View File

@@ -0,0 +1,135 @@
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
namespace Content.Shared._CP14.DayCycle;
public sealed partial class CP14DayCycleSystem : EntitySystem
{
public const int MinTimeEntryCount = 2;
private const float MaxTimeDiff = 0.05f;
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14DayCycleComponent, MapInitEvent>(OnMapInitDayCycle);
SubscribeLocalEvent<CP14DayCycleComponent, DayCycleDayStartedEvent>(OnDayStarted);
SubscribeLocalEvent<CP14DayCycleComponent, DayCycleNightStartedEvent>(OnNightStarted);
}
private void OnDayStarted(Entity<CP14DayCycleComponent> dayCycle, ref DayCycleDayStartedEvent args)
{
}
private void OnNightStarted(Entity<CP14DayCycleComponent> dayCycle, ref DayCycleNightStartedEvent args)
{
}
private void OnMapInitDayCycle(Entity<CP14DayCycleComponent> dayCycle, ref MapInitEvent args)
{
Init(dayCycle);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var dayCycleQuery = EntityQueryEnumerator<CP14DayCycleComponent, MapLightComponent>();
while (dayCycleQuery.MoveNext(out var uid, out var dayCycle, out var mapLight))
{
var entity = new Entity<CP14DayCycleComponent, MapLightComponent>(uid, dayCycle, mapLight);
if (dayCycle.TimeEntries.Count < MinTimeEntryCount)
continue;
SetAmbientColor((entity, entity), GetCurrentColor(entity, _timing.CurTime.TotalSeconds));
if (_timing.CurTime <= dayCycle.EntryEndTime)
continue;
SetTimeEntry((uid, dayCycle), dayCycle.NextTimeEntryIndex);
}
}
public void Init(Entity<CP14DayCycleComponent> dayCycle)
{
if (dayCycle.Comp.TimeEntries.Count < MinTimeEntryCount)
{
Log.Warning($"Attempting to init a daily cycle with the number of time entries less than {MinTimeEntryCount}");
return;
}
dayCycle.Comp.CurrentTimeEntryIndex = 0;
dayCycle.Comp.EntryStartTime = _timing.CurTime;
dayCycle.Comp.EntryEndTime = _timing.CurTime + dayCycle.Comp.CurrentTimeEntry.Duration;
Dirty(dayCycle);
}
public void AddTimeEntry(Entity<CP14DayCycleComponent> dayCycle, DayCycleEntry entry)
{
dayCycle.Comp.TimeEntries.Add(entry);
Dirty(dayCycle);
}
public void SetTimeEntry(Entity<CP14DayCycleComponent> dayCycle, int nextEntry)
{
nextEntry = Math.Clamp(nextEntry, 0, dayCycle.Comp.TimeEntries.Count - 1);
dayCycle.Comp.CurrentTimeEntryIndex = nextEntry;
dayCycle.Comp.EntryStartTime = dayCycle.Comp.EntryEndTime;
dayCycle.Comp.EntryEndTime += dayCycle.Comp.CurrentTimeEntry.Duration;
// TODO: Made with states,we might need an evening or something, and besides, it's too much hardcore
if (dayCycle.Comp.IsNight && !dayCycle.Comp.CurrentTimeEntry.IsNight) // Day started
{
dayCycle.Comp.IsNight = false;
var ev = new DayCycleDayStartedEvent(dayCycle);
RaiseLocalEvent(dayCycle, ref ev, true);
}
if (!dayCycle.Comp.IsNight && dayCycle.Comp.CurrentTimeEntry.IsNight) // Night started
{
dayCycle.Comp.IsNight = true;
var ev = new DayCycleNightStartedEvent(dayCycle);
RaiseLocalEvent(dayCycle, ref ev, true);
}
Dirty(dayCycle);
}
private void SetAmbientColor(Entity<MapLightComponent> light, Color color)
{
if (color == light.Comp.AmbientLightColor)
return;
light.Comp.AmbientLightColor = color;
Dirty(light);
}
private Color GetCurrentColor(Entity<CP14DayCycleComponent> dayCycle, double totalSeconds)
{
var timeScale = GetTimeScale(dayCycle, totalSeconds);
return Color.InterpolateBetween(dayCycle.Comp.StartColor, dayCycle.Comp.EndColor, timeScale);
}
private float GetTimeScale(Entity<CP14DayCycleComponent> dayCycle, double totalSeconds)
{
return GetLerpValue(dayCycle.Comp.EntryStartTime.TotalSeconds, dayCycle.Comp.EntryEndTime.TotalSeconds, totalSeconds);
}
private static float GetLerpValue(double start, double end, double current)
{
if (Math.Abs(start - end) < MaxTimeDiff)
return 0f;
var distanceFromStart = current - start;
var totalDistance = end - start;
return MathHelper.Clamp01((float)(distanceFromStart / totalDistance));
}
}

View File

@@ -1,58 +0,0 @@
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.DayCycle;
/// <summary>
/// Stores all the necessary data for the day and night cycle system to work
/// </summary>
[RegisterComponent, Access(typeof(DayCycleSystem))]
public sealed partial class DayCycleComponent : Component
{
[DataField(required: true)]
public List<DayCycleEntry> TimeEntries = new();
[DataField]
public bool IsNight = false;
[DataField]
public int CurrentTimeEntry = 0;
[DataField]
public TimeSpan EntryStartTime;
[DataField]
public TimeSpan EntryEndTime;
}
[DataDefinition, NetSerializable, Serializable]
public readonly partial record struct DayCycleEntry()
{
/// <summary>
/// the color of the world's lights at the beginning of this time of day
/// </summary>
[DataField]
public Color StartColor { get; init; } = Color.White;
/// <summary>
/// duration of color shift to the next time of day
/// </summary>
[DataField]
public TimeSpan Duration { get; init; } = TimeSpan.FromSeconds(60);
[DataField]
public bool IsNight { get; init; } = false;
}
/// <summary>
/// Event raised on map entity, wen night is started
/// </summary>
[ByRefEvent]
public readonly record struct DayCycleNightStartedEvent(EntityUid Map);
/// <summary>
/// Event raised on map entity, wen night is started
/// </summary>
[ByRefEvent]
public readonly record struct DayCycleDayStartedEvent(EntityUid Map);

View File

@@ -1,95 +0,0 @@
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
namespace Content.Shared._CP14.DayCycle;
public sealed partial class DayCycleSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DayCycleComponent, MapInitEvent>(OnMapInitDayCycle);
SubscribeLocalEvent<DayCycleComponent, DayCycleDayStartedEvent>(OnDayStarted);
SubscribeLocalEvent<DayCycleComponent, DayCycleNightStartedEvent>(OnNightStarted);
}
private void OnDayStarted(Entity<DayCycleComponent> dayCycle, ref DayCycleDayStartedEvent args)
{
}
private void OnNightStarted(Entity<DayCycleComponent> dayCycle, ref DayCycleNightStartedEvent args)
{
}
private void OnMapInitDayCycle(Entity<DayCycleComponent> dayCycle, ref MapInitEvent args)
{
if (dayCycle.Comp.TimeEntries.Count == 0)
return;
var currentEntry = dayCycle.Comp.TimeEntries[0];
dayCycle.Comp.EntryStartTime = _timing.CurTime;
dayCycle.Comp.EntryEndTime = _timing.CurTime + currentEntry.Duration;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var dayCycleQuery = EntityQueryEnumerator<DayCycleComponent, MapLightComponent>();
while (dayCycleQuery.MoveNext(out var uid, out var dayCycle, out var mapLight))
{
if (dayCycle.TimeEntries.Count <= 1)
continue;
var curEntry = dayCycle.CurrentTimeEntry;
var nextEntry = (curEntry + 1 >= dayCycle.TimeEntries.Count) ? 0 : (curEntry + 1);
var start = dayCycle.EntryStartTime;
var end = dayCycle.EntryEndTime;
var lerpValue = GetLerpValue((float) start.TotalSeconds, (float) end.TotalSeconds, (float) _timing.CurTime.TotalSeconds);
var startColor = dayCycle.TimeEntries[curEntry].StartColor;
var endColor = dayCycle.TimeEntries[nextEntry].StartColor;
mapLight.AmbientLightColor = Color.InterpolateBetween(startColor, endColor, lerpValue);
Dirty(uid, mapLight);
if (_timing.CurTime > dayCycle.EntryEndTime)
{
dayCycle.CurrentTimeEntry = nextEntry;
dayCycle.EntryStartTime = dayCycle.EntryEndTime;
dayCycle.EntryEndTime += dayCycle.TimeEntries[nextEntry].Duration;
if (dayCycle.IsNight && !dayCycle.TimeEntries[curEntry].IsNight) // Day started
{
dayCycle.IsNight = false;
var ev = new DayCycleDayStartedEvent(uid);
RaiseLocalEvent(uid, ref ev, true);
}
if (!dayCycle.IsNight && dayCycle.TimeEntries[curEntry].IsNight) // Night started
{
dayCycle.IsNight = true;
var ev = new DayCycleNightStartedEvent(uid);
RaiseLocalEvent(uid, ref ev, true);
}
}
}
}
public static float GetLerpValue(float start, float end, float current)
{
if (Math.Abs(start - end) < 0.05f)
return 0f;
var distanceFromStart = current - start;
var totalDistance = end - start;
return MathHelper.Clamp01(distanceFromStart / totalDistance);
}
}