@@ -1577,16 +1577,31 @@ void DollController::on_received_server_snapshot(const Snapshot &p_snapshot) {
15771577 VecFunc::remove (server_snapshots, DollSnapshot (FrameIndex::NONE));
15781578 }
15791579
1580- copy_controlled_objects_snapshot (p_snapshot, server_snapshots);
1580+ copy_controlled_objects_snapshot (p_snapshot, server_snapshots, true );
15811581}
15821582
15831583void DollController::on_snapshot_update_finished (const Snapshot &p_snapshot) {
1584- copy_controlled_objects_snapshot (p_snapshot, client_snapshots);
1584+ copy_controlled_objects_snapshot (p_snapshot, client_snapshots, false );
15851585}
15861586
15871587void DollController::copy_controlled_objects_snapshot (
15881588 const Snapshot &p_snapshot,
1589- std::vector<DollSnapshot> &r_snapshots) {
1589+ std::vector<DollSnapshot> &r_snapshots,
1590+ bool p_store_even_when_doll_is_not_processing) {
1591+ const FrameIndex doll_executed_input = MapFunc::at (p_snapshot.peers_frames_index , peer_controller->get_authority_peer (), FrameIndex::NONE);
1592+ const std::vector<ObjectData *> *controlled_objects = peer_controller->scene_synchronizer ->get_peer_controlled_objects_data (peer_controller->get_authority_peer ());
1593+
1594+ if (!p_store_even_when_doll_is_not_processing) {
1595+ if (doll_executed_input == FrameIndex::NONE) {
1596+ // Nothing to store.
1597+ return ;
1598+ }
1599+ if (!controlled_objects || controlled_objects->size () <= 0 ) {
1600+ // Nothing to store for this doll.
1601+ return ;
1602+ }
1603+ }
1604+
15901605 DollSnapshot *snap;
15911606 {
15921607 snap = find_snapshot_by_snapshot_id (r_snapshots, p_snapshot.input_id );
@@ -1597,13 +1612,10 @@ void DollController::copy_controlled_objects_snapshot(
15971612 }
15981613 }
15991614
1600- const FrameIndex doll_executed_input = MapFunc::at (p_snapshot.peers_frames_index , peer_controller->get_authority_peer (), FrameIndex::NONE);
1601-
16021615 snap->doll_executed_input = doll_executed_input;
16031616 // Extracts the data from the snapshot.
16041617 MapFunc::assign (snap->data .peers_frames_index , peer_controller->get_authority_peer (), doll_executed_input);
16051618
1606- const std::vector<ObjectData *> *controlled_objects = peer_controller->scene_synchronizer ->get_peer_controlled_objects_data (peer_controller->get_authority_peer ());
16071619 if (!controlled_objects || controlled_objects->size () <= 0 ) {
16081620 // Nothing to store for this doll.
16091621 return ;
@@ -1655,30 +1667,37 @@ bool DollController::__pcr__fetch_recovery_info(
16551667#endif
16561668) const {
16571669
1658- // 1. Fetch the server snapshot.
1659- // The server snapshot can be fetched, normally, using the snapshot index.
1660- const DollSnapshot *server_snapshot = find_snapshot_by_snapshot_id (server_snapshots, p_checking_frame_index);
1661-
1662- // This is not supposed to trigger
1663- ENSURE_V_MSG (server_snapshot, true , " This error should never trigger since the function `copy_controlled_objects_snapshots` always stores the received snapshots." );
1664-
1665- // 2. Now fetch the client snapshot.
1666- // Since the doll is following a a different timeline, we need to fetch the
1667- // client frame by checking the `doll_executed_index` instead.
1668- const auto &client_snapshot_it = VecFunc::find (client_snapshots, DollSnapshot (server_snapshot->doll_executed_input ));
1669- if (client_snapshot_it == client_snapshots.end ()) {
1670- // The client snapshot was not found, and this can happen only when the
1671- // input was not executed yet.
1672- // So, nothing to compare here.
1670+ // Since the doll is processing a parallel timeline, we can't simply use
1671+ // the `p_checking_frame_index` provided.
1672+
1673+ // 1. Find the last processed client snapshot for which a server snapshot is
1674+ // available.
1675+ //
1676+
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+ }
1689+
1690+ if (client_snapshot == nullptr ) {
1691+ // Nothing to check.
16731692 return true ;
16741693 }
16751694
16761695 // Now just compare the two snapshots.
16771696 return Snapshot::compare (
16781697 *peer_controller->scene_synchronizer ,
16791698 server_snapshot->data ,
1680- client_snapshot_it ->data ,
1681- - 1 ,
1699+ client_snapshot ->data ,
1700+ peer_controller-> get_authority_peer () ,
16821701 r_no_rewind_recover,
16831702 r_differences_info
16841703#ifdef DEBUG_ENABLED
@@ -1695,6 +1714,23 @@ void DollController::on_snapshot_applied(
16951714 // assertion is always satisfied.
16961715 ASSERT_COND (peer_controller->scene_synchronizer ->is_client ());
16971716
1717+ queued_instant_offset = 0 ;
1718+
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);
1725+
1726+ if make_unlikely (doll_frame_index == FrameIndex::NONE || p_frame_count_to_rewind <= 0 ) {
1727+ // - On the server, the doll was not processed so just apply the server snapshot.
1728+ // - 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 );
1731+ return ;
1732+ }
1733+
16981734 // This function handles the reconciliation mechanism.
16991735 // The reconciliation is implemented in this function because this is the
17001736 // best moment to manipulate the processing (to consume or build the input
@@ -1735,69 +1771,57 @@ void DollController::on_snapshot_applied(
17351771 queued_instant_offset = -index_to_frame_to_keep;
17361772 }
17371773
1738- // 5. Get the executed frame index on the server side.
1739- const FrameIndex doll_frame_index =
1740- MapFunc::at (
1741- p_global_server_snapshot.peers_frames_index ,
1742- peer_controller->get_authority_peer (),
1743- FrameIndex::NONE);
1744-
1745- if (doll_frame_index == FrameIndex::NONE) {
1746- // On the server, the doll was not executed so just apply the server snapshot.
1747- const auto server_snap_it =
1748- VecFunc::find (
1749- server_snapshots,
1750- DollSnapshot (FrameIndex::NONE));
1751- ENSURE_MSG (server_snap_it != server_snapshots.end (), " The doll was unable to set the NO-CONTROLLER snapshot because it was unable to find it in the server_snapshots array." );
1752- static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (server_snap_it->data , 0 , 0 , nullptr , true , true , true , true , true );
1753-
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+ }
17541794 } else {
1755- // At this point it's necessary to mention that the doll is procesing
1756- // on a different timeline, compared to the one executed on the server;
1757- // For this reason, this function applies the client snapshot, and leaves to
1758- // Rewinding's process function the task to apply the server snapshot
1759- // when it's the time to do it.
1760-
1761- // 6. Fetch the best FrameInput.
1762- FrameIndex index;
1763- if (queued_instant_offset > 0 ) {
1764- // Missing inputs, so we need to give room to the rewinding and apply
1765- // the available frames_input at the end of the rewinding.
1766- if make_likely (frames_input[0 ].id .id > std::uint32_t (queued_instant_offset)) {
1767- // In this case the available ID is big enough and it's enough
1768- // subtracting the missing amount to find the best index to apply.
1769- index = index - queued_instant_offset;
1795+ // More inputs than needed.
1796+ index = frames_input[-queued_instant_offset].id ;
1797+ }
1798+
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+ }
1804+
1805+ if (!client_snapshots.empty ()) {
1806+ // 7. Get the closest available snapshot, and apply it, no need to be
1807+ // precise here, since the process will apply the server snapshot
1808+ // when available.
1809+ int distance = std::numeric_limits<int >::max ();
1810+ DollSnapshot *best = nullptr ;
1811+ for (auto &snap : client_snapshots) {
1812+ const int delta = std::abs (std::int64_t (index.id ) - std::int64_t (snap.doll_executed_input .id ));
1813+ if (delta < distance) {
1814+ best = &snap;
1815+ distance = delta;
17701816 } else {
1771- // In this case the available ID is not big enough, so just assume
1772- // we start from 0 .
1773- index = { 0 } ;
1817+ // Since the snapshots are sorted, it can interrupt the
1818+ // processing right after the distance start increasing .
1819+ break ;
17741820 }
1775- } else {
1776- // More inputs than needed.
1777- index = frames_input[-queued_instant_offset].id ;
17781821 }
17791822
1780- if (!client_snapshots.empty ()) {
1781- // 7. Get the closest available snapshot, and apply it, no need to be
1782- // precise here, since the process will apply the server snapshot
1783- // when available.
1784- int distance = std::numeric_limits<int >::max ();
1785- DollSnapshot *best = &client_snapshots.front ();
1786- for (auto &snap : client_snapshots) {
1787- const int delta = std::abs (std::int64_t (best->doll_executed_input .id ) - std::int64_t (snap.doll_executed_input .id ));
1788- if (delta < distance) {
1789- best = &snap;
1790- distance = delta;
1791- } else {
1792- // Since the snapshots are sorted, it can interrupt the
1793- // processing right after the distance start increasing.
1794- break ;
1795- }
1796- }
1797-
1798- if (best) {
1799- static_cast <ClientSynchronizer *>(peer_controller->scene_synchronizer ->get_synchronizer_internal ())->apply_snapshot (best->data , 0 , 0 , nullptr , true , true , true , true , true );
1800- }
1823+ 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 );
18011825 }
18021826 }
18031827}
0 commit comments