make adjacency loading work, extend range and use loops

This commit is contained in:
Green Sky 2024-02-29 15:31:50 +01:00
parent 93f60bd073
commit 592a4cb9cf
No known key found for this signature in database

View File

@ -35,7 +35,6 @@ namespace Message::Components {
// all message fragments of this contact // all message fragments of this contact
struct ContactFragments final { struct ContactFragments final {
// kept up-to-date by events // kept up-to-date by events
//entt::dense_set<FragmentID> frags;
struct InternalEntry { struct InternalEntry {
// indecies into the sorted arrays // indecies into the sorted arrays
size_t i_b; size_t i_b;
@ -44,6 +43,7 @@ namespace Message::Components {
entt::dense_map<FragmentID, InternalEntry> frags; entt::dense_map<FragmentID, InternalEntry> frags;
// add 2 sorted contact lists for both range begin and end // add 2 sorted contact lists for both range begin and end
// TODO: adding and removing becomes expensive with enough frags, consider splitting or heap
std::vector<FragmentID> sorted_begin; std::vector<FragmentID> sorted_begin;
std::vector<FragmentID> sorted_end; std::vector<FragmentID> sorted_end;
@ -523,7 +523,8 @@ float MessageFragmentStore::tick(float time_delta) {
// last check event frags // last check event frags
// only checks if it collides with ranges, not adjacent // only checks if it collides with ranges, not adjacent
// bc ~range~ msgreg will be marked dirty and checked next tick // bc ~range~ msgreg will be marked dirty and checked next tick
if (!_event_check_queue.empty()) { const bool had_events = !_event_check_queue.empty();
for (size_t i = 0; i < 10 && !_event_check_queue.empty(); i++) {
std::cout << "MFS: event check\n"; std::cout << "MFS: event check\n";
auto fh = _fs.fragmentHandle(_event_check_queue.front().fid); auto fh = _fs.fragmentHandle(_event_check_queue.front().fid);
auto c = _event_check_queue.front().c; auto c = _event_check_queue.front().c;
@ -548,11 +549,13 @@ float MessageFragmentStore::tick(float time_delta) {
if (rangeVisible(frag_range.begin, frag_range.end, !msg_reg)) { if (rangeVisible(frag_range.begin, frag_range.end, !msg_reg)) {
loadFragment(*msg_reg, fh); loadFragment(*msg_reg, fh);
_potentially_dirty_contacts.emplace(c); _potentially_dirty_contacts.emplace(c);
}
std::cout << "MFS: event check none\n";
return 0.05f; // only one but soon again return 0.05f; // only one but soon again
} }
}
if (had_events) {
std::cout << "MFS: event check none\n";
return 0.05f; // only check events, even if non where hit
}
if (!_potentially_dirty_contacts.empty()) { if (!_potentially_dirty_contacts.empty()) {
std::cout << "MFS: pdc\n"; std::cout << "MFS: pdc\n";
@ -567,6 +570,8 @@ float MessageFragmentStore::tick(float time_delta) {
// first do collision check agains every contact associated fragment // first do collision check agains every contact associated fragment
// that is not already loaded !! // that is not already loaded !!
if (msg_reg->ctx().contains<Message::Components::ContactFragments>()) { if (msg_reg->ctx().contains<Message::Components::ContactFragments>()) {
const auto& cf = msg_reg->ctx().get<Message::Components::ContactFragments>();
if (!cf.frags.empty()) {
if (!msg_reg->ctx().contains<Message::Components::LoadedContactFragments>()) { if (!msg_reg->ctx().contains<Message::Components::LoadedContactFragments>()) {
msg_reg->ctx().emplace<Message::Components::LoadedContactFragments>(); msg_reg->ctx().emplace<Message::Components::LoadedContactFragments>();
} }
@ -608,111 +613,94 @@ float MessageFragmentStore::tick(float time_delta) {
// now, finally, check for adjecent fragments that need to be loaded // now, finally, check for adjecent fragments that need to be loaded
// we do this by finding the outermost fragment in a rage, and extend it by one // we do this by finding the outermost fragment in a rage, and extend it by one
// TODO: this is all extreamly unperformant code !!!!!! // TODO: rewrite using some bounding range tree to perform collision checks !!!
// rewrite using some bounding range tree to perform collision checks !!! // (this is now performing better, but still)
// for each view // for each view
auto c_b_view = msg_reg->view<Message::Components::Timestamp, Message::Components::ViewCurserBegin>(); auto c_b_view = msg_reg->view<Message::Components::Timestamp, Message::Components::ViewCurserBegin>();
c_b_view.use<Message::Components::ViewCurserBegin>(); c_b_view.use<Message::Components::ViewCurserBegin>();
for (const auto& [m, ts_begin_comp, vcb] : c_b_view.each()) { for (const auto& [_, ts_begin_comp, vcb] : c_b_view.each()) {
// track down both in the same run // aka "scroll down"
FragmentID frag_newest {entt::null}; { // find newest(-ish) frag in range
uint64_t frag_newest_ts {}; // or in reverse frag end <= range begin
FragmentID frag_oldest {entt::null};
uint64_t frag_oldest_ts {};
// find newest frag in range
for (const auto& [fid, si] : msg_reg->ctx().get<Message::Components::ContactFragments>().frags) { // lower bound of frag end and range begin
// we want to find the last and first fragment of the range (if not all hits are loaded, we did something wrong) const auto right = std::lower_bound(
if (!loaded_frags.contains(fid)) { cf.sorted_end.crbegin(),
continue; cf.sorted_end.crend(),
ts_begin_comp.ts,
[&](const FragmentID element, const auto& value) -> bool {
return _fs._reg.get<FragComp::MessagesTSRange>(element).end >= value;
}
);
FragmentID next_frag{entt::null};
if (right != cf.sorted_end.crend()) {
next_frag = cf.next(*right);
}
// we checked earlier that cf is not empty
if (!_fs._reg.valid(next_frag)) {
// fall back to closest, cf is not empty
next_frag = cf.sorted_end.front();
} }
// not checking frags for validity here, we checked above // a single adjacent frag is often not enough
auto fh = _fs.fragmentHandle(fid); // only ok bc next is cheap
for (size_t i = 0; i < 5 && _fs._reg.valid(next_frag); i++) {
const auto [range_begin, range_end] = fh.get<FragComp::MessagesTSRange>(); if (!loaded_frags.contains(next_frag)) {
std::cout << "MFS: next frag of range\n";
// perf, only check begin curser fist loadFragment(*msg_reg, {_fs._reg, next_frag});
if (ts_begin_comp.ts < range_end) { return 0.05f;
//if (ts_begin_comp.ts < range_end || ts_end > range_begin) {
continue;
} }
if (ts_begin_comp.ts > range_begin) { next_frag = cf.next(next_frag);
// begin curser does not hit the frag, but end might still hit/contain it }
// if has curser end, check that }
if (!msg_reg->valid(vcb.curser_end) || !msg_reg->all_of<Message::Components::ViewCurserEnd, Message::Components::Timestamp>(vcb.curser_end)) {
// no end, save no hit // curser end
if (!msg_reg->valid(vcb.curser_end) || !msg_reg->all_of<Message::Components::Timestamp>(vcb.curser_end)) {
continue; continue;
} }
const auto ts_end = msg_reg->get<Message::Components::Timestamp>(vcb.curser_end).ts; const auto ts_end = msg_reg->get<Message::Components::Timestamp>(vcb.curser_end).ts;
if (ts_end > range_begin) { // aka "scroll up"
continue; { // find oldest(-ish) frag in range
} // frag begin >= range end
}
//std::cout << "------------ hit\n";
// save hit // lower bound of frag begin and range end
if (!_fs._reg.valid(frag_newest)) { const auto left = std::lower_bound(
frag_newest = fid; cf.sorted_begin.cbegin(),
frag_newest_ts = range_begin; // new only compare against begin cf.sorted_begin.cend(),
} else { ts_end,
// now we check if >= prev [&](const FragmentID element, const auto& value) -> bool {
if (range_begin < frag_newest_ts) { return _fs._reg.get<FragComp::MessagesTSRange>(element).begin < value;
continue; }
);
FragmentID prev_frag{entt::null};
if (left != cf.sorted_begin.cend()) {
prev_frag = cf.prev(*left);
}
// we checked earlier that cf is not empty
if (!_fs._reg.valid(prev_frag)) {
// fall back to closest, cf is not empty
prev_frag = cf.sorted_begin.back();
} }
if (range_begin == frag_newest_ts) { // a single adjacent frag is often not enough
// equal ts -> fallback to id // only ok bc next is cheap
if (isLess(fh.get<FragComp::ID>().v, _fs._reg.get<FragComp::ID>(frag_newest).v)) { for (size_t i = 0; i < 5 && _fs._reg.valid(prev_frag); i++) {
// we dont "care" about equality here, since that *should* never happen if (!loaded_frags.contains(prev_frag)) {
continue; std::cout << "MFS: prev frag of range\n";
} loadFragment(*msg_reg, {_fs._reg, prev_frag});
}
frag_newest = fid;
frag_newest_ts = range_begin; // new only compare against begin
}
if (!_fs._reg.valid(frag_oldest)) {
frag_oldest = fid;
frag_oldest_ts = range_end; // old only compare against end
}
if (fid != frag_oldest && fid != frag_newest) {
// now check against old
if (range_end > frag_oldest_ts) {
continue;
}
if (range_end == frag_oldest_ts) {
// equal ts -> fallback to id
if (!isLess(fh.get<FragComp::ID>().v, _fs._reg.get<FragComp::ID>(frag_oldest).v)) {
// we dont "care" about equality here, since that *should* never happen
continue;
}
}
frag_oldest = fid;
frag_oldest_ts = range_end; // old only compare against end
}
}
const auto& cf = msg_reg->ctx().get<Message::Components::ContactFragments>();
auto frag_after = _fs.fragmentHandle(cf.next(frag_newest));
if (static_cast<bool>(frag_after) && !loaded_frags.contains(frag_after)) {
std::cout << "MFS: loading frag after newest\n";
loadFragment(*msg_reg, frag_after);
return 0.05f; return 0.05f;
} }
auto frag_before = _fs.fragmentHandle(cf.prev(frag_oldest)); prev_frag = cf.prev(prev_frag);
if (static_cast<bool>(frag_before) && !loaded_frags.contains(frag_before)) { }
std::cout << "MFS: loading frag before oldest\n"; }
loadFragment(*msg_reg, frag_before);
return 0.05f;
} }
} }
} else { } else {