From 02bacc9a6f51e820f234a55719d623fbec0687dc Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 10:37:31 -0800 Subject: [PATCH] Battle UFOs, Checkpoints: use srb2::MobjList instead of standard containers - Net synced; new mechanism in p_link.cpp to automatically manage mobj pointers at the global scope --- src/CMakeLists.txt | 1 + src/k_battle.c | 2 +- src/k_objects.h | 4 +-- src/objects/battle-ufo.cpp | 73 +++++++++++++------------------------- src/objects/checkpoint.cpp | 34 ++++++++---------- src/p_link.cpp | 49 +++++++++++++++++++++++++ src/p_link.h | 27 ++++++++++++++ src/p_saveg.c | 28 +++++++++++++++ src/p_tick.c | 4 +-- 9 files changed, 149 insertions(+), 73 deletions(-) create mode 100644 src/p_link.cpp create mode 100644 src/p_link.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 15512339d..59b594a04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 p_floor.c p_inter.c p_lights.c + p_link.cpp p_loop.c p_map.c p_mapthing.cpp diff --git a/src/k_battle.c b/src/k_battle.c index ee6bb180a..5fc1dc9e5 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -821,7 +821,7 @@ void K_BattleInit(boolean singleplayercontext) } g_battleufo.due = starttime; - g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID(); + g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1; } UINT8 K_Bumpers(player_t *player) diff --git a/src/k_objects.h b/src/k_objects.h index 215b4b84f..2d1b01c7c 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -184,8 +184,7 @@ void Obj_BattleUFODeath(mobj_t *ufo); void Obj_LinkBattleUFOSpawner(mobj_t *spawner); void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner); void Obj_SpawnBattleUFOFromSpawner(void); -INT32 Obj_GetFirstBattleUFOSpawnerID(void); -void Obj_ResetUFOSpawners(void); +INT32 Obj_RandomBattleUFOSpawnerID(void); void Obj_BattleUFOBeamThink(mobj_t *beam); /* Power-Up Aura */ @@ -230,7 +229,6 @@ void Obj_FakeShadowThink(mobj_t *shadow); boolean Obj_FakeShadowZ(const mobj_t *shadow, fixed_t *return_z, pslope_t **return_slope); /* Checkpoints */ -void Obj_ResetCheckpoints(void); void Obj_LinkCheckpoint(mobj_t *end); void Obj_UnlinkCheckpoint(mobj_t *end); void Obj_CheckpointThink(mobj_t *end); diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 5909c335e..7cc9873d9 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -1,9 +1,10 @@ #include +#include #include -#include #include "../math/fixed.hpp" #include "../mobj.hpp" +#include "../mobj_list.hpp" #include "../doomdef.h" #include "../m_random.h" @@ -14,6 +15,9 @@ using srb2::math::Fixed; using srb2::Mobj; +using srb2::MobjList; + +extern mobj_t* svg_battleUfoSpawners; #define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body #define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn @@ -27,6 +31,10 @@ struct Spawner : Mobj { void thing_args() = delete; INT32 id() const { return this->mobj_t::thing_args[0]; } + + void hnext() = delete; + Spawner* next() const { return Mobj::hnext(); } + void next(Spawner* n) { Mobj::hnext(n); } }; struct UFO : Mobj @@ -53,69 +61,43 @@ struct UFO : Mobj } }; -struct SpawnerCompare -{ - bool operator()(const Spawner* a, const Spawner* b) const - { - return a->id() < b->id(); - } -}; - class SpawnerList { private: - std::set set_; + MobjList list_; public: - void insert(Spawner* spawner) - { - auto [it, inserted] = set_.insert(spawner); - - if (inserted) - { - mobj_t* dummy = nullptr; - P_SetTarget(&dummy, spawner); - } - } - - void erase(Spawner* spawner) - { - if (set_.erase(spawner)) - { - mobj_t* dummy = spawner; - P_SetTarget(&dummy, nullptr); - } - } + void insert(Spawner* spawner) { list_.push_front(spawner); } + void erase(Spawner* spawner) { list_.erase(spawner); } Spawner* next(INT32 order) const { - auto it = std::upper_bound( - set_.begin(), - set_.end(), - order, - [](INT32 a, const Spawner* b) { return a < b->id(); } - ); + using T = const Spawner*; - return it != set_.end() ? *it : *set_.begin(); + auto it = std::find_if(list_.begin(), list_.end(), [order](T p) { return order < p->id(); }); + auto min = [&](auto cmp) { return std::min_element(list_.begin(), list_.end(), cmp); }; + + return *(it != list_.end() + ? min([order](T a, T b) { return order < a->id() && a->id() < b->id(); }) + : min([](T a, T b) { return a->id() < b->id(); })); } INT32 random_id() const { - if (set_.empty()) + if (list_.empty()) { return 0; } - auto it = set_.begin(); + auto it = list_.begin(); + std::size_t count = std::distance(it, list_.end()); - std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size())); - - return (*std::prev(it == set_.begin() ? set_.end() : it))->id(); + return std::next(it, P_RandomKey(PR_BATTLEUFO, count - 1u))->id(); } void spawn_ufo() const { - if (set_.empty()) + if (list_.empty()) { return; } @@ -236,16 +218,11 @@ void Obj_SpawnBattleUFOFromSpawner(void) g_spawners.spawn_ufo(); } -INT32 Obj_GetFirstBattleUFOSpawnerID(void) +INT32 Obj_RandomBattleUFOSpawnerID(void) { return g_spawners.random_id(); } -void Obj_ResetUFOSpawners(void) -{ - g_spawners = {}; -} - void Obj_BattleUFOBeamThink(mobj_t *beam) { P_SetObjectMomZ(beam, beam->info->speed, true); diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 903dcd349..361f22cc2 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -8,10 +8,11 @@ //----------------------------------------------------------------------------- #include -#include #include +#include "../mobj_list.hpp" + #include "../doomdef.h" #include "../doomtype.h" #include "../info.h" @@ -32,10 +33,13 @@ #include "../sounds.h" #include "../tables.h" +extern mobj_t* svg_checkpoints; + #define checkpoint_id(o) ((o)->thing_args[0]) #define checkpoint_other(o) ((o)->target) #define checkpoint_orb(o) ((o)->tracer) #define checkpoint_arm(o) ((o)->hnext) +#define checkpoint_next(o) ((o)->hprev) #define checkpoint_var(o) ((o)->movedir) #define checkpoint_speed(o) ((o)->movecount) #define checkpoint_speed_multiplier(o) ((o)->movefactor) @@ -120,6 +124,9 @@ struct Checkpoint : mobj_t Arm* arm() const { return static_cast(checkpoint_arm(this)); } void arm(Arm* n) { P_SetTarget(&checkpoint_arm(this), n); } + Checkpoint* next() const { return static_cast(checkpoint_next(this)); } + void next(Checkpoint* n) { P_SetTarget(&checkpoint_next(this), n); } + fixed_t var() const { return checkpoint_var(this); } void var(fixed_t n) { checkpoint_var(this) = n; } @@ -391,34 +398,23 @@ private: struct CheckpointManager { - auto begin() { return vec_.begin(); } - auto end() { return vec_.end(); } + auto begin() { return list_.begin(); } + auto end() { return list_.end(); } auto find(INT32 id) { return std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); } - void push_back(Checkpoint* chk) { vec_.push_back(chk); } + void push_front(Checkpoint* chk) { list_.push_front(chk); } - void erase(const Checkpoint* chk) - { - if (auto it = std::find(vec_.begin(), vec_.end(), chk); it != end()) - { - vec_.erase(it); - } - } + void erase(Checkpoint* chk) { list_.erase(chk); } private: - std::vector vec_; + srb2::MobjList list_; }; CheckpointManager g_checkpoints; }; // namespace -void Obj_ResetCheckpoints(void) -{ - g_checkpoints = {}; -} - void Obj_LinkCheckpoint(mobj_t* end) { auto chk = static_cast(end); @@ -456,7 +452,7 @@ void Obj_LinkCheckpoint(mobj_t* end) } else { - g_checkpoints.push_back(chk); + g_checkpoints.push_front(chk); } chk->gingerbread(); @@ -464,7 +460,7 @@ void Obj_LinkCheckpoint(mobj_t* end) void Obj_UnlinkCheckpoint(mobj_t* end) { - auto chk = static_cast(end); + auto chk = static_cast(end); g_checkpoints.erase(chk); diff --git a/src/p_link.cpp b/src/p_link.cpp new file mode 100644 index 000000000..1bef20bc4 --- /dev/null +++ b/src/p_link.cpp @@ -0,0 +1,49 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include +#include + +#include "p_link.h" +#include "p_mobj.h" + + +#define LINK_PACK \ + svg_battleUfoSpawners,\ + svg_checkpoints + + +using link = mobj_t*; +using each_ref = std::initializer_list>; + +link LINK_PACK; + +void P_InitMobjPointers(void) +{ + for (mobj_t*& head : each_ref {LINK_PACK}) + { + head = nullptr; + } +} + +void P_SaveMobjPointers(void(*fn)(mobj_t*)) +{ + for (mobj_t* head : {LINK_PACK}) + { + fn(head); + } +} + +void P_LoadMobjPointers(void(*fn)(mobj_t**)) +{ + for (mobj_t*& head : each_ref {LINK_PACK}) + { + fn(&head); + } +} diff --git a/src/p_link.h b/src/p_link.h new file mode 100644 index 000000000..5baa82556 --- /dev/null +++ b/src/p_link.h @@ -0,0 +1,27 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef p_link_h +#define p_link_h + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void P_InitMobjPointers(void); +void P_SaveMobjPointers(void(*callback)(mobj_t*)); +void P_LoadMobjPointers(void(*callback)(mobj_t**)); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif/*p_link_h*/ diff --git a/src/p_saveg.c b/src/p_saveg.c index 591bd628c..30b0a8df2 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -36,6 +36,7 @@ #include "lua_script.h" #include "p_slopes.h" #include "m_cond.h" // netUnlocked +#include "p_link.h" // SRB2Kart #include "k_grandprix.h" @@ -50,6 +51,8 @@ savedata_t savedata; savedata_cup_t cupsavedata; +static savebuffer_t *current_savebuffer; + // Block UINT32s to attempt to ensure that the correct data is // being sent and received #define ARCHIVEBLOCK_MISC 0x7FEEDEED @@ -3839,6 +3842,11 @@ static void SavePolyfadeThinker(savebuffer_t *save, const thinker_t *th, const U WRITEINT32(save->p, ht->timer); } +static void WriteMobjPointer(mobj_t *mobj) +{ + WRITEUINT32(current_savebuffer->p, SaveMobjnum(mobj)); +} + static void P_NetArchiveThinkers(savebuffer_t *save) { const thinker_t *th; @@ -3846,6 +3854,8 @@ static void P_NetArchiveThinkers(savebuffer_t *save) WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS); + P_SaveMobjPointers(WriteMobjPointer); + for (i = 0; i < NUM_THINKERLISTS; i++) { UINT32 numsaved = 0; @@ -5238,6 +5248,11 @@ static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker) return &ht->thinker; } +static void ReadMobjPointer(mobj_t **mobj_p) +{ + *mobj_p = LoadMobj(READUINT32(current_savebuffer->p)); +} + static void P_NetUnArchiveThinkers(savebuffer_t *save) { thinker_t *currentthinker; @@ -5273,6 +5288,8 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save) // we don't want the removed mobjs to come back P_InitThinkers(); + P_LoadMobjPointers(ReadMobjPointer); + // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity for (i = 0; i < numsectors; i++) { @@ -5583,12 +5600,19 @@ static mobj_t *RelinkMobj(mobj_t **ptr) return P_SetTarget(ptr, P_FindNewPosition(temp)); } +static void RelinkMobjVoid(mobj_t **ptr) +{ + RelinkMobj(ptr); +} + static void P_RelinkPointers(void) { thinker_t *currentthinker; mobj_t *mobj; UINT32 temp, i; + P_LoadMobjPointers(RelinkMobjVoid); + // use info field (value = oldposition) to relink mobjs for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ]; currentthinker = currentthinker->next) @@ -6648,6 +6672,8 @@ void P_SaveGame(savebuffer_t *save) void P_SaveNetGame(savebuffer_t *save, boolean resending) { + current_savebuffer = save; + thinker_t *th; mobj_t *mobj; UINT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise @@ -6724,6 +6750,8 @@ badloadgame: boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) { + current_savebuffer = save; + CV_LoadNetVars(&save->p); if (!P_NetUnArchiveMisc(save, reloading)) diff --git a/src/p_tick.c b/src/p_tick.c index c61fed92f..48738ac16 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -29,6 +29,7 @@ #include "r_main.h" #include "r_fps.h" #include "d_clisrv.h" // UpdateChallenges +#include "p_link.h" // Object place #include "m_cheat.h" @@ -299,8 +300,7 @@ void P_InitThinkers(void) skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL; } - Obj_ResetUFOSpawners(); - Obj_ResetCheckpoints(); + P_InitMobjPointers(); } //