Skip to content

Commit 81813b0

Browse files
committed
Fixed the majority of the issues of the new doll networking. There is only one issue left: sometimes the doll doesn't receive inputs.
1 parent b1eab7c commit 81813b0

5 files changed

Lines changed: 256 additions & 153 deletions

File tree

core/peer_networked_controller.cpp

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

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

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

15631553
void 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+
16601667
bool 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

Comments
 (0)