@@ -210,6 +210,11 @@ pub trait Config: 'static + Send + Sync {
210210 /// a player, including when a player is disconnected.
211211 type Input : Copy + Clone + PartialEq + Default + Serialize + DeserializeOwned + Send + Sync ;
212212
213+ /// How GGRS should predict the next input for a player when their input hasn't arrived yet.
214+ ///
215+ /// [PredictRepeatLast] is a good default; see [InputPredictor] for more information.
216+ type InputPredictor : InputPredictor < Self :: Input > ;
217+
213218 /// The save state type for the session.
214219 type State : Clone + Send + Sync ;
215220
@@ -244,6 +249,11 @@ pub trait Config: 'static {
244249 /// a player, including when a player is disconnected.
245250 type Input : Copy + Clone + PartialEq + Default + Serialize + DeserializeOwned ;
246251
252+ /// How GGRS should predict the next input for a player when their input hasn't arrived yet.
253+ ///
254+ /// [PredictRepeatLast] is a good default; see [InputPredictor] for more information.
255+ type InputPredictor : InputPredictor < Self :: Input > ;
256+
247257 /// The save state type for the session.
248258 type State ;
249259
@@ -267,3 +277,131 @@ where
267277 /// The pairs `(A, Message)` indicate from which address each packet was received.
268278 fn receive_all_messages ( & mut self ) -> Vec < ( A , Message ) > ;
269279}
280+
281+ /// An [InputPredictor] allows GGRS to predict the next input for a player based on previous input
282+ /// received.
283+ ///
284+ /// # Bundled Predictors
285+ ///
286+ /// [PredictRepeatLast] is a good default choice for most action games where inputs consist of the
287+ /// buttons player are holding down; if your game input instead consists of sporadic one-off events
288+ /// which are almost never repeated, then [PredictDefault] may better suit.
289+ ///
290+ /// You are welcome to implement your own predictor to exploit known properties of your input.
291+ ///
292+ /// # Understanding Predictions
293+ ///
294+ /// A correct prediction means a rollback will not happen when input is received late from a remote
295+ /// player. An incorrect prediction will later cause GGRS to request your game to rollback. It is
296+ /// normal and expected that some predictions will be incorrect, but the more incorrect predictions
297+ /// are given to GGRS, the more work your game will have to do to resimulate past game states (and
298+ /// the more rollbacks may be noticeable to your human players).
299+ ///
300+ /// For example, if your chosen input predictor says a player's input always makes them crouch, but
301+ /// in your game players only crouch in 1% of frames, then:
302+ ///
303+ /// * GGRS will make it seem to your game as if all remote players crouch on every frame.
304+ /// * When GGRS receives input from a remote player and finds out they are not crouching, it will
305+ /// ask your game to roll back to the frame that input was from and resimulate it plus all
306+ /// subsequent frames up to and including the present frame.
307+ /// * Therefore 99% of frames will be resimulated.
308+ ///
309+ /// # Improving Prediction Accuracy
310+ ///
311+ /// ## Quantize Inputs
312+ ///
313+ /// Input prediction based on repeating past inputs works best if your inputs are discrete (or
314+ /// quantized), as this increases the chances of them being the same from frame to frame.
315+ ///
316+ /// For example, say your game allows players to move forward or stand still using an analog
317+ /// joystick; here are two ways you could represent player input:
318+ ///
319+ /// * `moving_forward: bool` set to `true` when the joystick is pressed forward and `false`
320+ /// otherwise.
321+ /// * `forward_speed: f32` with a range from `0.0` to `1.0` depending on how far the joystick is
322+ /// pressed forward.
323+ ///
324+ /// The former works well with [PredictRepeatLast], but the (fairly) continuous nature of a 32-bit
325+ /// floating point number plus the precision of an analog joystick plus the inability of most humans
326+ /// to hold a joystick perfectly still means that the value of `forward_speed` from one frame to the
327+ /// next will almost always differ; this in turn will cause many mispredictions when used with
328+ /// [PredictRepeatLast].
329+ ///
330+ /// Quantization generally incurs a tradeoff between input precision and prediction accuracy, with
331+ /// the right choice depending on the game's design:
332+ ///
333+ /// * in a keyboard-only game, move-forward input is likely a binary "move or not" anyway, so
334+ /// quantizing is unnecessary.
335+ /// * in a 2D fighting game played with analog joysticks, it might be fine for movement to be
336+ /// represented as "stand still", "walk forward", and "run forward" based on how far the joystick
337+ /// is pressed forward.
338+ /// * in a platformer played with analog joysticks, 5 to 10 discrete moving forward speeds may be
339+ /// required in order for the game to feel precise enough.
340+ ///
341+ /// ## State-based vs Transition-based Input
342+ ///
343+ /// The bundled predictors works best if your input either captures the current state of player
344+ /// input ([PredictRepeatLast]) OR captures transitions between states ([PredictDefault]).
345+ ///
346+ /// For example, say your game allows players to hold a button to crouch; here are two ways you
347+ /// could represent player input:
348+ ///
349+ /// * state-based: `crouching_button_held`, set to `true` as long as the player is crouching
350+ /// * transition-based: `crouching_button_pressed` and `crouching_button_released`, which are set to
351+ /// true on the frames where the player first presses and and releases the crouch button
352+ /// (respectively)
353+ ///
354+ /// Given a sequence of these inputs over time, these two representations capture the same
355+ /// information (with some bookkeeping, your game can trivially convert between the two). But,
356+ /// consider a single instance of a player crouching for several frames in a row:
357+ ///
358+ /// In the first case (state-based), [PredictRepeatLast] will make two mispredictions: once on the
359+ /// first frame when crouching begins, and once on the last frame when the player releases the
360+ /// crouch button.
361+ ///
362+ /// But in the second case (transition-based), [PredictRepeatLast] will make four mispredictions:
363+ ///
364+ /// * When the player first presses the crouch button
365+ /// * The frame immediately after the crouch button was pressed
366+ /// * When the player releases the crouch button
367+ /// * The frame immediately after the crouch button was released
368+ ///
369+ /// Therefore, [PredictRepeatLast] is better suited to a state-based representation of input, and
370+ /// [PredictDefault] is better suited to a transition-based representation of input.
371+ ///
372+ /// If your input is a mix of both states and transitions, then consider implementing your own
373+ /// prediction strategy that exploits that.
374+ pub trait InputPredictor < I > {
375+ /// Predict the next input for a player based on a previous input.
376+ ///
377+ /// The previous input may not be available, for example in the case where no input from a
378+ /// remote player has been received in this session yet (notably, the very first simulation of
379+ /// the first frame of a session will never have any inputs from remote players). In such a case
380+ /// GGRS will use [I::default()](Default::default) instead of calling the predictor.
381+ ///
382+ fn predict ( previous : I ) -> I ;
383+ }
384+
385+ /// An [InputPredictor] that predicts that the next input for any player will be identical to the
386+ /// last received input for that player.
387+ ///
388+ /// This is a good default choice, and a sane starting point for any custom input prediction logic.
389+ pub struct PredictRepeatLast ;
390+ impl < I > InputPredictor < I > for PredictRepeatLast {
391+ fn predict ( previous : I ) -> I {
392+ previous
393+ }
394+ }
395+
396+ /// An input predictor that always predicts that the next input for any given player will be the
397+ /// [Default](Default::default()) input, regardless of what the previous input was.
398+ ///
399+ /// This is appropriate if your inputs capture transitions between rather than states themselves;
400+ /// see the discussion at [PredictRepeatLast] (which is better suited for inputs that capture
401+ /// state) for a concrete example.
402+ pub struct PredictDefault ;
403+ impl < I : Default > InputPredictor < I > for PredictDefault {
404+ fn predict ( _previous : I ) -> I {
405+ I :: default ( )
406+ }
407+ }
0 commit comments