Skip to content

Commit

Permalink
Merge pull request #240 from Fansana/day-night-cycle
Browse files Browse the repository at this point in the history
Add DayNight Cycle
  • Loading branch information
Memeji authored Oct 8, 2024
2 parents 7c5455e + 2783986 commit f47172a
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Content.Server/Shuttles/Systems/ArrivalsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Content.Server.Spawners.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared._NC14.DayNightCycle;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.DeviceNetwork;
Expand Down Expand Up @@ -485,6 +486,12 @@ private void SetupArrivalsStation()
Range = 32f
};
AddComp(mapUid, restricted);
var dayNight = new DayNightCycleComponent
{
CurrentCycleTime = 0.5f,
CycleDurationMinutes = 60,
};
AddComp(mapUid, dayNight);
}

_mapManager.DoMapInitialize(mapId);
Expand Down
50 changes: 50 additions & 0 deletions Content.Shared/_NC/DayNightCycle/DayNightCycleComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;

namespace Content.Shared._NC14.DayNightCycle
{
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class DayNightCycleComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("cycleDuration")]
public float CycleDurationMinutes { get; set; } = 60f; // Default cycle duration is 60 minutes

[DataField("timeEntries")]
public List<TimeEntry> TimeEntries { get; set; } = new()
{
new() { Time = 0.00f, ColorHex = "#000000" }, // Midnight
new() { Time = 0.04f, ColorHex = "#02020b" }, // Very early morning
new() { Time = 0.08f, ColorHex = "#312716" }, // Early dawn
new() { Time = 0.17f, ColorHex = "#4E3D23" }, // Dawn
new() { Time = 0.25f, ColorHex = "#58372D" }, // Sunrise
new() { Time = 0.33f, ColorHex = "#876A42" }, // Early morning
new() { Time = 0.42f, ColorHex = "#A08042" }, // Mid-morning
new() { Time = 0.50f, ColorHex = "#A88F73" }, // Noon
new() { Time = 0.58f, ColorHex = "#C1A78A" }, // Early afternoon
new() { Time = 0.67f, ColorHex = "#7D6244" }, // Late afternoon
new() { Time = 0.75f, ColorHex = "#8C6130" }, // Sunset
new() { Time = 0.83f, ColorHex = "#543521" }, // Dusk
new() { Time = 0.92f, ColorHex = "#02020b" }, // Early night
new() { Time = 1.00f, ColorHex = "#000000" } // Back to Midnight
};

[ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public int CurrentTimeEntryIndex { get; set; }

[ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public float CurrentCycleTime { get; set; }
}

[DataDefinition, NetSerializable, Serializable]
public sealed partial class TimeEntry
{
[DataField("colorHex")]
public string ColorHex { get; set; } = "#FFFFFF";

[DataField("time")]
public float Time { get; set; } // Normalized time (0-1)
}
}
117 changes: 117 additions & 0 deletions Content.Shared/_NC/DayNightCycle/DayNightCycleSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Linq;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;

namespace Content.Shared._NC14.DayNightCycle
{
public sealed class DayNightCycleSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;

private const float EARLY_MORNING_TIME = 0.2f; // This represents 20% into the cycle, which is early morning

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DayNightCycleComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<DayNightCycleComponent, ComponentStartup>(OnComponentStartup);
}

private void OnMapInit(EntityUid uid, DayNightCycleComponent component, MapInitEvent args)
{
if (component.TimeEntries.Count < 2)
{
// Default Fallout-inspired color cycle with more variants
component.TimeEntries = new List<TimeEntry>
{
new() { Time = 0.00f, ColorHex = "#000000" }, // Midnight
new() { Time = 0.04f, ColorHex = "#02020b" }, // Very early morning
new() { Time = 0.08f, ColorHex = "#312716" }, // Early dawn
new() { Time = 0.17f, ColorHex = "#4E3D23" }, // Dawn
new() { Time = 0.25f, ColorHex = "#58372D" }, // Sunrise
new() { Time = 0.33f, ColorHex = "#876A42" }, // Early morning
new() { Time = 0.42f, ColorHex = "#A08042" }, // Mid-morning
new() { Time = 0.50f, ColorHex = "#A88F73" }, // Noon
new() { Time = 0.58f, ColorHex = "#C1A78A" }, // Early afternoon
new() { Time = 0.67f, ColorHex = "#7D6244" }, // Late afternoon
new() { Time = 0.75f, ColorHex = "#8C6130" }, // Sunset
new() { Time = 0.83f, ColorHex = "#543521" }, // Dusk
new() { Time = 0.92f, ColorHex = "#02020b" }, // Early night
new() { Time = 1.00f, ColorHex = "#000000" } // Back to Midnight
};
}

InitializeEarlyMorning(component);
}

private void OnComponentStartup(EntityUid uid, DayNightCycleComponent component, ComponentStartup args)
{
InitializeEarlyMorning(component);
}

private void InitializeEarlyMorning(DayNightCycleComponent component)
{
component.CurrentCycleTime = EARLY_MORNING_TIME;
UpdateLightColor(component);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<DayNightCycleComponent, MapLightComponent>();
while (query.MoveNext(out var uid, out var dayNight, out var mapLight))
{
dayNight.CurrentCycleTime += frameTime / (dayNight.CycleDurationMinutes * 60f);
dayNight.CurrentCycleTime %= 1f; // Keep it between 0 and 1

UpdateLightColor(dayNight, mapLight, uid);
}
}

private void UpdateLightColor(DayNightCycleComponent dayNight, MapLightComponent? mapLight = null, EntityUid? uid = null)
{
var color = GetInterpolatedColor(dayNight);

if (mapLight != null && uid.HasValue)
{
mapLight.AmbientLightColor = color;
Dirty(uid.Value, mapLight);
Dirty(uid.Value, dayNight);
}
}

private Color GetInterpolatedColor(DayNightCycleComponent component)
{
var entries = component.TimeEntries;
var time = component.CurrentCycleTime;

for (int i = 0; i < entries.Count - 1; i++)
{
if (time >= entries[i].Time && time <= entries[i + 1].Time)
{
var t = (time - entries[i].Time) / (entries[i + 1].Time - entries[i].Time);
return InterpolateHexColors(entries[i].ColorHex, entries[i + 1].ColorHex, t);
}
}

// If we're here, we're between the last and first entry
var lastEntry = entries.Last();
var firstEntry = entries.First();
var wrappedT = (time - lastEntry.Time) / (1f + firstEntry.Time - lastEntry.Time);
return InterpolateHexColors(lastEntry.ColorHex, firstEntry.ColorHex, wrappedT);
}

private Color InterpolateHexColors(string hexColor1, string hexColor2, float t)
{
Color color1 = Color.FromHex(hexColor1);
Color color2 = Color.FromHex(hexColor2);

float r = color1.R + (color2.R - color1.R) * t;
float g = color1.G + (color2.G - color1.G) * t;
float b = color1.B + (color2.B - color1.B) * t;

return new Color(r, g, b);
}
}
}
3 changes: 3 additions & 0 deletions Resources/Maps/glacier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ entities:
- uid: 1
components:
- type: MetaData
- type: MapLight
ambientLightColor: '#030305FF'
- type: DayNightCycle
- type: Transform
- type: Map
mapPaused: True
Expand Down

0 comments on commit f47172a

Please sign in to comment.