From e68bb676dbbc50d48017c8a5b0898879736b78f7 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 12 Oct 2024 02:09:12 -0700 Subject: [PATCH] Fix netsync of race checkpoints and associated map lines - Use srb2::MobjList to keep checkpoint objects list intact after savegame load - Use std::unordered_map of line tag and vector of line_t pointers - Use line tag for the key so multiple checkpoints may be associated to the same set of lines --- src/objects/checkpoint.cpp | 115 ++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 65 deletions(-) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index c534b5bde..867ace7a6 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -9,6 +9,8 @@ //----------------------------------------------------------------------------- #include +#include +#include #include @@ -35,8 +37,6 @@ #include "../sounds.h" #include "../tables.h" -using std::vector; -using std::pair; using std::min; using std::max; using std::clamp; @@ -45,7 +45,6 @@ extern mobj_t* svg_checkpoints; #define checkpoint_id(o) ((o)->thing_args[0]) #define checkpoint_linetag(o) ((o)->thing_args[1]) -#define checkpoint_extralength(o) ((o)->thing_args[2]) #define checkpoint_other(o) ((o)->target) #define checkpoint_orb(o) ((o)->tracer) #define checkpoint_arm(o) ((o)->hnext) @@ -132,6 +131,7 @@ struct Checkpoint : mobj_t struct Arm : mobj_t {}; INT32 id() const { return checkpoint_id(this); } + INT32 linetag() const { return checkpoint_linetag(this); } Checkpoint* other() const { return static_cast(checkpoint_other(this)); } void other(Checkpoint* n) { P_SetTarget(&checkpoint_other(this), n); } @@ -453,39 +453,16 @@ struct CheckpointManager auto begin() { return list_.begin(); } auto end() { return list_.end(); } - auto find_checkpoint(INT32 id) { - auto it = find_if(list_.begin(), list_.end(), [id](auto pair) { return pair.first->id() == id; }); - if (it != list_.end()) - { - return it->first; - } - return static_cast(nullptr); - } - - // auto find_pair(Checkpoint* chk) { - // pair> retpair; - // auto it = find_if(list_.begin(), list_.end(), [chk](auto pair) { return pair.first == chk; }); - // if (it != list_.end()) - // { - // retpair = *it; - // return retpair; - // } - // return static_cast>>(nullptr); - // } - - void remove_checkpoint(mobj_t* end) - { - auto chk = static_cast(end); - auto it = find_if(list_.begin(), list_.end(), [&](auto pair) { return pair.first == chk; }); - if (it != list_.end()) - { - list_.erase(it); - } - } - - void link_checkpoint(mobj_t* end) + auto find_checkpoint(INT32 id) + { + auto it = std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); + return it != end() ? *it : nullptr; + } + + void remove_checkpoint(Checkpoint* end) { list_.erase(end); } + + void link_checkpoint(Checkpoint* chk) { - auto chk = static_cast(end); auto id = chk->id(); if (chk->spawnpoint && id == 0) { @@ -517,29 +494,39 @@ struct CheckpointManager } else // Checkpoint isn't in the list, find any associated tagged lines and make the pair { - vector checklines; - if (checkpoint_linetag(chk)) - { - INT32 li; - INT32 tag = checkpoint_linetag(chk); - TAG_ITER_LINES(tag, li) - { - line_t* line = lines + li; - checklines.push_back(line); - } - } - list_.emplace_back(chk, move(checklines)); + if (chk->linetag()) + lines_.try_emplace(chk->linetag(), std::move(tagged_lines(chk->linetag()))); + list_.push_front(chk); } chk->gingerbread(); } - void clear() { list_.clear(); } + void clear() { lines_.clear(); } - auto count() { return list_.size(); } + auto count() { return list_.count(); } + + const std::vector* lines_for(const Checkpoint* chk) const + { + auto it = lines_.find(chk->linetag()); + return it != lines_.end() ? &it->second : nullptr; + } private: - vector>> list_; + srb2::MobjList list_; + std::unordered_map> lines_; + + static std::vector tagged_lines(INT32 tag) + { + std::vector checklines; + INT32 li; + TAG_ITER_LINES(tag, li) + { + line_t* line = lines + li; + checklines.push_back(line); + } + return checklines; + } }; CheckpointManager g_checkpoints; @@ -548,13 +535,13 @@ CheckpointManager g_checkpoints; void Obj_LinkCheckpoint(mobj_t* end) { - g_checkpoints.link_checkpoint(end); + g_checkpoints.link_checkpoint(static_cast(end)); } void Obj_UnlinkCheckpoint(mobj_t* end) { auto chk = static_cast(end); - g_checkpoints.remove_checkpoint(end); + g_checkpoints.remove_checkpoint(chk); P_RemoveMobj(chk->orb()); P_RemoveMobj(chk->arm()); } @@ -575,20 +562,20 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe { LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius); - auto it = find_if( + auto it = std::find_if( g_checkpoints.begin(), g_checkpoints.end(), - [&](auto chkpair) + [&](Checkpoint* chk) { - Checkpoint* chk = chkpair.first; if (!chk->valid()) { return false; } LineOnDemand* gate; + const std::vector* lines = g_checkpoints.lines_for(chk); - if (chkpair.second.empty()) + if (!lines || lines->empty()) { LineOnDemand dyngate = chk->crossing_line(); if (!ray.overlaps(dyngate)) @@ -598,15 +585,15 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe else { auto it = find_if( - chkpair.second.begin(), - chkpair.second.end(), + lines->begin(), + lines->end(), [&](const line_t* line) { return ray.overlaps(*line); } ); - if (it == chkpair.second.end()) + if (it == lines->end()) { return false; } @@ -640,7 +627,7 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe return; } - Checkpoint* chk = it->first; + Checkpoint* chk = *it; if (player->checkpointId == chk->id()) { @@ -657,9 +644,8 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe if (gametyperules & GTR_CHECKPOINTS) { - for (auto chkpair : g_checkpoints) + for (Checkpoint* chk : g_checkpoints) { - Checkpoint* chk = chkpair.first; if (chk->valid()) { chk->untwirl(); @@ -741,13 +727,12 @@ void Obj_ClearCheckpoints() void Obj_DeactivateCheckpoints() { - for (auto chkpair : g_checkpoints) + for (Checkpoint* chk : g_checkpoints) { - Checkpoint* chk = chkpair.first; if (chk->valid()) { chk->untwirl(); chk->other()->untwirl(); } } -} \ No newline at end of file +}