Fix saved games a little. Should no longer cause issues with hexen2,ad,etc.
Fix black lightmaps in h2mp. Fix missing tinyfont in hexen2. Added the drop part of drag+drop to x11. Hopefully fixed x11 clipboard issues. Hidden some annoying developer prints under developer 2. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5298 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
3fb88f2ec2
commit
0980455e10
31 changed files with 866 additions and 272 deletions
|
@ -1307,7 +1307,7 @@ static void PR_ApplyCompilation_f (void)
|
|||
PR_RegisterFields();
|
||||
sv.world.edict_size=PR_InitEnts(svprogfuncs, sv.world.max_edicts);
|
||||
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, s, NULL, NULL);
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, s, NULL, NULL, NULL);
|
||||
|
||||
|
||||
PR_LoadGlabalStruct(false);
|
||||
|
@ -1555,6 +1555,35 @@ static void PR_FallbackSpawn_Misc_Model(pubprogfuncs_t *progfuncs, edict_t *self
|
|||
G_INT(OFS_PARM0) = EDICT_TO_PROG(progfuncs, self);
|
||||
PF_makestatic(progfuncs, pr_globals);
|
||||
}
|
||||
static void PR_FallbackSpawn_Func_Detail(pubprogfuncs_t *progfuncs, edict_t *self)
|
||||
{
|
||||
void *pr_globals;
|
||||
eval_t *val;
|
||||
|
||||
if (sv.world.worldmodel && sv.world.worldmodel->type==mod_brush && sv.world.worldmodel->fromgame == fg_quake3)
|
||||
{ //on q3bsp, these are expected to be handled directly by q3map2, but it doesn't always strip it.
|
||||
ED_Free(progfuncs, self);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self->v->model && (val = progfuncs->GetEdictFieldValue(progfuncs, self, "mdl", ev_string, NULL)))
|
||||
self->v->model = val->string;
|
||||
if (!*PR_GetString(progfuncs, self->v->model)) //must have a model, because otherwise various things will assume its not valid at all.
|
||||
progfuncs->SetStringField(progfuncs, self, &self->v->model, "*null", true);
|
||||
|
||||
self->v->solid = SOLID_BSP;
|
||||
self->v->movetype = MOVETYPE_PUSH;
|
||||
|
||||
//make sure the model is precached, to avoid errors.
|
||||
pr_globals = PR_globals(progfuncs, PR_CURRENT);
|
||||
G_INT(OFS_PARM0) = self->v->model;
|
||||
PF_precache_model(progfuncs, pr_globals);
|
||||
|
||||
pr_globals = PR_globals(progfuncs, PR_CURRENT);
|
||||
G_INT(OFS_PARM0) = EDICT_TO_PROG(progfuncs, self);
|
||||
G_INT(OFS_PARM1) = self->v->model;
|
||||
PF_setmodel(progfuncs, pr_globals);
|
||||
}
|
||||
struct spawnents_s
|
||||
{
|
||||
int killonspawnflags;
|
||||
|
@ -1672,6 +1701,13 @@ static void PDECL PR_DoSpawnInitialEntity(pubprogfuncs_t *progfuncs, struct edic
|
|||
}
|
||||
else if (!strcmp(eclassname, "misc_model"))
|
||||
PR_FallbackSpawn_Misc_Model(progfuncs, ed);
|
||||
//func_detail+func_group are for compat with ericw-tools, etc.
|
||||
else if (!strcmp(eclassname, "func_detail_illusionary"))
|
||||
PR_FallbackSpawn_Misc_Model(progfuncs, ed);
|
||||
else if (!strcmp(eclassname, "func_detail") || !strcmp(eclassname, "func_detail_wall") || !strcmp(eclassname, "func_detail_fence"))
|
||||
PR_FallbackSpawn_Func_Detail(progfuncs, ed);
|
||||
else if (!strcmp(eclassname, "func_group"))
|
||||
PR_FallbackSpawn_Func_Detail(progfuncs, ed);
|
||||
else
|
||||
{
|
||||
//only warn on the first occurence of the classname, don't spam.
|
||||
|
@ -1757,7 +1793,7 @@ void PR_SpawnInitialEntities(const char *file)
|
|||
ctx.fulldata = PR_FindGlobal(svprogfuncs, "__fullspawndata", PR_ANY, NULL);
|
||||
|
||||
if (svprogfuncs)
|
||||
sv.world.edict_size = PR_LoadEnts(svprogfuncs, file, &ctx, PR_DoSpawnInitialEntity);
|
||||
sv.world.edict_size = PR_LoadEnts(svprogfuncs, file, &ctx, PR_DoSpawnInitialEntity, NULL);
|
||||
else
|
||||
sv.world.edict_size = 0;
|
||||
}
|
||||
|
@ -4243,7 +4279,7 @@ void QCBUILTIN PF_sv_particleeffectnum(pubprogfuncs_t *prinst, struct globalvars
|
|||
|
||||
#ifdef NQPROT
|
||||
//DPP7's network protocol depends upon the ordering of these from an external file. unreliable, but if we're meant to be compatible then we need to at least pretend.
|
||||
if (!sv.strings.particle_precache[1] && sv_listen_dp.ival)
|
||||
if (!sv.strings.particle_precache[1] && (sv_listen_dp.ival || !strncmp(s, "effectinfo.", 11)))
|
||||
COM_Effectinfo_Enumerate(SV_ParticlePrecache_Add);
|
||||
#endif
|
||||
|
||||
|
@ -11764,10 +11800,12 @@ void PR_DumpPlatform_f(void)
|
|||
*/
|
||||
|
||||
{"CSQC_Init", "void(float apilevel, string enginename, float engineversion)", CS, "Called at startup. enginename and engineversion are arbitary hints and can take any form. enginename should be consistant between revisions, but this cannot truely be relied upon."},
|
||||
{"CSQC_WorldLoaded", "void()", CS, "Called after model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp."},
|
||||
{"CSQC_WorldLoaded", "void()", CS, "Called after the server's model+sound precaches have been executed. Gives a chance for the qc to read the entity lump from the bsp (via getentitytoken)."},
|
||||
{"CSQC_Shutdown", "void()", CS, "Specifies that the csqc is going down. Save your persistant settings here."},
|
||||
{"CSQC_UpdateView", "void(float vwidth, float vheight, float notmenu)", CS, "Called every single video frame. The CSQC is responsible for rendering the entire screen."},
|
||||
{"CSQC_UpdateViewLoading", "void(float vwidth, float vheight, float notmenu)", CS, "Alternative to CSQC_UpdateView, called when the engine thinks there should be a loading screen. If present, will inhibit the engine's normal loading screen, deferring to qc to draw it."},
|
||||
{"CSQC_DrawHud", "void(vector viewsize, float scoresshown)", CS, "Part of simple csqc, called after drawing the 3d view whenever CSQC_UpdateView is not defined."},
|
||||
{"CSQC_DrawScores", "void(vector viewsize, float scoresshown)", CS, "Part of simple csqc, called after CSQC_DrawHud whenever CSQC_UpdateView is not defined, and when there are no menus/console active."},
|
||||
{"CSQC_Parse_StuffCmd", "void(string msg)", CS, "Gives the CSQC a chance to intercept stuffcmds. Use the tokenize builtin to parse the message. Unrecognised commands would normally be localcmded, but its probably better to drop unrecognised stuffcmds completely."},
|
||||
{"CSQC_Parse_CenterPrint", "float(string msg)", CS, "Gives the CSQC a chance to intercept centerprints. Return true if you wish the engine to otherwise ignore the centerprint."},
|
||||
{"CSQC_Parse_Damage", "float(float save, float take, vector inflictororg)", CS, "Called as a result of player.dmg_save or player.dmg_take being set on the server.\nReturn true to completely inhibit the engine's colour shift and damage rolls, allowing you to do your own thing.\nYou can use punch_roll += (normalize(inflictororg-player.origin)*v_right)*(take+save)*autocvar_v_kickroll; as a modifier for the roll angle should the player be hit from the side, and slowly fade it away over time."},
|
||||
|
|
|
@ -517,7 +517,9 @@ static edict_t *QDECL Q1QVMPF_EntAlloc(pubprogfuncs_t *pf, pbool object, size_t
|
|||
return (struct edict_s *)e;
|
||||
}
|
||||
|
||||
static int QDECL Q1QVMPF_LoadEnts(pubprogfuncs_t *pf, const char *mapstring, void *ctx, void (PDECL *callback) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend))
|
||||
static int QDECL Q1QVMPF_LoadEnts(pubprogfuncs_t *pf, const char *mapstring, void *ctx,
|
||||
void (PDECL *ent_callback) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend),
|
||||
pbool (PDECL *ext_callback)(pubprogfuncs_t *pf, void *ctx, const char **str))
|
||||
{
|
||||
//the qvm calls the spawn functions itself.
|
||||
//no saved-games.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "pr_common.h"
|
||||
|
||||
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
|
||||
#define CACHEGAME_VERSION_DEFAULT CACHEGAME_VERSION_VERBOSE
|
||||
|
||||
extern cvar_t skill;
|
||||
extern cvar_t deathmatch;
|
||||
|
@ -77,8 +78,94 @@ void SV_SavegameComment (char *text, size_t textsize)
|
|||
}
|
||||
|
||||
#ifndef QUAKETC
|
||||
|
||||
pbool SV_Legacy_ExtendedSaveData(pubprogfuncs_t *progfuncs, void *loadctx, const char **ptr)
|
||||
{
|
||||
char token[8192];
|
||||
com_tokentype_t tt;
|
||||
const char *l = *ptr;
|
||||
size_t idx;
|
||||
if (l[0] == 's' && l[1] == 'v' && l[2] == '.')
|
||||
l += 3; //DPism
|
||||
|
||||
do
|
||||
{
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);
|
||||
} while(tt == TTP_LINEENDING);
|
||||
if (tt != TTP_RAWTOKEN)return false;
|
||||
|
||||
if (!strcmp(token, "lightstyle") || !strcmp(token, "lightstyles"))
|
||||
{ //lightstyle N "STYLESTRING" 1 1 1
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
idx = atoi(token);
|
||||
if (idx >= countof(sv.strings.lightstyles))
|
||||
return false; //unsupported index.
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
|
||||
if (sv.strings.lightstyles[idx])
|
||||
Z_Free((char*)sv.strings.lightstyles[idx]);
|
||||
sv.strings.lightstyles[idx] = Z_StrDup(token);
|
||||
sv.lightstylecolours[idx][0] = sv.lightstylecolours[idx][1] = sv.lightstylecolours[idx][2] = 1.0;
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
sv.lightstylecolours[idx][0] = atof(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
sv.lightstylecolours[idx][1] = atof(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
sv.lightstylecolours[idx][2] = atof(token);
|
||||
}
|
||||
else if (!strcmp(token, "model_precache") || !strcmp(token, "model"))
|
||||
{ //model_precache N "MODELNAME"
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
idx = atoi(token);
|
||||
if (!idx || idx >= countof(sv.strings.model_precache))
|
||||
return false; //unsupported index.
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
sv.strings.model_precache[idx] = PR_AddString(svprogfuncs, token, 0, false);
|
||||
}
|
||||
else if (!strcmp(token, "sound_precache") || !strcmp(token, "sound"))
|
||||
{ //sound_precache N "MODELNAME"
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
idx = atoi(token);
|
||||
if (!idx || idx >= countof(sv.strings.sound_precache))
|
||||
return false; //unsupported index.
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
sv.strings.sound_precache[idx] = PR_AddString(svprogfuncs, token, 0, false);
|
||||
}
|
||||
else if (!strcmp(token, "particle_precache"))
|
||||
{ //particle_precache N "MODELNAME"
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
idx = atoi(token);
|
||||
if (!idx || idx >= countof(sv.strings.particle_precache))
|
||||
return false; //unsupported index.
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
sv.strings.particle_precache[idx] = PR_AddString(svprogfuncs, token, 0, false);
|
||||
}
|
||||
else if (!strcmp(token, "buffer"))
|
||||
{
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
//buffer = atoi(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
//count = atoi(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
return false;
|
||||
}
|
||||
else if (!strcmp(token, "bufstr"))
|
||||
{
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
//buffer = atoi(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_RAWTOKEN)return false;
|
||||
//idx = atoi(token);
|
||||
l = COM_ParseTokenOut(l, NULL, token, sizeof(token), &tt);if (tt != TTP_STRING)return false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
*ptr = l;
|
||||
return true;
|
||||
}
|
||||
|
||||
//expects the version to have already been parsed
|
||||
static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
||||
static qboolean SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
||||
{
|
||||
//FIXME: Multiplayer save probably won't work with spectators.
|
||||
char mapname[MAX_QPATH];
|
||||
|
@ -101,11 +188,11 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
char *modelnames[MAX_PRECACHE_MODELS];
|
||||
char *soundnames[MAX_PRECACHE_SOUNDS];
|
||||
|
||||
if (version != 667 && version != 5 && version != 6) //5 for NQ, 6 for ZQ/FQ
|
||||
if (version != SAVEGAME_VERSION_FTE_LEG && version != SAVEGAME_VERSION_NQ && version != SAVEGAME_VERSION_QW)
|
||||
{
|
||||
VFS_CLOSE (f);
|
||||
Con_TPrintf ("Unable to load savegame of version %i\n", version);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
VFS_GETS(f, str, sizeof(str)); //discard comment.
|
||||
Con_Printf("loading legacy game from %s...\n", filename);
|
||||
|
@ -131,7 +218,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
}
|
||||
SV_SendMessagesToAll();
|
||||
|
||||
if (version == 5 || version == 6)
|
||||
if (version == SAVEGAME_VERSION_NQ || version == SAVEGAME_VERSION_QW)
|
||||
{
|
||||
slots = 1;
|
||||
SV_UpdateMaxPlayers(1);
|
||||
|
@ -163,7 +250,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
{
|
||||
VFS_CLOSE(f);
|
||||
Con_Printf ("Corrupted save game");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
SV_UpdateMaxPlayers(slots);
|
||||
for (clnum = 0; clnum < sv.allocated_client_slots; clnum++) //work out which players we had when we saved, and hope they accepted the reconnect.
|
||||
|
@ -196,7 +283,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (version == 5 || version == 6)
|
||||
if (version == SAVEGAME_VERSION_NQ || version == SAVEGAME_VERSION_QW)
|
||||
{
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (Cvar_FindVar("skill"), atof(str));
|
||||
|
@ -204,7 +291,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
Cvar_SetValue (Cvar_FindVar("coop"), 0);
|
||||
Cvar_SetValue (Cvar_FindVar("teamplay"), 0);
|
||||
|
||||
if (version == 5)
|
||||
if (version == SAVEGAME_VERSION_NQ)
|
||||
{
|
||||
progstype = PROG_NQ;
|
||||
Cvar_Set (&pr_ssqc_progs, "progs.dat"); //NQ's progs.
|
||||
|
@ -240,7 +327,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
{
|
||||
VFS_CLOSE (f);
|
||||
Con_TPrintf ("Couldn't load map\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
sv.allocated_client_slots = slots;
|
||||
|
@ -285,7 +372,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
// load the edicts out of the savegame file
|
||||
// the rest of the file is sent directly to the progs engine.
|
||||
|
||||
if (version == 5 || version == 6)
|
||||
if (version == SAVEGAME_VERSION_NQ || version == SAVEGAME_VERSION_QW)
|
||||
;//Q_InitProgs(); //reinitialize progs entirly.
|
||||
else
|
||||
{
|
||||
|
@ -322,7 +409,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
strcpy(file, "loadgame");
|
||||
clnum=VFS_READ(f, file+8, filelen);
|
||||
file[filelen+8]='\0';
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL);
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL, SV_Legacy_ExtendedSaveData);
|
||||
BZ_Free(file);
|
||||
|
||||
PR_LoadGlabalStruct(false);
|
||||
|
@ -332,7 +419,7 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
|
||||
VFS_CLOSE(f);
|
||||
|
||||
//FIXME: DP saved games have some / *\nkey values\nkey values\n* / thing in them to save precaches and stuff
|
||||
//FIXME: QSS+DP saved games have some / *\nkey values\nkey values\n* / thing in them to save precaches and stuff
|
||||
|
||||
World_ClearWorld(&sv.world, true);
|
||||
|
||||
|
@ -362,16 +449,17 @@ static void SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
|
|||
cl->playerclass = 0;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SV_LegacySavegame (const char *savename)
|
||||
static qboolean SV_LegacySavegame (const char *savename)
|
||||
{
|
||||
size_t len;
|
||||
char *s = NULL;
|
||||
client_t *cl;
|
||||
int clnum;
|
||||
|
||||
int version = SAVEGAME_VERSION;
|
||||
int version = SAVEGAME_VERSION_FTE_LEG;
|
||||
|
||||
char native[MAX_OSPATH];
|
||||
char name[MAX_QPATH];
|
||||
|
@ -382,27 +470,26 @@ static void SV_LegacySavegame (const char *savename)
|
|||
if (sv.state != ss_active)
|
||||
{
|
||||
Con_TPrintf("Can't apply: Server isn't running or is still loading\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sv.allocated_client_slots != 1 || svs.clients->state != cs_spawned)
|
||||
{
|
||||
//we don't care about fte-format legacy.
|
||||
Con_TPrintf("Unable to use legacy savegame format to save multiplayer games\n");
|
||||
SV_Savegame_f();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf (name, "%s", savename);
|
||||
COM_RequireExtension (name, ".sav", sizeof(name)); //do NOT allow .pak etc
|
||||
if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native)))
|
||||
return;
|
||||
return false;
|
||||
Con_TPrintf (U8("Saving game to %s...\n"), native);
|
||||
f = FS_OpenVFS(name, "wbp", FS_GAMEONLY);
|
||||
if (!f)
|
||||
{
|
||||
Con_TPrintf ("ERROR: couldn't open %s.\n", name);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
//if there are 1 of 1 players connected
|
||||
|
@ -412,9 +499,9 @@ static void SV_LegacySavegame (const char *savename)
|
|||
if (s)
|
||||
{
|
||||
if (progstype == PROG_QW)
|
||||
version = 6;
|
||||
version = SAVEGAME_VERSION_QW;
|
||||
else
|
||||
version = 5;
|
||||
version = SAVEGAME_VERSION_NQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,7 +510,7 @@ static void SV_LegacySavegame (const char *savename)
|
|||
SV_SavegameComment (comment, sizeof(comment));
|
||||
VFS_PRINTF(f, "%s\n", comment);
|
||||
|
||||
if (version != SAVEGAME_VERSION)
|
||||
if (version == SAVEGAME_VERSION_NQ || version == SAVEGAME_VERSION_QW)
|
||||
{
|
||||
//only 16 spawn parms.
|
||||
for (i=0; i < 16; i++)
|
||||
|
@ -467,31 +554,46 @@ static void SV_LegacySavegame (const char *savename)
|
|||
s = PR_SaveEnts(svprogfuncs, NULL, &len, 0, 1);
|
||||
VFS_PUTS(f, s);
|
||||
VFS_PUTS(f, "\n");
|
||||
/*
|
||||
// DarkPlaces extended savegame
|
||||
sv.lightstyles %i %s
|
||||
sv.model_precache %i %s
|
||||
sv.sound_precache %i %s
|
||||
sv.buffer %i %i "string"
|
||||
sv.bufstr %i %i "%s"
|
||||
|
||||
#if 1
|
||||
/* Extended save info
|
||||
** This should also be compatible with both DP and QSS.
|
||||
** WARNING: this does NOT protect against models/sounds being precached in different/random orders (statics/baselines/ambients will be wrong).
|
||||
** the only protection we get is from late precaches.
|
||||
** theoretically the loader could make it work by rewriting the various tables, but that would not necessarily be reliable.
|
||||
*/
|
||||
VFS_PUTS(f, "/*\n");
|
||||
VFS_PUTS(f, "// FTE extended savegame\n");
|
||||
for (i=0 ; i < countof(sv.strings.lightstyles); i++)
|
||||
{ //yes, repeat styles 0-63 again, for some reason, but only list ones that are not empty.
|
||||
if (sv.strings.lightstyles[i])
|
||||
VFS_PRINTF(f, "sv.lightstyles %i %s\n", i, sv.strings.lightstyles[i]);
|
||||
}
|
||||
for (i=1 ; i < countof(sv.strings.model_precache); i++)
|
||||
{
|
||||
if (sv.strings.model_precache[i])
|
||||
VFS_PRINTF(f, "sv.model_precache %i %s\n", i, sv.strings.model_precache[i]);
|
||||
}
|
||||
for (i=1 ; i < countof(sv.strings.sound_precache); i++)
|
||||
{
|
||||
if (sv.strings.sound_precache[i])
|
||||
VFS_PRINTF(f, "sv.lightstyles %i %s\n", i, sv.strings.sound_precache[i]);
|
||||
}
|
||||
// sv.buffer %i %i "string"
|
||||
// sv.bufstr %i %i "%s"
|
||||
VFS_PUTS(f, "*/\n");
|
||||
#endif
|
||||
svprogfuncs->parms->memfree(s);
|
||||
|
||||
VFS_CLOSE(f);
|
||||
|
||||
FS_FlushFSHashWritten(name);
|
||||
|
||||
Q_strncpyz(sv.loadgame_on_restart, savename, sizeof(sv.loadgame_on_restart));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define CACHEGAME_VERSION_OLD 513
|
||||
#define CACHEGAME_VERSION_VERBOSE 514
|
||||
#define CACHEGAME_VERSION_BINARY 515
|
||||
|
||||
|
||||
|
||||
|
||||
void SV_FlushLevelCache(void)
|
||||
{
|
||||
levelcache_t *cache;
|
||||
|
@ -701,35 +803,83 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
version = atoi(str);
|
||||
if (version != CACHEGAME_VERSION_OLD)
|
||||
if (version != CACHEGAME_VERSION_OLD && version != CACHEGAME_VERSION_VERBOSE)
|
||||
{
|
||||
VFS_CLOSE (f);
|
||||
Con_TPrintf ("Savegame is version %i, not %i\n", version, CACHEGAME_VERSION_OLD);
|
||||
Con_TPrintf ("Savegame is version %i, not %i\n", version, CACHEGAME_VERSION_DEFAULT);
|
||||
return false;
|
||||
}
|
||||
VFS_GETS(f, str, sizeof(str)); //comment
|
||||
|
||||
SV_SendMessagesToAll();
|
||||
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
pt = atof(str);
|
||||
if (version == CACHEGAME_VERSION_OLD)
|
||||
{
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
pt = atof(str);
|
||||
|
||||
// this silliness is so we can load 1.06 save files, which have float skill values
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
current_skill = (int)(atof(str) + 0.1);
|
||||
Cvar_Set (&skill, va("%i", current_skill));
|
||||
// this silliness is so we can load 1.06 save files, which have float skill values
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
current_skill = (int)(atof(str) + 0.1);
|
||||
Cvar_Set (&skill, va("%i", current_skill));
|
||||
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&deathmatch, atof(str));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&coop, atof(str));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&teamplay, atof(str));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&deathmatch, atof(str));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&coop, atof(str));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
Cvar_SetValue (&teamplay, atof(str));
|
||||
|
||||
VFS_GETS(f, mapname, sizeof(mapname));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
time = atof(str);
|
||||
VFS_GETS(f, mapname, sizeof(mapname));
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
time = atof(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
time = 0;
|
||||
pt = PROG_UNKNOWN;
|
||||
while (VFS_GETS(f, str, sizeof(str)))
|
||||
{
|
||||
char *s = str;
|
||||
cvar_t *var;
|
||||
s = COM_Parse(s);
|
||||
if (!strcmp(com_token, "map"))
|
||||
{ //map "foo": terminates the preamble.
|
||||
COM_ParseOut(s, mapname, sizeof(mapname));
|
||||
break;
|
||||
}
|
||||
else if (!strcmp(com_token, "cvar"))
|
||||
{
|
||||
s = COM_Parse(s);
|
||||
var = Cvar_FindVar(com_token);
|
||||
s = COM_Parse(s);
|
||||
if (var)
|
||||
Cvar_Set(var, com_token);
|
||||
}
|
||||
else if (!strcmp(com_token, "time"))
|
||||
{
|
||||
s = COM_Parse(s);
|
||||
time = atof(com_token);
|
||||
}
|
||||
else if (!strcmp(com_token, "vmmode"))
|
||||
{
|
||||
s = COM_Parse(s);
|
||||
if (!strcmp(com_token, "NONE")) pt = PROG_NONE;
|
||||
else if (!strcmp(com_token, "QW")) pt = PROG_QW;
|
||||
else if (!strcmp(com_token, "NQ")) pt = PROG_NQ;
|
||||
else if (!strcmp(com_token, "H2")) pt = PROG_H2;
|
||||
else if (!strcmp(com_token, "PREREL")) pt = PROG_PREREL;
|
||||
else if (!strcmp(com_token, "TENEBRAE")) pt = PROG_TENEBRAE;
|
||||
else if (!strcmp(com_token, "UNKNOWN")) pt = PROG_UNKNOWN;
|
||||
else pt = PROG_UNKNOWN;
|
||||
}
|
||||
else
|
||||
Con_TPrintf ("Unknown savegame directive %s\n", com_token);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: This sets up the default baselines+statics+ambients.
|
||||
//FIXME: if any model names changed, then we're screwed.
|
||||
SV_SpawnServer (mapname, startspot, false, false);
|
||||
sv.time = time;
|
||||
if (svs.gametype != gametype)
|
||||
|
@ -744,20 +894,6 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
return false;
|
||||
}
|
||||
|
||||
// sv.paused = true; // pause until all clients connect
|
||||
// sv.loadgame = true;
|
||||
|
||||
// load the light styles
|
||||
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
numstyles = atoi(str);
|
||||
if (numstyles > MAX_LIGHTSTYLES)
|
||||
{
|
||||
VFS_CLOSE (f);
|
||||
Con_Printf ("load failed - invalid number of lightstyles\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// load the edicts out of the savegame file
|
||||
// the rest of the file is sent directly to the progs engine.
|
||||
|
||||
|
@ -770,25 +906,39 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
PR_InitEnts(svprogfuncs, sv.world.max_edicts);
|
||||
}
|
||||
|
||||
for (i = 0; i<MAX_LIGHTSTYLES ; i++)
|
||||
{
|
||||
if (sv.strings.lightstyles[i])
|
||||
BZ_Free((void*)sv.strings.lightstyles[i]);
|
||||
sv.strings.lightstyles[i] = NULL;
|
||||
}
|
||||
|
||||
for (i=0 ; i<numstyles ; i++)
|
||||
if (version == CACHEGAME_VERSION_OLD)
|
||||
{
|
||||
// load the light styles
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
sv.strings.lightstyles[i] = Z_StrDup(str);
|
||||
}
|
||||
for ( ; i<MAX_LIGHTSTYLES ; i++)
|
||||
{
|
||||
sv.strings.lightstyles[i] = Z_StrDup("");
|
||||
}
|
||||
numstyles = atoi(str);
|
||||
if (numstyles > MAX_LIGHTSTYLES)
|
||||
{
|
||||
VFS_CLOSE (f);
|
||||
Con_Printf ("load failed - invalid number of lightstyles\n");
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i<MAX_LIGHTSTYLES ; i++)
|
||||
{
|
||||
if (sv.strings.lightstyles[i])
|
||||
BZ_Free((void*)sv.strings.lightstyles[i]);
|
||||
sv.strings.lightstyles[i] = NULL;
|
||||
}
|
||||
|
||||
modelpos = VFS_TELL(f);
|
||||
LoadModelsAndSounds(f);
|
||||
for (i=0 ; i<numstyles ; i++)
|
||||
{
|
||||
VFS_GETS(f, str, sizeof(str));
|
||||
sv.strings.lightstyles[i] = Z_StrDup(str);
|
||||
}
|
||||
for ( ; i<MAX_LIGHTSTYLES ; i++)
|
||||
{
|
||||
sv.strings.lightstyles[i] = Z_StrDup("");
|
||||
}
|
||||
|
||||
modelpos = VFS_TELL(f);
|
||||
LoadModelsAndSounds(f);
|
||||
}
|
||||
else
|
||||
modelpos = 0;
|
||||
|
||||
filepos = VFS_TELL(f);
|
||||
filelen = VFS_GETLEN(f);
|
||||
|
@ -797,7 +947,7 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
memset(file, 0, filelen+1);
|
||||
VFS_READ(f, file, filelen);
|
||||
file[filelen]='\0';
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL);
|
||||
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL, SV_Legacy_ExtendedSaveData);
|
||||
BZ_Free(file);
|
||||
|
||||
progstype = pt;
|
||||
|
@ -807,8 +957,11 @@ qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *
|
|||
pr_global_struct->time = sv.time = sv.world.physicstime = time;
|
||||
sv.starttime = Sys_DoubleTime() - sv.time;
|
||||
|
||||
VFS_SEEK(f, modelpos);
|
||||
LoadModelsAndSounds(f);
|
||||
if (modelpos != 0)
|
||||
{
|
||||
VFS_SEEK(f, modelpos);
|
||||
LoadModelsAndSounds(f);
|
||||
}
|
||||
|
||||
VFS_CLOSE(f);
|
||||
|
||||
|
@ -918,7 +1071,7 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
int i;
|
||||
char comment[SAVEGAME_COMMENT_LENGTH+1];
|
||||
levelcache_t *cache;
|
||||
int version = CACHEGAME_VERSION_OLD;
|
||||
int version = CACHEGAME_VERSION_DEFAULT;
|
||||
|
||||
if (!sv.state)
|
||||
return;
|
||||
|
@ -1078,44 +1231,13 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
case PROG_TENEBRAE: mode = "TENEBRAE"; break;
|
||||
case PROG_UNKNOWN: mode = "UNKNOWN"; break;
|
||||
}
|
||||
VFS_PRINTF (f, "vmmode %s\n", COM_QuotedString(mode, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "skill %s\n", COM_QuotedString(skill.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "deathmatch %s\n", COM_QuotedString(deathmatch.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "coop %s\n", COM_QuotedString(coop.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "teamplay %s\n", COM_QuotedString(teamplay.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "map %s\n", COM_QuotedString(svs.name, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "time %f\n", sv.time);
|
||||
|
||||
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
|
||||
if (sv.strings.lightstyles[i])
|
||||
VFS_PRINTF (f, "lstyle %i %s %f %f %f\n", i, COM_QuotedString(sv.strings.lightstyles[i], buf, sizeof(buf), false), sv.lightstylecolours[i][0], sv.lightstylecolours[i][1], sv.lightstylecolours[i][2]);
|
||||
for (i=1 ; i<MAX_PRECACHE_MODELS ; i++)
|
||||
if (sv.strings.model_precache[i] && *sv.strings.model_precache[i])
|
||||
VFS_PRINTF (f, "model %i %s\n", i, COM_QuotedString(sv.strings.model_precache[i], buf, sizeof(buf), false));
|
||||
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
|
||||
if (sv.strings.sound_precache[i] && *sv.strings.sound_precache[i])
|
||||
VFS_PRINTF (f, "sound %i %s\n", i, COM_QuotedString(sv.strings.sound_precache[i], buf, sizeof(buf), false));
|
||||
for (i=1 ; i<MAX_SSPARTICLESPRE ; i++)
|
||||
if (sv.strings.particle_precache[i] && *sv.strings.particle_precache[i])
|
||||
VFS_PRINTF (f, "particles %i %s\n", i, sv.strings.particle_precache[i]);
|
||||
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
|
||||
VFS_PRINTF (f, "vwep %i %s\n", i, COM_QuotedString(sv.strings.vw_model_precache[i], buf, sizeof(buf), false));
|
||||
|
||||
PR_Common_SaveGame(f, svprogfuncs, version >= CACHEGAME_VERSION_BINARY);
|
||||
|
||||
//FIXME: string buffers
|
||||
//FIXME: hash tables
|
||||
//FIXME: skeletal objects?
|
||||
//FIXME: static entities
|
||||
//FIXME: midi track
|
||||
//FIXME: custom temp-ents?
|
||||
//FIXME: pending uri_gets? (if only just to report fails on load)
|
||||
//FIXME: routing calls?
|
||||
//FIXME: sql queries?
|
||||
//FIXME: frik files?
|
||||
//FIXME: qc threads?
|
||||
|
||||
VFS_PRINTF (f, "entities\n");
|
||||
VFS_PRINTF (f, "vmmode %s\n", COM_QuotedString(mode, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "cvar skill %s\n", COM_QuotedString(skill.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "cvar deathmatch %s\n", COM_QuotedString(deathmatch.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "cvar coop %s\n", COM_QuotedString(coop.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "cvar teamplay %s\n", COM_QuotedString(teamplay.string, buf, sizeof(buf), false));
|
||||
VFS_PRINTF (f, "time %f\n", sv.time);
|
||||
VFS_PRINTF (f, "map %s\n", COM_QuotedString(svs.name, buf, sizeof(buf), false));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1165,6 +1287,43 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
svprogfuncs->parms->memfree(s);
|
||||
}
|
||||
|
||||
if (version >= CACHEGAME_VERSION_VERBOSE)
|
||||
{
|
||||
char buf[8192];
|
||||
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
|
||||
if (sv.strings.lightstyles[i])
|
||||
VFS_PRINTF (f, "lightstyle %i %s %f %f %f\n", i, COM_QuotedString(sv.strings.lightstyles[i], buf, sizeof(buf), false), sv.lightstylecolours[i][0], sv.lightstylecolours[i][1], sv.lightstylecolours[i][2]);
|
||||
for (i=1 ; i<MAX_PRECACHE_MODELS ; i++)
|
||||
if (sv.strings.model_precache[i] && *sv.strings.model_precache[i])
|
||||
VFS_PRINTF (f, "model %i %s\n", i, COM_QuotedString(sv.strings.model_precache[i], buf, sizeof(buf), false));
|
||||
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
|
||||
if (sv.strings.sound_precache[i] && *sv.strings.sound_precache[i])
|
||||
VFS_PRINTF (f, "sound %i %s\n", i, COM_QuotedString(sv.strings.sound_precache[i], buf, sizeof(buf), false));
|
||||
for (i=1 ; i<MAX_SSPARTICLESPRE ; i++)
|
||||
if (sv.strings.particle_precache[i] && *sv.strings.particle_precache[i])
|
||||
VFS_PRINTF (f, "particle %i %s\n", i, COM_QuotedString(sv.strings.particle_precache[i], buf, sizeof(buf), false));
|
||||
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
|
||||
if (sv.strings.vw_model_precache[i])
|
||||
VFS_PRINTF (f, "vwep %i %s\n", i, COM_QuotedString(sv.strings.vw_model_precache[i], buf, sizeof(buf), false));
|
||||
|
||||
PR_Common_SaveGame(f, svprogfuncs, version >= CACHEGAME_VERSION_BINARY);
|
||||
|
||||
//FIXME: string buffers
|
||||
//FIXME: hash tables
|
||||
//FIXME: skeletal objects?
|
||||
//FIXME: static entities
|
||||
//FIXME: midi track
|
||||
//FIXME: custom temp-ents?
|
||||
//FIXME: pending uri_gets? (if only just to report fails on load)
|
||||
//FIXME: routing calls?
|
||||
//FIXME: sql queries?
|
||||
//FIXME: frik files?
|
||||
//FIXME: qc threads?
|
||||
|
||||
// portalblobsize = CM_WritePortalState(sv.world.worldmodel, &portalblob);
|
||||
// VFS_WRITE(f, portalblob, portalblobsize);
|
||||
}
|
||||
|
||||
VFS_CLOSE (f);
|
||||
|
||||
|
||||
|
@ -1180,8 +1339,6 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
|
|||
FS_FlushFSHashWritten(name);
|
||||
}
|
||||
|
||||
#define FTESAVEGAME_VERSION 25000
|
||||
|
||||
//mapchange is true for Q2's map-change autosaves.
|
||||
void SV_Savegame (const char *savename, qboolean mapchange)
|
||||
{
|
||||
|
@ -1209,14 +1366,6 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
levelcache_t *cache;
|
||||
char *savefilename;
|
||||
|
||||
#ifndef QUAKETC
|
||||
if (!sv_savefmt.ival && !mapchange)
|
||||
{
|
||||
SV_LegacySavegame(savename);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sv.state || sv.state == ss_clustermode)
|
||||
{
|
||||
Con_Printf("Server is not active - unable to save\n");
|
||||
|
@ -1228,6 +1377,22 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef QUAKETC
|
||||
{
|
||||
int savefmt = sv_savefmt.ival;
|
||||
if (!*sv_savefmt.string && (svs.gametype != GT_PROGS || progstype == PROG_H2 || svs.levcache))
|
||||
savefmt = 1; //hexen2+q2/etc must not use the legacy format by default. can't use it when using any kind of hub system either (harder to detect upfront, which might give confused saved game naming but will at least work).
|
||||
else
|
||||
savefmt = sv_savefmt.ival;
|
||||
if (!savefmt && !mapchange)
|
||||
{
|
||||
if (SV_LegacySavegame(savename))
|
||||
return;
|
||||
Con_Printf("Unable to use legacy saved game format\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(svs.gametype)
|
||||
{
|
||||
default:
|
||||
|
@ -1265,7 +1430,7 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
return;
|
||||
}
|
||||
SV_SavegameComment(comment, sizeof(comment));
|
||||
VFS_PRINTF (f, "%d\n", FTESAVEGAME_VERSION+svs.gametype);
|
||||
VFS_PRINTF (f, "%d\n", SAVEGAME_VERSION_FTE_HUB+svs.gametype);
|
||||
VFS_PRINTF (f, "%s\n", comment);
|
||||
|
||||
VFS_PRINTF(f, "%i\n", sv.allocated_client_slots);
|
||||
|
@ -1285,9 +1450,31 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
VFS_PRINTF(f, "%s\n", cl->name);
|
||||
|
||||
if (*cl->name)
|
||||
for (len = 0; len < NUM_SPAWN_PARMS; len++)
|
||||
VFS_PRINTF(f, "%i (%f)\n", *(int*)&cl->spawn_parms[len], cl->spawn_parms[len]); //write ints as not everyone passes a float in the parms.
|
||||
//write floats too so you can use it to debug.
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
char tmp[65536];
|
||||
VFS_PRINTF(f, "{\n");
|
||||
for (len = 0; len < NUM_SPAWN_PARMS; len++)
|
||||
VFS_PRINTF(f, "\tparm%i 0x%x //%.9g\n", len, *(int*)&cl->spawn_parms[len], cl->spawn_parms[len]); //write hex as not everyone passes a float in the parms.
|
||||
VFS_PRINTF(f, "\tparm_string %s\n", COM_QuotedString(cl->spawn_parmstring?cl->spawn_parmstring:"", tmp, sizeof(tmp), false));
|
||||
/*if (cl->spawninfo)
|
||||
{
|
||||
VFS_PRINTF(f, "\tspawninfo %s\n", COM_QuotedString(cl->spawninfo, tmp, sizeof(tmp), false));
|
||||
VFS_PRINTF(f, "\tspawninfotime %9g\n", cl->spawninfotime);
|
||||
}*/
|
||||
VFS_PRINTF(f, "}\n"); //write ints as not everyone passes a float in the parms.
|
||||
}
|
||||
else
|
||||
{
|
||||
for (len = 0; len < NUM_SPAWN_PARMS; len++)
|
||||
VFS_PRINTF(f, "%i (%f)\n", *(int*)&cl->spawn_parms[len], cl->spawn_parms[len]); //write ints as not everyone passes a float in the parms.
|
||||
//write floats too so you can use it to debug.
|
||||
//FIXME: spawn_parmstring
|
||||
//FIXME: spawninfo[time] (for hexen2)
|
||||
//FIXME: startspot...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InfoBuf_WriteToFile(f, &svs.info, NULL, 0);
|
||||
|
@ -1414,6 +1601,8 @@ void SV_Savegame (const char *savename, qboolean mapchange)
|
|||
//fixme
|
||||
FS_FlushFSHashFull();
|
||||
}
|
||||
|
||||
Q_strncpyz(sv.loadgame_on_restart, savename, sizeof(sv.loadgame_on_restart));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1464,10 +1653,13 @@ void SV_Savegame_f (void)
|
|||
}
|
||||
#ifndef QUAKETC
|
||||
if (!Q_strcasecmp(Cmd_Argv(0), "savegame_legacy"))
|
||||
SV_LegacySavegame(savename);
|
||||
else
|
||||
{
|
||||
if (SV_LegacySavegame(savename))
|
||||
return;
|
||||
Con_Printf("Unable to use legacy save format\n");
|
||||
}
|
||||
#endif
|
||||
SV_Savegame(savename, false);
|
||||
SV_Savegame(savename, false);
|
||||
}
|
||||
else
|
||||
Con_Printf("%s: invalid number of arguments\n", Cmd_Argv(0));
|
||||
|
@ -1527,7 +1719,8 @@ void SV_AutoSave(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
void SV_Loadgame_f (void)
|
||||
//Attempts to load a named saved game.
|
||||
qboolean SV_Loadgame (const char *unsafe_savename)
|
||||
{
|
||||
levelcache_t *cache;
|
||||
unsigned char str[MAX_LOCALINFO_STRING+1], *trim;
|
||||
|
@ -1555,16 +1748,7 @@ void SV_Loadgame_f (void)
|
|||
};
|
||||
int bd,best;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
if (!Renderer_Started() && !isDedicated)
|
||||
{
|
||||
Cbuf_AddText(va("wait;%s %s\n", Cmd_Argv(0), Cmd_Args()), Cmd_ExecLevel);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Q_strncpyz(savename, Cmd_Argv(1), sizeof(savename));
|
||||
|
||||
Q_strncpyz(savename, unsafe_savename, sizeof(savename));
|
||||
if (!*savename || strstr(savename, ".."))
|
||||
strcpy(savename, "quick");
|
||||
|
||||
|
@ -1583,7 +1767,7 @@ void SV_Loadgame_f (void)
|
|||
if (!f)
|
||||
{
|
||||
Con_TPrintf ("ERROR: couldn't open %s.\n", filename);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(MENU_DAT) && !defined(SERVERONLY)
|
||||
|
@ -1592,18 +1776,23 @@ void SV_Loadgame_f (void)
|
|||
|
||||
VFS_GETS(f, str, sizeof(str)-1);
|
||||
version = atoi(str);
|
||||
if (version < FTESAVEGAME_VERSION || version >= FTESAVEGAME_VERSION+GT_MAX)
|
||||
if (version < SAVEGAME_VERSION_FTE_HUB || version >= SAVEGAME_VERSION_FTE_HUB+GT_MAX)
|
||||
{
|
||||
#ifdef QUAKETC
|
||||
VFS_CLOSE (f);
|
||||
Con_TPrintf ("Unable to load savegame of version %i\n", version);
|
||||
return false;
|
||||
#else
|
||||
SV_Loadgame_Legacy(filename, f, version);
|
||||
if (SV_Loadgame_Legacy(filename, f, version))
|
||||
{
|
||||
Q_strncpyz(sv.loadgame_on_restart, savename, sizeof(sv.loadgame_on_restart));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
gametype = version - FTESAVEGAME_VERSION;
|
||||
gametype = version - SAVEGAME_VERSION_FTE_HUB;
|
||||
VFS_GETS(f, str, sizeof(str)-1);
|
||||
#ifndef SERVERONLY
|
||||
if (!cls.state)
|
||||
|
@ -1676,6 +1865,32 @@ void SV_Loadgame_f (void)
|
|||
for (len = 0; len < NUM_SPAWN_PARMS; len++)
|
||||
{
|
||||
VFS_GETS(f, str, sizeof(str)-1);
|
||||
if (*str == '{')
|
||||
{
|
||||
while(VFS_GETS(f, str, sizeof(str)-1))
|
||||
{
|
||||
if (*str == '}')
|
||||
break;
|
||||
trim = COM_Parse(str);
|
||||
if (!strcmp(com_token, "parm_string"))
|
||||
{
|
||||
COM_Parse(str);
|
||||
cl->spawn_parmstring = Z_StrDup(com_token);
|
||||
}
|
||||
else if (!strncmp(com_token, "parm", 4) && (unsigned)atoi(com_token+4) < NUM_SPAWN_PARMS)
|
||||
{
|
||||
COM_Parse(str);
|
||||
len = atoi(com_token+4);
|
||||
if (!strncmp(com_token, "0x", 2))
|
||||
*(int*)&cl->spawn_parms[len] = strtoul(com_token, NULL, 16);
|
||||
else
|
||||
cl->spawn_parms[len] = strtod(com_token, NULL);
|
||||
}
|
||||
else
|
||||
Con_Printf("Unknown player data: %s\n", com_token);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (trim = str+strlen(str)-1; trim>=str && *trim <= ' '; trim--)
|
||||
*trim='\0';
|
||||
for (trim = str; *trim <= ' ' && *trim; trim++)
|
||||
|
@ -1802,5 +2017,21 @@ void SV_Loadgame_f (void)
|
|||
sv.spawned_client_slots += loadzombies;
|
||||
|
||||
sv.autosave_time = sv.time + sv_autosave.value*60;
|
||||
|
||||
Q_strncpyz(sv.loadgame_on_restart, savename, sizeof(sv.loadgame_on_restart));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SV_Loadgame_f (void)
|
||||
{
|
||||
#ifndef SERVERONLY
|
||||
if (!Renderer_Started() && !isDedicated)
|
||||
{
|
||||
Cbuf_AddText(va("wait;%s %s\n", Cmd_Argv(0), Cmd_Args()), Cmd_ExecLevel);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
SV_Loadgame(Cmd_Argv(1));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -140,6 +140,8 @@ typedef struct
|
|||
char mapname[256]; // text description of the map
|
||||
char modelname[MAX_QPATH]; // maps/<name>.bsp, for model_precache[0]
|
||||
|
||||
char loadgame_on_restart[MAX_QPATH]; //saved game to load on map_restart
|
||||
|
||||
world_t world;
|
||||
|
||||
union {
|
||||
|
@ -866,12 +868,12 @@ typedef struct bannedips_s {
|
|||
typedef enum {
|
||||
GT_PROGS, //q1, qw, h2 are similar enough that we consider it only one game mode. (We don't support the h2 protocol)
|
||||
GT_Q1QVM,
|
||||
#ifdef VM_LUA
|
||||
GT_LUA, //for the luls
|
||||
#endif
|
||||
GT_HALFLIFE,
|
||||
GT_QUAKE2, //q2 servers run from a q2 game dll
|
||||
GT_QUAKE3, //q3 servers run off the q3 qvm api
|
||||
#ifdef VM_LUA
|
||||
GT_LUA, //for the luls
|
||||
#endif
|
||||
GT_MAX
|
||||
} gametype_e;
|
||||
|
||||
|
@ -879,6 +881,7 @@ typedef struct levelcache_s {
|
|||
struct levelcache_s *next;
|
||||
char *mapname;
|
||||
gametype_e gametype;
|
||||
unsigned char savedplayers[(MAX_CLIENTS+7)>>3]; //bitmask to say which players are actually stored in the cache. so that restarts can restore.
|
||||
} levelcache_t;
|
||||
|
||||
#ifdef TCPCONNECT
|
||||
|
@ -1577,6 +1580,7 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade
|
|||
void SV_Savegame_f (void);
|
||||
void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx);
|
||||
void SV_Loadgame_f (void);
|
||||
qboolean SV_Loadgame (const char *unsafe_savename);
|
||||
void SV_AutoSave(void);
|
||||
void SV_FlushLevelCache(void);
|
||||
extern cvar_t sv_autosave;
|
||||
|
|
|
@ -450,12 +450,29 @@ command from the console or progs.
|
|||
quirks:
|
||||
a leading '*' means new unit, meaning all old map state is flushed regardless of startspot
|
||||
a '+' means 'set nextmap cvar to the following value and otherwise ignore, for q2 compat. only applies if there's also a '.' and the specified bsp doesn't exist, for q1 compat.
|
||||
just a '.' is taken to mean 'restart'. parms are not changed from their current values, startspot is also unchanged.
|
||||
just a '.' is taken to mean 'restart'. parms are not changed from their current values, startspot is also unchanged. Loads the last saved game instead when applicable.
|
||||
|
||||
'map' will change map, for most games. strips parms+serverflags+cache. note that NQ kicks everyone (NQ expects you to use changelevel for that).
|
||||
variations:
|
||||
'map' will change map, for most games. strips parms+serverflags+cache. note that vanilla NQ kicks everyone (NQ expects you to use changelevel for that).
|
||||
'changelevel' will not flush the level cache, for h2 compat (won't save current level state in such a situation, as nq would prefer not)
|
||||
'gamemap' will save the game to 'save0' after loading, for q2 compat
|
||||
'spmap' is for q3 and sets 'gametype' to '2', otherwise identical to 'map'. all other map commands will reset it to '0' if its '2' at the time.
|
||||
'map_restart' restarts the current map. Name is needed for q3 compat.
|
||||
'restart' is an alias for 'map_restart'. Exists for NQ compat, but as an alias for QW mods that tried to use it for mod-specific things.
|
||||
|
||||
hexen2 fixme:
|
||||
'restart restore' restarts the map, reloading from a saved game if applicable.
|
||||
'restart' forgets the current map (potentially breaking the game). we don't care much for that behaviour (could make it a 'restart unit' I guess).
|
||||
|
||||
quake2:
|
||||
'gamemap [*]foo.dm2[$spot][+nextserver]'
|
||||
* == new unit
|
||||
$ == start spot
|
||||
+ == value for nextserver cvar (used for cinematics).
|
||||
'map' is always a new unit.
|
||||
|
||||
quake:
|
||||
+ is used in certain map names. * cannot be, but $ potentially could be.
|
||||
======================
|
||||
*/
|
||||
void SV_Map_f (void)
|
||||
|
@ -523,7 +540,9 @@ void SV_Map_f (void)
|
|||
|
||||
sv.mapchangelocked = false;
|
||||
|
||||
if (strcmp(level, ".")) //restart current
|
||||
if (!strcmp(level, "."))
|
||||
;//restart current
|
||||
else
|
||||
{
|
||||
snprintf (expanded, sizeof(expanded), "maps/%s.bsp", level); // this function and the if statement below, is a quake bugfix which stopped a map called "dm6++.bsp" from loading because of the + sign, quake2 map syntax interprets + character as "intro.cin+base1.bsp", to play a cinematic then load a map after
|
||||
if (!COM_FCheckExists (expanded))
|
||||
|
@ -584,6 +603,14 @@ void SV_Map_f (void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SAVEDGAMES
|
||||
if (isrestart && *sv.loadgame_on_restart && SV_Loadgame(sv.loadgame_on_restart))
|
||||
{ //we managed to reload a saved game instead!
|
||||
//this is required in order to keep hub state consistent (dying mid-map would require saved games to store both current and start of map(not to be confused with initial state, which would be trivial))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// check to make sure the level exists
|
||||
if (*level == '*')
|
||||
{
|
||||
|
@ -644,7 +671,7 @@ void SV_Map_f (void)
|
|||
if (!exts[i])
|
||||
{
|
||||
// FTE is still a Quake engine so report BSP missing
|
||||
snprintf (expanded, sizeof(expanded), exts[0], level);
|
||||
snprintf (expanded, sizeof(expanded), exts[1], level);
|
||||
Con_TPrintf ("Can't find %s\n", expanded);
|
||||
#ifndef SERVERONLY
|
||||
SCR_SetLoadingStage(LS_NONE);
|
||||
|
@ -785,11 +812,9 @@ void SV_Map_f (void)
|
|||
}
|
||||
|
||||
SCR_SetLoadingFile("spawnserver");
|
||||
if (newunit || !startspot || cinematic
|
||||
#ifdef SAVEDGAMES
|
||||
|| !SV_LoadLevelCache(NULL, level, startspot, false)
|
||||
if (newunit || !startspot || cinematic || !SV_LoadLevelCache(NULL, level, startspot, false))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (waschangelevel && !startspot)
|
||||
startspot = "";
|
||||
|
@ -1951,6 +1976,12 @@ static void SV_Status_f (void)
|
|||
if (!sv.strings.sound_precache[count])
|
||||
break;
|
||||
Con_Printf("sounds : %i/%i\n", count, MAX_PRECACHE_SOUNDS);
|
||||
|
||||
for (count = 1; count < MAX_SSPARTICLESPRE; count++)
|
||||
if (!sv.strings.particle_precache[count])
|
||||
break;
|
||||
if (count!=1)
|
||||
Con_Printf("particles : %i/%i\n", count, MAX_SSPARTICLESPRE);
|
||||
}
|
||||
Con_Printf("gamedir : %s\n", FS_GetGamedir(true));
|
||||
if (sv.csqcdebug)
|
||||
|
@ -2882,25 +2913,38 @@ void SV_ReallyEvilHack_f(void)
|
|||
void SV_PrecacheList_f(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
|
||||
char *group = Cmd_Argv(1);
|
||||
if (!*group || !strncmp(group, "vwep", 4))
|
||||
{
|
||||
if (sv.strings.vw_model_precache[i])
|
||||
Con_Printf("vweap %u: %s\n", i, sv.strings.vw_model_precache[i]);
|
||||
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
|
||||
{
|
||||
if (sv.strings.vw_model_precache[i])
|
||||
Con_Printf("vwep %u: %s\n", i, sv.strings.vw_model_precache[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_PRECACHE_MODELS; i++)
|
||||
if (!*group || !strncmp(group, "model", 5))
|
||||
{
|
||||
if (sv.strings.model_precache[i])
|
||||
Con_Printf("model %u: %s\n", i, sv.strings.model_precache[i]);
|
||||
for (i = 0; i < MAX_PRECACHE_MODELS; i++)
|
||||
{
|
||||
if (sv.strings.model_precache[i])
|
||||
Con_Printf("model %u: %s\n", i, sv.strings.model_precache[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_PRECACHE_SOUNDS; i++)
|
||||
if (!*group || !strncmp(group, "sound", 5))
|
||||
{
|
||||
if (sv.strings.sound_precache[i])
|
||||
Con_Printf("sound %u: %s\n", i, sv.strings.sound_precache[i]);
|
||||
for (i = 0; i < MAX_PRECACHE_SOUNDS; i++)
|
||||
{
|
||||
if (sv.strings.sound_precache[i])
|
||||
Con_Printf("sound %u: %s\n", i, sv.strings.sound_precache[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_SSPARTICLESPRE; i++)
|
||||
if (!*group || !strncmp(group, "part", 4))
|
||||
{
|
||||
if (sv.strings.particle_precache[i])
|
||||
Con_Printf("pticl %u: %s\n", i, sv.strings.particle_precache[i]);
|
||||
for (i = 0; i < MAX_SSPARTICLESPRE; i++)
|
||||
{
|
||||
if (sv.strings.particle_precache[i])
|
||||
Con_Printf("part %u: %s\n", i, sv.strings.particle_precache[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -898,8 +898,8 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
|
|||
#ifndef SERVERONLY
|
||||
cl.worldmodel = NULL;
|
||||
r_worldentity.model = NULL;
|
||||
if (0)
|
||||
cls.state = ca_connected;
|
||||
// if (0)
|
||||
// cls.state = ca_connected;
|
||||
Surf_PreNewMap();
|
||||
#ifdef VM_CG
|
||||
CG_Stop();
|
||||
|
|
|
@ -5685,7 +5685,7 @@ void SV_ExecInitialConfigs(char *defaultexec)
|
|||
{
|
||||
Cbuf_AddText("cvar_purgedefaults\n", RESTRICT_LOCAL); //reset cvar defaults to their engine-specified values. the tail end of 'exec default.cfg' will update non-cheat defaults to mod-specified values.
|
||||
Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults
|
||||
Cbuf_AddText("alias restart \"changelevel .\"\n",RESTRICT_LOCAL);
|
||||
Cbuf_AddText("alias restart \"map_restart\"\n",RESTRICT_LOCAL);
|
||||
|
||||
Cbuf_AddText(va("sv_gamedir \"%s\"\n", FS_GetGamedir(true)), RESTRICT_LOCAL);
|
||||
|
||||
|
|
|
@ -1032,7 +1032,7 @@ int Sys_EnumerateFiles2 (const char *truepath, int apathofs, const char *match,
|
|||
dir = opendir(truepath);
|
||||
if (!dir)
|
||||
{
|
||||
Con_DPrintf("Failed to open dir %s\n", truepath);
|
||||
Con_DLPrintf((errno==ENOENT)?2:1, "Failed to open dir %s\n", truepath);
|
||||
return true;
|
||||
}
|
||||
do
|
||||
|
|
|
@ -5925,7 +5925,7 @@ typedef struct
|
|||
{
|
||||
char *name;
|
||||
void (*func) (void);
|
||||
qboolean noqchandling;
|
||||
int noqchandling;
|
||||
} ucmd_t;
|
||||
|
||||
ucmd_t ucmds[] =
|
||||
|
@ -5976,8 +5976,8 @@ ucmd_t ucmds[] =
|
|||
{"ptrack", SV_PTrack_f}, //ZOID - used with autocam
|
||||
{"snap", SV_NoSnap_f}, //cheat detection
|
||||
|
||||
{"enablecsqc", SV_EnableClientsCSQC, true},
|
||||
{"disablecsqc", SV_DisableClientsCSQC, true},
|
||||
{"enablecsqc", SV_EnableClientsCSQC, 2},
|
||||
{"disablecsqc", SV_DisableClientsCSQC, 2},
|
||||
|
||||
{"vote", SV_Vote_f},
|
||||
|
||||
|
@ -6178,15 +6178,26 @@ void SV_ExecuteUserCommand (const char *s, qboolean fromQC)
|
|||
for ( ; u->name ; u++)
|
||||
if (!strcmp (Cmd_Argv(0), u->name) )
|
||||
{
|
||||
if (u->noqchandling==2)
|
||||
{ //issue the command then let the QC handle it too
|
||||
if (!fromQC)
|
||||
{
|
||||
if (u->func)
|
||||
u->func();
|
||||
PR_KrimzonParseCommand(s);
|
||||
}
|
||||
host_client = oldhost;
|
||||
return;
|
||||
}
|
||||
if (!fromQC && !u->noqchandling)
|
||||
if (PR_KrimzonParseCommand(s)) //KRIMZON_SV_PARSECLIENTCOMMAND has the opertunity to parse out certain commands.
|
||||
if (PR_KrimzonParseCommand(s)) //KRIMZON_SV_PARSECLIENTCOMMAND has the opportunity to parse out certain commands.
|
||||
{
|
||||
host_client = oldhost;
|
||||
return;
|
||||
}
|
||||
// SV_BeginRedirect (RD_CLIENT, host_client->language);
|
||||
if (u->func)
|
||||
u->func ();
|
||||
u->func();
|
||||
host_client = oldhost;
|
||||
// SV_EndRedirect ();
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue