116 lines
3.6 KiB
Markdown
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.
|