@@ -1539,11 +1539,21 @@ void DollController::notify_frame_checked(FrameIndex p_doll_frame_index) {
15391539 }
15401540
15411541 // Remove all the server snapshots which doll frame was already executed.
1542+ // NOTE: This logic is removing all the snapshots older than the specified
1543+ // frame index while is not removing the specified frame index.
1544+ // It's quite important to keep that snapshot to ensure the function
1545+ // `apply_snapshot_instant_input_reconciliation` can work properly.
1546+ // It needs the snapshot the doll is at, to safely apply the reconciliation.
15421547 while (!server_snapshots.empty () && server_snapshots.front ().doll_executed_input < p_doll_frame_index) {
15431548 VecFunc::remove_at (server_snapshots, 0 );
15441549 }
15451550
15461551 // Removed all the checked doll frame snapshots.
1552+ // NOTE: This logic is removing all the snapshots older than the specified
1553+ // frame index while is not removing the specified frame index.
1554+ // It's quite important to keep that snapshot to ensure the function
1555+ // `apply_snapshot_instant_input_reconciliation` can work properly.
1556+ // It needs the snapshot the doll is at, to safely apply the reconciliation.
15471557 while (!client_snapshots.empty () && client_snapshots.front ().doll_executed_input < p_doll_frame_index) {
15481558 VecFunc::remove_at (client_snapshots, 0 );
15491559 }
@@ -1727,7 +1737,6 @@ bool DollController::__pcr__fetch_recovery_info(
17271737 DollSnapshot *client_snapshot;
17281738 DollSnapshot *server_snapshot;
17291739
1730- // This is valid until we reset it again.
17311740 const FrameIndex checkable_input = fetch_checkable_snapshot (client_snapshot, server_snapshot);
17321741 if (checkable_input == FrameIndex::NONE) {
17331742 // Nothing to check.
@@ -1763,7 +1772,17 @@ void DollController::on_snapshot_applied(
17631772 ASSERT_COND (p_frame_count_to_rewind >= 0 );
17641773#endif
17651774
1775+ // This function is executed when the SceneSynchronizer apply the server
1776+ // snapshot to reconcile the PlayerController.
1777+ // The doll, which timeline is detached from the main SceneSync (which follows the PlayerController) timeline,
1778+ // is still processed together with the SceneSync so it uses this event to
1779+ // Apply the doll server snapshots and compensate the doll input.
1780+ // NOTE: The input compensation is the act of:
1781+ // - Delaying the input processing when the input buffer is small (with the goal of growing the buffer)
1782+ // - Discarding part of the input buffer, if the buffer grown too much, to remain up-to-dated with the server.
1783+
17661784 if make_unlikely (!server_snapshots.empty () && server_snapshots.back ().doll_executed_input == FrameIndex::NONE) {
1785+ // This controller is not simulating on the server. This function handles this case.
17671786 apply_snapshot_no_input_reconciliation (p_global_server_snapshot);
17681787 }
17691788
@@ -1809,13 +1828,21 @@ void DollController::apply_snapshot_instant_input_reconciliation(const Snapshot
18091828 // on the current connection).
18101829 const int optimal_queued_inputs = fetch_optimal_queued_inputs ();
18111830
1831+ // 2. Then, find the ideal input to restore. Notice that this logic is used
1832+ // mainly to alter the input buffering size:
1833+ // If the input buffer `frames_input` is too big it discards the superflous inputs.
1834+ // If the input buffer is too small adds some fake inputs to delay the execution.
18121835 if make_likely (frames_input.back ().id .id >= std::uint32_t (optimal_queued_inputs)) {
18131836 last_doll_compared_input = frames_input.back ().id - optimal_queued_inputs;
18141837 } else {
18151838 last_doll_compared_input = FrameIndex{ 0 };
18161839 }
18171840
1818- // Search the snapshot to apply.
1841+ // 3. Once the ideal input to restore is found, it's necessary to find the
1842+ // nearest server snapshot to apply.
1843+ // Notice that this logic is build so to prefer building a bigger input buffer
1844+ // than needed, while keeping the scene consistent, rather than breaking
1845+ // the synchronization.
18191846 const DollSnapshot *snapshot_to_apply = nullptr ;
18201847 for (const DollSnapshot &snapshot : server_snapshots) {
18211848 if (snapshot.doll_executed_input <= last_doll_compared_input) {
@@ -1825,6 +1852,7 @@ void DollController::apply_snapshot_instant_input_reconciliation(const Snapshot
18251852 }
18261853 }
18271854
1855+ // 4. Just apply the snapshot.
18281856 if (snapshot_to_apply) {
18291857 static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (snapshot_to_apply->data , 0 , 0 , nullptr , true , true , true , true , true );
18301858 // Bring everything back to this point.
@@ -1834,10 +1862,10 @@ void DollController::apply_snapshot_instant_input_reconciliation(const Snapshot
18341862}
18351863
18361864void DollController::apply_snapshot_rewinding_input_reconciliation (const Snapshot &p_global_server_snapshot, const int p_frame_count_to_rewind) {
1837- // This function apply the snapshot and handles the reconciliation mechanism.
1838- // over the rewinding.
1865+ // This function applies the snapshot and handles the reconciliation mechanism
1866+ // during the rewinding process .
18391867 // The input reconciliation performed during the rewinding is the best because
1840- // allows to manipulate the timeline without causing too many rubberbanding .
1868+ // the timeline manipulations are much less visible .
18411869
18421870 // This function assume the "frame count to rewind" is never 0.
18431871 ASSERT_COND (p_frame_count_to_rewind > 0 );
@@ -1848,7 +1876,7 @@ void DollController::apply_snapshot_rewinding_input_reconciliation(const Snapsho
18481876
18491877 const int input_count = frames_input.size ();
18501878 const DollSnapshot *server_snapshot = nullptr ;
1851- FrameIndex new_last_doll_compared_input;
1879+ FrameIndex new_last_doll_compared_input = FrameIndex::NONE ;
18521880 if make_likely (input_count > 0 ) {
18531881 // 2. Fetch the best input to start processing.
18541882 const int optimal_input_count = p_frame_count_to_rewind + optimal_queued_inputs;
@@ -1857,9 +1885,7 @@ void DollController::apply_snapshot_rewinding_input_reconciliation(const Snapsho
18571885 // inputs so that the `input_count` equals to `optimal_queued_inputs`
18581886 // at the end of the reconcilation (rewinding) operation.
18591887
1860- // 3. Fetch the best FrameInput to reset.
1861- // Doesn't matter if we have or not the frame input. If not, the doll will
1862- // just wait idle.
1888+ // 3. Fetch the ideal frame to reset.
18631889 if make_likely (frames_input.back ().id .id >= std::uint32_t (optimal_input_count)) {
18641890 new_last_doll_compared_input = frames_input.back ().id - optimal_input_count;
18651891 } else {
@@ -1900,9 +1926,13 @@ void DollController::apply_snapshot_rewinding_input_reconciliation(const Snapsho
19001926 }
19011927
19021928 if make_unlikely (input_count == 0 || new_last_doll_compared_input == FrameIndex::NONE) {
1903- // There are no inputs and in this case this function has to avoidhawk:
1904- // - Advance on the timeline while rewinding (so it needs to set the timeline back).
1905- // - Try to compensate so to give the inputs enough time to arrive.
1929+ // There are no inputs or there were no server snapshots to apply during
1930+ // the rewinding phase, so it's preferable to wait more inputs and snapshots
1931+ // so to safely apply the reconciliation without introducing any desynchronizations.
1932+ //
1933+ // The follow logic make sure that the rewinding is about to happen
1934+ // doesn't alter this doll timeline: At the end of the rewinding this
1935+ // doll will be exactly as is right now.
19061936 const FrameIndex frames_to_travel = { std::uint32_t (p_frame_count_to_rewind + optimal_queued_inputs) };
19071937 if make_likely (current_input_buffer_id > frames_to_travel) {
19081938 last_doll_compared_input = current_input_buffer_id - frames_to_travel;
@@ -1913,12 +1943,18 @@ void DollController::apply_snapshot_rewinding_input_reconciliation(const Snapsho
19131943 last_doll_compared_input = new_last_doll_compared_input;
19141944 }
19151945
1916- // 5. Fetch frame index to start processing.
1917- queued_frame_index_to_process = last_doll_compared_input + 1 ;
1946+ // 5. Now it's time to prepare the doll for the next rewinding that is about to:
1947+ // - Reconcile the client
1948+ // - Resize the input buffer.
19181949 current_input_buffer_id = last_doll_compared_input;
1950+ queued_frame_index_to_process = last_doll_compared_input + 1 ;
19191951
19201952 if make_unlikely (server_snapshot) {
1921- // 6. Apply the server snapshot.
1953+ // 6. Apply the server snapshot found during the point `4`.
1954+ // That logic detected that this controller has the server snapshot
1955+ // for the input we have to reset.
1956+ // In this case, it's mandatory to apply that, to ensure the scene
1957+ // reconciliation.
19221958 static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (server_snapshots.back ().data , 0 , 0 , nullptr , true , true , true , true , true );
19231959 } else if make_likely (!client_snapshots.empty ()) {
19241960 // 7. Get the closest available snapshot, and apply it, no need to be
0 commit comments