pub struct Session<G: Game> { /* private fields */ }Expand description
A game running against an offscreen target, one frame per Session::step.
The session owns the game for its whole life, exactly as run
does, and borrows nothing from the caller. The caller is its player:
Session::set_pointer, Session::press, Session::release,
Session::pointer_delta, Session::wheel_delta and
Session::type_text are its controls. Each
move reaches what the game reads, the UI, or both: the UI is given the
egui::Event a window’s own event reaches it as, and reads no
PointerDelta of its own; text reaches the UI
alone. A rebind lasts
the session and is written to no store, and so does everything the game
saves — every key returns its fallback until the session itself saves
one.
Implementations§
Source§impl<G: Game> Session<G>
impl<G: Game> Session<G>
Sourcepub fn new(
config: Config,
size: UVec2,
init: impl FnOnce(&mut InitContext<'_, G>) -> Result<G, Error>,
) -> Result<Self, Error>
pub fn new( config: Config, size: UVec2, init: impl FnOnce(&mut InitContext<'_, G>) -> Result<G, Error>, ) -> Result<Self, Error>
Acquires a GPU, builds an offscreen target size physical pixels
across, and runs init against it, as run does
without a window.
size replaces the configuration’s window size, which means nothing
without a window; the clear color and the rest of config apply as
usual. Fails if no GPU is available, if size has a zero side, if a
style of the game’s does not compile, or if init does.
Sourcepub fn tick(&mut self)
pub fn tick(&mut self)
Runs one fixed simulation step: Game::tick with
Config::tick_interval, or the step the game last set.
Headless time moves only when called; a step set during a tick is
taken from the next tick on. A tick covers the span it simulates, so
it reads the clock at the end of that span and the
step after it draws at that same instant.
Sourcepub fn with_frame_interval(self, interval: Duration) -> Self
pub fn with_frame_interval(self, interval: Duration) -> Self
The same session, with the time each Session::step covers set
to interval.
A session’s clock is the caller’s: a tick advances it by its own
interval, and a step by this one. What a frame reads as
FrameContext::elapsed is the later
of the two, so a caller that ticks and steps over the same span
counts it once, as a window would. A session starts at
Duration::ZERO, which leaves every step at the same instant.
The UI paces its own animations by that clock, so an interval is what moves a fade or a highlight of the UI’s own with no window.
Sourcepub fn set_frame_interval(&mut self, interval: Duration)
pub fn set_frame_interval(&mut self, interval: Duration)
Sets the time each later Session::step covers; see
Session::with_frame_interval.
Sourcepub fn step(&mut self) -> FrameStats
pub fn step(&mut self) -> FrameStats
Runs one frame: Game::frame records its draws, and the engine
draws exactly those into the target, replacing what was there.
Nothing is timed for you — wrap the call to measure it. Drawing
never ticks: Session::tick is the only thing that simulates. A
step advances the clock by
with_frame_interval, which is the
dt the frame reads.
A floating UI window just opened may need a few more step calls
before it draws; a capture taken right after may not show it.
Sourcepub fn set_pointer(&mut self, at: Vec2)
pub fn set_pointer(&mut self, at: Vec2)
Moves the pointer to at, in physical pixels from the target’s top
left, which is what
FrameContext::pointer reads.
The next tick or step reads it, and it stays there until this moves
it again. The distance it moves is what a
PointerDelta binding reads, exactly as a
cursor’s is, and the UI reads the same move.
Sourcepub fn press(&mut self, control: impl Into<Switch>)
pub fn press(&mut self, control: impl Into<Switch>)
Presses control, which every action bound to it reads as down, and
which the UI reads as the same press.
The next tick and the step after it read the press as an edge, and no
tick or step after them reads that edge again. The control stays down
until Session::release.
Sourcepub fn release(&mut self, control: impl Into<Switch>)
pub fn release(&mut self, control: impl Into<Switch>)
Releases control, which the next tick and the step after it read as
an edge the same way.
Sourcepub fn pointer_delta(&mut self, lane: PointerDelta, pixels: f32)
pub fn pointer_delta(&mut self, lane: PointerDelta, pixels: f32)
Moves lane of the pointer by pixels, counted right and up as
Session::set_pointer counts them.
An axis bound to that lane reads it through its own scale, a fraction of what it moved. The UI reads nothing of it. The next tick or step reads it: a lane reports a distance since the last reading, never a place.
Sourcepub fn wheel_delta(&mut self, lane: WheelDelta, notches: f32)
pub fn wheel_delta(&mut self, lane: WheelDelta, notches: f32)
Turns lane of the wheel by notches, counted right and away: one
notch is one step of a mouse wheel, the same on every target.
An axis bound to that lane reads it through its own scale, a fraction of what it turned, and the UI scrolls by what a window reports for those notches. The next tick or step reads it: a lane reports a distance since the last reading, never a place.
Sourcepub fn type_text(&mut self, text: &str)
pub fn type_text(&mut self, text: &str)
Types text into the UI, wherever it holds the keyboard.
The next Session::step reads it. The game’s own actions read
nothing of it: text belongs to the UI layer, and an action reads
controls.
Sourcepub fn wait_for_gpu(&self) -> Result<(), Error>
pub fn wait_for_gpu(&self) -> Result<(), Error>
Waits until the GPU has finished every submitted frame.
Session::step returns at submission; fence each step to cap work
in flight at one frame (vsync’s bound), so step times measure frame
cost, not queue depth.
Sourcepub fn pixels(&self) -> Result<Vec<u8>, Error>
pub fn pixels(&self) -> Result<Vec<u8>, Error>
Reads the target back: 4 * width * height bytes of sRGB-encoded RGBA,
row by row from the top left, with no padding between rows.
Every call waits for the GPU and allocates, which suits tests, not
measurement done every frame. Before the first Session::step the
pixels are undefined.
Sourcepub fn size(&self) -> UVec2
pub fn size(&self) -> UVec2
The target’s size in physical pixels, as
FrameContext::window_size
reports it to the game.
Sourcepub fn closed(&self) -> bool
pub fn closed(&self) -> bool
Whether the game has requested the end of the run through
FrameContext::close, which a
window would have closed on.
A session has no loop to end: it runs every tick and step the caller calls for, and this stays true.
Sourcepub fn fault(&self) -> Option<Error>
pub fn fault(&self) -> Option<Error>
The fault the session’s device reported, which a run behind a window would have ended on: that the device was lost, or that it ran out of memory.
The text is the log line a run behind a window would write, never the
text a player reads, which states the adapter a window run drew on.
Each
Session::step reads the device, and this reports the first fault
it read, every call, as Session::closed does: a session has no
loop to end, and the caller stops when it chooses. A call the device
refused leaves nothing here; the engine logs it at error level.
Sourcepub fn cursor(&self) -> Cursor
pub fn cursor(&self) -> Cursor
The cursor the last Session::step drew the pointer as: what the
frame set through
FrameContext::set_cursor, or
the UI’s where the UI sets a cursor of its own.
Cursor::Arrow before the first step, and where a step’s frame
set none. A cursor the UI sets that Cursor does not hold reads
as the nearest one it holds. Cursor::Held reads back like any
other: a session has no window to hold a pointer in, so
Session::set_pointer places it as it always does.
Auto Trait Implementations§
impl<G> !RefUnwindSafe for Session<G>
impl<G> !Sync for Session<G>
impl<G> !UnwindSafe for Session<G>
impl<G> Freeze for Session<G>where
GameThread<G>: Freeze,
impl<G> Send for Session<G>where
GameThread<G>: Send,
impl<G> Unpin for Session<G>where
GameThread<G>: Unpin,
impl<G> UnsafeUnpin for Session<G>where
GameThread<G>: UnsafeUnpin,
Blanket Implementations§
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
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.impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
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