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
This commit is contained in:
James R 2023-12-03 10:37:31 -08:00
parent 43d090f699
commit 02bacc9a6f
9 changed files with 149 additions and 73 deletions

View file

@ -50,6 +50,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
p_floor.c p_floor.c
p_inter.c p_inter.c
p_lights.c p_lights.c
p_link.cpp
p_loop.c p_loop.c
p_map.c p_map.c
p_mapthing.cpp p_mapthing.cpp

View file

@ -821,7 +821,7 @@ void K_BattleInit(boolean singleplayercontext)
} }
g_battleufo.due = starttime; g_battleufo.due = starttime;
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID(); g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1;
} }
UINT8 K_Bumpers(player_t *player) UINT8 K_Bumpers(player_t *player)

View file

@ -184,8 +184,7 @@ void Obj_BattleUFODeath(mobj_t *ufo);
void Obj_LinkBattleUFOSpawner(mobj_t *spawner); void Obj_LinkBattleUFOSpawner(mobj_t *spawner);
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner); void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner);
void Obj_SpawnBattleUFOFromSpawner(void); void Obj_SpawnBattleUFOFromSpawner(void);
INT32 Obj_GetFirstBattleUFOSpawnerID(void); INT32 Obj_RandomBattleUFOSpawnerID(void);
void Obj_ResetUFOSpawners(void);
void Obj_BattleUFOBeamThink(mobj_t *beam); void Obj_BattleUFOBeamThink(mobj_t *beam);
/* Power-Up Aura */ /* 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); boolean Obj_FakeShadowZ(const mobj_t *shadow, fixed_t *return_z, pslope_t **return_slope);
/* Checkpoints */ /* Checkpoints */
void Obj_ResetCheckpoints(void);
void Obj_LinkCheckpoint(mobj_t *end); void Obj_LinkCheckpoint(mobj_t *end);
void Obj_UnlinkCheckpoint(mobj_t *end); void Obj_UnlinkCheckpoint(mobj_t *end);
void Obj_CheckpointThink(mobj_t *end); void Obj_CheckpointThink(mobj_t *end);

View file

@ -1,9 +1,10 @@
#include <algorithm> #include <algorithm>
#include <cstddef>
#include <iterator> #include <iterator>
#include <set>
#include "../math/fixed.hpp" #include "../math/fixed.hpp"
#include "../mobj.hpp" #include "../mobj.hpp"
#include "../mobj_list.hpp"
#include "../doomdef.h" #include "../doomdef.h"
#include "../m_random.h" #include "../m_random.h"
@ -14,6 +15,9 @@
using srb2::math::Fixed; using srb2::math::Fixed;
using srb2::Mobj; 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_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body
#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn #define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn
@ -27,6 +31,10 @@ struct Spawner : Mobj
{ {
void thing_args() = delete; void thing_args() = delete;
INT32 id() const { return this->mobj_t::thing_args[0]; } INT32 id() const { return this->mobj_t::thing_args[0]; }
void hnext() = delete;
Spawner* next() const { return Mobj::hnext<Spawner>(); }
void next(Spawner* n) { Mobj::hnext(n); }
}; };
struct UFO : Mobj 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 class SpawnerList
{ {
private: private:
std::set<Spawner*, SpawnerCompare> set_; MobjList<Spawner, svg_battleUfoSpawners> list_;
public: public:
void insert(Spawner* spawner) void insert(Spawner* spawner) { list_.push_front(spawner); }
{ void erase(Spawner* spawner) { list_.erase(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);
}
}
Spawner* next(INT32 order) const Spawner* next(INT32 order) const
{ {
auto it = std::upper_bound( using T = const Spawner*;
set_.begin(),
set_.end(),
order,
[](INT32 a, const Spawner* b) { return a < b->id(); }
);
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 INT32 random_id() const
{ {
if (set_.empty()) if (list_.empty())
{ {
return 0; 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::next(it, P_RandomKey(PR_BATTLEUFO, count - 1u))->id();
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
} }
void spawn_ufo() const void spawn_ufo() const
{ {
if (set_.empty()) if (list_.empty())
{ {
return; return;
} }
@ -236,16 +218,11 @@ void Obj_SpawnBattleUFOFromSpawner(void)
g_spawners.spawn_ufo(); g_spawners.spawn_ufo();
} }
INT32 Obj_GetFirstBattleUFOSpawnerID(void) INT32 Obj_RandomBattleUFOSpawnerID(void)
{ {
return g_spawners.random_id(); return g_spawners.random_id();
} }
void Obj_ResetUFOSpawners(void)
{
g_spawners = {};
}
void Obj_BattleUFOBeamThink(mobj_t *beam) void Obj_BattleUFOBeamThink(mobj_t *beam)
{ {
P_SetObjectMomZ(beam, beam->info->speed, true); P_SetObjectMomZ(beam, beam->info->speed, true);

View file

@ -8,10 +8,11 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <algorithm> #include <algorithm>
#include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include "../mobj_list.hpp"
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomtype.h" #include "../doomtype.h"
#include "../info.h" #include "../info.h"
@ -32,10 +33,13 @@
#include "../sounds.h" #include "../sounds.h"
#include "../tables.h" #include "../tables.h"
extern mobj_t* svg_checkpoints;
#define checkpoint_id(o) ((o)->thing_args[0]) #define checkpoint_id(o) ((o)->thing_args[0])
#define checkpoint_other(o) ((o)->target) #define checkpoint_other(o) ((o)->target)
#define checkpoint_orb(o) ((o)->tracer) #define checkpoint_orb(o) ((o)->tracer)
#define checkpoint_arm(o) ((o)->hnext) #define checkpoint_arm(o) ((o)->hnext)
#define checkpoint_next(o) ((o)->hprev)
#define checkpoint_var(o) ((o)->movedir) #define checkpoint_var(o) ((o)->movedir)
#define checkpoint_speed(o) ((o)->movecount) #define checkpoint_speed(o) ((o)->movecount)
#define checkpoint_speed_multiplier(o) ((o)->movefactor) #define checkpoint_speed_multiplier(o) ((o)->movefactor)
@ -120,6 +124,9 @@ struct Checkpoint : mobj_t
Arm* arm() const { return static_cast<Arm*>(checkpoint_arm(this)); } Arm* arm() const { return static_cast<Arm*>(checkpoint_arm(this)); }
void arm(Arm* n) { P_SetTarget(&checkpoint_arm(this), n); } void arm(Arm* n) { P_SetTarget(&checkpoint_arm(this), n); }
Checkpoint* next() const { return static_cast<Checkpoint*>(checkpoint_next(this)); }
void next(Checkpoint* n) { P_SetTarget(&checkpoint_next(this), n); }
fixed_t var() const { return checkpoint_var(this); } fixed_t var() const { return checkpoint_var(this); }
void var(fixed_t n) { checkpoint_var(this) = n; } void var(fixed_t n) { checkpoint_var(this) = n; }
@ -391,34 +398,23 @@ private:
struct CheckpointManager struct CheckpointManager
{ {
auto begin() { return vec_.begin(); } auto begin() { return list_.begin(); }
auto end() { return vec_.end(); } auto end() { return list_.end(); }
auto find(INT32 id) { return std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); } 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) void erase(Checkpoint* chk) { list_.erase(chk); }
{
if (auto it = std::find(vec_.begin(), vec_.end(), chk); it != end())
{
vec_.erase(it);
}
}
private: private:
std::vector<Checkpoint*> vec_; srb2::MobjList<Checkpoint, svg_checkpoints> list_;
}; };
CheckpointManager g_checkpoints; CheckpointManager g_checkpoints;
}; // namespace }; // namespace
void Obj_ResetCheckpoints(void)
{
g_checkpoints = {};
}
void Obj_LinkCheckpoint(mobj_t* end) void Obj_LinkCheckpoint(mobj_t* end)
{ {
auto chk = static_cast<Checkpoint*>(end); auto chk = static_cast<Checkpoint*>(end);
@ -456,7 +452,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
} }
else else
{ {
g_checkpoints.push_back(chk); g_checkpoints.push_front(chk);
} }
chk->gingerbread(); chk->gingerbread();
@ -464,7 +460,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
void Obj_UnlinkCheckpoint(mobj_t* end) void Obj_UnlinkCheckpoint(mobj_t* end)
{ {
auto chk = static_cast<const Checkpoint*>(end); auto chk = static_cast<Checkpoint*>(end);
g_checkpoints.erase(chk); g_checkpoints.erase(chk);

49
src/p_link.cpp Normal file
View file

@ -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 <functional>
#include <initializer_list>
#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<std::reference_wrapper<mobj_t*>>;
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);
}
}

27
src/p_link.h Normal file
View file

@ -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*/

View file

@ -36,6 +36,7 @@
#include "lua_script.h" #include "lua_script.h"
#include "p_slopes.h" #include "p_slopes.h"
#include "m_cond.h" // netUnlocked #include "m_cond.h" // netUnlocked
#include "p_link.h"
// SRB2Kart // SRB2Kart
#include "k_grandprix.h" #include "k_grandprix.h"
@ -50,6 +51,8 @@
savedata_t savedata; savedata_t savedata;
savedata_cup_t cupsavedata; savedata_cup_t cupsavedata;
static savebuffer_t *current_savebuffer;
// Block UINT32s to attempt to ensure that the correct data is // Block UINT32s to attempt to ensure that the correct data is
// being sent and received // being sent and received
#define ARCHIVEBLOCK_MISC 0x7FEEDEED #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); WRITEINT32(save->p, ht->timer);
} }
static void WriteMobjPointer(mobj_t *mobj)
{
WRITEUINT32(current_savebuffer->p, SaveMobjnum(mobj));
}
static void P_NetArchiveThinkers(savebuffer_t *save) static void P_NetArchiveThinkers(savebuffer_t *save)
{ {
const thinker_t *th; const thinker_t *th;
@ -3846,6 +3854,8 @@ static void P_NetArchiveThinkers(savebuffer_t *save)
WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS); WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS);
P_SaveMobjPointers(WriteMobjPointer);
for (i = 0; i < NUM_THINKERLISTS; i++) for (i = 0; i < NUM_THINKERLISTS; i++)
{ {
UINT32 numsaved = 0; UINT32 numsaved = 0;
@ -5238,6 +5248,11 @@ static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker)
return &ht->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) static void P_NetUnArchiveThinkers(savebuffer_t *save)
{ {
thinker_t *currentthinker; thinker_t *currentthinker;
@ -5273,6 +5288,8 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
// we don't want the removed mobjs to come back // we don't want the removed mobjs to come back
P_InitThinkers(); P_InitThinkers();
P_LoadMobjPointers(ReadMobjPointer);
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
for (i = 0; i < numsectors; i++) for (i = 0; i < numsectors; i++)
{ {
@ -5583,12 +5600,19 @@ static mobj_t *RelinkMobj(mobj_t **ptr)
return P_SetTarget(ptr, P_FindNewPosition(temp)); return P_SetTarget(ptr, P_FindNewPosition(temp));
} }
static void RelinkMobjVoid(mobj_t **ptr)
{
RelinkMobj(ptr);
}
static void P_RelinkPointers(void) static void P_RelinkPointers(void)
{ {
thinker_t *currentthinker; thinker_t *currentthinker;
mobj_t *mobj; mobj_t *mobj;
UINT32 temp, i; UINT32 temp, i;
P_LoadMobjPointers(RelinkMobjVoid);
// use info field (value = oldposition) to relink mobjs // use info field (value = oldposition) to relink mobjs
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ]; for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
currentthinker = currentthinker->next) currentthinker = currentthinker->next)
@ -6648,6 +6672,8 @@ void P_SaveGame(savebuffer_t *save)
void P_SaveNetGame(savebuffer_t *save, boolean resending) void P_SaveNetGame(savebuffer_t *save, boolean resending)
{ {
current_savebuffer = save;
thinker_t *th; thinker_t *th;
mobj_t *mobj; mobj_t *mobj;
UINT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise 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) boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
{ {
current_savebuffer = save;
CV_LoadNetVars(&save->p); CV_LoadNetVars(&save->p);
if (!P_NetUnArchiveMisc(save, reloading)) if (!P_NetUnArchiveMisc(save, reloading))

View file

@ -29,6 +29,7 @@
#include "r_main.h" #include "r_main.h"
#include "r_fps.h" #include "r_fps.h"
#include "d_clisrv.h" // UpdateChallenges #include "d_clisrv.h" // UpdateChallenges
#include "p_link.h"
// Object place // Object place
#include "m_cheat.h" #include "m_cheat.h"
@ -299,8 +300,7 @@ void P_InitThinkers(void)
skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL; skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL;
} }
Obj_ResetUFOSpawners(); P_InitMobjPointers();
Obj_ResetCheckpoints();
} }
// //