Editorial illustration: Match time is more than wall-clock time

Match time is more than wall-clock time

The problem I needed to solve

A match does not gain five minutes of play when a player spends five minutes outside the app. I separated active duration from wall-clock duration in match reporting.

Implementation in this snapshot

ForegroundMatchClock receives a now function. Seconds combines accumulated time with the active interval; Pause freezes it and Resume establishes a new interval origin.

The design decision and its cost

An injected clock makes the logic explainable without a direct MonoBehaviour dependency. Repeated Pause or Resume calls do not add effects, and negative values are clamped.

Current boundaries

Correctness depends on a monotonic clock and properly wired pause lifecycle. The class cannot detect backgrounding by itself and does not persist across process restarts.

Review scenarios and contract meaning

A match with several minutes of play and several minutes outside the application has two different durations. The foreground clock sums active intervals, which need not equal the wall-clock difference between start and end. This is an explanatory example rather than real report data. Idempotent Pause and Resume calls help prevent similar callbacks from accumulating time twice. Correct application lifecycle wiring remains necessary: the class cannot know on its own whether the window was actually foregrounded. Its injected time function must also match the expectation of monotonic time.

PHP reporting can read game_progress checkpoints and game_end through Latest record per entity for a match duration. The selection key combines player_id with the match identifier so matching identifiers across players do not merge. Event selection and filters run before choosing the newest timestamp. Date ranges use the event’s UTC time rather than the match’s starting day. A match ending the next day is consequently not automatically joined to all starts from the preceding day. A checkpoint without an ending shows only reported time; the remaining duration is not guessed. That boundary matters when interpreting the metric honestly.

A final checkpoint and an actual ending are different observations. An interrupted game may leave only partial evidence of active time. I read that as reported time without guessing completion or a win from missing events. Keeping ending reason, active duration and final-event presence separate avoids confusing incomplete data with a short successful experience.

What this stage taught me

For me, time definition became part of metric definition. Foreground duration can explain play better than two timestamps’ difference, but should be interpreted alongside ending reasons and session state.

Explore Dalo

Project source and discussion: GitHub · Telegram

Latest devlogs

Editorial illustration: Presenting selection and captures in Pasur

Presenting selection and captures in Pasur

Pasur motion should explain which hand card was played and which table cards were captured.

Read article
Editorial illustration: Pasur bot decisions from capture options

Pasur bot decisions from capture options

My teammate’s Pasur bot chooses among legal options without inspecting hidden opposing cards.

Read article
Editorial illustration: Capturing table cards in Pasur

Capturing table cards in Pasur

In my teammate’s implementation, Pasur combines selecting a hand card with selecting table cards. Its rules must produce valid sets and prohibit ignoring an available capture.

Read article
Dalo