Expand description
Portal integration: ads, cloud saves, host pause, lifecycle mute and the host-facing gameplay notices, in one place.
A portal is a host a game runs inside (Playgama, Yandex Games, CrazyGames,
and the rest). Six games in this family ship a byte-identical
sim/platform.rs and an app/platform.rs that differs between two of them
only in three log strings: ads with timeouts, cloud-save push and pull, the
host’s pause, the lifecycle mute, and a time_scale gate copy-pasted into
every frame loop that touches the clock. This module is that code, once.
§The three pieces
Portalis one backend: the adapter that speaks to a host. The Playgama one lives inportal::playgamabehind theplaygamafeature and is off by default.NoPortalis the desktop backend, and it refuses every request with a typed reason instead of pretending.PortalHostis the state machine the game owns. It asks the backend, absorbs what the backend reports, owns the ad deadline and the rate limit the host enforces, and answers one question per frame: does gameplay run, does the world tick, does sound play.Suspendis that answer, andSuspend::applyis the only placeSim::time_scaleis written.
§The no-fabrication rule
A host that cannot serve an ad or store a cloud save says so now, with a
typed Refusal: nothing waits on a callback that will not come, and
nothing reports a success it did not get. Every request is answered on the
frame it was made, and everything that was taken ends in an AdOutcome or
a cloud answer:
- an ad that is not supported, or that another break is already in the way
of, is refused before it starts (
AdRefused); - an ad the host accepted and never ended is released by its deadline, and
reported as
AdOutcome::TimedOut: a break the host forgot cannot hold the player; - a rewarded ad pays only when the host reported the reward point, never on
the strength of having asked (
AdOutcome::pays); - an empty or non-text cloud payload is refused rather than stored, because the platform reads an empty value as a delete;
- with no host at all,
NoPortalstill answers every request, withRefusal::NoPortal, rather than going quiet.
§What a game writes
// Once, at boot: the web after the SDK loaded, the desktop plain.
let mut portal = PortalHost::pull_first(Box::new(backend));
portal.loaded();
// Once per frame, in this order.
portal.update(dt); // one clock for ad deadlines
let gate = portal.gate(GameState {
playing: run.playing(),
transitional: run.transitional(),
modal: false,
muted: save.data.muted,
});
gate.apply(&mut sim); // the one writer of time_scale
if gate.live() { schedule.run(&mut sim.world); }
portal.ready(); // first playable frame: game_ready
for report in portal.take_reports() { /* ad outcomes, cloud answers */ }The gate replaces three hand-written lines that the games keep at every call
site that touches the clock (live, suspended, time_scale), and
Suspend::live replaces the fourth that decides whether the gameplay
schedule runs at all.
repame-fx’s SimDriver::frame(step_fx, blocked, tick_sim, clear_edges)
encodes the sequencing half of the same problem (step ungated fx first, then
tick gameplay only when open, and roll the input edges when it is not).
Suspend::suspended is exactly its blocked argument, so the two
compose: the gate decides, the driver sequences. The driver has no opinion
about run state, ads, modals, mute or lifecycle, and it does not own the
clock, which is why the gate is here and not there.
Modules§
- lifecycle
- App lifecycle: foreground or background, as the single fact the gate reads.
Structs§
- AdSchedule
- The interstitial rate limit the host enforces, as the game’s bridge config
declares it (
minimumDelayBetweenInterstitial,initialInterstitialDelay). - Game
State - What only the game knows, settled per frame.
- NoPortal
- Nothing is listening. Installed by
PortalHost::none, which is also the default host. - Portal
Host - The shell’s half of a portal: requests out, host facts in, one gate.
- Portal
Status - What a portal can do, and the host facts it knows without being asked.
- Portal
View - What the portal knows, as a plain value so the truth table is testable without a backend.
- Suspend
- One frame’s answer to “does gameplay run, does the world tick, does sound play”.
Enums§
- AdEnding
- The host’s last word on an ad, before the shell turns it into an outcome.
- AdKind
- The two ads a portal serves.
- AdOutcome
- What an ad did, after the shell has matched the host’s events to the request that asked for it.
- AdRefused
- Why an ad the game asked for is not on its way.
- Availability
- Whether a portal can serve one feature, with the host’s own reason when it cannot.
- Cause
- Why the clock is stopped, outermost first.
- Cloud
Refused - Why a cloud write did not go to the host.
- Host
Notice - A notice the host tracks gameplay by.
- Portal
Event - One thing a portal learned from the host.
- Portal
Report - One thing the shell decided, for the game to drain once per frame.
- Portal
Request - One request the shell hands a portal.
- Refusal
- Why a portal would not take a request, or cannot hand back what it has.
Constants§
- INTERSTITIAL_
TIMEOUT - How long the shell waits for an interstitial before releasing the game.
- REWARDED_
TIMEOUT - How long the shell waits for a rewarded video before releasing the game.
Traits§
- Portal
- One portal backend: the adapter between the shell and one host.