@@ -1289,12 +1289,12 @@ DollController::DollController(PeerNetworkedController *p_peer_controller) :
12891289 event_handler_client_snapshot_updated =
12901290 peer_controller->scene_synchronizer ->event_snapshot_update_finished .bind (std::bind (&DollController::on_snapshot_update_finished, this , std::placeholders::_1));
12911291
1292- event_handler_rewind_frame_begin =
1293- peer_controller->scene_synchronizer ->event_rewind_frame_begin .bind (std::bind (&DollController::on_rewind_frame_begin, this , std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
1294-
12951292 event_handler_state_validated =
12961293 peer_controller->scene_synchronizer ->event_state_validated .bind (std::bind (&DollController::on_state_validated, this , std::placeholders::_1, std::placeholders::_2));
12971294
1295+ event_handler_rewind_frame_begin =
1296+ peer_controller->scene_synchronizer ->event_rewind_frame_begin .bind (std::bind (&DollController::on_rewind_frame_begin, this , std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
1297+
12981298 event_handler_snapshot_applied =
12991299 peer_controller->scene_synchronizer ->event_snapshot_applied .bind (std::bind (&DollController::on_snapshot_applied, this , std::placeholders::_1, std::placeholders::_2));
13001300}
@@ -1306,12 +1306,12 @@ DollController::~DollController() {
13061306 peer_controller->scene_synchronizer ->event_snapshot_update_finished .unbind (event_handler_client_snapshot_updated);
13071307 event_handler_client_snapshot_updated = NS::NullPHandler;
13081308
1309- peer_controller->scene_synchronizer ->event_rewind_frame_begin .unbind (event_handler_rewind_frame_begin);
1310- event_handler_rewind_frame_begin = NS::NullPHandler;
1311-
13121309 peer_controller->scene_synchronizer ->event_state_validated .unbind (event_handler_state_validated);
13131310 event_handler_state_validated = NS::NullPHandler;
13141311
1312+ peer_controller->scene_synchronizer ->event_rewind_frame_begin .unbind (event_handler_rewind_frame_begin);
1313+ event_handler_rewind_frame_begin = NS::NullPHandler;
1314+
13151315 peer_controller->scene_synchronizer ->event_snapshot_applied .unbind (event_handler_snapshot_applied);
13161316 event_handler_snapshot_applied = NS::NullPHandler;
13171317}
@@ -1335,7 +1335,7 @@ bool DollController::receive_inputs(const Vector<uint8_t> &p_data) {
13351335 SCParseTmpData *pd = static_cast <SCParseTmpData *>(p_user_pointer);
13361336
13371337 ASSERT_COND (p_frame_index != FrameIndex::NONE);
1338- if (pd->controller .last_checked_input != FrameIndex::NONE && pd->controller .last_checked_input >= p_frame_index) {
1338+ if (pd->controller .last_doll_validated_input != FrameIndex::NONE && pd->controller .last_doll_validated_input >= p_frame_index) {
13391339 // This input is already processed.
13401340 return ;
13411341 }
@@ -1409,15 +1409,21 @@ bool DollController::fetch_next_input(double p_delta) {
14091409 // `on_snapshot_applied`, and is used to compensate the lag by
14101410 // getting rid or introduce inputs, during the recdonciliation (rewinding)
14111411 // phase.
1412- const int instant_to_process = queued_instant_to_process - queued_instant_offset;
1413- if (instant_to_process >= 0 ) {
1414- ENSURE_V_MSG (instant_to_process < int (frames_input.size ()), false , " The doll lag compensation failed. The offsetted instant_to_process is never supposed to overflow the frames_input. Something didn't work inside the `on_snapshot_applied`." );
1415- set_frame_input (frames_input[instant_to_process], false );
1416- return true ;
1417- } else {
1418- // The doll character is compensating for missing inputs, so return false for now.
1419- return false ;
1412+ const FrameIndex frame_to_process = queued_frame_index_to_process + queued_instant_to_process;
1413+ // Search the input.
1414+ for (const FrameInput &frame : frames_input) {
1415+ if (frame.id == frame_to_process) {
1416+ set_frame_input (frame, false );
1417+ return true ;
1418+ } else if (frame_to_process < frame.id ) {
1419+ // The frames are sorted, so it's impossible we find the frame in this case.
1420+ break ;
1421+ }
14201422 }
1423+ // The doll controller is compensating for missing inputs, so return
1424+ // false, on this frame to stop processing untill then.
1425+ current_input_buffer_id = frame_to_process;
1426+ return false ;
14211427 }
14221428
14231429 if make_unlikely (current_input_buffer_id == FrameIndex::NONE) {
@@ -1474,8 +1480,6 @@ bool DollController::fetch_next_input(double p_delta) {
14741480}
14751481
14761482void DollController::process (double p_delta) {
1477- notify_frame_checked (peer_controller->scene_synchronizer ->client_get_last_checked_frame_index ());
1478-
14791483 const bool is_new_input = fetch_next_input (p_delta);
14801484
14811485 if (is_new_input) {
@@ -1508,67 +1512,55 @@ void DollController::process(double p_delta) {
15081512}
15091513
15101514void DollController::on_state_validated (FrameIndex p_frame_index, bool p_detected_desync) {
1511- notify_frame_checked (p_frame_index);
1515+ notify_frame_checked (last_doll_compared_input);
1516+ is_last_doll_compared_input_valid = false ;
1517+ last_doll_compared_input = FrameIndex::NONE;
15121518}
15131519
1514- void DollController::notify_frame_checked (FrameIndex p_frame_index) {
1515- if (p_frame_index == FrameIndex::NONE) {
1516- // Nothing to do.
1517- return ;
1518- }
1519-
1520- if (last_checked_input >= p_frame_index) {
1521- // Already checked.
1522- return ;
1523- }
1524-
1525- DollSnapshot *server_snapshot = find_snapshot_by_snapshot_id (server_snapshots, p_frame_index);
1526- ENSURE_MSG (server_snapshot, " This should never trigger, since the server_snapshots is supposed to have the frame " + p_frame_index + " at this point." );
1527- const FrameIndex doll_frame_index = server_snapshot->doll_executed_input ;
1528-
1529- // Remove all the doll related data.
1530- if (doll_frame_index == FrameIndex::NONE) {
1520+ void DollController::notify_frame_checked (FrameIndex p_doll_frame_index) {
1521+ if (p_doll_frame_index == FrameIndex::NONE) {
15311522 // Nothing to do.
15321523 return ;
15331524 }
15341525
1535- if (last_doll_checked_input >= doll_frame_index ) {
1526+ if (last_doll_validated_input != FrameIndex::NONE && last_doll_validated_input >= p_doll_frame_index ) {
15361527 // Already checked.
15371528 return ;
15381529 }
15391530
15401531 // Removes all the inputs older than the known one (included).
1541- while (!frames_input.empty () && frames_input.front ().id <= doll_frame_index ) {
1542- if (frames_input.front ().id == doll_frame_index ) {
1532+ while (!frames_input.empty () && frames_input.front ().id <= p_doll_frame_index ) {
1533+ if (frames_input.front ().id == p_doll_frame_index ) {
15431534 // Pause the streaming if the last frame is empty.
15441535 streaming_paused = (frames_input.front ().buffer_size_bit - METADATA_SIZE) <= 0 ;
15451536 }
15461537 frames_input.pop_front ();
15471538 }
15481539
15491540 // Remove all the server snapshots which doll frame was already executed.
1550- while (!server_snapshots.empty () && server_snapshots.front ().doll_executed_input <= doll_frame_index ) {
1541+ while (!server_snapshots.empty () && server_snapshots.front ().doll_executed_input <= p_doll_frame_index ) {
15511542 VecFunc::remove_at (server_snapshots, 0 );
15521543 }
15531544
15541545 // Removed all the checked doll frame snapshots.
1555- while (!client_snapshots.empty () && client_snapshots.front ().doll_executed_input <= doll_frame_index ) {
1546+ while (!client_snapshots.empty () && client_snapshots.front ().doll_executed_input <= p_doll_frame_index ) {
15561547 VecFunc::remove_at (client_snapshots, 0 );
15571548 }
15581549
1559- last_checked_input = p_frame_index;
1560- last_doll_checked_input = doll_frame_index;
1550+ last_doll_validated_input = p_doll_frame_index;
15611551}
15621552
15631553void DollController::on_received_server_snapshot (const Snapshot &p_snapshot) {
1564- if (last_checked_input != FrameIndex::NONE && last_checked_input >= p_snapshot.input_id ) {
1554+ NS_PROFILE
1555+ const FrameIndex doll_executed_input = MapFunc::at (p_snapshot.peers_frames_index , peer_controller->get_authority_peer (), FrameIndex::NONE);
1556+ if (last_doll_validated_input != FrameIndex::NONE && last_doll_validated_input >= doll_executed_input) {
15651557 // Snapshot already checked, no need to store this.
15661558 return ;
15671559 }
15681560
15691561 // This check ensure that the server_snapshots contains just a single FrameIndex::NONE
15701562 // snapshot or a bunch of indexed one.
1571- if (p_snapshot.input_id == FrameIndex::NONE) {
1563+ if (p_snapshot.input_id == FrameIndex::NONE || doll_executed_input == FrameIndex::NONE ) {
15721564 // The received snapshot doesn't have a FrameIndex set, it means there is no controller
15731565 // so assume this is the most up-to-date snapshot.
15741566 server_snapshots.clear ();
@@ -1588,6 +1580,7 @@ void DollController::copy_controlled_objects_snapshot(
15881580 const Snapshot &p_snapshot,
15891581 std::vector<DollSnapshot> &r_snapshots,
15901582 bool p_store_even_when_doll_is_not_processing) {
1583+ NS_PROFILE
15911584 const FrameIndex doll_executed_input = MapFunc::at (p_snapshot.peers_frames_index , peer_controller->get_authority_peer (), FrameIndex::NONE);
15921585 const std::vector<ObjectData *> *controlled_objects = peer_controller->scene_synchronizer ->get_peer_controlled_objects_data (peer_controller->get_authority_peer ());
15931586
@@ -1657,41 +1650,61 @@ void DollController::copy_controlled_objects_snapshot(
16571650 is_doll_snap_A_older);
16581651}
16591652
1653+ FrameIndex DollController::fetch_best_recoverable_snapshot (DollSnapshot *&r_client_snapshot, DollSnapshot *&r_server_snapshot) {
1654+ for (auto client_snap_it = client_snapshots.rbegin (); client_snap_it != client_snapshots.rend (); client_snap_it++) {
1655+ if (client_snap_it->doll_executed_input != FrameIndex::NONE) {
1656+ auto server_snap_it = VecFunc::find (server_snapshots, client_snap_it->doll_executed_input );
1657+ if (server_snap_it != server_snapshots.end ()) {
1658+ r_client_snapshot = &(*client_snap_it);
1659+ r_server_snapshot = &*server_snap_it;
1660+ return client_snap_it->doll_executed_input ;
1661+ }
1662+ }
1663+ }
1664+ return FrameIndex::NONE;
1665+ }
1666+
16601667bool DollController::__pcr__fetch_recovery_info (
1661- FrameIndex p_checking_frame_index,
1668+ const FrameIndex p_checking_frame_index,
1669+ const int p_frame_count_to_rewind,
16621670 Snapshot *r_no_rewind_recover,
16631671 std::vector<std::string> *r_differences_info
16641672#ifdef DEBUG_ENABLED
16651673 ,
16661674 std::vector<ObjectNetId> *r_different_node_data
16671675#endif
1668- ) const {
1676+ ) {
1677+ // ---------------------------------------------- Force input reconciliation
1678+ const Settings &settings = peer_controller->scene_synchronizer ->get_settings ();
1679+ if (p_frame_count_to_rewind >= settings.lag_compensation .doll_force_input_reconciliation_min_frames ) {
1680+ const int optimal_queued_inputs = fetch_optimal_queued_inputs ();
1681+ const float optimal_input_count = p_frame_count_to_rewind + optimal_queued_inputs;
1682+ const int input_count = frames_input.size ();
1683+ if (input_count > (optimal_input_count + settings.lag_compensation .doll_force_input_reconciliation )) {
1684+ return false ;
1685+ }
1686+ }
16691687
1688+ // ---------------------------------------------------- Snapshot comparation
16701689 // Since the doll is processing a parallel timeline, we can't simply use
16711690 // the `p_checking_frame_index` provided.
16721691
16731692 // 1. Find the last processed client snapshot for which a server snapshot is
16741693 // available.
1675- //
1694+ DollSnapshot *client_snapshot;
1695+ DollSnapshot *server_snapshot;
16761696
1677- const DollSnapshot *client_snapshot = nullptr ;
1678- const DollSnapshot *server_snapshot = nullptr ;
1679- for (auto client_snap_it = client_snapshots.rbegin (); client_snap_it != client_snapshots.rend (); client_snap_it++) {
1680- if (client_snap_it->doll_executed_input != FrameIndex::NONE) {
1681- auto server_snap_it = VecFunc::find (server_snapshots, client_snap_it->doll_executed_input );
1682- if (server_snap_it != server_snapshots.end ()) {
1683- client_snapshot = &*client_snap_it;
1684- server_snapshot = &*server_snap_it;
1685- break ;
1686- }
1687- }
1688- }
1697+ // This is valid until we reset it again.
1698+ is_last_doll_compared_input_valid = true ;
1699+ last_doll_compared_input = fetch_best_recoverable_snapshot (client_snapshot, server_snapshot);
16891700
1690- if (client_snapshot == nullptr ) {
1701+ if (last_doll_compared_input == FrameIndex::NONE ) {
16911702 // Nothing to check.
16921703 return true ;
16931704 }
16941705
1706+ last_doll_compared_input = client_snapshot->doll_executed_input ;
1707+
16951708 // Now just compare the two snapshots.
16961709 return Snapshot::compare (
16971710 *peer_controller->scene_synchronizer ,
@@ -1714,20 +1727,22 @@ void DollController::on_snapshot_applied(
17141727 // assertion is always satisfied.
17151728 ASSERT_COND (peer_controller->scene_synchronizer ->is_client ());
17161729
1717- queued_instant_offset = 0 ;
1730+ queued_frame_index_to_process = FrameIndex{ 0 } ;
17181731
1719- // 0. Make sure the doll was processed on the server.
1720- const FrameIndex doll_frame_index =
1721- MapFunc::at (
1722- p_global_server_snapshot.peers_frames_index ,
1723- peer_controller->get_authority_peer (),
1724- FrameIndex::NONE);
1732+ if (!is_last_doll_compared_input_valid) {
1733+ DollSnapshot *client_snapshot;
1734+ DollSnapshot *server_snapshot;
1735+ last_doll_compared_input = fetch_best_recoverable_snapshot (client_snapshot, server_snapshot);
1736+ }
17251737
1726- if make_unlikely (doll_frame_index == FrameIndex::NONE || p_frame_count_to_rewind <= 0 ) {
1738+ if make_unlikely (last_doll_compared_input == FrameIndex::NONE || p_frame_count_to_rewind <= 0 ) {
17271739 // - On the server, the doll was not processed so just apply the server snapshot.
17281740 // - In case of no rewinding, it applies the most up to date server snapshot right away.
1729- ENSURE_MSG (!server_snapshots.empty (), " The doll was unable to set the server snapshot as there is no snapshot available right now." );
1730- static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (server_snapshots.back ().data , 0 , 0 , nullptr , true , true , true , true , true );
1741+ auto server_snapshot_it = VecFunc::find (server_snapshots, last_doll_compared_input);
1742+ ENSURE_MSG (server_snapshot_it != server_snapshots.end (), " This should be impossible. The doll was unable to set the server snapshot since the snapshot was not found: " + last_doll_compared_input);
1743+ static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (server_snapshot_it->data , 0 , 0 , nullptr , true , true , true , true , true );
1744+ // Reset the current_input_buffer_id, to make sure the next Frame processed starts from here.
1745+ current_input_buffer_id = last_doll_compared_input;
17311746 return ;
17321747 }
17331748
@@ -1751,65 +1766,26 @@ void DollController::on_snapshot_applied(
17511766 // inputs so that the `input_count` equals to `optimal_queued_inputs`
17521767 // at the end of the reconcilation (rewinding) operation.
17531768
1754- // 4. Compensate the lag.
1755- if (input_count < optimal_input_count) {
1756- // It has less inputs than the optimal input count defined.
1757- // In this case the offset, mention above, is going to be positive;
1758- // making sure the available frames_input are used at the end of the processing
1759- // so the `optimal_queued_inputs` is left at the end of the rewinding.
1760- const int missing_inputs = optimal_input_count - input_count;
1761- queued_instant_offset = missing_inputs;
1762-
1763- } else {
1764- // It has more inputs than the optimal input count defined.
1765- // In this case the offset is negative, meaning it throws away all the
1766- // extra inputs to recatch the server.
1767-
1768- // The following variable is the index pointing to the frame it want to
1769- // start processing.
1770- const int index_to_frame_to_keep = input_count - optimal_input_count;
1771- queued_instant_offset = -index_to_frame_to_keep;
1772- }
1773-
1774- // At this point it's necessary to mention that the doll is procesing
1775- // on a different timeline, compared to the one executed on the server;
1776- // For this reason, this function applies the client snapshot, and leaves to
1777- // Rewinding's process function the task to apply the server snapshot
1778- // when it's the time to do it.
1779-
1780- // 6. Fetch the best FrameInput to reset.
1781- FrameIndex index;
1782- if (queued_instant_offset > 0 ) {
1783- // Missing inputs, so we need to give room to the rewinding and apply
1784- // the available frames_input at the end of the rewinding.
1785- if make_likely (frames_input[0 ].id .id > std::uint32_t (queued_instant_offset)) {
1786- // In this case the available ID is big enough and it's enough
1787- // subtracting the missing amount to find the best index to apply.
1788- index = index - queued_instant_offset;
1789- } else {
1790- // In this case the available ID is not big enough, so just assume
1791- // we start from 0.
1792- index = { 0 };
1793- }
1769+ // 4. Fetch the best FrameInput to reset.
1770+ // Doesn't matter if we have or not the frame input. If not, the doll will
1771+ // just wait idle.
1772+ if make_likely (frames_input.back ().id .id >= std::uint32_t (optimal_input_count)) {
1773+ last_doll_compared_input = frames_input.back ().id - optimal_input_count;
17941774 } else {
1795- // More inputs than needed.
1796- index = frames_input[-queued_instant_offset].id ;
1775+ last_doll_compared_input = FrameIndex{ 0 };
17971776 }
17981777
1799- if (index > FrameIndex{ 0 }) {
1800- // Decrease the index by 1 to find the best snapshot to apply (that has
1801- // to be the one before the snapshot to rewind).
1802- index -= 1 ;
1803- }
1778+ // 5. Fetch frame index to start processing.
1779+ queued_frame_index_to_process = last_doll_compared_input + 1 ;
18041780
18051781 if (!client_snapshots.empty ()) {
1806- // 7 . Get the closest available snapshot, and apply it, no need to be
1782+ // 6 . Get the closest available snapshot, and apply it, no need to be
18071783 // precise here, since the process will apply the server snapshot
18081784 // when available.
18091785 int distance = std::numeric_limits<int >::max ();
18101786 DollSnapshot *best = nullptr ;
18111787 for (auto &snap : client_snapshots) {
1812- const int delta = std::abs (std::int64_t (index .id ) - std::int64_t (snap.doll_executed_input .id ));
1788+ const int delta = std::abs (std::int64_t (last_doll_compared_input .id ) - std::int64_t (snap.doll_executed_input .id ));
18131789 if (delta < distance) {
18141790 best = &snap;
18151791 distance = delta;
@@ -1821,7 +1797,12 @@ void DollController::on_snapshot_applied(
18211797 }
18221798
18231799 if (best) {
1824- static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (best->data , 0 , 0 , nullptr , true , true , true , true , true );
1800+ auto best_server_snap_it = NS::VecFunc::find (client_snapshots, best->doll_executed_input );
1801+ if (best_server_snap_it != client_snapshots.end ()) {
1802+ static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (best_server_snap_it->data , 0 , 0 , nullptr , true , true , true , true , true );
1803+ } else {
1804+ static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (best->data , 0 , 0 , nullptr , true , true , true , true , true );
1805+ }
18251806 }
18261807 }
18271808}
0 commit comments