Skip to main content

OnlineSession

Struct OnlineSession 

Source
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: u8

Seats in the match, humans plus AI. The lockstep only carries the humans, so this is not session.player_count().

§terms: MatchTerms

What 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: String

What 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: bool

A 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

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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.

Source

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

Source

pub fn new( transport: UdpTransport, session: Lockstep, seats: u8, terms: MatchTerms, ) -> OnlineSession

Source

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.

Source

pub fn request_pause(&mut self)

Call a pause, and tell the peers which frame it lands on.

Source

pub fn request_resume(&mut self)

Play on, and keep saying so for a moment (see RESUME_ECHOES).

Source

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.

Source

pub fn watching(&self) -> bool

Whether this peer watches rather than plays.

Source

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).

Source

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.

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts 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>

Converts 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)

Converts &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)

Converts &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 T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more