diff --git a/src/Sourcefile b/src/Sourcefile index bb9a358aa..5340ee62f 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -64,6 +64,7 @@ p_user.c p_slopes.c p_sweep.cpp p_test.cpp +p_deepcopy.cpp tables.c r_bsp.cpp r_data.c diff --git a/src/p_deepcopy.cpp b/src/p_deepcopy.cpp new file mode 100644 index 000000000..6a6b6ec37 --- /dev/null +++ b/src/p_deepcopy.cpp @@ -0,0 +1,229 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file p_deepcopy.cpp +/// \brief Methods for deep copying + +#include "p_deepcopy.h" + +#include "typedef.h" +#include "z_zone.h" +#include "taglist.h" +#include "r_defs.h" + +/*-------------------------------------------------- + static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *)) + + Make a deep copy of a struct, by using memcpy + for an initial shallow copy, and a callback + function to handle any memory addresses. + + Input Arguments:- + Type: The type of the structs. + target: The struct to copy into. + source: The struct to copy from. + callback: A callback function, intended to replace + pointers after the initial shallow copy. + + Return:- + N/A +--------------------------------------------------*/ + +template +static void P_DeepCopy(Type *target, Type *source, void (*callback)(Type *, Type *)) +{ + memcpy(target, source, sizeof(Type)); + + if (callback != nullptr) + { + callback(target, source); + } +} + +/*-------------------------------------------------- + static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *)) + + Make a deep copy of an array of structs, by using + memcpy for an initial shallow copy, and a callback + function to handle any memory addresses for each + individual struct. + + Input Arguments:- + Type: The type of the structs. + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + callback: A callback function, intended to replace + pointers after the initial shallow copy. + + Return:- + N/A +--------------------------------------------------*/ + +template +static void P_DeepCopyArray(Type **target_array, Type **source_array, size_t source_len, void (*callback)(Type *, Type *)) +{ + const size_t source_total = source_len * sizeof(Type); + + *target_array = static_cast(Z_Calloc(source_total, PU_LEVEL, nullptr)); + memcpy(*target_array, *source_array, source_total); + + if (callback != nullptr) + { + for (size_t i = 0; i < source_len; i++) + { + Type *target = &(*target_array)[i]; + Type *source = &(*source_array)[i]; + + callback(target, source); + } + } +} + +/*-------------------------------------------------- + static void copy_taglist_tags(taglist_t *target, taglist_t *source) + + Make a deep copy of taglist's tags fields. + Used as a helper function for other callbacks, + does not work as a full deep copy of taglist_t + on its own. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_taglist_tags(taglist_t *target, taglist_t *source) +{ + if (source->count) + { + target->tags = static_cast( + memcpy( + Z_Malloc( + source->count * sizeof(mtag_t), + PU_LEVEL, + nullptr + ), + source->tags, + source->count * sizeof(mtag_t) + ) + ); + } +} + +/*-------------------------------------------------- + static void copy_sector_callback(sector_t *target, sector_t *source) + + Handles memory addresses after creating a shallow copy + of a sector_t, to turn it into a deep copy. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_sector_callback(sector_t *target, sector_t *source) +{ + // (Not a true deep copy until all of the memory addresses are accounted for.) + copy_taglist_tags(&target->tags, &source->tags); +} + +/*-------------------------------------------------- + void P_DeepCopySector(sector_t *target, sector_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySector(sector_t *target, sector_t *source) +{ + P_DeepCopy(target, source, copy_sector_callback); +} + +/*-------------------------------------------------- + void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, copy_sector_callback); +} + +/*-------------------------------------------------- + static void copy_line_callback(line_t *target, line_t *source) + + Handles memory addresses after creating a shallow copy + of a line_t, to turn it into a deep copy. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +static void copy_line_callback(line_t *target, line_t *source) +{ + // (Not a true deep copy until all of the memory addresses are accounted for.) + copy_taglist_tags(&target->tags, &source->tags); +} + +/*-------------------------------------------------- + void P_DeepCopyLine(line_t *target, line_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopyLine(line_t *target, line_t *source) +{ + P_DeepCopy(target, source, copy_line_callback); +} + +/*-------------------------------------------------- + void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, copy_line_callback); +} + +/*-------------------------------------------------- + void P_DeepCopySide(line_t *target, line_t *source) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySide(side_t *target, side_t *source) +{ + P_DeepCopy(target, source, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.) +} + +/*-------------------------------------------------- + void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) + + See header file for description. +--------------------------------------------------*/ + +void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) +{ + P_DeepCopyArray(target_array, source_array, source_len, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.) +} diff --git a/src/p_deepcopy.h b/src/p_deepcopy.h new file mode 100644 index 000000000..8eb766f7a --- /dev/null +++ b/src/p_deepcopy.h @@ -0,0 +1,131 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2024 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file p_deepcopy.h +/// \brief Methods for deep copying + +#ifndef __P_DEEPCOPY__ +#define __P_DEEPCOPY__ + +#include "doomdef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------- + void P_DeepCopySector(sector_t *target, sector_t *source); + + Make a deep copy of a single sector_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySector(sector_t *target, sector_t *source); + + +/*-------------------------------------------------- + void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len); + + Make a deep copy of an array of sector_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySectors(sector_t **target_array, sector_t **source_array, size_t source_len); + + +/*-------------------------------------------------- + void P_DeepCopyLine(line_t *target, line_t *source) + + Make a deep copy of a single line_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopyLine(line_t *target, line_t *source); + + +/*-------------------------------------------------- + void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len) + + Make a deep copy of an array of line_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopyLines(line_t **target_array, line_t **source_array, size_t source_len); + + +/*-------------------------------------------------- + void P_DeepCopySide(line_t *target, line_t *source) + + Make a deep copy of a single side_t. + + Input Arguments:- + target: The struct to copy into. + source: The struct to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySide(side_t *target, side_t *source); + + +/*-------------------------------------------------- + void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len) + + Make a deep copy of an array of side_t. + + Input Arguments:- + target_array: The start of the array to copy into. + This will be allocated by this function, so + it should be freed beforehand. + source_array: The start of the array to copy from. + source_len: The length of the array to copy from. + + Return:- + N/A +--------------------------------------------------*/ + +void P_DeepCopySides(side_t **target_array, side_t **source_array, size_t source_len); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __P_DEEPCOPY__ diff --git a/src/p_saveg.c b/src/p_saveg.c index 6b71e40fd..260a31635 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1123,7 +1123,7 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save) #define SD_DIFF3 0x80 // diff3 flags -#define SD_TAGLIST 0x01 +#define SD__UNUSED 0x01 #define SD_COLORMAP 0x02 #define SD_CRUMBLESTATE 0x04 #define SD_FLOORLIGHT 0x08 @@ -1173,7 +1173,7 @@ static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawn #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 -#define LD_CLLCOUNT 0x04 +#define LD_TAG 0x04 #define LD_S1TEXOFF 0x08 #define LD_S1TOPTEX 0x10 #define LD_S1BOTTEX 0x20 @@ -1187,7 +1187,7 @@ static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawn #define LD_S2MIDTEX 0x08 #define LD_ARGS 0x10 #define LD_STRINGARGS 0x20 -#define LD_EXECUTORDELAY 0x40 +#define LD__UNUSED 0x40 #define LD_DIFF3 0x80 // diff3 flags @@ -1678,7 +1678,7 @@ static void UnArchiveSectors(savebuffer_t *save) static void ArchiveLines(savebuffer_t *save) { - size_t i; + size_t i, j; const line_t *li = lines; const line_t *spawnli = spawnlines; const side_t *si; @@ -1695,8 +1695,8 @@ static void ArchiveLines(savebuffer_t *save) if (li->special != spawnli->special) diff |= LD_SPECIAL; - if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved - diff |= LD_CLLCOUNT; + if (!Tag_Compare(&li->tags, &spawnli->tags)) + diff |= LD_TAG; if (!P_LineArgsEqual(li, spawnli)) diff2 |= LD_ARGS; @@ -1704,9 +1704,6 @@ static void ArchiveLines(savebuffer_t *save) if (!P_LineStringArgsEqual(li, spawnli)) diff2 |= LD_STRINGARGS; - if (li->executordelay != spawnli->executordelay) - diff2 |= LD_EXECUTORDELAY; - if (li->activation != spawnli->activation) diff3 |= LD_ACTIVATION; @@ -1756,8 +1753,12 @@ static void ArchiveLines(savebuffer_t *save) WRITEUINT32(save->p, li->flags); if (diff & LD_SPECIAL) WRITEINT16(save->p, li->special); - if (diff & LD_CLLCOUNT) - WRITEINT16(save->p, li->callcount); + if (diff & LD_TAG) + { + WRITEUINT32(save->p, li->tags.count); + for (j = 0; j < li->tags.count; j++) + WRITEINT16(save->p, li->tags.tags[j]); + } si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) @@ -1803,8 +1804,6 @@ static void ArchiveLines(savebuffer_t *save) WRITECHAR(save->p, li->stringargs[j][k]); } } - if (diff2 & LD_EXECUTORDELAY) - WRITEINT32(save->p, li->executordelay); if (diff3 & LD_ACTIVATION) WRITEUINT32(save->p, li->activation); } @@ -1814,7 +1813,7 @@ static void ArchiveLines(savebuffer_t *save) static void UnArchiveLines(savebuffer_t *save) { - UINT16 i; + UINT16 i, j; line_t *li; side_t *si; UINT8 diff, diff2, diff3; @@ -1845,8 +1844,28 @@ static void UnArchiveLines(savebuffer_t *save) li->flags = READUINT32(save->p); if (diff & LD_SPECIAL) li->special = READINT16(save->p); - if (diff & LD_CLLCOUNT) - li->callcount = READINT16(save->p); + if (diff & LD_TAG) + { + size_t ncount = READUINT32(save->p); + + // Remove entries from global lists. + for (j = 0; j < lines[i].tags.count; j++) + Taggroup_Remove(tags_lines, lines[i].tags.tags[j], i); + + // Reallocate if size differs. + if (ncount != lines[i].tags.count) + { + lines[i].tags.count = ncount; + lines[i].tags.tags = (mtag_t*)Z_Realloc(lines[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); + } + + for (j = 0; j < ncount; j++) + lines[i].tags.tags[j] = READINT16(save->p); + + // Add new entries. + for (j = 0; j < lines[i].tags.count; j++) + Taggroup_Add(tags_lines, lines[i].tags.tags[j], i); + } si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) @@ -1869,13 +1888,11 @@ static void UnArchiveLines(savebuffer_t *save) si->midtexture = READINT32(save->p); if (diff2 & LD_ARGS) { - UINT8 j; for (j = 0; j < NUM_SCRIPT_ARGS; j++) li->args[j] = READINT32(save->p); } if (diff2 & LD_STRINGARGS) { - UINT8 j; for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) { size_t len = READINT32(save->p); @@ -1894,8 +1911,6 @@ static void UnArchiveLines(savebuffer_t *save) li->stringargs[j][len] = '\0'; } } - if (diff2 & LD_EXECUTORDELAY) - li->executordelay = READINT32(save->p); if (diff3 & LD_ACTIVATION) li->activation = READUINT32(save->p); @@ -2254,9 +2269,9 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 // not the default but the most probable if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0) diff |= MD_MOM; - if (mobj->radius != mobj->info->radius) + if (mobj->radius != FixedMul(mapobjectscale, mobj->info->radius)) diff |= MD_RADIUS; - if (mobj->height != mobj->info->height) + if (mobj->height != FixedMul(mapobjectscale, mobj->info->height)) diff |= MD_HEIGHT; if (mobj->flags != mobj->info->flags) diff |= MD_FLAGS; @@ -2301,11 +2316,11 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 diff |= MD_MOVEFACTOR; if (mobj->fuse) diff |= MD_FUSE; - if (mobj->watertop) + if (mobj->watertop != INT32_MAX) diff |= MD_WATERTOP; if (mobj->waterbottom) diff |= MD_WATERBOTTOM; - if (mobj->scale != FRACUNIT) + if (mobj->scale != mapobjectscale) diff |= MD_SCALE; if (mobj->destscale != mobj->scale) diff |= MD_DSCALE; @@ -3552,6 +3567,21 @@ static inline pslope_t *LoadSlope(UINT32 slopeid) return NULL; } +static mobjtype_t g_doomednum_to_mobjtype[UINT16_MAX]; + +static void CalculateDoomednumToMobjtype(void) +{ + memset(g_doomednum_to_mobjtype, MT_NULL, sizeof(g_doomednum_to_mobjtype)); + + for (size_t i = MT_NULL+1; i < NUMMOBJTYPES; i++) + { + if (mobjinfo[i].doomednum > 0 && mobjinfo[i].doomednum <= UINT16_MAX) + { + g_doomednum_to_mobjtype[ mobjinfo[i].doomednum ] = i; + } + } +} + static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) { mobj_t *mobj; @@ -3623,20 +3653,26 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) mobj->type = READUINT32(save->p); else { - for (i = 0; i < NUMMOBJTYPES; i++) - if (mobj->spawnpoint && mobj->spawnpoint->type == mobjinfo[i].doomednum) - break; - if (i == NUMMOBJTYPES) + mobjtype_t new_type = MT_NULL; + if (mobj->spawnpoint) + { + new_type = g_doomednum_to_mobjtype[mobj->spawnpoint->type]; + } + + if (new_type <= MT_NULL || new_type >= NUMMOBJTYPES) { if (mobj->spawnpoint) - CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type); + CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum %d\n", mobj->spawnpoint->type); else - CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n"); + CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum NULL\n"); + I_Error("Netsave corrupted"); } - mobj->type = i; + + mobj->type = new_type; } mobj->info = &mobjinfo[mobj->type]; + if (diff & MD_POS) { mobj->x = mobj->old_x = READFIXED(save->p); @@ -3664,11 +3700,11 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) if (diff & MD_RADIUS) mobj->radius = READFIXED(save->p); else - mobj->radius = mobj->info->radius; + mobj->radius = FixedMul(mobj->info->radius, mapobjectscale); if (diff & MD_HEIGHT) mobj->height = READFIXED(save->p); else - mobj->height = mobj->info->height; + mobj->height = FixedMul(mobj->info->height, mapobjectscale); if (diff & MD_FLAGS) mobj->flags = READUINT32(save->p); else @@ -3746,12 +3782,14 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) mobj->fuse = READINT32(save->p); if (diff & MD_WATERTOP) mobj->watertop = READFIXED(save->p); + else + mobj->watertop = INT32_MAX; if (diff & MD_WATERBOTTOM) mobj->waterbottom = READFIXED(save->p); if (diff & MD_SCALE) mobj->scale = READFIXED(save->p); else - mobj->scale = FRACUNIT; + mobj->scale = mapobjectscale; if (diff & MD_DSCALE) mobj->destscale = READFIXED(save->p); else @@ -4599,6 +4637,10 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save) if (READUINT32(save->p) != ARCHIVEBLOCK_THINKERS) I_Error("Bad $$$.sav at archive block Thinkers"); + // Pre-calculate this lookup, because it was wasting + // a shit ton of time loading mobj thinkers. + CalculateDoomednumToMobjtype(); + // remove all the current thinkers for (i = 0; i < NUM_THINKERLISTS; i++) { @@ -5367,7 +5409,7 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool { TracyCZone(__zone, true); - size_t i; + size_t i, j; size_t numTasks; const INT16 prevgamemap = gamemap; @@ -5425,6 +5467,193 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool return false; } } + else + { + // Only reload stuff that can we modify in the save states themselves. + // This is still orders of magnitude faster than a full level reload. + // Considered memcpy, but it's complicated -- save that for local saves. + + sector_t *ss = sectors; + sector_t *spawnss = spawnsectors; + for (i = 0; i < numsectors; i++, ss++, spawnss++) + { + ss->floorheight = spawnss->floorheight; + ss->ceilingheight = spawnss->ceilingheight; + ss->floorpic = spawnss->floorpic; + ss->ceilingpic = spawnss->ceilingpic; + ss->lightlevel = spawnss->lightlevel; + ss->special = spawnss->special; + ss->floor_xoffs = spawnss->floor_xoffs; + ss->floor_yoffs = spawnss->floor_yoffs; + ss->ceiling_xoffs = spawnss->ceiling_xoffs; + ss->ceiling_yoffs = spawnss->ceiling_yoffs; + ss->floorpic_angle = spawnss->floorpic_angle; + ss->ceilingpic_angle = spawnss->ceilingpic_angle; + + if (Tag_Compare(&ss->tags, &spawnss->tags) == false) + { + if (spawnss->tags.count) + { + ss->tags.count = spawnss->tags.count; + ss->tags.tags = + memcpy( + Z_Realloc( + ss->tags.tags, + spawnss->tags.count * sizeof(mtag_t), + PU_LEVEL, + NULL + ), + spawnss->tags.tags, + spawnss->tags.count * sizeof(mtag_t) + ); + } + else + { + ss->tags.count = 0; + Z_Free(ss->tags.tags); + } + } + + ss->extra_colormap = ss->spawn_extra_colormap; + ss->crumblestate = CRUMBLE_NONE; + ss->floorlightlevel = spawnss->floorlightlevel; + ss->floorlightabsolute = spawnss->floorlightabsolute; + ss->ceilinglightlevel = spawnss->ceilinglightlevel; + ss->ceilinglightabsolute = spawnss->ceilinglightabsolute; + ss->flags = spawnss->flags; + ss->specialflags = spawnss->specialflags; + ss->damagetype = spawnss->damagetype; + ss->triggertag = spawnss->triggertag; + ss->triggerer = spawnss->triggerer; + ss->gravity = spawnss->gravity; + ss->action = spawnss->action; + + memcpy(ss->args, spawnss->args, NUM_SCRIPT_ARGS * sizeof(*ss->args)); + + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) + { + size_t len = 0; + + if (spawnss->stringargs[j]) + { + len = strlen(spawnss->stringargs[j]); + } + + if (!len) + { + Z_Free(ss->stringargs[j]); + ss->stringargs[j] = NULL; + } + else + { + ss->stringargs[j] = Z_Realloc(ss->stringargs[j], len + 1, PU_LEVEL, NULL); + M_Memcpy(ss->stringargs[j], spawnss->stringargs[j], len); + ss->stringargs[j][len] = '\0'; + } + } + + ss->activation = spawnss->activation; + ss->botController.flags = spawnss->botController.flags; + ss->botController.forceAngle = spawnss->botController.forceAngle; + + if (ss->ffloors) + { + ffloor_t *rover; + for (rover = ss->ffloors; rover; rover = rover->next) + { + rover->fofflags = rover->spawnflags; + rover->alpha = rover->spawnalpha; + } + } + } + + line_t *li = lines; + line_t *spawnli = spawnlines; + side_t *si = NULL; + side_t *spawnsi = NULL; + for (i = 0; i < numlines; i++, spawnli++, li++) + { + li->flags = spawnli->flags; + li->special = spawnli->special; + li->callcount = 0; + + if (Tag_Compare(&li->tags, &spawnli->tags) == false) + { + if (spawnli->tags.count) + { + li->tags.count = spawnli->tags.count; + li->tags.tags = + memcpy( + Z_Realloc( + li->tags.tags, + spawnli->tags.count * sizeof(mtag_t), + PU_LEVEL, + NULL + ), + spawnli->tags.tags, + spawnli->tags.count * sizeof(mtag_t) + ); + + } + else + { + li->tags.count = 0; + Z_Free(li->tags.tags); + } + } + + memcpy(li->args, spawnli->args, NUM_SCRIPT_ARGS * sizeof(*li->args)); + + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) + { + size_t len = 0; + + if (spawnli->stringargs[j]) + { + len = strlen(spawnli->stringargs[j]); + } + + if (!len) + { + Z_Free(li->stringargs[j]); + li->stringargs[j] = NULL; + } + else + { + li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); + M_Memcpy(li->stringargs[j], spawnli->stringargs[j], len); + li->stringargs[j][len] = '\0'; + } + } + + li->executordelay = spawnli->executordelay; + li->activation = spawnli->activation; + + if (li->sidenum[0] != 0xffff) + { + si = &sides[li->sidenum[0]]; + spawnsi = &spawnsides[li->sidenum[0]]; + + si->textureoffset = spawnsi->textureoffset; + si->toptexture = spawnsi->toptexture; + si->bottomtexture = spawnsi->bottomtexture; + si->midtexture = spawnsi->midtexture; + } + + if (li->sidenum[1] != 0xffff) + { + si = &sides[li->sidenum[1]]; + spawnsi = &spawnsides[li->sidenum[1]]; + + si->textureoffset = spawnsi->textureoffset; + si->toptexture = spawnsi->toptexture; + si->bottomtexture = spawnsi->bottomtexture; + si->midtexture = spawnsi->midtexture; + } + } + + Taglist_InitGlobalTables(); + } // get the time leveltime = READUINT32(save->p); diff --git a/src/p_setup.c b/src/p_setup.c index 35b21f991..fd29591b7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -106,6 +106,7 @@ #include "acs/interface.h" #include "doomstat.h" // MAXMUSNAMES #include "k_mapuser.h" +#include "p_deepcopy.h" #include "blan/b_soc.h" @@ -7919,7 +7920,7 @@ static boolean P_LoadMapFromFile(void) TracyCZone(__zone, true); virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP"); - size_t i; + udmf = textmap != NULL; udmf_version = patch_version = 0; @@ -7950,17 +7951,9 @@ static boolean P_LoadMapFromFile(void) CONS_Alert(CONS_ERROR, "Failed to load map patch for %s\n", G_BuildMapName(gamemap)); // Copy relevant map data for NetArchive purposes. - spawnsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL); - spawnlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL); - spawnsides = Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL); - - memcpy(spawnsectors, sectors, numsectors * sizeof(*sectors)); - memcpy(spawnlines, lines, numlines * sizeof(*lines)); - memcpy(spawnsides, sides, numsides * sizeof(*sides)); - - for (i = 0; i < numsectors; i++) - if (sectors[i].tags.count) - spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); + P_DeepCopySectors(&spawnsectors, §ors, numsectors); + P_DeepCopyLines(&spawnlines, &lines, numlines); + P_DeepCopySides(&spawnsides, &sides, numsides); TracyCZoneEnd(__zone); return true;