Merge branch 'fix-ufo-desync' into 'master'

Fix Battle UFO desync if midgame joins + UFO bobbing speed fix

Closes #783

See merge request KartKrew/Kart!1671
This commit is contained in:
James R. 2023-12-08 03:27:42 +00:00
commit 3c9f4fe3b5
13 changed files with 330 additions and 172 deletions

View file

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

View file

@ -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)

View file

@ -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);

86
src/mobj_list.hpp Normal file
View file

@ -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 <type_traits>
#include "cxxutil.hpp"
#include "mobj.hpp"
#include "mobj_list_view.hpp"
namespace srb2
{
// Requires:
// void T::next(T*)
// T* T::next() const
template <typename T, mobj_t*& Head>
struct MobjList
{
static_assert(std::is_convertible_v<T, mobj_t>);
MobjList() {}
T* front() const { return static_cast<T*>(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*/

View file

@ -14,15 +14,17 @@
#include <iterator>
#include <type_traits>
#include "mobj.hpp"
#include "p_mobj.h"
namespace srb2
{
// for (T* ptr : MobjList(hnext(), [](T* ptr) { return ptr->hnext(); }))
template <typename T, typename F, std::enable_if_t<std::is_convertible_v<T, Mobj>, bool> = true>
template <typename T, typename F>
struct MobjListView
{
static_assert(std::is_convertible_v<T, mobj_t>);
struct Iterator
{
using iterator_category = std::forward_iterator_tag;
@ -32,12 +34,20 @@ 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_; };
reference operator*() const { return ptr_; }
pointer operator->() { return &ptr_; }
pointer operator->() { return ptr_; }
Iterator& operator++()
{
@ -56,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) {}

View file

@ -1,6 +1,10 @@
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <set>
#include "../math/fixed.hpp"
#include "../mobj.hpp"
#include "../mobj_list.hpp"
#include "../doomdef.h"
#include "../m_random.h"
@ -9,101 +13,96 @@
#include "../k_objects.h"
#include "../k_kart.h"
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
#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]; }
void hnext() = delete;
Spawner* next() const { return Mobj::hnext<Spawner>(); }
void next(Spawner* n) { Mobj::hnext(n); }
};
struct UFO : mobj_t
struct UFO : Mobj
{
Spawner* spawner() const { return static_cast<Spawner*>(ufo_spawner(this)); }
void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); }
void target() = delete;
Spawner* spawner() const { return Mobj::target<Spawner>(); }
void spawner(Spawner* n) { Mobj::target(n); }
void spawn_beam()
{
mobj_t *x;
Mobj *x = spawn_from<Mobj>({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;
}
};
struct SpawnerCompare
{
bool operator()(const Spawner* a, const Spawner* b) const
void bob()
{
return a->id() < b->id();
// 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());
}
};
class SpawnerList
{
private:
std::set<Spawner*, SpawnerCompare> set_;
MobjList<Spawner, svg_battleUfoSpawners> 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()));
if (count > 1u)
{
std::advance(it, P_RandomKey(PR_BATTLEUFO, count - 1u));
}
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
return it->id();
}
void spawn_ufo() const
{
if (set_.empty())
if (list_.empty())
{
return;
}
@ -123,10 +122,7 @@ void Obj_BattleUFOThink(mobj_t *mobj)
{
UFO* ufo = static_cast<UFO*>(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 targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo);
ufo->momz = targz;
ufo->bob();
if ((leveltime/2) & 1)
{
@ -227,16 +223,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);

View file

@ -8,10 +8,11 @@
//-----------------------------------------------------------------------------
#include <algorithm>
#include <vector>
#include <fmt/format.h>
#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<Arm*>(checkpoint_arm(this)); }
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); }
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<Checkpoint*> vec_;
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
};
CheckpointManager g_checkpoints;
}; // namespace
void Obj_ResetCheckpoints(void)
{
g_checkpoints = {};
}
void Obj_LinkCheckpoint(mobj_t* end)
{
auto chk = static_cast<Checkpoint*>(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<const Checkpoint*>(end);
auto chk = static_cast<Checkpoint*>(end);
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

@ -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))
{

View file

@ -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);

View file

@ -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;
@ -4538,6 +4548,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);
@ -5234,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;
@ -5269,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++)
{
@ -5572,12 +5593,26 @@ 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 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)
@ -5592,37 +5627,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)
@ -5636,23 +5661,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);
}
}
@ -5664,37 +5683,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)
@ -5726,72 +5735,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);
}
}
@ -6683,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
@ -6759,6 +6750,8 @@ badloadgame:
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
{
current_savebuffer = save;
CV_LoadNetVars(&save->p);
if (!P_NetUnArchiveMisc(save, reloading))

View file

@ -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();
}
//