Skip to content

Commit b1eab7c

Browse files
committed
Fixing the apply snapshot
1 parent 43fe946 commit b1eab7c

4 files changed

Lines changed: 217 additions & 90 deletions

File tree

core/peer_networked_controller.cpp

Lines changed: 105 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -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

15831583
void 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

15871587
void 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
}

core/peer_networked_controller.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,10 @@ struct DollController final : public RemotelyControlledController {
408408

409409
void on_received_server_snapshot(const Snapshot &p_snapshot);
410410
void on_snapshot_update_finished(const Snapshot &p_snapshot);
411-
void copy_controlled_objects_snapshot(const Snapshot &p_snapshot, std::vector<DollSnapshot> &r_snapshots);
411+
void copy_controlled_objects_snapshot(
412+
const Snapshot &p_snapshot,
413+
std::vector<DollSnapshot> &r_snapshots,
414+
bool p_store_even_when_doll_is_not_processing);
412415

413416
// Checks whether this doll requires a reconciliation.
414417
// The check done is relative to the doll timeline, and not the scene sync timeline.

core/snapshot.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ NS::Snapshot NS::Snapshot::make_copy(const Snapshot &p_other) {
116116
void NS::Snapshot::copy(const Snapshot &p_other) {
117117
input_id = p_other.input_id;
118118
simulated_objects = p_other.simulated_objects;
119+
peers_frames_index = p_other.peers_frames_index;
119120
object_vars.resize(p_other.object_vars.size());
120121
for (std::size_t i = 0; i < p_other.object_vars.size(); i++) {
121122
object_vars[i].resize(p_other.object_vars[i].size());
@@ -195,6 +196,7 @@ bool NS::Snapshot::compare(
195196
r_no_rewind_recover->object_vars.resize(MAX(p_snap_A.object_vars.size(), p_snap_B.object_vars.size()));
196197
}
197198

199+
// TODO instead to iterate over all the object_vars, iterate over the simulated. This will make it save a bunch of time.
198200
for (ObjectNetId net_object_id = { 0 }; net_object_id < ObjectNetId{ uint32_t(p_snap_A.object_vars.size()) }; net_object_id += 1) {
199201
const NS::ObjectData *rew_object_data = scene_synchronizer.get_object_data(net_object_id);
200202
if (rew_object_data == nullptr || rew_object_data->realtime_sync_enabled_on_client == false) {

0 commit comments

Comments
 (0)