Files
dusk/.claude/time.md
T
2026-06-16 10:15:59 -05:00

116 lines
3.6 KiB
Markdown

# Time System
Source: `src/dusk/time/`, platform layers in `src/dusk<platform>/time/`
## Global state
```c
extern dusktime_t TIME;
```
```c
typedef struct {
float_t delta; // Fixed step size in seconds (DUSK_TIME_STEP)
float_t time; // Accumulated game time in seconds
// Only present when DUSK_TIME_DYNAMIC is defined:
float_t lastNonDynamic;
bool_t dynamicUpdate; // true on sub-step ticks
float_t dynamicDelta; // real elapsed seconds this frame
float_t dynamicTime; // accumulated real time
} dusktime_t;
```
## Fixed vs dynamic timestep
### Fixed timestep (default)
`DUSK_TIME_STEP` defaults to `16ms / 1000 = 0.016f` seconds (62.5 Hz).
Every call to `timeUpdate()` advances `TIME.time` by exactly
`DUSK_TIME_STEP` and sets `TIME.delta = DUSK_TIME_STEP`. This is the
safe, deterministic mode for physics and game logic.
### Dynamic timestep (`DUSK_TIME_DYNAMIC`)
When enabled, `timeUpdate()` calls the platform tick hook to measure
actual elapsed time. It fires a "non-dynamic" step (`dynamicUpdate =
false`, `delta = DUSK_TIME_STEP`) once per fixed interval, and
"dynamic" sub-steps (`dynamicUpdate = true`) in between. Systems that
must run on the fixed interval (physics, networking) skip the dynamic
sub-steps by checking:
```c
if(TIME.dynamicUpdate) return;
```
## Platform hooks
Each platform provides three macros in its `time/timeplatform.h`:
| Macro | Purpose |
|-------|---------|
| `timeTickPlatform()` | Sample the hardware timer |
| `timeGetDeltaPlatform()` | Return seconds since last tick |
| `timeGetRealPlatform()` | Return epoch seconds since 1970 |
| `timeGetRealTimeZonePlatform()` | Return local timezone offset (seconds) |
`timeTickPlatform` and `timeGetDeltaPlatform` are only required when
`DUSK_TIME_DYNAMIC` is defined.
## Platform implementations
| Platform | Tick source | Real time source |
|----------|------------|-----------------|
| Linux | `SDL_GetTicks64()` (via SDL2) | `clock_gettime(CLOCK_REALTIME)` |
| Knulli | `SDL_GetTicks64()` (via SDL2) | `clock_gettime(CLOCK_REALTIME)` |
| PSP | `SDL_GetTicks64()` (via SDL2) | `sceRtcGetCurrentTick()` (microseconds) |
| GameCube | none (fixed step only) | `ticks_to_microsecs(__SYS_GetSystemTime())` + 2000->1970 offset |
| Wii | none (fixed step only) | same as GameCube |
GameCube / Wii note: the hardware timer returns ticks since
2000-01-01, so an offset of 946684800 seconds is added to convert to
UNIX epoch. The timezone offset is always returned as 0.0 on Dolphin
(timezone is not available without network time).
## Epoch time (`timeepoch.h`)
```c
typedef struct {
double_t time; // raw UTC seconds since 1970
double_t timeZone; // timezone offset in seconds
double_t offsetTime; // time + timeZone
} dusktimeepoch_t;
dusktimeepoch_t timeGetEpoch(void);
// Returns current time in local timezone.
```
### Epoch helpers
```c
int32_t timeEpochGetYear(epoch);
int32_t timeEpochGetMonth(epoch); // 1-12
int32_t timeEpochGetDayOfMonth(epoch); // 1-31
int32_t timeEpochGetHours(epoch); // 0-23
int32_t timeEpochGetMinutes(epoch); // 0-59
int32_t timeEpochGetSeconds(epoch); // 0-59
bool_t timeEpochIsLeapYear(year);
size_t timeEpochFormat(
dusktimeepoch_t epoch,
const char_t *format, // %Y %m %d %H %M %S
char_t *buffer,
size_t bufferSize
);
```
## Adding a new platform time implementation
1. Create `src/dusk<platform>/time/time<platform>.h/.c`.
2. Implement `timeGetReal<Platform>()` and
`timeGetRealTimeZone<Platform>()`.
3. If `DUSK_TIME_DYNAMIC`: also implement `timeTick<Platform>()` and
`timeGetDelta<Platform>()`.
4. Create `src/dusk<platform>/time/timeplatform.h` with the `#define`
macros pointing to your functions.