Add level pool allocator and use it for mobj, precip, thinkers

This should substantially reduce the number of malloc/free calls made to
create and destroy mobjs, especially during level load and net
save/load.

memory_resource standard header is not available on the OSX deployment
target we are using, so I had to write my own fixed size pool allocator.
This commit is contained in:
Eidolon 2024-10-21 09:34:09 -05:00
parent 9c2e4a350a
commit cdd3bad813
16 changed files with 493 additions and 124 deletions

View file

@ -10,11 +10,13 @@
#include "memory.h"
#include <array>
#include <new>
#include <cstdint>
#include "../cxxutil.hpp"
#include "../z_zone.h"
using namespace srb2;
namespace
{
@ -58,6 +60,81 @@ void LinearMemory::reset() noexcept
} // namespace
PoolAllocator::~PoolAllocator()
{
release();
}
constexpr static size_t nearest_multiple(size_t v, size_t divisor)
{
return (v + (divisor - 1)) & ~(divisor - 1);
}
PoolAllocator::ChunkFooter* PoolAllocator::allocate_chunk()
{
uint8_t* chunk = (uint8_t*)Z_Malloc(nearest_multiple(blocks_ * block_size_, alignof(ChunkFooter)) + sizeof(ChunkFooter), tag_, nullptr);
ChunkFooter* footer = (ChunkFooter*)(chunk + (blocks_ * block_size_));
footer->next = nullptr;
footer->start = (void*)chunk;
for (size_t i = 0; i < blocks_; i++)
{
FreeBlock* cur = (FreeBlock*)(chunk + (i * block_size_));
FreeBlock* next = (FreeBlock*)(chunk + ((i + 1) * block_size_));
cur->next = next;
}
((FreeBlock*)(chunk + ((blocks_ - 1) * block_size_)))->next = nullptr;
return footer;
}
void* PoolAllocator::allocate()
{
if (first_chunk_ == nullptr)
{
SRB2_ASSERT(head_ == nullptr);
// No chunks allocated yet
first_chunk_ = allocate_chunk();
head_ = (FreeBlock*)first_chunk_->start;
}
if (head_->next == nullptr)
{
// Current chunk will be full; allocate another at the end of the list
ChunkFooter* last_chunk = first_chunk_;
while (last_chunk->next != nullptr)
{
last_chunk = last_chunk->next;
}
ChunkFooter* new_chunk = allocate_chunk();
last_chunk->next = new_chunk;
head_->next = (FreeBlock*)new_chunk->start;
}
FreeBlock* ret = head_;
head_ = head_->next;
return ret;
}
void PoolAllocator::deallocate(void* p)
{
FreeBlock* block = reinterpret_cast<FreeBlock*>(p);
block->next = head_;
head_ = block;
}
void PoolAllocator::release()
{
ChunkFooter* next = nullptr;
for (ChunkFooter* i = first_chunk_; i != nullptr; i = next)
{
next = i->next;
Z_Free(i->start);
}
first_chunk_ = nullptr;
head_ = nullptr;
}
static LinearMemory g_frame_memory {4 * 1024 * 1024};
void* Z_Frame_Alloc(size_t size)

View file

@ -14,6 +14,58 @@
#include <stddef.h>
#ifdef __cplusplus
#include <cstdint>
namespace srb2
{
/// Pool allocator; manages bulk allocations of same-size block. If the pool is full,
/// allocations will fail by returning nullptr.
class PoolAllocator final
{
struct FreeBlock
{
FreeBlock* next;
};
struct ChunkFooter
{
ChunkFooter* next;
void* start;
};
ChunkFooter* first_chunk_;
FreeBlock* head_;
size_t block_size_;
size_t blocks_;
int32_t tag_;
ChunkFooter* allocate_chunk();
public:
constexpr PoolAllocator(size_t block_size, size_t blocks, int32_t tag)
: first_chunk_(nullptr)
, head_(nullptr)
, block_size_(block_size)
, blocks_(blocks)
, tag_(tag)
{}
PoolAllocator(const PoolAllocator&) = delete;
PoolAllocator(PoolAllocator&&) noexcept = default;
~PoolAllocator();
PoolAllocator& operator=(const PoolAllocator&) = delete;
PoolAllocator& operator=(PoolAllocator&&) noexcept = default;
void* allocate();
void deallocate(void* p);
constexpr size_t block_size() const noexcept { return block_size_; };
void release();
};
} // namespace srb2
extern "C" {
#endif // __cpluspplus

View file

@ -38,6 +38,15 @@ typedef union
actionf_p1 acp1;
} actionf_t;
typedef enum
{
/// The allocation is standard e.g. Z_Malloc
TAT_MALLOC,
/// The allocation is in the pool allocator (e.g. Z_LevelPoolCalloc)
TAT_LEVELPOOL
} thinker_alloc_type_e;
// Historically, "think_t" is yet another function pointer to a routine
// to handle an actor.
typedef actionf_t think_t;
@ -52,7 +61,8 @@ struct thinker_t
// killough 11/98: count of how many other objects reference
// this one using pointers. Used for garbage collection.
INT32 references;
boolean cachable;
INT32 alloctype;
size_t size;
#ifdef PARANOIA
INT32 debug_mobjtype;

View file

@ -12,6 +12,7 @@
/// \file p_ceilng.c
/// \brief Ceiling aninmation (lowering, crushing, raising)
#include "d_think.h"
#include "doomdef.h"
#include "p_local.h"
#include "r_fps.h"
@ -273,7 +274,9 @@ static ceiling_t *CreateCeilingThinker(sector_t *sec)
return NULL;
}
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
ceiling = Z_LevelPoolCalloc(sizeof(*ceiling));
ceiling->thinker.alloctype = TAT_LEVELPOOL;
ceiling->thinker.size = sizeof(*ceiling);
P_AddThinker(THINK_MAIN, &ceiling->thinker);
sec->ceilingdata = ceiling;
@ -597,7 +600,9 @@ static ceiling_t *CreateCrushThinker(sector_t *sec)
return NULL;
}
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
ceiling = Z_LevelPoolCalloc(sizeof(*ceiling));
ceiling->thinker.alloctype = TAT_LEVELPOOL;
ceiling->thinker.size = sizeof(*ceiling);
P_AddThinker(THINK_MAIN, &ceiling->thinker);
sec->ceilingdata = ceiling;

View file

@ -1618,7 +1618,9 @@ static floormove_t *CreateFloorThinker(sector_t *sec)
return NULL;
}
dofloor = Z_Calloc(sizeof (*dofloor), PU_LEVSPEC, NULL);
dofloor = Z_LevelPoolCalloc(sizeof(*dofloor));
dofloor->thinker.alloctype = TAT_LEVELPOOL;
dofloor->thinker.size = sizeof(*dofloor);
P_AddThinker(THINK_MAIN, &dofloor->thinker);
// make sure another floor thinker won't get started over this one
@ -1911,7 +1913,9 @@ static elevator_t *CreateElevatorThinker(sector_t *sec)
return NULL;
}
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
elevator = Z_LevelPoolCalloc(sizeof(*elevator));
elevator->thinker.alloctype = TAT_LEVELPOOL;
elevator->thinker.size = sizeof(*elevator);
P_AddThinker(THINK_MAIN, &elevator->thinker);
// make sure other thinkers won't get started over this one
@ -2211,7 +2215,9 @@ void EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline)
if (sec->ceilingdata) // One at a time, ma'am.
return;
bouncer = Z_Calloc(sizeof (*bouncer), PU_LEVSPEC, NULL);
bouncer = Z_LevelPoolCalloc(sizeof(*bouncer));
bouncer->thinker.alloctype = TAT_LEVELPOOL;
bouncer->thinker.size = sizeof(*bouncer);
P_AddThinker(THINK_MAIN, &bouncer->thinker);
sec->ceilingdata = bouncer;
bouncer->thinker.function.acp1 = (actionf_p1)T_BounceCheese;
@ -2238,7 +2244,9 @@ void EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boole
backsector = sec;
// create and initialize new thinker
faller = Z_Calloc(sizeof (*faller), PU_LEVSPEC, NULL);
faller = Z_LevelPoolCalloc(sizeof(*faller));
faller->thinker.alloctype = TAT_LEVELPOOL;
faller->thinker.size = sizeof(*faller);
P_AddThinker(THINK_MAIN, &faller->thinker);
faller->thinker.function.acp1 = (actionf_p1)T_ContinuousFalling;
@ -2274,7 +2282,9 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
return 0;
// create and initialize new crumble thinker
crumble = Z_Calloc(sizeof (*crumble), PU_LEVSPEC, NULL);
crumble = Z_LevelPoolCalloc(sizeof(*crumble));
crumble->thinker.alloctype = TAT_LEVELPOOL;
crumble->thinker.size = sizeof(*crumble);
P_AddThinker(THINK_MAIN, &crumble->thinker);
crumble->thinker.function.acp1 = (actionf_p1)T_StartCrumble;
@ -2346,7 +2356,9 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
{
// create and initialize new elevator thinker
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
block = Z_LevelPoolCalloc(sizeof(*block));
block->thinker.alloctype = TAT_LEVELPOOL;
block->thinker.size = sizeof(*block);
P_AddThinker(THINK_MAIN, &block->thinker);
roversec->floordata = block;
roversec->ceilingdata = block;

View file

@ -75,7 +75,9 @@ fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *sector, INT16 lighta, INT1
fireflicker_t *flick;
P_RemoveLighting(sector); // out with the old, in with the new
flick = Z_Calloc(sizeof (*flick), PU_LEVSPEC, NULL);
flick = Z_LevelPoolCalloc(sizeof(*flick));
flick->thinker.alloctype = TAT_LEVELPOOL;
flick->thinker.size = sizeof(*flick);
P_AddThinker(THINK_MAIN, &flick->thinker);
@ -150,7 +152,9 @@ void P_SpawnLightningFlash(sector_t *sector)
sector->lightingdata = NULL;
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
flash = Z_LevelPoolCalloc(sizeof(*flash));
flash->thinker.alloctype = TAT_LEVELPOOL;
flash->thinker.size = sizeof(*flash);
P_AddThinker(THINK_MAIN, &flash->thinker);
@ -209,7 +213,9 @@ strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *sector, INT16 lighta, INT16 lig
strobe_t *flash;
P_RemoveLighting(sector); // out with the old, in with the new
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
flash = Z_LevelPoolCalloc(sizeof(*flash));
flash->thinker.alloctype = TAT_LEVELPOOL;
flash->thinker.size = sizeof(*flash);
P_AddThinker(THINK_MAIN, &flash->thinker);
@ -279,7 +285,9 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *sector, INT16 lighta, INT16 ligh
glow_t *g;
P_RemoveLighting(sector); // out with the old, in with the new
g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL);
g = Z_LevelPoolCalloc(sizeof(*g));
g->thinker.alloctype = TAT_LEVELPOOL;
g->thinker.size = sizeof(*g);
P_AddThinker(THINK_MAIN, &g->thinker);
@ -333,7 +341,9 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean
return;
}
ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL);
ll = Z_LevelPoolCalloc(sizeof(*ll));
ll->thinker.alloctype = TAT_LEVELPOOL;
ll->thinker.size = sizeof(*ll);
ll->thinker.function.acp1 = (actionf_p1)T_LightFade;
sector->lightingdata = ll; // set it to the lightlevel_t

View file

@ -78,7 +78,6 @@ typedef enum
NUM_THINKERLISTS
} thinklistnum_t; /**< Thinker lists. */
extern thinker_t thlist[];
extern mobj_t *mobjcache;
void P_InitThinkers(void);
void P_InvalidateThinkersWithoutInit(void);

View file

@ -12,6 +12,7 @@
/// \file p_mobj.c
/// \brief Moving object handling. Spawn functions
#include "d_think.h"
#include "dehacked.h"
#include "doomdef.h"
#include "g_game.h"
@ -64,8 +65,6 @@ mobj_t *waypointcap = NULL;
// general purpose.
mobj_t *trackercap = NULL;
mobj_t *mobjcache = NULL;
void P_InitCachedActions(void)
{
actioncachehead.prev = actioncachehead.next = &actioncachehead;
@ -1682,7 +1681,7 @@ boolean P_XYMovement(mobj_t *mo)
predictedz = mo->z + slopemom.z;
else
predictedz = mo->z;
}
} else if (P_IsObjectOnGround(mo) && !mo->momz)
predictedz = mo->z;
@ -1931,7 +1930,7 @@ boolean P_XYMovement(mobj_t *mo)
// );
}
}
else
else
{
// if (mo->player)
// CONS_Printf("Ramp Launch %d %d+%d > 0 && %d-%d > %d ", mo->scale, FixedDiv(slopemom.z, mo->scale), P_GetMobjGravity(mo)*24, predictedz, mo->z, slopemom.z/2);
@ -2833,7 +2832,7 @@ void P_PlayerZMovement(mobj_t *mo)
// CONS_Printf(" True\n");
mo->momz = 0;
}
// else
// else
// {
// CONS_Printf(" False\n");
// }
@ -8423,7 +8422,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + mobj->target->height/2);
// Taken from K_FlipFromObject. We just want to flip the visual according to its target, but that's it.
mobj->eflags = (mobj->eflags & ~MFE_VERTICALFLIP)|(mobj->target->eflags & MFE_VERTICALFLIP);
break;
}
case MT_BUBBLESHIELD:
@ -8529,7 +8528,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->extravalue2 = mobj->target->player->bubbleblowup;
P_SetScale(mobj, (mobj->destscale = scale));
// For some weird reason, the Bubble Shield is the exception flip-wise, it has the offset baked into the sprite.
// So instead of simply flipping the object, we have to do a position offset.
fixed_t positionOffset = 0;
@ -9031,7 +9030,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
{
cur->skin = &skins[newplayer->skin];
cur->color = newplayer->skincolor;
// Even if we didn't have the Perfect Sign to consider,
// it's still necessary to refresh SPR2 on skin changes.
P_SetMobjState(cur, (newperfect == true) ? S_KART_SIGL : S_KART_SIGN);
@ -10846,19 +10845,9 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
mobj_t *P_AllocateMobj(void)
{
mobj_t *mobj;
if (mobjcache != NULL)
{
mobj = mobjcache;
mobjcache = mobjcache->hnext;
memset(mobj, 0, sizeof(*mobj));
}
else
{
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
}
mobj_t* mobj = (mobj_t*)Z_LevelPoolCalloc(sizeof(mobj_t));
mobj->thinker.alloctype = TAT_LEVELPOOL;
mobj->thinker.size = sizeof(mobj_t);
return mobj;
}
@ -11375,7 +11364,9 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
const mobjinfo_t *info = &mobjinfo[type];
state_t *st;
fixed_t start_z = INT32_MIN;
precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
precipmobj_t *mobj = Z_LevelPoolCalloc(sizeof(precipmobj_t));
mobj->thinker.alloctype = TAT_LEVELPOOL;
mobj->thinker.size = sizeof(precipmobj_t);
mobj->type = type;
mobj->info = info;
@ -11657,13 +11648,6 @@ void P_RemoveMobj(mobj_t *mobj)
if (!mobj->thinker.next)
{ // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through!
INT32 prevreferences;
if (!mobj->thinker.references)
{
// no references, dump it directly in the mobj cache
mobj->hnext = mobjcache;
mobjcache = mobj;
return;
}
prevreferences = mobj->thinker.references;
P_AddThinker(THINK_MOBJ, (thinker_t *)mobj);
@ -12263,7 +12247,7 @@ void P_SpawnPlayer(INT32 playernum)
P_SetScale(aring, p->mo->scale);
K_MatchGenericExtraFlags(aring, p->mo);
aring->renderflags |= RF_DONTDRAW;
mobj_t *abody = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_AMPBODY);
P_SetTarget(&abody->target, p->mo);
P_SetScale(abody, p->mo->scale);

View file

@ -1995,7 +1995,9 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata)
return false;
// create a new thinker
th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polyrotate_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polyrotate_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotate;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2067,7 +2069,9 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata)
return false;
// create a new thinker
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polymove_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polymove_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjMove;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2129,7 +2133,9 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
return false;
// create a new thinker
th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polywaypoint_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polywaypoint_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjWaypoint;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2197,7 +2203,9 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
INT32 start;
// allocate and add a new slide door thinker
th = Z_Malloc(sizeof(polyslidedoor_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polyslidedoor_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polyslidedoor_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSlide;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
@ -2248,7 +2256,9 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
INT32 start;
// allocate and add a new swing door thinker
th = Z_Malloc(sizeof(polyswingdoor_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polyswingdoor_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polyswingdoor_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSwing;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
@ -2333,7 +2343,9 @@ boolean EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
return false;
// create a new thinker
th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polydisplace_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polydisplace_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjDisplace;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2382,7 +2394,9 @@ boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata)
return false;
// create a new thinker
th = Z_Malloc(sizeof(polyrotdisplace_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polyrotdisplace_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polyrotdisplace_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotDisplace;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2483,7 +2497,9 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata)
}
// create a new thinker
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polymove_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polymove_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjFlag;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
@ -2632,7 +2648,9 @@ boolean EV_DoPolyObjFade(polyfadedata_t *pfdata)
P_RemoveThinker(po->thinker);
// create a new thinker
th = Z_Malloc(sizeof(polyfade_t), PU_LEVSPEC, NULL);
th = Z_LevelPoolMalloc(sizeof(polyfade_t));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(polyfade_t);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjFade;
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;

View file

@ -12,6 +12,7 @@
/// \file p_saveg.cpp
/// \brief Archiving: SaveGame I/O
#include "d_think.h"
#include "doomdef.h"
#include "byteptr.h"
#include "d_main.h"
@ -4928,7 +4929,9 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker)
{
noenemies_t *ht = (noenemies_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
noenemies_t *ht = (noenemies_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
return &ht->thinker;
@ -4936,7 +4939,9 @@ static thinker_t* LoadNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadBounceCheeseThinker(savebuffer_t *save, actionf_p1 thinker)
{
bouncecheese_t *ht = (bouncecheese_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
bouncecheese_t *ht = (bouncecheese_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
ht->sector = LoadSector(READUINT32(save->p));
@ -4954,7 +4959,9 @@ static thinker_t* LoadBounceCheeseThinker(savebuffer_t *save, actionf_p1 thinker
static thinker_t* LoadContinuousFallThinker(savebuffer_t *save, actionf_p1 thinker)
{
continuousfall_t *ht = (continuousfall_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
continuousfall_t *ht = (continuousfall_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->speed = READFIXED(save->p);
@ -4974,7 +4981,9 @@ static thinker_t* LoadContinuousFallThinker(savebuffer_t *save, actionf_p1 think
static thinker_t* LoadMarioBlockThinker(savebuffer_t *save, actionf_p1 thinker)
{
mariothink_t *ht = (mariothink_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
mariothink_t *ht = (mariothink_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->speed = READFIXED(save->p);
@ -4994,7 +5003,9 @@ static thinker_t* LoadMarioBlockThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadMarioCheckThinker(savebuffer_t *save, actionf_p1 thinker)
{
mariocheck_t *ht = (mariocheck_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
mariocheck_t *ht = (mariocheck_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
ht->sector = LoadSector(READUINT32(save->p));
@ -5003,7 +5014,9 @@ static thinker_t* LoadMarioCheckThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadThwompThinker(savebuffer_t *save, actionf_p1 thinker)
{
thwomp_t *ht = (thwomp_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
thwomp_t *ht = (thwomp_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
ht->sector = LoadSector(READUINT32(save->p));
@ -5027,7 +5040,9 @@ static thinker_t* LoadThwompThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadFloatThinker(savebuffer_t *save, actionf_p1 thinker)
{
floatthink_t *ht = (floatthink_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
floatthink_t *ht = (floatthink_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
ht->sector = LoadSector(READUINT32(save->p));
@ -5038,7 +5053,9 @@ static thinker_t* LoadFloatThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadEachTimeThinker(savebuffer_t *save, actionf_p1 thinker)
{
size_t i;
eachtime_t *ht = (eachtime_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
eachtime_t *ht = (eachtime_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
for (i = 0; i < MAXPLAYERS; i++)
@ -5051,7 +5068,9 @@ static thinker_t* LoadEachTimeThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadRaiseThinker(savebuffer_t *save, actionf_p1 thinker)
{
raise_t *ht = (raise_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
raise_t *ht = (raise_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->tag = READINT16(save->p);
ht->sector = LoadSector(READUINT32(save->p));
@ -5066,7 +5085,9 @@ static thinker_t* LoadRaiseThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadCeilingThinker(savebuffer_t *save, actionf_p1 thinker)
{
ceiling_t *ht = (ceiling_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ceiling_t *ht = (ceiling_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->type = (ceiling_e)READUINT8(save->p);
ht->sector = LoadSector(READUINT32(save->p));
@ -5091,7 +5112,9 @@ static thinker_t* LoadCeilingThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadFloormoveThinker(savebuffer_t *save, actionf_p1 thinker)
{
floormove_t *ht = (floormove_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
floormove_t *ht = (floormove_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->type = (floor_e)READUINT8(save->p);
ht->crush = READUINT8(save->p);
@ -5115,7 +5138,9 @@ static thinker_t* LoadFloormoveThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadLightflashThinker(savebuffer_t *save, actionf_p1 thinker)
{
lightflash_t *ht = (lightflash_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
lightflash_t *ht = (lightflash_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->maxlight = READINT32(save->p);
@ -5127,7 +5152,9 @@ static thinker_t* LoadLightflashThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadStrobeThinker(savebuffer_t *save, actionf_p1 thinker)
{
strobe_t *ht = (strobe_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
strobe_t *ht = (strobe_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->count = READINT32(save->p);
@ -5142,7 +5169,9 @@ static thinker_t* LoadStrobeThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadGlowThinker(savebuffer_t *save, actionf_p1 thinker)
{
glow_t *ht = (glow_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
glow_t *ht = (glow_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->minlight = READINT16(save->p);
@ -5156,7 +5185,9 @@ static thinker_t* LoadGlowThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadFireflickerThinker(savebuffer_t *save, actionf_p1 thinker)
{
fireflicker_t *ht = (fireflicker_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
fireflicker_t *ht = (fireflicker_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->count = READINT32(save->p);
@ -5170,7 +5201,9 @@ static thinker_t* LoadFireflickerThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadElevatorThinker(savebuffer_t *save, actionf_p1 thinker, boolean setplanedata)
{
elevator_t *ht = (elevator_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
elevator_t *ht = (elevator_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->type = (elevator_e)READUINT8(save->p);
ht->sector = LoadSector(READUINT32(save->p));
@ -5199,7 +5232,9 @@ static thinker_t* LoadElevatorThinker(savebuffer_t *save, actionf_p1 thinker, bo
static thinker_t* LoadCrumbleThinker(savebuffer_t *save, actionf_p1 thinker)
{
crumble_t *ht = (crumble_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
crumble_t *ht = (crumble_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sourceline = LoadLine(READUINT32(save->p));
ht->sector = LoadSector(READUINT32(save->p));
@ -5221,7 +5256,9 @@ static thinker_t* LoadCrumbleThinker(savebuffer_t *save, actionf_p1 thinker)
static thinker_t* LoadScrollThinker(savebuffer_t *save, actionf_p1 thinker)
{
scroll_t *ht = (scroll_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
scroll_t *ht = (scroll_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->dx = READFIXED(save->p);
ht->dy = READFIXED(save->p);
@ -5238,7 +5275,9 @@ static thinker_t* LoadScrollThinker(savebuffer_t *save, actionf_p1 thinker)
static inline thinker_t* LoadFrictionThinker(savebuffer_t *save, actionf_p1 thinker)
{
friction_t *ht = (friction_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
friction_t *ht = (friction_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->friction = READINT32(save->p);
ht->movefactor = READINT32(save->p);
@ -5250,7 +5289,9 @@ static inline thinker_t* LoadFrictionThinker(savebuffer_t *save, actionf_p1 thin
static thinker_t* LoadPusherThinker(savebuffer_t *save, actionf_p1 thinker)
{
pusher_t *ht = (pusher_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
pusher_t *ht = (pusher_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->type = (pushertype_e)READUINT8(save->p);
ht->x_mag = READFIXED(save->p);
@ -5266,7 +5307,9 @@ static thinker_t* LoadPusherThinker(savebuffer_t *save, actionf_p1 thinker)
static inline thinker_t* LoadLaserThinker(savebuffer_t *save, actionf_p1 thinker)
{
laserthink_t *ht = (laserthink_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
laserthink_t *ht = (laserthink_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->tag = READINT16(save->p);
ht->sourceline = LoadLine(READUINT32(save->p));
@ -5276,7 +5319,9 @@ static inline thinker_t* LoadLaserThinker(savebuffer_t *save, actionf_p1 thinker
static inline thinker_t* LoadLightlevelThinker(savebuffer_t *save, actionf_p1 thinker)
{
lightlevel_t *ht = (lightlevel_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
lightlevel_t *ht = (lightlevel_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->sourcelevel = READINT16(save->p);
@ -5291,7 +5336,9 @@ static inline thinker_t* LoadLightlevelThinker(savebuffer_t *save, actionf_p1 th
static inline thinker_t* LoadExecutorThinker(savebuffer_t *save, actionf_p1 thinker)
{
executor_t *ht = (executor_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
executor_t *ht = (executor_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->line = LoadLine(READUINT32(save->p));
ht->caller = LoadMobj(READUINT32(save->p));
@ -5302,7 +5349,9 @@ static inline thinker_t* LoadExecutorThinker(savebuffer_t *save, actionf_p1 thin
static inline thinker_t* LoadDisappearThinker(savebuffer_t *save, actionf_p1 thinker)
{
disappear_t *ht = (disappear_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
disappear_t *ht = (disappear_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->appeartime = READUINT32(save->p);
ht->disappeartime = READUINT32(save->p);
@ -5317,7 +5366,9 @@ static inline thinker_t* LoadDisappearThinker(savebuffer_t *save, actionf_p1 thi
static inline thinker_t* LoadFadeThinker(savebuffer_t *save, actionf_p1 thinker)
{
sector_t *ss;
fade_t *ht = (fade_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
fade_t *ht = (fade_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->dest_exc = GetNetColormapFromList(READUINT32(save->p));
ht->sectornum = READUINT32(save->p);
@ -5358,7 +5409,9 @@ static inline thinker_t* LoadFadeThinker(savebuffer_t *save, actionf_p1 thinker)
static inline thinker_t* LoadFadeColormapThinker(savebuffer_t *save, actionf_p1 thinker)
{
fadecolormap_t *ht = (fadecolormap_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
fadecolormap_t *ht = (fadecolormap_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->sector = LoadSector(READUINT32(save->p));
ht->source_exc = GetNetColormapFromList(READUINT32(save->p));
@ -5373,7 +5426,9 @@ static inline thinker_t* LoadFadeColormapThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadPlaneDisplaceThinker(savebuffer_t *save, actionf_p1 thinker)
{
planedisplace_t *ht = (planedisplace_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
planedisplace_t *ht = (planedisplace_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->affectee = READINT32(save->p);
@ -5386,7 +5441,9 @@ static inline thinker_t* LoadPlaneDisplaceThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadDynamicLineSlopeThinker(savebuffer_t *save, actionf_p1 thinker)
{
dynlineplanethink_t* ht = (dynlineplanethink_t*)Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
dynlineplanethink_t* ht = (dynlineplanethink_t*)Z_LevelPoolMalloc(sizeof(*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->type = (dynplanetype_t)READUINT8(save->p);
@ -5399,7 +5456,9 @@ static inline thinker_t* LoadDynamicLineSlopeThinker(savebuffer_t *save, actionf
static inline thinker_t* LoadDynamicVertexSlopeThinker(savebuffer_t *save, actionf_p1 thinker)
{
size_t i;
dynvertexplanethink_t* ht = (dynvertexplanethink_t*)Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
dynvertexplanethink_t* ht = (dynvertexplanethink_t*)Z_LevelPoolMalloc(sizeof(*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->slope = LoadSlope(READUINT32(save->p));
@ -5414,7 +5473,9 @@ static inline thinker_t* LoadDynamicVertexSlopeThinker(savebuffer_t *save, actio
static inline thinker_t* LoadPolyrotatetThinker(savebuffer_t *save, actionf_p1 thinker)
{
polyrotate_t *ht = (polyrotate_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polyrotate_t *ht = (polyrotate_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->speed = READINT32(save->p);
@ -5425,7 +5486,9 @@ static inline thinker_t* LoadPolyrotatetThinker(savebuffer_t *save, actionf_p1 t
static thinker_t* LoadPolymoveThinker(savebuffer_t *save, actionf_p1 thinker)
{
polymove_t *ht = (polymove_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polymove_t *ht = (polymove_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->speed = READINT32(save->p);
@ -5438,7 +5501,9 @@ static thinker_t* LoadPolymoveThinker(savebuffer_t *save, actionf_p1 thinker)
static inline thinker_t* LoadPolywaypointThinker(savebuffer_t *save, actionf_p1 thinker)
{
polywaypoint_t *ht = (polywaypoint_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polywaypoint_t *ht = (polywaypoint_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->speed = READINT32(save->p);
@ -5453,7 +5518,9 @@ static inline thinker_t* LoadPolywaypointThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadPolyslidedoorThinker(savebuffer_t *save, actionf_p1 thinker)
{
polyslidedoor_t *ht = (polyslidedoor_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polyslidedoor_t *ht = (polyslidedoor_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->delay = READINT32(save->p);
@ -5473,7 +5540,9 @@ static inline thinker_t* LoadPolyslidedoorThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadPolyswingdoorThinker(savebuffer_t *save, actionf_p1 thinker)
{
polyswingdoor_t *ht = (polyswingdoor_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polyswingdoor_t *ht = (polyswingdoor_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->delay = READINT32(save->p);
@ -5488,7 +5557,9 @@ static inline thinker_t* LoadPolyswingdoorThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadPolydisplaceThinker(savebuffer_t *save, actionf_p1 thinker)
{
polydisplace_t *ht = (polydisplace_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polydisplace_t *ht = (polydisplace_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->controlSector = LoadSector(READUINT32(save->p));
@ -5500,7 +5571,9 @@ static inline thinker_t* LoadPolydisplaceThinker(savebuffer_t *save, actionf_p1
static inline thinker_t* LoadPolyrotdisplaceThinker(savebuffer_t *save, actionf_p1 thinker)
{
polyrotdisplace_t *ht = (polyrotdisplace_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polyrotdisplace_t *ht = (polyrotdisplace_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->controlSector = LoadSector(READUINT32(save->p));
@ -5512,7 +5585,9 @@ static inline thinker_t* LoadPolyrotdisplaceThinker(savebuffer_t *save, actionf_
static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker)
{
polyfade_t *ht = (polyfade_t*)Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
polyfade_t *ht = (polyfade_t*)Z_LevelPoolMalloc(sizeof (*ht));
ht->thinker.alloctype = TAT_LEVELPOOL;
ht->thinker.size = sizeof (*ht);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save->p);
ht->sourcevalue = READINT32(save->p);
@ -5563,7 +5638,14 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
{
(next->prev = currentthinker->prev)->next = next;
R_DestroyLevelInterpolators(currentthinker);
Z_Free(currentthinker);
if (currentthinker->alloctype == TAT_LEVELPOOL)
{
Z_LevelPoolFree(currentthinker, currentthinker->size);
}
else
{
Z_Free(currentthinker);
}
}
}
}
@ -6876,7 +6958,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
spawnss->tags.count * sizeof(mtag_t)
)
);
}
else
{
@ -6966,7 +7048,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
spawnli->tags.count * sizeof(mtag_t)
)
);
}
else
{

View file

@ -8683,7 +8683,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
Patch_FreeTag(PU_PATCH_LOWPRIORITY);
Patch_FreeTag(PU_PATCH_ROTATED);
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
mobjcache = NULL;
R_InitializeLevelInterpolators();

View file

@ -11,6 +11,7 @@
/// \file p_slopes.c
/// \brief ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron
#include "d_think.h"
#include "doomdef.h"
#include "r_defs.h"
#include "r_state.h"
@ -300,7 +301,9 @@ void T_DynamicSlopeVert (dynvertexplanethink_t* th)
static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent)
{
dynlineplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL);
dynlineplanethink_t* th = Z_LevelPoolCalloc(sizeof (*th));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(*th);
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine;
th->slope = slope;
th->type = type;
@ -314,7 +317,9 @@ static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t typ
static inline void P_AddDynVertexSlopeThinker (pslope_t* slope, const INT16 tags[3], const vector3_t vx[3])
{
dynvertexplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL);
dynvertexplanethink_t* th = Z_LevelPoolCalloc(sizeof (*th));
th->thinker.alloctype = TAT_LEVELPOOL;
th->thinker.size = sizeof(*th);
size_t i;
INT32 l;
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert;
@ -1091,7 +1096,7 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
vector3_t mom; // Ditto.
if (P_CanApplySlopePhysics(thing, slope) == false) // No physics, no need to make anything complicated.
{
{
if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope
{
thing->standingslope = slope;
@ -1151,7 +1156,7 @@ void P_ButteredSlope(mobj_t *mo)
{
// Allow the player to stand still on slopes below a certain steepness.
// 45 degree angle steep, to be exact.
return;
return;
}
}

View file

@ -16,6 +16,7 @@
/// utility functions, etc.
/// Line Tag handling. Line and Sector triggers.
#include "d_think.h"
#include "dehacked.h"
#include "doomdef.h"
#include "g_game.h"
@ -1297,7 +1298,9 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector)
delay = (line->backsector->ceilingheight >> FRACBITS) + (line->backsector->floorheight >> FRACBITS);
}
e = Z_Calloc(sizeof (*e), PU_LEVSPEC, NULL);
e = Z_LevelPoolCalloc(sizeof (*e));
e->thinker.alloctype = TAT_LEVELPOOL;
e->thinker.size = sizeof (*e);
e->thinker.function.acp1 = (actionf_p1)T_ExecutorDelay;
e->line = line;
@ -6393,7 +6396,9 @@ static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline)
floatthink_t *floater;
// create and initialize new thinker
floater = Z_Calloc(sizeof (*floater), PU_LEVSPEC, NULL);
floater = Z_LevelPoolCalloc(sizeof (*floater));
floater->thinker.alloctype = TAT_LEVELPOOL;
floater->thinker.size = sizeof (*floater);
P_AddThinker(THINK_MAIN, &floater->thinker);
floater->thinker.function.acp1 = (actionf_p1)T_FloatSector;
@ -6424,7 +6429,9 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control,
planedisplace_t *displace;
// create and initialize new displacement thinker
displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL);
displace = Z_LevelPoolCalloc(sizeof (*displace));
displace->thinker.alloctype = TAT_LEVELPOOL;
displace->thinker.size = sizeof (*displace);
P_AddThinker(THINK_MAIN, &displace->thinker);
displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace;
@ -6454,7 +6461,9 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline)
mariocheck_t *block;
// create and initialize new elevator thinker
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
block = Z_LevelPoolCalloc(sizeof (*block));
block->thinker.alloctype = TAT_LEVELPOOL;
block->thinker.size = sizeof (*block);
P_AddThinker(THINK_MAIN, &block->thinker);
block->thinker.function.acp1 = (actionf_p1)T_MarioBlockChecker;
@ -6479,7 +6488,9 @@ static void P_AddRaiseThinker(sector_t *sec, INT16 tag, fixed_t speed, fixed_t c
{
raise_t *raise;
raise = Z_Calloc(sizeof (*raise), PU_LEVSPEC, NULL);
raise = Z_LevelPoolCalloc(sizeof (*raise));
raise->thinker.alloctype = TAT_LEVELPOOL;
raise->thinker.size = sizeof (*raise);
P_AddThinker(THINK_MAIN, &raise->thinker);
raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
@ -6506,7 +6517,9 @@ static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, b
{
raise_t *airbob;
airbob = Z_Calloc(sizeof (*airbob), PU_LEVSPEC, NULL);
airbob = Z_LevelPoolCalloc(sizeof (*airbob));
airbob->thinker.alloctype = TAT_LEVELPOOL;
airbob->thinker.size = sizeof (*airbob);
P_AddThinker(THINK_MAIN, &airbob->thinker);
airbob->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
@ -6548,7 +6561,9 @@ static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t
return;
// create and initialize new elevator thinker
thwomp = Z_Calloc(sizeof (*thwomp), PU_LEVSPEC, NULL);
thwomp = Z_LevelPoolCalloc(sizeof (*thwomp));
thwomp->thinker.alloctype = TAT_LEVELPOOL;
thwomp->thinker.size = sizeof (*thwomp);
P_AddThinker(THINK_MAIN, &thwomp->thinker);
thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector;
@ -6588,7 +6603,9 @@ static inline void P_AddNoEnemiesThinker(line_t *sourceline)
noenemies_t *nobaddies;
// create and initialize new thinker
nobaddies = Z_Calloc(sizeof (*nobaddies), PU_LEVSPEC, NULL);
nobaddies = Z_LevelPoolCalloc(sizeof (*nobaddies));
nobaddies->thinker.alloctype = TAT_LEVELPOOL;
nobaddies->thinker.size = sizeof (*nobaddies);
P_AddThinker(THINK_MAIN, &nobaddies->thinker);
nobaddies->thinker.function.acp1 = (actionf_p1)T_NoEnemiesSector;
@ -6608,7 +6625,9 @@ static void P_AddEachTimeThinker(line_t *sourceline, boolean triggerOnExit)
eachtime_t *eachtime;
// create and initialize new thinker
eachtime = Z_Calloc(sizeof (*eachtime), PU_LEVSPEC, NULL);
eachtime = Z_LevelPoolCalloc(sizeof (*eachtime));
eachtime->thinker.alloctype = TAT_LEVELPOOL;
eachtime->thinker.size = sizeof (*eachtime);
P_AddThinker(THINK_MAIN, &eachtime->thinker);
eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker;
@ -6632,7 +6651,9 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
CONS_Alert(CONS_WARNING, M_GetText("Detected a camera scanner effect (linedef type 5). This effect is deprecated and will be removed in the future!\n"));
// create and initialize new elevator thinker
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
elevator = Z_LevelPoolCalloc(sizeof (*elevator));
elevator->thinker.alloctype = TAT_LEVELPOOL;
elevator->thinker.size = sizeof (*elevator);
P_AddThinker(THINK_MAIN, &elevator->thinker);
elevator->thinker.function.acp1 = (actionf_p1)T_CameraScanner;
@ -6713,7 +6734,9 @@ void T_LaserFlash(laserthink_t *flash)
static inline void P_AddLaserThinker(INT16 tag, line_t *line, boolean nobosses)
{
laserthink_t *flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
laserthink_t *flash = Z_LevelPoolCalloc(sizeof (*flash));
flash->thinker.alloctype = TAT_LEVELPOOL;
flash->thinker.size = sizeof (*flash);
P_AddThinker(THINK_MAIN, &flash->thinker);
@ -8244,7 +8267,9 @@ void T_Scroll(scroll_t *s)
*/
static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT32 affectee, INT32 accel, INT32 exclusive)
{
scroll_t *s = Z_Calloc(sizeof *s, PU_LEVSPEC, NULL);
scroll_t *s = Z_LevelPoolCalloc(sizeof (*s));
s->thinker.alloctype = TAT_LEVELPOOL;
s->thinker.size = sizeof (*s);
s->thinker.function.acp1 = (actionf_p1)T_Scroll;
s->type = type;
s->dx = dx;
@ -8389,7 +8414,9 @@ static void P_SpawnScrollers(void)
*/
static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t offset, INT32 line, INT32 sourceline)
{
disappear_t *d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL);
disappear_t *d = Z_LevelPoolCalloc(sizeof (*d));
d->thinker.alloctype = TAT_LEVELPOOL;
d->thinker.size = sizeof (*d);
d->thinker.function.acp1 = (actionf_p1)T_Disappear;
d->appeartime = appeartime;
@ -8784,7 +8811,9 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
if (rover->alpha == max(1, min(256, relative ? rover->alpha + destvalue : destvalue)))
return;
d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL);
d = Z_LevelPoolCalloc(sizeof (*d));
d->thinker.alloctype = TAT_LEVELPOOL;
d->thinker.size = sizeof (*d);
d->thinker.function.acp1 = (actionf_p1)T_Fade;
d->rover = rover;
@ -8937,7 +8966,9 @@ static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, ext
return;
}
d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL);
d = Z_LevelPoolCalloc(sizeof (*d));
d->thinker.alloctype = TAT_LEVELPOOL;
d->thinker.size = sizeof (*d);
d->thinker.function.acp1 = (actionf_p1)T_FadeColormap;
d->sector = sector;
d->source_exc = source_exc;
@ -9060,7 +9091,9 @@ void T_FadeColormap(fadecolormap_t *d)
*/
static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer)
{
friction_t *f = Z_Calloc(sizeof *f, PU_LEVSPEC, NULL);
friction_t *f = Z_LevelPoolCalloc(sizeof (*f));
f->thinker.alloctype = TAT_LEVELPOOL;
f->thinker.size = sizeof (*f);
f->thinker.function.acp1 = (actionf_p1)T_Friction;
f->friction = friction;
@ -9194,7 +9227,9 @@ static void P_SpawnFriction(void)
*/
static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, fixed_t z_mag, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider)
{
pusher_t *p = Z_Calloc(sizeof *p, PU_LEVSPEC, NULL);
pusher_t *p = Z_LevelPoolCalloc(sizeof (*p));
p->thinker.alloctype = TAT_LEVELPOOL;
p->thinker.size = sizeof (*p);
p->thinker.function.acp1 = (actionf_p1)T_Pusher;
p->type = type;

View file

@ -12,6 +12,7 @@
/// \file p_tick.c
/// \brief Archiving: SaveGame I/O, Thinker, Ticker
#include "d_think.h"
#include "doomstat.h"
#include "d_main.h"
#include "g_game.h"
@ -330,7 +331,6 @@ void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
thlist[n].prev = thinker;
thinker->references = 0; // killough 11/98: init reference counter to 0
thinker->cachable = n == THINK_MOBJ;
#ifdef PARANOIA
thinker->debug_mobjtype = MT_NULL;
@ -448,11 +448,9 @@ void P_UnlinkThinker(thinker_t *thinker)
I_Assert(thinker->references == 0);
(next->prev = thinker->prev)->next = next;
if (thinker->cachable)
if (thinker->alloctype == TAT_LEVELPOOL)
{
// put cachable thinkers in the mobj cache, so we can avoid allocations
((mobj_t *)thinker)->hnext = mobjcache;
mobjcache = (mobj_t *)thinker;
Z_LevelPoolFree(thinker, thinker->size);
}
else
{

View file

@ -31,6 +31,7 @@
#include <tracy/tracy/TracyC.h>
#include "core/memory.h"
#include "doomdef.h"
#include "doomstat.h"
#include "r_patch.h"
@ -53,7 +54,6 @@ static boolean Z_calloc = false;
#define ZONEID 0xa441d13d
typedef struct memblock_s
{
void **user;
@ -76,6 +76,16 @@ typedef struct memblock_s
// both the head and tail of the zone memory block list
static memblock_t head;
static constexpr size_t kLevelLargePoolBlockSize = sizeof(mobj_t);
static constexpr size_t kLevelMedPoolBlockSize = sizeof(precipmobj_t);
static constexpr size_t kLevelSmallPoolBlockSize = 128;
static constexpr size_t kLevelTinyPoolBlockSize = 64;
static srb2::PoolAllocator g_level_large_pool { kLevelLargePoolBlockSize, 1024, PU_LEVEL };
static srb2::PoolAllocator g_level_med_pool { kLevelMedPoolBlockSize, 32768, PU_LEVEL };
static srb2::PoolAllocator g_level_small_pool { kLevelSmallPoolBlockSize, 4096, PU_LEVEL };
static srb2::PoolAllocator g_level_tiny_pool { kLevelTinyPoolBlockSize, 8192, PU_LEVEL };
//
// Function prototypes
//
@ -355,6 +365,16 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag)
TracyCZone(__zone, true);
Z_CheckHeap(420);
// First, release all pools, since they can make allocations in zones.
if (PU_LEVEL >= lowtag && PU_LEVEL <= hightag)
{
g_level_large_pool.release();
g_level_med_pool.release();
g_level_small_pool.release();
g_level_tiny_pool.release();
}
for (block = head.next; block != &head; block = next)
{
next = block->next; // get link before freeing
@ -664,3 +684,59 @@ char *Z_StrDup(const char *s)
{
return strcpy((char*)ZZ_Alloc(strlen(s) + 1), s);
}
void* Z_LevelPoolMalloc(size_t size)
{
void* p = nullptr;
if (size <= kLevelTinyPoolBlockSize)
{
p = g_level_tiny_pool.allocate();
}
else if (size <= kLevelSmallPoolBlockSize)
{
p = g_level_small_pool.allocate();
}
else if (size <= kLevelMedPoolBlockSize)
{
p = g_level_med_pool.allocate();
}
else if (size <= kLevelLargePoolBlockSize)
{
p = g_level_large_pool.allocate();
}
if (p == nullptr)
{
p = Z_Malloc(size, PU_LEVEL, nullptr);
}
return p;
}
void* Z_LevelPoolCalloc(size_t size)
{
void* p = Z_LevelPoolMalloc(size);
memset(p, 0, size);
return p;
}
void Z_LevelPoolFree(void* p, size_t size)
{
if (size <= kLevelTinyPoolBlockSize)
{
return g_level_tiny_pool.deallocate(p);
}
if (size <= kLevelSmallPoolBlockSize)
{
return g_level_small_pool.deallocate(p);
}
if (size <= kLevelMedPoolBlockSize)
{
return g_level_med_pool.deallocate(p);
}
if (size <= kLevelLargePoolBlockSize)
{
return g_level_large_pool.deallocate(p);
}
return Z_Free(p);
}

View file

@ -148,6 +148,13 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag);
char *Z_StrDup(const char *in);
#define Z_Unlock(p) (void)p // TODO: remove this now that NDS code has been removed
//
// Specialty allocation functions
//
void *Z_LevelPoolMalloc(size_t size);
void *Z_LevelPoolCalloc(size_t size);
void Z_LevelPoolFree(void *p, size_t size);
#ifdef __cplusplus
} // extern "C"
#endif