Added cl_autodemo cvar to automatically record games. 1 records multiview demos where possible, -1 strictly records singleview demos.

Enclosed mvd recording in ifdefs, so it can be disabled at compile-time for any mods that don't want to have to deal with it.
Removed the recorded players thing.
Allow csqc to use EF_FULLBRIGHT.
Fix cl_pure to attempt to actually download missing packages.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5303 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-09-01 04:18:08 +00:00
parent bf30886163
commit 5b7a426afe
48 changed files with 1331 additions and 795 deletions

View file

@ -919,7 +919,7 @@ ifdef windir
M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --static-libs`
SV_LDFLAGS=`$(SDLCONFIG) --static-libs`
else
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(SDLCONFIG) --static-libs`
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) `$(SDLCONFIG) --static-libs`
VK_LDFLAGS=$(VKLDFLAGS) $(IMAGELDFLAGS) `$(SDLCONFIG) --static-libs`
M_LDFLAGS=$(MLDFLAGS) $(IMAGELDFLAGS) `$(SDLCONFIG) --static-libs`
SV_LDFLAGS=`$(SDLCONFIG) --static-libs`

View file

@ -1007,7 +1007,7 @@ void CL_Stop_f (void)
{
if (!cls.demorecording)
{
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && defined(MVD_RECORDING)
SV_MVDStop_f();
#else
Con_Printf ("Not recording a demo.\n");
@ -1135,8 +1135,10 @@ void CL_WriteSetDemoMessage (void)
record a single player game.
*/
#ifndef CLIENTONLY
#ifdef MVD_RECORDING
mvddest_t *SV_MVD_InitRecordFile (char *name);
qboolean SV_MVD_Record (mvddest_t *dest);
#endif
void CL_RecordMap_f (void)
{
char demoname[MAX_QPATH];
@ -1154,9 +1156,22 @@ void CL_RecordMap_f (void)
SV_SpawnServer (mapname, NULL, false, false);
#ifdef MVD_RECORDING
COM_DefaultExtension(demoname, ".mvd", sizeof(demoname));
#else
COM_DefaultExtension(demoname, ".dem", sizeof(demoname));
#endif
COM_FileExtension(demoname, demoext, sizeof(demoext));
#if defined(AVAIL_GZDEC) && !defined(CLIENTONLY)
{
extern cvar_t sv_demoAutoCompress;
if (sv_demoAutoCompress.ival)
Q_strncatz(demoname, ".gz", sizeof(demoname));
}
#endif
#ifdef MVD_RECORDING
if (!strcmp(demoext, "mvd"))
{
if (!SV_MVD_Record (SV_MVD_InitRecordFile(demoname)))
@ -1165,6 +1180,7 @@ void CL_RecordMap_f (void)
// Cbuf_AddText(va("mvdrecord %s\n", COM_QuotedString(demoname, buf, sizeof(buf))), RESTRICT_LOCAL);
}
else
#endif
{
cls.demooutfile = FS_OpenVFS (demoname, "wb", FS_GAME);
if (!cls.demooutfile)
@ -1172,6 +1188,11 @@ void CL_RecordMap_f (void)
CL_Disconnect_f();
return;
}
#ifdef AVAIL_GZDEC
if (!Q_strcasecmp(".gz", COM_GetFileExtension(demoname, NULL)))
cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true);
#endif
#ifdef NQPROT
if (!strcmp(demoext, "dem"))
{
@ -1197,10 +1218,10 @@ static void CLQW_RecordServerData(sizebuf_t *buf, int *seq)
// send the serverdata
MSG_WriteByte (buf, svc_serverdata);
#ifdef PROTOCOL_VERSION_FTE
if (cls.fteprotocolextensions) //maintain demo compatability
if (cls.fteprotocolextensions&~PEXT1_HIDEPROTOCOLS) //maintain demo compatability
{
MSG_WriteLong (buf, PROTOCOL_VERSION_FTE);
MSG_WriteLong (buf, cls.fteprotocolextensions);
MSG_WriteLong (buf, cls.fteprotocolextensions&~PEXT1_HIDEPROTOCOLS);
}
if (cls.fteprotocolextensions2) //maintain demo compatability
{
@ -1308,6 +1329,7 @@ void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
unsigned int i;
const char *val;
//This is for compat with DP.
val = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
if (*val)
{
@ -1328,10 +1350,10 @@ void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
}
MSG_WriteByte(buf, svc_serverdata);
if (cls.fteprotocolextensions)
if (cls.fteprotocolextensions&~PEXT1_HIDEPROTOCOLS)
{
MSG_WriteLong (buf, PROTOCOL_VERSION_FTE);
MSG_WriteLong (buf, cls.fteprotocolextensions);
MSG_WriteLong (buf, cls.fteprotocolextensions&~PEXT1_HIDEPROTOCOLS);
}
if (cls.fteprotocolextensions2)
{
@ -1365,6 +1387,8 @@ void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
if (protmain == PROTOCOL_VERSION_RMQ)
MSG_WriteLong (buf, protfl);
if (cls.fteprotocolextensions2 & PEXT2_PREDINFO)
MSG_WriteString(buf, FS_GetGamedir(true));
MSG_WriteByte (buf, cl.allocated_client_slots);
MSG_WriteByte (buf, cl.deathmatch?GAME_DEATHMATCH:GAME_COOP);
MSG_WriteString (buf, cl.levelname);
@ -1586,6 +1610,123 @@ static int CL_Record_Lightstyles(sizebuf_t *buf, int seq)
return seq;
}
// send current status of all other players
static int CL_RecordInitialPlayers(sizebuf_t *buf, int seq, qboolean isnq)
{
char info[MAX_LOCALINFO_STRING];
player_info_t *player;
int i;
for (i = 0; i < cl.allocated_client_slots; i++)
{
player = cl.players + i;
if (buf->cursize > buf->maxsize/2)
CL_WriteRecordDemoMessage (buf, seq++);
if (player->frags != 0)
{
MSG_WriteByte (buf, svc_updatefrags);
MSG_WriteByte (buf, i);
MSG_WriteShort(buf, player->frags);
}
if (isnq)
{
if (!*player->name)
continue;
MSG_WriteByte (buf, svc_updatename);
MSG_WriteByte (buf, i);
MSG_WriteString (buf, player->name);
MSG_WriteByte (buf, svc_updatecolors);
MSG_WriteByte (buf, i);
MSG_WriteByte (buf, player->rtopcolor*16+player->rbottomcolor);
}
else
{
if (player->ping != 0)
{
MSG_WriteByte (buf, svc_updateping);
MSG_WriteByte (buf, i);
MSG_WriteShort (buf, player->ping);
}
if (player->pl != 0)
{
MSG_WriteByte (buf, svc_updatepl);
MSG_WriteByte (buf, i);
MSG_WriteByte (buf, player->pl);
}
if (player->userinfo.numkeys)
{
MSG_WriteByte (buf, svc_updateentertime);
MSG_WriteByte (buf, i);
MSG_WriteFloat (buf, realtime - player->realentertime); //seconds since
}
if (player->userinfo.numkeys)
{
InfoBuf_ToString(&player->userinfo, info, min(buf->maxsize-buf->cursize-6, sizeof(info)), basicuserinfos, NULL, NULL, NULL, NULL);
MSG_WriteByte (buf, svc_updateuserinfo);
MSG_WriteByte (buf, i);
MSG_WriteLong (buf, player->userid);
MSG_WriteString (buf, info);
//spam svc_setinfo for all the infos that didn't fit.
}
}
}
return seq;
}
static int CL_RecordInitialStats(sizebuf_t *buf, int seq, qboolean isnq)
{
int seat, i;
for (seat = 0; seat < cl.splitclients; seat++)
{
//higher stats should be 0 and thus not be sent, if not valid.
for (i = 0; i < MAX_CL_STATS; i++)
{
if (cl.playerview[seat].stats[i] || cl.playerview[seat].statsf[i])
{
double fs = cl.playerview[seat].statsf[i];
double is = cl.playerview[seat].stats[i];
if (seat)
{
MSG_WriteByte (buf, svcfte_choosesplitclient);
MSG_WriteByte (buf, seat);
}
if ((int)fs == is)
{
MSG_WriteByte (buf, isnq?svcnq_updatestatlong:svcqw_updatestatlong);
MSG_WriteByte (buf, i);
MSG_WriteLong (buf, is);
}
else
{
MSG_WriteByte (buf, svcfte_updatestatfloat);
MSG_WriteByte (buf, i);
MSG_WriteLong (buf, fs);
}
}
if (cl.playerview[seat].statsstr[i])
{
if (seat)
{
MSG_WriteByte (buf, svcfte_choosesplitclient);
MSG_WriteByte (buf, seat);
}
MSG_WriteByte (buf, svcfte_updatestatstring);
MSG_WriteByte (buf, i);
MSG_WriteString (buf, cl.playerview[seat].statsstr[i]);
}
if (buf->cursize > buf->maxsize/2)
CL_WriteRecordDemoMessage (buf, seq++);
}
}
return seq;
}
const char *Get_Q2ConfigString(int i);
/*
@ -1601,9 +1742,8 @@ void CL_Record_f (void)
char name[MAX_OSPATH];
sizebuf_t buf;
char buf_data[MAX_OVERALLMSGLEN];
int n, i, seat;
int n, i;
char *s, *p, *fname;
player_info_t *player;
extern char gamedirfile[];
int seq = 1;
const char *defaultext;
@ -1653,7 +1793,7 @@ void CL_Record_f (void)
// They did.
if ( s != NULL ) {
if (!Q_strcasecmp(s, defaultext))
*s = 0; //hack away that extension that they added.
*s = 0; //hack away that extension that they added, so that we don't get dupes.
}
}
else
@ -1707,7 +1847,12 @@ void CL_Record_f (void)
}
// Make sure the filename doesn't contain illegal characters
for (p=fname ; *p ; p++)
p=fname;
#ifdef MVD_RECORDING
if (*sv_demoDir.string && !strncmp(p, sv_demoDir.string, strlen(sv_demoDir.string)) && p[strlen(sv_demoDir.string)] == '/')
p += strlen(sv_demoDir.string)+1; //allow a demos/ prefix (primarily because of autodemos)
#endif
for ( ; *p ; p++)
{
char c;
*p &= 0x7F; // strip high bit
@ -1716,10 +1861,18 @@ void CL_Record_f (void)
|| c=='<' || c=='>' || c=='"' || c=='.')
*p = '_';
}
Q_strncpyz(name, fname, sizeof(name)-8);
Q_strncpyz(name, fname, sizeof(name)-4-strlen(defaultext));
#if defined(AVAIL_GZDEC) && !defined(CLIENTONLY) && defined(MVD_RECORDING)
{
extern cvar_t sv_demoAutoCompress;
if (sv_demoAutoCompress.ival == 1 || !*sv_demoAutoCompress.string)
defaultext = va("%s.gz", defaultext);
}
#endif
//make a unique name (unless the user specified it).
strcat (name, defaultext); //we have the space
Q_strncatz(name, defaultext, sizeof(name));
if (c != 2)
{
vfsfile_t *f;
@ -1728,7 +1881,7 @@ void CL_Record_f (void)
if (f)
{
//remove the extension again
Q_strncpyz(name, fname, sizeof(name)-8);
Q_strncpyz(name, fname, sizeof(name)-4-strlen(defaultext));
p = name + strlen(name);
strcat(p, "_XX");
strcat(p, defaultext);
@ -1737,8 +1890,8 @@ void CL_Record_f (void)
do
{
VFS_CLOSE (f);
p[0] = i%100 + '0';
p[1] = i%10 + '0';
p[0] = ((i/10)%10) + '0';
p[1] = (i%10) + '0';
f = FS_OpenVFS (name, "rb", FS_GAME);
i++;
} while (f && i < 100);
@ -1748,12 +1901,18 @@ void CL_Record_f (void)
//
// open the demo file
//
cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME);
cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAMEONLY);
if (!cls.demooutfile)
{
Con_Printf ("ERROR: couldn't open.\n");
return;
}
#ifdef AVAIL_GZDEC
if (!Q_strcasecmp(".gz", COM_GetFileExtension(name, NULL)))
cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true);
#endif
cls.demohadkeyframe = false;
Con_Printf ("recording to %s.\n", name);
@ -1903,100 +2062,9 @@ void CL_Record_f (void)
if (buf.cursize)
CL_WriteRecordDemoMessage (&buf, seq++);
// send current status of all other players
for (i = 0; i < cl.allocated_client_slots; i++)
{
player = cl.players + i;
if (player->frags != 0)
{
MSG_WriteByte (&buf, svc_updatefrags);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->frags);
}
if (player->ping != 0)
{
MSG_WriteByte (&buf, svc_updateping);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->ping);
}
if (player->pl != 0)
{
MSG_WriteByte (&buf, svc_updatepl);
MSG_WriteByte (&buf, i);
MSG_WriteByte (&buf, player->pl);
}
if (player->userinfo.numkeys)
{
MSG_WriteByte (&buf, svc_updateentertime);
MSG_WriteByte (&buf, i);
MSG_WriteFloat (&buf, realtime - player->realentertime); //seconds since
}
if (player->userinfo.numkeys)
{
char info[MAX_LOCALINFO_STRING];
InfoBuf_ToString(&player->userinfo, info, sizeof(info), basicuserinfos, NULL, NULL, NULL, NULL);
MSG_WriteByte (&buf, svc_updateuserinfo);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, player->userid);
MSG_WriteString (&buf, info);
}
if (buf.cursize > buf.maxsize/2)
CL_WriteRecordDemoMessage (&buf, seq++);
}
seq = CL_RecordInitialPlayers(&buf, seq, false);
seq = CL_Record_Lightstyles(&buf, seq);
for (seat = 0; seat < cl.splitclients; seat++)
{
//higher stats should be 0 and thus not be sent, if not valid.
for (i = 0; i < MAX_CL_STATS; i++)
{
if (cl.playerview[seat].stats[i] || cl.playerview[seat].statsf[i])
{
double fs = cl.playerview[seat].statsf[i];
double is = cl.playerview[seat].stats[i];
if (seat)
{
MSG_WriteByte (&buf, svcfte_choosesplitclient);
MSG_WriteByte (&buf, seat);
}
if ((int)fs == is)
{
MSG_WriteByte (&buf, svcqw_updatestatlong);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, is);
}
else
{
MSG_WriteByte (&buf, svcfte_updatestatfloat);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, fs);
}
}
if (cl.playerview[seat].statsstr[i])
{
if (seat)
{
MSG_WriteByte (&buf, svcfte_choosesplitclient);
MSG_WriteByte (&buf, seat);
}
MSG_WriteByte (&buf, svcfte_updatestatstring);
MSG_WriteByte (&buf, i);
MSG_WriteString (&buf, cl.playerview[seat].statsstr[i]);
}
if (buf.cursize > buf.maxsize/2)
CL_WriteRecordDemoMessage (&buf, seq++);
}
}
seq = CL_RecordInitialStats(&buf, seq, false);
// get the client to check and download skins
// when that is completed, a begin command will be issued
@ -2075,9 +2143,9 @@ void CL_Record_f (void)
MSG_WriteByte (&buf, svcnq_signonnum);
MSG_WriteByte (&buf, 2);
CL_WriteRecordDemoMessage (&buf, seq++);
//fixme: clients
seq = CL_RecordInitialPlayers(&buf, seq, true);
seq = CL_Record_Lightstyles(&buf, seq);
//fixme: stats
seq = CL_RecordInitialStats(&buf, seq, true);
MSG_WriteByte (&buf, svcnq_signonnum);
MSG_WriteByte (&buf, 3);
CL_WriteRecordDemoMessage (&buf, seq++);
@ -2089,6 +2157,10 @@ void CL_Record_f (void)
CL_Stop_f();
break;
}
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
if (cl.numackframes < sizeof(cl.ackframes)/sizeof(cl.ackframes[0]))
cl.ackframes[cl.numackframes++] = -1;
}
static int QDECL CompleteDemoList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
@ -2102,7 +2174,11 @@ void CL_DemoList_c(int argn, const char *partial, struct xcommandargcompletioncb
if (argn == 1)
{
COM_EnumerateFiles(va("%s*.qwd", partial), CompleteDemoList, ctx);
COM_EnumerateFiles(va("%s*.qwd.gz", partial), CompleteDemoList, ctx);
#ifdef NQPROT
COM_EnumerateFiles(va("%s*.dem", partial), CompleteDemoList, ctx);
COM_EnumerateFiles(va("%s*.dem.gz", partial), CompleteDemoList, ctx);
#endif
COM_EnumerateFiles(va("%s*.mvd", partial), CompleteDemoList, ctx);
COM_EnumerateFiles(va("%s*.mvd.gz", partial), CompleteDemoList, ctx);
@ -2181,6 +2257,11 @@ void CL_ReRecord_f (void)
return;
}
#ifdef AVAIL_GZDEC
if (!Q_strcasecmp(".gz", COM_GetFileExtension(name, NULL)))
cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true);
#endif
Con_Printf ("recording to %s.\n", name);
#ifdef NQPROT
@ -2497,7 +2578,7 @@ void CL_PlayDemo(char *demoname, qboolean usesystempath)
Q_strncpyz (cls.lastdemoname, demoname, sizeof(cls.lastdemoname));
#ifdef AVAIL_GZDEC
if (strlen(name) >= 3 && !Q_strcasecmp(name + strlen(name) - 3, ".gz"))
if (!strcmp(COM_GetFileExtension(name,NULL), ".gz"))
f = FS_DecompressGZip(f, NULL);
#endif

View file

@ -4002,6 +4002,7 @@ void CL_LinkPacketEntities (void)
modelflags = model->flags;
}
#ifndef NOLEGACY
if (cl.model_precache_vwep[0] && state->modelindex2 < MAX_VWEP_MODELS)
{
if (state->modelindex == cl_playerindex && cl.model_precache_vwep[0]->loadstate == MLS_LOADED &&
@ -4013,7 +4014,9 @@ void CL_LinkPacketEntities (void)
else
model2 = NULL;
}
else if (state->modelindex2 && state->modelindex2 < MAX_PRECACHE_MODELS)
else
#endif
if (state->modelindex2 && state->modelindex2 < MAX_PRECACHE_MODELS)
model2 = cl.model_precache[state->modelindex2];
else
model2 = NULL;
@ -4972,7 +4975,9 @@ void CL_LinkPlayers (void)
static int flickertime;
static int flicker;
float predictmsmult = 1000*cl_predict_players_frac.value;
#ifndef NOLEGACY
int modelindex2;
#endif
extern cvar_t cl_demospeed;
int displayseq;
@ -5023,15 +5028,19 @@ void CL_LinkPlayers (void)
continue;
//the extra modelindex check is to stop lame mods from using vweps with rings
#ifndef NOLEGACY
if (state->command.impulse && cl.model_precache_vwep[0] && cl.model_precache_vwep[0]->type != mod_dummy && state->modelindex == cl_playerindex)
{
model = cl.model_precache_vwep[0];
modelindex2 = state->command.impulse;
}
else
#endif
{
model = cl.model_precache[state->modelindex];
#ifndef NOLEGACY
modelindex2 = 0;
#endif
}
// spawn light flashes, even ones coming from invisible objects
@ -5221,8 +5230,10 @@ void CL_LinkPlayers (void)
CL_AddFlagModels (ent, 0);
else if (state->effects & QWEF_FLAG2)
CL_AddFlagModels (ent, 1);
#ifndef NOLEGACY
if (modelindex2)
CL_AddVWeapModel (ent, cl.model_precache_vwep[modelindex2]);
#endif
CLQ1_AddShadow(ent);
CLQ1_AddPowerupShell(ent, false, state->effects);

View file

@ -390,6 +390,17 @@ void CL_MakeActive(char *gamename)
SCR_EndLoadingPlaque();
CL_UpdateWindowTitle();
#ifdef MVD_RECORDING
if (sv_demoAutoRecord.ival && !sv.mvdrecording && !cls.demorecording && !cls.demoplayback && MVD_CheckSpace(false))
{ //don't auto-record if we're already recording... or playing a different demo.
extern cvar_t sv_demoAutoPrefix;
char timestamp[64];
time_t tm = time(NULL);
strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", localtime(&tm));
Cbuf_AddText(va("record %s%s%s%s_%s\n", sv_demoDir.string, *sv_demoDir.string?"/":"", sv_demoAutoPrefix.string, host_mapname.string, timestamp), RESTRICT_LOCAL);
}
#endif
TP_ExecTrigger("f_begin", true);
if (cls.demoplayback)
TP_ExecTrigger("f_spawndemo", true);
@ -1445,8 +1456,7 @@ void CL_Rcon_f (void)
{
char cryptpass[1024], crypttime[64];
const char *hex = "0123456789ABCDEF"; //must be upper-case for compat with mvdsv.
time_t clienttime;
time(&clienttime);
time_t clienttime = time(NULL);
size_t digestsize;
unsigned char digest[64];
const unsigned char **tokens = alloca(sizeof(*tokens)*(4+Cmd_Argc()*2));

View file

@ -829,6 +829,7 @@ void CL_DownloadFinished(qdownload_t *dl)
break;
}
}
#ifndef NOLEGACY
for (i = 0; i < MAX_VWEP_MODELS; i++)
{
if (!strcmp(cl.model_name_vwep[i], filename))
@ -837,6 +838,7 @@ void CL_DownloadFinished(qdownload_t *dl)
break;
}
}
#endif
}
S_ResetFailedLoad(); //okay, so this can still get a little spammy in bad places...
@ -1163,6 +1165,7 @@ static void Model_CheckDownloads (void)
CL_CheckModelResources(s);
}
#ifndef NOLEGACY
for (i = 0; i < MAX_VWEP_MODELS; i++)
{
s = cl.model_name_vwep[i];
@ -1176,6 +1179,7 @@ static void Model_CheckDownloads (void)
CL_CheckOrEnqueDownloadFile(s, s, 0);
CL_CheckModelResources(s);
}
#endif
}
static int CL_LoadModels(int stage, qboolean dontactuallyload)
@ -1300,6 +1304,7 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
endstage();
}
}
#ifndef NOLEGACY
for (i = 0; i < MAX_VWEP_MODELS; i++)
{
if (!cl.model_name_vwep[i][0])
@ -1317,6 +1322,7 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
endstage();
}
}
#endif
}
@ -1609,6 +1615,7 @@ void CL_RequestNextDownload (void)
if (!cl.contentstage)
{
int pure;
stage = 0;
stage = CL_LoadModels(stage, true);
stage = CL_LoadSounds(stage, true);
@ -1616,8 +1623,12 @@ void CL_RequestNextDownload (void)
cl.contentstage = 0;
//might be safer to do it later, but kinder to do it before wasting time.
if (!FS_PureOkay())
{
pure = FS_PureOkay();
if (pure < 0 || (pure==0 && (cls.download || cl.downloadlist)))
return; //we're downloading something and may still be able to satisfy it.
if (pure == 0 && !cls.demoplayback)
{ //failure!
Con_Printf(CON_ERROR"You are missing pure packages, and they could not be autodownloaded.\nYou may need to purchase an update.\n");
#ifdef HAVE_MEDIA_ENCODER
if (cls.demoplayback && Media_Capturing())
{
@ -4108,8 +4119,10 @@ static void CL_ParseModellist (qboolean lots)
cl_spikeindex = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/player.mdl"))
cl_playerindex = nummodels;
#ifndef NOLEGACY
if (*cl.model_name_vwep[0] && !strcmp(cl.model_name[nummodels],cl.model_name_vwep[0]) && cl_playerindex == -1)
cl_playerindex = nummodels;
#endif
if (!strcmp(cl.model_name[nummodels],"progs/h_player.mdl"))
cl_h_playerindex = nummodels;
if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl"))
@ -6303,6 +6316,7 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
cl.serverpakschanged = true;
CL_CheckServerPacks();
}
#ifndef NOLEGACY
else if (!strncmp(stufftext, "//vwep ", 7)) //list of vwep model indexes, because using the normal model precaches wasn't cool enough
{ //(from zquake/ezquake)
int i;
@ -6323,6 +6337,7 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
}
}
}
#endif
else if (cls.demoplayback && !strncmp(stufftext, "playdemo ", 9))
{ //some demos (like speed-demos-archive's marathon runs) chain multiple demos with playdemo commands
//these should still chain properly even when the demo is in some archive(like .dz) or subdir

View file

@ -1077,22 +1077,33 @@ void CL_ParseTEnt (void)
case TENQ_BEAM:
type = TEQW_BEAM;
break;
case TENQ_EXPLOSION_SPRITE:
type = TE_EXPLOSION;
case TENQ_QWEXPLOSION:
type = TEQW_QWEXPLOSION;
break;
case TE_EXPLOSION:
type = TEQW_EXPLOSION_NOSPRITE;
case TENQ_NQEXPLOSION:
type = TEQW_NQEXPLOSION;
break;
case TE_GUNSHOT:
type = TE_GUNSHOT_NQCOMPAT;
case TENQ_NQGUNSHOT:
type = TEQW_NQGUNSHOT;
break;
case TE_GUNSHOT_NQCOMPAT:
type = TE_GUNSHOT;
case TENQ_QWGUNSHOT:
type = TEQW_QWGUNSHOT;
break;
case TENQ_RAILTRAIL:
type = TEQW_RAILTRAIL;
break;
case TENQ_NEHLIGHTNING4:
type = TEQW_NEHLIGHTNING4;
break;
// case TENQ_NEHSMOKE:
// type = TEQW_NEHSMOKE;
// break;
default:
break;
}
}
//else QW values
//right, nq vs qw doesn't matter now, supposedly.
@ -1103,15 +1114,14 @@ void CL_ParseTEnt (void)
"tarexplosion", "lightning1", "lightning2", "wizspike",
"knightspike", "lightning3", "lavasplash", "teleport",
"blood", "lightningblood", "bullet", "superbullet", //bullets deprecated
"railtrail", "beam", "explosion2", "nqexplosion",
"nqgunshot", "?", "?", "?",
"neh_explosion3", "railtrail/neh_lightning4", "beam", "explosion2",
"nqexplosion", "nqgunshot", "?", "?",
#ifdef HEXEN2
"h2lightsml", "h2chain", "h2sunstf1", "h2sunstf2",
"h2light", "h2cb", "h2ic", "h2gaze",
"h2famine", "h2partexp"
#endif
};
if (type < countof(te_names))
Con_Printf(" te_%s\n", te_names[type]);
else
@ -1274,7 +1284,7 @@ void CL_ParseTEnt (void)
S_StartSound (0, 0, cl_sfx_ric3, pos, NULL, 1, 1, 0, 0, 0);
}
break;
case TE_SUPERBULLET:
case TEQW_SUPERBULLET:
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
pos[2] = MSG_ReadCoord ();
@ -1342,8 +1352,8 @@ void CL_ParseTEnt (void)
ex->endalpha = ex->startalpha; //don't fade out
}
break;
case TEQW_EXPLOSION_NOSPRITE: //nq-style, no sprite
case TE_EXPLOSION: //qw-style, with (optional) sprite
case TEQW_NQEXPLOSION: //nq-style, no sprite
case TEQW_QWEXPLOSION: //qw-style, with (optional) sprite
// particles
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
@ -1375,7 +1385,7 @@ void CL_ParseTEnt (void)
S_StartSound (0, 0, cl_sfx_r_exp3, pos, NULL, 1, 1, 0, 0, 0);
// sprite
if (type == TE_EXPLOSION && cl_expsprite.ival) // temp hopefully
if (type == TEQW_QWEXPLOSION && cl_expsprite.ival) // temp hopefully
{
explosion_t *ex = CL_AllocExplosion (pos);
ex->start = cl.time;
@ -1411,6 +1421,7 @@ void CL_ParseTEnt (void)
}
break;
case TE_EXPLOSION3_NEH:
case TEDP_EXPLOSIONRGB:
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
@ -1420,6 +1431,18 @@ void CL_ParseTEnt (void)
if (cl_legacystains.ival) Surf_AddStain(pos, -1, -1, -1, 100);
if (type == TEDP_EXPLOSIONRGB)
{
pos2[0] = MSG_ReadByte()/255.0;
pos2[1] = MSG_ReadByte()/255.0;
pos2[2] = MSG_ReadByte()/255.0;
}
else
{ //TE_EXPLOSION3_NEH
pos2[0] = MSG_ReadCoord();
pos2[1] = MSG_ReadCoord();
pos2[2] = MSG_ReadCoord();
}
// light
if (r_explosionlight.value)
@ -1430,9 +1453,9 @@ void CL_ParseTEnt (void)
dl->die = cl.time + 0.5;
dl->decay = 300;
dl->color[0] = 0.4f*MSG_ReadByte()/255.0f;
dl->color[1] = 0.4f*MSG_ReadByte()/255.0f;
dl->color[2] = 0.4f*MSG_ReadByte()/255.0f;
dl->color[0] = 0.4f*pos2[0];
dl->color[1] = 0.4f*pos2[1];
dl->color[2] = 0.4f*pos2[2];
dl->channelfade[0] = 0;
dl->channelfade[1] = 0;
dl->channelfade[2] = 0;
@ -1490,6 +1513,11 @@ void CL_ParseTEnt (void)
case TE_LIGHTNING3: // lightning bolts
CL_ParseBeam (BT_Q1LIGHTNING3);
break;
case TEQW_NEHLIGHTNING4:
Con_DPrintf("TEQW_NEHLIGHTNING4 not implemented\n");
MSG_ReadString();
CL_ParseBeam (BT_Q1LIGHTNING2);
break;
case TE_LAVASPLASH:
pos[0] = MSG_ReadCoord ();
@ -1518,9 +1546,9 @@ void CL_ParseTEnt (void)
break;
case TE_GUNSHOT: // bullet hitting wall
case TE_GUNSHOT_NQCOMPAT:
if (type == TE_GUNSHOT_NQCOMPAT)
case TEQW_QWGUNSHOT: // bullet hitting wall
case TEQW_NQGUNSHOT:
if (type == TEQW_NQGUNSHOT)
cnt = 1;
else
cnt = MSG_ReadByte ();
@ -1535,7 +1563,7 @@ void CL_ParseTEnt (void)
break;
case TEQW_BLOOD: // bullets hitting body
case TEQW_QWBLOOD: // bullets hitting body
cnt = MSG_ReadByte ();
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
@ -1565,7 +1593,7 @@ void CL_ParseTEnt (void)
CL_ParseBeam (BT_Q1BEAM);
break;
case TE_RAILTRAIL:
case TEQW_RAILTRAIL:
pos[0] = MSG_ReadCoord ();
pos[1] = MSG_ReadCoord ();
pos[2] = MSG_ReadCoord ();
@ -1836,6 +1864,11 @@ void CL_ParseTEnt (void)
}
break;
// case TEQW_NEHRAILTRAIL:
// case TEQW_NEHEXPLOSION3:
// case TEQW_NEHLIGHTNING4:
// case TEQW_NEHSMOKE:
default:
Host_EndGame ("CL_ParseTEnt: bad type - %i", type);
}
@ -2438,7 +2471,7 @@ void CL_SmokeAndFlash(vec3_t origin)
ex = CL_AllocExplosion (origin);
VectorClear(ex->angles);
// ex->type = ex_flash;
ex->flags = Q2RF_FULLBRIGHT;
ex->flags = RF_FULLBRIGHT;
ex->numframes = 2;
ex->start = cl.time;
ex->model = Mod_ForName (q2tentmodels[q2cl_mod_flash].modelname, MLV_WARN);
@ -2648,7 +2681,7 @@ void CLQ2_ParseTEnt (void)
case CRTE_BLASTER_MUZZLEFLASH:
MSG_ReadPos (pos);
ex = CL_AllocExplosion (pos);
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
ex->flags = RF_FULLBRIGHT|RF_NOSHADOW;
ex->start = cl.q2frame.servertime - 100;
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0.1*5, 0*5);
P_RunParticleEffectTypeString(pos, NULL, 1, "te_muzzleflash");
@ -2656,7 +2689,7 @@ void CLQ2_ParseTEnt (void)
case CRTE_BLUE_MUZZLEFLASH:
MSG_ReadPos (pos);
ex = CL_AllocExplosion (pos);
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
ex->flags = RF_FULLBRIGHT|RF_NOSHADOW;
ex->start = cl.q2frame.servertime - 100;
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0.1*5, 0*5);
P_RunParticleEffectTypeString(pos, NULL, 1, "te_blue_muzzleflash");
@ -2664,7 +2697,7 @@ void CLQ2_ParseTEnt (void)
case CRTE_SMART_MUZZLEFLASH:
MSG_ReadPos (pos);
ex = CL_AllocExplosion (pos);
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
ex->flags = RF_FULLBRIGHT|RF_NOSHADOW;
ex->start = cl.q2frame.servertime - 100;
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0*5, 0.2*5);
P_RunParticleEffectTypeString(pos, NULL, 1, "te_smart_muzzleflash");
@ -2675,7 +2708,7 @@ void CLQ2_ParseTEnt (void)
MSG_ReadPos (pos);
ex = CL_AllocExplosion (pos);
VectorCopy (pos, ex->origin);
ex->flags = Q2RF_FULLBRIGHT|RF_NOSHADOW;
ex->flags = RF_FULLBRIGHT|RF_NOSHADOW;
ex->start = cl.q2frame.servertime - 100;
CL_NewDlight(0, pos, 350, 0.5, 0.2*5, 0*5, 0.2*5);
P_RunParticleEffectTypeString(pos, NULL, 1, "te_deathfield");

View file

@ -844,10 +844,17 @@ typedef struct
//
// information that is static for the entire time connected to a server
//
char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH];
char model_name[MAX_PRECACHE_MODELS][MAX_QPATH];
char sound_name[MAX_PRECACHE_SOUNDS][MAX_QPATH];
char *particle_ssname[MAX_SSPARTICLESPRE];
#ifndef NOLEGACY
char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH];
struct model_s *model_precache_vwep[MAX_VWEP_MODELS];
#endif
char model_name[MAX_PRECACHE_MODELS][MAX_QPATH];
struct model_s *model_precache[MAX_PRECACHE_MODELS];
char sound_name[MAX_PRECACHE_SOUNDS][MAX_QPATH];
struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS];
char *particle_ssname[MAX_SSPARTICLESPRE];
int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat.
#ifdef Q2CLIENT
char *configstring_general[Q2MAX_CLIENTS|Q2MAX_GENERAL];
char *image_name[Q2MAX_IMAGES];
@ -855,11 +862,6 @@ typedef struct
short inventory[MAX_SPLITS][Q2MAX_ITEMS];
#endif
struct model_s *model_precache_vwep[MAX_VWEP_MODELS];
struct model_s *model_precache[MAX_PRECACHE_MODELS];
struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS];
int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat.
char model_csqcname[MAX_CSMODELS][MAX_QPATH];
struct model_s *model_csqcprecache[MAX_CSMODELS];
char *particle_csname[MAX_CSPARTICLESPRE];

View file

@ -2615,6 +2615,7 @@ void Con_DrawConsole (int lines, qboolean noback)
{
char *tiptext = NULL;
shader_t *shader = NULL;
model_t *model = NULL;
char *mouseover;
if (!mouseconsole->mouseover || !mouseconsole->mouseover(mouseconsole, &tiptext, &shader))
{
@ -2662,13 +2663,20 @@ void Con_DrawConsole (int lines, qboolean noback)
shader->height = 240;
}
}
key = Info_ValueForKey(info, "modelviewer");
if (*key)
{
model = Mod_ForName(key, MLV_WARN);
if (model->loadstate != MLS_LOADED)
model = NULL;
}
}
tiptext = Info_ValueForKey(info, "tip");
}
Z_Free(mouseover);
}
}
if ((tiptext && *tiptext) || shader)
if ((tiptext && *tiptext) || shader || model)
{
//FIXME: draw a proper background.
//FIXME: support line breaks.
@ -2683,7 +2691,12 @@ void Con_DrawConsole (int lines, qboolean noback)
lines = Font_LineBreaks(buffer, COM_ParseFunString(CON_WHITEMASK, tiptext, buffer, sizeof(buffer), false), (256.0 * vid.pixelwidth) / vid.width, countof(starts), starts, ends);
th = (Font_CharHeight()*lines * vid.height) / vid.pixelheight;
if (shader)
if (model)
{
iw = 128;
ih = 128;
}
else if (shader)
{
int w, h;
if (R_GetShaderSizes(shader, &w, &h, false) >= 0)
@ -2726,6 +2739,94 @@ void Con_DrawConsole (int lines, qboolean noback)
}
Font_EndString(font_console);
if (model)
{
playerview_t pv;
entity_t ent;
vec3_t fwd, rgt, up;
vec3_t lightpos = {0, 1, 0};
if (R2D_Flush)
R2D_Flush();
memset(&pv, 0, sizeof(pv));
CL_DecayLights ();
CL_ClearEntityLists();
V_ClearRefdef(&pv);
r_refdef.drawsbar = false;
V_CalcRefdef(&pv);
r_refdef.grect.width = iw;
r_refdef.grect.height = ih;
r_refdef.grect.x = x-8-iw;
r_refdef.grect.y = y+((th>ih)?(th-ih)/2:0);
r_refdef.time = realtime;
r_refdef.flags = RDF_NOWORLDMODEL;
r_refdef.afov = 60;
r_refdef.fov_x = 0;
r_refdef.fov_y = 0;
r_refdef.dirty |= RDFD_FOV;
VectorClear(r_refdef.viewangles);
r_refdef.viewangles[0] = 20;
r_refdef.viewangles[1] = realtime * 90;
AngleVectors(r_refdef.viewangles, fwd, rgt, up);
VectorScale(fwd, -64, r_refdef.vieworg);
memset(&ent, 0, sizeof(ent));
ent.scale = 1;
// ent.angles[1] = realtime*45;//mods->yaw;
// ent.angles[0] = realtime*23.4;//mods->pitch;
ent.angles[0]*=r_meshpitch.value;
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
ent.angles[0]*=r_meshpitch.value;
VectorInverse(ent.axis[1]);
ent.model = model;
if (!ent.model)
return; //panic!
ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
Vector4Set(ent.shaderRGBAf, 1, 1, 1, 1);
/*if (strstr(model->name, "player"))
{
ent.bottomcolour = genhsv(realtime*0.1 + 0, 1, 1);
ent.topcolour = genhsv(realtime*0.1 + 0.5, 1, 1);
}
else*/
{
ent.topcolour = TOP_DEFAULT;
ent.bottomcolour = BOTTOM_DEFAULT;
}
// ent.fatness = sin(realtime)*5;
ent.playerindex = -1;
ent.skinnum = 0;
ent.shaderTime = 0;//realtime;
ent.framestate.g[FS_REG].lerpweight[0] = 1;
// ent.framestate.g[FS_REG].frame[0] = animationnum;
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime;
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
// ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname));
ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66;
ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33;
V_ApplyRefdef();
VectorNormalize(lightpos);
ent.light_dir[0] = DotProduct(lightpos, ent.axis[0]);
ent.light_dir[1] = DotProduct(lightpos, ent.axis[1]);
ent.light_dir[2] = DotProduct(lightpos, ent.axis[2]);
ent.light_known = 2;
V_AddEntity(&ent);
R_RenderView();
}
if (shader)
{
if (th > ih)

View file

@ -229,6 +229,50 @@ void M_Menu_Options_f (void)
NULL
};
#endif
#if !defined(CLIENTONLY) && defined(MVD_RECORDING)
extern cvar_t sv_demoAutoRecord;
static const char *autorecordopts[] = {
"Off",
"Singleview",
"Multiview",
NULL
};
static const char *autorecordvals[] = {
"0",
"-1",
"1",
NULL
};
extern cvar_t cl_loopbackprotocol;
static const char *lprotopts[] = {
"Vanilla QW",
"FTE QW (recommended)",
#ifdef NQPROT
"FTE NQ",
"666",
"BJP3",
// "DP6",
// "DP7",
"Automatic (FTE NQ/QW)",
"Vanilla NQ",
#endif
NULL
};
static const char *lprotvals[] = {
"qwid",
"qw",
#ifdef NQPROT
"nq",
"fitz",
"bjp3",
// "dp6",
// "dp7",
"auto",
"nqid",
#endif
NULL
};
#endif
menubulk_t bulk[] = {
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
@ -250,6 +294,10 @@ void M_Menu_Options_f (void)
MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0),
#if !defined(CLIENTONLY) && defined(SAVEDGAMES)
MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL),
#endif
#if !defined(CLIENTONLY) && defined(MVD_RECORDING)
MB_COMBOCVAR("Auto Record", sv_demoAutoRecord, autorecordopts, autorecordvals, NULL),
MB_COMBOCVAR("Force Protocol", cl_loopbackprotocol, lprotopts, lprotvals, "Some protocols may impose additional limitations/breakages, and are listed only for potential demo-recording compat."),
#endif
MB_SPACING(4),
// removed hud options (cl_sbar, cl_hudswap, old-style chat, old-style msg)
@ -904,7 +952,7 @@ const char *presetexec[] =
"r_bloom 1;"
"r_deluxemapping 0;" //won't be seen anyway
"r_particledesc \"high tsshaft\";"
"r_waterstyle 3;"
// "r_waterstyle 3;" //too expensive.
"r_glsl_offsetmapping 1;"
"r_shadow_realtime_world 1;"
"gl_texture_anisotropic_filtering 16;"

View file

@ -1009,6 +1009,31 @@ void M_Demo_Reselect(demomenu_t *info, const char *name)
void M_Menu_Demos_f (void)
{
char *demoexts[] = {
".mvd", ".mvd.gz",
".qwz", ".qwz.gz",
#ifdef NQPROT
".dem", ".dem.gz",
#endif
#ifdef Q2CLIENT
".dm2", ".dm2.gz"
#endif
//there are also qizmo demos (.qwz) out there...
//we don't support them, but if we were to ask quizmo to decode them for us, we could do.
};
char *archiveexts[] = {
#ifdef PACKAGE_PK3
".zip", ".pk3", ".pk4",
#endif
#ifdef PACKAGE_Q1PAK
".pak",
#endif
#ifdef PACKAGE_DZIP
".dz",
#endif
NULL
};
size_t u;
demomenu_t *info;
menu_t *menu;
static demoloc_t mediareenterloc = {FS_GAME, "demos/"};
@ -1038,36 +1063,20 @@ void M_Menu_Demos_f (void)
}
info->numext = 0;
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = ".qwd";
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = ".dem";
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = ".dm2";
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = ".mvd";
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = ".mvd.gz";
//there are also qizmo demos (.qwz) out there...
//we don't support them, but if we were to ask quizmo to decode them for us, we could do.
for (u = 0; u < countof(demoexts); u++)
{
info->command[info->numext] = "closemenu;playdemo";
info->ext[info->numext++] = demoexts[u];
}
//and some archive formats... for the luls
#ifdef PACKAGE_PK3
info->command[info->numext] = NULL;
info->ext[info->numext++] = ".zip";
info->command[info->numext] = NULL;
info->ext[info->numext++] = ".pk3";
info->command[info->numext] = NULL;
info->ext[info->numext++] = ".pk4";
#endif
#ifdef PACKAGE_Q1PAK
info->command[info->numext] = NULL;
info->ext[info->numext++] = ".pak";
#endif
#ifdef PACKAGE_DZIP
info->command[info->numext] = NULL;
info->ext[info->numext++] = ".dz";
#endif
for (u = 0; u < countof(archiveexts); u++)
{
if (archiveexts[u])
continue;
info->command[info->numext] = NULL;
info->ext[info->numext++] = archiveexts[u];
}
MC_AddWhiteText(menu, 24, 170, 8, "Choose a Demo", false);
MC_AddWhiteText(menu, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false);

View file

@ -369,6 +369,16 @@ typedef struct texnums_s {
texid_t fullbright;
texid_t reflectcube;
texid_t reflectmask;
//the material's pushconstants. vulkan guarentees only 128 bytes. so 8 vec4s. note that lmscales should want 4 of them...
/*struct
{
vec4_t basefactors;
vec4_t specfactors;
vec4_t fullbrightfactors;
//FIXME: envmap index, lightmap index, etc.
} factors;*/
} texnums_t;
//not all modes accept meshes - STENCIL(intentional) and DEPTHONLY(not implemented)

View file

@ -1636,7 +1636,7 @@ parsefluid:
else if (!Q_strncasecmp(e, "transparent", 11))
mod->rflags |= RF_TRANSLUCENT; //force blend
else if (!Q_strncasecmp(e, "fullbright", 10))
mod->rflags |= Q2RF_FULLBRIGHT; //fullbright, woo
mod->rflags |= RF_FULLBRIGHT; //fullbright, woo
else if (!Q_strncasecmp(e, "shadow", 6))
mod->rflags &= ~RF_NOSHADOW; //clear noshadow
else if (!Q_strncasecmp(e, "noshadow", 8))
@ -2378,7 +2378,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
Q_strncatz(outstr, " additive", outstrlen);
if (ptype->models[i].rflags&RF_TRANSLUCENT)
Q_strncatz(outstr, " transparent", outstrlen);
if (ptype->models[i].rflags&Q2RF_FULLBRIGHT)
if (ptype->models[i].rflags&RF_FULLBRIGHT)
Q_strncatz(outstr, " fullbright", outstrlen);
if (ptype->models[i].rflags&RF_NOSHADOW)
Q_strncatz(outstr, " noshadow", outstrlen);

View file

@ -876,6 +876,8 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
}
effects = in->v->effects;
if (effects & EF_FULLBRIGHT)
out->flags |= RF_FULLBRIGHT;
if (effects & NQEF_ADDITIVE)
out->flags |= RF_ADDITIVE;
if (effects & EF_NOSHADOW)
@ -7022,7 +7024,7 @@ void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(v
//also kinda irrelevant with sv_pure.
#ifndef FTE_TARGET_WEB
if (file
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && defined(MVD_RECORDING)
&& !sv_demo_write_csqc.ival
#endif
)

View file

@ -464,7 +464,7 @@ cvar_t gl_screenangle = CVAR("gl_screenangle", "0");
#endif
#ifdef VKQUAKE
cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0.");
cvar_t vk_stagingbuffers = CVARFD ("vk_stagingbuffers", "", CVAR_RENDERERLATCH, "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0.");
cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers.");
cvar_t vk_debug = CVARFD("vk_debug", "0", CVAR_VIDEOLATCH, "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_dualqueue = CVARFD("vk_dualqueue", "", CVAR_VIDEOLATCH, "Attempt to use a separate queue for presentation. Blank for default.");
@ -1731,6 +1731,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
cl.model_precache[i] = Mod_FindName (Mod_FixName(cl.model_name[i], cl.model_name[1]));
}
#ifndef NOLEGACY
for (i=0; i < MAX_VWEP_MODELS; i++)
{
if (*cl.model_name_vwep[i])
@ -1738,6 +1739,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
else
cl.model_precache_vwep[i] = NULL;
}
#endif
#ifdef CSQC_DAT
for (i=1 ; i<MAX_CSMODELS ; i++)
@ -1815,7 +1817,7 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n"));
void R_ReloadRenderer_f (void)
{
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
void *portalblob = NULL;
size_t portalsize = 0;
#endif
@ -1824,7 +1826,7 @@ void R_ReloadRenderer_f (void)
if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS)
return; //don't bother reloading the renderer if its not actually rendering anything anyway.
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
{
void *t;
@ -1841,7 +1843,7 @@ void R_ReloadRenderer_f (void)
R_ApplyRenderer_Load(NULL);
Cvar_ApplyCallbacks(CVAR_RENDERERCALLBACK);
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
if (portalblob)
{
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
@ -2076,7 +2078,7 @@ void R_RestartRenderer (rendererstate_t *newr)
return;
}
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
if (sv.state == ss_active && sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)
{
void *t;
@ -2160,7 +2162,7 @@ void R_RestartRenderer (rendererstate_t *newr)
}
}
#ifndef CLIENTONLY
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
if (portalblob)
{
if (sv.world.worldmodel && sv.world.worldmodel->loadstate == MLS_LOADED)

View file

@ -972,9 +972,6 @@ static qboolean OpenAL_InitLibrary(void)
firefoxstaticsounds = !!strstr(emscripten_run_script_string("navigator.userAgent"), "Firefox");
if (firefoxstaticsounds)
Con_DPrintf("Firefox detected - disabling static sounds to avoid SORRY, I CAN'T HEAR YOU\n");
#else
if (COM_CheckParm("-noopenal"))
return false;
#endif
#ifdef OPENAL_STATIC
@ -1019,6 +1016,9 @@ static qboolean OpenAL_InitLibrary(void)
{NULL}
};
if (COM_CheckParm("-noopenal"))
return false;
if (!openallib_tried)
{
openallib_tried = true;

View file

@ -3117,7 +3117,16 @@ static const char *If_Token_Term(const char *func, const char **end)
level++;
s2++;
}
func = If_Token(s, end, IF_PRI_MAX);
if (!level)
{
char *t = malloc(s2-s+1);
memcpy(t, s, s2-s);
t[s2-s-((s2==s)?0:1)] = 0;
func = If_Token(t, end, IF_PRI_MAX);
free(t);
}
else
func = If_Token(s, end, IF_PRI_MAX);
*end = s2;
s = *end;
s2 = func;

View file

@ -612,7 +612,7 @@ void FS_UnloadPackFiles(void);
void FS_ReloadPackFiles(void);
char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum);
void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed); //implies an fs_restart. ref package names are optional, for q3 where pure names don't contain usable paths
qboolean FS_PureOkay(void);
int FS_PureOkay(void);
//recursively tries to open files until it can get a zip.
vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name);

View file

@ -112,6 +112,7 @@
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
#define SAVEDGAMES //Can save the game.
#define MVD_RECORDING //server can record MVDs.
// Networking options
#define NQPROT //act as an nq client/server, with nq gamecode.

View file

@ -114,6 +114,7 @@
////#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
////#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
//#define SAVEDGAMES //Can save the game.
//#define MVD_RECORDING //server can record MVDs.
// Networking options
//#define NQPROT //act as an nq client/server, with nq gamecode.

View file

@ -111,6 +111,7 @@
//#define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7)
//#define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140)
#define SAVEDGAMES //Can save the game.
#define MVD_RECORDING //server can record MVDs.
// Networking options
//#define NQPROT //act as an nq client/server, with nq gamecode.

View file

@ -99,6 +99,7 @@
#undef PSKMODELS
// What do we NOT want to use
#undef MVD_RECORDING //server can record MVDs.
#undef D3D9QUAKE
#undef D3D11QUAKE
#undef D3D8QUAKE

View file

@ -3528,7 +3528,8 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn
}
}
qboolean FS_PureOkay(void)
#ifndef SERVERONLY
int FS_PureOkay(void)
{
//returns true if all pure packages that we're meant to need could load.
//if they couldn't then they won't override things, or the game will just be completely screwed due to having absolutely no game data
@ -3591,7 +3592,10 @@ qboolean FS_PureOkay(void)
continue;
else //if (!sp)
{
Con_Printf("Pure package %s:%i missing\n", pname, crc);
if (!CL_CheckDLFile(va("package/%s", pname)))
if (CL_CheckOrEnqueDownloadFile(va("package/%s", pname), va("%s.%i", pname, crc), DLLF_NONGAME))
return -1;
Con_Printf(CON_ERROR"Pure package %s:%i missing.\n", pname, crc);
return false;
}
}
@ -3600,6 +3604,7 @@ qboolean FS_PureOkay(void)
return true;
}
#endif
char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum)
{ //this is for q3 compatibility.

View file

@ -3307,7 +3307,9 @@ typedef struct ftenet_tcpconnect_stream_s {
{
qboolean connection_close;
} httpstate;
#ifdef MVD_RECORDING
qtvpendingstate_t qtvstate;
#endif
struct
{
char resource[32];
@ -3475,8 +3477,8 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
char adr[256];
int i;
const char *filetype = NULL;
char *resp = NULL; //response headers (no length/gap)
char *body = NULL; //response body
const char *resp = NULL; //response headers (no length/gap)
const char *body = NULL; //response body
int method;
if (!strcmp(arg[WCATTR_METHOD], "GET"))
method = 0;
@ -3489,15 +3491,14 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
body = NULL;
}
//FIXME: demonum/
st->dlfile = NULL;
if (!resp && *arg[WCATTR_URL] == '/')
{ //'can't use SV_LocateDownload, as that assumes an active client.
char *name = arg[WCATTR_URL]+1;
const char *name = arg[WCATTR_URL]+1;
char *extraheaders = "";
time_t modificationtime = 0;
char *query = strchr(arg[WCATTR_URL]+1, '?');
func_t func = 0;
if (query)
*query++ = 0;
@ -3506,33 +3507,35 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
if (!*name)
name = "index.html";
if (sv.state && svs.gametype == GT_PROGS && svprogfuncs)
func = svprogfuncs->FindFunction(svprogfuncs, "HTTP_GeneratePage", PR_ANY);
if (func)
{
void *pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
((string_t *)pr_globals)[OFS_PARM0] = svprogfuncs->TempString(svprogfuncs, query?va("%s?%s", name, query):name);
((string_t *)pr_globals)[OFS_PARM1] = svprogfuncs->TempString(svprogfuncs, arg[WCATTR_METHOD]);
((string_t *)pr_globals)[OFS_PARM2] = 0; //we don't support any postdata at this time.
((string_t *)pr_globals)[OFS_PARM3] = 0; //we don't support any request headers at this time.
((string_t *)pr_globals)[OFS_PARM4] = 0; //we don't have any default response headers yet.
((string_t *)pr_globals)[OFS_PARM5] = 0;
((string_t *)pr_globals)[OFS_PARM6] = 0;
((string_t *)pr_globals)[OFS_PARM7] = 0;
svprogfuncs->ExecuteProgram(svprogfuncs, func);
if (((string_t *)pr_globals)[OFS_RETURN])
{ //note that "" is not null
body = svprogfuncs->StringToNative(svprogfuncs, ((string_t *)pr_globals)[OFS_RETURN]);
resp = svprogfuncs->StringToNative(svprogfuncs, ((string_t *)pr_globals)[OFS_PARM4]);
resp = va("%s%s", *body?"HTTP/1.1 200 Ok\r\n":"HTTP/1.1 404 File Not Found\r\n", resp);
}
}
//FIXME: provide some resource->filename mapping that allows various misc files.
/*if (!strcmp(name, "live.html"))
{
resp = "HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html\r\n";
body =
"<!DOCTYPE HTML>"
"<html>"
"<style>"
"html, body { height: 100%%; width: 100%%; margin: 0; padding: 0;}"
"div { height: 100%%; width: 100%%; }"
"</style>"
"<div>"
"<object name=\"ieplug\" type=\"application/x-fteplugin\" classid=\"clsid:7d676c9f-fb84-40b6-b3ff-e10831557eeb\" width=\"100%%\" height=\"100%%\">"
"<param name=\"game\" value=\"q1\">"
"<object name=\"npplug\" type=\"application/x-fteplugin\" width=\"100%%\" height=\"100%%\">"
"<param name=\"game\" value=\"q1\">"
"Please install a plugin first.<br/>"
"</object>"
"</object>"
"</div>"
"</html>"
;
}
else */
if (!strcmp(name, "index.html"))
if (body)
;
else if (!strcmp(name, "index.html"))
{
resp = "HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html\r\n";
@ -3636,6 +3639,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
"Content-Type: application/x-ftemanifest\r\n";
body = NULL;
}*/
#ifdef MVD_RECORDING
else if (!Q_strncasecmp(name, "demolist", 8))
{
filetype = "text/html";
@ -3656,6 +3660,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
body = NULL;
}
}
#endif
else if (!SV_AllowDownload(name))
{
Con_Printf("Denied download of %s to %s\n", arg[WCATTR_URL], NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
@ -3680,9 +3685,10 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
{
flocation_t gzloc;
flocation_t rawloc;
extern cvar_t sv_demoDir;
#ifdef MVD_RECORDING
if (!Q_strncasecmp(name, "demos/", 6))
name = va("%s/%s", sv_demoDir.string, name+6);
#endif
if (FS_FLocateFile(name, FSLF_IFFOUND, &rawloc))
{
@ -4484,6 +4490,7 @@ closesvstream:
if (headerscomplete)
{
#ifdef MVD_RECORDING
//for QTV connections, we just need the method and a blank line. our qtv parser will parse the actual headers.
if (!Q_strncasecmp(st->inbuffer, "QTV", 3))
{
@ -4503,6 +4510,7 @@ closesvstream:
}
}
else
#endif
{
net_message.cursize = 0;
if (!FTENET_TCP_ParseHTTPRequest(con, st))

View file

@ -2929,9 +2929,18 @@ void QCBUILTIN PF_edict_for_num(pubprogfuncs_t *prinst, struct globalvars_s *pr_
unsigned int num = G_FLOAT(OFS_PARM0);
if (num >= w->num_edicts)
RETURN_EDICT(prinst, w->edicts);
G_INT(OFS_RETURN) = num;
/*
ent = (edict_t*)EDICT_NUM_PB(prinst, num);
RETURN_EDICT(prinst, ent);
if (!ent)
{
ent = ED_AllocIntoTable(progfuncs, num, false, prinst.fields_size);
ent->ereftype = ER_FREE;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ent, true);
}
RETURN_EDICT(prinst, ent);*/
}
/*

View file

@ -38,12 +38,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_ENTITYDBL2 0x00004000 //max of 1024 ents instead of 512
#define PEXT_FLOATCOORDS 0x00008000 //supports floating point origins.
//#define PEXT_VWEAP 0x00010000 //cause an extra qbyte to be sent, and an extra list of models for vweaps.
#ifdef Q2BSPS
#define PEXT_Q2BSP 0x00020000
#endif
#ifdef Q3BSPS
#define PEXT_Q3BSP 0x00040000
#endif
#define PEXT_Q2BSP_ 0x00020000
#define PEXT_Q3BSP_ 0x00040000
#define PEXT_COLOURMOD 0x00080000 //this replaces an older value which would rarly have caried any actual data.
@ -64,7 +60,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_BIGUSERINFOS PEXT_CSQC //FIXME: while useful for csqc, we should include something else that isn't so often stripped, or is available in ezquake, or something.
#else
#define PEXT_BIGUSERINFOS 0xffffffff
#endif
#endif
#ifdef Q2BSPS
#define PEXT_Q2BSP PEXT_Q2BSP_
#endif
#ifdef Q3BSPS
#define PEXT_Q3BSP PEXT_Q3BSP_
#endif
#define PEXT1_HIDEPROTOCOLS (PEXT_Q3BSP_|PEXT_Q2BSP_|PEXT_HLBSP) //These are hints for the server, and not useful to the client (they can figure stuff out themselves)
#define PEXT2_PRYDONCURSOR 0x00000001
#define PEXT2_VOICECHAT 0x00000002
@ -916,8 +920,10 @@ enum {
enum {
TE_SPIKE = 0,
TE_SUPERSPIKE = 1,
TE_GUNSHOT = 2, //qw has count byte, nq does not
TE_EXPLOSION = 3, //remapped to TEQW_EXPLOSIONNOSPRITE for nq.
TEQW_QWGUNSHOT = 2, //qw has count byte, nq does not
TENQ_NQGUNSHOT = 2, //nq has no count byte
TEQW_QWEXPLOSION = 3, //remapped to TEQW_EXPLOSIONNOSPRITE for nq.
TENQ_NQEXPLOSION = 3, //remapped to TEQW_EXPLOSIONNOSPRITE for nq.
TE_TAREXPLOSION = 4,
TE_LIGHTNING1 = 5,
TE_LIGHTNING2 = 6,
@ -927,25 +933,27 @@ enum {
TE_LAVASPLASH = 10,
TE_TELEPORT = 11,
TEQW_BLOOD = 12, //implemented as a particle() in nq
TEQW_QWBLOOD = 12, //implemented as a particle() in nq
TENQ_EXPLOSION2 = 12, //remapped to TEQW_EXPLOSION2 for qw
TEQW_LIGHTNINGBLOOD = 13, //implemented as a particle() in nq
TENQ_BEAM = 13, //remapped to TEQW_BEAM for qw
#ifdef PEXT_TE_BULLET
TE_BULLET = 14,
TE_SUPERBULLET = 15,
TEQW_SUPERBULLET = 15,
#endif
TENEH_RAILTRAIL = 15, //gah [vector] origin [coord] red [coord] green [coord] blue
TENEH_EXPLOSION3 = 16, //gah [vector] origin [coord] red [coord] green [coord] blue
TE_RAILTRAIL = 17, //use the builtin, luke.
TENEH_LIGHTNING4 = 17, //gah [string] model [entity] entity [vector] start [vector] end
TENQ_RAILTRAIL = 15, //gah [vector] origin [coord] red [coord] green [coord] blue
TE_EXPLOSION3_NEH = 16, //gah [vector] origin [coord] red [coord] green [coord] blue
TEQW_RAILTRAIL = 17, //use the builtin, luke.
TENQ_NEHLIGHTNING4 = 17, //gah [string] model [entity] entity [vector] start [vector] end
TEQW_NEHLIGHTNING4 = 1000, //give a real value if its ever properly implemented
TEQW_BEAM = 18, //use the builtin, luke.
TENEH_SMOKE = 18, //gah [vector] origin [byte] palette
TENQ_NEHSMOKE = 18, //gah [vector] origin [byte] palette
TEQW_EXPLOSION2 = 19, //use the builtin, luke.
TEQW_EXPLOSION_NOSPRITE = 20, //nq-style explosion over qw
TENQ_EXPLOSION_SPRITE = 20, //qw-style explosion over nq
TE_GUNSHOT_NQCOMPAT = 21, //nq has count byte, qw does not
TEQW_NQEXPLOSION = 20, //nq-style explosion over qw
TENQ_QWEXPLOSION = 20, //qw-style explosion over nq
TEQW_NQGUNSHOT = 21, //nq has count byte, qw does not
TENQ_QWGUNSHOT = 21, //nq has count byte, qw does not
// hexen 2
TEH2_STREAM_LIGHTNING_SMALL = 24,
@ -959,7 +967,7 @@ enum {
TEH2_STREAM_FAMINE = 32,
TEH2_PARTICLEEXPLOSION = 33,
TEDP_BLOOD = 50,
TEDP_BLOOD = 50, // [coord*3] origin [byte*3] vel [byte] count
TEDP_SPARK = 51,
TEDP_BLOODSHOWER = 52,
TEDP_EXPLOSIONRGB = 53,
@ -1298,7 +1306,7 @@ typedef struct q1usercmd_s
#define Q2RF_MINLIGHT (1u<<0) //ni always have some light (viewmodel)
#define RF_EXTERNALMODEL (1u<<1) //i don't draw through eyes, only mirrors
#define RF_WEAPONMODEL (1u<<2) //i only draw through eyes
#define Q2RF_FULLBRIGHT (1u<<3) //i always draw full intensity
#define RF_FULLBRIGHT (1u<<3) //i always draw full intensity
#define RF_DEPTHHACK (1u<<4) //i for view weapon Z crunching
#define RF_TRANSLUCENT (1u<<5) //forces shader sort order and BEF_FORCETRANSPARENT
#define Q2RF_FRAMELERP (1u<<6) //q2only

View file

@ -676,7 +676,11 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (e->playerindex >= 0 && e->playerindex <= MAX_CLIENTS)
{
//heads don't get skinned, only players (and weaponless players), they do still get recoloured.
if (model==cl.model_precache[cl_playerindex] || model==cl.model_precache_vwep[0])
if (model==cl.model_precache[cl_playerindex]
#ifndef NOLEGACY
|| model==cl.model_precache_vwep[0]
#endif
)
{
if (!cl.players[e->playerindex].qwskin)
Skin_Find(&cl.players[e->playerindex]);
@ -1333,15 +1337,17 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
e->light_known = 2;
return e->light_known-1;
}
if (
#ifdef HEXEN2
if ((e->drawflags & MLS_MASK) == MLS_FULLBRIGHT || (e->flags & Q2RF_FULLBRIGHT))
(e->drawflags & MLS_MASK) == MLS_FULLBRIGHT ||
#endif
(e->flags & RF_FULLBRIGHT))
{
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;
e->light_range[0] = e->light_range[1] = e->light_range[2] = 0;
e->light_known = 2;
return e->light_known-1;
}
#endif
if (r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch)
{
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;

View file

@ -7306,8 +7306,8 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
struct brushface_s faces[countof(planes)];
//patch info
brushtex_t *patch_tex;
int patch_w, patch_h;
brushtex_t *patch_tex=NULL;
int patch_w=0, patch_h=0;
vec5_t patch_v[64][64];
#ifdef RUNTIMELIGHTING
@ -7344,7 +7344,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
brush.patch = NULL;
Terr_Brush_Insert(submod, subhm, &brush);
}
else
else if (patch_tex)
Terr_Patch_Insert(submod, subhm, patch_tex, patch_w, patch_h, patch_v[0], countof(patch_v[0]));
subhm->brushesedited = oe;
}

View file

@ -2505,6 +2505,10 @@ static shaderkey_t shaderkeys[] =
{"progblendfunc", Shader_ProgBlendFunc, "fte"}, //specifies the blend mode (actually just overrides the first subpasses' blendmode.
{"progmap", Shader_ProgMap, "fte"}, //avoids needing extra subpasses (actually just inserts an extra pass).
{"basefactor", NULL, "fte"}, //material scalers for glsl
{"specularfactor", NULL, "fte"}, //material scalers for glsl
{"fullbrightfactor", NULL, "fte"}, //material scalers for glsl
//dp compat
{"reflectcube", Shader_ReflectCube, "dp"},
{"camera", Shader_DP_Camera, "dp"},
@ -5847,11 +5851,10 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
if (!builtin && r_lightmap.ival)
builtin = (
"{\n"
"fte_program drawflat_wall\n"
"fte_program drawflat_wall#LM\n"
"{\n"
"map $lightmap\n"
"tcgen lightmap\n"
"rgbgen srgb 255 255 255\n"
"}\n"
"}\n"
);

View file

@ -7990,7 +7990,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"uniform vec4 e_lmscale;\n"
"void main ()\n"
"{\n"
"#ifdef LM\n"
"col = vec4(1.0);\n"
"#else\n"
"col = vec4(e_lmscale.rgb * ((v_normal.z < 0.73)?r_wallcolor:r_floorcolor), e_lmscale.a);\n"
"#endif\n"
"lm = v_lmcoord;\n"
"gl_Position = ftetransform();\n"
"}\n"
@ -9805,6 +9809,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_OPENGL, 110, "postproc_ascii",
"!!cvardf r_glsl_ascii_mono=0\n"
"!!samps 1\n"
//derived from https://www.shadertoy.com/view/lssGDj
"#include \"sys/defs.h\"\n"
@ -9838,7 +9843,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;\n"
"if (r_glsl_ascii_mono != 0)\n"
"if (r_glsl_ascii_mono != 0.0)\n"
"gray = gray = pow(gray, 0.7); //quake is just too dark otherwise.\n"
"else\n"
"gray = gray = pow(gray, 0.45); //col*char is FAR too dark otherwise, and much of the colour will come from the col term anyway.\n"
@ -9854,7 +9859,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"if (gray > 0.8) n = 11512810.0; // #\n"
"vec2 p = mod(uv/4.0, 2.0) - vec2(1.0);\n"
"if (r_glsl_ascii_mono != 0)\n"
"if (r_glsl_ascii_mono != 0.0)\n"
"col = vec3(character(n, p));\n"
"else\n"
"col = col*character(n, p); //note that this is kinda cheating.\n"

View file

@ -724,7 +724,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
nl = strchr(msg, '\n');
if (nl)
*nl = '\0';
Con_Printf("HTTP: %s %s (%s)\n", buffer, COM_TrimString(msg, trimmed, sizeof(trimmed)), Location);
Con_Printf("%s: %s %s (%s)\n", dl->url, buffer, COM_TrimString(msg, trimmed, sizeof(trimmed)), Location);
if (!*Location)
Con_Printf("Server redirected to null location\n");
else
@ -763,7 +763,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
if (nl>msg&&nl[-1] == '\r')
nl--;
*nl = '\0';
Con_Printf("HTTP: %s%s\n", buffer, msg);
Con_Printf("%s: %s%s\n", dl->url, buffer, msg);
return false; //something went wrong.
}

View file

@ -1,4 +1,5 @@
#include "qcc.h"
#if !defined(MINIMAL) && !defined(OMIT_QCC)
#include <time.h>
void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base);
@ -1635,3 +1636,4 @@ void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptname)
void Packager_Destroy(struct pkgctx_s *ctx)
{
}
#endif

View file

@ -1247,12 +1247,11 @@ pbool PDECL ED_ParseEval (pubprogfuncs_t *ppf, eval_t *eval, int type, const cha
pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs, int fldtype, char *s)
{
int i;
char string[128];
fdef_t *def;
char *v, *w;
string_t st;
mfunction_t *func;
int type = fldtype & ~DEF_SAVEGLOBAL;
double d;
qcptr += fldofs*sizeof(int);
switch (type)
@ -1267,37 +1266,40 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
break;
case ev_float:
*(float *)(progfuncs->funcs.stringtable + qcptr) = (float)atof (s);
while(*s == ' ' || *s == '\t')
s++;
d = strtod(s, &s);
while(*s == ' ' || *s == '\t')
s++;
*(float *)(progfuncs->funcs.stringtable + qcptr) = d;
if (*s)
return false; //some kind of junk in there.
break;
case ev_entity: //ent references are simple ints for us.
case ev_integer:
*(int *)(progfuncs->funcs.stringtable + qcptr) = atoi (s);
while(*s == ' ' || *s == '\t')
s++;
i = strtol(s, &s, 0);
while(*s == ' ' || *s == '\t')
s++;
*(int *)(progfuncs->funcs.stringtable + qcptr) = i;
if (*s)
return false; //some kind of junk in there.
break;
case ev_vector:
strcpy (string, s);
v = string;
w = string;
for (i=0 ; i<3 ; i++)
{
while (*v && *v != ' ')
v++;
if (!*v)
{
((float *)(progfuncs->funcs.stringtable + qcptr))[i] = (float)atof (w);
w = v;
}
else
{
*v = 0;
((float *)(progfuncs->funcs.stringtable + qcptr))[i] = (float)atof (w);
w = v = v+1;
}
while(*s == ' ' || *s == '\t')
s++;
d = strtod(s, &s);
((float *)(progfuncs->funcs.stringtable + qcptr))[i] = d;
}
break;
case ev_entity:
*(int *)(progfuncs->funcs.stringtable + qcptr) = atoi (s);
while(*s == ' ' || *s == '\t')
s++;
if (*s)
return false; //some kind of junk in there.
break;
case ev_field:
@ -1311,7 +1313,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
break;
case ev_function:
if (s[1]==':'&&s[2]=='\0')
if (s[0] && s[1]==':'&&s[2]=='\0') //this isn't right...
{
*(func_t *)(progfuncs->funcs.stringtable + qcptr) = 0;
return true;
@ -1326,7 +1328,7 @@ pbool ED_ParseEpair (progfuncs_t *progfuncs, size_t qcptr, unsigned int fldofs,
break;
default:
break;
return false;
}
return true;
}
@ -1341,7 +1343,7 @@ Used for initial level load and for savegames.
====================
*/
#if 1
const char *ED_ParseEdict (progfuncs_t *progfuncs, const char *data, edictrun_t *ent)
static const char *ED_ParseEdict (progfuncs_t *progfuncs, const char *data, edictrun_t *ent, pbool *out_maphack)
{
fdef_t *key;
pbool init;
@ -1432,8 +1434,19 @@ const char *ED_ParseEdict (progfuncs_t *progfuncs, const char *data, edictrun_t
}
cont:
switch(key->type)
{
case ev_function:
case ev_field:
case ev_entity:
case ev_pointer:
*out_maphack = true; //one of these types of fields means evil maphacks are at play.
break;
}
if (!ED_ParseEpair (progfuncs, (char*)ent->fields - progfuncs->funcs.stringtable, key->ofs, key->type, qcc_token))
{
if (externs->badfield && externs->badfield(&progfuncs->funcs, (struct edict_s*)ent, keyname, qcc_token))
continue;
continue;
// Sys_Error ("ED_ParseEdict: parse error on entities");
}
@ -1911,6 +1924,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
int crc = 1;
int entsize = 0;
int numents = 0;
pbool maphacks = false;
pbool resethunk=0;
pbool isloadgame;
@ -2021,7 +2035,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
ed->ereftype = ER_ENTITY;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
file = ED_ParseEdict(progfuncs, file, ed);
file = ED_ParseEdict(progfuncs, file, ed, &maphacks);
if (entspawned)
entspawned(ppf, (struct edict_s *)ed, ctx, datastart, file);
@ -2262,7 +2276,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
externs->entspawn((struct edict_s *) ed, true);
ed->ereftype = ER_ENTITY;
file = ED_ParseEdict (progfuncs, file, ed);
file = ED_ParseEdict (progfuncs, file, ed, &maphacks);
}
sv_num_edicts = ++numents;
continue;
@ -2292,7 +2306,7 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PD
ed->ereftype = ER_ENTITY;
if (externs->entspawn)
externs->entspawn((struct edict_s *) ed, true);
file = ED_ParseEdict(progfuncs, file, ed);
file = ED_ParseEdict(progfuncs, file, ed, &maphacks);
if (entspawned)
entspawned(ppf, (struct edict_s *)ed, ctx, datastart, file);
@ -2409,6 +2423,7 @@ struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, const char *buf, size_
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
edictrun_t *ent;
const char *start = buf;
pbool maphacks = false; //don't really care.
buf = QCC_COM_Parse(buf); //read the key
if (!buf || !*qcc_token)
@ -2425,7 +2440,7 @@ struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, const char *buf, size_
if (ent->ereftype == ER_FREE && externs->entspawn)
externs->entspawn((struct edict_s *) ent, false);
buf = ED_ParseEdict(progfuncs, buf, ent);
buf = ED_ParseEdict(progfuncs, buf, ent, &maphacks);
*size = buf - start;

View file

@ -392,7 +392,6 @@ char *PDECL ED_NewString (pubprogfuncs_t *ppf, const char *string, int minlength
void PDECL ED_Print (pubprogfuncs_t *progfuncs, struct edict_s *ed);
//void ED_Write (FILE *f, edictrun_t *ed);
const char *ED_ParseEdict (progfuncs_t *progfuncs, const char *data, edictrun_t *ent);
//void ED_WriteGlobals (FILE *f);
void ED_ParseGlobals (char *data);

View file

@ -600,7 +600,7 @@ extern qboolean ssqc_deprecated_warned;
#define svcdp_showlmp 35 // [string] slotname [string] lmpfilename [short] x [short] y
#define svcdp_hidelmp 36 // [string] slotname
#define TE_RAILTRAIL_NEH 15 // [vector] origin [coord] red [coord] green [coord] blue (fixme: ignored)
//#define TE_RAILTRAIL_NEH 15 // [vector] origin [coord] red [coord] green [coord] blue (fixme: ignored)
#define TE_EXPLOSION3_NEH 16 // [vector] origin [coord] red [coord] green [coord] blue (fixme: ignored)
#define TE_LIGHTNING4_NEH 17 // [string] model [entity] entity [vector] start [vector] end
#define TE_SMOKE_NEH 18
@ -861,7 +861,7 @@ void NPP_NQFlush(void)
buffer[0] = svcfte_cgamepacket;
}
break;
case TE_EXPLOSION:
case TENQ_NQEXPLOSION:
if (writedest == &sv.datagram)
{ //for old clients, use a te_explosion.
//for clients that support it, use a TEQW_EXPLOSIONNOSPRITE
@ -880,7 +880,7 @@ void NPP_NQFlush(void)
requireextension = PEXT_TE_BULLET;
SV_MulticastProtExt(org, multicasttype, pr_global_struct->dimension_send, 0, requireextension);
buffer[1] = TEQW_EXPLOSION_NOSPRITE;
buffer[1] = TEQW_NQEXPLOSION;
}
break;
case TENQ_BEAM:
@ -901,7 +901,7 @@ void NPP_NQFlush(void)
memcpy(&cd, &buffer[2+destprim->coordsize*2], destprim->coordsize);
org[2] = MSG_FromCoord(cd, destprim->coordsize);
buffer[1] = TE_EXPLOSION; //use a generic crappy explosion
buffer[1] = TEQW_QWEXPLOSION; //use a generic crappy explosion
SZ_Write(&sv.multicast, buffer, bufferlen-2); //trim the two trailing colour bytes
SV_MulticastProtExt(org, multicasttype, pr_global_struct->dimension_send, 0, requireextension);
}
@ -1240,7 +1240,7 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
multicasttype=MULTICAST_PHS;
protocollen = destprim->coordsize*6+sizeof(short)+sizeof(qbyte)*2;
break;
case TE_GUNSHOT:
case TENQ_NQGUNSHOT:
multicastpos=3;
multicasttype=MULTICAST_PVS;
//we need to emit annother qbyte here. QuakeWorld has a number of particles.
@ -1249,7 +1249,7 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
data = 1;
protocollen = destprim->coordsize*3+sizeof(qbyte)*3;
break;
case TE_EXPLOSION:
case TENQ_NQEXPLOSION:
case TE_SPIKE:
case TE_SUPERSPIKE:
multicastpos=2;
@ -1279,12 +1279,12 @@ void NPP_NQWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
multicasttype=MULTICAST_PHS;
break;
case TE_EXPLOSIONSMALL2:
data = TE_EXPLOSION;
data = TEQW_QWEXPLOSION;
protocollen = sizeof(qbyte)*2 + destprim->coordsize*3;
multicastpos=2;
multicasttype=MULTICAST_PHS;
break;
case TE_RAILTRAIL:
case TEQW_RAILTRAIL:
protocollen = destprim->coordsize*6+sizeof(qbyte)*1;
multicastpos=2;
multicasttype=MULTICAST_PHS;
@ -1904,7 +1904,7 @@ void NPP_QWFlush(void)
}
break;
case TEQW_LIGHTNINGBLOOD:
case TEQW_BLOOD: //needs to be converted to a particle
case TEQW_QWBLOOD: //needs to be converted to an svc_particle
{
vec3_t org;
qbyte count;
@ -1957,7 +1957,7 @@ void NPP_QWFlush(void)
NPP_AddData(&colour, sizeof(qbyte));
}
break;
case TE_GUNSHOT: //needs byte 3 removed
case TEQW_QWGUNSHOT: //needs byte 3 removed
if (bufferlen >= 3)
{
memmove(buffer+2, buffer+3, bufferlen-3);
@ -2184,14 +2184,14 @@ void NPP_QWWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
multicasttype=MULTICAST_PHS;
protocollen = destprim->coordsize*6+sizeof(short)+sizeof(qbyte)*2;
break;
case TEQW_BLOOD: //needs to be converted to a particle
case TE_GUNSHOT: //needs qbyte 2 removed
case TEQW_QWBLOOD: //needs to be converted to a particle
case TEQW_QWGUNSHOT: //needs qbyte 2 removed
multicastpos=3;
multicasttype=MULTICAST_PVS;
protocollen = destprim->coordsize*3+sizeof(qbyte)*3;
break;
case TEQW_LIGHTNINGBLOOD:
case TE_EXPLOSION:
case TEQW_QWEXPLOSION:
case TE_SPIKE:
case TE_SUPERSPIKE:
multicastpos=2;
@ -2207,7 +2207,7 @@ void NPP_QWWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
multicasttype=MULTICAST_PVS;
protocollen = destprim->coordsize*3+sizeof(qbyte)*2;
break;
case TE_RAILTRAIL:
case TEQW_RAILTRAIL:
multicastpos=1;
multicasttype=MULTICAST_PVS;
protocollen = destprim->coordsize*3+sizeof(qbyte)*1;

View file

@ -3226,7 +3226,7 @@ void QCBUILTIN PF_particle (pubprogfuncs_t *prinst, globalvars_t *pr_globals) //
if (color == 73)
{
MSG_WriteByte (&sv.multicast, svc_temp_entity);
MSG_WriteByte (&sv.multicast, TEQW_BLOOD);
MSG_WriteByte (&sv.multicast, TEQW_QWBLOOD);
MSG_WriteByte (&sv.multicast, count<10?1:(count+10)/20);
MSG_WriteCoord (&sv.multicast, org[0]);
MSG_WriteCoord (&sv.multicast, org[1]);
@ -3292,7 +3292,7 @@ static void QCBUILTIN PF_te_blooddp (pubprogfuncs_t *prinst, globalvars_t *pr_gl
(void)dir; //FIXME: sould be sending TEDP_BLOOD
MSG_WriteByte (&sv.multicast, svc_temp_entity);
MSG_WriteByte (&sv.multicast, TEQW_BLOOD);
MSG_WriteByte (&sv.multicast, TEQW_QWBLOOD);
MSG_WriteByte (&sv.multicast, count<10?1:(count+10)/20);
MSG_WriteCoord (&sv.multicast, org[0]);
MSG_WriteCoord (&sv.multicast, org[1]);
@ -3878,6 +3878,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
else
SV_StuffcmdToClient(cl, str);
}
#ifdef MVD_RECORDING
if (!(flags & STUFFCMD_IGNOREINDEMO))
if (sv.mvdrecording)
{
@ -3885,6 +3886,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
MSG_WriteByte (msg, svc_stufftext);
MSG_WriteString (msg, str);
}
#endif
return;
}
@ -3948,6 +3950,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
SV_StuffcmdToClient(cl, str);
}
#ifdef MVD_RECORDING
if (!(flags & STUFFCMD_IGNOREINDEMO))
if (sv.mvdrecording)
{
@ -3955,6 +3958,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
MSG_WriteByte (msg, svc_stufftext);
MSG_WriteString (msg, str);
}
#endif
//this seems a little dangerous. v_cshift could leave a spectator's machine unusable if they switch players at unfortunate times.
if (!(flags & STUFFCMD_DEMOONLY))
@ -4444,6 +4448,7 @@ static void QCBUILTIN PF_getmodelindex (pubprogfuncs_t *prinst, struct globalvar
G_FLOAT(OFS_RETURN) = PF_precache_model_Internal(prinst, s, queryonly);
}
#ifndef NOLEGACY
void QCBUILTIN PF_precache_vwep_model (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i;
@ -4480,6 +4485,7 @@ void QCBUILTIN PF_precache_vwep_model (pubprogfuncs_t *prinst, struct globalvars
G_FLOAT(OFS_RETURN) = 0;
}
}
#endif
// warning: PF_svcoredump defined but not used
/*
@ -4620,6 +4626,7 @@ void QCBUILTIN PF_applylightstyle(int style, const char *val, vec3_t rgb)
}
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
if (style < MAX_STANDARDLIGHTSTYLES || *val)
@ -4645,6 +4652,7 @@ void QCBUILTIN PF_applylightstyle(int style, const char *val, vec3_t rgb)
}
}
}
#endif
}
/*
@ -5572,9 +5580,12 @@ static void QCBUILTIN PF_qtBroadcast_WriteEntity (pubprogfuncs_t *prinst, struct
//======================================================
//copes with any qw point entities.
void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is available for some tent types.
void SV_point_tempentity (vec3_t o, int qwtype, int count) //count (usually 1) is available for some tent types.
{
int split=0;
#ifdef NQPROT
int nqtype = qwtype;
#endif
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
@ -5586,49 +5597,63 @@ void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, svc_temp_entity);
#endif
switch(type)
switch(qwtype)
{
case TE_BULLET:
MSG_WriteByte (&sv.multicast, TE_SPIKE);
qwtype = TE_BULLET;
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, TE_SPIKE);
nqtype = TE_BULLET;
#endif
type = TE_BULLET;
split = PEXT_TE_BULLET;
break;
case TE_SUPERBULLET:
case TEQW_SUPERBULLET:
MSG_WriteByte (&sv.multicast, TE_SUPERSPIKE);
qwtype = TEQW_SUPERBULLET;
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, TE_SUPERSPIKE);
nqtype = TE_SUPERSPIKE;
#endif
type = TE_SUPERBULLET;
split = PEXT_TE_BULLET;
break;
case TEQW_BLOOD:
case TE_GUNSHOT:
MSG_WriteByte (&sv.multicast, type);
case TEQW_QWBLOOD:
case TEQW_QWGUNSHOT:
MSG_WriteByte (&sv.multicast, qwtype);
MSG_WriteByte (&sv.multicast, count);
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, type); //nq doesn't have a count.
MSG_WriteByte (&sv.nqmulticast, nqtype); //nq doesn't have a count.
#endif
break;
case TEQW_EXPLOSION_NOSPRITE:
MSG_WriteByte (&sv.multicast, TE_EXPLOSION);
case TEQW_QWEXPLOSION:
MSG_WriteByte (&sv.multicast, TEQW_QWEXPLOSION);
qwtype = -1;
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, TE_EXPLOSION);
MSG_WriteByte (&sv.nqmulticast, TENQ_NQEXPLOSION);
nqtype = TENQ_QWEXPLOSION;
#endif
split = PEXT_TE_BULLET;
break;
case TEQW_NQEXPLOSION:
MSG_WriteByte (&sv.multicast, TEQW_QWEXPLOSION);
qwtype = TEQW_NQEXPLOSION;
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, TENQ_NQEXPLOSION);
nqtype = -1;
#endif
type = TEQW_EXPLOSION_NOSPRITE;
split = PEXT_TE_BULLET;
break;
case TE_LIGHTNING1:
case TE_LIGHTNING2:
case TE_LIGHTNING3:
SV_Error("SV_point_tempentity - type is a beam\n");
break;
default:
MSG_WriteByte (&sv.multicast, type);
MSG_WriteByte (&sv.multicast, qwtype);
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, type);
MSG_WriteByte (&sv.nqmulticast, nqtype);
#endif
break;
}
MSG_WriteCoord (&sv.multicast, o[0]);
MSG_WriteCoord (&sv.multicast, o[1]);
@ -5638,7 +5663,7 @@ void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is
MSG_WriteCoord (&sv.nqmulticast, o[1]);
MSG_WriteCoord (&sv.nqmulticast, o[2]);
#endif
if (type == TEQW_BLOOD || type == TEQW_LIGHTNINGBLOOD)
if (qwtype == TEQW_QWBLOOD || qwtype == TEQW_LIGHTNINGBLOOD)
{
#ifdef NQPROT
sv.nqmulticast.cursize = 0; //don't send a te_blood or lightningblood to an nq client - they'll die horribly.
@ -5653,7 +5678,7 @@ void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is
MSG_WriteChar (&sv.nqmulticast, 0);
MSG_WriteChar (&sv.nqmulticast, 0);
MSG_WriteByte (&sv.nqmulticast, count*20);
if (type == TEQW_BLOOD)
if (qwtype == TEQW_QWBLOOD)
MSG_WriteByte (&sv.nqmulticast, 73);
else
MSG_WriteByte (&sv.nqmulticast, 225);
@ -5665,13 +5690,29 @@ void SV_point_tempentity (vec3_t o, int type, int count) //count (usually 1) is
if (!split) //don't bother sending again.
return;
//this is for cool people (not nq users)
MSG_WriteByte (&sv.multicast, svc_temp_entity);
MSG_WriteByte (&sv.multicast, type);
MSG_WriteCoord (&sv.multicast, o[0]);
MSG_WriteCoord (&sv.multicast, o[1]);
MSG_WriteCoord (&sv.multicast, o[2]);
//this is for people with an extension to do that effect properly
if (qwtype >= 0)
{
MSG_WriteByte (&sv.multicast, svc_temp_entity);
MSG_WriteByte (&sv.multicast, qwtype);
if (qwtype == TEQW_QWBLOOD || qwtype == TEQW_QWGUNSHOT)
MSG_WriteByte (&sv.multicast, count);
MSG_WriteCoord (&sv.multicast, o[0]);
MSG_WriteCoord (&sv.multicast, o[1]);
MSG_WriteCoord (&sv.multicast, o[2]);
}
#ifdef NQPROT
if (nqtype >= 0)
{
MSG_WriteByte (&sv.nqmulticast, svc_temp_entity);
MSG_WriteByte (&sv.nqmulticast, nqtype);
if (/*nqtype == TENQ_QWBLOOD ||*/ nqtype == TEQW_NQGUNSHOT)
MSG_WriteByte (&sv.multicast, count);
MSG_WriteCoord (&sv.nqmulticast, o[0]);
MSG_WriteCoord (&sv.nqmulticast, o[1]);
MSG_WriteCoord (&sv.nqmulticast, o[2]);
}
#endif
SV_MulticastProtExt (o, MULTICAST_PHS, pr_global_struct->dimension_send, 0, split);
}
@ -6947,6 +6988,7 @@ static void QCBUILTIN PF_readcmd (pubprogfuncs_t *prinst, struct globalvars_s *p
SV_BeginRedirect(old, oldl);
}
#ifdef MVD_RECORDING
/*
=================
PF_forcedemoframe
@ -6963,7 +7005,7 @@ static void QCBUILTIN PF_forcedemoframe (pubprogfuncs_t *prinst, struct globalva
// if (G_FLOAT(OFS_PARM0) == 1)
// SV_SendDemoMessage();
}
#endif
/*
=================
@ -8667,10 +8709,15 @@ static void QCBUILTIN PF_te_gunshot(pubprogfuncs_t *prinst, struct globalvars_s
{
int count;
if (svprogfuncs->callargc >= 2)
{
count = G_FLOAT(OFS_PARM1);
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_QWGUNSHOT, count);
}
else
{
count = 1;
SV_point_tempentity(G_VECTOR(OFS_PARM0), TE_GUNSHOT, count);
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_NQGUNSHOT, count);
}
}
//DP_TE_QUADEFFECTS1
static void QCBUILTIN PF_te_gunshotquad(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -8710,7 +8757,7 @@ static void QCBUILTIN PF_te_bloodqw(pubprogfuncs_t *prinst, struct globalvars_s
count = G_FLOAT(OFS_PARM1);
else
count = 1;
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_BLOOD, count);
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_QWBLOOD, count);
}
//DP_TE_STANDARDEFFECTBUILTINS
@ -8729,10 +8776,10 @@ static void QCBUILTIN PF_te_superspikequad(pubprogfuncs_t *prinst, struct global
//void(vector org) te_explosion = #421;
static void QCBUILTIN PF_te_explosion(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
if (progstype != PROG_QW)
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_EXPLOSION_NOSPRITE, 1);
if (progstype == PROG_QW)
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_QWEXPLOSION, 1);
else
SV_point_tempentity(G_VECTOR(OFS_PARM0), TE_EXPLOSION, 1);
SV_point_tempentity(G_VECTOR(OFS_PARM0), TEQW_NQEXPLOSION, 1);
}
//DP_TE_QUADEFFECTS1
static void QCBUILTIN PF_te_explosionquad(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -8789,7 +8836,7 @@ static void QCBUILTIN PF_te_explosion2(pubprogfuncs_t *prinst, struct globalvars
for(;;)
{
MSG_WriteByte (&sv.multicast, svc_temp_entity);
MSG_WriteByte (&sv.multicast, old?TE_EXPLOSION:TEQW_EXPLOSION2);
MSG_WriteByte (&sv.multicast, old?TEQW_QWEXPLOSION:TEQW_EXPLOSION2);
MSG_WriteCoord (&sv.multicast, org[0]);
MSG_WriteCoord (&sv.multicast, org[1]);
MSG_WriteCoord (&sv.multicast, org[2]);
@ -8799,13 +8846,16 @@ static void QCBUILTIN PF_te_explosion2(pubprogfuncs_t *prinst, struct globalvars
MSG_WriteByte (&sv.multicast, length);
}
#ifdef NQPROT
MSG_WriteByte (&sv.nqmulticast, svc_temp_entity);
MSG_WriteByte (&sv.nqmulticast, TENQ_EXPLOSION2);
MSG_WriteCoord (&sv.nqmulticast, org[0]);
MSG_WriteCoord (&sv.nqmulticast, org[1]);
MSG_WriteCoord (&sv.nqmulticast, org[2]);
MSG_WriteByte (&sv.nqmulticast, start);
MSG_WriteByte (&sv.nqmulticast, length);
if (!old)
{
MSG_WriteByte (&sv.nqmulticast, svc_temp_entity);
MSG_WriteByte (&sv.nqmulticast, TENQ_EXPLOSION2);
MSG_WriteCoord (&sv.nqmulticast, org[0]);
MSG_WriteCoord (&sv.nqmulticast, org[1]);
MSG_WriteCoord (&sv.nqmulticast, org[2]);
MSG_WriteByte (&sv.nqmulticast, start);
MSG_WriteByte (&sv.nqmulticast, length);
}
#endif
if (old)
@ -10335,7 +10385,9 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("void(string dst, string src, float count)",NULL), true},
{"logtext", PF_logtext, 0, 0, 0, 100, D("void(string name, float console, string text)",NULL), true},
{"mvdcalltimeofday",PF_calltimeofday, 0, 0, 0, 102, D("void()",NULL), true},
#ifdef MVD_RECORDING
{"forcedemoframe", PF_forcedemoframe, 0, 0, 0, 103, D("void(float now)",NULL), true},
#endif
//end of mvdsv
#endif
{"redirectcmd", PF_redirectcmd, 0, 0, 0, 101, D("void(entity to, string str)","Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'.")},
@ -10996,7 +11048,9 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"setpause", PF_setpause, 0, 0, 0, 531, D("void(float pause)", "Sets whether the server should or should not be paused. This does not affect auto-paused things like when the console is down.")},
//end dp extras
//begin mvdsv extras
#ifndef NOLEGACY
{"precache_vwep_model",PF_precache_vwep_model,0,0, 0, 532, "float(string mname)"},
#endif
//end mvdsv extras
//restart dp extras
{"log", PF_Logarithm, 0, 0, 0, 532, D("float(float v, optional float base)", "Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by.")},
@ -11621,16 +11675,16 @@ void PR_DumpPlatform_f(void)
{"input_buttons", "float", CS},
{"input_impulse", "float", CS},
{"msg_entity", "entity", QW|NQ},
{"main", "void()", QW|NQ},
{"StartFrame", "void()", QW|NQ},
{"PlayerPreThink", "void()", QW|NQ},
{"PlayerPostThink", "void()", QW|NQ},
{"ClientKill", "void()", QW|NQ},
{"ClientConnect", "void()", QW|NQ},
{"PutClientInServer", "void()", QW|NQ},
{"ClientDisconnect", "void()", QW|NQ},
{"SetNewParms", "void()", QW|NQ},
{"SetChangeParms", "void()", QW|NQ},
{"main", "void()", QW|NQ, D("This function is never called, and is effectively dead code.")},
{"StartFrame", "void()", QW|NQ, D("Called at the start of each new physics frame. Player entities may think out of sequence so try not to depend upon explicit ordering too much.")},
{"PlayerPreThink", "void()", QW|NQ, D("With Prediction(QW compat/FTE default): Called before the player's input commands are processed.\nNo Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change.")},
{"PlayerPostThink", "void()", QW|NQ, D("Called after the player's input commands are processed.")},
{"ClientKill", "void()", QW|NQ, D("Called in response to 'cmd kill' (or just 'kill').")},
{"ClientConnect", "void(optional float csqcactive)", QW|NQ, D("Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to.")},
{"PutClientInServer", "void()", QW|NQ, D("Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc.")},
{"ClientDisconnect", "void()", QW|NQ, D("Called once a client disconnects or times out. Not guarenteed to be called on map changes.")},
{"SetNewParms", "void()", QW|NQ, D("Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set.")},
{"SetChangeParms", "void()", QW|NQ, D("Called for each client on map changes. Should copy various entity fields to the parm* globals.")},
{"end_sys_globals", "void", QW|NQ|CS|MENU},
@ -11826,7 +11880,7 @@ void PR_DumpPlatform_f(void)
{"GameCommand", "void(string cmdtext)", CS|MENU},
{"Cef_GeneratePage", "string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders)", QW|NQ|CS|MENU, "Provides an entrypoint to generate pages for the CEF plugin from within QC. Headers are \n-separated key/value pairs (use tokenizebyseparator)."},
// {"HTTP_GeneratePage", "string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders)", QW|NQ, "Provides an entrypoint to generate pages for pages requested over http (sv_listen_tcp+net_enable_http). Headers are \n-separated key/value pairs (use tokenizebyseparator)."},
{"HTTP_GeneratePage", "string(string uri, string method, string postdata, __in string requestheaders, __inout string responseheaders)", QW|NQ, "Provides an entrypoint to generate pages for pages requested over http (sv_port_tcp+net_enable_http). Headers are \r\n-separated key/value pairs (use tokenizebyseparator). Return __NULL__ to let the engine handle it, an empty string for a 404, and any other text for a regular 200 response."},
{"init", "void(float prevprogs)", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget)."},
{"initents", "void()", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules."},

View file

@ -2836,7 +2836,7 @@ cont:
return data;
}
static int QDECL Lua_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 Lua_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), pbool (PDECL *unhandledcallback)(pubprogfuncs_t *,void *,const char **))
{
lua_State *L = lua.ctx;
struct edict_s *ed = NULL;

View file

@ -77,9 +77,7 @@ void SV_SavegameComment (char *text, size_t textsize)
text[textsize-1] = '\0';
}
#ifndef QUAKETC
pbool SV_Legacy_ExtendedSaveData(pubprogfuncs_t *progfuncs, void *loadctx, const char **ptr)
pbool SV_ExtendedSaveData(pubprogfuncs_t *progfuncs, void *loadctx, const char **ptr)
{
char token[8192];
com_tokentype_t tt;
@ -164,6 +162,8 @@ pbool SV_Legacy_ExtendedSaveData(pubprogfuncs_t *progfuncs, void *loadctx, const
return true;
}
#ifndef QUAKETC
//expects the version to have already been parsed
static qboolean SV_Loadgame_Legacy(char *filename, vfsfile_t *f, int version)
{
@ -409,7 +409,7 @@ static qboolean 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_Legacy_ExtendedSaveData);
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL, SV_ExtendedSaveData);
BZ_Free(file);
PR_LoadGlabalStruct(false);
@ -947,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_Legacy_ExtendedSaveData);
sv.world.edict_size=svprogfuncs->load_ents(svprogfuncs, file, NULL, NULL, SV_ExtendedSaveData);
BZ_Free(file);
progstype = pt;
@ -1302,9 +1302,11 @@ void SV_SaveLevelCache(const char *savedir, qboolean dontharmgame)
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));
#ifndef NOLEGACY
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));
#endif
PR_Common_SaveGame(f, svprogfuncs, version >= CACHEGAME_VERSION_BINARY);

View file

@ -117,6 +117,7 @@ typedef struct
qboolean mapchangelocked;
#ifdef SAVEDGAMES
char loadgame_on_restart[MAX_QPATH]; //saved game to load on map_restart
double autosave_time;
#endif
double time;
@ -140,8 +141,6 @@ 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 {
@ -153,7 +152,9 @@ typedef struct
};
#endif
struct {
#ifndef NOLEGACY
const char *vw_model_precache[32];
#endif
const char *model_precache[MAX_PRECACHE_MODELS]; // NULL terminated
const char *particle_precache[MAX_SSPARTICLESPRE]; // NULL terminated
const char *sound_precache[MAX_PRECACHE_SOUNDS]; // NULL terminated
@ -164,8 +165,10 @@ typedef struct
qboolean stringsalloced; //if true, we need to free the string pointers safely rather than just memsetting them to 0
vec3_t lightstylecolours[MAX_LIGHTSTYLES];
#ifdef HEXEN2
char h2miditrack[MAX_QPATH];
qbyte h2cdtrack;
#endif
int allocated_client_slots; //number of slots available. (used mostly to stop single player saved games cacking up)
int spawned_client_slots; //number of PLAYER slots which are active (ie: putclientinserver was called)
@ -223,8 +226,6 @@ typedef struct
int signon_buffer_size[MAX_SIGNON_BUFFERS];
qbyte signon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM];
qboolean msgfromdemo;
qboolean gamedirchanged;
qboolean haveitems2; //use items2 field instead of serverflags for the high bits of STAT_ITEMS
@ -232,11 +233,12 @@ typedef struct
#ifdef MVD_RECORDING
qboolean mvdrecording;
#endif
//====================================================
//this lot is for serverside playback of demos
//this lot is for serverside playback of mvds. Use QTV instead.
#ifdef SERVER_DEMO_PLAYBACK
qboolean mvdplayback;
float realtime;
@ -408,9 +410,13 @@ enum
PRESPAWN_INVALID=0,
PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map
PRESPAWN_SERVERINFO,
#ifdef MVD_RECORDING
PRESPAWN_CSPROGS, //demos contain a copy of the csprogs.
#endif
PRESPAWN_SOUNDLIST, //nq skips these
#ifndef NOLEGACY
PRESPAWN_VWEPMODELLIST, //qw ugly extension.
#endif
PRESPAWN_MODELLIST,
PRESPAWN_MAPCHECK, //wait for old prespawn command
PRESPAWN_PARTICLES,
@ -676,8 +682,6 @@ typedef struct client_s
int trustlevel;
qboolean wasrecorded; //this client shouldn't get any net messages sent to them
vec3_t specorigin; //mvds need to use a different origin from the one QC has.
vec3_t specvelocity;
@ -737,7 +741,7 @@ typedef struct client_s
//=============================================================================
//mvd stuff
#ifdef MVD_RECORDING
#define MSG_BUF_SIZE 8192
typedef struct
@ -768,13 +772,13 @@ typedef struct {
int to;
int size;
qbyte data[1]; //gcc doesn't allow [] (?)
} header_t;
} mvd_header_t;
typedef struct
{
sizebuf_t sb;
int bufsize;
header_t *h;
mvd_header_t *h;
} demobuf_t;
typedef struct
@ -821,7 +825,7 @@ typedef struct
struct mvddest_s *dest;
} demo_t;
#endif
//=============================================================================
@ -935,10 +939,6 @@ typedef struct
struct netprim_s netprim;
qboolean demoplayback;
qboolean demorecording;
qboolean msgfromdemo;
int language; //the server operators language
laggedpacket_t *free_lagged_packet;
packet_entities_t entstatebuffer; /*just a temp buffer*/
@ -1479,7 +1479,7 @@ void SV_ChatThink(client_t *client);
#endif
#ifdef MVD_RECORDING
/*
//
// sv_mvd.c
@ -1551,12 +1551,16 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest);
extern demo_t demo; // server demo struct
extern cvar_t sv_demoDir;
extern cvar_t sv_demoAutoRecord;
extern cvar_t sv_demofps;
extern cvar_t sv_demoPings;
extern cvar_t sv_demoUseCache;
extern cvar_t sv_demoMaxSize;
extern cvar_t sv_demoMaxDirSize;
qboolean MVD_CheckSpace(qboolean broadcastwarnings);
void SV_MVD_AutoRecord (void);
char *SV_Demo_CurrentOutput(void);
void SV_Demo_PrintOutputs(void);
void SV_MVDInit(void);
@ -1575,6 +1579,7 @@ typedef struct
char challenge[32];
} qtvpendingstate_t;
int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p);
#endif
// savegame.c
void SV_Savegame_f (void);

View file

@ -692,8 +692,10 @@ void SV_Map_f (void)
}
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_MVDStop_f();
#endif
#ifndef SERVERONLY
if (!isDedicated) //otherwise, info used on map loading isn't present
@ -1999,7 +2001,9 @@ static void SV_Status_f (void)
Con_Printf("gamedir : %s\n", FS_GetGamedir(true));
if (sv.csqcdebug)
Con_Printf("csqc debug : true\n");
#ifdef MVD_RECORDING
SV_Demo_PrintOutputs();
#endif
NET_PrintConnectionsStatus(svs.sockets);
@ -2187,6 +2191,7 @@ void SV_ConSay_f(void)
SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg;
@ -2198,6 +2203,7 @@ void SV_ConSay_f(void)
MSG_WriteChar(msg, '\n');
MSG_WriteChar(msg, 0);
}
#endif
}
static void SV_ConSayOne_f (void)
@ -2927,6 +2933,7 @@ void SV_PrecacheList_f(void)
{
unsigned int i;
char *group = Cmd_Argv(1);
#ifndef NOLEGACY
if (!*group || !strncmp(group, "vwep", 4))
{
for (i = 0; i < sizeof(sv.strings.vw_model_precache)/sizeof(sv.strings.vw_model_precache[0]); i++)
@ -2935,6 +2942,7 @@ void SV_PrecacheList_f(void)
Con_Printf("vwep %u: %s\n", i, sv.strings.vw_model_precache[i]);
}
}
#endif
if (!*group || !strncmp(group, "model", 5))
{
for (i = 0; i < MAX_PRECACHE_MODELS; i++)

View file

@ -6,176 +6,6 @@
void NPP_MVDWriteByte(qbyte data, client_t *to, int broadcast);
void SV_New_f (void);
/*
float svdemotime;
FILE *svdemofile;
void SV_WriteDemoMessage (sizebuf_t *msg)
{
short len;
float time;
if (!svs.demorecording)
return;
time = LittleFloat(sv.time);
fwrite(&time, 1, sizeof(time), svdemofile);
len = LittleShort((short)msg->cursize);
fwrite(&len, 1, sizeof(len), svdemofile);
fwrite(msg->data, 1, msg->cursize, svdemofile);
}
qboolean SV_GetDemoMessage (void)
{
short len;
float time;
if (sv.time < svdemotime)
{
sv.msgfromdemo = false;
return NET_GetPacket(NS_SERVER);
}
sv.msgfromdemo = true;
fread(&len, 1, sizeof(len), svdemofile);
net_message.cursize = LittleShort(len);
fread(net_message.data, 1, net_message.cursize, svdemofile);
sv.time = svdemotime;
if (!fread(&time, 1, sizeof(time), svdemofile))
{
svs.demoplayback = false;
fclose(svdemofile);
}
svdemotime = LittleFloat(time);
net_from.ip[0] = 0;
net_from.ip[1] = 0;
net_from.ip[2] = 0;
net_from.ip[3] = 0;
return true;
}
qboolean SV_GetPacket (void)
{
if (svs.demoplayback)
return SV_GetDemoMessage ();
if (!NET_GetPacket (NS_SERVER))
return false;
SV_WriteDemoMessage (&net_message);
return true;
}
void SV_RecordDemo_f (void)
{
client_t *c;
int clnum;
int i;
char *name;
char *mapname;
name = Cmd_Argv(1);
mapname = Cmd_Argv(2);
svdemofile = fopen(name, "wb");
if (!svdemofile)
{
Con_Printf("Failed to open output file\n");
return;
}
fwrite(mapname, 1, sizeof(char)*(strlen(mapname)+1), svdemofile);
for (clnum = 0; clnum < svs.allocated_client_slots; clnum++) //clear the server so the clients reconnect and send nice fresh messages.
{
c = &svs.clients[clnum];
if (c->state < cs_connected)
continue;
ClientReliableWrite_Begin (c, svc_stufftext, 2+strlen("reconnect\n"));
ClientReliableWrite_String (c, "disconnect;wait;reconnect\n");
c->drop = true;
}
SV_SendMessagesToAll ();
svs.demorecording = true;
i = predictablerandgetseed();
fwrite(&i, 1, sizeof(i), svdemofile);
SV_SpawnServer(mapname, NULL, false, false);
}
void SV_LoadClientDemo (void);
void SV_PlayDemo_f(void)
{
client_t *c;
int clnum;
int i;
char *name;
float time;
char mapname[64];
name = Cmd_Argv(1);
if (svdemofile)
fclose(svdemofile);
svs.demoplayback=false;
svs.demorecording=false;
COM_FOpenFile(name, &svdemofile);
if (!svdemofile)
{
Con_Printf("Failed to open input file\n");
return;
}
#ifndef SERVERONLY
CL_Disconnect();
#endif
i = 0;
do
{
fread(mapname+i, 1, sizeof(char), svdemofile);
i++;
} while (mapname[i-1]);
svs.demoplayback = true;
for (clnum = 0; clnum < svs.allocated_client_slots; clnum++) //clear the server so new clients don't conflict.
{
c = &svs.clients[clnum];
if (c->state < cs_connected)
continue;
ClientReliableWrite_Begin (c, svc_stufftext, 2+strlen("reconnect\n"));
ClientReliableWrite_String (c, "reconnect\n");
c->drop = true;
}
SV_SendMessagesToAll ();
fread(&i, 1, sizeof(i), svdemofile);
predictablesrand(i);
fread(&time, 1, sizeof(time), svdemofile);
svdemotime = LittleFloat(time);
SV_SpawnServer(mapname, NULL, false, false);
}
*/
qboolean SV_GetPacket (void)
{

View file

@ -2363,6 +2363,7 @@ qboolean Cull_Traceline(pvscamera_t *cameras, edict_t *seen)
return true;
}
#ifdef MVD_RECORDING
void SV_WritePlayersToMVD (client_t *client, client_frame_t *frame, sizebuf_t *msg)
{
int j;
@ -2449,6 +2450,7 @@ void SV_WritePlayersToMVD (client_t *client, client_frame_t *frame, sizebuf_t *m
dcl->flags |= DF_GIB;
}
}
#endif
/*
=============
@ -4034,9 +4036,11 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
// send over the players in the PVS
if (svs.gametype != GT_HALFLIFE)
{
#ifdef MVD_RECORDING
if (client == &demo.recorder)
SV_WritePlayersToMVD(client, frame, msg);
else
#endif
SV_WritePlayersToClient (client, frame, clent, cameras, msg);
}

View file

@ -605,8 +605,10 @@ void SV_UnspawnServer (void) //terminate the running server.
Con_TPrintf("Server ended\n");
SV_FinalMessage("Server unspawned\n");
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_MVDStop (MVD_CLOSE_STOPPED, false);
#endif
for (i = 0; i < sv.allocated_client_slots; i++)
{
@ -1725,8 +1727,9 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
FS_ReferenceControl(0, 0);
#ifdef MVD_RECORDING
SV_MVD_SendInitialGamestate(NULL);
#endif
SSV_UpdateAddresses();

View file

@ -221,8 +221,10 @@ void SV_Shutdown (void)
SV_UnspawnServer();
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_MVDStop (MVD_CLOSE_STOPPED, false);
#endif
if (svs.entstatebuffer.entities)
{
@ -722,7 +724,9 @@ void SV_DropClient (client_t *drop)
{
// send notification to all remaining clients
SV_FullClientUpdate (drop, NULL);
#ifdef MVD_RECORDING
SV_MVD_FullClientUpdate(NULL, drop);
#endif
}
if (drop->controlled)
@ -968,8 +972,10 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
{
SV_FullClientUpdate(client, &svs.clients[i]);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_FullClientUpdate(client, &demo.recorder);
#endif
return;
}
@ -2549,7 +2555,7 @@ client_t *SVC_DirectConnect(void)
}
}
if (sv.msgfromdemo || net_from.type == NA_LOOPBACK) //normal rules don't apply
if (net_from.type == NA_LOOPBACK) //normal rules don't apply
;
else
{
@ -2737,9 +2743,6 @@ client_t *SVC_DirectConnect(void)
newcl->protocol = protocol;
Q_strncpyz(newcl->guid, guid, sizeof(newcl->guid));
if (sv.msgfromdemo)
newcl->wasrecorded = true;
// Con_TPrintf("%s:%s:connect\n", sv.name, NET_AdrToString (adrbuf, sizeof(adrbuf), &adr));
// if there is already a slot for this ip, drop it
@ -3127,89 +3130,82 @@ client_t *SVC_DirectConnect(void)
newcl->lockedtill = 0;
#ifdef SVRANKING
if (svs.demorecording || (svs.demoplayback && newcl->wasrecorded)) //disable rankings. Could cock things up.
{
SV_GetNewSpawnParms(newcl);
}
else
{
//rankid is figured out in extract from user info
if (!newcl->rankid) //failed to get a userid
if (!newcl->rankid) //failed to get a userid
{
if (rank_needlogin.value)
{
if (rank_needlogin.value)
{
SV_RejectMessage (protocol, "Bad password/username\nThis server requires logins. Please see the serverinfo for website and info on how to register.\n");
newcl->state = cs_free;
return NULL;
}
SV_RejectMessage (protocol, "Bad password/username\nThis server requires logins. Please see the serverinfo for website and info on how to register.\n");
newcl->state = cs_free;
return NULL;
}
// SV_OutOfBandPrintf (isquake2client, adr, "\nWARNING: You have not got a place on the ranking system, probably because a user with the same name has already connected and your pwds differ.\n\n");
if (!preserveparms)
SV_GetNewSpawnParms(newcl);
}
else
if (!preserveparms)
SV_GetNewSpawnParms(newcl);
}
else
{
rankstats_t rs;
if (!Rank_GetPlayerStats(newcl->rankid, &rs))
{
rankstats_t rs;
if (!Rank_GetPlayerStats(newcl->rankid, &rs))
{
SV_RejectMessage (protocol, "Rankings/Account system failed\n");
Con_TPrintf("banned player %s is trying to connect\n", newcl->name);
newcl->name[0] = 0;
InfoBuf_Clear(&newcl->userinfo, true);
newcl->state = cs_free;
return NULL;
}
SV_RejectMessage (protocol, "Rankings/Account system failed\n");
Con_TPrintf("banned player %s is trying to connect\n", newcl->name);
newcl->name[0] = 0;
InfoBuf_Clear(&newcl->userinfo, true);
newcl->state = cs_free;
return NULL;
}
if (rs.flags1 & RANK_MUTED)
{
SV_BroadcastTPrintf(PRINT_MEDIUM, "%s is muted (still)\n", newcl->name);
}
if (rs.flags1 & RANK_CUFFED)
{
SV_BroadcastTPrintf(PRINT_LOW, "%s is now cuffed permanently\n", newcl->name);
}
if (rs.flags1 & RANK_CRIPPLED)
{
SV_BroadcastTPrintf(PRINT_HIGH, "%s is still crippled\n", newcl->name);
}
if (rs.flags1 & RANK_MUTED)
{
SV_BroadcastTPrintf(PRINT_MEDIUM, "%s is muted (still)\n", newcl->name);
}
if (rs.flags1 & RANK_CUFFED)
{
SV_BroadcastTPrintf(PRINT_LOW, "%s is now cuffed permanently\n", newcl->name);
}
if (rs.flags1 & RANK_CRIPPLED)
{
SV_BroadcastTPrintf(PRINT_HIGH, "%s is still crippled\n", newcl->name);
}
if (rs.timeonserver)
{
if (preserveparms)
{ //do nothing.
}
else if (sv_resetparms.value)
{
SV_GetNewSpawnParms(newcl);
}
else
{
extern cvar_t rank_parms_first, rank_parms_last;
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
{
if (i < NUM_RANK_SPAWN_PARMS && i >= rank_parms_first.ival && i <= rank_parms_last.ival)
newcl->spawn_parms[i] = rs.parm[i];
else
newcl->spawn_parms[i] = 0;
}
}
if (rs.timeonserver > 3*60) //woo. Ages.
s = va(langtext("Welcome back %s. You have previously spent %i:%i hours connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/(60*60)), (int)((int)(rs.timeonserver/60)%(60)));
else //measure this guy in minuites.
s = va(langtext("Welcome back %s. You have previously spent %i mins connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/60));
SV_OutOfBandPrintf (protocol == SCP_QUAKE2, &adr, s);
if (rs.timeonserver)
{
if (preserveparms)
{ //do nothing.
}
else if (!preserveparms)
else if (sv_resetparms.value)
{
SV_GetNewSpawnParms(newcl);
SV_OutOfBandTPrintf (protocol == SCP_QUAKE2, &adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver);
}
//else loaded players already have their initial parms set
else
{
extern cvar_t rank_parms_first, rank_parms_last;
for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
{
if (i < NUM_RANK_SPAWN_PARMS && i >= rank_parms_first.ival && i <= rank_parms_last.ival)
newcl->spawn_parms[i] = rs.parm[i];
else
newcl->spawn_parms[i] = 0;
}
}
if (rs.timeonserver > 3*60) //woo. Ages.
s = va(langtext("Welcome back %s. You have previously spent %i:%i hours connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/(60*60)), (int)((int)(rs.timeonserver/60)%(60)));
else //measure this guy in minuites.
s = va(langtext("Welcome back %s. You have previously spent %i mins connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/60));
SV_OutOfBandPrintf (protocol == SCP_QUAKE2, &adr, s);
}
else if (!preserveparms)
{
SV_GetNewSpawnParms(newcl);
SV_OutOfBandTPrintf (protocol == SCP_QUAKE2, &adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver);
}
//else loaded players already have their initial parms set
}
#else
// call the progs to get default spawn parms for the new client
@ -3220,44 +3216,28 @@ client_t *SVC_DirectConnect(void)
#endif
if (!newcl->wasrecorded)
{
SV_AcceptMessage (newcl);
SV_AcceptMessage (newcl);
newcl->state = cs_free;
if (ISNQCLIENT(newcl))
{
//FIXME: we should delay this until we actually have a name, because right now they'll be called unnamed or unconnected or something
SV_BroadcastPrintf(PRINT_LOW, "New client connected\n");
}
else if (redirect)
{
}
else if (newcl->spectator)
{
SV_BroadcastTPrintf(PRINT_LOW, "spectator %s connected\n", newcl->name);
newcl->state = cs_free;
if (ISNQCLIENT(newcl))
{
//FIXME: we should delay this until we actually have a name, because right now they'll be called unnamed or unconnected or something
SV_BroadcastPrintf(PRINT_LOW, "New client connected\n");
}
else if (redirect)
{
}
else if (newcl->spectator)
{
SV_BroadcastTPrintf(PRINT_LOW, "spectator %s connected\n", newcl->name);
// Con_Printf ("Spectator %s connected\n", newcl->name);
}
else
{
SV_BroadcastTPrintf(PRINT_LOW, "client %s connected\n", newcl->name);
// Con_DPrintf ("Client %s connected\n", newcl->name);
}
newcl->state = cs_connected;
}
else
{
if (newcl->spectator)
{
SV_BroadcastTPrintf(PRINT_LOW, "recorded spectator %s connected\n", newcl->name);
// Con_Printf ("Recorded spectator %s connected\n", newcl->name);
}
else
{
SV_BroadcastTPrintf(PRINT_LOW, "recorded client %s connected\n", newcl->name);
// Con_DPrintf ("Recorded client %s connected\n", newcl->name);
}
SV_BroadcastTPrintf(PRINT_LOW, "client %s connected\n", newcl->name);
// Con_DPrintf ("Client %s connected\n", newcl->name);
}
newcl->state = cs_connected;
newcl->sendinfo = true;
if (redirect)
@ -3361,7 +3341,7 @@ int Rcon_Validate (void)
const size_t digestsize = 20;
size_t i, k;
unsigned char digest[digestsize];
unsigned char digest[512];
const unsigned char **tokens = alloca(sizeof(*tokens)*(Cmd_Argc()*2+5)); //overallocation in case argc is 0.
size_t *toksizes = alloca(sizeof(*toksizes)*(Cmd_Argc()*2+5)); //overallocation in case argc is 0.
if (strlen(pass) > digestsize*2)
@ -4778,11 +4758,13 @@ static void SV_PauseChanged(void)
ClientReliableWrite_Byte (cl, sv.paused!=0);
}
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
ClientReliableWrite_Begin (&demo.recorder, svc_setpause, 2);
ClientReliableWrite_Byte (&demo.recorder, sv.paused!=0);
}
#endif
}
/*
@ -5046,10 +5028,9 @@ float SV_Frame (void)
// send messages back to the clients that had packets read this frame
SV_SendClientMessages ();
// demo_start = Sys_DoubleTime ();
#ifdef MVD_RECORDING
SV_SendMVDMessage();
// demo_end = Sys_DoubleTime ();
// svs.stats.demo += demo_end - demo_start;
#endif
// send a heartbeat to the master if needed
SV_Master_Heartbeat ();
@ -5097,8 +5078,10 @@ static void SV_InfoChanged(void *context, const char *key)
if (context != &svs.info && *key == '_')
return; //these keys are considered private to originating client/server, and are not broadcast to anyone else
if (svs.demorecording)
#ifdef MVD_RECORDING
if (sv.mvdrecording)
InfoSync_Add(&demo.recorder.infosync, context, key); //make sure it gets written into mvds too.
#endif
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state >= cs_connected)
@ -5289,7 +5272,9 @@ void SV_InitLocal (void)
Cmd_AddCommandAD ("load", SV_Loadgame_f, SV_Savegame_c, "Loads an existing saved game.");
#endif
#ifdef MVD_RECORDING
SV_MVDInit();
#endif
svs.info.ChangeCB = SV_InfoChanged;
svs.info.ChangeCTX = &svs.info;

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quakedef.h"
#ifdef MVD_RECORDING
#ifndef CLIENTONLY
#include "winquake.h"
@ -26,16 +27,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "netinc.h"
void SV_MVDStop_f (void);
#define demo_size_padding 0x1000
static void QDECL SV_DemoDir_Callback(struct cvar_s *var, char *oldvalue);
cvar_t sv_demoAutoRecord = CVARAD("sv_demoAutoRecord", "0", "cl_autodemo", "If set, automatically record demos.\n-1: record on client connection.\n1+: record once there's this many active players on the server.");
cvar_t sv_demoUseCache = CVARD("sv_demoUseCache", "", "If set, demo data will be flushed only periodically");
cvar_t sv_demoCacheSize = CVAR("sv_demoCacheSize", "0x80000"); //half a meg
cvar_t sv_demoMaxDirSize = CVARD("sv_demoMaxDirSize", "102400", "Maximum allowed serverside storage for mvds. set to blank to remove the limit. New demos cannot be recorded once this reaches 0."); //so ktpro autorecords.
cvar_t sv_demoMaxDirSize = CVARD("sv_demoMaxDirSize", "100mb", "Maximum allowed serverside storage space for mvds. set to blank to remove the limit. New demos cannot be recorded once this size is reached."); //so ktpro autorecords.
cvar_t sv_demoMaxDirCount = CVARD("sv_demoMaxDirCount", "500", "Maximum allowed serverside mvds to record. Set to 0 to remove the limit. New demos cannot be recorded once this many demos have already been recorded."); //so ktpro autorecords.
cvar_t sv_demoMaxDirAge = CVARD("sv_demoMaxDirAge", "0", "Maximum allowed age for demos, any older demos will be deleted when sv_demoClearOld is set (this doesn't prevent recording new demos).");
cvar_t sv_demoClearOld = CVARD("sv_demoClearOld", "0", "Automatically delete demos to keep the demos count reasonable.");
cvar_t sv_demoDir = CVARC("sv_demoDir", "demos", SV_DemoDir_Callback);
cvar_t sv_demofps = CVAR("sv_demofps", "30");
cvar_t sv_demoPings = CVARD("sv_demoPings", "10", "Interval between ping updates in mvds");
@ -49,6 +53,7 @@ cvar_t qtv_password = CVAR( "qtv_password", "");
cvar_t qtv_maxstreams = CVARAFD( "qtv_maxstreams", "0",
"mvd_maxstreams", 0, "This is the maximum number of QTV clients/proxies that may be directly connected to the server. If empty then there is no limit. 0 disallows any streaming.");
cvar_t sv_demoAutoPrefix = CVAR("sv_demoAutoPrefix", "auto_");
cvar_t sv_demoPrefix = CVAR("sv_demoPrefix", "");
cvar_t sv_demoSuffix = CVAR("sv_demoSuffix", "");
cvar_t sv_demotxt = CVAR("sv_demotxt", "1");
@ -656,20 +661,20 @@ void DemoWriteQTVTimePad(int msecs) //broadcast to all proxies
// returns the file size
// return -1 if file is not present
// the file should be in BINARY mode for stupid OSs that care
#define MAX_DIRFILES 1000
#define MAX_MVD_NAME 64
typedef struct
{
char name[MAX_MVD_NAME];
int size;
qofs_t size;
time_t mtime;
searchpathfuncs_t *path;
} file_t;
typedef struct
{
file_t *files;
int size;
qofs_t size;
int numfiles;
int numdirs;
@ -690,11 +695,19 @@ static int QDECL Sys_listdirFound(const char *fname, qofs_t fsize, time_t mtime,
return true;
}
if (dir->numfiles == dir->maxfiles)
return true;
{
int nc = dir->numfiles + 256;
file_t *n = realloc(dir->files, nc*sizeof(*dir->files));
if (!n)
return false;
dir->files = n;
dir->maxfiles = nc;
}
f = &dir->files[dir->numfiles++];
Q_strncpyz(f->name, fname, sizeof(f->name));
f->size = fsize;
f->mtime = mtime;
f->path = spath;
dir->size += fsize;
return true;
@ -712,22 +725,29 @@ static int QDECL Sys_listdir_Sort(const void *va, const void *vb)
return -1;
}
static dir_t *Sys_listdir (char *path, char *ext, qboolean usesorting)
static dir_t *Sys_listdemos (char *path, int ispublic, qboolean usesorting)
{
const char *exts[] = {
".mvd", ".mvd.gz",
".qwz", ".qwz.gz",
#ifdef NQPROT
".dem", ".dem.gz",
#endif
#if defined(Q2SERVER) || defined(Q2CLIENT)
".dm2", ".dm2.gz"
#endif
};
char searchterm[MAX_QPATH];
size_t i;
unsigned int maxfiles = MAX_DIRFILES;
dir_t *dir = malloc(sizeof(*dir) + sizeof(*dir->files)*maxfiles);
dir_t *dir = malloc(sizeof(*dir));
memset(dir, 0, sizeof(*dir));
dir->files = (file_t*)(dir+1);
dir->maxfiles = maxfiles;
dir->files = NULL;
dir->maxfiles = 0;
Q_strncpyz(searchterm, va("%s/*%s", path, ext), sizeof(searchterm));
COM_EnumerateFiles(searchterm, Sys_listdirFound, dir);
if (!strcmp(ext, ".mvd"))
for (i = 0; i < (ispublic?2:countof(exts)); i++)
{
Q_strncpyz(searchterm, va("%s/*%s.gz", path, ext), sizeof(searchterm));
Q_strncpyz(searchterm, va("%s/*%s", path, exts[i]), sizeof(searchterm));
COM_EnumerateFiles(searchterm, Sys_listdirFound, dir);
}
@ -738,6 +758,8 @@ static dir_t *Sys_listdir (char *path, char *ext, qboolean usesorting)
}
static void Sys_freedir(dir_t *dir)
{
if (dir)
free(dir->files);
free(dir);
}
@ -1175,6 +1197,9 @@ void MVD_Init (void)
Cvar_Register (&sv_demoCacheSize, MVDVARGROUP);
Cvar_Register (&sv_demoMaxSize, MVDVARGROUP);
Cvar_Register (&sv_demoMaxDirSize, MVDVARGROUP);
Cvar_Register (&sv_demoMaxDirCount, MVDVARGROUP);
Cvar_Register (&sv_demoMaxDirAge, MVDVARGROUP);
Cvar_Register (&sv_demoClearOld, MVDVARGROUP);
Cvar_Register (&sv_demoDir, MVDVARGROUP);
Cvar_Register (&sv_demoPrefix, MVDVARGROUP);
Cvar_Register (&sv_demoSuffix, MVDVARGROUP);
@ -1182,6 +1207,8 @@ void MVD_Init (void)
Cvar_Register (&sv_demoExtraNames, MVDVARGROUP);
Cvar_Register (&sv_demoExtensions, MVDVARGROUP);
Cvar_Register (&sv_demoAutoCompress,MVDVARGROUP);
Cvar_Register (&sv_demoAutoRecord, MVDVARGROUP);
Cvar_Register (&sv_demoAutoPrefix, MVDVARGROUP);
Cvar_Register (&sv_demo_write_csqc,MVDVARGROUP);
}
@ -1261,6 +1288,7 @@ mvddest_t *SV_FindRecordFile(char *match, mvddest_t ***link_out)
}
return NULL;
}
/*
====================
SV_InitRecord
@ -1269,12 +1297,10 @@ SV_InitRecord
mvddest_t *SV_MVD_InitRecordFile (char *name)
{
char *s;
char *s, *txtname;
mvddest_t *dst;
vfsfile_t *file;
char path[MAX_OSPATH];
if (strlen(name) >= countof(dst->filename))
{
Con_Printf ("ERROR: couldn't open \"%s\". Too long.\n", name);
@ -1289,7 +1315,7 @@ mvddest_t *SV_MVD_InitRecordFile (char *name)
}
#ifdef AVAIL_GZDEC
if (!Q_strcasecmp("gz", COM_FileExtension(name, path, sizeof(path))))
if (!Q_strcasecmp(".gz", COM_GetFileExtension(name, NULL)))
file = FS_GZ_WriteFilter(file, true, true);
#endif
@ -1344,7 +1370,8 @@ mvddest_t *SV_MVD_InitRecordFile (char *name)
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording (%s):\n%s\n", "memory", name);
break;
case DEST_THREADEDFILE:
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording (%s):\n%s\n", "worker thread", name);
//SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording (%s):\n%s\n", "worker thread", name);
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording:\n%s\n", name);
break;
case DEST_FILE:
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording (%s):\n%s\n", "disk", name);
@ -1352,31 +1379,39 @@ mvddest_t *SV_MVD_InitRecordFile (char *name)
}
Cvar_ForceSet(Cvar_Get("serverdemo", "", CVAR_NOSET, ""), SV_Demo_CurrentOutput());
Q_strncpyz(path, name, MAX_OSPATH);
Q_strncpyz(path + strlen(path) - 3, "txt", MAX_OSPATH - strlen(path) + 3);
txtname = SV_MVDName2Txt(name);
if (sv_demotxt.value)
{
vfsfile_t *f;
f = FS_OpenVFS (path, "wt", FS_GAMEONLY);
if (f != NULL)
if (sv_demotxt.value == 2)
{
char buf[2000];
date_t date;
//this is a special mode for mods that want to write it instead (done via the sv_demoinfoadd command).
f = FS_OpenVFS (txtname, "wt", FS_GAMEONLY);
if (f)
VFS_CLOSE(f);
}
else
{
f = FS_OpenVFS (txtname, "wt", FS_GAMEONLY);
if (f != NULL)
{
char buf[2000];
date_t date;
COM_TimeOfDay(&date);
COM_TimeOfDay(&date);
snprintf(buf, sizeof(buf), "date %s\nmap %s\nteamplay %d\ndeathmatch %d\ntimelimit %d\n%s",date.str, svs.name, (int)teamplay.value, (int)deathmatch.value, (int)timelimit.value, SV_PrintTeams());
VFS_WRITE(f, buf, strlen(buf));
VFS_FLUSH(f);
VFS_CLOSE(f);
snprintf(buf, sizeof(buf), "date %s\nmap %s\nteamplay %d\ndeathmatch %d\ntimelimit %d\n%s",date.str, svs.name, (int)teamplay.value, (int)deathmatch.value, (int)timelimit.value, SV_PrintTeams());
VFS_WRITE(f, buf, strlen(buf));
VFS_FLUSH(f);
VFS_CLOSE(f);
}
}
}
else
{
FS_Remove(path, FS_GAMEONLY);
FS_FlushFSHashRemoved(path);
FS_Remove(txtname, FS_GAMEONLY);
FS_FlushFSHashRemoved(txtname);
}
return dst;
@ -1607,13 +1642,8 @@ qboolean SV_MVD_Record (mvddest_t *dest)
}
//pointless extensions that are redundant with mvds
demo.recorder.fteprotocolextensions &= ~PEXT_ACCURATETIMINGS | PEXT_HLBSP | PEXT_CHUNKEDDOWNLOADS;
#ifdef PEXT_Q2BSP
demo.recorder.fteprotocolextensions &= ~PEXT_Q2BSP;
#endif
#ifdef PEXT_Q3BSP
demo.recorder.fteprotocolextensions &= ~PEXT_Q3BSP;
#endif
demo.recorder.fteprotocolextensions &= ~PEXT_ACCURATETIMINGS | PEXT_CHUNKEDDOWNLOADS;
demo.recorder.fteprotocolextensions &= ~PEXT1_HIDEPROTOCOLS;
}
// else
// SV_WriteRecordMVDMessage(&buf, dem_read);
@ -1917,6 +1947,86 @@ char *SV_CleanName (unsigned char *name)
return out;
}
//figure out the actual size limit. this is somewhat approximate anyway.
qofs_t MVD_DemoMaxDirSize(void)
{
char *e;
double maxdirsize = strtod(sv_demoMaxDirSize.string, &e);
if (*e == ' ' || *e == '\t')
e++;
//that will be trailed by g[b], m[b], k[b], or b
if (*e == 'b' || *e == 'B')
return maxdirsize;
else if (*e == 'k' || *e == 'K')
return maxdirsize * 1024;
else if (*e == 'm' || *e == 'M')
return maxdirsize * 1024*1024;
else if (*e == 'g' || *e == 'G')
return maxdirsize * 1024*1024*1024;
else
return maxdirsize * 1024; //assume kb.
}
//returns if there's enough disk space to record another demo.
qboolean MVD_CheckSpace(qboolean broadcastwarnings)
{
dir_t *dir;
qofs_t maxdirsize = MVD_DemoMaxDirSize();
if (maxdirsize > 0 || sv_demoMaxDirCount.ival > 0 || sv_demoMaxDirAge.ival > 0)
{
dir = Sys_listdemos(sv_demoDir.string, false, SORT_BY_DATE);
if (sv_demoClearOld.ival && *sv_demoDir.string)
{
time_t removebeforetime = time(NULL) - sv_demoMaxDirAge.value*60*60*24;
while (dir->numfiles && (
(maxdirsize>0 && dir->size > maxdirsize) ||
(sv_demoMaxDirCount.ival>0 && dir->numfiles >= sv_demoMaxDirCount.ival) ||
(sv_demoMaxDirAge.ival && dir->files[dir->numfiles-1].mtime && dir->files[dir->numfiles-1].mtime - removebeforetime < 0)))
{
file_t *f = &dir->files[dir->numfiles-1]; //this is the file we want to kill.
if (!f->path || !f->path->RemoveFile)
{ //erm, can't remove it...
dir->size -= f->size;
dir->numfiles--;
continue;
}
if (f->path->RemoveFile(f->path, f->name))
{ //okay, looks like we managed to kill it.
Con_Printf(CON_WARNING"Removed demo \"%s\"\n", f->name);
dir->size -= f->size;
dir->numfiles--;
//Try to take the .txt too.
f->path->RemoveFile(f->path, SV_MVDName2Txt(f->name));
continue;
}
}
}
if (dir->numfiles && sv_demoMaxDirCount.ival>0 && dir->numfiles >= sv_demoMaxDirCount.ival)
{
if (broadcastwarnings)
SV_BroadcastPrintf(PRINT_MEDIUM, CON_WARNING"insufficient directory space, increase server's sv_demoMaxDirCount\n");
else
Con_Printf(CON_WARNING"insufficient demo space, increase sv_demoMaxDirCount\n");
Sys_freedir(dir);
return false;
}
if (dir->numfiles && maxdirsize>0 && dir->size > maxdirsize)
{
if (broadcastwarnings)
SV_BroadcastPrintf(PRINT_MEDIUM, CON_WARNING"insufficient directory space, increase server's sv_demoMaxDirSize\n");
else
Con_Printf(CON_WARNING"insufficient demo space, increase sv_demoMaxDirSize\n");
Sys_freedir(dir);
return false;
}
Sys_freedir(dir);
}
return true;
}
/*
====================
SV_Record_f
@ -1929,7 +2039,6 @@ void SV_MVD_Record_f (void)
int c;
char name[MAX_OSPATH+MAX_MVD_NAME];
char newname[MAX_MVD_NAME];
dir_t *dir;
c = Cmd_Argc();
if (c != 2)
@ -1943,15 +2052,8 @@ void SV_MVD_Record_f (void)
return;
}
dir = Sys_listdir(sv_demoDir.string, ".*", SORT_NO);
if (sv_demoMaxDirSize.value && dir->size > sv_demoMaxDirSize.value*1024)
{
Con_Printf("insufficient directory space, increase sv_demoMaxDirSize\n");
Sys_freedir(dir);
if (!MVD_CheckSpace(Cmd_FromGamecode()))
return;
}
Sys_freedir(dir);
dir = NULL;
Q_strncpyz(newname, va("%s%s", sv_demoPrefix.string, SV_CleanName(Cmd_Argv(1))),
sizeof(newname) - strlen(sv_demoSuffix.string) - 5);
@ -1975,6 +2077,49 @@ void SV_MVD_Record_f (void)
SV_MVD_Record (SV_MVD_InitRecordFile(name));
}
//called when a connecting player becomes active.
void SV_MVD_AutoRecord (void)
{
//not enabled (for the server) anyway.
if (sv_demoAutoRecord.ival <= 0)
return;
//don't record multiple...
if (sv.mvdrecording)
return;
//only do it if we're underneath our quotas.
if (!MVD_CheckSpace(true))
return;
if (sv_demoAutoRecord.ival > 0)
{
int playercount = 0, i;
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state >= cs_spawned)
playercount++;
}
if (playercount >= sv_demoAutoRecord.ival)
{ //okay, we've reached our player count, its time to start recording now.
char name[MAX_OSPATH];
char timestamp[64];
time_t tm = time(NULL);
strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", localtime(&tm));
Q_snprintfz(name, sizeof(name), "%s/%s%s_%s", sv_demoDir.string, sv_demoAutoPrefix.string, svs.name, timestamp);
#ifdef AVAIL_GZDEC
if (sv_demoAutoCompress.ival == 1 || !*sv_demoAutoCompress.string) //default is to gzip.
Q_strncatz(name, ".mvd.gz", sizeof(name));
else
#endif
Q_strncatz(name, ".mvd", sizeof(name));
FS_CreatePath (name, FS_GAMEONLY);
SV_MVD_Record (SV_MVD_InitRecordFile(name));
}
}
}
void SV_MVD_QTVReverse_f (void)
{
#if 1//ndef HAVE_TCP
@ -2170,7 +2315,6 @@ int Dem_CountTeamPlayers (char *t)
void SV_MVDEasyRecord_f (void)
{
int c;
dir_t *dir;
char name[1024];
char name2[MAX_OSPATH*7]; // scream
//char name2[MAX_OSPATH*2];
@ -2190,14 +2334,8 @@ void SV_MVDEasyRecord_f (void)
return;
}
dir = Sys_listdir(sv_demoDir.string, ".*", SORT_NO);
if (sv_demoMaxDirSize.value && dir->size > sv_demoMaxDirSize.value*1024)
{
Con_Printf("insufficient directory space, increase sv_demoMaxDirSize\n");
Sys_freedir(dir);
if (!MVD_CheckSpace(Cmd_FromGamecode()))
return;
}
Sys_freedir(dir);
if (c == 2)
{
@ -2286,9 +2424,10 @@ void SV_MVDList_f (void)
file_t *list;
float f;
int i,j,show;
qofs_t maxdirsize = MVD_DemoMaxDirSize();
Con_Printf("content of %s/*.mvd\n", sv_demoDir.string);
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
dir = Sys_listdemos(sv_demoDir.string, true, SORT_BY_DATE);
list = dir->files;
if (!list->name[0])
{
@ -2307,10 +2446,10 @@ void SV_MVDList_f (void)
for (d = demo.dest; d; d = d->nextdest)
{
if (d->desttype != DEST_STREAM && !strcmp(list->name, d->simplename))
Con_Printf("*%d: ^[^7%s\\demo\\%s/%s^] %dk\n", i, list->name, sv_demoDir.string, list->name, d->totalsize/1024);
Con_Printf("*%d: ^[^7%s\\demo\\%s/%s^] %uk\n", i, list->name, sv_demoDir.string, list->name, (unsigned int)(d->totalsize/1024));
}
if (!d)
Con_Printf("%d: ^[^7%s\\demo\\%s/%s^] %dk\n", i, list->name, sv_demoDir.string, list->name, list->size/1024);
Con_Printf("%d: ^[^7%s\\demo\\%s/%s^] %uk\n", i, list->name, sv_demoDir.string, list->name, (unsigned int)(list->size/1024));
}
}
@ -2318,9 +2457,9 @@ void SV_MVDList_f (void)
dir->size += d->totalsize;
Con_Printf("\ndirectory size: %.1fMB\n",(float)dir->size/(1024*1024));
if (sv_demoMaxDirSize.value)
if (maxdirsize)
{
f = (sv_demoMaxDirSize.value*1024 - dir->size)/(1024*1024);
f = (maxdirsize - dir->size)/(1024*1024);
if ( f < 0)
f = 0;
Con_Printf("space available: %.1fMB\n", f);
@ -2337,9 +2476,10 @@ void SV_UserCmdMVDList_f (void)
file_t *list;
float f;
int i,j,show;
qofs_t maxdirsize = MVD_DemoMaxDirSize();
SV_ClientPrintf(host_client, PRINT_HIGH, "available demos:\n");
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
dir = Sys_listdemos(sv_demoDir.string, true, SORT_BY_DATE);
list = dir->files;
if (!list->name[0])
{
@ -2363,23 +2503,26 @@ void SV_UserCmdMVDList_f (void)
if (!d)
{
if (host_client->fteprotocolextensions2 & PEXT_CSQC) //its a hack to use csqc this way, but oh well, but other clients don't want the gibberish.
SV_ClientPrintf(host_client, PRINT_HIGH, "%d: ^[%s\\type\\/download demos/%s^] %dk\n", i, list->name, list->name, list->size/1024);
SV_ClientPrintf(host_client, PRINT_HIGH, "%d: ^[%s\\type\\/download demos/%s^] %dk\n", i, list->name, list->name, (unsigned int)(list->size/1024));
else
SV_ClientPrintf(host_client, PRINT_HIGH, "%d: %s %dk\n", i, list->name, list->size/1024);
SV_ClientPrintf(host_client, PRINT_HIGH, "%d: %s %dk\n", i, list->name, (unsigned int)(list->size/1024));
}
}
if (host_client->num_backbuf == MAX_BACK_BUFFERS)
if (host_client->num_backbuf >= MAX_BACK_BUFFERS/2)
{
SV_ClientPrintf(host_client, PRINT_HIGH, "*MORE*\n");
break;
}
}
for (d = demo.dest; d; d = d->nextdest)
dir->size += d->totalsize;
SV_ClientPrintf(host_client, PRINT_HIGH, "\ndirectory size: %.1fMB\n",(float)dir->size/(1024*1024));
if (sv_demoMaxDirSize.value)
if (maxdirsize)
{
f = (sv_demoMaxDirSize.value*1024 - dir->size)/(1024*1024);
f = (maxdirsize - dir->size)/(1024*1024);
if ( f < 0)
f = 0;
SV_ClientPrintf(host_client, PRINT_HIGH, "space available: %.1fMB\n", f);
@ -2395,6 +2538,7 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
file_t *list;
float f;
int i;
qofs_t maxdirsize = MVD_DemoMaxDirSize();
VFS_PRINTF(pipe,
"<html>"
@ -2418,7 +2562,7 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
, fs_manifest->formalname, hostname.string);
VFS_PRINTF(pipe, "available demos:<br/>\n");
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
dir = Sys_listdemos(sv_demoDir.string, true, SORT_BY_DATE);
list = dir->files;
if (!list->name[0])
{
@ -2436,7 +2580,7 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
{
char datetime[64];
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", localtime(&list->mtime));
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %dk <a href='javascript:void(0)' onclick='playdemo(\"%s\")'>play</a> %s<br/>\n", i, list->name, list->name, list->size/1024, list->name, datetime);
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %uk <a href='javascript:void(0)' onclick='playdemo(\"%s\")'>play</a> %s<br/>\n", i, list->name, list->name, (unsigned int)(list->size/1024), list->name, datetime);
}
}
@ -2444,9 +2588,9 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
dir->size += d->totalsize;
VFS_PRINTF(pipe, "<br/>\ndirectory size: %.1fMB<br/>\n",(float)dir->size/(1024*1024));
if (sv_demoMaxDirSize.value)
if (maxdirsize)
{
f = (sv_demoMaxDirSize.value*1024 - dir->size)/(1024*1024);
f = (maxdirsize - dir->size)/(1024*1024);
if ( f < 0)
f = 0;
VFS_PRINTF(pipe, "space available: %.1fMB<br/>\n", f);
@ -2479,7 +2623,7 @@ char *SV_MVDNum(char *buffer, int bufferlen, int num) //lame number->name lookup
file_t *list;
dir_t *dir;
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
dir = Sys_listdemos(sv_demoDir.string, true, SORT_BY_DATE);
list = dir->files;
if (num < 0)
@ -2501,16 +2645,23 @@ char *SV_MVDNum(char *buffer, int bufferlen, int num) //lame number->name lookup
char *SV_MVDName2Txt(char *name)
{
char s[MAX_OSPATH];
const char *ext;
if (!name)
return NULL;
Q_strncpyz(s, name, MAX_OSPATH);
if (strstr(s, ".mvd.gz") != NULL)
Q_strncpyz(s + strlen(s) - 6, "txt", MAX_OSPATH - strlen(s) + 6);
else
Q_strncpyz(s + strlen(s) - 3, "txt", MAX_OSPATH - strlen(s) + 3);
ext = COM_GetFileExtension(s, NULL);
if (!Q_strcasecmp(ext, ".gz"))
ext = COM_GetFileExtension(s, ext);
else if (!Q_strcasecmp(ext, ".xz"))
ext = COM_GetFileExtension(s, ext);
if (!ext || !*ext) //if there's no extension on there, then make sure we're pointing to the end of the string.
ext = s+strlen(s);
if (ext > s+sizeof(s)+4) //make sure we don't overflow the buffer by truncating the base/path, ensuring that we don't write some other type of file.
ext = s+sizeof(s)+4; //should probably make this an error case and abort instead.
strcpy((char*)ext, ".txt");
return va("%s", s);
}
@ -2529,7 +2680,7 @@ void SV_MVDRemove_f (void)
if (Cmd_Argc() != 2)
{
Con_Printf("rmdemo <demoname> - removes the demo\nrmdemo *<token> - removes demo with <token> in the name\nrmdemo * - removes all demos\n");
Con_Printf("%s <demoname> - removes the demo\nrmdemo *<token> - removes demo with <token> in the name\nrmdemo * - removes all demos\n", Cmd_Argv(0));
return;
}
@ -2542,7 +2693,7 @@ void SV_MVDRemove_f (void)
// remove all demos with specified token
ptr++;
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
dir = Sys_listdemos(sv_demoDir.string, true, SORT_BY_DATE);
list = dir->files;
for (i = 0;i < dir->numfiles; list++)
{
@ -2605,14 +2756,14 @@ void SV_MVDRemoveNum_f (void)
if (Cmd_Argc() != 2)
{
Con_Printf("rmdemonum <#>\n");
Con_Printf("%s <#>\n", Cmd_Argv(0));
return;
}
val = Cmd_Argv(1);
if ((num = atoi(val)) == 0 && val[0] != '0')
{
Con_Printf("rmdemonum <#>\n");
Con_Printf("%s <#>\n", Cmd_Argv(0));
return;
}
@ -2644,12 +2795,13 @@ void SV_MVDInfoAdd_f (void)
char *name, *args, path[MAX_OSPATH];
vfsfile_t *f;
//** is a special hack for ktx
if (Cmd_Argc() < 3) {
Con_Printf("usage:MVDInfoAdd <demonum> <info string>\n<demonum> = * for currently recorded demo\n");
Con_Printf("%s <demonum> <info string>\n<demonum> = * for currently recorded demo\n", Cmd_Argv(0));
return;
}
if (!strcmp(Cmd_Argv(1), "*"))
if (!strcmp(Cmd_Argv(1), "*") || !strcmp(Cmd_Argv(1), "**"))
{
mvddest_t *active = SV_FindRecordFile(NULL, NULL);
if (!active)
@ -2673,19 +2825,34 @@ void SV_MVDInfoAdd_f (void)
snprintf(path, MAX_OSPATH, "%s/%s", sv_demoDir.string, name);
}
if ((f = FS_OpenVFS(path, "a+t", FS_GAMEONLY)) == NULL)
if ((f = FS_OpenVFS(path, "ab", FS_GAMEONLY)) == NULL)
{
Con_Printf("failed to open the file\n");
Con_Printf("%s: failed to open \"%s\"\n", Cmd_Argv(0), path);
return;
}
// skip demonum
args = Cmd_Args();
while (*args > 32) args++;
while (*args && *args <= 32) args++;
if (!strcmp(Cmd_Argv(1), "**"))
{
size_t fsize;
args = FS_LoadMallocFile(Cmd_Argv(2), &fsize);
if (args)
{
VFS_WRITE(f, args, fsize);
FS_FreeFile(args);
}
else
Con_Printf("%s: failed to open input file\n", Cmd_Argv(0));
}
else
{
// skip demonum
args = Cmd_Args();
while (*args > 32) args++;
while (*args && *args <= 32) args++;
VFS_WRITE(f, args, strlen(args));
VFS_WRITE(f, "\n", 1);
VFS_WRITE(f, args, strlen(args));
VFS_WRITE(f, "\n", 1);
}
VFS_FLUSH(f);
VFS_CLOSE(f);
}
@ -2697,7 +2864,7 @@ void SV_MVDInfoRemove_f (void)
if (Cmd_Argc() < 2)
{
Con_Printf("usage:demoInfoRemove <demonum>\n<demonum> = * for currently recorded demo\n");
Con_Printf("%s <demonum>\n<demonum> = * for currently recorded demo\n", Cmd_Argv(0));
return;
}
@ -2744,7 +2911,7 @@ void SV_MVDInfo_f (void)
if (Cmd_Argc() < 2)
{
Con_Printf("usage:demoinfo <demonum>\n<demonum> = * for currently recorded demo\n");
Con_Printf("%s <demonum>\n<demonum> = * for currently recorded demo\n", Cmd_Argv(0));
return;
}
@ -2806,14 +2973,14 @@ void SV_MVDPlayNum_f(void)
if (Cmd_Argc() != 2)
{
Con_Printf("mvdplaynum <#>\n");
Con_Printf("%s <#>\n", Cmd_Argv(0));
return;
}
val = Cmd_Argv(1);
if ((num = atoi(val)) == 0 && val[0] != '0')
{
Con_Printf("mvdplaynum <#>\n");
Con_Printf("%s <#>\n", Cmd_Argv(0));
return;
}
@ -2872,3 +3039,4 @@ void SV_MVDInit(void)
}
#endif
#endif

View file

@ -501,6 +501,7 @@ void VARGS SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...)
if(strlen(string) >= sizeof(string))
Sys_Error("SV_ClientPrintf: Buffer stomped\n");
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
@ -508,6 +509,7 @@ void VARGS SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...)
MSG_WriteByte (msg, level);
MSG_WriteString (msg, string);
}
#endif
if (cl->controller)
SV_PrintToClient(cl->controller, level, string);
@ -531,6 +533,7 @@ void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t stringnum, .
if(strlen(string) >= sizeof(string))
Sys_Error("SV_ClientTPrintf: Buffer stomped\n");
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
@ -538,6 +541,7 @@ void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t stringnum, .
MSG_WriteByte (msg, level);
MSG_WriteString (msg, string);
}
#endif
SV_PrintToClient(cl, level, string);
}
@ -585,6 +589,7 @@ void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...)
SV_PrintToClient(cl, level, string);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, strlen(string)+3);
@ -592,6 +597,7 @@ void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...)
MSG_WriteByte (msg, level);
MSG_WriteString (msg, string);
}
#endif
}
@ -1136,6 +1142,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
}
}
#ifdef MVD_RECORDING
if (sv.mvdrecording && ((demo.recorder.fteprotocolextensions & with) == with) && !(demo.recorder.fteprotocolextensions & without))
{
sizebuf_t *msg;
@ -1184,6 +1191,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
}
SZ_Write(msg, sv.multicast.data, sv.multicast.cursize);
}
#endif
#ifdef NQPROT
SZ_Clear (&sv.nqmulticast);
@ -1336,6 +1344,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
callback(client, &client->datagram, ctx);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg;
@ -1388,6 +1397,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
}
callback(&demo.recorder, msg, ctx);
}
#endif
}
//version does all the work now
@ -1803,12 +1813,14 @@ void SV_WriteCenterPrint(client_t *cl, char *s)
}
ClientReliableWrite_String (cl, s);
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, 2 + strlen(s));
MSG_WriteByte (msg, svc_centerprint);
MSG_WriteString (msg, s);
}
#endif
}
/*
@ -2928,8 +2940,10 @@ void SV_FlushBroadcasts (void)
}
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_MVD_WriteReliables(true);
#endif
SZ_Clear (&sv.reliable_datagram);
SZ_Clear (&sv.datagram);
@ -3126,6 +3140,7 @@ void SV_UpdateToReliableMessages (void)
ClientReliableWrite_Short(client, host_client->edict->v->frags);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin(dem_all, 0, 4);
@ -3133,6 +3148,7 @@ void SV_UpdateToReliableMessages (void)
MSG_WriteByte(msg, i);
MSG_WriteShort(msg, host_client->edict->v->frags);
}
#endif
host_client->old_frags = host_client->edict->v->frags;
}
@ -3194,6 +3210,7 @@ void SV_UpdateToReliableMessages (void)
ClientReliableWrite_Short(client, curfrags);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
{
sizebuf_t *msg = MVDWrite_Begin(dem_all, 0, 4);
@ -3201,6 +3218,7 @@ void SV_UpdateToReliableMessages (void)
MSG_WriteByte(msg, i);
MSG_WriteShort(msg, curfrags);
}
#endif
host_client->old_frags = curfrags;
}
@ -3384,6 +3402,7 @@ void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *k
SV_SendUserinfoChange(client, about, isbasic, key, newval);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording && (isbasic || (demo.recorder.fteprotocolextensions & PEXT_BIGUSERINFOS)))
{
sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(newval)+4);
@ -3392,6 +3411,7 @@ void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *k
MSG_WriteString (msg, key);
MSG_WriteString (msg, newval);
}
#endif
}
/*
@ -3470,13 +3490,6 @@ void SV_SendClientMessages (void)
SV_ChatThink(c);
#endif
if (c->wasrecorded)
{
c->netchan.message.cursize = 0;
c->datagram.cursize = 0;
continue;
}
#ifdef NEWSPEEDCHEATPROT
//allow the client more time for client movement.
//if they're running too slowly, FORCE them to run
@ -3665,8 +3678,10 @@ void SV_SendClientMessages (void)
}
c->lastoutgoingphysicstime = sv.world.physicstime;
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
SV_ProcessSendFlags(&demo.recorder);
#endif
SV_CleanupEnts();
}
@ -3674,6 +3689,7 @@ void SV_SendClientMessages (void)
//#pragma optimize( "", on )
//#endif
#ifdef MVD_RECORDING
void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time);
void DemoWriteQTVTimePad(int msecs);
@ -3871,7 +3887,7 @@ void SV_SendMVDMessage(void)
// MVDSetMsgBuf(demo.dbuf,&demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf);
}
#endif
/*

View file

@ -1050,19 +1050,30 @@ void SV_SendClientPrespawnInfo(client_t *client)
else if (client->prespawn_idx == 4)
{
int track = 0;
const char *noise = "";
if (progstype == PROG_H2)
{
track = sv.h2cdtrack; //hexen2 has a special hack
}
else if (svprogfuncs)
{
track = ((edict_t*)sv.world.edicts)->v->sounds;
noise = PR_GetString(svprogfuncs, ((edict_t*)sv.world.edicts)->v->noise);
}
ClientReliableWrite_Begin(client, svc_cdtrack, 2);
ClientReliableWrite_Byte (client, track);
if (ISNQCLIENT(client))
if (track == -1 && *noise)
SV_StuffcmdToClient(client, va("cd loop \"%s\"\n", noise));
else
{
ClientReliableWrite_Begin(client, svc_cdtrack, 2);
ClientReliableWrite_Byte (client, track);
if (ISNQCLIENT(client))
ClientReliableWrite_Byte (client, track);
if (!track && *sv.h2miditrack)
SV_StuffcmdToClient(client, va("music \"%s\"\n", sv.h2miditrack));
if (!track && *sv.h2miditrack)
SV_StuffcmdToClient(client, va("music \"%s\"\n", sv.h2miditrack));
}
}
else if (client->prespawn_idx == 5)
{
@ -1080,6 +1091,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
}
}
#ifdef MVD_RECORDING
if (client->prespawn_stage == PRESPAWN_CSPROGS)
{
extern cvar_t sv_demo_write_csqc;
@ -1144,6 +1156,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
client->prespawn_stage++;
client->prespawn_idx = 0;
}
#endif
if (client->prespawn_stage == PRESPAWN_SOUNDLIST)
{
@ -1218,6 +1231,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
}
}
#ifndef NOLEGACY
if (client->prespawn_stage == PRESPAWN_VWEPMODELLIST)
{
//no indicies. the protocol can't cope with them.
@ -1257,6 +1271,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
}
client->prespawn_stage++;
}
#endif
if (client->prespawn_stage == PRESPAWN_MODELLIST)
{
@ -1702,7 +1717,7 @@ void SVQW_PreSpawn_f (void)
}
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount && !sv.msgfromdemo)
if ( atoi(Cmd_Argv(1)) != svs.spawncount)
{
Con_Printf ("SV_PreSpawn_f from different level\n");
//FIXME: we shouldn't need the following line.
@ -1769,7 +1784,7 @@ void SVQW_Spawn_f (void)
}
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount && !sv.msgfromdemo)
if ( atoi(Cmd_Argv(1)) != svs.spawncount)
{
Con_Printf ("SV_Spawn_f from different level\n");
SV_New_f ();
@ -1785,7 +1800,9 @@ void SVQW_Spawn_f (void)
// normally this could overflow, but no need to check due to backbuf
for (i=0, client = svs.clients ; i<svs.allocated_client_slots ; i++, client++)
SV_FullClientUpdate(client, host_client);
#ifdef MVD_RECORDING
SV_MVD_FullClientUpdate(NULL, host_client);
#endif
// send all current light styles
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
@ -2020,9 +2037,15 @@ void SV_Begin_Core(client_t *split)
SV_SpawnParmsToQC(split);
// call the spawn function
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, split->edict);
PR_ExecuteProgram (svprogfuncs, SpectatorConnect);
{
globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
pr_global_struct->time = sv.world.physicstime;
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, split->edict);
if (pr_globals)
G_FLOAT(OFS_PARM0) = split->csqcactive; //this arg is part of EXT_CSQC_1, but doesn't have to be supported by the mod
PR_ExecuteProgram (svprogfuncs, SpectatorConnect);
}
}
sv.spawned_observer_slots++;
}
@ -2156,7 +2179,7 @@ void SV_Begin_f (void)
split->state = cs_spawned;
// handle the case of a level changing while a client was connecting
if ( atoi(Cmd_Argv(1)) != svs.spawncount && !sv.msgfromdemo)
if ( atoi(Cmd_Argv(1)) != svs.spawncount)
{
Con_Printf ("SV_Begin_f from different level\n");
SV_New_f ();
@ -2216,6 +2239,10 @@ void SV_Begin_f (void)
MSG_WriteAngle (&host_client->netchan.message, host_client->edict->v->angles[1] );
MSG_WriteAngle (&host_client->netchan.message, 0 );
}
#ifdef MVD_RECORDING
SV_MVD_AutoRecord();
#endif
}
//=============================================================================
@ -2708,6 +2735,7 @@ void SV_VoiceReadPacket(void)
ring->receiver[j>>3] |= 1<<(j&3);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording && sv_voip_record.ival && !(sv_voip_record.ival == 2 && !host_client->spectator))
{
sizebuf_t *msg;
@ -2733,6 +2761,7 @@ void SV_VoiceReadPacket(void)
MSG_WriteShort(msg, ring->datalen);
SZ_Write(msg, ring->data, ring->datalen);
}
#endif
}
void SV_VoiceInitClient(client_t *client)
{
@ -3041,7 +3070,6 @@ qboolean SV_AllowDownload (const char *name)
static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks)
{
extern cvar_t allow_download_anymap, allow_download_pakcontents;
extern cvar_t sv_demoDir;
qboolean protectedpak;
qboolean found;
static char tmpname[MAX_QPATH];
@ -3049,6 +3077,7 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
if (replacementname)
*replacementname = NULL;
#ifdef MVD_RECORDING
//mvdsv demo downloading support demonum/ -> demos/XXXX (sets up the client paths)
if (!Q_strncasecmp(name, "demonum/", 8))
{
@ -3066,6 +3095,7 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
return DLERR_REDIRECTFILE;
}
}
#endif
if (!SV_AllowDownload(name))
{
@ -3073,12 +3103,14 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
return DLERR_PERMISSIONS; //not permitted (even if it exists).
}
#ifdef MVD_RECORDING
//mvdsv demo downloading support. demos/ -> demodir (sets up the server paths)
if (!Q_strncasecmp(name, "demos/", 6))
{
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6);
name = tmpname;
}
#endif
if (!Q_strncasecmp(name, "package/", 8))
{
@ -3241,6 +3273,7 @@ void SV_DownloadSize_f(void)
}
}
#ifdef MVD_RECORDING
void SV_DemoDownload_f(void)
{
int arg;
@ -3298,6 +3331,7 @@ void SV_DemoDownload_f(void)
}
}
}
#endif
/*
==================
@ -3309,7 +3343,6 @@ void SV_BeginDownload_f(void)
char *name = Cmd_Argv(1);
char *redirection = NULL;
extern cvar_t allow_download_anymap, allow_download_pakcontents;
extern cvar_t sv_demoDir;
flocation_t loc;
int result;
@ -3682,13 +3715,14 @@ void SV_Say (qboolean team)
char t1[32], *t2;
int cls = 0;
float floodtime;
#ifdef MVD_RECORDING
sizebuf_t *msg;
qboolean mvdrecording;
#endif
qboolean sent[MAX_CLIENTS]; //so we don't send to the same splitscreen connection twice. (it's ugly)
int cln;
qboolean mvdrecording;
char *s, *s2;
if (Cmd_Argc () < 2)
@ -3780,8 +3814,10 @@ void SV_Say (qboolean team)
if (!(host_client->penalties & BAN_MUTE))
Sys_Printf ("%s", text);
#ifdef MVD_RECORDING
mvdrecording = sv.mvdrecording;
sv.mvdrecording = false; //so that the SV_ClientPrintf doesn't send to all players.
#endif
for (j = 0, client = svs.clients; j < svs.allocated_client_slots; j++, client++)
{
if (client->state != cs_spawned && client->state != cs_connected)
@ -3828,6 +3864,7 @@ void SV_Say (qboolean team)
SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
}
#ifdef MVD_RECORDING
sv.mvdrecording = mvdrecording;
if (!sv.mvdrecording || !cls)
@ -3842,6 +3879,7 @@ void SV_Say (qboolean team)
MSG_WriteByte (msg, svc_print);
MSG_WriteByte (msg, PRINT_CHAT);
MSG_WriteString (msg, text);
#endif
}
@ -4029,7 +4067,7 @@ void SV_Pause_f (void)
return;
}
if (host_client->spectator && !svs.demoplayback)
if (host_client->spectator)
{
SV_ClientTPrintf (host_client, PRINT_HIGH, "Spectators may not pause the game\n");
return;
@ -5476,7 +5514,9 @@ static void SVNQ_Spawn_f (void)
// normally this could overflow, but no need to check due to backbuf
for (i=0, client = svs.clients; i<sv.allocated_client_slots ; i++, client++)
SV_FullClientUpdate(client, host_client);
#ifdef MVD_RECORDING
SV_MVD_FullClientUpdate(NULL, host_client);
#endif
// send all current light styles
for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
@ -5958,11 +5998,13 @@ ucmd_t ucmds[] =
{"setinfo", SV_SetInfo_f},
{"serverinfo", SV_ShowServerinfo_f},
#ifdef MVD_RECORDING
/*demo/download commands*/
{"demolist", SV_UserCmdMVDList_f},
{"dlist", SV_UserCmdMVDList_f}, //apparently people are too lazy to type.
{"demoinfo", SV_MVDInfo_f},
{"dl", SV_DemoDownload_f},
#endif
{"stopdownload", SV_StopDownload_f},
{"dlsize", SV_DownloadSize_f},
@ -6098,8 +6140,8 @@ ucmd_t nqucmds[] =
/*various misc extensions*/
{"protocols", SVNQ_Protocols_f, true},
{"pext", SV_Pext_f, true},
{"enablecsqc", SV_EnableClientsCSQC},
{"disablecsqc", SV_DisableClientsCSQC},
{"enablecsqc", SV_EnableClientsCSQC, 2},
{"disablecsqc", SV_DisableClientsCSQC, 2},
{"challengeconnect", NULL},
/*spectating, this should be fun...*/
@ -6184,7 +6226,8 @@ void SV_ExecuteUserCommand (const char *s, qboolean fromQC)
{
if (u->func)
u->func();
PR_KrimzonParseCommand(s);
if (host_client->spawned)
PR_KrimzonParseCommand(s);
}
host_client = oldhost;
return;
@ -7491,6 +7534,7 @@ void SV_ReadQCRequest(void)
int i;
globalvars_t *pr_globals;
client_t *cl = host_client;
edict_t *ed;
if (!svprogfuncs)
{
@ -7550,7 +7594,14 @@ void SV_ReadQCRequest(void)
e = MSGSV_ReadEntity(host_client);
if (e < 0 || e >= sv.world.num_edicts)
e = 0;
G_INT(OFS_PARM0+i*3) = EDICT_TO_PROG(svprogfuncs, EDICT_NUM_PB(svprogfuncs, e));
ed = EDICT_NUM_PB(svprogfuncs, e);
if (!ed)
{
ed = sv.world.edicts;
Con_Printf("client %s sent invalid entity\n", fromclient->name);
host_client->drop = true;
}
G_INT(OFS_PARM0+i*3) = EDICT_TO_PROG(svprogfuncs, ed);
break;
}
i++;
@ -7564,6 +7615,7 @@ done:
else
fname = va("CSEv_%s", rname);
f = PR_FindFunction(svprogfuncs, fname, PR_ANY);
#ifndef NOLEGACY
if (!f)
{
if (i)
@ -7572,7 +7624,10 @@ done:
rname = va("Cmd_%s", rname);
f = PR_FindFunction(svprogfuncs, rname, PR_ANY);
}
if (!cl)
#endif
if (host_client->drop)
;
else if (!cl)
; //bad seat! not going to warn as they might have been removed recently
else if (f)
{
@ -7905,6 +7960,8 @@ void SV_ExecuteClientMessage (client_t *cl)
#endif
case clcdp_ackframe:
cl->delta_sequence = MSG_ReadLong();
if (cl->delta_sequence == -1 && cl->pendingdeltabits)
cl->pendingdeltabits[0] = UF_REMOVE;
SV_AckEntityFrame(cl, cl->delta_sequence);
break;
}

View file

@ -13,7 +13,11 @@ varying vec2 lm;
uniform vec4 e_lmscale;
void main ()
{
#ifdef LM
col = vec4(1.0);
#else
col = vec4(e_lmscale.rgb * ((v_normal.z < 0.73)?r_wallcolor:r_floorcolor), e_lmscale.a);
#endif
lm = v_lmcoord;
gl_Position = ftetransform();
}

View file

@ -3597,7 +3597,10 @@ static void BE_DrawMeshChain_Internal(void)
vkCmdBindVertexBuffers(vk.rendertarg->cbuf, 0, VK_BUFF_MAX, vertexbuffers, vertexoffsets);
if (BE_SetupMeshProgram(altshader->prog, altshader->passes, altshader->flags, idxcount))
{
// vkCmdPushConstants(vk.rendertarg->cbuf, altshader->prog->layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(shaderstate.curtexnums->factors), shaderstate.curtexnums->factors);
vkCmdDrawIndexed(vk.rendertarg->cbuf, idxcount, 1, idxfirst, 0, 0);
}
}
else if (1)
{