pub struct OnlineSession {Show 13 fields
pub transport: UdpTransport,
pub session: Lockstep,
pub seats: u8,
pub terms: MatchTerms,
pub beach: Vec<u8>,
pub peer_seats: Vec<Option<u8>>,
pub names: [String; 6],
pub desync_at: Option<u32>,
pub abandoned: Vec<(u8, u32)>,
pub announcer: Option<Announcer>,
pub game_name: String,
pub next_round: bool,
pub series_standing: Option<(u8, [u8; 6])>,
/* private fields */
}Fields§
§transport: UdpTransport§session: Lockstep§seats: u8Seats in the match, humans plus AI. The lockstep only carries the
humans, so this is not session.player_count().
terms: MatchTermsWhat the lobby agreed the match is: AI seats, map, gulls, round length, light, team scoring, and the board’s seed. Every peer builds from these, so nothing about the round is a local opinion.
beach: Vec<u8>The host’s handmade beach, compressed, when the round is played on
one. A generated arena travels as a seed in Self::terms; a
level somebody built has to travel as itself, because no peer but
the host has the file. Empty for the built-in maps.
peer_seats: Vec<Option<u8>>Host side: the seat each peer index was given, None for the
watchers among them. Empty on a joiner, which answers nobody.
names: [String; 6]What each seat is called, agreed at the handshake so every peer shows the same table. Empty entries fall back to seat labels; local couch names never apply to an online round.
desync_at: Option<u32>First frame where the peers’ state hashes disagreed, if ever: a determinism bug surfaced loudly rather than played through.
abandoned: Vec<(u8, u32)>Seats given up on this round, each with the frame it was emptied from, so the shell can put an AI in each and say so once rather than every frame, and the host can keep telling the table.
announcer: Option<Announcer>Host side: the beacon, carried out of the lobby so the beach stays
on the air while the round runs, listed as in progress with its
occupancy, for anyone who wants the next one. None on a joiner,
and on a direct PINCH_HOST pair, which never announced at all.
game_name: StringWhat the beach is called, for the beacon it keeps up while the round runs. Not a player’s name: the list is choosing between games.
next_round: boolA next round has been agreed and the session is armed for it; the shell reads this and walks everyone back into the arena. Cleared by whoever acts on it.
series_standing: Option<(u8, [u8; 6])>Where the series stands as the next round begins, as the host said
it: the 1-based round number and the wins per seat, both re-dealt to
this round’s chairs. The shell folds it into its Tournament on the
way into the arena, so a peer admitted mid-series joins the table’s
standings rather than starting its own, and a survivor whose seat
moved keeps the wins it earned. None outside a series.
Implementations§
Source§impl OnlineSession
impl OnlineSession
Sourcepub fn host_gone(&self) -> bool
pub fn host_gone(&self) -> bool
Whether the host has gone: a joiner’s own verdict on the one peer it has, and the only thing it may decide by itself.
Deciding this alone is safe where deciding a seat is not. An abandoned seat keeps playing under an AI and every peer must agree on the frame that happened; a joiner leaving takes nothing with it but itself.
A pause makes no difference: the pump runs through one (that is what carries the resume), so a host that is there keeps talking however still the picture is, and one that has quit under the pause card should not leave the table sitting on it for good.
Sourcepub fn abandon_stalled(&mut self, delta: f32, paused: bool) -> Vec<u8> ⓘ
pub fn abandon_stalled(&mut self, delta: f32, paused: bool) -> Vec<u8> ⓘ
Watch for a player who has stopped sending, and give up on them.
The host alone decides, and says so; a peer that ran its own timer would fill the seat on whichever frame its own patience ran out, and two peers filling it on different frames is a desync.
Two things have to be true, and the second is the one that matters:
the round is held up by that seat, and the machine holding it has
not said a word for [ABANDON_AFTER]. A held-up frame on its own is
weak evidence: it is also what a burst of loss looks like, and what
a peer that is a second behind looks like. A table where the slowest
laptop loses its castle every few minutes is worse than one that
waits. Silence is the strong evidence: every peer sends on
every tick it runs, resending every commit a peer could still be
missing, so a machine still in the room is a machine still talking.
Returns what was given up on this call, which the tests read. The lasting record is abandoned, because a joiner is told
rather than deciding and its seats never pass through here.
Sourcepub fn waiting_on(&self) -> Option<u8>
pub fn waiting_on(&self) -> Option<u8>
The seat the status line should name, if any.
A lockstep frame runs only when every seat’s input is in, so a still picture is the ordinary shape of somebody else’s trouble. This lets the screen say whose, instead of leaving a table of people asking each other whether it has crashed.
Source§impl OnlineSession
impl OnlineSession
Sourcepub fn poll_between_rounds(&mut self, delta: f32)
pub fn poll_between_rounds(&mut self, delta: f32)
Drain the socket between rounds, when the sim is stopped and pump
is therefore not running either.
The results card is when people turn up wanting in, and when the host decides there will be another round, so the two messages that matter here are a greeting to queue and the invitation that answers it. Inputs and hashes belong to the round that just ended, and are dropped with it.
A joiner also keeps greeting, which is not for the host’s benefit:
the answer is what proves the host is still there. Nothing else is
sent between rounds, so without it the silence clock would grow on
a table where everybody is present and simply reading the scores,
and Self::host_gone would call the round off under them.
Sourcepub fn call_next_round(
&mut self,
terms: MatchTerms,
round: u8,
wins: [u8; 6],
) -> (u8, [u8; 6])
pub fn call_next_round( &mut self, terms: MatchTerms, round: u8, wins: [u8; 6], ) -> (u8, [u8; 6])
Host: call the next round on terms, admitting the queue, and tell
every peer which seat it now holds. Arms this session too, so host
and joiners take the same path back into the arena.
round/wins are the series standing as it is now, by this
round’s seats; the return value is the same standing re-dealt to the
seats the next round hands out, which the caller folds back into its
Tournament. Seats are re-dealt in peer order every round (they have
to stay the contiguous 0..humans the sim fills the top of with AI),
so a peer that leaves shifts everyone behind it up a chair; carrying
the wins across by hand is what keeps a survivor’s rounds its own
rather than the next player’s. Outside a series round is 0 and the
wins are ignored.
Sourcepub fn begin_round(
&mut self,
seats: u8,
seat: Option<u8>,
terms: MatchTerms,
names: [String; 6],
)
pub fn begin_round( &mut self, seats: u8, seat: Option<u8>, terms: MatchTerms, names: [String; 6], )
Take up the terms of a new round: a fresh board, a lockstep back at frame zero, and whatever the table is called now.
The seed is what marks this a new round rather than the stale
Start a host re-answers stray greetings with, so a caller that
does not change it will find nothing happens.
Sourcepub fn is_next_round(&self, terms: &MatchTerms) -> bool
pub fn is_next_round(&self, terms: &MatchTerms) -> bool
Whether a Start off the wire is the next round rather than the
stale one a host re-answers a greeting with.
Source§impl OnlineSession
impl OnlineSession
pub fn new( transport: UdpTransport, session: Lockstep, seats: u8, terms: MatchTerms, ) -> OnlineSession
Sourcepub fn keep_announcing(&mut self, delta: f32)
pub fn keep_announcing(&mut self, delta: f32)
Keep the beach on the air while the round runs, so a lobby can list it as in progress rather than not at all. Hosts only, and the beacon says running, so nobody is offered a join that lockstep could not honour; what it offers is a place in the queue.
taken counts the humans, not the table: an AI seat gives way to a
player who wants it, the same way the lobby fills bots in behind
whoever turned up.
Sourcepub fn request_pause(&mut self)
pub fn request_pause(&mut self)
Call a pause, and tell the peers which frame it lands on.
Sourcepub fn request_resume(&mut self)
pub fn request_resume(&mut self)
Play on, and keep saying so for a moment (see RESUME_ECHOES).
Sourcepub fn is_host(&self) -> bool
pub fn is_host(&self) -> bool
Is this session the star’s hub? Seat 0 hosts and relays.
Public because the shell has to know who calls the next round, which it did through a second method of the same one line, under a second copy of this sentence.
Sourcepub fn pump(
&mut self,
local_action: PlayerAction,
tick: impl FnMut(&mut Self),
) -> bool
pub fn pump( &mut self, local_action: PlayerAction, tick: impl FnMut(&mut Self), ) -> bool
One fixed-tick’s worth of network pumping: commit and (re)send local
input, drain the socket (the host relays joiner inputs to the other
joiners and re-answers stray hellos with their seat), then simulate
every frame that has complete inputs via tick. Records hashes on
the HASH_INTERVAL cadence. Returns whether the local action was
committed (false = at the commit lead; retry it next tick).
Sourcepub fn after_frame(&mut self, hash: u64)
pub fn after_frame(&mut self, hash: u64)
Called by the tick closure after simulating a frame, with the fresh state hash.
Trait Implementations§
Source§impl Drop for OnlineSession
A hosted beach stops being announced when its session goes, whichever
way that happens: the match ending, the player quitting to the menu, a
desync giving up. Putting it here rather than at each of those exits is
what keeps the promise: there is no path that drops a session and
forgets to take the beach off the network with it.
impl Drop for OnlineSession
A hosted beach stops being announced when its session goes, whichever way that happens: the match ending, the player quitting to the menu, a desync giving up. Putting it here rather than at each of those exits is what keeps the promise: there is no path that drops a session and forgets to take the beach off the network with it.
Auto Trait Implementations§
impl Freeze for OnlineSession
impl RefUnwindSafe for OnlineSession
impl Send for OnlineSession
impl Sync for OnlineSession
impl Unpin for OnlineSession
impl UnsafeUnpin for OnlineSession
impl UnwindSafe for OnlineSession
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more