User observed: 'time is flipped — supposed to be day/evening, but shows night/morning.' That's a ~half-day offset. Root cause in ACE DerethDateTime.cs line 23: private const double dayZeroTicks = 0; // Morningthaw 1, 10 P.Y. - Morntide-and-Half ACE anchors tick 0 to Morntide-and-Half (slot 7 on the 0-indexed 16-slot scale) — NOT Darktide (slot 0 = midnight) as our DayFraction function assumed. Confirmed by DerethDateTime.cs:145: private int hour = (int)Hours.Morntide_and_Half; Fix: shift DayFraction by +7/16 * DayTicks (3333.75) so tick 0 maps to its real calendar slot. Exposed as DayFractionOriginOffsetTicks constant for documentation + downstream referencing. Effect on sun: previously, server tick ~0 (just-booted ACE) produced dayFraction 0 → midnight sky → night colors at noon real-time. Now dayFraction 7/16 = 0.4375 → late morning sky → noon-ish colors within 1/16 of a day, which matches what a user actually sees when launching during daytime. Tests updated for the corrected convention: - DerethDateTime.DayFraction(0) = 7/16 (not 0). - CurrentHour(0) = MorntideAndHalf (not Darktide). - IsDaytime(0) = true. - Midnight (Darktide, slot 0) is 9/16 of a day past tick 0. - SkyState + WorldTimeDebug tests retargeted to the new frame. Build green, 711 tests pass. Ref: references/ACE/Source/ACE.Common/DerethDateTime.cs:23-25 + :145. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
100 lines
3.7 KiB
C#
100 lines
3.7 KiB
C#
using AcDream.Core.World;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.World;
|
|
|
|
public sealed class DerethDateTimeTests
|
|
{
|
|
// ACE calendar anchor: tick 0 = Morningthaw 1, 10 P.Y. at Morntide-and-Half
|
|
// (slot 7 on the 0-indexed 16-slot scale). The DayFraction function
|
|
// applies +7/16 offset so "what time is it in the day" reads correctly.
|
|
|
|
[Fact]
|
|
public void DayFraction_AtTick0_IsMorntideAndHalf()
|
|
{
|
|
// Tick 0 = Morntide-and-Half = slot 7 = 7/16 of the day.
|
|
Assert.Equal(7.0 / 16.0, DerethDateTime.DayFraction(0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void DayFraction_AtHalfDayFromTick0_IsHalf()
|
|
{
|
|
// From tick 0 (slot 7) + half a day = slot 7 + 8 = slot 15 (Gloaming-and-Half).
|
|
// Verify the formula advances by 0.5 correctly: (0 + DayTicks/2) → 7/16 + 1/2 = 15/16.
|
|
Assert.Equal(15.0 / 16.0, DerethDateTime.DayFraction(DerethDateTime.DayTicks / 2), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void DayFraction_WrapsAfterOneDay()
|
|
{
|
|
// Full day from tick 0 returns to the same slot (Morntide-and-Half = 7/16).
|
|
Assert.Equal(7.0 / 16.0, DerethDateTime.DayFraction(DerethDateTime.DayTicks), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentHour_AtTick0_IsMorntideAndHalf()
|
|
{
|
|
// ACE ref: DerethDateTime.cs:145 — `hour = (int)Hours.Morntide_and_Half;`
|
|
Assert.Equal(DerethDateTime.HourName.MorntideAndHalf, DerethDateTime.CurrentHour(0));
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentHour_AtMidnight_IsDarktide()
|
|
{
|
|
// ACE ref: DerethDateTime.cs:25 — `dayOneTicks = 0 + hourOneTicks + (hourTicks * 8)
|
|
// // Morningthaw 2, 10 P.Y. - Darktide`. From tick 0 to Darktide next day = 4020.
|
|
// Using our slot-based formula: from slot 7 -> slot 0 (wrap) = 9 slots = 9 * 476.25
|
|
// = 4286.25 ticks (slight difference because ACE snaps to quarter hours; our
|
|
// continuous formula is smoother). We verify slot 0 (Darktide) at 9/16 of a day
|
|
// past tick 0.
|
|
double ticks = DerethDateTime.DayTicks * (9.0 / 16.0);
|
|
Assert.Equal(DerethDateTime.HourName.Darktide, DerethDateTime.CurrentHour(ticks));
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentHour_AtNoon_IsMidsong()
|
|
{
|
|
// Midsong is slot 8 on the 16-slot scale. From tick 0 (slot 7) advance by 1 slot.
|
|
double ticks = DerethDateTime.DayTicks * (1.0 / 16.0);
|
|
Assert.Equal(DerethDateTime.HourName.Midsong, DerethDateTime.CurrentHour(ticks));
|
|
}
|
|
|
|
[Fact]
|
|
public void IsDaytime_Tick0_True()
|
|
{
|
|
// Morntide-and-Half (slot 7) falls in the daytime band (slots 4..11).
|
|
Assert.True(DerethDateTime.IsDaytime(0));
|
|
}
|
|
|
|
[Fact]
|
|
public void IsDaytime_Darktide_False()
|
|
{
|
|
// Darktide = slot 0. Need tick offset of 9/16 from tick 0 to reach it.
|
|
double ticks = DerethDateTime.DayTicks * (9.0 / 16.0);
|
|
Assert.False(DerethDateTime.IsDaytime(ticks));
|
|
}
|
|
|
|
[Fact]
|
|
public void ToCalendar_PY0Day1_Snowreap()
|
|
{
|
|
var cal = DerethDateTime.ToCalendar(0);
|
|
Assert.Equal(0, cal.Year);
|
|
Assert.Equal(DerethDateTime.MonthName.Snowreap, cal.Month);
|
|
Assert.Equal(1, cal.Day);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToCalendar_AdvancesCorrectly()
|
|
{
|
|
// One year from start → PY 1, Snowreap 1.
|
|
var cal = DerethDateTime.ToCalendar(DerethDateTime.YearTicks);
|
|
Assert.Equal(1, cal.Year);
|
|
Assert.Equal(DerethDateTime.MonthName.Snowreap, cal.Month);
|
|
Assert.Equal(1, cal.Day);
|
|
|
|
// One month into year 1.
|
|
var cal2 = DerethDateTime.ToCalendar(DerethDateTime.YearTicks + DerethDateTime.MonthTicks);
|
|
Assert.Equal(1, cal2.Year);
|
|
Assert.Equal(DerethDateTime.MonthName.ColdMeet, cal2.Month);
|
|
}
|
|
}
|