From df5d1e5fb533c739ca53d919b16fae1c07e57a46 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 09:51:22 -0800 Subject: [PATCH 01/11] srb2::MobjListView: relax constraint so basic mobj_t is allowed --- src/mobj_list_view.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mobj_list_view.hpp b/src/mobj_list_view.hpp index 638e7d952..a9b69f681 100644 --- a/src/mobj_list_view.hpp +++ b/src/mobj_list_view.hpp @@ -14,15 +14,17 @@ #include #include -#include "mobj.hpp" +#include "p_mobj.h" namespace srb2 { // for (T* ptr : MobjList(hnext(), [](T* ptr) { return ptr->hnext(); })) -template , bool> = true> +template struct MobjListView { + static_assert(std::is_convertible_v); + struct Iterator { using iterator_category = std::forward_iterator_tag; From a211ae73fe00262a6c23ff2103f3cab4206e4cda Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 09:53:08 -0800 Subject: [PATCH 02/11] srb2::MobjListView: fix arrow operator --- src/mobj_list_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mobj_list_view.hpp b/src/mobj_list_view.hpp index a9b69f681..246dbd8ba 100644 --- a/src/mobj_list_view.hpp +++ b/src/mobj_list_view.hpp @@ -39,7 +39,7 @@ struct MobjListView bool operator!=(const Iterator& b) const { return ptr_ != b.ptr_; }; reference operator*() const { return ptr_; } - pointer operator->() { return &ptr_; } + pointer operator->() { return ptr_; } Iterator& operator++() { From aba94d205bf30554ea9f6ce784ecfce6c38f9df3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 09:53:35 -0800 Subject: [PATCH 03/11] srb2::MobjListView: support copy assignment --- src/mobj_list_view.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mobj_list_view.hpp b/src/mobj_list_view.hpp index 246dbd8ba..fd804c55e 100644 --- a/src/mobj_list_view.hpp +++ b/src/mobj_list_view.hpp @@ -34,6 +34,14 @@ struct MobjListView using reference = value_type; Iterator(pointer ptr, F adv) : ptr_(deref(ptr)), adv_(adv) {} + Iterator& operator=(const Iterator& b) + { + // adv_ may be a lambda. However, lambdas are not + // copy assignable. Therefore, perform copy + // construction instead! + this->~Iterator(); + return *new(this) Iterator {b}; + } bool operator==(const Iterator& b) const { return ptr_ == b.ptr_; }; bool operator!=(const Iterator& b) const { return ptr_ != b.ptr_; }; From b5809b6ed266f7f63ce489e377e471826e3d9174 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 10:36:56 -0800 Subject: [PATCH 04/11] Add srb2::MobjList, similar to std::forward_list --- src/mobj_list.hpp | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/mobj_list.hpp diff --git a/src/mobj_list.hpp b/src/mobj_list.hpp new file mode 100644 index 000000000..ad9ac8964 --- /dev/null +++ b/src/mobj_list.hpp @@ -0,0 +1,86 @@ +// 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 mobj_list_hpp +#define mobj_list_hpp + +#include + +#include "cxxutil.hpp" +#include "mobj.hpp" +#include "mobj_list_view.hpp" + +namespace srb2 +{ + +// Requires: +// void T::next(T*) +// T* T::next() const +template +struct MobjList +{ + static_assert(std::is_convertible_v); + + MobjList() {} + + T* front() const { return static_cast(Head); } + bool empty() const { return !front(); } + + void push_front(T* ptr) + { + ptr->next(front()); + front(ptr); + } + + void erase(T* node) + { + if (front() == node) + { + front(node->next()); + node->next(nullptr); + return; + } + + auto view = this->view(); + auto end = view.end(); + auto it = view.begin(); + + SRB2_ASSERT(it != end); + + for (;;) + { + T* prev = *it; + + it++; + + if (it == end) + { + break; + } + + if (*it == node) + { + prev->next(node->next()); + node->next(nullptr); + break; + } + } + } + + auto begin() const { return view().begin(); } + auto end() const { return view().end(); } + +private: + void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; } + auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); } +}; + +}; // namespace srb2 + +#endif/*mobj_list_hpp*/ From ada9263374eeedc49913fbff638d9f95fdb40771 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 10:07:12 -0800 Subject: [PATCH 05/11] Obj_BattleUFOThink: fix exponential scaling --- src/objects/battle-ufo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 2ccbb78da..c98b72f8b 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -124,7 +124,7 @@ void Obj_BattleUFOThink(mobj_t *mobj) UFO* ufo = static_cast(mobj); // Copied and slightly modified from k_kart.c - fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = (BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)) / 4; fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo); ufo->momz = targz; From ca1bbfd53f60d0f28ba1871abd9dd9e5adf1304f Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 10:12:13 -0800 Subject: [PATCH 06/11] objects/battle-ufo.cpp: refactor to make some use of srb2::Mobj --- src/objects/battle-ufo.cpp | 39 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index c98b72f8b..5909c335e 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -2,6 +2,9 @@ #include #include +#include "../math/fixed.hpp" +#include "../mobj.hpp" + #include "../doomdef.h" #include "../m_random.h" #include "../p_local.h" @@ -9,36 +12,45 @@ #include "../k_objects.h" #include "../k_kart.h" +using srb2::math::Fixed; +using srb2::Mobj; + #define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body #define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn #define BATTLEUFO_BOB_AMP (4) // UFO bob strength #define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed -#define spawner_id(o) ((o)->thing_args[0]) - -#define ufo_spawner(o) ((o)->target) - namespace { -struct Spawner : mobj_t +struct Spawner : Mobj { - INT32 id() const { return spawner_id(this); } + void thing_args() = delete; + INT32 id() const { return this->mobj_t::thing_args[0]; } }; -struct UFO : mobj_t +struct UFO : Mobj { - Spawner* spawner() const { return static_cast(ufo_spawner(this)); } - void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); } + void target() = delete; + Spawner* spawner() const { return Mobj::target(); } + void spawner(Spawner* n) { Mobj::target(n); } + void spawn_beam() { - mobj_t *x; + Mobj *x = spawn_from({0, 0, height / 4}, MT_BATTLEUFO_BEAM); - x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM); x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE; x->colorized = true; x->color = SKINCOLOR_SAPPHIRE; } + + void bob() + { + // Copied and slightly modified from k_kart.c + Fixed sine = (BATTLEUFO_BOB_AMP * Fixed {FSIN(M_TAU_FIXED * BATTLEUFO_BOB_SPEED * leveltime)}) / 4; + + momz = flip(sine * scale()); + } }; struct SpawnerCompare @@ -123,10 +135,7 @@ void Obj_BattleUFOThink(mobj_t *mobj) { UFO* ufo = static_cast(mobj); - // Copied and slightly modified from k_kart.c - fixed_t sine = (BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)) / 4; - fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo); - ufo->momz = targz; + ufo->bob(); if ((leveltime/2) & 1) { From 39486a56d62a25515ac8cb49df7c1a9986660159 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 09:56:07 -0800 Subject: [PATCH 07/11] p_saveg.c: initialize "special" fields of mobj, if spawned from mapthing, in default state --- src/p_mobj.c | 36 +++++++++++++++++++++--------------- src/p_mobj.h | 1 + src/p_saveg.c | 4 ++++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index a21d676cb..11f804ab8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14538,24 +14538,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) return true; } -static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) +void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj) { - mobj_t *mobj = NULL; size_t arg = SIZE_MAX; - mobj = P_SpawnMobj(x, y, z, type); - mobj->spawnpoint = mthing; - - mobj->angle = FixedAngle(mthing->angle << FRACBITS); - mobj->pitch = FixedAngle(mthing->pitch << FRACBITS); - mobj->roll = FixedAngle(mthing->roll << FRACBITS); - - P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); - mobj->destscale = FixedMul(mobj->destscale, mthing->scale); - - mobj->spritexscale = mthing->spritexscale; - mobj->spriteyscale = mthing->spriteyscale; - P_SetThingTID(mobj, mthing->tid); mobj->special = mthing->special; @@ -14609,6 +14595,26 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, mobj->script_stringargs[arg] = Z_Realloc(mobj->script_stringargs[arg], len + 1, PU_LEVEL, NULL); M_Memcpy(mobj->script_stringargs[arg], mthing->script_stringargs[arg], len + 1); } +} + +static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) +{ + mobj_t *mobj = NULL; + + mobj = P_SpawnMobj(x, y, z, type); + mobj->spawnpoint = mthing; + + mobj->angle = FixedAngle(mthing->angle << FRACBITS); + mobj->pitch = FixedAngle(mthing->pitch << FRACBITS); + mobj->roll = FixedAngle(mthing->roll << FRACBITS); + + P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); + mobj->destscale = FixedMul(mobj->destscale, mthing->scale); + + mobj->spritexscale = mthing->spritexscale; + mobj->spriteyscale = mthing->spriteyscale; + + P_CopyMapThingSpecialFieldsToMobj(mthing, mobj); if (!P_SetupSpawnedMapThing(mthing, mobj)) { diff --git a/src/p_mobj.h b/src/p_mobj.h index 2570acda9..dabdafe51 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -557,6 +557,7 @@ fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const f fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y); mobj_t *P_SpawnMapThing(mapthing_t *mthing); +void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj); void P_SpawnHoop(mapthing_t *mthing); void P_SpawnItemPattern(mapthing_t *mthing); void P_SpawnItemLine(mapthing_t *mt1, mapthing_t *mt2); diff --git a/src/p_saveg.c b/src/p_saveg.c index 2f8a5d66b..9a40538ef 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4538,6 +4538,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) mobj->script_stringargs[j][len] = '\0'; } } + else if (mobj->spawnpoint) + { + P_CopyMapThingSpecialFieldsToMobj(mobj->spawnpoint, mobj); + } if (diff2 & MD2_FLOORSPRITESLOPE) { pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); From 43d090f6992bd3d27f98012ce2b136e848298da8 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 09:58:15 -0800 Subject: [PATCH 08/11] p_saveg.c: consolidate P_RelinkPointers copy-pasted code --- src/p_saveg.c | 99 ++++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 69 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 9a40538ef..591bd628c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5576,6 +5576,13 @@ static inline void P_UnArchivePolyObjects(savebuffer_t *save) P_UnArchivePolyObj(save, &PolyObjects[i]); } +static mobj_t *RelinkMobj(mobj_t **ptr) +{ + UINT32 temp = (UINT32)(size_t)*ptr; + *ptr = NULL; + return P_SetTarget(ptr, P_FindNewPosition(temp)); +} + static void P_RelinkPointers(void) { thinker_t *currentthinker; @@ -5596,37 +5603,27 @@ static void P_RelinkPointers(void) if (mobj->tracer) { - temp = (UINT32)(size_t)mobj->tracer; - mobj->tracer = NULL; - if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->tracer)) CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type); } if (mobj->target) { - temp = (UINT32)(size_t)mobj->target; - mobj->target = NULL; - if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->target)) CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type); } if (mobj->hnext) { - temp = (UINT32)(size_t)mobj->hnext; - mobj->hnext = NULL; - if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->hnext)) CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type); } if (mobj->hprev) { - temp = (UINT32)(size_t)mobj->hprev; - mobj->hprev = NULL; - if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->hprev)) CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type); } if (mobj->itnext) { - temp = (UINT32)(size_t)mobj->itnext; - mobj->itnext = NULL; - if (!P_SetTarget(&mobj->itnext, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->itnext)) CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type); } if (mobj->terrain) @@ -5640,23 +5637,17 @@ static void P_RelinkPointers(void) } if (mobj->terrainOverlay) { - temp = (UINT32)(size_t)mobj->terrainOverlay; - mobj->terrainOverlay = NULL; - if (!P_SetTarget(&mobj->terrainOverlay, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->terrainOverlay)) CONS_Debug(DBG_GAMELOGIC, "terrainOverlay not found on %d\n", mobj->type); } if (mobj->punt_ref) { - temp = (UINT32)(size_t)mobj->punt_ref; - mobj->punt_ref = NULL; - if (!P_SetTarget(&mobj->punt_ref, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->punt_ref)) CONS_Debug(DBG_GAMELOGIC, "punt_ref not found on %d\n", mobj->type); } if (mobj->owner) { - temp = (UINT32)(size_t)mobj->owner; - mobj->owner = NULL; - if (!P_SetTarget(&mobj->owner, P_FindNewPosition(temp))) + if (!RelinkMobj(&mobj->owner)) CONS_Debug(DBG_GAMELOGIC, "owner not found on %d\n", mobj->type); } } @@ -5668,37 +5659,27 @@ static void P_RelinkPointers(void) if (players[i].skybox.viewpoint) { - temp = (UINT32)(size_t)players[i].skybox.viewpoint; - players[i].skybox.viewpoint = NULL; - if (!P_SetTarget(&players[i].skybox.viewpoint, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].skybox.viewpoint)) CONS_Debug(DBG_GAMELOGIC, "skybox.viewpoint not found on player %d\n", i); } if (players[i].skybox.centerpoint) { - temp = (UINT32)(size_t)players[i].skybox.centerpoint; - players[i].skybox.centerpoint = NULL; - if (!P_SetTarget(&players[i].skybox.centerpoint, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].skybox.centerpoint)) CONS_Debug(DBG_GAMELOGIC, "skybox.centerpoint not found on player %d\n", i); } if (players[i].awayview.mobj) { - temp = (UINT32)(size_t)players[i].awayview.mobj; - players[i].awayview.mobj = NULL; - if (!P_SetTarget(&players[i].awayview.mobj, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].awayview.mobj)) CONS_Debug(DBG_GAMELOGIC, "awayview.mobj not found on player %d\n", i); } if (players[i].followmobj) { - temp = (UINT32)(size_t)players[i].followmobj; - players[i].followmobj = NULL; - if (!P_SetTarget(&players[i].followmobj, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].followmobj)) CONS_Debug(DBG_GAMELOGIC, "followmobj not found on player %d\n", i); } if (players[i].follower) { - temp = (UINT32)(size_t)players[i].follower; - players[i].follower = NULL; - if (!P_SetTarget(&players[i].follower, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].follower)) CONS_Debug(DBG_GAMELOGIC, "follower not found on player %d\n", i); } if (players[i].currentwaypoint) @@ -5730,72 +5711,52 @@ static void P_RelinkPointers(void) } if (players[i].hoverhyudoro) { - temp = (UINT32)(size_t)players[i].hoverhyudoro; - players[i].hoverhyudoro = NULL; - if (!P_SetTarget(&players[i].hoverhyudoro, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].hoverhyudoro)) CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on player %d\n", i); } if (players[i].stumbleIndicator) { - temp = (UINT32)(size_t)players[i].stumbleIndicator; - players[i].stumbleIndicator = NULL; - if (!P_SetTarget(&players[i].stumbleIndicator, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].stumbleIndicator)) CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on player %d\n", i); } if (players[i].wavedashIndicator) { - temp = (UINT32)(size_t)players[i].wavedashIndicator; - players[i].wavedashIndicator = NULL; - if (!P_SetTarget(&players[i].wavedashIndicator, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].wavedashIndicator)) CONS_Debug(DBG_GAMELOGIC, "wavedashIndicator not found on player %d\n", i); } if (players[i].trickIndicator) { - temp = (UINT32)(size_t)players[i].trickIndicator; - players[i].trickIndicator = NULL; - if (!P_SetTarget(&players[i].trickIndicator, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].trickIndicator)) CONS_Debug(DBG_GAMELOGIC, "trickIndicator not found on player %d\n", i); } if (players[i].whip) { - temp = (UINT32)(size_t)players[i].whip; - players[i].whip = NULL; - if (!P_SetTarget(&players[i].whip, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].whip)) CONS_Debug(DBG_GAMELOGIC, "whip not found on player %d\n", i); } if (players[i].hand) { - temp = (UINT32)(size_t)players[i].hand; - players[i].hand = NULL; - if (!P_SetTarget(&players[i].hand, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].hand)) CONS_Debug(DBG_GAMELOGIC, "hand not found on player %d\n", i); } if (players[i].ringShooter) { - temp = (UINT32)(size_t)players[i].ringShooter; - players[i].ringShooter = NULL; - if (!P_SetTarget(&players[i].ringShooter, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].ringShooter)) CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i); } if (players[i].flickyAttacker) { - temp = (UINT32)(size_t)players[i].flickyAttacker; - players[i].flickyAttacker = NULL; - if (!P_SetTarget(&players[i].flickyAttacker, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].flickyAttacker)) CONS_Debug(DBG_GAMELOGIC, "flickyAttacker not found on player %d\n", i); } if (players[i].powerup.flickyController) { - temp = (UINT32)(size_t)players[i].powerup.flickyController; - players[i].powerup.flickyController = NULL; - if (!P_SetTarget(&players[i].powerup.flickyController, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].powerup.flickyController)) CONS_Debug(DBG_GAMELOGIC, "powerup.flickyController not found on player %d\n", i); } if (players[i].powerup.barrier) { - temp = (UINT32)(size_t)players[i].powerup.barrier; - players[i].powerup.barrier = NULL; - if (!P_SetTarget(&players[i].powerup.barrier, P_FindNewPosition(temp))) + if (!RelinkMobj(&players[i].powerup.barrier)) CONS_Debug(DBG_GAMELOGIC, "powerup.barrier not found on player %d\n", i); } } From 02bacc9a6f51e820f234a55719d623fbec0687dc Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 10:37:31 -0800 Subject: [PATCH 09/11] 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(); } // From 5329afd23c39012fa790da545532be619073ebb7 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 3 Dec 2023 11:46:45 -0800 Subject: [PATCH 10/11] srb2::MobjListView: call P_MobjWasRemoved directly Avoid calling an overridden method --- src/mobj_list_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mobj_list_view.hpp b/src/mobj_list_view.hpp index fd804c55e..122ec6684 100644 --- a/src/mobj_list_view.hpp +++ b/src/mobj_list_view.hpp @@ -66,7 +66,7 @@ struct MobjListView pointer ptr_; F adv_; - static T* deref(T* ptr) { return ptr && ptr->valid() ? ptr : nullptr; } + static T* deref(T* ptr) { return !P_MobjWasRemoved(ptr) ? ptr : nullptr; } }; MobjListView(T* ptr, F adv) : ptr_(ptr), adv_(adv) {} From 4931f32bb86c9231935813eeb157a9a606c008df Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 6 Dec 2023 04:06:00 -0800 Subject: [PATCH 11/11] SpawnerList::random_id: avoid division by zero in PRNG function --- src/objects/battle-ufo.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/objects/battle-ufo.cpp b/src/objects/battle-ufo.cpp index 7cc9873d9..bbefa9672 100644 --- a/src/objects/battle-ufo.cpp +++ b/src/objects/battle-ufo.cpp @@ -92,7 +92,12 @@ public: auto it = list_.begin(); std::size_t count = std::distance(it, list_.end()); - return std::next(it, P_RandomKey(PR_BATTLEUFO, count - 1u))->id(); + if (count > 1u) + { + std::advance(it, P_RandomKey(PR_BATTLEUFO, count - 1u)); + } + + return it->id(); } void spawn_ufo() const