Merge outstanding savegame changes from yquake.

- Switch from an whitelist base approach regarding platforms and systems
  to an blacklist approach. This is savegame version 2.
- Fix coop_respan struct not fully initialized after savegame load while
  running in coop mode. This is savegame version 3.

Support for savegame version 2 was added to keep the divergence between
zaero and the other addons low.
This commit is contained in:
Yamagi Burmeister 2019-02-04 13:24:13 +01:00
parent 4e031fe308
commit 4bdd8facd5
5 changed files with 135 additions and 52 deletions

View file

@ -28,19 +28,16 @@ endif
# Detect the architecture
ifeq ($(OSTYPE), Windows)
# At this time only i386 is supported on Windows
ARCH := i386
# seems like mingw doesn't set CC by default
CC := gcc
ifdef PROCESSOR_ARCHITEW6432
# 64 bit Windows
ARCH := $(PROCESSOR_ARCHITEW6432)
else
# Some platforms call it "amd64" and some "x86_64"
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/amd64/x86_64/)
# 32 bit Windows
ARCH := $(PROCESSOR_ARCHITECTURE)
endif
# Refuse all other platforms as a firewall against PEBKAC
# (You'll need some #ifdef for your unsupported plattform!)
ifeq ($(findstring $(ARCH), i386 x86_64 sparc64 ia64),)
$(error arch $(ARCH) is currently not supported)
else
# Normalize some abiguous ARCH strings
ARCH := $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/^arm.*/arm/')
endif
# ----------
@ -73,6 +70,11 @@ endif
# ----------
# Defines the operating system and architecture
CFLAGS += -DOSTYPE=\"$(OSTYPE)\" -DARCH=\"$(ARCH)\"
# ----------
# Base LDFLAGS.
ifeq ($(OSTYPE), Darwin)
LDFLAGS := -shared -arch i386 -arch x86_64

View file

@ -641,6 +641,7 @@ typedef struct
int ofs;
fieldtype_t type;
int flags;
short save_ver;
} field_t;

View file

@ -54,40 +54,49 @@
* in tables/ are changed, otherwise
* strange things may happen.
*/
#define SAVEGAMEVER "YQ2-2"
#define SAVEGAMEVER "YQ2-3"
/*
* This macros are used to
* prohibit loading of savegames
* created on other systems or
* architectures. This will
* crash q2 in spectecular
* ways
* This macros are used to prohibit loading of savegames
* created on other systems or architectures. This will
* crash q2 in spectacular ways
*/
#if defined(__FreeBSD__)
#define OS "FreeBSD"
#elif defined(__APPLE__)
#define OS "MacOS X"
#ifndef OSTYPE
#error OSTYPE should be defined by the build system
#endif
#ifndef ARCH
#error ARCH should be defined by the build system
#endif
/*
* Older operating system and architecture detection
* macros, implemented by savegame version YQ2-1.
*/
#if defined(__APPLE__)
#define OSTYPE_1 "MacOS X"
#elif defined(__FreeBSD__)
#define OSTYPE_1 "FreeBSD"
#elif defined(__OpenBSD__)
#define OS "OpenBSD"
#define OSTYPE_1 "OpenBSD"
#elif defined(__linux__)
#define OS "Linux"
#define OSTYPE_1 "Linux"
#elif defined(_WIN32)
#define OS "Windows"
#define OSTYPE_1 "Windows"
#else
#define OS "Unknown"
#define OSTYPE_1 "Unknown"
#endif
#if defined(__i386__)
#define ARCH "i386"
#define ARCH_1 "i386"
#elif defined(__x86_64__)
#define ARCH "amd64"
#define ARCH_1 "amd64"
#elif defined(__sparc__)
#define ARCH "sparc64"
#define ARCH_1 "sparc64"
#elif defined(__ia64__)
#define ARCH "ia64"
#define ARCH_1 "ia64"
#else
#define ARCH "unknown"
#define ARCH_1 "unknown"
#endif
/*
@ -692,7 +701,7 @@ WriteClient(FILE *f, gclient_t *client)
* Read the client struct from a file
*/
void
ReadClient(FILE *f, gclient_t *client)
ReadClient(FILE *f, gclient_t *client, short save_ver)
{
field_t *field;
@ -701,6 +710,16 @@ ReadClient(FILE *f, gclient_t *client)
for (field = clientfields; field->name; field++)
{
ReadField(f, field, (byte *)client);
if (field->save_ver <= save_ver)
{
ReadField(f, field, (byte *)client);
}
}
if (save_ver < 3)
{
InitClientResp(client);
}
}
@ -746,7 +765,7 @@ WriteGame(const char *filename, qboolean autosave)
strncpy(str_ver, SAVEGAMEVER, sizeof(str_ver));
strncpy(str_game, GAMEVERSION, sizeof(str_game));
strncpy(str_os, OS, sizeof(str_os));
strncpy(str_os, OSTYPE, sizeof(str_os) - 1);
strncpy(str_arch, ARCH, sizeof(str_arch));
fwrite(str_ver, sizeof(str_ver), 1, f);
@ -780,6 +799,7 @@ ReadGame(const char *filename)
char str_game[32];
char str_os[32];
char str_arch[32];
short save_ver = 0;
gi.FreeTags(TAG_GAME);
@ -796,27 +816,84 @@ ReadGame(const char *filename)
fread(str_os, sizeof(str_os), 1, f);
fread(str_arch, sizeof(str_arch), 1, f);
if (strcmp(str_ver, SAVEGAMEVER))
if (!strcmp(str_ver, SAVEGAMEVER))
{
save_ver = 3;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else if (!strcmp(str_ver, "YQ2-2"))
{
save_ver = 2;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else if (!strcmp(str_ver, "YQ2-1"))
{
save_ver = 1;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE_1))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
if (!strcmp(str_os, "Windows"))
{
/* Windows was forced to i386 */
if (strcmp(str_arch, "i386"))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else
{
if (strcmp(str_arch, ARCH_1))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
}
else
{
fclose(f);
gi.error("Savegame from an incompatible version.\n");
}
else if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OS))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
@ -827,7 +904,7 @@ ReadGame(const char *filename)
for (i = 0; i < game.maxclients; i++)
{
ReadClient(f, &game.clients[i]);
ReadClient(f, &game.clients[i], save_ver);
}
fclose(f);

View file

@ -12,4 +12,7 @@
{"newweapon", CLOFS(newweapon), F_ITEM},
{"", CLOFS(zCameraTrack), F_EDICT},
{"", CLOFS(zCameraLocalEntity), F_EDICT},
{"resp.coop_respawn.weapon", CLOFS(resp.coop_respawn.weapon), F_ITEM, 0, 3},
{"resp.coop_respawn.lastweapon", CLOFS(resp.coop_respawn.lastweapon), F_ITEM, 0, 3},
{"resp.coop_respawn.lastweapon2", CLOFS(resp.coop_respawn.lastweapon2), F_ITEM, 0, 3},
{NULL, 0, F_INT}

View file

@ -14,7 +14,7 @@ extern void WriteLevelLocals ( FILE * f ) ;
extern void WriteEdict ( FILE * f , edict_t * ent ) ;
extern void ReadGame ( const char * filename ) ;
extern void WriteGame ( const char * filename , qboolean autosave ) ;
extern void ReadClient ( FILE * f , gclient_t * client ) ;
extern void ReadClient ( FILE * f , gclient_t * client , short save_ver ) ;
extern void WriteClient ( FILE * f , gclient_t * client ) ;
extern void ReadField ( FILE * f , field_t * field , byte * base ) ;
extern void WriteField2 ( FILE * f , field_t * field , byte * base ) ;