pub struct Lockstep { /* private fields */ }Expand description
Transport-agnostic lockstep state machine for one peer.
Implementations§
Source§impl Lockstep
impl Lockstep
pub fn new(local: PlayerId, players: Vec<PlayerId>, delay: u32) -> Lockstep
Sourcepub fn observer(players: Vec<PlayerId>, delay: u32) -> Lockstep
pub fn observer(players: Vec<PlayerId>, delay: u32) -> Lockstep
A session that watches: it receives every player’s input and simulates the same frames, but commits nothing and is waited for by nobody. A spectator falling behind is a spectator’s problem.
Sourcepub fn request_pause(&mut self) -> u32
pub fn request_pause(&mut self) -> u32
Call a pause. Returns the frame the session will freeze on, to be broadcast to the peers; a pause already in flight wins if it lands earlier, so two players hitting Escape together agree.
Sourcepub fn receive_pause(&mut self, frame: u32)
pub fn receive_pause(&mut self, frame: u32)
A peer called a pause at frame. The earliest proposal wins, so
every peer converges on one frame however the messages interleave.
Two kinds of Pause are not proposals and are dropped: one naming
a frame this peer has already simulated (every player committed
past it, so nobody is stopping there), and one naming a pause that
has since been lifted (see lifted). Both are the per-tick echoes
of a pause that is over, arriving after the resume.
Sourcepub fn resume(&mut self) -> u32
pub fn resume(&mut self) -> u32
Lift the pause and let commits flow again. Safe to call unpaused. Returns the frame the lifted pause was to freeze on (the highest ever lifted here, if there was no pause to lift), for the peers.
Sourcepub fn receive_resume(&mut self, frame: u32) -> u32
pub fn receive_resume(&mut self, frame: u32) -> u32
A peer lifted the pause that was to freeze on frame. Whatever
pause is in flight here is lifted with it: the peers agree on one
frame, and a peer that had not yet heard the earliest proposal is
resuming from the same pause under a later number.
Sourcepub fn pause_frame(&self) -> Option<u32>
pub fn pause_frame(&self) -> Option<u32>
The frame this session is frozen on, if paused.
Sourcepub fn lifted_pause(&self) -> Option<u32>
pub fn lifted_pause(&self) -> Option<u32>
The frame of the pause most recently lifted, if any ever was: what
a repeated Resume names.
Sourcepub fn paused(&self) -> bool
pub fn paused(&self) -> bool
Whether a pause has been called (the freeze itself lands a beat
later, when the simulated frame reaches Lockstep::pause_frame).
Sourcepub fn frozen(&self) -> bool
pub fn frozen(&self) -> bool
Whether the sim has actually come to rest on the pause frame: the moment the picture on screen stops moving.
Sourcepub fn commit_local(&mut self, action: PlayerAction) -> Option<InputMsg>
pub fn commit_local(&mut self, action: PlayerAction) -> Option<InputMsg>
Commit the local action for the next input frame; returns the message
to send to every peer, or None if the sim has fallen too far behind
(a stalled peer) or the session is paused. The caller should retry
the action next frame rather than let commits run unboundedly ahead.
Sourcepub fn recent_commits(&self) -> &[InputMsg]
pub fn recent_commits(&self) -> &[InputMsg]
The recent local commits, oldest first: every one a peer still in
step with us could be missing (see [resend_span]). Resend these
every step so packet loss (or a not-yet-completed handshake) cannot
stall the peer.
Sourcepub fn awaiting(&self) -> Vec<PlayerId> ⓘ
pub fn awaiting(&self) -> Vec<PlayerId> ⓘ
Which players the next frame is still waiting on. Empty means it is ready to simulate; anything else is who everybody is held up by.
Read-only, because the shell asks this to put a name on screen while the picture is still, and a question the HUD asks every frame must not be one that writes. Only seated players can hold a frame up; an absent seat is filled at the moment its frame is made.
Sourcepub fn abandon(&mut self, player: PlayerId, frame: u32)
pub fn abandon(&mut self, player: PlayerId, frame: u32)
Give up on a player who has stopped sending, from frame on.
Every frame from there fills their slot the way an absent seat is filled, including the frames already waiting on it, which unsticks the round in the same breath. What moves into the empty chair is not this layer’s business: the shell puts an AI there, and every peer derives the same moves for it from the same board.
The frame is the one the decider was held up on, and it travels
with the decision, because the peers do not all hold the same
inputs from a player who has gone quiet: the host relays each input
as it arrives, and a peer that missed the relay of frame n may
well hold n + 2. Filling only the empty slots had that peer play
n + 2 as sent while the host, which never got n and stopped
there, played it empty. Every slot from frame on is emptied
instead, whatever it held, and every peer applies the same frame.
A peer cannot have simulated past frame already: the decider had
no input for it, and no peer hears from a player except through
the decider.
Sourcepub fn receive(&mut self, msg: InputMsg)
pub fn receive(&mut self, msg: InputMsg)
Feed a peer’s message (duplicates and already-simulated frames are ignored, so resends are harmless).
A frame further ahead than any peer still in step could have
committed is ignored too: their commits run at most a lead past
their frame, and their frame at most a lead past ours (see
[resend_span]). Every frame accepted here makes a slot, and a peer
naming frames up to u32::MAX would otherwise grow the table
without bound.
Sourcepub fn advance(&mut self) -> Option<[PlayerAction; 6]>
pub fn advance(&mut self) -> Option<[PlayerAction; 6]>
If every player’s action for the next frame is known, pop it for
simulation. None means “stall this render frame”: never guess.
pub fn frame(&self) -> u32
pub fn player_count(&self) -> usize
Auto Trait Implementations§
impl Freeze for Lockstep
impl RefUnwindSafe for Lockstep
impl Send for Lockstep
impl Sync for Lockstep
impl Unpin for Lockstep
impl UnsafeUnpin for Lockstep
impl UnwindSafe for Lockstep
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