@@ -765,6 +765,141 @@ impl<T: Config> SessionBuilder<T> {
765765 self
766766 }
767767
768+ // =========================================================================
769+ // Session Presets
770+ // =========================================================================
771+
772+ /// Applies LAN-optimized defaults for low-latency local network play.
773+ ///
774+ /// This preset configures the session for minimal latency scenarios typical
775+ /// of local area networks, where RTT is typically <10ms and packet loss is rare.
776+ ///
777+ /// # Configuration Applied
778+ ///
779+ /// - **Sync**: Fast handshake with fewer required roundtrips ([`SyncConfig::lan()`])
780+ /// - **Protocol**: Competitive settings with quick detection ([`ProtocolConfig::competitive()`])
781+ /// - **Time Sync**: Small window for responsive sync ([`TimeSyncConfig::lan()`])
782+ /// - **Input Delay**: 0 frames (can be adjusted with [`with_input_delay()`])
783+ ///
784+ /// # Example
785+ ///
786+ /// ```
787+ /// use fortress_rollback::{SessionBuilder, Config};
788+ ///
789+ /// # struct MyConfig;
790+ /// # impl Config for MyConfig {
791+ /// # type Input = u8;
792+ /// # type State = ();
793+ /// # type Address = std::net::SocketAddr;
794+ /// # }
795+ /// let builder = SessionBuilder::<MyConfig>::new()
796+ /// .with_lan_defaults();
797+ /// ```
798+ ///
799+ /// [`SyncConfig::lan()`]: crate::SyncConfig::lan
800+ /// [`ProtocolConfig::competitive()`]: crate::ProtocolConfig::competitive
801+ /// [`TimeSyncConfig::lan()`]: crate::TimeSyncConfig::lan
802+ /// [`with_input_delay()`]: Self::with_input_delay
803+ pub fn with_lan_defaults ( self ) -> Self {
804+ self . with_sync_config ( SyncConfig :: lan ( ) )
805+ . with_protocol_config ( ProtocolConfig :: competitive ( ) )
806+ . with_time_sync_config ( TimeSyncConfig :: lan ( ) )
807+ }
808+
809+ /// Applies Internet-optimized defaults for typical online play.
810+ ///
811+ /// This preset configures the session for typical internet connections with
812+ /// moderate latency (30-100ms RTT) and occasional packet loss (<5%).
813+ ///
814+ /// # Configuration Applied
815+ ///
816+ /// - **Sync**: Default handshake settings ([`SyncConfig::default()`])
817+ /// - **Protocol**: Default network timing ([`ProtocolConfig::default()`])
818+ /// - **Time Sync**: Default averaging window ([`TimeSyncConfig::default()`])
819+ /// - **Input Delay**: 2 frames (recommended for hiding network jitter)
820+ ///
821+ /// # Errors
822+ ///
823+ /// Returns [`FortressError::InvalidRequest`] if the input delay cannot be set
824+ /// (e.g., if the input queue is too small).
825+ ///
826+ /// # Example
827+ ///
828+ /// ```
829+ /// use fortress_rollback::{SessionBuilder, Config, FortressError};
830+ ///
831+ /// # struct MyConfig;
832+ /// # impl Config for MyConfig {
833+ /// # type Input = u8;
834+ /// # type State = ();
835+ /// # type Address = std::net::SocketAddr;
836+ /// # }
837+ /// let builder = SessionBuilder::<MyConfig>::new()
838+ /// .with_internet_defaults()?;
839+ /// # Ok::<(), FortressError>(())
840+ /// ```
841+ ///
842+ /// [`SyncConfig::default()`]: crate::SyncConfig::default
843+ /// [`ProtocolConfig::default()`]: crate::ProtocolConfig::default
844+ /// [`TimeSyncConfig::default()`]: crate::TimeSyncConfig::default
845+ /// [`FortressError::InvalidRequest`]: crate::FortressError::InvalidRequest
846+ pub fn with_internet_defaults ( self ) -> Result < Self , FortressError > {
847+ self . with_sync_config ( SyncConfig :: default ( ) )
848+ . with_protocol_config ( ProtocolConfig :: default ( ) )
849+ . with_time_sync_config ( TimeSyncConfig :: default ( ) )
850+ . with_input_delay ( 2 )
851+ }
852+
853+ /// Applies mobile/high-latency defaults for unstable connections.
854+ ///
855+ /// This preset configures the session for challenging network conditions
856+ /// typical of mobile/cellular networks or high-latency connections:
857+ /// - High RTT (100-300ms)
858+ /// - Variable latency (high jitter)
859+ /// - Intermittent packet loss (5-20%)
860+ /// - Connection handoffs (WiFi/cellular switches)
861+ ///
862+ /// # Configuration Applied
863+ ///
864+ /// - **Sync**: Robust handshake with more retries ([`SyncConfig::mobile()`])
865+ /// - **Protocol**: Tolerant settings with larger buffers ([`ProtocolConfig::mobile()`])
866+ /// - **Time Sync**: Large window for stable sync ([`TimeSyncConfig::mobile()`])
867+ /// - **Input Queue**: Larger queue for longer history ([`InputQueueConfig::high_latency()`])
868+ /// - **Input Delay**: 4 frames (helps absorb jitter spikes)
869+ ///
870+ /// # Errors
871+ ///
872+ /// Returns [`FortressError::InvalidRequest`] if the input delay cannot be set.
873+ ///
874+ /// # Example
875+ ///
876+ /// ```
877+ /// use fortress_rollback::{SessionBuilder, Config, FortressError};
878+ ///
879+ /// # struct MyConfig;
880+ /// # impl Config for MyConfig {
881+ /// # type Input = u8;
882+ /// # type State = ();
883+ /// # type Address = std::net::SocketAddr;
884+ /// # }
885+ /// let builder = SessionBuilder::<MyConfig>::new()
886+ /// .with_high_latency_defaults()?;
887+ /// # Ok::<(), FortressError>(())
888+ /// ```
889+ ///
890+ /// [`SyncConfig::mobile()`]: crate::SyncConfig::mobile
891+ /// [`ProtocolConfig::mobile()`]: crate::ProtocolConfig::mobile
892+ /// [`TimeSyncConfig::mobile()`]: crate::TimeSyncConfig::mobile
893+ /// [`InputQueueConfig::high_latency()`]: crate::InputQueueConfig::high_latency
894+ /// [`FortressError::InvalidRequest`]: crate::FortressError::InvalidRequest
895+ pub fn with_high_latency_defaults ( self ) -> Result < Self , FortressError > {
896+ self . with_sync_config ( SyncConfig :: mobile ( ) )
897+ . with_protocol_config ( ProtocolConfig :: mobile ( ) )
898+ . with_time_sync_config ( TimeSyncConfig :: mobile ( ) )
899+ . with_input_queue_config ( InputQueueConfig :: high_latency ( ) )
900+ . with_input_delay ( 4 )
901+ }
902+
768903 /// Consumes the builder to construct a [`P2PSession`] and starts synchronization of endpoints.
769904 /// # Errors
770905 /// - Returns [`InvalidRequest`] if insufficient players have been registered.
@@ -1290,4 +1425,105 @@ mod tests {
12901425 . handles
12911426 . contains_key( & PlayerHandle :: new( 1 ) ) ) ;
12921427 }
1428+
1429+ // ========================================================================
1430+ // Session Preset Tests
1431+ // ========================================================================
1432+
1433+ #[ test]
1434+ fn with_lan_defaults_returns_valid_builder ( ) {
1435+ // Arrange & Act: Create builder with LAN preset
1436+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1437+ . with_num_players ( 2 )
1438+ . unwrap ( )
1439+ . with_lan_defaults ( ) ;
1440+
1441+ // Assert: Builder is in a valid state and can accept players
1442+ let result = builder. add_local_player ( 0 ) ;
1443+ assert ! ( result. is_ok( ) ) ;
1444+ }
1445+
1446+ #[ test]
1447+ fn with_internet_defaults_returns_valid_builder ( ) {
1448+ // Arrange & Act: Create builder with internet preset
1449+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1450+ . with_num_players ( 2 )
1451+ . unwrap ( )
1452+ . with_internet_defaults ( )
1453+ . expect ( "with_internet_defaults should succeed" ) ;
1454+
1455+ // Assert: Builder is in a valid state and can accept players
1456+ let result = builder. add_local_player ( 0 ) ;
1457+ assert ! ( result. is_ok( ) ) ;
1458+ }
1459+
1460+ #[ test]
1461+ fn with_high_latency_defaults_returns_valid_builder ( ) {
1462+ // Arrange & Act: Create builder with high-latency preset
1463+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1464+ . with_num_players ( 2 )
1465+ . unwrap ( )
1466+ . with_high_latency_defaults ( )
1467+ . expect ( "with_high_latency_defaults should succeed" ) ;
1468+
1469+ // Assert: Builder is in a valid state and can accept players
1470+ let result = builder. add_local_player ( 0 ) ;
1471+ assert ! ( result. is_ok( ) ) ;
1472+ }
1473+
1474+ #[ test]
1475+ fn with_lan_defaults_applies_expected_configs ( ) {
1476+ // Arrange & Act
1477+ let builder = SessionBuilder :: < TestConfig > :: new ( ) . with_lan_defaults ( ) ;
1478+
1479+ // Assert: Verify the preset applied the expected configuration
1480+ assert_eq ! ( builder. sync_config, SyncConfig :: lan( ) ) ;
1481+ assert_eq ! ( builder. protocol_config, ProtocolConfig :: competitive( ) ) ;
1482+ assert_eq ! ( builder. time_sync_config, TimeSyncConfig :: lan( ) ) ;
1483+ }
1484+
1485+ #[ test]
1486+ fn with_internet_defaults_applies_expected_configs ( ) {
1487+ // Arrange & Act
1488+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1489+ . with_internet_defaults ( )
1490+ . expect ( "with_internet_defaults should succeed" ) ;
1491+
1492+ // Assert: Verify the preset applied the expected configuration
1493+ assert_eq ! ( builder. sync_config, SyncConfig :: default ( ) ) ;
1494+ assert_eq ! ( builder. protocol_config, ProtocolConfig :: default ( ) ) ;
1495+ assert_eq ! ( builder. time_sync_config, TimeSyncConfig :: default ( ) ) ;
1496+ assert_eq ! ( builder. input_delay, 2 ) ;
1497+ }
1498+
1499+ #[ test]
1500+ fn with_high_latency_defaults_applies_expected_configs ( ) {
1501+ // Arrange & Act
1502+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1503+ . with_high_latency_defaults ( )
1504+ . expect ( "with_high_latency_defaults should succeed" ) ;
1505+
1506+ // Assert: Verify the preset applied the expected configuration
1507+ assert_eq ! ( builder. sync_config, SyncConfig :: mobile( ) ) ;
1508+ assert_eq ! ( builder. protocol_config, ProtocolConfig :: mobile( ) ) ;
1509+ assert_eq ! ( builder. time_sync_config, TimeSyncConfig :: mobile( ) ) ;
1510+ assert_eq ! ( builder. input_queue_config, InputQueueConfig :: high_latency( ) ) ;
1511+ assert_eq ! ( builder. input_delay, 4 ) ;
1512+ }
1513+
1514+ #[ test]
1515+ fn presets_are_chainable_with_other_methods ( ) {
1516+ // Arrange & Act: Chain preset with additional configuration
1517+ let builder = SessionBuilder :: < TestConfig > :: new ( )
1518+ . with_num_players ( 4 )
1519+ . unwrap ( )
1520+ . with_lan_defaults ( )
1521+ . with_max_prediction_window ( 6 )
1522+ . with_desync_detection_mode ( DesyncDetection :: Off ) ;
1523+
1524+ // Assert: Both preset and subsequent configs applied
1525+ assert_eq ! ( builder. sync_config, SyncConfig :: lan( ) ) ;
1526+ assert_eq ! ( builder. max_prediction, 6 ) ;
1527+ assert_eq ! ( builder. desync_detection, DesyncDetection :: Off ) ;
1528+ }
12931529}
0 commit comments