Merge branch 'more-saveg-fixes' into 'master'

Several netsave fixes / improvements

See merge request KartKrew/Kart!2475
This commit is contained in:
Sal 2024-10-18 01:08:07 +00:00
commit 067a1007da
5 changed files with 633 additions and 47 deletions

View file

@ -167,6 +167,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
music.cpp
music_manager.cpp
sanitize.cpp
p_deepcopy.cpp
)
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)

229
src/p_deepcopy.cpp Normal file
View file

@ -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 <typename Type>
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 <typename Type>
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<Type *>(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<mtag_t *>(
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<sector_t>(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<sector_t>(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<line_t>(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<line_t>(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<side_t>(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<side_t>(target_array, source_array, source_len, nullptr); // (Not a true deep copy until all of the memory addresses are accounted for.)
}

131
src/p_deepcopy.h Normal file
View file

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

View file

@ -2000,7 +2000,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
@ -2050,7 +2050,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
@ -2064,7 +2064,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
@ -2476,7 +2476,7 @@ static void UnArchiveSectors(savebuffer_t *save)
// Add new entries.
for (j = 0; j < sectors[i].tags.count; j++)
Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
Taggroup_Add(tags_sectors, sectors[i].tags.tags[j], i);
}
@ -2553,7 +2553,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;
@ -2570,8 +2570,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;
@ -2579,9 +2579,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;
@ -2631,8 +2628,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)
@ -2678,8 +2679,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);
}
@ -2689,7 +2688,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;
@ -2720,8 +2719,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)
@ -2744,13 +2763,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);
@ -2769,8 +2786,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);
}
@ -3142,9 +3157,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 || mobj->lastmomz != 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;
@ -3188,11 +3203,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;
@ -4461,6 +4476,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 ] = static_cast<mobjtype_t>(i);
}
}
}
static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
{
mobj_t *mobj;
@ -4532,20 +4562,26 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
mobj->type = (mobjtype_t)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 = (mobjtype_t)i;
mobj->type = new_type;
}
mobj->info = &mobjinfo[mobj->type];
if (diff & MD_POS)
{
mobj->x = mobj->old_x = READFIXED(save->p);
@ -4574,11 +4610,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
@ -4656,12 +4692,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
@ -5506,6 +5544,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++)
{
@ -6794,6 +6836,197 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
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 = static_cast<mtag_t *>(
memcpy(
Z_Realloc(
ss->tags.tags,
spawnss->tags.count * sizeof(mtag_t),
PU_LEVEL,
nullptr
),
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] = nullptr;
}
else
{
ss->stringargs[j] = static_cast<char *>(Z_Realloc(ss->stringargs[j], len + 1, PU_LEVEL, nullptr));
M_Memcpy(ss->stringargs[j], spawnss->stringargs[j], len);
ss->stringargs[j][len] = '\0';
}
}
ss->activation = spawnss->activation;
ss->botController.trick = spawnss->botController.trick;
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 = nullptr;
side_t *spawnsi = nullptr;
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 = static_cast<mtag_t *>(
memcpy(
Z_Realloc(
li->tags.tags,
spawnli->tags.count * sizeof(mtag_t),
PU_LEVEL,
nullptr
),
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] = nullptr;
}
else
{
li->stringargs[j] = static_cast<char *>(Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, nullptr));
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);

View file

@ -119,6 +119,7 @@
#include "k_endcam.h"
#include "k_credits.h"
#include "k_objects.h"
#include "p_deepcopy.h"
// Replay names have time
#if !defined (UNDER_CE)
@ -7535,7 +7536,6 @@ static boolean P_LoadMapFromFile(void)
TracyCZone(__zone, true);
virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP");
size_t i;
udmf = textmap != NULL;
udmf_version = 0;
@ -7563,17 +7563,9 @@ static boolean P_LoadMapFromFile(void)
P_WriteTextmap();
// Copy relevant map data for NetArchive purposes.
spawnsectors = static_cast<sector_t*>(Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL));
spawnlines = static_cast<line_t*>(Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL));
spawnsides = static_cast<side_t*>(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 = static_cast<mtag_t*>(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, &sectors, numsectors);
P_DeepCopyLines(&spawnlines, &lines, numlines);
P_DeepCopySides(&spawnsides, &sides, numsides);
P_MakeMapMD5(curmapvirt, &mapmd5);