1
0
Fork 0
forked from fte/fteqw

dpp7: Treat 'dropped' c2s packets as choked when using dpp7 protocols. This is because the protocol provides no way to disambiguate, and I don't like false reports of packetloss (only reliables loss can be detected, and that's not frequent enough to be meaningful). Pings can still be determined with dpp7, for those few packets which are acked.

package manager: reworked to enable/disable plugins when downloaded, which can also be present-but-disabled.
package manager: display a confirmation prompt before applying changes. do not allow other changes to be made while applying. prompt may be skipped with 'pkg apply' in dedicated servers.
sv: downloads are no longer forced to lower case.
sv: added sv_demoAutoCompress cvar. set to 1 to directly record to *.mvd.gz
cl: properly support directly playing .mvd.gz files
menus: reworked to separate mouse and keyboard focus. mouse focus becomes keyboard focus only on mouse clicks. tooltips follow mouse cursors.
menus: cleaned up menu heirachy a little. now simpler.
server browser: changed 'hide *' filters to 'show *' instead. I felt it was more logical.
deluxmapping: changed to disabled, load, generate, like r_loadlit is.
render targets api now supports negative formats to mean nearest filtering, where filtering is part of texture state.
drawrotpic fixed, now batches and interacts with drawpic correctly.
drawline fixed, no interacts with draw* correctly, but still does not batch.
fixed saving games.
provide proper userinfo to nq clients, where supported.
qcc: catch string table overflows safely, giving errors instead of crashes. switch to 32bit statements if some over-sized function requires it.
qtv: some bigcoords support tweaks

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5073 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-03-21 05:27:07 +00:00
parent cb010176a1
commit a97007ae5a
61 changed files with 1877 additions and 893 deletions

View file

@ -2327,39 +2327,34 @@ void CL_PlayDemo(char *demoname, qboolean usesystempath)
{ {
char name[256]; char name[256];
vfsfile_t *f; vfsfile_t *f;
int i;
char *exts[] =
{
".qwd",
".dem",
".mvd",
".dm2",
};
// //
// open the demo file // open the demo file
// //
f = NULL;
for (i = 0; i < countof(exts); i++)
{
Q_strncpyz (name, demoname, sizeof(name)); Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".qwd", sizeof(name)); COM_DefaultExtension (name, exts[i], sizeof(name));
f = CL_OpenFileInZipOrSys(name, usesystempath); f = CL_OpenFileInZipOrSys(name, usesystempath);
if (!f) if (f)
{ break;
#ifdef AVAIL_GZDEC
Q_strncpyz (name, demoname, sizeof(name)); Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".dem", sizeof(name)); COM_DefaultExtension (name, va("%s.gz", exts[i]), sizeof(name));
if (usesystempath) f = CL_OpenFileInZipOrSys(name, usesystempath);
f = VFSOS_Open(name, "rb"); if (f)
else break;
f = FS_OpenVFS(name, "rb", FS_GAME); #endif
}
if (!f)
{
Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".mvd", sizeof(name));
if (usesystempath)
f = VFSOS_Open(name, "rb");
else
f = FS_OpenVFS(name, "rb", FS_GAME);
}
if (!f)
{
Q_strncpyz (name, demoname, sizeof(name));
COM_DefaultExtension (name, ".dm2", sizeof(name));
if (usesystempath)
f = VFSOS_Open(name, "rb");
else
f = FS_OpenVFS(name, "rb", FS_GAME);
} }
if (!f) if (!f)
{ {
@ -2371,6 +2366,11 @@ void CL_PlayDemo(char *demoname, qboolean usesystempath)
} }
Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname)); Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname));
#ifdef AVAIL_GZDEC
if (strlen(name) >= 3 && !Q_strcasecmp(name + strlen(name) - 3, ".gz"))
f = FS_DecompressGZip(f, NULL);
#endif
CL_PlayDemoFile(f, name, usesystempath); CL_PlayDemoFile(f, name, usesystempath);
} }

View file

@ -286,8 +286,6 @@ jmp_buf host_abort;
void Master_Connect_f (void); void Master_Connect_f (void);
float server_version = 0; // version of server we connected to
char emodel_name[] = char emodel_name[] =
{ 'e' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 }; { 'e' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
char pmodel_name[] = char pmodel_name[] =
@ -1819,7 +1817,7 @@ void CL_User_f (void)
if (cl.players[i].userid == uid if (cl.players[i].userid == uid
|| !strcmp(cl.players[i].name, Cmd_Argv(1)) ) || !strcmp(cl.players[i].name, Cmd_Argv(1)) )
{ {
if (cls.protocol == CP_NETQUAKE) if (!cl.players[i].userinfovalid)
Con_Printf("name: %s\ncolour %i %i\nping: %i\n", cl.players[i].name, cl.players[i].rbottomcolor, cl.players[i].rtopcolor, cl.players[i].ping); Con_Printf("name: %s\ncolour %i %i\nping: %i\n", cl.players[i].name, cl.players[i].rbottomcolor, cl.players[i].rtopcolor, cl.players[i].ping);
else else
Info_Print (cl.players[i].userinfo, ""); Info_Print (cl.players[i].userinfo, "");
@ -2011,6 +2009,7 @@ void CL_CheckServerInfo(void)
int oldstate; int oldstate;
#endif #endif
int oldteamplay; int oldteamplay;
qboolean spectating = cl.spectator && cl.spectator != 2; //spectator 2 = spectator-with-scores, considered to be players. this means we don't want to allow spec cheats while they're inactive, because that would be weird.
oldteamplay = cl.teamplay; oldteamplay = cl.teamplay;
cl.teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay")); cl.teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
@ -2026,11 +2025,12 @@ void CL_CheckServerInfo(void)
cls.allow_csqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc")) || *Info_ValueForKey(cl.serverinfo, "*csprogs"); cls.allow_csqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc")) || *Info_ValueForKey(cl.serverinfo, "*csprogs");
cl.csqcdebug = atoi(Info_ValueForKey(cl.serverinfo, "*csqcdebug"));
if (cl.spectator || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "watervis"))) if (spectating || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "watervis")))
cls.allow_watervis=true; cls.allow_watervis=true;
if (cl.spectator || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "allow_skybox")) || atoi(Info_ValueForKey(cl.serverinfo, "allow_skyboxes"))) if (spectating || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "allow_skybox")) || atoi(Info_ValueForKey(cl.serverinfo, "allow_skyboxes")))
cls.allow_skyboxes=true; //mostly obsolete. cls.allow_skyboxes=true; //mostly obsolete.
s = Info_ValueForKey(cl.serverinfo, "fbskins"); s = Info_ValueForKey(cl.serverinfo, "fbskins");
@ -2042,7 +2042,7 @@ void CL_CheckServerInfo(void)
cls.allow_fbskins = 1; cls.allow_fbskins = 1;
s = Info_ValueForKey(cl.serverinfo, "*cheats"); s = Info_ValueForKey(cl.serverinfo, "*cheats");
if (cl.spectator || cls.demoplayback || !stricmp(s, "on")) if (spectating || cls.demoplayback || !stricmp(s, "on"))
cls.allow_cheats = true; cls.allow_cheats = true;
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -2052,7 +2052,7 @@ void CL_CheckServerInfo(void)
#endif #endif
s = Info_ValueForKey(cl.serverinfo, "strict"); s = Info_ValueForKey(cl.serverinfo, "strict");
if ((!cl.spectator && !cls.demoplayback && *s && strcmp(s, "0")) || !ruleset_allow_semicheats.ival) if ((!spectating && !cls.demoplayback && *s && strcmp(s, "0")) || !ruleset_allow_semicheats.ival)
{ {
cls.allow_semicheats = false; cls.allow_semicheats = false;
cls.allow_cheats = false; cls.allow_cheats = false;
@ -2127,7 +2127,7 @@ void CL_CheckServerInfo(void)
cls.allow_anyparticles = false; cls.allow_anyparticles = false;
if (cl.spectator || cls.demoplayback) if (spectating || cls.demoplayback)
cl.fpd = 0; cl.fpd = 0;
else else
cl.fpd = atoi(Info_ValueForKey(cl.serverinfo, "fpd")); cl.fpd = atoi(Info_ValueForKey(cl.serverinfo, "fpd"));
@ -2181,44 +2181,6 @@ void CL_CheckServerInfo(void)
if (oldteamplay != cl.teamplay) if (oldteamplay != cl.teamplay)
Skin_FlushPlayers(); Skin_FlushPlayers();
} }
/*
==================
CL_FullServerinfo_f
Sent by server just after the svc_serverdata
==================
*/
void CL_FullServerinfo_f (void)
{
char *p;
float v;
if (!Cmd_FromGamecode())
{
Con_Printf("Hey! fullserverinfo is meant to come from the server!\n");
return;
}
if (Cmd_Argc() != 2)
{
Con_TPrintf ("usage: fullserverinfo <complete info string>\n");
return;
}
Q_strncpyz (cl.serverinfo, Cmd_Argv(1), sizeof(cl.serverinfo));
if ((p = Info_ValueForKey(cl.serverinfo, "*version")) && *p) {
v = Q_atof(p);
if (v) {
if (!server_version)
Con_TPrintf ("Version %1.2f Server\n", v);
server_version = v;
}
}
CL_CheckServerInfo();
cl.csqcdebug = atoi(Info_ValueForKey(cl.serverinfo, "*csqcdebug"));
}
/* /*
================== ==================
@ -3537,11 +3499,14 @@ void CL_ReadPackets (void)
//============================================================================= //=============================================================================
qboolean CL_AllowArbitaryDownload(char *localfile) qboolean CL_AllowArbitaryDownload(char *oldname, char *localfile)
{ {
int allow; int allow;
//never allow certain (native code) arbitary downloads. //never allow certain (native code) arbitary downloads.
if (!strnicmp(localfile, "game", 4) || !stricmp(localfile, "progs.dat") || !stricmp(localfile, "menu.dat") || !stricmp(localfile, "csprogs.dat") || !stricmp(localfile, "qwprogs.dat") || strstr(localfile, "..") || strstr(localfile, ":") || strstr(localfile, "//") || strstr(localfile, ".qvm") || strstr(localfile, ".dll") || strstr(localfile, ".so")) if (!Q_strncasecmp(localfile, "game", 4) || //q2-ey things
!Q_strcasecmp(localfile, "progs.dat") || !Q_strcasecmp(localfile, "menu.dat") || !Q_strcasecmp(localfile, "csprogs.dat") || !Q_strcasecmp(localfile, "qwprogs.dat") || //overriding gamecode is bad (csqc should be dlcached)
strstr(localfile, "\\") || strstr(localfile, "..") || strstr(localfile, "./") || strstr(localfile, ":") || strstr(localfile, "//") || //certain path patterns are just bad
Q_strcasestr(localfile, ".qvm") || Q_strcasestr(localfile, ".dll") || Q_strcasestr(localfile, ".so")) //disallow any native code
{ //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar) { //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar)
Con_Printf("Ignoring arbitary download to \"%s\" due to possible security risk\n", localfile); Con_Printf("Ignoring arbitary download to \"%s\" due to possible security risk\n", localfile);
return false; return false;
@ -3551,8 +3516,11 @@ qboolean CL_AllowArbitaryDownload(char *localfile)
{ {
char ext[8]; char ext[8];
COM_FileExtension(localfile, ext, sizeof(ext)); COM_FileExtension(localfile, ext, sizeof(ext));
if (!strncmp(localfile, "package/", 8) || !strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4") || (!strncmp(localfile, "demos/", 6) && !strcmp(ext, "mvd"))) if (!strncmp(localfile, "demos/", 6) && (!Q_strcasecmp(ext, "mvd") || !Q_strcasecmp(ext, "gz")))
return true; return true; //mvdsv popularised the server sending 'download demo/foobar.mvd' in response to 'download demonum/5' aka 'cmd dl #'
else if (!strncmp(localfile, "package/", 8) && (!Q_strcasecmp(ext, "pak") || !Q_strcasecmp(ext, "pk3") || !Q_strcasecmp(ext, "pk4")))
return true; //packages, woo.
//fixme: we should probably try using package/$gamedir/foo.pak if we get redirected to that.
else else
{ {
Con_Printf("Ignoring non-package download redirection to \"%s\"\n", localfile); Con_Printf("Ignoring non-package download redirection to \"%s\"\n", localfile);
@ -3630,7 +3598,7 @@ void CL_Download_f (void)
DL_Abort(cls.download, QDL_FAILED); DL_Abort(cls.download, QDL_FAILED);
//don't let gamecode order us to download random junk //don't let gamecode order us to download random junk
if (!CL_AllowArbitaryDownload(localname)) if (!CL_AllowArbitaryDownload(NULL, localname))
return; return;
CL_CheckOrEnqueDownloadFile(url, localname, DLLF_REQUIRED|DLLF_VERBOSE); CL_CheckOrEnqueDownloadFile(url, localname, DLLF_REQUIRED|DLLF_VERBOSE);
@ -3671,7 +3639,7 @@ void CL_DownloadSize_f(void)
{ //'download this file instead' { //'download this file instead'
redirection = Cmd_Argv(3); redirection = Cmd_Argv(3);
if (!CL_AllowArbitaryDownload(redirection)) if (!CL_AllowArbitaryDownload(rname, redirection))
return; return;
dl = CL_DownloadFailed(rname, NULL); dl = CL_DownloadFailed(rname, NULL);
@ -4138,7 +4106,6 @@ void CL_Init (void)
Cmd_AddCommand ("setinfo", CL_SetInfo_f); Cmd_AddCommand ("setinfo", CL_SetInfo_f);
Cmd_AddCommand ("fullinfo", CL_FullInfo_f); Cmd_AddCommand ("fullinfo", CL_FullInfo_f);
Cmd_AddCommand ("fullserverinfo", CL_FullServerinfo_f);
Cmd_AddCommand ("color", CL_Color_f); Cmd_AddCommand ("color", CL_Color_f);
Cmd_AddCommand ("download", CL_Download_f); Cmd_AddCommand ("download", CL_Download_f);
@ -4827,7 +4794,7 @@ void Host_DoRunFile(hrf_t *f)
{ {
if (!(f->flags & HRF_ACTION)) if (!(f->flags & HRF_ACTION))
{ {
M_Menu_Prompt(Host_RunFilePrompted, f, "File already exists.", "What would you like to do?", displayname, "Overwrite", "Run old", "Cancel"); M_Menu_Prompt(Host_RunFilePrompted, f, va("File already exists.\nWhat would you like to do?\n%s\n", displayname), "Overwrite", "Run old", "Cancel");
return; return;
} }
} }
@ -4835,7 +4802,7 @@ void Host_DoRunFile(hrf_t *f)
{ {
if (!(f->flags & HRF_ACTION)) if (!(f->flags & HRF_ACTION))
{ {
M_Menu_Prompt(Host_RunFilePrompted, f, "File appears new.", "Would you like to install", displayname, "Install!", "", "Cancel"); M_Menu_Prompt(Host_RunFilePrompted, f, va("File appears new.\nWould you like to install\n%s\n", displayname), "Install!", "", "Cancel");
return; return;
} }
} }
@ -4885,6 +4852,7 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
fname = utf8; fname = utf8;
nlen = strlen(fname); nlen = strlen(fname);
} }
else
#elif !defined(FTE_TARGET_WEB) #elif !defined(FTE_TARGET_WEB)
//unix file urls are fairly consistant. //unix file urls are fairly consistant.
if (nlen >= 8 && !strncmp(fname, "file:///", 8)) if (nlen >= 8 && !strncmp(fname, "file:///", 8))
@ -4892,7 +4860,46 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
fname += 7; fname += 7;
nlen -= 7; nlen -= 7;
} }
else
#endif #endif
if (nlen >= 5 && !strncmp(fname, "qw://", 5))
{ //this is also implemented by ezquake, so be careful here...
//"qw://[stream@]host[:port]/COMMAND" join, spectate, qtvplay
char *t, *cmd;
const char *url;
char buffer[8192];
t = Z_Malloc(nlen+1);
memcpy(t, fname, nlen);
t[nlen] = 0;
url = t+5;
for (cmd = t+5; *cmd; cmd++)
{
if (*cmd == '/')
{
*cmd++ = 0;
break;
}
}
//quote the url safely.
url = COM_QuotedString(url, buffer, sizeof(buffer), false);
//now figure out what the command actually was
if (!Q_strcasecmp(cmd, "join"))
Cbuf_AddText(va("join %s\n", url), RESTRICT_LOCAL);
else if (!Q_strcasecmp(cmd, "spectate") || !strcmp(cmd, "observe"))
Cbuf_AddText(va("observe %s\n", url), RESTRICT_LOCAL);
else if (!Q_strcasecmp(cmd, "qtvplay"))
Cbuf_AddText(va("qtvplay %s\n", url), RESTRICT_LOCAL);
else if (!*cmd || !Q_strcasecmp(cmd, "connect"))
Cbuf_AddText(va("connect %s\n", url), RESTRICT_LOCAL);
else
Con_Printf("Unknown url command: %s\n", cmd);
Z_Free(t);
return true;
}
f = Z_Malloc(sizeof(*f) + nlen); f = Z_Malloc(sizeof(*f) + nlen);
memcpy(f->fname, fname, nlen); memcpy(f->fname, fname, nlen);

View file

@ -490,7 +490,12 @@ void CL_AckedInputFrame(int inseq, int outseq, qboolean worldstateokay)
{ {
//nq has no concept of choking. outbound packets that are accepted during a single frame will be erroneoulsy considered dropped. nq never had a netgraph based upon outgoing timings. //nq has no concept of choking. outbound packets that are accepted during a single frame will be erroneoulsy considered dropped. nq never had a netgraph based upon outgoing timings.
// Con_Printf("Dropped moveframe %i\n", i); // Con_Printf("Dropped moveframe %i\n", i);
cl.outframes[i].latency = -1; if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
{ //dp doesn't ack every single packet. trying to report packet loss correctly is futile, we'll just get bad-mouthed.
cl.outframes[i].latency = -2; //flag as choked
}
else
cl.outframes[i].latency = -1; //flag as dropped
} }
} }
cl.inframes[inseq&UPDATE_MASK].ackframe = outseq; cl.inframes[inseq&UPDATE_MASK].ackframe = outseq;
@ -703,6 +708,8 @@ void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int f
#ifdef WEBCLIENT #ifdef WEBCLIENT
if (!strncmp(filename, "http://", 7) || !strncmp(filename, "https://", 8)) if (!strncmp(filename, "http://", 7) || !strncmp(filename, "https://", 8))
{
if (!cls.download || !(cls.download->flags & DLLF_ALLOWWEB))
{ {
struct dl_download *wdl = HTTP_CL_Get(filename, localname, CL_WebDownloadFinished); struct dl_download *wdl = HTTP_CL_Get(filename, localname, CL_WebDownloadFinished);
if (wdl) if (wdl)
@ -714,6 +721,7 @@ void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int f
} }
else else
CL_DownloadFailed(filename, NULL); CL_DownloadFailed(filename, NULL);
}
return; return;
} }
#endif #endif
@ -1140,7 +1148,7 @@ void Model_CheckDownloads (void)
continue; continue;
#endif #endif
CL_CheckOrEnqueDownloadFile(s, s, (i==1)?DLLF_REQUIRED:0); //world is required to be loaded. CL_CheckOrEnqueDownloadFile(s, s, (i==1)?DLLF_REQUIRED|DLLF_ALLOWWEB:0); //world is required to be loaded.
CL_CheckModelResources(s); CL_CheckModelResources(s);
} }
@ -2669,7 +2677,7 @@ void CLDP_ParseDownloadBegin(char *s)
char buffer[8192]; char buffer[8192];
qofs_t size, pos, chunk; qofs_t size, pos, chunk;
char *fname; char *fname;
Cmd_TokenizeString(s+1, false, false); Cmd_TokenizeString(s, false, false);
size = (qofs_t)strtoull(Cmd_Argv(1), NULL, 0); size = (qofs_t)strtoull(Cmd_Argv(1), NULL, 0);
fname = Cmd_Argv(2); fname = Cmd_Argv(2);
@ -2717,7 +2725,7 @@ void CLDP_ParseDownloadFinished(char *s)
if (!dl || !dl->file) if (!dl || !dl->file)
return; return;
Cmd_TokenizeString(s+1, false, false); Cmd_TokenizeString(s, false, false);
VFS_CLOSE (dl->file); VFS_CLOSE (dl->file);
@ -2744,7 +2752,7 @@ void CLDP_ParseDownloadFinished(char *s)
return; return;
} }
Cmd_TokenizeString(s+1, false, false); Cmd_TokenizeString(s, false, false);
if (size != atoi(Cmd_Argv(1))) if (size != atoi(Cmd_Argv(1)))
{ {
Con_Printf("Download failed: wrong file size\n"); Con_Printf("Download failed: wrong file size\n");
@ -3670,6 +3678,12 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution.
CSQC_Init(cls.demoplayback, false, 0); CSQC_Init(cls.demoplayback, false, 0);
#endif #endif
} }
static void CLNQ_SendInitialUserInfo(void *ctx, const char *key, const char *value)
{
char keybuf[2048];
char valbuf[4096];
CL_SendClientCommand(true, "setinfo %s %s\n", COM_QuotedString(key, keybuf, sizeof(keybuf), false), COM_QuotedString(value, valbuf, sizeof(valbuf), false));
}
void CLNQ_SignonReply (void) void CLNQ_SignonReply (void)
{ {
extern cvar_t topcolor; extern cvar_t topcolor;
@ -3690,27 +3704,16 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
case 2: case 2:
CL_SendClientCommand(true, "name \"%s\"\n", name.string); CL_SendClientCommand(true, "name \"%s\"\n", name.string);
CL_SendClientCommand(true, "color %i %i\n", topcolor.ival, bottomcolor.ival); CL_SendClientCommand(true, "color %i %i\n", topcolor.ival, bottomcolor.ival);
if (cl.haveserverinfo)
CL_SendClientCommand(true, "spawn %s", ""); Info_Enumerate(cls.userinfo[0], NULL, CLNQ_SendInitialUserInfo);
else if (CPNQ_IS_DP) //dp needs a couple of extras to work properly. don't send them on other servers because that generally results in error messages.
if (CPNQ_IS_DP) //dp needs a couple of extras to work properly.
{ {
CL_SendClientCommand(true, "rate %s", rate.string); CL_SendClientCommand(true, "rate %s", rate.string);
CL_SendClientCommand(true, "playermodel %s", model.string); CL_SendClientCommand(true, "playermodel %s", model.string);
CL_SendClientCommand(true, "playerskin %s", skin.string); CL_SendClientCommand(true, "playerskin %s", skin.string);
/*
#ifdef PEXT_CSQC
{
char *s;
s = Info_ValueForKey(cl.serverinfo, "*csprogs");
CSQC_Init(false, *s?true:false, atoi(s));
}
#endif
*/
} }
CL_SendClientCommand(true, "spawn %s", "");
break; break;
case 3: case 3:
@ -4044,6 +4047,7 @@ void CLQ2_ParseClientinfo(int i, char *s)
char *model, *name; char *model, *name;
player_info_t *player; player_info_t *player;
//s contains "name\model/skin" //s contains "name\model/skin"
//q2 doesn't really do much with userinfos.
if (i >= MAX_CLIENTS) if (i >= MAX_CLIENTS)
return; return;
@ -4051,6 +4055,7 @@ void CLQ2_ParseClientinfo(int i, char *s)
player = &cl.players[i]; player = &cl.players[i];
*player->userinfo = '\0'; *player->userinfo = '\0';
cl.players[i].userinfovalid = true;
model = strchr(s, '\\'); model = strchr(s, '\\');
if (model) if (model)
@ -5039,6 +5044,7 @@ void CL_UpdateUserinfo (void)
player = &cl.players[slot]; player = &cl.players[slot];
player->userid = MSG_ReadLong (); player->userid = MSG_ReadLong ();
Q_strncpyz (player->userinfo, MSG_ReadString(), sizeof(player->userinfo)); Q_strncpyz (player->userinfo, MSG_ReadString(), sizeof(player->userinfo));
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player); CL_ProcessUserInfo (slot, player);
@ -5079,6 +5085,7 @@ void CL_ParseSetInfo (void)
Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value); Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo)); Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo));
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player); CL_ProcessUserInfo (slot, player);
} }
@ -6139,7 +6146,7 @@ static void CL_ParseItemTimer(void)
for (timer = cl.itemtimers; timer; timer = timer->next) for (timer = cl.itemtimers; timer; timer = timer->next)
{ {
if (VectorCompare(timer->origin, org) && timer->entnum == entnum) if (VectorCompare(timer->origin, org) && timer->entnum == entnum && entnum)
break; break;
} }
if (!timer) if (!timer)
@ -6206,15 +6213,65 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
Con_DLPrintf((cls.state==ca_active)?1:2, "stufftext: %s\n", stufftext); Con_DLPrintf((cls.state==ca_active)?1:2, "stufftext: %s\n", stufftext);
if (!strncmp(stufftext, "fullserverinfo ", 15)) if (!strncmp(stufftext, "fullserverinfo ", 15))
{ {
Cmd_ExecuteString(stufftext, RESTRICT_SERVER+destsplit); //do this NOW so that it's done before any models or anything are loaded Cmd_TokenizeString(stufftext, false, false);
if (Cmd_Argc() == 2)
{
cl.haveserverinfo = true;
Q_strncpyz (cl.serverinfo, Cmd_Argv(1), sizeof(cl.serverinfo));
CL_CheckServerInfo();
}
#if _MSC_VER > 1200 #if _MSC_VER > 1200
if (cls.netchan.remote_address.type != NA_LOOPBACK) if (cls.netchan.remote_address.type != NA_LOOPBACK)
Sys_RecentServer("+connect", cls.servername, va("%s (%s)", Info_ValueForKey(cl.serverinfo, "hostname"), cls.servername), "Join QW Server"); Sys_RecentServer("+connect", cls.servername, va("%s (%s)", Info_ValueForKey(cl.serverinfo, "hostname"), cls.servername), "Join QW Server");
#endif #endif
} }
else else if (!strncmp(stufftext, "//svi ", 6)) //for serverinfo over NQ protocols
{ {
if (!strncmp(stufftext, "//querycmd ", 11)) Cmd_TokenizeString(stufftext+2, false, false);
Con_DPrintf("SERVERINFO: %s=%s\n", Cmd_Argv(1), Cmd_Argv(2));
Info_SetValueForStarKey (cl.serverinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING);
CL_CheckServerInfo();
}
#ifdef NQPROT
//DP's download protocol
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "cl_serverextension_download ", 28)) //<supported>. server lets us know that it supports it.
cl_dp_serverextension_download = true; //warning, this is sent BEFORE svc_serverdata, so cannot use cl.foo
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "cl_downloadbegin ", 17)) //<size> <name>. server [reliably] lets us know that its going to start sending data.
CLDP_ParseDownloadBegin(stufftext);
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "cl_downloadfinished ", 20)) //<size> <crc>. server [reliably] lets us know that we acked the entire thing
CLDP_ParseDownloadFinished(stufftext);
else if (cls.protocol == CP_NETQUAKE && !strcmp(stufftext, "stopdownload")) //download command reported failure. safe to request the next.
{
if (cls.download)
CL_DownloadFailed(cls.download->remotename, cls.download);
}
//DP servers use these to report the correct csprogs.dat file+version to use.
//WARNING: these are sent BEFORE svc_serverdata, so we cannot store this state into cl.foo
//we poke the data into cl.serverinfo once we get the following svc_serverdata.
//we then clobber it from a fullserverinfo message if its an fte server running dpp7, but hey.
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "csqc_progname ", 14))
COM_ParseOut(stufftext+14, cl_dp_csqc_progsname, sizeof(cl_dp_csqc_progsname));
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "csqc_progsize ", 14))
cl_dp_csqc_progssize = atoi(stufftext+14);
else if (cls.protocol == CP_NETQUAKE && !strncmp(stufftext, "csqc_progcrc ", 13))
cl_dp_csqc_progscrc = atoi(stufftext+13);
//NQ servers/mods like spamming this. Its annoying, but we might as well use it if we can, while also muting it.
else if (!strncmp(stufftext, "cl_fullpitch ", 13) || !strncmp(stufftext, "pq_fullpitch ", 13))
{
if (!cl.haveserverinfo)
{
Info_SetValueForStarKey(cl.serverinfo, "maxpitch", (atoi(stufftext+13))? "90":"", sizeof(cl.serverinfo));
Info_SetValueForStarKey(cl.serverinfo, "minpitch", (atoi(stufftext+13))?"-90":"", sizeof(cl.serverinfo));
CL_CheckServerInfo();
}
}
#endif
else if (!strncmp(stufftext, "//querycmd ", 11)) //for servers to check if a command exists or not.
{ {
COM_Parse(stufftext + 11); COM_Parse(stufftext + 11);
if (Cmd_Exists(com_token)) if (Cmd_Exists(com_token))
@ -6224,19 +6281,19 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit);
} }
} }
else if (!strncmp(stufftext, "//paknames ", 11)) else if (!strncmp(stufftext, "//paknames ", 11)) //so that the client knows what to download...
{ { //there's a couple of prefixes involved etc
Q_strncatz(cl.serverpaknames, stufftext+11, sizeof(cl.serverpaknames)); Q_strncatz(cl.serverpaknames, stufftext+11, sizeof(cl.serverpaknames));
cl.serverpakschanged = true; cl.serverpakschanged = true;
} }
else if (!strncmp(stufftext, "//paks ", 7)) else if (!strncmp(stufftext, "//paks ", 7)) //gives the client a list of hashes to match against
{ { //the client can re-order for cl_pure support, or download dupes to avoid version mismatches
Q_strncatz(cl.serverpakcrcs, stufftext+7, sizeof(cl.serverpakcrcs)); Q_strncatz(cl.serverpakcrcs, stufftext+7, sizeof(cl.serverpakcrcs));
cl.serverpakschanged = true; cl.serverpakschanged = true;
CL_CheckServerPacks(); CL_CheckServerPacks();
} }
else if (!strncmp(stufftext, "//vwep ", 7)) 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; int i;
char *mname; char *mname;
Cmd_TokenizeString(stufftext+7, false, false); Cmd_TokenizeString(stufftext+7, false, false);
@ -6255,39 +6312,76 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
} }
} }
} }
else if (!strncmp(stufftext, "//exectrigger ", 14)) else if (!strncmp(stufftext, "//exectrigger ", 14)) //so that mods can add whatever 'alias grabbedarmour' or whatever triggers that users might want to script responses for, without errors about unknown commands
{ {
COM_Parse(stufftext + 14); COM_Parse(stufftext + 14);
if (Cmd_AliasExist(com_token, RESTRICT_SERVER)) if (Cmd_AliasExist(com_token, RESTRICT_SERVER))
Cmd_ExecuteString(com_token, RESTRICT_SERVER); //do this NOW so that it's done before any models or anything are loaded Cmd_ExecuteString(com_token, RESTRICT_SERVER); //do this NOW so that it's done before any models or anything are loaded
} }
else if (!strncmp(stufftext, "//set ", 6)) else if (!strncmp(stufftext, "//set ", 6)) //equivelent to regular set, except non-spammy if it doesn't exist, and happens instantly without extra latency.
{ {
Cmd_ExecuteString(stufftext+2, RESTRICT_SERVER+destsplit); //do this NOW so that it's done before any models or anything are loaded Cmd_ExecuteString(stufftext+2, RESTRICT_SERVER+destsplit); //do this NOW so that it's done before any models or anything are loaded
} }
else if (!strncmp(stufftext, "//at ", 5)) else if (!strncmp(stufftext, "//at ", 5)) //ktx autotrack hints
{ {
Cam_SetModAutoTrack(atoi(stufftext+5)); Cam_SetModAutoTrack(atoi(stufftext+5));
} }
else if (!strncmp(stufftext, "//wps ", 5)) else if (!strncmp(stufftext, "//wps ", 5)) //ktx weapon statistics
{ {
Cmd_TokenizeString(stufftext+5, false, false); Cmd_TokenizeString(stufftext+5, false, false);
CL_ParseWeaponStats(); CL_ParseWeaponStats();
} }
else if (!strncmp(stufftext, "//kickfile ", 11)) else if (!strncmp(stufftext, "//kickfile ", 11)) //FTE sends this to give a more friendly error about modified BSP files, although it could be used for more stuff.
{ {
flocation_t loc; flocation_t loc;
Cmd_TokenizeString(stufftext+2, false, false); Cmd_TokenizeString(stufftext+2, false, false);
if (FS_FLocateFile(Cmd_Argv(1), FSLF_IFFOUND, &loc)) if (FS_FLocateFile(Cmd_Argv(1), FSLF_IFFOUND, &loc))
Con_Printf("You have been kicked due to the file \"%s\" being modified.\n", Cmd_Argv(1)); {
if (!*loc.rawname)
Con_Printf("You have been kicked due to the file "U8("%s")" being modified, inside "U8("%s")"\n", Cmd_Argv(1), loc.search->logicalpath);
else
Con_Printf("You have been kicked due to the file "U8("%s")" being modfied, located at "U8("%s")"\n", Cmd_Argv(1), loc.rawname);
} }
else if (!strncmp(stufftext, "//it ", 5)) }
else if (!strncmp(stufftext, "//it ", 5)) //it <timeout> <org xyz> <radius> <rgb> <timername> <entnum>
{ {
Cmd_TokenizeString(stufftext+5, false, false); Cmd_TokenizeString(stufftext+5, false, false);
CL_ParseItemTimer(); CL_ParseItemTimer();
} }
else if (!strncmp(stufftext, "//fui ", 6)) //ui <slot> <key> <value>. Full user info updates.
{
unsigned int slot;
const char *value;
Cmd_TokenizeString(stufftext+6, false, false);
slot = atoi(Cmd_Argv(0));
value = Cmd_Argv(1);
if (slot < MAX_CLIENTS)
{
player_info_t *player = &cl.players[slot];
Con_DPrintf("SETINFO %s: %s\n", player->name, value);
Q_strncpyz(player->userinfo, value, sizeof(player->userinfo));
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player);
}
}
else if (!strncmp(stufftext, "//ui ", 5)) //ui <slot> <key> <value>. Full user info updates.
{
unsigned int slot;
const char *key, *value;
Cmd_TokenizeString(stufftext+5, false, false);
slot = atoi(Cmd_Argv(0));
key = Cmd_Argv(1);
value = Cmd_Argv(2);
if (slot < MAX_CLIENTS)
{
player_info_t *player = &cl.players[slot];
Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo));
CL_ProcessUserInfo (slot, player);
}
}
#ifdef PLUGINS #ifdef PLUGINS
else if (!strncmp(stufftext, "//tinfo ", 8)) else if (!strncmp(stufftext, "//tinfo ", 8)) //ktx-team-info <pidx> <org xyz> <health> <armour> <STAT_ITEMS> <nickname>
{ {
Cmd_TokenizeString(stufftext+2, false, false); Cmd_TokenizeString(stufftext+2, false, false);
CL_ParseTeamInfo(); CL_ParseTeamInfo();
@ -6311,7 +6405,6 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
Cbuf_AddText (stufftext, RESTRICT_SERVER+destsplit); Cbuf_AddText (stufftext, RESTRICT_SERVER+destsplit);
Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit);
} }
}
msg++; msg++;
memmove(stufftext, msg, strlen(msg)+1); memmove(stufftext, msg, strlen(msg)+1);
@ -6609,7 +6702,6 @@ void CLQW_ParseServerMessage (void)
case svc_stufftext: case svc_stufftext:
s = MSG_ReadString (); s = MSG_ReadString ();
CL_ParseStuffCmd(s, destsplit); CL_ParseStuffCmd(s, destsplit);
break; break;
@ -7479,6 +7571,17 @@ qboolean CLNQ_ParseNQPrints(char *s)
return false; return false;
} }
void CLNQ_CheckPlayerIsSpectator(int i)
{
cl.players[i].spectator =
(cl.players[i].frags==-999) || //DP mods tend to use -999
(cl.players[i].frags==-99); //crmod uses -99 for spectators, which is annoying.
//we can't add any colour checks, as apparently this fucks up too.
if (!*cl.players[i].name)
cl.players[i].spectator = false;
}
void CLNQ_ParseServerMessage (void) void CLNQ_ParseServerMessage (void)
{ {
const int destsplit = 0; const int destsplit = 0;
@ -7564,53 +7667,14 @@ void CLNQ_ParseServerMessage (void)
s = MSG_ReadString (); s = MSG_ReadString ();
#ifdef PLUGINS #ifdef PLUGINS
if (Plug_CenterPrintMessage(s, 0)) if (Plug_CenterPrintMessage(s, destsplit))
#endif #endif
SCR_CenterPrint (0, s, false); SCR_CenterPrint (destsplit, s, false);
break; break;
case svc_stufftext: case svc_stufftext:
s = MSG_ReadString (); s = MSG_ReadString ();
if (*s == 1 && !cls.allow_csqc) CL_ParseStuffCmd(s, destsplit);
{
Con_DPrintf("Proquake: %s\n", s);
s = CLNQ_ParseProQuakeMessage(s);
}
Con_DPrintf ("stufftext: %s\n", s);
if (!strncmp(s, "cl_serverextension_download ", 14))
{
cl_dp_serverextension_download = true;
}
else if (!strncmp(s, "//svi ", 6))
{
Cmd_TokenizeString(s+2, false, false);
Con_DPrintf("SERVERINFO: %s=%s\n", Cmd_Argv(1), Cmd_Argv(2));
Info_SetValueForStarKey (cl.serverinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING);
CL_CheckServerInfo();
}
else if (!strncmp(s, "\ncl_downloadbegin ", 17))
CLDP_ParseDownloadBegin(s);
else if (!strncmp(s, "\ncl_downloadfinished ", 17))
CLDP_ParseDownloadFinished(s);
else if (!strcmp(s, "\nstopdownload\n"))
{
if (cls.download)
CL_DownloadFailed(cls.download->remotename, cls.download);
}
else if (!strncmp(s, "csqc_progname ", 14))
COM_ParseOut(s+14, cl_dp_csqc_progsname, sizeof(cl_dp_csqc_progsname));
else if (!strncmp(s, "csqc_progsize ", 14))
cl_dp_csqc_progssize = atoi(s+14);
else if (!strncmp(s, "csqc_progcrc ", 13))
cl_dp_csqc_progscrc = atoi(s+13);
else if (!strncmp(s, "cl_fullpitch ", 13) || !strncmp(s, "pq_fullpitch ", 13))
{
//
}
else
{
Cbuf_AddText (s, RESTRICT_SERVER); //no cheating here...
}
break; break;
case svc_version: case svc_version:
@ -7798,6 +7862,8 @@ void CLNQ_ParseServerMessage (void)
Info_SetValueForKey(cl.players[i].userinfo, "name", cl.players[i].name, sizeof(cl.players[i].userinfo)); Info_SetValueForKey(cl.players[i].userinfo, "name", cl.players[i].name, sizeof(cl.players[i].userinfo));
if (!cl.nqplayernamechanged) if (!cl.nqplayernamechanged)
cl.nqplayernamechanged = realtime+2; cl.nqplayernamechanged = realtime+2;
CLNQ_CheckPlayerIsSpectator(i);
} }
break; break;
@ -7807,7 +7873,10 @@ void CLNQ_ParseServerMessage (void)
if (i >= MAX_CLIENTS) if (i >= MAX_CLIENTS)
MSG_ReadShort(); MSG_ReadShort();
else else
{
cl.players[i].frags = MSG_ReadShort(); cl.players[i].frags = MSG_ReadShort();
CLNQ_CheckPlayerIsSpectator(i);
}
break; break;
case svc_updatecolors: case svc_updatecolors:
{ {
@ -7818,6 +7887,7 @@ void CLNQ_ParseServerMessage (void)
{ {
cl.players[i].rtopcolor = a&0x0f; cl.players[i].rtopcolor = a&0x0f;
cl.players[i].rbottomcolor = (a&0xf0)>>4; cl.players[i].rbottomcolor = (a&0xf0)>>4;
CLNQ_CheckPlayerIsSpectator(i);
sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor); sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor);
@ -7931,7 +8001,7 @@ void CLNQ_ParseServerMessage (void)
cl.completed_time = cl.gametime; cl.completed_time = cl.gametime;
} }
cl.intermissionmode = IM_NQFINALE; cl.intermissionmode = IM_NQFINALE;
SCR_CenterPrint (0, MSG_ReadString (), false); SCR_CenterPrint (destsplit, MSG_ReadString (), false);
break; break;
case svc_cutscene: case svc_cutscene:
@ -7941,7 +8011,7 @@ void CLNQ_ParseServerMessage (void)
cl.completed_time = cl.gametime; cl.completed_time = cl.gametime;
} }
cl.intermissionmode = IM_NQCUTSCENE; cl.intermissionmode = IM_NQCUTSCENE;
SCR_CenterPrint (0, MSG_ReadString (), false); SCR_CenterPrint (destsplit, MSG_ReadString (), false);
break; break;
case svc_sellscreen: //pantsie case svc_sellscreen: //pantsie

View file

@ -3134,6 +3134,7 @@ void SCR_DeInit (void)
Cmd_RemoveCommand ("screenshot_mega"); Cmd_RemoveCommand ("screenshot_mega");
Cmd_RemoveCommand ("screenshot_stereo"); Cmd_RemoveCommand ("screenshot_stereo");
Cmd_RemoveCommand ("screenshot_vr"); Cmd_RemoveCommand ("screenshot_vr");
Cmd_RemoveCommand ("screenshot_cubemap");
Cmd_RemoveCommand ("envmap"); Cmd_RemoveCommand ("envmap");
Cmd_RemoveCommand ("sizeup"); Cmd_RemoveCommand ("sizeup");
Cmd_RemoveCommand ("sizedown"); Cmd_RemoveCommand ("sizedown");

View file

@ -158,6 +158,7 @@ typedef struct player_info_s
{ {
int userid; int userid;
char userinfo[EXTENDED_INFO_STRING]; char userinfo[EXTENDED_INFO_STRING];
qboolean userinfovalid; //set if we actually know the userinfo (ie: false on vanilla nq servers)
char teamstatus[128]; char teamstatus[128];
float teamstatustime; float teamstatustime;
@ -739,6 +740,7 @@ typedef struct
qboolean stillloading; // set when doing something slow, and the game is still loading. qboolean stillloading; // set when doing something slow, and the game is still loading.
qboolean haveserverinfo; //nq servers will usually be false. don't override stuff if we already know better.
char serverinfo[MAX_SERVERINFO_STRING]; char serverinfo[MAX_SERVERINFO_STRING];
char serverpaknames[1024]; char serverpaknames[1024];
char serverpakcrcs[1024]; char serverpakcrcs[1024];
@ -1022,7 +1024,6 @@ extern int rtlights_first, rtlights_max;
extern int cl_baselines_count; extern int cl_baselines_count;
extern qboolean nomaster; extern qboolean nomaster;
extern float server_version; // version of server we connected to
//============================================================================= //=============================================================================

View file

@ -11,8 +11,6 @@
#ifdef PACKAGEMANAGER #ifdef PACKAGEMANAGER
#include "fs.h" #include "fs.h"
vfsfile_t *FS_XZ_DecompressWriteFilter(vfsfile_t *infile);
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
//whole load of extra args for the downloads menu (for the downloads menu to handle engine updates). //whole load of extra args for the downloads menu (for the downloads menu to handle engine updates).
#ifdef VKQUAKE #ifdef VKQUAKE
@ -81,12 +79,15 @@ extern cvar_t pm_downloads_url;
#define DPF_DISPLAYVERSION 0x20 //some sort of conflict, the package is listed twice, so show versions so the user knows what's old. #define DPF_DISPLAYVERSION 0x20 //some sort of conflict, the package is listed twice, so show versions so the user knows what's old.
#define DPF_FORGETONUNINSTALL 0x40 //for previously installed packages, remove them from the list if there's no current version any more (should really be automatic if there's no known mirrors) #define DPF_FORGETONUNINSTALL 0x40 //for previously installed packages, remove them from the list if there's no current version any more (should really be automatic if there's no known mirrors)
#define DPF_HIDDEN 0x80 //wrong arch, file conflicts, etc. still listed if actually installed. #define DPF_HIDDEN 0x80 //wrong arch, file conflicts, etc. still listed if actually installed.
#define DPF_ENGINE 0x100 //engine update. replaces old autoupdate mechanism
#define DPF_PURGE 0x200 //package should be completely removed (ie: the dlcache dir too). if its still marked then it should be reinstalled anew. available on cached or corrupt packages, implied by native. #define DPF_PURGE 0x200 //package should be completely removed (ie: the dlcache dir too). if its still marked then it should be reinstalled anew. available on cached or corrupt packages, implied by native.
#define DPF_MANIFEST 0x400 //package was named by the manifest, and should only be uninstalled after a warning. #define DPF_MANIFEST 0x400 //package was named by the manifest, and should only be uninstalled after a warning.
#define DPF_TESTING 0x800 //package is provided on a testing/trial basis, and will only be selected/listed if autoupdates are configured to allow it. #define DPF_TESTING 0x800 //package is provided on a testing/trial basis, and will only be selected/listed if autoupdates are configured to allow it.
#define DPF_ENGINE 0x1000 //engine update. replaces old autoupdate mechanism
#define DPF_PLUGIN 0x2000 //this is a plugin package, with a dll
#define DPF_PRESENT (DPF_NATIVE|DPF_CACHED) #define DPF_PRESENT (DPF_NATIVE|DPF_CACHED)
#define DPF_DISABLEDINSTALLED (DPF_ENGINE|DPF_PLUGIN) //engines+plugins can be installed without being enabled.
//pak.lst //pak.lst
//priories <0 //priories <0
//pakX //pakX
@ -179,10 +180,12 @@ typedef struct package_s {
static qboolean loadedinstalled; static qboolean loadedinstalled;
static package_t *availablepackages; static package_t *availablepackages;
static int numpackages; static int numpackages;
static char *manifestpackage; //metapackage named by the manicfest. static char *manifestpackages; //metapackage named by the manicfest.
static char *declinedpackages; //metapackage named by the manicfest.
static int domanifestinstall; //SECURITY_MANIFEST_* static int domanifestinstall; //SECURITY_MANIFEST_*
static qboolean doautoupdate; //updates will be marked (but not applied without the user's actions) static qboolean doautoupdate; //updates will be marked (but not applied without the user's actions)
static qboolean pkg_updating; //when flagged, further changes are blocked until completion.
//FIXME: these are allocated for the life of the exe. changing basedir should purge the list. //FIXME: these are allocated for the life of the exe. changing basedir should purge the list.
static int numdownloadablelists = 0; static int numdownloadablelists = 0;
@ -248,8 +251,8 @@ qboolean PM_PurgeOnDisable(package_t *p)
//corrupt packages must be purged //corrupt packages must be purged
if (p->flags & DPF_CORRUPT) if (p->flags & DPF_CORRUPT)
return true; return true;
//engine updates can be present and not enabled //certain updates can be present and not enabled
if (p->flags & DPF_ENGINE) if (p->flags & DPF_DISABLEDINSTALLED)
return false; return false;
//hashed packages can also be present and not enabled, but only if they're in the cache and not native //hashed packages can also be present and not enabled, but only if they're in the cache and not native
if (*p->gamedir && p->qhash && (p->flags & DPF_CACHED)) if (*p->gamedir && p->qhash && (p->flags & DPF_CACHED))
@ -353,7 +356,10 @@ void PM_ValidatePackage(package_t *p)
else if (!o) else if (!o)
{ {
if (!PM_PurgeOnDisable(p)) if (!PM_PurgeOnDisable(p))
{
p->flags |= fl; p->flags |= fl;
VFS_CLOSE(pf);
}
else if (p->qhash) else if (p->qhash)
{ {
char buf[8]; char buf[8];
@ -683,9 +689,20 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
} }
else if (!strcmp(Cmd_Argv(1), "updatemode")) else if (!strcmp(Cmd_Argv(1), "updatemode"))
{ {
if (!(parseflags & DPF_ENABLED)) //don't use a downloaded file's version of this if (parseflags & DPF_ENABLED) //don't use a downloaded file's version of this, only use the local version of it.
Cvar_ForceSet(&pm_autoupdate, Cmd_Argv(2)); Cvar_ForceSet(&pm_autoupdate, Cmd_Argv(2));
} }
else if (!strcmp(Cmd_Argv(1), "declined"))
{
if (parseflags & DPF_ENABLED) //don't use a downloaded file's version of this, only use the local version of it.
{
Z_Free(declinedpackages);
if (*Cmd_Argv(2))
declinedpackages = Z_StrDup(Cmd_Argv(2));
else
declinedpackages = NULL;
}
}
else else
{ {
//erk //erk
@ -774,7 +791,7 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
else if (!strncmp(arg, "test=", 5)) else if (!strncmp(arg, "test=", 5))
flags |= DPF_TESTING; flags |= DPF_TESTING;
else if (!strncmp(arg, "stale=", 6) && version==2) else if (!strncmp(arg, "stale=", 6) && version==2)
flags &= ~DPF_ENABLED; flags &= ~DPF_ENABLED; //known about, (probably) cached, but not actually enabled.
else if (!strncmp(arg, "installed=", 6) && version>2) else if (!strncmp(arg, "installed=", 6) && version>2)
flags |= parseflags & DPF_ENABLED; flags |= parseflags & DPF_ENABLED;
else else
@ -908,7 +925,10 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
p->flags |= DPF_ENGINE; p->flags |= DPF_ENGINE;
} }
else if (!Q_strcasecmp(p->arch, THISARCH)) else if (!Q_strcasecmp(p->arch, THISARCH))
; {
if (p->fsroot == FS_ROOT && !*p->gamedir)
p->flags |= DPF_PLUGIN;
}
else else
p->flags |= DPF_HIDDEN; //other engine builds or other cpus are all hidden p->flags |= DPF_HIDDEN; //other engine builds or other cpus are all hidden
} }
@ -933,6 +953,28 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
} }
} }
#ifdef PLUGINS
void PM_EnumeratePlugins(void (*callback)(const char *name))
{
package_t *p;
struct packagedep_s *d;
for (p = availablepackages; p; p = p->next)
{
if ((p->flags & DPF_ENABLED) && (p->flags & DPF_PLUGIN))
{
for (d = p->deps; d; d = d->next)
{
if (d->dtype == DEP_FILE)
{
if (!Q_strncasecmp(d->name, "fteplug_", 8))
callback(d->name);
}
}
}
}
}
#endif
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri)
{ {
package_t *p; package_t *p;
@ -983,7 +1025,6 @@ void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const cha
void PM_Shutdown(void) void PM_Shutdown(void)
{ {
//free everything... //free everything...
loadedinstalled = false;
pm_downloads_url.modified = false; pm_downloads_url.modified = false;
downloadablessequence++; downloadablessequence++;
@ -1006,6 +1047,7 @@ void PM_Shutdown(void)
while (availablepackages) while (availablepackages)
PM_FreePackage(availablepackages); PM_FreePackage(availablepackages);
loadedinstalled = false;
} }
@ -1062,6 +1104,10 @@ static package_t *PM_MarkedPackage(const char *packagename)
static void PM_RevertChanges(void) static void PM_RevertChanges(void)
{ {
package_t *p; package_t *p;
if (pkg_updating)
return;
for (p = availablepackages; p; p = p->next) for (p = availablepackages; p; p = p->next)
{ {
if (p->flags & DPF_ENABLED) if (p->flags & DPF_ENABLED)
@ -1078,6 +1124,9 @@ static void PM_UnmarkPackage(package_t *package)
package_t *o; package_t *o;
struct packagedep_s *dep; struct packagedep_s *dep;
if (pkg_updating)
return;
if (!(package->flags & DPF_MARKED)) if (!(package->flags & DPF_MARKED))
return; //looks like its already deselected. return; //looks like its already deselected.
package->flags &= ~(DPF_MARKED); package->flags &= ~(DPF_MARKED);
@ -1107,6 +1156,9 @@ static void PM_MarkPackage(package_t *package)
struct packagedep_s *dep, *dep2; struct packagedep_s *dep, *dep2;
qboolean replacing = false; qboolean replacing = false;
if (pkg_updating)
return;
if (package->flags & DPF_MARKED) if (package->flags & DPF_MARKED)
return; //looks like its already picked. return; //looks like its already picked.
@ -1206,27 +1258,48 @@ static void PM_MarkPackage(package_t *package)
} }
} }
static qboolean PM_NameIsInStrings(const char *strings, const char *match)
{
char tok[1024];
while (strings && *strings)
{
strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok));
if (!Q_strcasecmp(tok, match)) //okay its here.
return true;
}
return false;
}
//just flag stuff as needing updating //just flag stuff as needing updating
static unsigned int PM_MarkUpdates (void) static unsigned int PM_MarkUpdates (void)
{ {
unsigned int changecount = 0; unsigned int changecount = 0;
package_t *p, *o, *b, *e = NULL; package_t *p, *o, *b, *e = NULL;
if (manifestpackage) if (manifestpackages)
{ {
p = PM_MarkedPackage(manifestpackage); char tok[1024];
char *strings = manifestpackages;
while (strings && *strings)
{
strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok));
if (PM_NameIsInStrings(declinedpackages, tok))
continue;
p = PM_MarkedPackage(tok);
if (!p) if (!p)
{ {
p = PM_FindPackage(manifestpackage); p = PM_FindPackage(tok);
if (p) if (p)
{ {
PM_MarkPackage(p); PM_MarkPackage(p);
changecount++; changecount++;
} }
} }
else if (!(p->flags & DPF_PRESENT)) else if (!(p->flags & DPF_ENABLED))
changecount++; changecount++;
} }
}
for (p = availablepackages; p; p = p->next) for (p = availablepackages; p; p = p->next)
{ {
@ -1272,6 +1345,61 @@ static unsigned int PM_MarkUpdates (void)
return changecount; return changecount;
} }
#if defined(M_Menu_Prompt) || defined(SERVERONLY)
#else
static unsigned int PM_ChangeList(char *out, size_t outsize)
{
unsigned int changes = 0;
const char *change;
package_t *p;
size_t l;
size_t ofs = 0;
if (!outsize)
out = NULL;
else
*out = 0;
for (p = availablepackages; p; p=p->next)
{
if (!(p->flags & DPF_MARKED) != !(p->flags & DPF_ENABLED) || (p->flags & DPF_PURGE))
{
changes++;
if (!out)
continue;
if (p->flags & DPF_MARKED)
{
if (p->flags & DPF_PURGE)
change = va(" reinstall %s\n", p->name);
else if (p->flags & DPF_PRESENT)
change = va(" enable %s\n", p->name);
else
change = va(" install %s\n", p->name);
}
else if ((p->flags & DPF_PURGE) || !(p->qhash && (p->flags & DPF_CACHED)))
change = va(" uninstall %s\n", p->name);
else
change = va(" disable %s\n", p->name);
l = strlen(change);
if (ofs+l >= outsize)
{
Q_strncpyz(out, "Too many changes\n", outsize);
out = NULL;
break;
}
else
{
memcpy(out+ofs, change, l);
ofs += l;
out[ofs] = 0;
}
}
}
return changes;
}
#endif
static void PM_PrintChanges(void) static void PM_PrintChanges(void)
{ {
qboolean changes = 0; qboolean changes = 0;
@ -1309,6 +1437,9 @@ static void PM_ListDownloaded(struct dl_download *dl)
f = dl->file; f = dl->file;
dl->file = NULL; dl->file = NULL;
if (!availablepackages)
Con_Printf("ZOMG NO PACKAGES\n");
i = dl->user_num; i = dl->user_num;
if (dl != downloadablelist[i].curdl) if (dl != downloadablelist[i].curdl)
@ -1335,13 +1466,14 @@ static void PM_ListDownloaded(struct dl_download *dl)
if (!downloadablelist[i].received) if (!downloadablelist[i].received)
break; break;
} }
if (domanifestinstall == MANIFEST_SECURITY_INSTALLER && manifestpackage) /*
if (domanifestinstall == MANIFEST_SECURITY_INSTALLER && manifestpackages)
{ {
package_t *meta; package_t *meta;
meta = PM_MarkedPackage(manifestpackage); meta = PM_MarkedPackage(manifestpackages);
if (!meta) if (!meta)
{ {
meta = PM_FindPackage(manifestpackage); meta = PM_FindPackage(manifestpackages);
if (meta) if (meta)
{ {
PM_RevertChanges(); PM_RevertChanges();
@ -1368,6 +1500,7 @@ static void PM_ListDownloaded(struct dl_download *dl)
} }
} }
} }
*/
if ((doautoupdate || domanifestinstall == MANIFEST_SECURITY_DEFAULT) && i == numdownloadablelists) if ((doautoupdate || domanifestinstall == MANIFEST_SECURITY_DEFAULT) && i == numdownloadablelists)
{ {
if (PM_MarkUpdates()) if (PM_MarkUpdates())
@ -1474,6 +1607,7 @@ static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize)
} }
static void PM_WriteInstalledPackages(void) static void PM_WriteInstalledPackages(void)
{ {
char buf[8192];
int i; int i;
char *s; char *s;
package_t *p, *e = NULL; package_t *p, *e = NULL;
@ -1488,7 +1622,9 @@ static void PM_WriteInstalledPackages(void)
s = "version 2\n"; s = "version 2\n";
VFS_WRITE(f, s, strlen(s)); VFS_WRITE(f, s, strlen(s));
s = va("set updatemode \"%s\"\n", pm_autoupdate.string); s = va("set updatemode %s\n", COM_QuotedString(pm_autoupdate.string, buf, sizeof(buf), false));
VFS_WRITE(f, s, strlen(s));
s = va("set declined %s\n", COM_QuotedString(declinedpackages?declinedpackages:"", buf, sizeof(buf), false));
VFS_WRITE(f, s, strlen(s)); VFS_WRITE(f, s, strlen(s));
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
@ -1504,7 +1640,6 @@ static void PM_WriteInstalledPackages(void)
{ {
if (p->flags & (DPF_PRESENT|DPF_ENABLED)) if (p->flags & (DPF_PRESENT|DPF_ENABLED))
{ {
char buf[8192];
buf[0] = 0; buf[0] = 0;
COM_QuotedString(va("%s%s", p->category, p->name), buf, sizeof(buf), false); COM_QuotedString(va("%s%s", p->category, p->name), buf, sizeof(buf), false);
if (p->flags & DPF_ENABLED) if (p->flags & DPF_ENABLED)
@ -1656,6 +1791,31 @@ static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime,
return 1; return 1;
} }
//package has been downloaded and installed, but some packages need to be enabled
//(plugins might have other dll dependancies, so this can only happen AFTER the entire package was extracted)
void PM_PackageEnabled(package_t *p)
{
char ext[8];
struct packagedep_s *dep;
FS_FlushFSHashFull();
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype != DEP_FILE)
continue;
COM_FileExtension(dep->name, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_ReloadPackFiles();
#ifdef PLUGINS
if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, "fteplug_", 8))
Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL);
#endif
#ifdef MENU_DAT
if (!Q_strcasecmp(dep->name, "menu.dat"))
Cmd_ExecuteString("menu_restart\n", RESTRICT_LOCAL);
#endif
}
}
static void PM_StartADownload(void); static void PM_StartADownload(void);
//callback from PM_StartADownload //callback from PM_StartADownload
static void PM_Download_Got(struct dl_download *dl) static void PM_Download_Got(struct dl_download *dl)
@ -1739,8 +1899,10 @@ static void PM_Download_Got(struct dl_download *dl)
COM_FileExtension(dep->name, ext, sizeof(ext)); COM_FileExtension(dep->name, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_UnloadPackFiles(); //we reload them after FS_UnloadPackFiles(); //we reload them after
#ifdef PLUGINS
if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8)) if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8))
Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open
#endif
nfl = DPF_NATIVE; nfl = DPF_NATIVE;
if (*p->gamedir) if (*p->gamedir)
@ -1778,10 +1940,7 @@ static void PM_Download_Got(struct dl_download *dl)
PM_ValidatePackage(p); PM_ValidatePackage(p);
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) PM_PackageEnabled(p);
FS_ReloadPackFiles();
if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8))
Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL);
Z_Free(tempname); Z_Free(tempname);
PM_StartADownload(); PM_StartADownload();
@ -1911,9 +2070,13 @@ static void PM_StartADownload(void)
package_t *p; package_t *p;
const int simultaneous = PM_IsApplying(true)?1:2; const int simultaneous = PM_IsApplying(true)?1:2;
int i; int i;
qboolean downloading = false;
for (p = availablepackages; p && simultaneous > PM_IsApplying(false); p=p->next) for (p = availablepackages; p && simultaneous > PM_IsApplying(false); p=p->next)
{ {
if (p->download)
downloading = true;
if (p->trymirrors) if (p->trymirrors)
{ //flagged for a (re?)download { //flagged for a (re?)download
char *mirror = NULL; char *mirror = NULL;
@ -1936,19 +2099,25 @@ static void PM_StartADownload(void)
if (i == countof(p->mirror)) if (i == countof(p->mirror))
{ //this appears to be a meta package with no download { //this appears to be a meta package with no download
//just directly install it. //just directly install it.
//FIXME: make sure there's no files...
p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT); p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT);
p->flags |= DPF_ENABLED; p->flags |= DPF_ENABLED;
Con_Printf("Enabled meta package %s\n", p->name);
PM_WriteInstalledPackages(); PM_WriteInstalledPackages();
PM_PackageEnabled(p);
} }
continue; continue;
} }
if (!PM_PurgeOnDisable(p)) if ((p->flags & DPF_PRESENT) && !PM_PurgeOnDisable(p))
{ //its in our cache directory, so lets just use that { //its in our cache directory, so lets just use that
p->trymirrors = 0; p->trymirrors = 0;
p->flags |= DPF_ENABLED; p->flags |= DPF_ENABLED;
Con_Printf("Enabled cached package %s\n", p->name);
PM_WriteInstalledPackages(); PM_WriteInstalledPackages();
FS_ReloadPackFiles(); PM_PackageEnabled(p);
continue; continue;
} }
@ -1980,7 +2149,7 @@ static void PM_StartADownload(void)
{ {
vfsfile_t *raw; vfsfile_t *raw;
raw = FS_OpenVFS(temp, "wb", p->fsroot); raw = FS_OpenVFS(temp, "wb", p->fsroot);
tmpfile = FS_GZ_DecompressWriteFilter(raw, true); tmpfile = FS_GZ_WriteFilter(raw, true, false);
if (!tmpfile) if (!tmpfile)
VFS_CLOSE(raw); VFS_CLOSE(raw);
} }
@ -2000,6 +2169,7 @@ static void PM_StartADownload(void)
p->download->user_ctx = temp; p->download->user_ctx = temp;
DL_CreateThread(p->download, NULL, NULL); DL_CreateThread(p->download, NULL, NULL);
downloading = true;
} }
else else
{ {
@ -2011,12 +2181,19 @@ static void PM_StartADownload(void)
} }
} }
} }
//clear the updating flag once there's no more activity needed
pkg_updating = downloading;
} }
//'just' starts doing all the things needed to remove/install selected packages //'just' starts doing all the things needed to remove/install selected packages
static void PM_ApplyChanges(void) static void PM_ApplyChanges(void)
{ {
package_t *p, **link; package_t *p, **link;
if (pkg_updating)
return;
pkg_updating = true;
//delete any that don't exist //delete any that don't exist
for (link = &availablepackages; *link ; ) for (link = &availablepackages; *link ; )
{ {
@ -2028,22 +2205,33 @@ static void PM_ApplyChanges(void)
qboolean reloadpacks = false; qboolean reloadpacks = false;
struct packagedep_s *dep; struct packagedep_s *dep;
if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p))
{
for (dep = p->deps; dep; dep = dep->next) for (dep = p->deps; dep; dep = dep->next)
{ {
if (dep->dtype == DEP_FILE) if (dep->dtype == DEP_FILE)
{
if (!reloadpacks)
{ {
char ext[8]; char ext[8];
COM_FileExtension(dep->name, ext, sizeof(ext)); COM_FileExtension(dep->name, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
{
reloadpacks = true; reloadpacks = true;
#ifdef PLUGINS //when disabling/purging plugins, be sure to unload them first (unfortunately there might be some latency before this can actually happen).
if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, "fteplug_", 8))
Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open
#endif
}
}
if (reloadpacks) //okay, some package was removed, unload all, do the deletions/disables, then reload them. This is kinda shit. Would be better to remove individual packages, which would avoid unnecessary config execs.
FS_UnloadPackFiles(); FS_UnloadPackFiles();
}
} if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p))
{
Con_Printf("Purging package %s\n", p->name);
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILE)
{
if (*p->gamedir) if (*p->gamedir)
{ {
char *f = va("%s/%s", p->gamedir, dep->name); char *f = va("%s/%s", p->gamedir, dep->name);
@ -2061,6 +2249,8 @@ static void PM_ApplyChanges(void)
} }
} }
} }
else
Con_Printf("Disabling package %s\n", p->name);
p->flags &= ~(DPF_PURGE|DPF_ENABLED); p->flags &= ~(DPF_PURGE|DPF_ENABLED);
/* FIXME: windows bug: /* FIXME: windows bug:
@ -2116,20 +2306,131 @@ static void PM_ApplyChanges(void)
PM_StartADownload(); //and try to do those downloads. PM_StartADownload(); //and try to do those downloads.
} }
#if defined(M_Menu_Prompt) || defined(SERVERONLY)
//if M_Menu_Prompt is a define, then its a stub...
static void PM_PromptApplyChanges(void)
{
PM_ApplyChanges();
}
#else
static qboolean PM_DeclinedPackages(char *out, size_t outsize)
{
size_t ofs = 0;
package_t *p;
qboolean ret = false;
if (manifestpackages)
{
char tok[1024];
char *strings = manifestpackages;
while (strings && *strings)
{
strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok));
//already in the list
if (PM_NameIsInStrings(declinedpackages, tok))
continue;
p = PM_MarkedPackage(tok);
if (p) //don't mark it as declined if it wasn't
continue;
p = PM_FindPackage(tok);
if (p)
{ //okay, it was declined
ret = true;
if (!out)
{ //we're confirming that they should be flagged as declined
if (declinedpackages)
{
char *t = declinedpackages;
declinedpackages = Z_StrDup(va("%s;%s", declinedpackages, tok));
Z_Free(t);
}
else
declinedpackages = Z_StrDup(tok);
}
else
{ //we're collecting a list of package names
char *change = va("%s\n", p->name);
size_t l = strlen(change);
if (ofs+l >= outsize)
{
Q_strncpyz(out, "Too many changes\n", outsize);
out = NULL;
break;
}
else
{
memcpy(out+ofs, change, l);
ofs += l;
out[ofs] = 0;
}
break;
}
}
}
}
if (!out && ret)
PM_WriteInstalledPackages();
return ret;
}
static void PM_PromptApplyChanges_Callback(void *ctx, int opt)
{
pkg_updating = false;
if (opt == 0)
PM_ApplyChanges();
}
static void PM_PromptApplyChanges(void);
static void PM_PromptApplyDecline_Callback(void *ctx, int opt)
{
pkg_updating = false;
if (opt == 1)
{
PM_DeclinedPackages(NULL, 0);
PM_PromptApplyChanges();
}
}
static void PM_PromptApplyChanges(void)
{
unsigned int changes;
char text[8192];
//lock it down, so noone can make any changes while this prompt is still displayed
if (pkg_updating)
{
M_Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, "An update is already in progress\nPlease wait\n", NULL, NULL, "Cancel");
return;
}
pkg_updating = true;
strcpy(text, "Really decline the following\nrecommendedpackages?\n\n");
if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text)))
M_Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel");
else
{
strcpy(text, "Apply the following changes?\n\n");
changes = PM_ChangeList(text+strlen(text), sizeof(text)-strlen(text));
if (!changes)
pkg_updating = false;//no changes...
else
M_Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, text, "Apply", NULL, "Cancel");
}
}
#endif
//names packages that were listed from the manifest. //names packages that were listed from the manifest.
//if 'mark' is true, then this is an initial install. //if 'mark' is true, then this is an initial install.
void PM_ManifestPackage(const char *metaname, int security) void PM_ManifestPackage(const char *metaname, int security)
{ {
domanifestinstall = security; domanifestinstall = security;
Z_Free(manifestpackage); Z_Free(manifestpackages);
if (metaname && security) if (metaname && security)
{ {
manifestpackage = Z_StrDup(metaname); manifestpackages = Z_StrDup(metaname);
if (security) // PM_UpdatePackageList(false, false);
PM_UpdatePackageList(false, false);
} }
else else
manifestpackage = NULL; manifestpackages = NULL;
} }
void PM_Command_f(void) void PM_Command_f(void)
@ -2181,7 +2482,7 @@ void PM_Command_f(void)
else else
status = ""; status = "";
Con_Printf(" ^[%s%s%s%s^] %s^9 %s\n", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:""); Con_Printf(" ^[%s%s%s%s^] %s^9 %s (%s%s)\n", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":"");
} }
Con_Printf("<end of list>\n"); Con_Printf("<end of list>\n");
} }
@ -2277,24 +2578,29 @@ void PM_Command_f(void)
else if (!strcmp(act, "apply")) else if (!strcmp(act, "apply"))
{ {
Con_Printf("Applying package changes\n"); Con_Printf("Applying package changes\n");
if (qrenderer != QR_NONE)
PM_PromptApplyChanges();
else
PM_ApplyChanges(); PM_ApplyChanges();
} }
else if (!strcmp(act, "changes")) else if (!strcmp(act, "changes"))
{ {
PM_PrintChanges(); PM_PrintChanges();
} }
else if (!strcmp(act, "reset")) else if (!strcmp(act, "reset") || !strcmp(act, "revert"))
{ {
Con_Printf("Applying package changes\n");
PM_RevertChanges(); PM_RevertChanges();
PM_ApplyChanges();
PM_PrintChanges();
} }
else if (!strcmp(act, "upgrade")) else if (!strcmp(act, "upgrade"))
{ {
Con_Printf("Updating packages\n"); unsigned int changes = PM_MarkUpdates();
PM_MarkUpdates(); if (changes)
PM_ApplyChanges(); {
Con_Printf("%u packages flagged\n");
PM_PromptApplyChanges();
}
else
Con_Printf("Already using latest versions of all packages\n");
} }
else if (!strcmp(act, "add") || !strcmp(act, "get") || !strcmp(act, "install") || !strcmp(act, "enable")) else if (!strcmp(act, "add") || !strcmp(act, "get") || !strcmp(act, "install") || !strcmp(act, "enable"))
{ {
@ -2424,6 +2730,9 @@ void PM_Command_f (void)
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri)
{ {
} }
void PM_EnumeratePlugins(void (*callback)(const char *name))
{
}
void PM_ManifestPackage(const char *metaname, int security) void PM_ManifestPackage(const char *metaname, int security)
{ {
} }
@ -2666,7 +2975,7 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k
{ {
if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{ {
PM_ApplyChanges(); PM_PromptApplyChanges();
return true; return true;
} }
return false; return false;

View file

@ -86,8 +86,7 @@ extern cvar_t cl_cursor;
extern cvar_t cl_cursorsize; extern cvar_t cl_cursorsize;
extern cvar_t cl_cursorbias; extern cvar_t cl_cursorbias;
extern cvar_t m_preset_chosen; extern cvar_t m_preset_chosen;
menu_t *currentmenu; menu_t *topmenu;
menu_t *firstmenu;
menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old); menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old);
#ifdef HEXEN2 #ifdef HEXEN2
@ -328,30 +327,12 @@ static qboolean MI_Selectable(menuoption_t *op)
} }
} }
static void M_CheckMouseMove(void) static qboolean M_MouseMoved(menu_t *menu)
{ {
qboolean foundexclusive = false;
menu_t *menu;
menuoption_t *option; menuoption_t *option;
// if (menu->prev && !menu->exclusive)
if (omousex != (int)mousecursor_x || omousey != (int)mousecursor_y) // if (M_MouseMoved(menu->prev))
mousemoved = true; // return true;
else
mousemoved = false;
omousex = mousecursor_x;
omousey = mousecursor_y;
if (mousemoved)
{
for (menu = firstmenu; menu; menu = menu->parent)
{
if (menu->exclusive)
{
if (foundexclusive)
continue;
foundexclusive=true;
}
for(option = menu->options; option; option = option->common.next) for(option = menu->options; option; option = option->common.next)
{ {
if (mousemoved && !bindingactive && !option->common.ishidden) if (mousemoved && !bindingactive && !option->common.ishidden)
@ -362,9 +343,9 @@ static void M_CheckMouseMove(void)
{ {
if (MI_Selectable(option)) if (MI_Selectable(option))
{ {
if (menu->selecteditem != option) if (menu->mouseitem != option)
{ {
if (!option->common.noselectionsound && vid.activeapp) /* if (!option->common.noselectionsound && vid.activeapp)
{ {
#ifdef HEXEN2 #ifdef HEXEN2
if (M_GameType() == MGT_HEXEN2) if (M_GameType() == MGT_HEXEN2)
@ -373,20 +354,32 @@ static void M_CheckMouseMove(void)
#endif #endif
S_LocalSound ("misc/menu1.wav"); S_LocalSound ("misc/menu1.wav");
} }
*/
menu->selecteditem = option; menu->mouseitem = option;
menu->tooltiptime = realtime + 1; menu->tooltiptime = realtime + 1;
MenuTooltipChange(menu, menu->selecteditem->common.tooltip); MenuTooltipChange(menu, menu->mouseitem->common.tooltip);
}
if (menu->cursoritem)
menu->cursoritem->common.posy = menu->selecteditem->common.posy;
} }
// if (menu->cursoritem)
// menu->cursoritem->common.posy = menu->selecteditem->common.posy;
} }
} }
} }
} }
} }
return true;
} }
static void M_CheckMouseMove(void)
{
if (omousex != (int)mousecursor_x || omousey != (int)mousecursor_y)
mousemoved = true;
else
mousemoved = false;
omousex = mousecursor_x;
omousey = mousecursor_y;
if (mousemoved)
M_MouseMoved(topmenu);
} }
static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu) static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu)
@ -395,6 +388,20 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
mpic_t *p; mpic_t *p;
int pw,ph; int pw,ph;
if (option && option->common.type == mt_box && !option->common.ishidden)
{
Draw_TextBox(xpos+option->common.posx, ypos+option->common.posy, option->box.width, option->box.height);
option = option->common.next;
}
if (menu == topmenu && menu->mouseitem)
{
float alphamax = 0.5, alphamin = 0.2;
R2D_ImageColours(.5,.4,0,(sin(realtime*2)+1)*0.5*(alphamax-alphamin)+alphamin);
R2D_FillBlock(xpos+menu->mouseitem->common.posx, ypos+menu->mouseitem->common.posy, menu->mouseitem->common.width, menu->mouseitem->common.height);
R2D_ImageColours(1,1,1,1);
}
while (option) while (option)
{ {
if (!option->common.ishidden) if (!option->common.ishidden)
@ -411,7 +418,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d"); Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d");
} }
else if (option->common.width) else if (option->common.width)
Draw_FunStringWidth(xpos + option->common.posx, ypos+option->common.posy, option->text.text, option->common.width, true, option->text.isred); Draw_FunStringWidth(xpos + option->common.posx, ypos+option->common.posy, option->text.text, option->common.width, option->text.rightalign, option->text.isred);
else if (option->text.isred) else if (option->text.isred)
Draw_AltFunString(xpos+option->common.posx, ypos+option->common.posy, option->text.text); Draw_AltFunString(xpos+option->common.posx, ypos+option->common.posy, option->text.text);
else else
@ -524,9 +531,9 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
} }
#if 0 #if 0
if (on) if (on)
Draw_Character (x, y, 131); Draw_Character (x, y, 0xe083);
else else
Draw_Character (x, y, 129); Draw_Character (x, y, 0xe081);
#endif #endif
if (!menu->cursoritem && menu->selecteditem == option) if (!menu->cursoritem && menu->selecteditem == option)
Draw_AltFunString (x, y, on ? "on" : "off"); Draw_AltFunString (x, y, on ? "on" : "off");
@ -619,15 +626,19 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
static void MenuDraw(menu_t *menu) static void MenuDraw(menu_t *menu)
{ {
if (!menu->exclusive && menu->prev) //popup menus draw the one underneath them
MenuDraw(menu->prev);
if (!menu->dontexpand) if (!menu->dontexpand)
menu->xpos = ((vid.width - 320)>>1); menu->xpos = ((vid.width - 320)>>1);
if (menu->predraw) if (menu->predraw)
menu->predraw(menu); menu->predraw(menu);
MenuDrawItems(menu->xpos, menu->ypos, menu->options, menu); MenuDrawItems(menu->xpos, menu->ypos, menu->options, menu);
// draw tooltip // draw tooltip
if (menu->selecteditem && menu->tooltip && realtime > menu->tooltiptime) if (menu->mouseitem && menu->tooltip && realtime > menu->tooltiptime)
{ {
menuoption_t *option = menu->selecteditem; menuoption_t *option = menu->mouseitem;
if (omousex > menu->xpos+option->common.posx && omousex < menu->xpos+option->common.posx+option->common.width) if (omousex > menu->xpos+option->common.posx && omousex < menu->xpos+option->common.posx+option->common.width)
if (omousey > menu->ypos+option->common.posy && omousey < menu->ypos+option->common.posy+option->common.height) if (omousey > menu->ypos+option->common.posy && omousey < menu->ypos+option->common.posy+option->common.height)
{ {
@ -688,7 +699,8 @@ menutext_t *MC_AddWhiteText(menu_t *menu, int lhs, int rhs, int y, const char *t
n->common.iszone = true; n->common.iszone = true;
n->common.posx = lhs; n->common.posx = lhs;
n->common.posy = y; n->common.posy = y;
n->common.width = (rhs && rightalign)?rhs-lhs:0; n->common.width = (rhs)?rhs-lhs:0;
n->rightalign = rightalign;
if (text) if (text)
{ {
n->text = (char*)(n+1); n->text = (char*)(n+1);
@ -1410,7 +1422,7 @@ void MC_Slider_Key(menuslider_t *option, int key)
void MC_CheckBox_Key(menucheck_t *option, menu_t *menu, int key) void MC_CheckBox_Key(menucheck_t *option, menu_t *menu, int key)
{ {
if (key != K_ENTER && key != K_KP_ENTER && key != K_LEFTARROW && key != K_RIGHTARROW && key != K_MOUSE1) if (key != K_ENTER && key != K_KP_ENTER && key != K_LEFTARROW && key != K_RIGHTARROW && key != K_MWHEELUP && key != K_MWHEELDOWN && key != K_MOUSE1)
return; return;
if (option->func) if (option->func)
option->func(option, menu, CHK_TOGGLE); option->func(option, menu, CHK_TOGGLE);
@ -1476,7 +1488,7 @@ void MC_EditBox_Key(menuedit_t *edit, int key, unsigned int unicode)
void MC_Combo_Key(menucombo_t *combo, int key) void MC_Combo_Key(menucombo_t *combo, int key)
{ {
if (key == K_ENTER || key == K_KP_ENTER || key == K_RIGHTARROW || key == K_MOUSE1) if (key == K_ENTER || key == K_KP_ENTER || key == K_RIGHTARROW || key == K_MWHEELDOWN || key == K_MOUSE1)
{ {
combo->selectedoption++; combo->selectedoption++;
if (combo->selectedoption >= combo->numoptions) if (combo->selectedoption >= combo->numoptions)
@ -1487,7 +1499,7 @@ changed:
Cvar_Set(combo->cvar, (char *)combo->values[combo->selectedoption]); Cvar_Set(combo->cvar, (char *)combo->values[combo->selectedoption]);
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
} }
else if (key == K_LEFTARROW) else if (key == K_LEFTARROW || key == K_MWHEELUP)
{ {
combo->selectedoption--; combo->selectedoption--;
if (combo->selectedoption < 0) if (combo->selectedoption < 0)
@ -1496,41 +1508,16 @@ changed:
} }
} }
void M_AddMenuFront (menu_t *menu)
{
menu_t *pmenu;
m_state = m_complex;
if (!firstmenu)
{
M_AddMenu(menu);
return;
}
pmenu = firstmenu;
while(pmenu->parent)
pmenu = pmenu->parent;
pmenu->parent = menu;
menu->child = pmenu;
menu->parent = NULL;
menu->exclusive = true;
menu->xpos = ((vid.width - 320)>>1);
currentmenu = menu;
}
void M_AddMenu (menu_t *menu) void M_AddMenu (menu_t *menu)
{ {
m_state = m_complex; m_state = m_complex;
menu->parent = firstmenu; menu->prev = topmenu;
if (firstmenu) if (topmenu)
firstmenu->child = menu; topmenu->next = menu;
menu->child = NULL; menu->next = NULL;
firstmenu = menu; topmenu = menu;
menu->exclusive = true; menu->exclusive = true;
currentmenu = menu;
} }
menu_t *M_CreateMenu (int extrasize) menu_t *M_CreateMenu (int extrasize)
{ {
@ -1550,23 +1537,29 @@ menu_t *M_CreateMenuInfront (int extrasize)
menu->iszone=true; menu->iszone=true;
menu->data = menu+1; menu->data = menu+1;
M_AddMenuFront(menu); M_AddMenu(menu);
menu->xpos = ((vid.width - 320)>>1);
menu->exclusive = false; menu->exclusive = false;
return menu; return menu;
} }
void M_HideMenu (menu_t *menu) void M_HideMenu (menu_t *menu)
{ {
if (menu == firstmenu) if (menu == topmenu)
firstmenu = menu->parent; {
topmenu = menu->prev;
if (topmenu)
topmenu->next = NULL;
menu->prev = NULL;
}
else else
{ {
menu_t *prev; menu_t *prev;
prev = menu->child; prev = menu->next;
if (prev) if (prev)
prev->parent = menu->parent; prev->prev = menu->prev;
if (menu->parent) if (menu->prev)
menu->parent->child = menu; menu->prev->next = menu;
} }
} }
void M_RemoveMenu (menu_t *menu) void M_RemoveMenu (menu_t *menu)
@ -1580,20 +1573,20 @@ void M_RemoveMenu (menu_t *menu)
if (menu->remove) if (menu->remove)
menu->remove(menu); menu->remove(menu);
if (menu == firstmenu) if (menu == topmenu)
{ {
firstmenu = menu->parent; topmenu = menu->prev;
if (firstmenu) if (topmenu)
firstmenu->child = NULL; topmenu->next = NULL;
} }
else else
{ {
menu_t *prev; menu_t *prev;
prev = menu->child; prev = menu->next;
if (prev) if (prev)
prev->parent = menu->parent; prev->prev = menu->prev;
if (menu->parent) if (menu->prev)
menu->parent->child = menu; menu->prev->next = menu;
} }
op = menu->options; op = menu->options;
@ -1617,16 +1610,13 @@ void M_RemoveMenu (menu_t *menu)
menu->iszone=false; menu->iszone=false;
Z_Free(menu); Z_Free(menu);
} }
if (menu == currentmenu)
currentmenu = firstmenu;
} }
void M_ReloadMenus(void) void M_ReloadMenus(void)
{ {
menu_t *m; menu_t *m;
for (m = firstmenu; m; m = m->parent) for (m = topmenu; m; m = m->prev)
{ {
if (m->reset) if (m->reset)
m->reset(m); m->reset(m);
@ -1637,11 +1627,11 @@ void M_RemoveAllMenus (qboolean leaveprompts)
{ {
menu_t **link, *m; menu_t **link, *m;
for (link = &firstmenu; *link; ) for (link = &topmenu; *link; )
{ {
m = *link; m = *link;
if ((m->persist || !m->exclusive) && leaveprompts) if ((m->persist || !m->exclusive) && leaveprompts)
link = &m->parent; link = &m->prev;
else else
M_RemoveMenu(m); M_RemoveMenu(m);
} }
@ -1649,17 +1639,14 @@ void M_RemoveAllMenus (qboolean leaveprompts)
} }
void M_MenuPop_f (void) void M_MenuPop_f (void)
{ {
if (!currentmenu) if (!topmenu)
return; return;
M_RemoveMenu(currentmenu); M_RemoveMenu(topmenu);
} }
void M_Complex_Draw(void) void M_Complex_Draw(void)
{ {
menu_t *menu, *cmenu; if (!topmenu)
qboolean foundexclusive = false;
if (!firstmenu)
{ {
Key_Dest_Remove(kdm_emenu); Key_Dest_Remove(kdm_emenu);
m_state = m_none; m_state = m_none;
@ -1668,19 +1655,7 @@ void M_Complex_Draw(void)
M_CheckMouseMove(); M_CheckMouseMove();
for (menu = firstmenu; menu; ) MenuDraw(topmenu);
{
cmenu = menu;
menu = menu->parent; //this way we can remove the currently drawn menu easily (if needed)
if (cmenu->exclusive)
{
if (foundexclusive)
continue;
foundexclusive=true;
}
MenuDraw(cmenu);
}
} }
menuoption_t *M_NextItem(menu_t *m, menuoption_t *old) menuoption_t *M_NextItem(menu_t *m, menuoption_t *old)
@ -1707,11 +1682,11 @@ menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old)
while (1) while (1)
{ {
if (!op) if (!op)
op = currentmenu->options; op = m->options;
op = M_NextItem(m, op); op = M_NextItem(m, op);
if (!op) if (!op)
op = currentmenu->options; op = m->options;
if (op == old) if (op == old)
{ {
@ -1731,18 +1706,18 @@ menuoption_t *M_PrevSelectableItem(menu_t *m, menuoption_t *old)
menuoption_t *op; menuoption_t *op;
if (!old) if (!old)
old = currentmenu->options; old = m->options;
op = old; op = old;
while (1) while (1)
{ {
if (!op) if (!op)
op = currentmenu->options; op = m->options;
op = op->common.next; op = op->common.next;
if (!op) if (!op)
op = currentmenu->options; op = m->options;
if (op == old) if (op == old)
return old; //whoops. return old; //whoops.
@ -1755,6 +1730,7 @@ menuoption_t *M_PrevSelectableItem(menu_t *m, menuoption_t *old)
void M_Complex_Key(int key, int unicode) void M_Complex_Key(int key, int unicode)
{ {
menu_t *currentmenu = topmenu;
if (!currentmenu) if (!currentmenu)
return; //erm... return; //erm...
@ -1854,6 +1830,34 @@ void M_Complex_Key(int key, int unicode)
currentmenu->cursoritem->common.posy = currentmenu->selecteditem->common.posy; currentmenu->cursoritem->common.posy = currentmenu->selecteditem->common.posy;
} }
break; break;
case K_MOUSE1:
case K_MOUSE3:
case K_MOUSE4:
case K_MOUSE5:
case K_MOUSE6:
case K_MOUSE7:
case K_MOUSE8:
case K_MOUSE9:
case K_MOUSE10:
case K_MWHEELUP:
case K_MWHEELDOWN:
if (!currentmenu->mouseitem)
break;
if (currentmenu->mouseitem && currentmenu->selecteditem != currentmenu->mouseitem)
{
currentmenu->selecteditem = currentmenu->mouseitem;
#ifdef HEXEN2
if (M_GameType() == MGT_HEXEN2)
S_LocalSound ("raven/menu1.wav");
else
#endif
S_LocalSound ("misc/menu1.wav");
if (currentmenu->cursoritem)
currentmenu->cursoritem->common.posy = currentmenu->selecteditem->common.posy;
}
//fall through
default: default:
if (!currentmenu->selecteditem) if (!currentmenu->selecteditem)
{ {
@ -2131,12 +2135,14 @@ void M_Menu_Main_f (void)
} }
else else
{ {
int width;
m_state = m_complex; m_state = m_complex;
Key_Dest_Add(kdm_emenu); Key_Dest_Add(kdm_emenu);
mainm = M_CreateMenu(0); mainm = M_CreateMenu(0);
p = R2D_SafeCachePic("gfx/ttl_main.lmp"); p = R2D_SafeCachePic("gfx/mainmenu.lmp");
if (R_GetShaderSizes(p, NULL, NULL, true) <= 0) R2D_SafeCachePic("gfx/ttl_main.lmp");
if (R_GetShaderSizes(p, &width, NULL, true) <= 0)
{ {
MC_AddRedText(mainm, 16, 170, 0, "MAIN MENU", false); MC_AddRedText(mainm, 16, 170, 0, "MAIN MENU", false);
@ -2152,21 +2158,18 @@ void M_Menu_Main_f (void)
MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp"); MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp");
MC_AddPicture(mainm, 72, 32, 240, 112, "gfx/mainmenu.lmp"); MC_AddPicture(mainm, 72, 32, 240, 112, "gfx/mainmenu.lmp");
p = R2D_SafeCachePic("gfx/mainmenu.lmp");
b=MC_AddConsoleCommand (mainm, 72, 312, 32, "", "menu_single\n"); b=MC_AddConsoleCommand (mainm, 72, 312, 32, "", "menu_single\n");
b->common.tooltip = "Start singleplayer Quake game."; b->common.tooltip = "Start singleplayer Quake game.";
mainm->selecteditem = (menuoption_t *)b; mainm->selecteditem = (menuoption_t *)b;
b->common.width = p->width; b->common.width = width;
b->common.height = 20; b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 72, 312, 52, "", "menu_multi\n"); b=MC_AddConsoleCommand (mainm, 72, 312, 52, "", "menu_multi\n");
b->common.tooltip = "Multiplayer menu."; b->common.tooltip = "Multiplayer menu.";
b->common.width = p->width; b->common.width = width;
b->common.height = 20; b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 72, 312, 72, "", "menu_options\n"); b=MC_AddConsoleCommand (mainm, 72, 312, 72, "", "menu_options\n");
b->common.tooltip = "Options menu."; b->common.tooltip = "Options menu.";
b->common.width = p->width; b->common.width = width;
b->common.height = 20; b->common.height = 20;
if (m_helpismedia.value) if (m_helpismedia.value)
{ {
@ -2178,7 +2181,7 @@ void M_Menu_Main_f (void)
b=MC_AddConsoleCommand(mainm, 72, 312, 92, "", "help\n"); b=MC_AddConsoleCommand(mainm, 72, 312, 92, "", "help\n");
b->common.tooltip = "Help menu."; b->common.tooltip = "Help menu.";
} }
b->common.width = p->width; b->common.width = width;
b->common.height = 20; b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 72, 312, 112, "", "menu_quit\n"); b=MC_AddConsoleCommand (mainm, 72, 312, 112, "", "menu_quit\n");
#ifdef FTE_TARGET_WEB #ifdef FTE_TARGET_WEB
@ -2186,7 +2189,7 @@ void M_Menu_Main_f (void)
#else #else
b->common.tooltip = "Exit to DOS."; b->common.tooltip = "Exit to DOS.";
#endif #endif
b->common.width = p->width; b->common.width = width;
b->common.height = 20; b->common.height = 20;
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32); mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32);

View file

@ -1060,7 +1060,7 @@ static void CalcFilters(menu_t *menu)
if (info->filter[2]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_QUAKEWORLD, SLIST_TEST_NOTEQUAL); if (info->filter[2]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_QUAKEWORLD, SLIST_TEST_NOTEQUAL);
} }
if (info->filter[3]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_PROXY, SLIST_TEST_NOTCONTAIN); if (info->filter[3]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_PROXY, SLIST_TEST_NOTCONTAIN);
if (info->filter[5]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_FAVORITE, SLIST_TEST_CONTAINS); if (!info->filter[5]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_FAVORITE, SLIST_TEST_CONTAINS);
if (info->filter[6]) Master_SetMaskInteger(false, SLKEY_NUMHUMANS, 0, SLIST_TEST_NOTEQUAL); if (info->filter[6]) Master_SetMaskInteger(false, SLKEY_NUMHUMANS, 0, SLIST_TEST_NOTEQUAL);
if (info->filter[7]) Master_SetMaskInteger(false, SLKEY_FREEPLAYERS, 0, SLIST_TEST_NOTEQUAL); if (info->filter[7]) Master_SetMaskInteger(false, SLKEY_FREEPLAYERS, 0, SLIST_TEST_NOTEQUAL);
@ -1075,7 +1075,7 @@ static qboolean SL_ReFilter (menucheck_t *option, menu_t *menu, chk_set_t set)
switch(set) switch(set)
{ {
case CHK_CHECKED: case CHK_CHECKED:
return info->filter[option->bits]; return !info->filter[option->bits];
case CHK_TOGGLE: case CHK_TOGGLE:
if (option->bits>0) if (option->bits>0)
{ {
@ -1201,22 +1201,23 @@ void M_Menu_ServerList2_f(void)
#ifdef NQPROT #ifdef NQPROT
if (M_GameType() == MGT_QUAKE1) if (M_GameType() == MGT_QUAKE1)
{ {
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*1, "Hide NQ ", SL_ReFilter, 1); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*1, "Show NQ ", SL_ReFilter, 1);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*2, "Hide QW ", SL_ReFilter, 2); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*2, "Show QW ", SL_ReFilter, 2);
} }
#endif #endif
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*3, "Hide Proxies", SL_ReFilter, 3); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*3, "Show Proxies", SL_ReFilter, 3);
info->filtertext = info->filtertext =
MC_AddEditCvar (menu, 128, 200, vid.height - 64+8*4, "Filter ", sb_filtertext.name, true); MC_AddEditCvar (menu, 128, 200, vid.height - 64+8*4, "Filter ", sb_filtertext.name, true);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*5, "Only Favs ", SL_ReFilter, 5); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*5, "Only Favs ", SL_ReFilter, 5);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*6, "Hide Empty", SL_ReFilter, 6); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*6, "Show Empty", SL_ReFilter, 6);
MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*7, "Hide Full ", SL_ReFilter, 7); MC_AddCheckBoxFunc(menu, 128, 208, vid.height - 64+8*7, "Show Full ", SL_ReFilter, 7);
MC_AddCommand(menu, 64, 320, 0, info->refreshtext, SL_DoRefresh); MC_AddCommand(menu, 64, 320, 0, info->refreshtext, SL_DoRefresh);
info->filter[1] = !!sb_hidenetquake.value; info->filter[1] = !!sb_hidenetquake.value;
info->filter[2] = !!sb_hidequakeworld.value; info->filter[2] = !!sb_hidequakeworld.value;
info->filter[3] = !!sb_hideproxies.value; info->filter[3] = !!sb_hideproxies.value;
info->filter[5] = true;//!sb_showonlyfavourites.value;
info->filter[6] = !!sb_hideempty.value; info->filter[6] = !!sb_hideempty.value;
info->filter[7] = !!sb_hidefull.value; info->filter[7] = !!sb_hidefull.value;

View file

@ -181,20 +181,6 @@ void M_Menu_Options_f (void)
#endif #endif
int y; int y;
#ifdef WEBCLIENT
static const char *autoupopts[] = {
"Off",
"Tested(Recommended)",
"Untested(Latest)",
NULL
};
static const char *autoupvals[] = {
"0",
"1",
"2",
NULL
};
#endif
static const char *projections[] = { static const char *projections[] = {
"Regular", "Regular",
"Stereographic", "Stereographic",
@ -237,6 +223,9 @@ void M_Menu_Options_f (void)
menubulk_t bulk[] = { menubulk_t bulk[] = {
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."), MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
#ifdef WEBCLIENT
MB_CONSOLECMD("Updates and packages", "menu_download\n", "Modify keyboard and mouse inputs."),
#endif
MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."), MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."),
MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."), MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."),
MB_CONSOLECMD("Save all settings", "cfg_save\n", "Writes changed settings out to a config file."), MB_CONSOLECMD("Save all settings", "cfg_save\n", "Writes changed settings out to a config file."),
@ -250,9 +239,6 @@ void M_Menu_Options_f (void)
MB_CHECKBOXCVAR("Lookspring", lookspring, 0), MB_CHECKBOXCVAR("Lookspring", lookspring, 0),
MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0), MB_CHECKBOXCVAR("Lookstrafe", lookstrafe, 0),
MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0), MB_CHECKBOXCVAR("Windowed Mouse", _windowed_mouse, 0),
#ifdef WEBCLIENT
MB_COMBOCVAR("Auto Update", pm_autoupdate, autoupopts, autoupvals, "This offers to download engine+package updates from the internet, when new versions are available."),
#endif
#ifndef CLIENTONLY #ifndef CLIENTONLY
MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL), MB_COMBOCVAR("Auto Save", sv_autosave, autosaveopts, autosavevals, NULL),
#endif #endif
@ -760,7 +746,7 @@ const char *presetexec[] =
"seta gl_polyblend 0;" "seta gl_polyblend 0;"
"seta gl_flashblend 0;" "seta gl_flashblend 0;"
"seta gl_specular 0;" "seta gl_specular 0;"
"seta r_deluxemapping 0;" "seta r_deluxmapping 0;"
"seta r_loadlit 0;" "seta r_loadlit 0;"
"seta r_fastsky 1;" "seta r_fastsky 1;"
"seta r_drawflame 0;" "seta r_drawflame 0;"
@ -880,12 +866,12 @@ const char *presetexec[] =
"r_shadow_realtime_dlight 1;" "r_shadow_realtime_dlight 1;"
// "gl_detail 1;" // "gl_detail 1;"
"r_lightstylesmooth 1;" "r_lightstylesmooth 1;"
"r_deluxemapping 1;" "r_deluxmapping 2;"
"gl_texture_anisotropic_filtering 4;" "gl_texture_anisotropic_filtering 4;"
, // realtime options , // realtime options
"r_bloom 1;" "r_bloom 1;"
"r_deluxemapping 0;" //won't be seen anyway "r_deluxmapping 0;" //won't be seen anyway
"r_particledesc \"high tsshaft\";" "r_particledesc \"high tsshaft\";"
"r_waterstyle 3;" "r_waterstyle 3;"
"r_glsl_offsetmapping 1;" "r_glsl_offsetmapping 1;"
@ -944,7 +930,7 @@ void M_Menu_Preset_f (void)
#else #else
bias = 1; bias = 1;
#endif #endif
if (r_deluxemapping_cvar.ival) if (r_deluxmapping_cvar.ival)
item = 2; //nice item = 2; //nice
else if (gl_load24bit.ival) else if (gl_load24bit.ival)
item = 3; //normal item = 3; //normal
@ -1216,7 +1202,6 @@ void M_Menu_Textures_f (void)
MB_COMBOCVAR("Anisotropy", gl_texture_anisotropic_filtering, anisotropylevels, anisotropyvalues, NULL), MB_COMBOCVAR("Anisotropy", gl_texture_anisotropic_filtering, anisotropylevels, anisotropyvalues, NULL),
MB_SPACING(4), MB_SPACING(4),
MB_CHECKBOXCVAR("Software-style Rendering", r_softwarebanding_cvar, 0), MB_CHECKBOXCVAR("Software-style Rendering", r_softwarebanding_cvar, 0),
MB_CHECKBOXCVAR("Deluxemapping", r_deluxemapping_cvar, 0),
MB_CHECKBOXCVAR("Specular Highlights", gl_specular, 0), MB_CHECKBOXCVAR("Specular Highlights", gl_specular, 0),
// MB_CHECKBOXCVAR("Detail Textures", gl_detail, 0), // MB_CHECKBOXCVAR("Detail Textures", gl_detail, 0),
MB_CHECKBOXCVAR("offsetmapping", r_glsl_offsetmapping, 0), MB_CHECKBOXCVAR("offsetmapping", r_glsl_offsetmapping, 0),
@ -1481,6 +1466,7 @@ void M_Menu_Lighting_f (void)
MB_SPACING(4), MB_SPACING(4),
#endif #endif
MB_COMBOCVAR("LIT Loading", r_loadlits, loadlitopts, loadlitvalues, "Determines if the engine should use external colored lighting for maps. The generated setting will cause the engine to generate colored lighting for maps that don't have the associated data."), MB_COMBOCVAR("LIT Loading", r_loadlits, loadlitopts, loadlitvalues, "Determines if the engine should use external colored lighting for maps. The generated setting will cause the engine to generate colored lighting for maps that don't have the associated data."),
MB_COMBOCVAR("Deluxmapping", r_deluxmapping_cvar, loadlitopts, loadlitvalues, "Controls whether static lighting should respond to lighting directions."),
MB_CHECKBOXCVAR("Lightstyle Lerp", r_lightstylesmooth, 0), MB_CHECKBOXCVAR("Lightstyle Lerp", r_lightstylesmooth, 0),
MB_SPACING(4), MB_SPACING(4),
MB_COMBOCVAR("Flash Blend", r_flashblend, fbopts, fbvalues, "Disables or enables the spherical light effect for dynamic lights. Traced means the sphere effect will be line of sight checked before displaying the effect."), MB_COMBOCVAR("Flash Blend", r_flashblend, fbopts, fbvalues, "Disables or enables the spherical light effect for dynamic lights. Traced means the sphere effect will be line of sight checked before displaying the effect."),
@ -2507,6 +2493,9 @@ void M_Menu_Video_f (void)
#ifdef VKQUAKE #ifdef VKQUAKE
"Vulkan (Experimental)", "Vulkan (Experimental)",
#endif #endif
#ifdef D3D8QUAKE
"Direct3D 8 (limited)",
#endif
#ifdef D3D9QUAKE #ifdef D3D9QUAKE
"Direct3D 9 (limited)", "Direct3D 9 (limited)",
#endif #endif
@ -2533,6 +2522,9 @@ void M_Menu_Video_f (void)
#ifdef VKQUAKE #ifdef VKQUAKE
"vk", "vk",
#endif #endif
#ifdef D3D8QUAKE
"d3d8",
#endif
#ifdef D3D9QUAKE #ifdef D3D9QUAKE
"d3d9", "d3d9",
#endif #endif

View file

@ -89,8 +89,8 @@ void M_MenuS_Clear_f (void)
void M_MenuS_Script_f (void) //create a menu. void M_MenuS_Script_f (void) //create a menu.
{ {
extern menu_t *topmenu;
int items; int items;
extern menu_t *currentmenu;
menu_t *oldmenu; menu_t *oldmenu;
char *alias = Cmd_Argv(1); char *alias = Cmd_Argv(1);
Key_Dest_Add(kdm_emenu); Key_Dest_Add(kdm_emenu);
@ -115,7 +115,7 @@ void M_MenuS_Script_f (void) //create a menu.
M_MenuS_Clear_f(); M_MenuS_Clear_f();
} }
oldmenu = currentmenu; oldmenu = topmenu;
menu_script = M_CreateMenu(0); menu_script = M_CreateMenu(0);
if (oldmenu) if (oldmenu)

View file

@ -748,49 +748,79 @@ static void M_Menu_Prompt_Cancel (struct menu_s *gm)
if (callback) if (callback)
callback(ctx, -1); callback(ctx, -1);
} }
void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel) void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, const char *messages, char *optionyes, char *optionno, char *optioncancel)
{ {
promptmenu_t *m; promptmenu_t *m;
char *t; char *t;
int y;
int x = 64, w = 224;
Key_Dest_Add(kdm_emenu); Key_Dest_Add(kdm_emenu);
m_state = m_complex; m_state = m_complex;
m = (promptmenu_t*)M_CreateMenuInfront(sizeof(*m) - sizeof(m->m) + strlen(m1)+strlen(m2)+strlen(m3)+strlen(optionyes)+strlen(optionyes)+strlen(optioncancel)+6); m = (promptmenu_t*)M_CreateMenuInfront(sizeof(*m) - sizeof(m->m) + strlen(messages)+(optionyes?strlen(optionyes):0)+(optionno?strlen(optionno):0)+(optioncancel?strlen(optioncancel):0)+6);
m->callback = callback; m->callback = callback;
m->ctx = ctx; m->ctx = ctx;
m->m.remove = M_Menu_Prompt_Cancel; m->m.remove = M_Menu_Prompt_Cancel;
t = (char*)(m+1); t = (char*)(m+1);
strcpy(t, m1); if (optionyes)
m1 = t; {
t += strlen(t)+1;
strcpy(t, m2);
m2 = t;
t += strlen(t)+1;
strcpy(t, m3);
m3 = t;
t += strlen(t)+1;
strcpy(t, optionyes); strcpy(t, optionyes);
optionyes = t; optionyes = t;
t += strlen(t)+1; t += strlen(t)+1;
}
if (optionno)
{
strcpy(t, optionno); strcpy(t, optionno);
optionno = t; optionno = t;
t += strlen(t)+1; t += strlen(t)+1;
}
if (optioncancel)
{
strcpy(t, optioncancel); strcpy(t, optioncancel);
optioncancel = t; optioncancel = t;
t += strlen(t)+1;
}
MC_AddWhiteText(&m->m, 64, 0, 84, m1, false); y = 76;
MC_AddWhiteText(&m->m, 64, 0, 92, m2, false); y += 8; //top border
MC_AddWhiteText(&m->m, 64, 0, 100, m3, false); strcpy(t, messages);
m->b_yes = MC_AddCommand(&m->m, 64, 0, 116, optionyes, M_Menu_Prompt_Button); for(messages = t; t; y += 8)
m->b_no = MC_AddCommand(&m->m, 144,0, 116, optionno, M_Menu_Prompt_Button); {
m->b_cancel = MC_AddCommand(&m->m, 224,0, 116, optioncancel, M_Menu_Prompt_Button); messages = t;
t = strchr(messages, '\n');
if (t)
*t++ = 0;
if (*messages)
MC_AddWhiteText(&m->m, x, x+w, y, messages, 2);
}
y += 8; //blank space
if (optionyes)
{
m->b_yes = MC_AddCommand(&m->m, x, x+70, y, optionyes, M_Menu_Prompt_Button);
m->b_yes->rightalign = 2;
}
if (optionno)
{
m->b_no = MC_AddCommand(&m->m, x+w/3, x+(2*w)/3, y, optionno, M_Menu_Prompt_Button);
m->b_no->rightalign = 2; //actually center align
}
if (optioncancel)
{
m->b_cancel = MC_AddCommand(&m->m, x+(2*w)/3, x+w, y, optioncancel, M_Menu_Prompt_Button);
m->b_cancel->rightalign = 2;
}
y += 8; //footer
y += 8; //bottom border
m->m.selecteditem = (menuoption_t *)m->b_cancel; m->m.selecteditem = (menuoption_t *)m->b_cancel;
MC_AddBox (&m->m, 56, 76, 25, 5); MC_AddBox (&m->m, x-8, 76, (w/8), (y-76)/8);
} }
//============================================================================= //=============================================================================
@ -1372,8 +1402,8 @@ void M_Draw (int uimenu)
#ifndef NOBUILTINMENUS #ifndef NOBUILTINMENUS
if ((!menu_script || scr_con_current) && !m_recursiveDraw) if ((!menu_script || scr_con_current) && !m_recursiveDraw)
{ {
extern menu_t *firstmenu; extern menu_t *topmenu;
if (m_state == m_complex && firstmenu && firstmenu->selecteditem && firstmenu->selecteditem->common.type == mt_slider && (firstmenu->selecteditem->slider.var == &v_gamma || firstmenu->selecteditem->slider.var == &v_contrast)) if (m_state == m_complex && topmenu && topmenu->selecteditem && topmenu->selecteditem->common.type == mt_slider && (topmenu->selecteditem->slider.var == &v_gamma || topmenu->selecteditem->slider.var == &v_contrast))
/*no menu tint if we're trying to adjust gamma*/; /*no menu tint if we're trying to adjust gamma*/;
else else
R2D_FadeScreen (); R2D_FadeScreen ();

View file

@ -111,7 +111,7 @@ void M_Menu_Mods_f (void); //used at startup if the current gamedirs look dodgy.
void M_Menu_Installer (void); //given an embedded manifest, this displays an install menu for said game. void M_Menu_Installer (void); //given an embedded manifest, this displays an install menu for said game.
mpic_t *M_CachePic (char *path); mpic_t *M_CachePic (char *path);
void M_Menu_Quit_f (void); void M_Menu_Quit_f (void);
void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel); void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, const char *messages, char *optionyes, char *optionno, char *optioncancel);
struct menu_s; struct menu_s;
@ -198,6 +198,7 @@ typedef struct menucheck_s {
typedef struct { typedef struct {
menucommon_t common; menucommon_t common;
const char *text; const char *text;
qboolean rightalign;
qboolean isred; qboolean isred;
} menutext_t; } menutext_t;
@ -286,12 +287,13 @@ typedef struct menu_s {
menuoption_t *options; menuoption_t *options;
menuoption_t *selecteditem; menuoption_t *selecteditem;
menuoption_t *mouseitem;
menutooltip_t *tooltip; menutooltip_t *tooltip;
double tooltiptime; double tooltiptime;
struct menu_s *child; struct menu_s *prev;
struct menu_s *parent; struct menu_s *next;
int cursorpos; int cursorpos;
menuoption_t *cursoritem; menuoption_t *cursoritem;
@ -371,7 +373,6 @@ menu_t *M_Options_Title(int *y, int infosize); /*Create a menu with the default
menu_t *M_CreateMenu (int extrasize); menu_t *M_CreateMenu (int extrasize);
menu_t *M_CreateMenuInfront (int extrasize); menu_t *M_CreateMenuInfront (int extrasize);
void M_AddMenu (menu_t *menu); void M_AddMenu (menu_t *menu);
void M_AddMenuFront (menu_t *menu);
void M_HideMenu (menu_t *menu); void M_HideMenu (menu_t *menu);
void M_RemoveMenu (menu_t *menu); void M_RemoveMenu (menu_t *menu);
void M_RemoveAllMenus (qboolean leaveprompts); void M_RemoveAllMenus (qboolean leaveprompts);

View file

@ -488,7 +488,7 @@ typedef struct rendererinfo_s {
#define BE_RenderToTextureUpdate2d rf->BE_RenderToTextureUpdate2d #define BE_RenderToTextureUpdate2d rf->BE_RenderToTextureUpdate2d
#define RT_IMAGEFLAGS IF_NOMIPMAP|IF_CLAMP|IF_LINEAR|IF_RENDERTARGET #define RT_IMAGEFLAGS (IF_NOMIPMAP|IF_CLAMP|IF_LINEAR|IF_RENDERTARGET)
texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfmt, unsigned int imageflags); texid_t R2D_RT_Configure(const char *id, int width, int height, uploadfmt_t rtfmt, unsigned int imageflags);
texid_t R2D_RT_GetTexture(const char *id, unsigned int *width, unsigned int *height); texid_t R2D_RT_GetTexture(const char *id, unsigned int *width, unsigned int *height);

View file

@ -4503,7 +4503,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
return 1; return 1;
// inwater check, switch only once // inwater check, switch only once
if (r_part_contentswitch.ival && ptype->inwater >= 0 && cl.worldmodel) if (r_part_contentswitch.ival && ptype->inwater >= 0 && cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
{ {
int cont; int cont;
cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, org); cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, org);
@ -5937,7 +5937,7 @@ static int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlk
return 1; return 1;
// inwater check, switch only once // inwater check, switch only once
if (r_part_contentswitch.ival && ptype->inwater >= 0 && cl.worldmodel) if (r_part_contentswitch.ival && ptype->inwater >= 0 && cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
{ {
int cont; int cont;
cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, startpos); cont = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, startpos);

View file

@ -759,6 +759,14 @@ static model_t *CSQC_GetModelForIndex(int index)
return NULL; return NULL;
} }
static float CSQC_PitchScaleForModelIndex(int index)
{
model_t *mod = CSQC_GetModelForIndex(index);
if (mod && (mod->type == mod_alias || mod->type == mod_halflife))
return r_meshpitch.value; //these are buggy.
return 1;
}
static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out) static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
{ {
int ival; int ival;
@ -827,7 +835,7 @@ static qboolean CopyCSQCEdictToEntity(csqcedict_t *in, entity_t *out)
else else
{ {
VectorCopy(in->v->angles, out->angles); VectorCopy(in->v->angles, out->angles);
if (model->type == mod_alias) if (model && model->type == mod_alias)
out->angles[0] *= r_meshpitch.value; out->angles[0] *= r_meshpitch.value;
AngleVectors(out->angles, out->axis[0], out->axis[1], out->axis[2]); AngleVectors(out->angles, out->axis[0], out->axis[1], out->axis[2]);
VectorInverse(out->axis[1]); VectorInverse(out->axis[1]);
@ -1512,7 +1520,7 @@ typedef struct
// vec3_t sdir; // vec3_t sdir;
// vec3_t tdir; // vec3_t tdir;
} qcvertex_t; } qcvertex_t;
void QCBUILTIN PF_R_AddTrisoup(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_R_AddTrisoup_Simple(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
shader_t *shader; //parm 0 shader_t *shader; //parm 0
unsigned int qcflags = G_INT(OFS_PARM1); unsigned int qcflags = G_INT(OFS_PARM1);
@ -2060,6 +2068,9 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
{ {
float fmt = G_FLOAT(OFS_PARM2); float fmt = G_FLOAT(OFS_PARM2);
float *size = G_VECTOR(OFS_PARM3); float *size = G_VECTOR(OFS_PARM3);
if (fmt < 0)
R2D_RT_Configure(r_refdef.rt_destcolour[i].texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
else
R2D_RT_Configure(r_refdef.rt_destcolour[i].texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS); R2D_RT_Configure(r_refdef.rt_destcolour[i].texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS);
} }
BE_RenderToTextureUpdate2d(true); BE_RenderToTextureUpdate2d(true);
@ -2071,6 +2082,9 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
{ {
float fmt = G_FLOAT(OFS_PARM2); float fmt = G_FLOAT(OFS_PARM2);
float *size = G_VECTOR(OFS_PARM3); float *size = G_VECTOR(OFS_PARM3);
if (fmt < 0)
R2D_RT_Configure(r_refdef.rt_sourcecolour.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
else
R2D_RT_Configure(r_refdef.rt_sourcecolour.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS); R2D_RT_Configure(r_refdef.rt_sourcecolour.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS);
} }
BE_RenderToTextureUpdate2d(false); BE_RenderToTextureUpdate2d(false);
@ -2081,6 +2095,9 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
{ {
float fmt = G_FLOAT(OFS_PARM2); float fmt = G_FLOAT(OFS_PARM2);
float *size = G_VECTOR(OFS_PARM3); float *size = G_VECTOR(OFS_PARM3);
if (fmt < 0)
R2D_RT_Configure(r_refdef.rt_depth.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
else
R2D_RT_Configure(r_refdef.rt_depth.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS); R2D_RT_Configure(r_refdef.rt_depth.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS);
} }
BE_RenderToTextureUpdate2d(false); BE_RenderToTextureUpdate2d(false);
@ -2091,6 +2108,9 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
{ {
float fmt = G_FLOAT(OFS_PARM2); float fmt = G_FLOAT(OFS_PARM2);
float *size = G_VECTOR(OFS_PARM3); float *size = G_VECTOR(OFS_PARM3);
if (fmt < 0)
R2D_RT_Configure(r_refdef.rt_ripplemap.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
else
R2D_RT_Configure(r_refdef.rt_ripplemap.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS); R2D_RT_Configure(r_refdef.rt_ripplemap.texname, size[0], size[1], PR_TranslateTextureFormat(fmt), RT_IMAGEFLAGS);
} }
BE_RenderToTextureUpdate2d(false); BE_RenderToTextureUpdate2d(false);
@ -4987,6 +5007,14 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s
} }
} }
static void AngleVectorsIndex (const vec3_t angles, int modelindex, vec3_t forward, vec3_t right, vec3_t up)
{
vec3_t fixedangles;
fixedangles[0] = angles[0] * CSQC_PitchScaleForModelIndex(modelindex);
fixedangles[1] = angles[1];
fixedangles[2] = angles[2];
AngleVectors(fixedangles, forward, right, up);
}
static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int entnum = G_FLOAT(OFS_PARM0); int entnum = G_FLOAT(OFS_PARM0);
@ -5000,6 +5028,136 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s *
return; return;
} }
if (entnum > 0 && entnum <= cl.allocated_client_slots && cl.lerpplayers[entnum-1].sequence == cl.lerpentssequence)
{
player_state_t *ps = &cl.inframes[cl.validsequence&UPDATE_MASK].playerstate[entnum-1];
le = &cl.lerpplayers[entnum-1];
switch(fldnum)
{
case GE_ACTIVE:
G_FLOAT(OFS_RETURN) = 1;
break;
case GE_ORIGIN:
/*lerped position*/
VectorCopy(le->origin, G_VECTOR(OFS_RETURN));
break;
case GE_SCALE:
G_FLOAT(OFS_RETURN) = ps->scale / 16.0f;
break;
case GE_ALPHA:
G_FLOAT(OFS_RETURN) = ps->alpha / 255.0f;
break;
case GE_COLORMOD:
G_FLOAT(OFS_RETURN+0) = ps->colourmod[0] / 8.0f;
G_FLOAT(OFS_RETURN+1) = ps->colourmod[1] / 8.0f;
G_FLOAT(OFS_RETURN+2) = ps->colourmod[2] / 8.0f;
break;
case GE_SKIN:
G_FLOAT(OFS_RETURN) = ps->skinnum;
break;
case GE_MINS:
VectorCopy(ps->szmins, G_VECTOR(OFS_RETURN));
break;
case GE_MAXS:
VectorCopy(ps->szmaxs, G_VECTOR(OFS_RETURN));
break;
case GE_ABSMIN:
VectorAdd(ps->szmins, le->origin, G_VECTOR(OFS_RETURN));
break;
case GE_ABSMAX:
VectorAdd(ps->szmaxs, le->origin, G_VECTOR(OFS_RETURN));
break;
case GE_ORIGINANDVECTORS:
VectorCopy(le->origin, G_VECTOR(OFS_RETURN));
AngleVectorsIndex(le->angles, ps->modelindex, csqcg.forward, csqcg.right, csqcg.up);
break;
case GE_FORWARD:
AngleVectorsIndex(le->angles, ps->modelindex, G_VECTOR(OFS_RETURN), NULL, NULL);
break;
case GE_RIGHT:
AngleVectorsIndex(le->angles, ps->modelindex, NULL, G_VECTOR(OFS_RETURN), NULL);
break;
case GE_UP:
AngleVectorsIndex(le->angles, ps->modelindex, NULL, NULL, G_VECTOR(OFS_RETURN));
break;
case GE_PANTSCOLOR:
G_FLOAT(OFS_RETURN) = cl.players[entnum-1].tbottomcolor;
break;
case GE_SHIRTCOLOR:
G_FLOAT(OFS_RETURN) = cl.players[entnum-1].ttopcolor;
break;
case GE_LIGHT:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_MODELINDEX:
G_FLOAT(OFS_RETURN) = ps->modelindex;
break;
case GE_MODELINDEX2:
G_FLOAT(OFS_RETURN) = ps->command.impulse; //evil hack
break;
case GE_EFFECTS:
G_FLOAT(OFS_RETURN) = ps->effects;
break;
case GE_FRAME:
G_FLOAT(OFS_RETURN) = ps->frame;
break;
case GE_ANGLES:
VectorCopy(le->angles, G_VECTOR(OFS_RETURN));
break;
case GE_FATNESS:
G_FLOAT(OFS_RETURN) = ps->fatness;
break;
case GE_DRAWFLAGS:
G_FLOAT(OFS_RETURN) = SCALE_ORIGIN_ORIGIN;
break;
case GE_ABSLIGHT:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_GLOWMOD:
VectorSet(G_VECTOR(OFS_RETURN), 1, 1, 1);
break;
case GE_GLOWSIZE:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_GLOWCOLOUR:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_RTSTYLE:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_RTPFLAGS:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_RTCOLOUR:
VectorSet(G_VECTOR(OFS_RETURN), 1, 1, 1);
break;
case GE_RTRADIUS:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_TAGENTITY:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_TAGINDEX:
G_FLOAT(OFS_RETURN) = 0;
break;
case GE_GRAVITYDIR:
VectorCopy(ps->gravitydir, G_VECTOR(OFS_RETURN));
break;
case GE_TRAILEFFECTNUM:
G_FLOAT(OFS_RETURN) = 0;
break;
default:
VectorCopy(vec3_origin, G_VECTOR(OFS_RETURN));
break;
}
return;
}
if (entnum >= cl.maxlerpents || !cl.lerpentssequence || cl.lerpents[entnum].sequence != cl.lerpentssequence) if (entnum >= cl.maxlerpents || !cl.lerpentssequence || cl.lerpents[entnum].sequence != cl.lerpentssequence)
{ {
if (fldnum != GE_ACTIVE) if (fldnum != GE_ACTIVE)
@ -5061,16 +5219,16 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s *
break; break;
case GE_ORIGINANDVECTORS: case GE_ORIGINANDVECTORS:
VectorCopy(le->origin, G_VECTOR(OFS_RETURN)); VectorCopy(le->origin, G_VECTOR(OFS_RETURN));
AngleVectors(le->angles, csqcg.forward, csqcg.right, csqcg.up); AngleVectorsIndex(le->angles, es->modelindex, csqcg.forward, csqcg.right, csqcg.up);
break; break;
case GE_FORWARD: case GE_FORWARD:
AngleVectors(le->angles, G_VECTOR(OFS_RETURN), NULL, NULL); AngleVectorsIndex(le->angles, es->modelindex, G_VECTOR(OFS_RETURN), NULL, NULL);
break; break;
case GE_RIGHT: case GE_RIGHT:
AngleVectors(le->angles, NULL, G_VECTOR(OFS_RETURN), NULL); AngleVectorsIndex(le->angles, es->modelindex, NULL, G_VECTOR(OFS_RETURN), NULL);
break; break;
case GE_UP: case GE_UP:
AngleVectors(le->angles, NULL, NULL, G_VECTOR(OFS_RETURN)); AngleVectorsIndex(le->angles, es->modelindex, NULL, NULL, G_VECTOR(OFS_RETURN));
break; break;
case GE_PANTSCOLOR: case GE_PANTSCOLOR:
if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED)) if (es->colormap <= cl.allocated_client_slots && !(es->dpflags & RENDER_COLORMAPPED))
@ -5829,7 +5987,7 @@ static struct {
{"R_BeginPolygon", PF_R_PolygonBegin, 306}, // #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???) {"R_BeginPolygon", PF_R_PolygonBegin, 306}, // #306 void(string texturename) R_BeginPolygon (EXT_CSQC_???)
{"R_PolygonVertex", PF_R_PolygonVertex, 307}, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex (EXT_CSQC_???) {"R_PolygonVertex", PF_R_PolygonVertex, 307}, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex (EXT_CSQC_???)
{"R_EndPolygon", PF_R_PolygonEnd, 308}, // #308 void() R_EndPolygon (EXT_CSQC_???) {"R_EndPolygon", PF_R_PolygonEnd, 308}, // #308 void() R_EndPolygon (EXT_CSQC_???)
{"addtrisoup_1", PF_R_AddTrisoup, 0}, {"addtrisoup_simple", PF_R_AddTrisoup_Simple, 0},
{"getproperty", PF_R_GetViewFlag, 309}, // #309 vector/float(float property) getproperty (EXT_CSQC_1) {"getproperty", PF_R_GetViewFlag, 309}, // #309 vector/float(float property) getproperty (EXT_CSQC_1)

View file

@ -693,8 +693,6 @@ void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *p
G_INT(OFS_RETURN) = 0; //assume the worst G_INT(OFS_RETURN) = 0; //assume the worst
#define RT_IMAGEFLAGS IF_NOMIPMAP|IF_CLAMP|IF_LINEAR|IF_RENDERTARGET
if (width < 0 || height < 0 || width > 16384 || height > 16384) if (width < 0 || height < 0 || width > 16384 || height > 16384)
{ //this is actually kinda likely when everyone assumes everything is a float. { //this is actually kinda likely when everyone assumes everything is a float.
PR_BIError(prinst, "PF_CL_uploadimage: dimensions are out of range\n"); PR_BIError(prinst, "PF_CL_uploadimage: dimensions are out of range\n");
@ -892,7 +890,11 @@ void QCBUILTIN PF_CL_drawline (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
"}\n" "}\n"
"}\n"); "}\n");
BE_DrawMesh_Single(shader_draw_line, &mesh, NULL, flags|BEF_LINES); R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
R2D_Line(point1[0], point1[1], point2[0], point2[1], shader_draw_line);
R2D_ImageColours(1,1,1,1);
// BE_DrawMesh_Single(shader_draw_line, &mesh, NULL, flags|BEF_LINES);
} }
//vector drawgetimagesize(string pic) = #460; //vector drawgetimagesize(string pic) = #460;

View file

@ -649,17 +649,28 @@ void R2D_Image2dQuad(vec2_t points[], vec2_t texcoords[], mpic_t *pic)
return; return;
} }
if (draw_active_shader != pic || draw_active_flags != r2d_be_flags || draw_mesh.numvertexes+4 > DRAW_QUADS)
{
if (R2D_Flush) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
for (i = 0; i < 4; i++) draw_active_shader = pic;
{ draw_active_flags = r2d_be_flags;
Vector2Copy(points[i], draw_mesh_xyz[i]); R2D_Flush = R2D_ImageFlush;
Vector2Copy(texcoords[i], draw_mesh_st[i]);
Vector4Copy(draw_active_colour, draw_mesh_colors[i]); draw_mesh.numindexes = 0;
draw_mesh.numvertexes = 0;
} }
BE_DrawMesh_Single(pic, &draw_mesh, NULL, r2d_be_flags); for (i = 0; i < 4; i++)
{
Vector2Copy(points[i], draw_mesh_xyz[draw_mesh.numvertexes+i]);
Vector2Copy(texcoords[i], draw_mesh_st[draw_mesh.numvertexes+i]);
Vector4Copy(draw_active_colour, draw_mesh_colors[draw_mesh.numvertexes+i]);
}
draw_mesh.numvertexes += 4;
draw_mesh.numindexes += 6;
} }
/*draws a block of the current colour on the screen*/ /*draws a block of the current colour on the screen*/
@ -702,13 +713,18 @@ void R2D_FillBlock(float x, float y, float w, float h)
void R2D_Line(float x1, float y1, float x2, float y2, shader_t *shader) void R2D_Line(float x1, float y1, float x2, float y2, shader_t *shader)
{ {
if (R2D_Flush) if (R2D_Flush)
{
R2D_Flush(); R2D_Flush();
R2D_Flush = NULL;
}
VectorSet(draw_mesh_xyz[0], x1, y1, 0); VectorSet(draw_mesh_xyz[0], x1, y1, 0);
Vector2Set(draw_mesh_st[0], 0, 0); Vector2Set(draw_mesh_st[0], 0, 0);
Vector4Copy(draw_active_colour, draw_mesh_colors[0]);
VectorSet(draw_mesh_xyz[1], x2, y2, 0); VectorSet(draw_mesh_xyz[1], x2, y2, 0);
Vector2Set(draw_mesh_st[1], 1, 0); Vector2Set(draw_mesh_st[1], 1, 0);
Vector4Copy(draw_active_colour, draw_mesh_colors[1]);
if (!shader) if (!shader)
{ {

View file

@ -3316,6 +3316,7 @@ void Surf_LightmapMode(void)
lightmap_bgra = true; lightmap_bgra = true;
break; break;
#ifdef D3DQUAKE #ifdef D3DQUAKE
case QR_DIRECT3D8:
case QR_DIRECT3D9: case QR_DIRECT3D9:
case QR_DIRECT3D11: case QR_DIRECT3D11:
/*always bgra, hope your card supports it*/ /*always bgra, hope your card supports it*/
@ -3797,7 +3798,7 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
void Surf_PreNewMap(void) void Surf_PreNewMap(void)
{ {
r_loadbumpmapping = r_deluxemapping || r_glsl_offsetmapping.ival; r_loadbumpmapping = r_deluxmapping || r_glsl_offsetmapping.ival;
#ifdef RTLIGHTS #ifdef RTLIGHTS
r_loadbumpmapping |= r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival; r_loadbumpmapping |= r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival;
#endif #endif

View file

@ -43,7 +43,7 @@ static const texid_t r_nulltex = NULL;
//desktop-gl will generally cope with ints, but expect a performance hit from that with old gpus (so we don't bother) //desktop-gl will generally cope with ints, but expect a performance hit from that with old gpus (so we don't bother)
//vulkan+dx10 can cope with ints, but might be 24bit //vulkan+dx10 can cope with ints, but might be 24bit
//either way, all renderers in the same build need to use the same thing. //either way, all renderers in the same build need to use the same thing.
#if (defined(GLQUAKE) && !defined(NOLEGACY)) || defined(MINIMAL) || defined(D3D9QUAKE) || defined(ANDROID) #if (defined(GLQUAKE) && !defined(NOLEGACY)) || defined(MINIMAL) || defined(D3D8QUAKE) || defined(D3D9QUAKE) || defined(ANDROID)
#define sizeof_index_t 2 #define sizeof_index_t 2
#endif #endif
#if sizeof_index_t == 2 #if sizeof_index_t == 2
@ -438,7 +438,14 @@ void Image_Shutdown(void);
image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags); image_t *Image_LoadTexture (const char *identifier, int width, int height, uploadfmt_t fmt, void *data, unsigned int flags);
#ifdef D3D8QUAKE
void D3D8_Set2D (void);
void D3D8_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis);
qboolean D3D8_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips);
void D3D8_DestroyTexture (texid_t tex);
#endif
#ifdef D3D9QUAKE #ifdef D3D9QUAKE
void D3D9_Set2D (void);
void D3D9_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis); void D3D9_UpdateFiltering (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis);
qboolean D3D9_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips); qboolean D3D9_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips);
void D3D9_DestroyTexture (texid_t tex); void D3D9_DestroyTexture (texid_t tex);
@ -597,8 +604,8 @@ extern cvar_t r_telestyle;
extern cvar_t r_dynamic; extern cvar_t r_dynamic;
extern cvar_t r_novis; extern cvar_t r_novis;
extern cvar_t r_netgraph; extern cvar_t r_netgraph;
extern cvar_t r_deluxemapping_cvar; extern cvar_t r_deluxmapping_cvar;
extern qboolean r_deluxemapping; extern qboolean r_deluxmapping;
extern cvar_t r_softwarebanding_cvar; extern cvar_t r_softwarebanding_cvar;
extern qboolean r_softwarebanding; extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar; extern cvar_t r_lightprepass_cvar;

View file

@ -201,7 +201,7 @@ cvar_t scr_allowsnap = CVARF ("scr_allowsnap", "1",
CVAR_NOTFROMSERVER); CVAR_NOTFROMSERVER);
cvar_t scr_centersbar = CVAR ("scr_centersbar", "2"); cvar_t scr_centersbar = CVAR ("scr_centersbar", "2");
cvar_t scr_centertime = CVAR ("scr_centertime", "2"); cvar_t scr_centertime = CVAR ("scr_centertime", "2");
cvar_t scr_logcenterprint = CVARD ("con_logcenterprint", "1", ""); cvar_t scr_logcenterprint = CVARD ("con_logcenterprint", "1", "Specifies whether to print centerprints on the console.\n0: never\n1: single-player or coop only.\n2: always.\n");
cvar_t scr_chatmodecvar = CVAR ("scr_chatmode", "0"); cvar_t scr_chatmodecvar = CVAR ("scr_chatmode", "0");
cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7", cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7",
Cvar_Limiter_ZeroToOne_Callback); Cvar_Limiter_ZeroToOne_Callback);
@ -314,9 +314,9 @@ cvar_t gl_ati_truform_type = CVAR ("gl_ati_truform_type", "1");
cvar_t r_tessellation_level = CVAR ("r_tessellation_level", "5"); cvar_t r_tessellation_level = CVAR ("r_tessellation_level", "5");
cvar_t gl_blend2d = CVAR ("gl_blend2d", "1"); cvar_t gl_blend2d = CVAR ("gl_blend2d", "1");
cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them"); cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them");
cvar_t r_deluxemapping_cvar = CVARAFD ("r_deluxemapping", "0", "r_glsl_deluxemapping", cvar_t r_deluxmapping_cvar = CVARAFD ("r_deluxmapping", "0", "r_deluxemapping", //fixme: rename to r_glsl_deluxmapping once configs catch up
CVAR_ARCHIVE, "Enables bumpmapping based upon precomputed light directions"); CVAR_ARCHIVE, "Enables bumpmapping based upon precomputed light directions.\n0=off\n1=use if available\n2=auto-generate (if possible)");
qboolean r_deluxemapping; qboolean r_deluxmapping;
cvar_t r_shaderblobs = CVARD ("r_shaderblobs", "0", "If enabled, can massively accelerate vid restarts / loading (especially with the d3d renderer). Can cause issues when upgrading engine versions, so this is disabled by default."); cvar_t r_shaderblobs = CVARD ("r_shaderblobs", "0", "If enabled, can massively accelerate vid restarts / loading (especially with the d3d renderer). Can cause issues when upgrading engine versions, so this is disabled by default.");
cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed."); cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed.");
cvar_t gl_conback = CVARFDC ("gl_conback", "", cvar_t gl_conback = CVARFDC ("gl_conback", "",
@ -476,7 +476,7 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES); Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES);
Cvar_Register (&r_deluxemapping_cvar, GRAPHICALNICETIES); Cvar_Register (&r_deluxmapping_cvar, GRAPHICALNICETIES);
#ifdef R_XFLIP #ifdef R_XFLIP
Cvar_Register (&r_xflip, GLRENDEREROPTIONS); Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
@ -1051,8 +1051,13 @@ extern rendererinfo_t rpirendererinfo;
rendererinfo_t waylandrendererinfo; rendererinfo_t waylandrendererinfo;
rendererinfo_t fbdevrendererinfo; rendererinfo_t fbdevrendererinfo;
#endif #endif
#ifdef D3DQUAKE #ifdef D3D8QUAKE
extern rendererinfo_t d3d8rendererinfo;
#endif
#ifdef D3D9QUAKE
extern rendererinfo_t d3d9rendererinfo; extern rendererinfo_t d3d9rendererinfo;
#endif
#ifdef D3D11QUAKE
extern rendererinfo_t d3d11rendererinfo; extern rendererinfo_t d3d11rendererinfo;
#endif #endif
#ifdef SWQUAKE #ifdef SWQUAKE
@ -1091,6 +1096,9 @@ rendererinfo_t *rendererinfo[] =
#ifdef VKQUAKE #ifdef VKQUAKE
&vkrendererinfo, &vkrendererinfo,
#endif #endif
#ifdef D3D8QUAKE
&d3d8rendererinfo,
#endif
#ifndef NPQTV #ifndef NPQTV
&dedicatedrendererinfo, &dedicatedrendererinfo,
#endif #endif
@ -1347,7 +1355,7 @@ TRACE(("dbg: R_ApplyRenderer: Palette loaded\n"));
TRACE(("dbg: R_ApplyRenderer: vid applied\n")); TRACE(("dbg: R_ApplyRenderer: vid applied\n"));
r_softwarebanding = false; r_softwarebanding = false;
r_deluxemapping = false; r_deluxmapping = false;
r_lightprepass = false; r_lightprepass = false;
W_LoadWadFile("gfx.wad"); W_LoadWadFile("gfx.wad");
@ -1950,6 +1958,7 @@ mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
else if (psprite->frames[frame].type == SPR_ANGLED) else if (psprite->frames[frame].type == SPR_ANGLED)
{ {
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
// pspriteframe = pspritegroup->frames[(int)((r_refdef.viewangles[1]-currententity->angles[1])/360*pspritegroup->numframes + 0.5-4)%pspritegroup->numframes];
pspriteframe = pspritegroup->frames[(int)((r_refdef.viewangles[1]-currententity->angles[1])/360*8 + 0.5-4)&7]; pspriteframe = pspritegroup->frames[(int)((r_refdef.viewangles[1]-currententity->angles[1])/360*8 + 0.5-4)&7];
} }
else else

View file

@ -1038,6 +1038,8 @@ qboolean Sys_remove (char *path)
err = GetLastError(); err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
return true; //succeed when the file already didn't exist return true; //succeed when the file already didn't exist
if (err == ERROR_ACCESS_DENIED)
return false; //windows is shite. this may simply include that its open in another process that didn't include the SHARE_DELETE permission.
return false; //other errors? panic return false; //other errors? panic
} }
else else
@ -3657,6 +3659,14 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
memset(&parms, 0, sizeof(parms)); memset(&parms, 0, sizeof(parms));
/*work around potentially serious windows flaw loading dlls from the current directory, by loading a dll...*/
{
BOOL (WINAPI *pSetDllDirectoryW)(LPCWSTR lpPathName);
dllfunction_t ffsfuncs[] = {{(void*)&pSetDllDirectoryW, "SetDllDirectoryW"}, {NULL,NULL}};
if (Sys_LoadLibrary("kernel32.dll", ffsfuncs))
pSetDllDirectoryW(L""); //disables it (null for 'use working directory')
}
Win7_Init(); Win7_Init();
#ifdef _MSC_VER #ifdef _MSC_VER
@ -3850,6 +3860,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
old = FindWindowW(L"FTED3D11QUAKE", NULL); old = FindWindowW(L"FTED3D11QUAKE", NULL);
if (!old) if (!old)
old = FindWindowW(L"FTED3D9QUAKE", NULL); old = FindWindowW(L"FTED3D9QUAKE", NULL);
if (!old)
old = FindWindowW(L"FTED3D8QUAKE", NULL);
if (old) if (old)
{ {
COPYDATASTRUCT cds; COPYDATASTRUCT cds;

View file

@ -737,7 +737,7 @@ qboolean Con_Editor_Close(console_t *con, qboolean force)
{ {
if (!strncmp(con->title, "MODIFIED: ", 10)) if (!strncmp(con->title, "MODIFIED: ", 10))
{ {
M_Menu_Prompt(Con_Editor_CloseCallback, con, "Save changes?", con->name, "", "Yes", "No", "Cancel"); M_Menu_Prompt(Con_Editor_CloseCallback, con, va("Save changes?\n%s\n", con->name), "Yes", "No", "Cancel");
return false; return false;
} }
} }

View file

@ -35,7 +35,8 @@ typedef enum
QR_SOFTWARE, //not worth using QR_SOFTWARE, //not worth using
QR_VULKAN, // QR_VULKAN, //
QR_DIRECT3D12, //no implementation QR_DIRECT3D12, //no implementation
QR_METAL //no implementation QR_METAL, //no implementation
QR_DIRECT3D8 //
} r_qrenderer_t; } r_qrenderer_t;
typedef struct { typedef struct {

View file

@ -347,7 +347,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#if defined(SWQUAKE) && !defined(_DEBUG) #if defined(SWQUAKE) && !defined(_DEBUG)
#undef SWQUAKE #undef SWQUAKE
#endif #endif
#if (defined(D3D9QUAKE) || defined(D3D11QUAKE)) && !defined(D3DQUAKE) #if (defined(D3D8QUAKE) || defined(D3D9QUAKE) || defined(D3D11QUAKE)) && !defined(D3DQUAKE)
#define D3DQUAKE #define D3DQUAKE
#endif #endif
@ -463,7 +463,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define SQL #define SQL
#endif #endif
#if (defined(AVAIL_GZDEC) && !defined(ZLIB)) || !defined(NPFTE) #if defined(AVAIL_GZDEC) && (!defined(AVAIL_ZLIB) || defined(NPFTE))
//gzip needs zlib to work (pk3s can still contain non-compressed files) //gzip needs zlib to work (pk3s can still contain non-compressed files)
#undef AVAIL_GZDEC #undef AVAIL_GZDEC
#endif #endif

View file

@ -115,7 +115,7 @@ cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "A
cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n"); cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients.\n");
cvar_t sys_platform = CVAR("sys_platform", PLATFORM); cvar_t sys_platform = CVAR("sys_platform", PLATFORM);
cvar_t pm_downloads_url = CVARFD("pm_downloads_url", NULL, CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "The URL of a package updates list."); //read from the default.fmf cvar_t pm_downloads_url = CVARFD("pm_downloads_url", NULL, CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "The URL of a package updates list."); //read from the default.fmf
cvar_t pm_autoupdate = CVARFD("pm_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. cvar_t pm_autoupdate = CVARFD("pm_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only.
qboolean com_modified; // set true if using non-id files qboolean com_modified; // set true if using non-id files
@ -355,6 +355,7 @@ int Q_strncmp (char *s1, char *s2, int count)
#endif #endif
//case comparisons are specific to ascii only, so this should be 'safe' for utf-8 strings too.
int Q_strncasecmp (const char *s1, const char *s2, int n) int Q_strncasecmp (const char *s1, const char *s2, int n)
{ {
int c1, c2; int c1, c2;
@ -2933,32 +2934,33 @@ static char *bidi_chartype;
static unsigned int bidi_charcount; static unsigned int bidi_charcount;
//semi-colon delimited tokens //semi-colon delimited tokens, without whitespace awareness
char *COM_ParseStringSetSep (const char *data, char sep) char *COM_ParseStringSetSep (const char *data, char sep, char *out, size_t outsize)
{ {
int c; int c;
size_t len; size_t len;
if (out == com_token)
COM_AssertMainThread("COM_ParseStringSetSep"); COM_AssertMainThread("COM_ParseStringSetSep");
len = 0; len = 0;
com_token[0] = 0; out[0] = 0;
if (data) if (data)
for (;*data;) for (;*data;)
{ {
if (len >= sizeof(com_token)-1) if (len >= outsize-1)
{ {
com_token[len] = 0; out[len] = 0;
return (char*)data; return (char*)data;
} }
c = *data++; c = *data++;
if (c == ';') if (c == ';')
break; break;
com_token[len++] = c; out[len++] = c;
} }
com_token[len] = 0; out[len] = 0;
return (char*)data; return (char*)data;
} }
void COM_BiDi_Shutdown(void) void COM_BiDi_Shutdown(void)
@ -3004,12 +3006,12 @@ static void COM_BiDi_Setup(void)
if (end) if (end)
*end++ = 0; *end++ = 0;
tok = COM_ParseStringSetSep(line,';'); //number tok = COM_ParseStringSetSep(line,';', com_token, sizeof(com_token)); //number
c = strtoul(com_token, NULL, 16); c = strtoul(com_token, NULL, 16);
tok = COM_ParseStringSetSep(tok,';'); //name tok = COM_ParseStringSetSep(tok,';', com_token, sizeof(com_token)); //name
tok = COM_ParseStringSetSep(tok,';'); //class? tok = COM_ParseStringSetSep(tok,';', com_token, sizeof(com_token)); //class?
tok = COM_ParseStringSetSep(tok,';'); //? tok = COM_ParseStringSetSep(tok,';', com_token, sizeof(com_token)); //?
tok = COM_ParseStringSetSep(tok,';'); //bidi tok = COM_ParseStringSetSep(tok,';', com_token, sizeof(com_token)); //bidi
if (c < bidi_charcount) if (c < bidi_charcount)
{ {
if (!Q_strcasecmp(com_token, "R") || !Q_strcasecmp(com_token, "AL")) if (!Q_strcasecmp(com_token, "R") || !Q_strcasecmp(com_token, "AL"))
@ -5825,7 +5827,7 @@ char *Info_ValueForKey (const char *s, const char *key)
} }
} }
char *Info_KeyForNumber (char *s, int num) char *Info_KeyForNumber (const char *s, int num)
{ {
static char pkey[1024]; static char pkey[1024];
char *o; char *o;
@ -6111,50 +6113,49 @@ void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsi
Info_SetValueForStarKey (s, key, value, maxsize); Info_SetValueForStarKey (s, key, value, maxsize);
} }
void Info_Print (char *s, char *lineprefix) void Info_Enumerate (const char *s, void *ctx, void(*cb)(void *ctx, const char *key, const char *value))
{ {
char key[1024]; char key[1024];
char value[1024]; char value[1024];
char *o; char *o;
int l;
if (*s == '\\') if (*s == '\\')
s++; s++;
while (*s) while (*s)
{ {
o = key; o = key;
while (*s && *s != '\\') while (*s && *s != '\\' && o < key+countof(key)-1)
*o++ = *s++; *o++ = *s++;
l = o - key;
if (l < 20)
{
memset (o, ' ', 20-l);
key[20] = 0;
}
else
*o = 0; *o = 0;
Con_Printf ("%s%s", lineprefix, key);
if (!*s) if (!*s++)
{ {
//should never happen. //should never happen.
Con_Printf ("<no value>\n"); cb(ctx, key, "");
return; return;
} }
o = value; o = value;
s++; while (*s && *s != '\\' && o < value+countof(value)-1)
while (*s && *s != '\\')
*o++ = *s++; *o++ = *s++;
*o = 0; *o = 0;
if (*s) if (*s)
s++; s++;
Con_Printf ("%s\n", value); cb(ctx, key, value);
} }
} }
static void Info_PrintCB (void *ctx, const char *key, const char *value)
{
char *lineprefix = ctx;
Con_Printf ("%s%-20s%s\n", lineprefix, key, value);
}
void Info_Print (const char *s, const char *lineprefix)
{
Info_Enumerate(s, (void*)lineprefix, Info_PrintCB);
}
void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags) void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags)
{ {
const char *quotedvalue; const char *quotedvalue;

View file

@ -335,7 +335,6 @@ void QDECL Q_strncpyz(char*d, const char*s, int n);
#define strncpy Q_strncpy #define strncpy Q_strncpy
#endif*/ #endif*/
/*replacement functions which do not care for locale in text formatting ('C' locale), or are non-standard*/ /*replacement functions which do not care for locale in text formatting ('C' locale), or are non-standard*/
char *Q_strcasestr(const char *haystack, const char *needle); char *Q_strcasestr(const char *haystack, const char *needle);
int Q_strncasecmp (const char *s1, const char *s2, int n); int Q_strncasecmp (const char *s1, const char *s2, int n);
@ -359,7 +358,8 @@ extern qboolean com_eof;
#define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token)) #define COM_Parse(d) COM_ParseOut(d,com_token, sizeof(com_token))
#define COM_ParseOut(d,o,l) COM_ParseType(d,o,l,NULL) #define COM_ParseOut(d,o,l) COM_ParseType(d,o,l,NULL)
char *COM_ParseType (const char *data, char *out, int outlen, com_tokentype_t *toktype); char *COM_ParseType (const char *data, char *out, int outlen, com_tokentype_t *toktype);
char *COM_ParseStringSet (const char *data, char *out, size_t outlen); char *COM_ParseStringSet (const char *data, char *out, size_t outlen); //whitespace or semi-colon separators
char *COM_ParseStringSetSep (const char *data, char sep, char *out, size_t outsize); //single-char-separator, no whitespace
char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *writtenlen); char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *writtenlen);
char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize); char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize);
char *COM_ParseToken (const char *data, const char *punctuation); char *COM_ParseToken (const char *data, const char *punctuation);
@ -688,12 +688,13 @@ unsigned int COM_RemapMapChecksum(unsigned int checksum);
#define MAX_INFO_KEY 256 #define MAX_INFO_KEY 256
char *Info_ValueForKey (const char *s, const char *key); char *Info_ValueForKey (const char *s, const char *key);
void Info_RemoveKey (char *s, const char *key); void Info_RemoveKey (char *s, const char *key);
char *Info_KeyForNumber (char *s, int num); char *Info_KeyForNumber (const char *s, int num);
void Info_RemovePrefixedKeys (char *start, char prefix); void Info_RemovePrefixedKeys (char *start, char prefix);
void Info_RemoveNonStarKeys (char *start); void Info_RemoveNonStarKeys (char *start);
void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize); void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize);
void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize); void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize);
void Info_Print (char *s, char *lineprefix); void Info_Print (const char *s, const char *lineprefix);
void Info_Enumerate (const char *s, void *ctx, void(*cb)(void *ctx, const char *key, const char *value));
void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags); void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags);
void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf); void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf);

View file

@ -196,7 +196,7 @@ extern console_t *con_chat;
//shared between console and keys. //shared between console and keys.
//really the console input should be in console.c instead of keys.c I suppose. //really the console input should be in console.c instead of keys.c I suppose.
#define MAXCMDLINE 8192 #define MAXCMDLINE 8192
#define CON_EDIT_LINES_MASK ((1<<6)-1) #define CON_EDIT_LINES_MASK ((1<<8)-1)
extern unsigned char *key_lines[CON_EDIT_LINES_MASK+1]; extern unsigned char *key_lines[CON_EDIT_LINES_MASK+1];
extern int edit_line; extern int edit_line;
extern int key_linepos; extern int key_linepos;

View file

@ -1878,9 +1878,9 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r
COM_CreatePath(fullname); COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode); vfs = VFSOS_Open(fullname, mode);
} }
if (vfs && !strcmp(mode, "wb")) if (vfs && (*mode == 'w' || *mode == 'a'))
return vfs; return vfs;
//fall through
case FS_PUBGAMEONLY: case FS_PUBGAMEONLY:
if (!FS_NativePath(filename, relativeto, fullname, sizeof(fullname))) if (!FS_NativePath(filename, relativeto, fullname, sizeof(fullname)))
return NULL; return NULL;
@ -2912,7 +2912,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
if (*dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") if (*dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/")
|| strstr(dir, "\\") || strstr(dir, ":") || strstr(dir, "\"") ) || strstr(dir, "\\") || strstr(dir, ":") || strstr(dir, "\"") )
{ {
Con_Printf ("Gamedir should be a single filename, not a path\n"); Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", dir);
return; return;
} }
@ -3105,6 +3105,24 @@ const gamemode_info_t gamemode_info[] = {
{NULL} {NULL}
}; };
void QDECL Q_strnlowercatz(char *d, const char *s, int n)
{
int c = strlen(d);
d += c;
n -= c;
n -= 1; //for the null
while (*s && n-- > 0)
{
if (*s >= 'A' && *s <= 'Z')
*d = (*s-'A') + 'a';
else
*d = *s;
d++;
s++;
}
*d = 0;
}
qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, int llen) qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, int llen)
{ {
const char *fn; const char *fn;
@ -3117,7 +3135,8 @@ qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, in
if (!strncmp(pname, "downloads/", 10)) if (!strncmp(pname, "downloads/", 10))
{ {
Q_snprintfz(local, llen, "%s", pname); *local = 0;
Q_strnlowercatz(local, pname, llen);
return true; return true;
} }
@ -3137,7 +3156,7 @@ qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, in
} }
Q_strncpyz(local, pname, min((fn - pname) + 1, llen)); Q_strncpyz(local, pname, min((fn - pname) + 1, llen));
Q_strncatz(local, "dlcache/", llen); Q_strncatz(local, "dlcache/", llen);
Q_strncatz(local, fn, llen); Q_strnlowercatz(local, fn, llen);
if (crc && *crc) if (crc && *crc)
{ {
Q_strncatz(local, ".", llen); Q_strncatz(local, ".", llen);
@ -3198,6 +3217,7 @@ qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, in
//'small' wrapper to open foo.zip/bar to read files within zips that are not part of the gamedir. //'small' wrapper to open foo.zip/bar to read files within zips that are not part of the gamedir.
//name needs to be null terminated. recursive. pass null for search. //name needs to be null terminated. recursive. pass null for search.
//name is restored to its original state after the call, only technically not const
vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name) vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
{ {
int found; int found;
@ -3208,6 +3228,9 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name)
char *end; char *end;
int i; int i;
//keep chopping off the last part of the filename until we get an actual package
//once we do, recurse into that package
end = name + strlen(name); end = name + strlen(name);
while (end > name) while (end > name)
@ -3412,7 +3435,13 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
if (!*dir || *dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") if (!*dir || *dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/")
|| strstr(dir, "\\") || strstr(dir, ":") ) || strstr(dir, "\\") || strstr(dir, ":") )
{ {
Con_Printf ("Gamedir should be a single filename, not a path\n"); Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", dir);
continue;
}
if (!Q_strncasecmp(dir, "downloads", 9))
{
Con_Printf ("Gamedir should not be \"%s\"\n", dir);
continue; continue;
} }
@ -4296,8 +4325,6 @@ qboolean FS_DownloadingPackage(void)
return !fs_manifest || !!curpackagedownload; return !fs_manifest || !!curpackagedownload;
} }
//vfsfile_t *FS_DecompressXZip(vfsfile_t *infile, vfsfile_t *outfile); //vfsfile_t *FS_DecompressXZip(vfsfile_t *infile, vfsfile_t *outfile);
vfsfile_t *FS_XZ_DecompressWriteFilter(vfsfile_t *infile);
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
static void FS_ExtractPackage(searchpathfuncs_t *archive, flocation_t *loc, const char *origname, const char *finalname) static void FS_ExtractPackage(searchpathfuncs_t *archive, flocation_t *loc, const char *origname, const char *finalname)
{ {
vfsfile_t *in = archive->OpenVFS(archive, loc, "rb"); vfsfile_t *in = archive->OpenVFS(archive, loc, "rb");
@ -4681,7 +4708,7 @@ static qboolean FS_BeginPackageDownload(struct manpack_s *pack, char *baseurl, q
break; break;
case X_GZ: case X_GZ:
#ifdef AVAIL_GZDEC #ifdef AVAIL_GZDEC
tmpf = FS_GZ_DecompressWriteFilter(tmpf, true); tmpf = FS_GZ_WriteFilter(tmpf, true, false);
#else #else
VFS_CLOSE(tmpf); VFS_CLOSE(tmpf);
tmpf = NULL; tmpf = NULL;

View file

@ -68,6 +68,7 @@ void FS_UnRegisterFileSystemModule(void *module);
void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix); void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix);
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri); void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri);
void PM_EnumeratePlugins(void (*callback)(const char *name));
int PM_IsApplying(qboolean listsonly); int PM_IsApplying(qboolean listsonly);
void PM_ManifestPackage(const char *name, int security); void PM_ManifestPackage(const char *name, int security);
qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running
@ -84,3 +85,6 @@ int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man),
#define SPF_WRITABLE 64 //safe to write here. lots of weird rules etc. #define SPF_WRITABLE 64 //safe to write here. lots of weird rules etc.
#define SPF_BASEPATH 128 //part of the basegames, and not the mod gamedir(s). #define SPF_BASEPATH 128 //part of the basegames, and not the mod gamedir(s).
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags); qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags);
vfsfile_t *FS_XZ_DecompressWriteFilter(vfsfile_t *infile);
vfsfile_t *FS_GZ_WriteFilter(vfsfile_t *outfile, qboolean autoclosefile, qboolean compress);

View file

@ -627,9 +627,9 @@ searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc
wchar_t wide[MAX_OSPATH]; wchar_t wide[MAX_OSPATH];
memcpy(np->rootpath, desc, dlen+1); memcpy(np->rootpath, desc, dlen+1);
if (!WinNT) if (!WinNT)
np->changenotification = FindFirstChangeNotificationA(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME); np->changenotification = FindFirstChangeNotificationA(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_CREATION);
else else
np->changenotification = FindFirstChangeNotificationW(widen(wide, sizeof(wide), np->rootpath), true, FILE_NOTIFY_CHANGE_FILE_NAME); np->changenotification = FindFirstChangeNotificationW(widen(wide, sizeof(wide), np->rootpath), true, FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_CREATION);
} }
np->pub.fsver = FSVER; np->pub.fsver = FSVER;

View file

@ -46,11 +46,17 @@ void *zlib_handle;
#define qinflateEnd inflateEnd #define qinflateEnd inflateEnd
#define qinflate inflate #define qinflate inflate
#define qinflateInit2_ inflateInit2_ #define qinflateInit2_ inflateInit2_
#define qdeflateEnd deflateEnd
#define qdeflate deflate
#define qdeflateInit2_ deflateInit2_
#define qget_crc_table get_crc_table #define qget_crc_table get_crc_table
#endif #endif
#define qinflateInit2(strm, windowBits) \ #define qinflateInit2(strm, windowBits) \
qinflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) qinflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
#define qdeflateInit2(strm, level, method, windowBits, memLevel, strategy) \
qdeflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
(strategy), ZLIB_VERSION, sizeof(z_stream))
qboolean LibZ_Init(void) qboolean LibZ_Init(void)
{ {
@ -60,6 +66,9 @@ qboolean LibZ_Init(void)
{(void*)&qinflateEnd, "inflateEnd"}, {(void*)&qinflateEnd, "inflateEnd"},
{(void*)&qinflate, "inflate"}, {(void*)&qinflate, "inflate"},
{(void*)&qinflateInit2_, "inflateInit2_"}, {(void*)&qinflateInit2_, "inflateInit2_"},
{(void*)&qdeflateEnd, "deflateEnd"},
{(void*)&qdeflate, "deflate"},
{(void*)&qdeflateInit2_, "deflateInit2_"},
// {(void*)&qcrc32, "crc32"}, // {(void*)&qcrc32, "crc32"},
#ifdef ZIPCRYPT #ifdef ZIPCRYPT
{(void*)&qget_crc_table, "get_crc_table"}, {(void*)&qget_crc_table, "get_crc_table"},
@ -260,6 +269,7 @@ typedef struct
vfsfile_t vf; vfsfile_t vf;
vfsfile_t *outfile; vfsfile_t *outfile;
qboolean autoclosefile; qboolean autoclosefile;
qboolean compress;
//gzip header handling //gzip header handling
qboolean headerparsed; qboolean headerparsed;
@ -273,9 +283,21 @@ typedef struct
static qboolean QDECL FS_GZ_Dec_Close(vfsfile_t *f) static qboolean QDECL FS_GZ_Dec_Close(vfsfile_t *f)
{ {
vf_gz_dec_t *n = (vf_gz_dec_t*)f; vf_gz_dec_t *n = (vf_gz_dec_t*)f;
if (n->compress)
qdeflate(&n->strm, Z_FINISH);
else
qinflate(&n->strm, Z_FINISH);
if (n->strm.next_out != n->out)
VFS_WRITE(n->outfile, n->out, n->strm.next_out-n->out);
if (n->compress)
qdeflateEnd(&n->strm);
else
qinflateEnd(&n->strm);
if (n->autoclosefile) if (n->autoclosefile)
VFS_CLOSE(n->outfile); VFS_CLOSE(n->outfile);
qinflateEnd(&n->strm);
Z_Free(n); Z_Free(n);
return true; return true;
} }
@ -380,6 +402,9 @@ noheader:
while(n->strm.avail_in) while(n->strm.avail_in)
{ {
if (n->compress)
ret = qdeflate(&n->strm, Z_SYNC_FLUSH);
else
ret = qinflate(&n->strm, Z_SYNC_FLUSH); ret = qinflate(&n->strm, Z_SYNC_FLUSH);
if (!n->strm.avail_out) if (!n->strm.avail_out)
@ -437,12 +462,13 @@ noheader:
return len; return len;
} }
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile) vfsfile_t *FS_GZ_WriteFilter(vfsfile_t *outfile, qboolean autoclosefile, qboolean compress)
{ {
vf_gz_dec_t *n = Z_Malloc(sizeof(*n)); vf_gz_dec_t *n = Z_Malloc(sizeof(*n));
n->outfile = outfile; n->outfile = outfile;
n->autoclosefile = autoclosefile; n->autoclosefile = autoclosefile;
n->compress = compress;
n->strm.next_in = NULL; n->strm.next_in = NULL;
n->strm.avail_in = 0; n->strm.avail_in = 0;
@ -460,6 +486,12 @@ vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefil
n->vf.WriteBytes = FS_GZ_Dec_Write; n->vf.WriteBytes = FS_GZ_Dec_Write;
n->vf.seekingisabadplan = true; n->vf.seekingisabadplan = true;
if (n->compress)
{
n->headerparsed = true; //deflate will write out a minimal header for us, so we can just splurge everything without rewinding.
qdeflateInit2(&n->strm, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS|16, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
}
else
qinflateInit2(&n->strm, -MAX_WBITS); qinflateInit2(&n->strm, -MAX_WBITS);
return &n->vf; return &n->vf;

View file

@ -13,7 +13,7 @@
#ifdef PLUGINS #ifdef PLUGINS
cvar_t plug_sbar = CVARD("plug_sbar", "3", "Controls whether plugins are allowed to draw the hud, rather than the engine (when allowed by csqc). This is typically used to permit the ezhud plugin without needing to bother unloading it.\n=0: never use hud plugins.\n&1: Use hud plugins in deathmatch.\n&2: Use hud plugins in singleplayer/coop.\n=3: Always use hud plugins (when loaded)."); cvar_t plug_sbar = CVARD("plug_sbar", "3", "Controls whether plugins are allowed to draw the hud, rather than the engine (when allowed by csqc). This is typically used to permit the ezhud plugin without needing to bother unloading it.\n=0: never use hud plugins.\n&1: Use hud plugins in deathmatch.\n&2: Use hud plugins in singleplayer/coop.\n=3: Always use hud plugins (when loaded).");
cvar_t plug_loaddefault = CVAR("plug_loaddefault", "1"); cvar_t plug_loaddefault = CVARD("plug_loaddefault", "1", "0: Load plugins only via explicit plug_load commands\n1: Load built-in plugins and those selected via the package manager\n2: Scan for misc plugins, loading all that can be found, but not built-ins.\n3: Scan for plugins, and then load any built-ins");
qintptr_t Plug_Bullet_Init(qintptr_t *args); qintptr_t Plug_Bullet_Init(qintptr_t *args);
qintptr_t Plug_ODE_Init(qintptr_t *args); qintptr_t Plug_ODE_Init(qintptr_t *args);
@ -248,20 +248,48 @@ static qintptr_t EXPORT_FN Plug_SystemCallsNative(qintptr_t arg, ...)
} }
qintptr_t (QDECL *plugin_syscall)( qintptr_t arg, ... ) = Plug_SystemCallsNative; qintptr_t (QDECL *plugin_syscall)( qintptr_t arg, ... ) = Plug_SystemCallsNative;
static char *Plug_CleanName(const char *file, char *out, size_t sizeof_out)
{
size_t len;
//"fteplug_ezhud_x86.REV.dll" gets converted into "ezhud"
//skip fteplug_
if (!Q_strncasecmp(file, "fteplug_", 8))
file += 8;
//strip .REV.dll
COM_StripAllExtensions(file, out, sizeof_out);
//strip _x86
len = strlen(out);
if (len > strlen("_"ARCH_CPU_POSTFIX) && !Q_strncasecmp(out+len-strlen("_"ARCH_CPU_POSTFIX), "_"ARCH_CPU_POSTFIX, strlen("_"ARCH_CPU_POSTFIX)))
{
len -= strlen("_"ARCH_CPU_POSTFIX);
out[len] = 0;
}
return out;
}
plugin_t *Plug_Load(const char *file, int type) plugin_t *Plug_Load(const char *file, int type)
{ {
char temp[MAX_OSPATH];
plugin_t *newplug; plugin_t *newplug;
Plug_CleanName(file, temp, sizeof(temp));
for (newplug = plugs; newplug; newplug = newplug->next) for (newplug = plugs; newplug; newplug = newplug->next)
{ {
if (!Q_strcasecmp(newplug->name, file)) if (!Q_strcasecmp(newplug->name, temp))
return newplug; return newplug;
} }
newplug = Z_Malloc(sizeof(plugin_t)+strlen(file)+1); newplug = Z_Malloc(sizeof(plugin_t)+strlen(temp)+1);
newplug->name = (char*)(newplug+1); newplug->name = (char*)(newplug+1);
strcpy(newplug->name, file); strcpy(newplug->name, temp);
if (!newplug->vm && (type & PLUG_NATIVE) && !Q_strncasecmp(file, "fteplug_", 8) && !Q_strcasecmp(ARCH_DL_POSTFIX+1, COM_FileExtension(file, temp, sizeof(temp))))
{
COM_StripExtension(file, temp, sizeof(temp));
newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL);
}
if (!newplug->vm && (type & PLUG_NATIVE)) if (!newplug->vm && (type & PLUG_NATIVE))
newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL); newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL);
if (!newplug->vm && (type & PLUG_NATIVE)) if (!newplug->vm && (type & PLUG_NATIVE))
@ -1529,6 +1557,11 @@ void VM_Test_f(void)
} }
}*/ }*/
static void Plug_LoadDownloaded(const char *fname)
{
Plug_Load(fname, PLUG_NATIVE);
}
void Plug_Initialise(qboolean fromgamedir) void Plug_Initialise(qboolean fromgamedir)
{ {
char nat[MAX_OSPATH]; char nat[MAX_OSPATH];
@ -1536,10 +1569,6 @@ void Plug_Initialise(qboolean fromgamedir)
if (!numplugbuiltins) if (!numplugbuiltins)
{ {
Cvar_Register(&plug_sbar, "plugins"); Cvar_Register(&plug_sbar, "plugins");
#ifdef SUBSERVERS
if (!SSV_IsSubServer())
#endif
Cvar_Register(&plug_loaddefault, "plugins"); Cvar_Register(&plug_loaddefault, "plugins");
Cmd_AddCommand("plug_closeall", Plug_CloseAll_f); Cmd_AddCommand("plug_closeall", Plug_CloseAll_f);
@ -1620,9 +1649,11 @@ void Plug_Initialise(qboolean fromgamedir)
Plug_Client_Init(); Plug_Client_Init();
} }
if (plug_loaddefault.value) #ifdef SUBSERVERS
if (!SSV_IsSubServer()) //subservers will need plug_load I guess
#endif
if (plug_loaddefault.ival & 2)
{ {
unsigned int u;
if (!fromgamedir) if (!fromgamedir)
{ {
FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)); FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat));
@ -1633,6 +1664,11 @@ void Plug_Initialise(qboolean fromgamedir)
{ {
COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm"); COM_EnumerateFiles("plugins/*.qvm", Plug_Emumerated, ".qvm");
} }
}
if (plug_loaddefault.ival & 1)
{
unsigned int u;
PM_EnumeratePlugins(Plug_LoadDownloaded);
for (u = 0; staticplugins[u].name; u++) for (u = 0; staticplugins[u].name; u++)
{ {
Plug_Load(staticplugins[u].name, PLUG_NATIVE); Plug_Load(staticplugins[u].name, PLUG_NATIVE);
@ -2040,12 +2076,15 @@ void Plug_Close_f(void)
{ {
plugin_t *plug; plugin_t *plug;
char *name = Cmd_Argv(1); char *name = Cmd_Argv(1);
char cleaned[MAX_OSPATH];
if (Cmd_Argc()<2) if (Cmd_Argc()<2)
{ {
Con_Printf("Close which plugin?\n"); Con_Printf("Close which plugin?\n");
return; return;
} }
name = Plug_CleanName(name, cleaned, sizeof(cleaned));
if (currentplug) if (currentplug)
Sys_Error("Plug_CloseAll_f called inside a plugin!\n"); Sys_Error("Plug_CloseAll_f called inside a plugin!\n");

View file

@ -104,6 +104,11 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_arch, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
// run through the search paths // run through the search paths
iterator = NULL; iterator = NULL;
while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath))) while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath)))

View file

@ -671,7 +671,7 @@ void D3D9BE_Init(void)
R_InitFlashblends(); R_InitFlashblends();
} }
void D3DBE_Set2D(void) void D3D9BE_Set2D(void)
{ //start of some 2d rendering code. { //start of some 2d rendering code.
r_refdef.time = realtime; r_refdef.time = realtime;
shaderstate.curtime = r_refdef.time; shaderstate.curtime = r_refdef.time;

View file

@ -898,7 +898,7 @@ void D3D9_Set2D (void)
r_refdef.pxrect.width = vid.fbpwidth; r_refdef.pxrect.width = vid.fbpwidth;
r_refdef.pxrect.height = vid.fbpheight; r_refdef.pxrect.height = vid.fbpheight;
D3DBE_Set2D(); D3D9BE_Set2D();
} }
static int d3d9error(int i) static int d3d9error(int i)

View file

@ -1386,7 +1386,6 @@ void GenerateFogTexture(texid_t *tex, float density, float zscale)
void GLBE_DestroyFBOs(void) void GLBE_DestroyFBOs(void)
{ {
size_t i; size_t i;
GLBE_FBO_Destroy(&shaderstate.fbo_2dfbo);
GLBE_FBO_Destroy(&shaderstate.fbo_lprepass); GLBE_FBO_Destroy(&shaderstate.fbo_lprepass);
for (i = 0; i < R_MAX_RECURSE; i++) for (i = 0; i < R_MAX_RECURSE; i++)
@ -1430,6 +1429,7 @@ void GLBE_DestroyFBOs(void)
void GLBE_Shutdown(void) void GLBE_Shutdown(void)
{ {
GLBE_FBO_Destroy(&shaderstate.fbo_2dfbo);
GLBE_DestroyFBOs(); GLBE_DestroyFBOs();
BZ_Free(shaderstate.wbatches); BZ_Free(shaderstate.wbatches);

View file

@ -60,7 +60,7 @@ Draw_Init
void GLDraw_Init (void) void GLDraw_Init (void)
{ {
//figure out which extra features we can support on these drivers. //figure out which extra features we can support on these drivers.
r_deluxemapping = r_deluxemapping_cvar.ival; r_deluxmapping = r_deluxmapping_cvar.ival;
r_lightprepass = r_lightprepass_cvar.ival && sh_config.progs_supported; r_lightprepass = r_lightprepass_cvar.ival && sh_config.progs_supported;
r_softwarebanding = r_softwarebanding_cvar.ival && sh_config.progs_supported; r_softwarebanding = r_softwarebanding_cvar.ival && sh_config.progs_supported;
if (gl_config.gles && gl_config.glversion < 3.0) if (gl_config.gles && gl_config.glversion < 3.0)

View file

@ -292,7 +292,7 @@ static int dehex_e(int i, qboolean *error)
*error = true; *error = true;
return 0; return 0;
} }
static qboolean Terr_IsSectionFName(heightmap_t *hm, char *fname, int *sx, int *sy) static qboolean Terr_IsSectionFName(heightmap_t *hm, const char *fname, int *sx, int *sy)
{ {
int l; int l;
qboolean error = false; qboolean error = false;
@ -1873,7 +1873,7 @@ int Heightmap_Save(heightmap_t *hm)
#ifndef CLIENTONLY #ifndef CLIENTONLY
//on servers, we can get requests to download current map sections. if so, give them it. //on servers, we can get requests to download current map sections. if so, give them it.
qboolean Terrain_LocateSection(char *name, flocation_t *loc) qboolean Terrain_LocateSection(const char *name, flocation_t *loc)
{ {
heightmap_t *hm; heightmap_t *hm;
hmsection_t *s; hmsection_t *s;
@ -1881,7 +1881,7 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc)
char fname[MAX_QPATH]; char fname[MAX_QPATH];
//reject if its not in maps //reject if its not in maps
if (strncmp(name, "maps/", 5)) if (Q_strncasecmp(name, "maps/", 5))
return false; return false;
if (!sv.world.worldmodel) if (!sv.world.worldmodel)

View file

@ -1755,7 +1755,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
samples = ql2->lmsize; samples = ql2->lmsize;
litdata = shifts+ql2->numsurfs; litdata = shifts+ql2->numsurfs;
if (r_deluxemapping) if (r_deluxmapping)
luxdata = litdata+samples*3; luxdata = litdata+samples*3;
} }
} }
@ -1817,7 +1817,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
} }
if (!luxdata && r_loadlits.ival && r_deluxemapping) if (!luxdata && r_loadlits.ival && r_deluxmapping)
{ //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous. { //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous.
char luxname[MAX_QPATH]; char luxname[MAX_QPATH];
size_t luxsz = 0; size_t luxsz = 0;
@ -1882,14 +1882,14 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
#endif #endif
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxemapping))) if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxmapping)))
{ {
writelitfile = !litdata; writelitfile = !litdata;
numlightdata = l->filelen; numlightdata = l->filelen;
lightmodel = loadmodel; lightmodel = loadmodel;
relitsurface = 0; relitsurface = 0;
} }
else if (!lightmodel && r_loadlits.value && r_deluxemapping && !luxdata && !(r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value<=0)) else if (!lightmodel && r_deluxmapping_cvar.value>1 && r_deluxmapping && !luxdata && !(r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value<=0))
{ //if deluxemapping is on, generate missing lux files a little more often, but don't bother if we have rtlights on anyway. { //if deluxemapping is on, generate missing lux files a little more often, but don't bother if we have rtlights on anyway.
writelitfile = false; writelitfile = false;
numlightdata = l->filelen; numlightdata = l->filelen;
@ -1915,7 +1915,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
} }
} }
/*if we're relighting, make sure there's the proper lux data to be updated*/ /*if we're relighting, make sure there's the proper lux data to be updated*/
if (lightmodel == loadmodel && r_deluxemapping && !luxdata) if (lightmodel == loadmodel && r_deluxmapping && !luxdata)
{ {
int i; int i;
luxdata = ZG_Malloc(&loadmodel->memgroup, samples*3); luxdata = ZG_Malloc(&loadmodel->memgroup, samples*3);

View file

@ -1023,7 +1023,7 @@ void Terr_FreeModel(model_t *mod);
void Terr_FinishTerrain(model_t *model); void Terr_FinishTerrain(model_t *model);
void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable); void Terr_PurgeTerrainModel(model_t *hm, qboolean lightmapsonly, qboolean lightmapreusable);
void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force); //call this after loading a bsp
qboolean Terrain_LocateSection(char *name, flocation_t *loc); //used on servers to generate sections for download. qboolean Terrain_LocateSection(const char *name, flocation_t *loc); //used on servers to generate sections for download.
qboolean Heightmap_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace); qboolean Heightmap_Trace(model_t *model, int forcehullnum, framestate_t *framestate, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int contentmask, struct trace_s *trace);
unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org); unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org);
struct fragmentdecal_s; struct fragmentdecal_s;

View file

@ -929,6 +929,8 @@ qboolean R_ImportRTLights(const char *entlump)
lightscale = 1; lightscale = 1;
if (fadescale <= 0) if (fadescale <= 0)
fadescale = 1; fadescale = 1;
if (color[0] >= 16 || color[1] >= 16 || color[2] >= 16) //_color 255 255 255 should be identity, not super-oversaturated.
VectorScale(color, 1/255.0, color); //if only there were standards for this sort of thing.
if (color[0] == color[1] && color[0] == color[2]) if (color[0] == color[1] && color[0] == color[2])
{ {
color[0] *= overridecolor[0]; color[0] *= overridecolor[0];

View file

@ -299,7 +299,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
else if (!Q_stricmp(token, "lightmap")) else if (!Q_stricmp(token, "lightmap"))
conditiontrue = conditiontrue == !r_fullbright.value; conditiontrue = conditiontrue == !r_fullbright.value;
else if (!Q_stricmp(token, "deluxmap")) else if (!Q_stricmp(token, "deluxmap"))
conditiontrue = conditiontrue == r_deluxemapping; conditiontrue = conditiontrue == r_deluxmapping;
else if (!Q_stricmp(token, "softwarebanding")) else if (!Q_stricmp(token, "softwarebanding"))
conditiontrue = conditiontrue == r_softwarebanding; conditiontrue = conditiontrue == r_softwarebanding;
@ -311,6 +311,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
conditiontrue = conditiontrue == (qrenderer == QR_VULKAN); conditiontrue = conditiontrue == (qrenderer == QR_VULKAN);
else if (!Q_stricmp(token, "opengl")) else if (!Q_stricmp(token, "opengl"))
conditiontrue = conditiontrue == (qrenderer == QR_OPENGL); conditiontrue = conditiontrue == (qrenderer == QR_OPENGL);
else if (!Q_stricmp(token, "d3d8"))
conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D8);
else if (!Q_stricmp(token, "d3d9")) else if (!Q_stricmp(token, "d3d9"))
conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D9); conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D9);
else if (!Q_stricmp(token, "d3d11")) else if (!Q_stricmp(token, "d3d11"))
@ -1354,6 +1356,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
cantess = true; cantess = true;
else if (strncmp("SPECULAR", script, end - script)) else if (strncmp("SPECULAR", script, end - script))
if (strncmp("DELUXE", script, end - script)) if (strncmp("DELUXE", script, end - script))
if (strncmp("DELUX", script, end - script))
if (strncmp("OFFSETMAPPING", script, end - script)) if (strncmp("OFFSETMAPPING", script, end - script))
if (strncmp("RELIEFMAPPING", script, end - script)) if (strncmp("RELIEFMAPPING", script, end - script))
Con_DPrintf("Unknown pemutation in glsl program %s\n", name); Con_DPrintf("Unknown pemutation in glsl program %s\n", name);
@ -1585,7 +1588,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
permutationdefines[pn++] = "#define RELIEFMAPPING\n"; permutationdefines[pn++] = "#define RELIEFMAPPING\n";
} }
if (r_deluxemapping) //fixme: should be per-model really if (r_deluxmapping) //fixme: should be per-model really
permutationdefines[pn++] = "#define DELUXE\n"; permutationdefines[pn++] = "#define DELUXE\n";
} }
permutationdefines[pn++] = NULL; permutationdefines[pn++] = NULL;

View file

@ -46,8 +46,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define APIENTRY #define APIENTRY
#endif #endif
void D3D9_Set2D (void);
void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs);
qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2); qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2);
void ClearBounds (vec3_t mins, vec3_t maxs); void ClearBounds (vec3_t mins, vec3_t maxs);

View file

@ -787,6 +787,31 @@ void GLBE_FBO_Pop(int oldfbo);
void GLBE_FBO_Destroy(fbostate_t *state); void GLBE_FBO_Destroy(fbostate_t *state);
int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, int colourbuffers, texid_t destdepth, int width, int height, int layer); int GLBE_FBO_Update(fbostate_t *state, unsigned int enables, texid_t *destcol, int colourbuffers, texid_t destdepth, int width, int height, int layer);
#endif #endif
#ifdef D3D8QUAKE
void D3D8BE_Init(void);
void D3D8BE_Shutdown(void);
void D3D8BE_SelectMode(backendmode_t mode);
void D3D8BE_DrawMesh_List(shader_t *shader, int nummeshes, mesh_t **mesh, vbo_t *vbo, texnums_t *texnums, unsigned int beflags);
void D3D8BE_DrawMesh_Single(shader_t *shader, mesh_t *meshchain, vbo_t *vbo, unsigned int beflags);
void D3D8BE_SubmitBatch(batch_t *batch);
batch_t *D3D8BE_GetTempBatch(void);
void D3D8BE_GenBrushModelVBO(model_t *mod);
void D3D8BE_ClearVBO(vbo_t *vbo);
void D3D8BE_UploadAllLightmaps(void);
void D3D8BE_DrawWorld (batch_t **worldbatches);
qboolean D3D8BE_LightCullModel(vec3_t org, model_t *model);
void D3D8BE_SelectEntity(entity_t *ent);
qboolean D3D8BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);
void D3D8BE_VBO_Begin(vbobctx_t *ctx, size_t maxsize);
void D3D8BE_VBO_Data(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray);
void D3D8BE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray, void **vbomem, void **ebomem);
void D3D8BE_VBO_Destroy(vboarray_t *vearray, void *mem);
void D3D8BE_Scissor(srect_t *rect);
void D3D8Shader_Init(void);
void D3D8BE_Reset(qboolean before);
void D3D8BE_Set2D(void);
#endif
#ifdef D3D9QUAKE #ifdef D3D9QUAKE
void D3D9BE_Init(void); void D3D9BE_Init(void);
void D3D9BE_Shutdown(void); void D3D9BE_Shutdown(void);
@ -810,7 +835,7 @@ void D3D9BE_Scissor(srect_t *rect);
void D3D9Shader_Init(void); void D3D9Shader_Init(void);
void D3D9BE_Reset(qboolean before); void D3D9BE_Reset(qboolean before);
void D3DBE_Set2D(void); void D3D9BE_Set2D(void);
#endif #endif
#ifdef D3D11QUAKE #ifdef D3D11QUAKE
void D3D11BE_Init(void); void D3D11BE_Init(void);

View file

@ -5,8 +5,6 @@
#include "netinc.h" #include "netinc.h"
#include "fs.h" #include "fs.h"
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
#if defined(WEBCLIENT) #if defined(WEBCLIENT)
#ifndef NPFTE #ifndef NPFTE
static struct dl_download *activedownloads; static struct dl_download *activedownloads;
@ -794,7 +792,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
if (con->gzip) if (con->gzip)
{ {
#ifdef AVAIL_GZDEC #ifdef AVAIL_GZDEC
con->file = FS_GZ_DecompressWriteFilter(dl->file, false); con->file = FS_GZ_WriteFilter(dl->file, false, false);
#else #else
Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname); Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname);
dl->status = DL_FAILED; dl->status = DL_FAILED;
@ -925,7 +923,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
dl->status = DL_FAILED; dl->status = DL_FAILED;
else else
{ {
#if AVAIL_GZDEC #ifdef AVAIL_GZDEC
if (con->gzip && con->file) if (con->gzip && con->file)
{ {
VFS_CLOSE(con->file); VFS_CLOSE(con->file);

View file

@ -452,6 +452,7 @@ stringtab_t *stringtablist[256];
int QCC_CopyString (char *str) int QCC_CopyString (char *str)
{ {
int old; int old;
size_t len;
if (!str) if (!str)
return 0; return 0;
@ -492,8 +493,11 @@ int QCC_CopyString (char *str)
} }
old = strofs; old = strofs;
strcpy (strings+strofs, str); len = strlen(str)+1;
strofs += strlen(str)+1; if (strofs + len > MAX_STRINGS)
QCC_Error(ERR_INTERNAL, "QCC_CopyString: stringtable size limit exceeded\n");
memcpy (strings+strofs, str, len);
strofs += len;
return old; return old;
} }
@ -507,6 +511,8 @@ int QCC_CopyStringLength (char *str, size_t length)
return !flag_nullemptystr; return !flag_nullemptystr;
old = strofs; old = strofs;
if (strofs + length > MAX_STRINGS)
QCC_Error(ERR_INTERNAL, "QCC_CopyString: stringtable size limit exceeded\n");
memcpy (strings+strofs, str, length); memcpy (strings+strofs, str, length);
strofs += length; strofs += length;
return old; return old;
@ -514,6 +520,7 @@ int QCC_CopyStringLength (char *str, size_t length)
int QCC_CopyDupBackString (char *str) int QCC_CopyDupBackString (char *str)
{ {
size_t length;
int old; int old;
char *s; char *s;
@ -522,8 +529,11 @@ int QCC_CopyDupBackString (char *str)
return s-strings; return s-strings;
old = strofs; old = strofs;
length = strlen(str)+1;
if (strofs + length > MAX_STRINGS)
QCC_Error(ERR_INTERNAL, "QCC_CopyString: stringtable size limit exceeded\n");
strcpy (strings+strofs, str); strcpy (strings+strofs, str);
strofs += strlen(str)+1; strofs += length;
return old; return old;
} }
@ -1232,6 +1242,7 @@ pbool QCC_WriteData (int crc)
int *statement_linenums; int *statement_linenums;
void *funcdata; void *funcdata;
size_t funcdatasize; size_t funcdatasize;
pbool bigjumps;
extern char *basictypenames[]; extern char *basictypenames[];
@ -1270,6 +1281,17 @@ pbool QCC_WriteData (int crc)
QCC_UnmarshalLocals(); QCC_UnmarshalLocals();
QCC_FinaliseTemps(); QCC_FinaliseTemps();
for (i=0 ; i<numstatements ; i++)
{
if (!statements[i].a.sym && (statements[i].a.ofs > 0x7fff || statements[i].a.ofs < 0x7fff))
break;
if (!statements[i].a.sym && (statements[i].a.ofs > 0x7fff || statements[i].a.ofs < 0x7fff))
break;
if (!statements[i].a.sym && (statements[i].a.ofs > 0x7fff || statements[i].a.ofs < 0x7fff))
break;
}
bigjumps = i<numstatements;
switch (qcc_targetformat) switch (qcc_targetformat)
{ {
case QCF_HEXEN2: case QCF_HEXEN2:
@ -1277,7 +1299,12 @@ pbool QCC_WriteData (int crc)
if (bodylessfuncs) if (bodylessfuncs)
printf("Warning: There are some functions without bodies.\n"); printf("Warning: There are some functions without bodies.\n");
if (numpr_globals > 65530 ) if (bigjumps)
{
printf("Forcing target to FTE32 due to large functions\n");
outputsttype = PST_FTE32;
}
else if (numpr_globals > 65530)
{ {
printf("Forcing target to FTE32 due to numpr_globals\n"); printf("Forcing target to FTE32 due to numpr_globals\n");
outputsttype = PST_FTE32; outputsttype = PST_FTE32;
@ -1309,11 +1336,19 @@ pbool QCC_WriteData (int crc)
if (qcc_targetformat == QCF_FTEDEBUG) if (qcc_targetformat == QCF_FTEDEBUG)
debugtarget = true; debugtarget = true;
if (numpr_globals > 65530) if (outputsttype != PST_FTE32)
{
if (bigjumps)
{
printf("Using 32 bit target due to large functions\n");
outputsttype = PST_FTE32;
}
else if (numpr_globals > 65530)
{ {
printf("Using 32 bit target due to numpr_globals\n"); printf("Using 32 bit target due to numpr_globals\n");
outputsttype = PST_FTE32; outputsttype = PST_FTE32;
} }
}
if (qcc_targetformat == QCF_DARKPLACES) if (qcc_targetformat == QCF_DARKPLACES)
compressoutput = 0; compressoutput = 0;

View file

@ -9007,29 +9007,7 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v
SV_ExtractFromUserinfo (&svs.clients[entnum-1], false); SV_ExtractFromUserinfo (&svs.clients[entnum-1], false);
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); value = Info_ValueForKey(svs.clients[entnum-1].userinfo, key);
MSG_WriteByte (&sv.reliable_datagram, entnum-1);
MSG_WriteString (&sv.reliable_datagram, key);
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key));
#ifdef NQPROT
if (!strcmp(key, "name"))
{
MSG_WriteByte(&sv.nqreliable_datagram, svc_updatename);
MSG_WriteByte(&sv.nqreliable_datagram, entnum-1);
MSG_WriteString (&sv.nqreliable_datagram, Info_ValueForKey(svs.clients[entnum-1].userinfo, key));
}
else if (!strcmp(key, "topcolor") || !strcmp(key, "bottomcolor"))
{
int c;
//this sucks, but whatever.
c = (atoi(Info_ValueForKey(svs.clients[entnum-1].userinfo, "topcolor" )) & 0xf)<<4;
c|= (atoi(Info_ValueForKey(svs.clients[entnum-1].userinfo, "bottomcolor")) & 0xf);
MSG_WriteByte(&sv.nqreliable_datagram, svc_updatecolors);
MSG_WriteByte(&sv.nqreliable_datagram, entnum-1);
MSG_WriteByte (&sv.nqreliable_datagram, c);
}
#endif
if (!strcmp(key, "*spectator")) if (!strcmp(key, "*spectator"))
{ {
@ -9050,10 +9028,8 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v
else else
svs.clients[entnum-1].spectator = ns; svs.clients[entnum-1].spectator = ns;
} }
#ifdef _DEBUG
if (!strcmp(key, "*transfer")) SV_BroadcastUserinfoChange(host_client, SV_UserInfoIsBasic(key), key, value);
Con_Printf("WARNING: *transfer is no longer supported\n");
#endif
} }
return 1; return 1;
@ -9063,7 +9039,7 @@ int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *v
return 0; return 0;
} }
void QCBUILTIN PF_ForceInfoKey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_ForceInfoKey(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
edict_t *e; edict_t *e;
const char *value; const char *value;
@ -10044,15 +10020,15 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//we support them for mvdsv compatability but some of them look very hacky. //we support them for mvdsv compatability but some of them look very hacky.
//these ones are not honoured with numbers, but can be used via the proper means. //these ones are not honoured with numbers, but can be used via the proper means.
{"teamfield", PF_teamfield, 0, 0, 0, 87, D("void(.string teamfield)",NULL), true}, {"teamfield", PF_teamfield, 0, 0, 0, 87, D("void(.string teamfield)",NULL), true},
{"substr", PF_substr, 0, 0, 0, 88, D("string(string str, float start, float len)",NULL), true}, {"substr", PF_substr, 0, 0, 0, 88, D("string(string str, float start, float len)","Returns the theDoes not work on tempstrings nor zoned strings."), true},
{"mvdstrcat", PF_strcat, 0, 0, 0, 89, D("string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, {"mvdstrcat", PF_strcat, 0, 0, 0, 89, D("string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true},
{"mvdstrlen", PF_strlen, 0, 0, 0, 90, D("float(string s)",NULL), true}, {"mvdstrlen", PF_strlen, 0, 0, 0, 90, D("float(string s)",NULL), true},
{"str2byte", PF_str2byte, 0, 0, 0, 91, D("float(string str)",NULL), true}, {"str2byte", PF_str2byte, 0, 0, 0, 91, D("float(string str)","Returns the value of the first byte of the given string."), true},
{"str2short", PF_str2short, 0, 0, 0, 92, D("float(string str)",NULL), true}, {"str2short", PF_str2short, 0, 0, 0, 92, D("float(string str)","Returns the value of the first two bytes of the given string, treated as a short."), true},
{"mvdnewstr", PF_mvdsv_newstring, 0, 0, 0, 93, D("string(string s, optional float bufsize)",NULL), true}, {"mvdnewstr", PF_mvdsv_newstring, 0, 0, 0, 93, D("string(string s, optional float bufsize)","Allocs a copy of the string. If bufsize is longer than the string then there will be extra space available on the end. The resulting string can then be modified freely."), true},
{"mvdfreestr", PF_mvdsv_freestring,0, 0, 0, 94, D("void(string s)",NULL), true}, {"mvdfreestr", PF_mvdsv_freestring,0, 0, 0, 94, D("void(string s)","Frees memory allocated by mvdnewstr."), true},
{"conprint", PF_conprint, 0, 0, 0, 95, D("void(string s, ...)",NULL), true}, {"conprint", PF_conprint, 0, 0, 0, 95, D("void(string s, ...)","Prints the string(s) onto the local console, bypassing redirects."), true},
{"readcmd", PF_readcmd, 0, 0, 0, 96, D("string(string str)",NULL), true}, {"readcmd", PF_readcmd, 0, 0, 0, 0/*96*/, D("string(string str)",NULL), true},
{"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("void(string dst, string src)",NULL), true}, {"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("void(string dst, string src)",NULL), true},
{"strstr", PF_strstr, 0, 0, 0, 98, D("string(string str, string sub)",NULL), true}, {"strstr", PF_strstr, 0, 0, 0, 98, D("string(string str, string sub)",NULL), true},
{"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("void(string dst, string src, float count)",NULL), true}, {"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("void(string dst, string src, float count)",NULL), true},
@ -10342,7 +10318,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC) {"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC)
{"addentities", PF_Fixme, 0, 0, 0, 301, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC) {"addentities", PF_Fixme, 0, 0, 0, 301, D("void(float mask)", "Walks through all entities effectively doing this:\n if (ent.drawmask&mask){ if (!ent.predaw()) addentity(ent); }\nIf mask&MASK_DELTA, non-csqc entities, particles, and related effects will also be added to the rentity list.\n If mask&MASK_STDVIEWMODEL then the default view model will also be added.")},// (EXT_CSQC)
{"addentity", PF_Fixme, 0, 0, 0, 302, D("void(entity ent)", "Copies the entity fields into a new rentity for later rendering via addscene.")},// (EXT_CSQC) {"addentity", PF_Fixme, 0, 0, 0, 302, D("void(entity ent)", "Copies the entity fields into a new rentity for later rendering via addscene.")},// (EXT_CSQC)
{"addtrisoup_1", PF_Fixme, 0, 0, 0, 0, D("void(string texturename, float flags, void *verts, int *indexes, int numindexes)", "Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame.")}, {"addtrisoup_simple",PF_Fixme, 0, 0, 0, 0, D("typedef float vec2[2];\ntypedef float vec3[3];\ntypedef float vec4[4];\ntypedef struct trisoup_simple_vert_s {vec3 xyz;vec2 st;vec4 rgba;} trisoup_simple_vert_t;\nvoid(string texturename, int flags, struct trisoup_simple_vert_s *verts, int *indexes, int numindexes)", "Adds the specified trisoup into the scene as additional geometry. This permits caching geometry to reduce builtin spam. Indexes are a triangle list (so eg quads will need 6 indicies to form two triangles). NOTE: this is not going to be a speedup over polygons if you're still generating lots of new data every frame.")},
{"setproperty", PF_Fixme, 0, 0, 0, 303, D("#define setviewprop setproperty\nfloat(float property, ...)", "Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats.")},// (EXT_CSQC) {"setproperty", PF_Fixme, 0, 0, 0, 303, D("#define setviewprop setproperty\nfloat(float property, ...)", "Allows you to override default view properties like viewport, fov, and whether the engine hud will be drawn. Different VF_ values have slightly different arguments, some are vectors, some floats.")},// (EXT_CSQC)
{"renderscene", PF_Fixme, 0, 0, 0, 304, D("void()", "Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy.\nThe scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame.\nYou may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView.")},// (EXT_CSQC) {"renderscene", PF_Fixme, 0, 0, 0, 304, D("void()", "Draws all entities, polygons, and particles on the rentity list (which were added via addentities or addentity), using the various view properties set via setproperty. There is no ordering dependancy.\nThe scene must generally be cleared again before more entities are added, as entities will persist even over to the next frame.\nYou may call this builtin multiple times per frame, but should only be called from CSQC_UpdateView.")},// (EXT_CSQC)

View file

@ -1220,6 +1220,8 @@ void SV_SendServerInfoChange(const char *key, const char *value);
void SV_SendMessagesToAll (void); void SV_SendMessagesToAll (void);
void SV_FindModelNumbers (void); void SV_FindModelNumbers (void);
void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *key, const char *newval);
// //
// sv_user.c // sv_user.c
// //
@ -1227,7 +1229,7 @@ void SV_FindModelNumbers (void);
void SVNQ_New_f (void); void SVNQ_New_f (void);
void SVNQ_ExecuteClientMessage (client_t *cl); void SVNQ_ExecuteClientMessage (client_t *cl);
#endif #endif
qboolean SV_UserInfoIsBasic(char *infoname); //standard message. qboolean SV_UserInfoIsBasic(const char *infoname); //standard message.
void SV_ExecuteClientMessage (client_t *cl); void SV_ExecuteClientMessage (client_t *cl);
void SVQ2_ExecuteClientMessage (client_t *cl); void SVQ2_ExecuteClientMessage (client_t *cl);
int SV_PMTypeForClient (client_t *cl, edict_t *ent); int SV_PMTypeForClient (client_t *cl, edict_t *ent);
@ -1498,6 +1500,7 @@ extern cvar_t sv_demoMaxDirSize;
char *SV_Demo_CurrentOutput(void); char *SV_Demo_CurrentOutput(void);
void SV_MVDInit(void); void SV_MVDInit(void);
char *SV_MVDNum(char *buffer, int bufferlen, int num); char *SV_MVDNum(char *buffer, int bufferlen, int num);
const char *SV_MVDLastNum(unsigned int num);
void SV_SendMVDMessage(void); void SV_SendMVDMessage(void);
void SV_MVD_WriteReliables(qboolean writebroadcasts); void SV_MVD_WriteReliables(qboolean writebroadcasts);
qboolean SV_ReadMVD (void); qboolean SV_ReadMVD (void);

View file

@ -2135,7 +2135,6 @@ SV_Serverinfo_f
Examine or change the serverinfo string Examine or change the serverinfo string
=========== ===========
*/ */
extern char *Info_KeyForNumber(char *s, int num);
void SV_Serverinfo_f (void) void SV_Serverinfo_f (void)
{ {
cvar_t *var; cvar_t *var;

View file

@ -178,9 +178,14 @@ qboolean SV_AddNailUpdate (edict_t *ent)
{ {
if (ent->v->modelindex != sv_nailmodel if (ent->v->modelindex != sv_nailmodel
&& ent->v->modelindex != sv_supernailmodel) && ent->v->modelindex != sv_supernailmodel)
return false; return false; //must be a nail
if (sv_nailhack.value || (host_client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) if (sv_nailhack.value || (host_client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
return false; return false; //'nailhack' is named because of a qizmo-publicised binary hack to disable svc_nails. replacementdeltas also trims much of the state so we may as well use it.
//should probably also detect qizmo specifically - its trajectory stuff beats svc_nails.
if (ent->v->origin[0] <= -4096 || ent->v->origin[0] >= 4096 ||
ent->v->origin[1] <= -4096 || ent->v->origin[1] >= 4096 ||
ent->v->origin[2] <= -4096 || ent->v->origin[2] >= 4096)
return !(host_client->fteprotocolextensions & PEXT_FLOATCOORDS); //outside the bounds of the nails protocol. just swallow it if it can't be sent anyway.
#ifdef SERVER_DEMO_PLAYBACK #ifdef SERVER_DEMO_PLAYBACK
demonails = false; demonails = false;

View file

@ -1028,6 +1028,14 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
ClientReliableWrite_Begin (to, svc_updatecolors, 3); ClientReliableWrite_Begin (to, svc_updatecolors, 3);
ClientReliableWrite_Byte (to, i); ClientReliableWrite_Byte (to, i);
ClientReliableWrite_Byte (to, playercolor); ClientReliableWrite_Byte (to, playercolor);
if (to->fteprotocolextensions2 & PEXT2_PREDINFO)
{
char quotedval[8192];
char *s = va("//fui %i %s\n", i, COM_QuotedString(client->userinfo, quotedval, sizeof(quotedval), false));
ClientReliableWrite_Begin(to, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String(to, s);
}
} }
} }
@ -2084,7 +2092,7 @@ Q3: connect "\key\val"
DP: connect\key\val DP: connect\key\val
QW: connect $VER $QPORT $CHALLENGE "\key\val" QW: connect $VER $QPORT $CHALLENGE "\key\val"
SS: connect2 $VER $QPORT $CHALLENGE "\key\val" "\key\val" SS: connect2 $VER $QPORT $CHALLENGE "\key\val" "\key\val"
NQ: hacked to take the form of QW NQ: hacked to take the form of QW, but with protocol version 3.
extension flags follow it. extension flags follow it.
*/ */
client_t *SVC_DirectConnect(void) client_t *SVC_DirectConnect(void)
@ -2318,7 +2326,12 @@ client_t *SVC_DirectConnect(void)
// note an extra qbyte is needed to replace spectator key // note an extra qbyte is needed to replace spectator key
for (i = 0; i < numssclients; i++) for (i = 0; i < numssclients; i++)
{
Q_strncpyz (userinfo[i], Cmd_Argv(4+i), sizeof(userinfo[i])-1); Q_strncpyz (userinfo[i], Cmd_Argv(4+i), sizeof(userinfo[i])-1);
if (protocol == SCP_NETQUAKE)
Info_RemoveKey(userinfo[i], "mod"); //its served its purpose.
}
} }
{ {
@ -5085,12 +5098,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
{ {
Info_SetValueForKey(cl->userinfo, "team", p, sizeof(cl->userinfo)); Info_SetValueForKey(cl->userinfo, "team", p, sizeof(cl->userinfo));
if (verbose) if (verbose)
{ SV_BroadcastUserinfoChange(cl, true, "team", p);
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, cl-svs.clients);
MSG_WriteString (&sv.reliable_datagram, "team");
MSG_WriteString (&sv.reliable_datagram, p);
}
} }
Q_strncpyz (cl->team, val, sizeof(cl->teambuf)); Q_strncpyz (cl->team, val, sizeof(cl->teambuf));

View file

@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef CLIENTONLY #ifndef CLIENTONLY
#include "winquake.h" #include "winquake.h"
#include "fs.h"
#include "netinc.h" #include "netinc.h"
@ -41,6 +42,7 @@ cvar_t sv_demoPings = CVARD("sv_demoPings", "10", "Interval between ping updates
cvar_t sv_demoMaxSize = CVARD("sv_demoMaxSize", "", "Demos will be truncated to be no larger than this size."); cvar_t sv_demoMaxSize = CVARD("sv_demoMaxSize", "", "Demos will be truncated to be no larger than this size.");
cvar_t sv_demoExtraNames = CVAR("sv_demoExtraNames", ""); cvar_t sv_demoExtraNames = CVAR("sv_demoExtraNames", "");
cvar_t sv_demoExtensions = CVARD("sv_demoExtensions", "", "Enables protocol extensions within MVDs. This will cause older/non-fte clients to error upon playback.\n0: off.\n1: all extensions.\n2: extensions also supported by a certain other engine."); cvar_t sv_demoExtensions = CVARD("sv_demoExtensions", "", "Enables protocol extensions within MVDs. This will cause older/non-fte clients to error upon playback.\n0: off.\n1: all extensions.\n2: extensions also supported by a certain other engine.");
cvar_t sv_demoAutoCompress = CVARD("sv_demoAutoCompress", "", "Specifies whether to compress demos as they're recorded.\n0 = no compression.\n1 = gzip compression.");
cvar_t qtv_password = CVAR( "qtv_password", ""); cvar_t qtv_password = CVAR( "qtv_password", "");
cvar_t qtv_streamport = CVARAF( "qtv_streamport", "0", cvar_t qtv_streamport = CVARAF( "qtv_streamport", "0",
@ -55,6 +57,17 @@ cvar_t sv_demotxt = CVAR("sv_demotxt", "1");
void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time); void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time);
void SV_WriteRecordMVDMessage (sizebuf_t *msg); void SV_WriteRecordMVDMessage (sizebuf_t *msg);
static struct
{ //tracks the previously recorded demos, so we don't have to content with dates and filesystem ordering and stuff.
#define DEMOLOG_LENGTH 16
unsigned int sequence; //incremented
struct
{
char filename[MAX_QPATH];
} log[DEMOLOG_LENGTH];
} demolog;
demo_t demo; demo_t demo;
static float demo_prevtime; static float demo_prevtime;
//static dbuffer_t *demobuffer; //static dbuffer_t *demobuffer;
@ -105,6 +118,8 @@ static void DestClose(mvddest_t *d, enum mvdclosereason_e reason)
else if (d->desttype != DEST_STREAM) else if (d->desttype != DEST_STREAM)
{ {
char buf[512]; char buf[512];
Q_strncpyz(demolog.log[demolog.sequence%DEMOLOG_LENGTH].filename, d->simplename, sizeof(demolog.log[demolog.sequence%DEMOLOG_LENGTH].filename));
demolog.sequence++;
SV_BroadcastPrintf (PRINT_CHAT, "Server recording complete\n^[/download %s^]\n", COM_QuotedString(va("demos/%s",d->simplename), buf, sizeof(buf), false)); SV_BroadcastPrintf (PRINT_CHAT, "Server recording complete\n^[/download %s^]\n", COM_QuotedString(va("demos/%s",d->simplename), buf, sizeof(buf), false));
} }
@ -729,6 +744,7 @@ typedef struct
{ {
char name[MAX_MVD_NAME]; char name[MAX_MVD_NAME];
int size; int size;
time_t mtime;
} file_t; } file_t;
typedef struct typedef struct
@ -759,11 +775,24 @@ static int QDECL Sys_listdirFound(const char *fname, qofs_t fsize, time_t mtime,
f = &dir->files[dir->numfiles++]; f = &dir->files[dir->numfiles++];
Q_strncpyz(f->name, fname, sizeof(f->name)); Q_strncpyz(f->name, fname, sizeof(f->name));
f->size = fsize; f->size = fsize;
f->mtime = mtime;
dir->size += fsize; dir->size += fsize;
return true; return true;
} }
static int Sys_listdir_Sort(const void *va, const void *vb)
{
const file_t *fa = va;
const file_t *fb = vb;
if (fa->mtime == fb->mtime)
return 0;
if (fa->mtime >= fb->mtime)
return 1;
return -1;
}
static dir_t *Sys_listdir (char *path, char *ext, qboolean usesorting) static dir_t *Sys_listdir (char *path, char *ext, qboolean usesorting)
{ {
char searchterm[MAX_QPATH]; char searchterm[MAX_QPATH];
@ -777,6 +806,15 @@ static dir_t *Sys_listdir (char *path, char *ext, qboolean usesorting)
Q_strncpyz(searchterm, va("%s/*%s", path, ext), sizeof(searchterm)); Q_strncpyz(searchterm, va("%s/*%s", path, ext), sizeof(searchterm));
COM_EnumerateFiles(searchterm, Sys_listdirFound, dir); COM_EnumerateFiles(searchterm, Sys_listdirFound, dir);
if (!strcmp(ext, ".mvd"))
{
Q_strncpyz(searchterm, va("%s/*%s.gz", path, ext), sizeof(searchterm));
COM_EnumerateFiles(searchterm, Sys_listdirFound, dir);
}
if (usesorting)
qsort(dir->files, dir->numfiles, sizeof(*dir->files), Sys_listdir_Sort);
return dir; return dir;
} }
static void Sys_freedir(dir_t *dir) static void Sys_freedir(dir_t *dir)
@ -1256,6 +1294,7 @@ void MVD_Init (void)
Cvar_Register (&sv_demotxt, MVDVARGROUP); Cvar_Register (&sv_demotxt, MVDVARGROUP);
Cvar_Register (&sv_demoExtraNames, MVDVARGROUP); Cvar_Register (&sv_demoExtraNames, MVDVARGROUP);
Cvar_Register (&sv_demoExtensions, MVDVARGROUP); Cvar_Register (&sv_demoExtensions, MVDVARGROUP);
Cvar_Register (&sv_demoAutoCompress,MVDVARGROUP);
} }
static char *SV_PrintTeams(void) static char *SV_PrintTeams(void)
@ -1361,6 +1400,11 @@ mvddest_t *SV_MVD_InitRecordFile (char *name)
return NULL; return NULL;
} }
#ifdef AVAIL_GZDEC
if (!Q_strcasecmp("gz", COM_FileExtension(name, path, sizeof(path))))
file = FS_GZ_WriteFilter(file, true, true);
#endif
dst = Z_Malloc(sizeof(mvddest_t)); dst = Z_Malloc(sizeof(mvddest_t));
dst->socket = INVALID_SOCKET; dst->socket = INVALID_SOCKET;
strcpy(dst->filename, name); strcpy(dst->filename, name);
@ -1649,7 +1693,7 @@ qboolean SV_MVD_Record (mvddest_t *dest)
if (sv_demoExtensions.ival == 2 || !*sv_demoExtensions.string) if (sv_demoExtensions.ival == 2 || !*sv_demoExtensions.string)
{ /*more limited subset supported by ezquake*/ { /*more limited subset supported by ezquake*/
demo.recorder.fteprotocolextensions = PEXT_CHUNKEDDOWNLOADS|PEXT_256PACKETENTITIES|PEXT_FLOATCOORDS|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_SPAWNSTATIC2; demo.recorder.fteprotocolextensions = PEXT_CHUNKEDDOWNLOADS|PEXT_256PACKETENTITIES|/*PEXT_FLOATCOORDS|*/PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_SPAWNSTATIC2;
// demo.recorder.fteprotocolextensions |= PEXT_HLBSP; /*ezquake DOES have this, but it is pointless and should have been in some feature mask rather than protocol extensions*/ // demo.recorder.fteprotocolextensions |= PEXT_HLBSP; /*ezquake DOES have this, but it is pointless and should have been in some feature mask rather than protocol extensions*/
// demo.recorder.fteprotocolextensions |= PEXT_ACCURATETIMINGS; /*ezquake does not support this any more*/ // demo.recorder.fteprotocolextensions |= PEXT_ACCURATETIMINGS; /*ezquake does not support this any more*/
// demo.recorder.fteprotocolextensions |= PEXT_TRANS; /*ezquake has no support for .alpha*/ // demo.recorder.fteprotocolextensions |= PEXT_TRANS; /*ezquake has no support for .alpha*/
@ -1936,6 +1980,11 @@ void SV_MVD_Record_f (void)
COM_StripExtension(name, name, sizeof(name)); COM_StripExtension(name, name, sizeof(name));
#ifdef AVAIL_GZDEC
if (sv_demoAutoCompress.ival == 1)
COM_DefaultExtension(name, ".mvd.gz", sizeof(name));
else
#endif
COM_DefaultExtension(name, ".mvd", sizeof(name)); COM_DefaultExtension(name, ".mvd", sizeof(name));
FS_CreatePath (name, FS_GAMEONLY); FS_CreatePath (name, FS_GAMEONLY);
@ -2223,7 +2272,7 @@ void SV_MVDEasyRecord_f (void)
Q_strncpyz(name2, name, sizeof(name2)); Q_strncpyz(name2, name, sizeof(name2));
// COM_StripExtension(name2, name2); // COM_StripExtension(name2, name2);
FS_CreatePath (name2, FS_GAMEONLY); FS_CreatePath (name2, FS_GAMEONLY);
strcat (name2, ".mvd"); Q_strncatz(name2, ".mvd", sizeof(name2));
if ((f = FS_OpenVFS(name2, "rb", FS_GAMEONLY)) == 0) if ((f = FS_OpenVFS(name2, "rb", FS_GAMEONLY)) == 0)
f = FS_OpenVFS(va("%s.gz", name2), "rb", FS_GAMEONLY); f = FS_OpenVFS(va("%s.gz", name2), "rb", FS_GAMEONLY);
@ -2234,13 +2283,17 @@ void SV_MVDEasyRecord_f (void)
VFS_CLOSE (f); VFS_CLOSE (f);
snprintf(name2, sizeof(name2), "%s_%02i", name, i); snprintf(name2, sizeof(name2), "%s_%02i", name, i);
// COM_StripExtension(name2, name2); // COM_StripExtension(name2, name2);
strcat (name2, ".mvd"); Q_strncatz(name2, ".mvd", sizeof(name2));
if ((f = FS_OpenVFS (name2, "rb", FS_GAMEONLY)) == 0) if ((f = FS_OpenVFS (name2, "rb", FS_GAMEONLY)) == 0)
f = FS_OpenVFS(va("%s.gz", name2), "rb", FS_GAMEONLY); f = FS_OpenVFS(va("%s.gz", name2), "rb", FS_GAMEONLY);
i++; i++;
} while (f); } while (f);
} }
#ifdef AVAIL_GZDEC
if (sv_demoAutoCompress.ival == 1)
Q_strncatz(name2, ".gz", sizeof(name2));
#endif
SV_MVD_Record (SV_MVD_InitRecordFile(name2)); SV_MVD_Record (SV_MVD_InitRecordFile(name2));
} }
@ -2370,6 +2423,7 @@ void SV_MVDStream_Poll(void)
#endif #endif
} }
//console command for servers/admins
void SV_MVDList_f (void) void SV_MVDList_f (void)
{ {
mvddest_t *d; mvddest_t *d;
@ -2420,6 +2474,7 @@ void SV_MVDList_f (void)
Sys_freedir(dir); Sys_freedir(dir);
} }
//console command used to print to connected clients (we're acting as a dedicated server)
void SV_UserCmdMVDList_f (void) void SV_UserCmdMVDList_f (void)
{ {
mvddest_t *d; mvddest_t *d;
@ -2451,10 +2506,18 @@ void SV_UserCmdMVDList_f (void)
SV_ClientPrintf(host_client, PRINT_HIGH, "*%d: %s %dk\n", i, list->name, d->totalsize/1024); SV_ClientPrintf(host_client, PRINT_HIGH, "*%d: %s %dk\n", i, list->name, d->totalsize/1024);
} }
if (!d) 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);
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, list->size/1024);
} }
} }
if (host_client->num_backbuf == MAX_BACK_BUFFERS)
SV_ClientPrintf(host_client, PRINT_HIGH, "*MORE*\n", i, list->name, list->size/1024);
}
for (d = demo.dest; d; d = d->nextdest) for (d = demo.dest; d; d = d->nextdest)
dir->size += d->totalsize; dir->size += d->totalsize;
@ -2470,7 +2533,14 @@ void SV_UserCmdMVDList_f (void)
Sys_freedir(dir); Sys_freedir(dir);
} }
char *SV_MVDNum(char *buffer, int bufferlen, int num) const char *SV_MVDLastNum(unsigned int num)
{
if (!num || num > DEMOLOG_LENGTH)
return NULL;
num = demolog.sequence - num;
return demolog.log[num % DEMOLOG_LENGTH].filename;
}
char *SV_MVDNum(char *buffer, int bufferlen, int num) //lame number->name lookup according to a list generated at an arbitrary time
{ {
file_t *list; file_t *list;
dir_t *dir; dir_t *dir;
@ -2478,6 +2548,8 @@ char *SV_MVDNum(char *buffer, int bufferlen, int num)
dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE); dir = Sys_listdir(sv_demoDir.string, ".mvd", SORT_BY_DATE);
list = dir->files; list = dir->files;
if (num < 0)
num = dir->numfiles + num;
if (num > dir->numfiles || num <= 0) if (num > dir->numfiles || num <= 0)
{ {
Sys_freedir(dir); Sys_freedir(dir);

View file

@ -1196,15 +1196,18 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
if (reliable) if (reliable)
{ {
char msgbuf[1024]; char msgbuf[8192];
sizebuf_t msg = {0}; sizebuf_t msg = {0};
msg.data = msgbuf; msg.data = msgbuf;
msg.maxsize = sizeof(msgbuf); msg.maxsize = sizeof(msgbuf);
msg.prim = client->datagram.prim; msg.prim = client->datagram.prim;
callback(client, &msg, ctx); callback(client, &msg, ctx);
if (msg.cursize)
{
ClientReliableCheckBlock(client, msg.cursize); ClientReliableCheckBlock(client, msg.cursize);
ClientReliableWrite_SZ(client, msg.data, msg.cursize); ClientReliableWrite_SZ(client, msg.data, msg.cursize);
} }
}
else else
callback(client, &client->datagram, ctx); callback(client, &client->datagram, ctx);
} }
@ -2863,6 +2866,11 @@ void SV_UpdateToReliableMessages (void)
continue; continue;
ClientReliableWrite_Begin(client, svc_updatefrags, 4); ClientReliableWrite_Begin(client, svc_updatefrags, 4);
ClientReliableWrite_Byte(client, i); ClientReliableWrite_Byte(client, i);
#ifdef NQPROT
if (ISNQCLIENT(client) && host_client->spectator == 1)
ClientReliableWrite_Short(client, -999);
else
#endif
ClientReliableWrite_Short(client, host_client->edict->v->frags); ClientReliableWrite_Short(client, host_client->edict->v->frags);
} }
@ -2926,6 +2934,11 @@ void SV_UpdateToReliableMessages (void)
continue; continue;
ClientReliableWrite_Begin(client, svc_updatefrags, 4); ClientReliableWrite_Begin(client, svc_updatefrags, 4);
ClientReliableWrite_Byte(client, i); ClientReliableWrite_Byte(client, i);
#ifdef NQPROT
if (ISNQCLIENT(client) && host_client->spectator == 1)
ClientReliableWrite_Short(client, -999);
else
#endif
ClientReliableWrite_Short(client, curfrags); ClientReliableWrite_Short(client, curfrags);
} }
@ -3011,6 +3024,91 @@ void SV_UpdateToReliableMessages (void)
//#endif //#endif
//a single userinfo value was changed.
static void SV_SendUserinfoChange(client_t *to, client_t *about, qboolean isbasic, const char *key, const char *newval)
{
int playernum = about - svs.clients;
if (ISQWCLIENT(to))
{
if (isbasic || (to->fteprotocolextensions & PEXT_BIGUSERINFOS))
{
ClientReliableWrite_Begin(to, svc_setinfo, 4+strlen(key)+strlen(newval));
ClientReliableWrite_Byte(to, playernum);
ClientReliableWrite_String(to, key);
ClientReliableWrite_String(to, newval);
}
}
#ifdef NQPROT
else if (ISNQCLIENT(to))
{
if (!strcmp(key, "*spectator"))
{ //nq does not support spectators, mods tend to use frags=-999 or -99 instead.
//yes, this breaks things.
ClientReliableWrite_Begin(to, svc_updatefrags, 4);
ClientReliableWrite_Byte(to, playernum);
if (atoi(newval) == 1)
ClientReliableWrite_Short(to, -999);
else
ClientReliableWrite_Short(to, about->old_frags); //restore their true frag count
}
else if (!strcmp(key, "name"))
{
ClientReliableWrite_Begin(to, svc_updatename, 3+strlen(newval));
ClientReliableWrite_Byte(to, playernum);
ClientReliableWrite_String(to, newval);
}
else if (!strcmp(key, "topcolor") || !strcmp(key, "bottomcolor"))
{ //due to these being combined, nq players get double colour change notifications...
int tc = atoi(Info_ValueForKey(about->userinfo, "topcolor"));
int bc = atoi(Info_ValueForKey(about->userinfo, "bottomcolor"));
if (tc < 0 || tc > 13)
tc = 0;
if (bc < 0 || bc > 13)
bc = 0;
ClientReliableWrite_Begin(to, svc_updatecolors, 3);
ClientReliableWrite_Byte(to, playernum);
ClientReliableWrite_Byte(to, 16*tc + bc);
}
if (to->fteprotocolextensions2 & PEXT2_PREDINFO)
{
char quotedkey[1024];
char quotedval[8192];
char *s = va("//ui %i %s %s\n", playernum, COM_QuotedString(key, quotedkey, sizeof(quotedkey), false), COM_QuotedString(newval, quotedval, sizeof(quotedval), false));
ClientReliableWrite_Begin(to, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String(to, s);
}
}
#endif
}
void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *key, const char *newval)
{
client_t *client;
int j;
for (j = 0; j < svs.allocated_client_slots; j++)
{
client = svs.clients+j;
if (client->state < cs_connected)
continue; // reliables go to all connected or spawned
if (client->controller)
continue; //splitscreen
if (client->protocol == SCP_BAD)
continue; //botclient
SV_SendUserinfoChange(client, about, isbasic, key, newval);
}
if (sv.mvdrecording && (isbasic || (demo.recorder.fteprotocolextensions & PEXT_BIGUSERINFOS)))
{
sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(newval)+4);
MSG_WriteByte (msg, svc_setinfo);
MSG_WriteByte (msg, about - svs.clients);
MSG_WriteString (msg, key);
MSG_WriteString (msg, newval);
}
}
/* /*
======================= =======================

View file

@ -2813,13 +2813,13 @@ qboolean SV_AllowDownload (const char *name)
//block attempts to download logs //block attempts to download logs
if (!Q_strcasecmp("log", ext)) if (!Q_strcasecmp("log", ext))
return !!allow_download_logs.value; return !!allow_download_logs.value;
if (strncmp(name, "logs/", 5) == 0) if (Q_strncasecmp(name, "logs/", 5) == 0)
return !!allow_download_logs.value; return !!allow_download_logs.value;
if (!strncmp(name, "package/", 8)) if (!Q_strncasecmp(name, "package/", 8))
{ {
//eg: package/id1/foobar.pk3 //eg: package/id1/foobar.pk3
if (!strcmp("pk4", ext) || !strcmp("pk3", ext) || !strcmp("pak", ext) || (!strncmp(name, "package/downloads/", 18) && !strcmp("zip", ext))) if (!Q_strcasecmp("pk4", ext) || !Q_strcasecmp("pk3", ext) || !Q_strcasecmp("pak", ext) || (!Q_strncasecmp(name, "package/downloads/", 18) && !Q_strcasecmp("zip", ext)))
{ {
if (!allow_download_packages.ival) if (!allow_download_packages.ival)
return false; return false;
@ -2832,49 +2832,49 @@ qboolean SV_AllowDownload (const char *name)
return false; return false;
} }
if (strncmp(name, "maps/", 5) == 0) if (Q_strncasecmp(name, "maps/", 5) == 0)
return !!allow_download_maps.value; return !!allow_download_maps.value;
//skins? //skins?
if (strncmp(name, "skins/", 6) == 0) if (Q_strncasecmp(name, "skins/", 6) == 0)
return !!allow_download_skins.value; return !!allow_download_skins.value;
//models //models
if ((strncmp(name, "progs/", 6) == 0) || if ((Q_strncasecmp(name, "progs/", 6) == 0) ||
(strncmp(name, "models/", 7) == 0)) (Q_strncasecmp(name, "models/", 7) == 0))
return !!allow_download_models.value; return !!allow_download_models.value;
//sound //sound
if (strncmp(name, "sound/", 6) == 0) if (Q_strncasecmp(name, "sound/", 6) == 0)
return !!allow_download_sounds.value; return !!allow_download_sounds.value;
//particles //particles
if (strncmp(name, "particles/", 6) == 0) if (Q_strncasecmp(name, "particles/", 6) == 0)
return !!allow_download_particles.value; return !!allow_download_particles.value;
//demos //demos
if (strncmp(name, "demos/", 6) == 0) if (Q_strncasecmp(name, "demos/", 6) == 0)
return !!allow_download_demos.value; return !!allow_download_demos.value;
//textures //textures
if (strncmp(name, "textures/", 9) == 0) if (Q_strncasecmp(name, "textures/", 9) == 0)
return !!allow_download_textures.value; return !!allow_download_textures.value;
if (strncmp(name, "locs/", 5) == 0) if (Q_strncasecmp(name, "locs/", 5) == 0)
return !!allow_download_locs.value; return !!allow_download_locs.value;
//wads //wads
if (strncmp(name, "wads/", 5) == 0) if (Q_strncasecmp(name, "wads/", 5) == 0)
return !!allow_download_wads.value; return !!allow_download_wads.value;
if (!strchr(name, '/') && !strcmp("wad", ext)) if (!strchr(name, '/') && !Q_strcasecmp("wad", ext))
return !!allow_download_wads.value; return !!allow_download_wads.value;
//configs //configs
if (strncmp(name, "config/", 7) == 0) if (Q_strncasecmp(name, "config/", 7) == 0)
return !!allow_download_configs.value; return !!allow_download_configs.value;
if (!strcmp("cfg", ext)) if (!Q_strcasecmp("cfg", ext))
return !!allow_download_configs.value; return !!allow_download_configs.value;
//pak/pk3s. //pak/pk3s.
if (!strchr(name, '/') && (!strcmp("pk4", ext) || !strcmp("pk3", ext) || !strcmp("pak", ext))) if (!strchr(name, '/') && (!Q_strcasecmp("pk4", ext) || !Q_strcasecmp("pk3", ext) || !Q_strcasecmp("pak", ext)))
{ {
if (strnicmp(name, "pak", 3)) //don't give out core pak/pk3 files. This matches q3 logic. if (Q_strncasecmp(name, "pak", 3)) //don't give out core pak/pk3 files. This matches q3 logic.
return !!allow_download_packages.value; return !!allow_download_packages.value;
else else
return !!allow_download_packages.value && !!allow_download_copyrighted.value; return !!allow_download_packages.value && !!allow_download_copyrighted.value;
@ -2892,7 +2892,7 @@ qboolean SV_AllowDownload (const char *name)
return !!allow_download_other.value; return !!allow_download_other.value;
} }
static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks) 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 allow_download_anymap, allow_download_pakcontents;
extern cvar_t sv_demoDir; extern cvar_t sv_demoDir;
@ -2903,16 +2903,8 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
if (replacementname) if (replacementname)
*replacementname = NULL; *replacementname = NULL;
//mangle the name by making it lower case.
{
char *p;
for (p = name; *p; p++)
*p = (char)tolower((unsigned char)*p);
}
//mvdsv demo downloading support demonum/ -> demos/XXXX (sets up the client paths) //mvdsv demo downloading support demonum/ -> demos/XXXX (sets up the client paths)
if (!strncmp(name, "demonum/", 8)) if (!Q_strncasecmp(name, "demonum/", 8))
{ {
if (replacementname) if (replacementname)
{ {
@ -2936,13 +2928,13 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
} }
//mvdsv demo downloading support. demos/ -> demodir (sets up the server paths) //mvdsv demo downloading support. demos/ -> demodir (sets up the server paths)
if (!strncmp(name, "demos/", 6)) if (Q_strncasecmp(name, "demos/", 6))
{ {
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6); Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6);
name = tmpname; name = tmpname;
} }
if (!strncmp(name, "package/", 8)) if (!Q_strncasecmp(name, "package/", 8))
{ {
vfsfile_t *f = FS_OpenVFS(name+8, "rb", FS_ROOT); vfsfile_t *f = FS_OpenVFS(name+8, "rb", FS_ROOT);
if (f) if (f)
@ -2978,11 +2970,11 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
{ {
char tryalt[MAX_QPATH]; char tryalt[MAX_QPATH];
char ext[8]; char ext[8];
if (strncmp(name, alternatives[alt][0], strlen(alternatives[alt][0]))) if (Q_strncasecmp(name, alternatives[alt][0], strlen(alternatives[alt][0])))
{ {
if (*alternatives[alt][2]) if (*alternatives[alt][2])
{ {
if (strcmp(COM_FileExtension(name, ext, sizeof(ext)), alternatives[alt][2]+1)) if (Q_strcasecmp(COM_FileExtension(name, ext, sizeof(ext)), alternatives[alt][2]+1))
continue; continue;
memcpy(tryalt, alternatives[alt][1], strlen(alternatives[alt][1])); memcpy(tryalt, alternatives[alt][1], strlen(alternatives[alt][1]));
COM_StripExtension(name+strlen(alternatives[alt][0]), tryalt+strlen(alternatives[alt][1]), sizeof(tryalt)-strlen(alternatives[alt][1])); COM_StripExtension(name+strlen(alternatives[alt][0]), tryalt+strlen(alternatives[alt][1]), sizeof(tryalt)-strlen(alternatives[alt][1]));
@ -3011,7 +3003,7 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
// special check for maps, if it came from a pak file, don't allow download // special check for maps, if it came from a pak file, don't allow download
if (protectedpak) if (protectedpak)
{ {
if (!allow_download_anymap.value && !strncmp(name, "maps/", 5)) if (!allow_download_anymap.value && !Q_strncasecmp(name, "maps/", 5))
{ {
Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8); Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8);
return DLERR_PERMISSIONS; return DLERR_PERMISSIONS;
@ -3103,6 +3095,64 @@ void SV_DownloadSize_f(void)
} }
} }
void SV_DemoDownload_f(void)
{
int arg;
unsigned long num;
const char *name, *mvdname;
char mvdnamebuffer[MAX_QPATH];
if (Cmd_Argc() < 2)
{
//fixme: help text, or possibly just display links to the last 10 demos?
return;
}
if (Cmd_Argc() == 2)
{
name = Cmd_Argv(1);
if (!strcmp(name, "\\") || !Q_strcasecmp(name, "stop") || !Q_strcasecmp(name, "cancel"))
{
//fte servers don't do download queues, as it is impossible to avoid race conditions with vanilla clients anyway.
return;
}
}
for (arg = 1; arg < Cmd_Argc(); arg++)
{
name = Cmd_Argv(arg);
if (*name == '.')
{ //just count the dots
for (num = 0, mvdname = name; *mvdname == '.'; mvdname++)
num++;
if (*mvdname)
{
SV_ClientPrintf (host_client, PRINT_HIGH, "invalid demo id %s\n", name);
continue;
}
mvdname = SV_MVDLastNum(num);
}
else
{
char *e;
num = strtoul(name, &e, 10);
if (!num || *e)
{
SV_ClientPrintf (host_client, PRINT_HIGH, "invalid demo id %s\n", name);
continue;
}
mvdname = SV_MVDNum(mvdnamebuffer, sizeof(mvdnamebuffer), num);
}
if (!mvdname)
SV_ClientPrintf (host_client, PRINT_HIGH, "%s is an invalid MVD demonum.\n", name);
else
{
const char *s = va("download \"demos/%s\"\n", mvdname);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String (host_client, s);
}
}
}
/* /*
================== ==================
SV_BeginDownload_f SV_BeginDownload_f
@ -3249,7 +3299,7 @@ void SV_BeginDownload_f(void)
else else
#endif #endif
if (ISNQCLIENT(host_client)) if (ISNQCLIENT(host_client))
{ { //dp's download protocol
SV_PrintToClient(host_client, PRINT_HIGH, error); SV_PrintToClient(host_client, PRINT_HIGH, error);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12); ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12);
@ -4051,7 +4101,7 @@ void SV_Msg_f (void)
SV_ClientTPrintf (host_client, PRINT_HIGH, "new msg level set to %i\n", host_client->messagelevel); SV_ClientTPrintf (host_client, PRINT_HIGH, "new msg level set to %i\n", host_client->messagelevel);
} }
qboolean SV_UserInfoIsBasic(char *infoname) qboolean SV_UserInfoIsBasic(const char *infoname)
{ {
int i; int i;
char *basicinfos[] = { char *basicinfos[] = {
@ -4082,12 +4132,9 @@ Allow clients to change userinfo
*/ */
void SV_SetInfo_f (void) void SV_SetInfo_f (void)
{ {
int i, j; int i;
char oldval[MAX_INFO_KEY]; char oldval[MAX_INFO_KEY];
char *key, *val; char *key, *val;
qboolean basic; //infos that we send to any old qw client.
client_t *client;
if (Cmd_Argc() == 1) if (Cmd_Argc() == 1)
{ {
@ -4149,48 +4196,7 @@ void SV_SetInfo_f (void)
i = host_client - svs.clients; i = host_client - svs.clients;
val = Info_ValueForKey(host_client->userinfo, key); val = Info_ValueForKey(host_client->userinfo, key);
basic = SV_UserInfoIsBasic(key); SV_BroadcastUserinfoChange(host_client, SV_UserInfoIsBasic(key), key, val);
for (j = 0; j < svs.allocated_client_slots; j++)
{
client = svs.clients+j;
if (client->state < cs_connected)
continue; // reliables go to all connected or spawned
if (client->controller)
continue; //splitscreen
if (client->protocol == SCP_BAD)
continue; //botclient
if (ISQWCLIENT(client))
{
if (basic || (client->fteprotocolextensions & PEXT_BIGUSERINFOS))
{
ClientReliableWrite_Begin(client, svc_setinfo, 1+1+strlen(key)+1+strlen(val)+1);
ClientReliableWrite_Byte(client, i);
ClientReliableWrite_String(client, key);
ClientReliableWrite_String(client, val);
}
}
if (ISNQCLIENT(client))
{
if (!strcmp(key, "name"))
{
ClientReliableWrite_Begin(client, svc_updatename, 1+1+strlen(val)+1);
ClientReliableWrite_Byte(client, i);
ClientReliableWrite_String(client, val);
}
}
}
if (sv.mvdrecording && (basic || (demo.recorder.fteprotocolextensions & PEXT_BIGUSERINFOS)))
{
sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, strlen(key)+strlen(val)+4);
MSG_WriteByte (msg, svc_setinfo);
MSG_WriteByte (msg, i);
MSG_WriteString (msg, key);
MSG_WriteString (msg, val);
}
} }
//doh't spam chat changes. they're not interesting, and just spammy. //doh't spam chat changes. they're not interesting, and just spammy.
@ -5824,9 +5830,12 @@ ucmd_t ucmds[] =
{"serverinfo", SV_ShowServerinfo_f}, {"serverinfo", SV_ShowServerinfo_f},
/*demo/download commands*/ /*demo/download commands*/
{"stopdownload", SV_StopDownload_f},
{"demolist", SV_UserCmdMVDList_f}, {"demolist", SV_UserCmdMVDList_f},
{"dlist", SV_UserCmdMVDList_f}, //apparently people are too lazy to type.
{"demoinfo", SV_MVDInfo_f}, {"demoinfo", SV_MVDInfo_f},
{"dl", SV_DemoDownload_f},
{"stopdownload", SV_StopDownload_f},
{"dlsize", SV_DownloadSize_f}, {"dlsize", SV_DownloadSize_f},
{"download", SV_BeginDownload_f}, {"download", SV_BeginDownload_f},
{"nextdl", SV_NextDownload_f, true}, {"nextdl", SV_NextDownload_f, true},
@ -6437,7 +6446,7 @@ int SV_PMTypeForClient (client_t *cl, edict_t *ent)
{ //it prevents bugs from being visible in unsuspecting mods. { //it prevents bugs from being visible in unsuspecting mods.
if (cl && cl->spectator) if (cl && cl->spectator)
{ {
if (cl->zquake_extensions & Z_EXT_PM_TYPE_NEW) if ((cl->zquake_extensions & Z_EXT_PM_TYPE_NEW) || (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
return PM_SPECTATOR; return PM_SPECTATOR;
return PM_OLD_SPECTATOR; return PM_OLD_SPECTATOR;
} }
@ -6451,7 +6460,8 @@ int SV_PMTypeForClient (client_t *cl, edict_t *ent)
{ {
case MOVETYPE_NOCLIP: case MOVETYPE_NOCLIP:
/*older/vanilla clients have a b0rked spectator mode that we don't want to break*/ /*older/vanilla clients have a b0rked spectator mode that we don't want to break*/
if (cl && cl->zquake_extensions & Z_EXT_PM_TYPE_NEW) if (cl)
if ((cl->zquake_extensions & Z_EXT_PM_TYPE_NEW) || (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
return PM_SPECTATOR; return PM_SPECTATOR;
return PM_OLD_SPECTATOR; return PM_OLD_SPECTATOR;
@ -7891,7 +7901,7 @@ void SVNQ_ReadClientMove (usercmd_t *move)
move->sidemove = MSG_ReadShort (); move->sidemove = MSG_ReadShort ();
move->upmove = MSG_ReadShort (); move->upmove = MSG_ReadShort ();
move->msec=bound(0, timesincelast*1000, 255); move->msec=bound(0, timesincelast*1000, 250);
frame->move_msecs = timesincelast*1000; frame->move_msecs = timesincelast*1000;
// read buttons // read buttons
@ -7932,7 +7942,7 @@ void SVNQ_ReadClientMove (usercmd_t *move)
if (SV_CanTrack(host_client, i)) if (SV_CanTrack(host_client, i))
break; break;
} }
if (i == host_client->spec_track) if (i >= host_client->spec_track)
i = 0; i = 0;
} }

View file

@ -134,6 +134,20 @@ void WriteFloat(netmsg_t *b, float f)
u.f = f; u.f = f;
WriteLong(b, u.i); WriteLong(b, u.i);
} }
void WriteCoord(netmsg_t *b, float c, unsigned int pext)
{
if (pext & PEXT_FLOATCOORDS)
WriteFloat(b, c);
else
WriteShort(b, c*8);
}
void WriteAngle(netmsg_t *b, float a, unsigned int pext)
{
if (pext & PEXT_FLOATCOORDS)
WriteShort(b, (a/360.0)*0x10000);
else
WriteByte(b, (a/360.0)*0x100 + 0.49); //round better, to avoid rounding bias
}
void WriteString2(netmsg_t *b, const char *str) void WriteString2(netmsg_t *b, const char *str)
{ //no null terminator, convienience function. { //no null terminator, convienience function.
while(*str) while(*str)

View file

@ -574,7 +574,7 @@ static int ParseList(sv_t *tv, netmsg_t *m, filename_t *list, int to, unsigned i
return ReadByte(m); return ReadByte(m);
} }
static void ParseEntityState(entity_state_t *es, netmsg_t *m) //for baselines/static entities static void ParseEntityState(sv_t *tv, entity_state_t *es, netmsg_t *m) //for baselines/static entities
{ {
int i; int i;
@ -584,8 +584,8 @@ static void ParseEntityState(entity_state_t *es, netmsg_t *m) //for baselines/st
es->skinnum = ReadByte(m); es->skinnum = ReadByte(m);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
es->origin[i] = ReadShort(m); es->origin[i] = ReadCoord(m, tv->pext);
es->angles[i] = ReadByte(m); es->angles[i] = ReadAngle(m, tv->pext);
} }
} }
static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask) static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
@ -597,7 +597,7 @@ static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
ParseError(m); ParseError(m);
return; return;
} }
ParseEntityState(&tv->map.entity[entnum].baseline, m); ParseEntityState(tv, &tv->map.entity[entnum].baseline, m);
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1); ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
} }
@ -642,7 +642,7 @@ void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Sys_Printf(tv->cluster, "Too many static entities\n"); Sys_Printf(tv->cluster, "Too many static entities\n");
} }
ParseEntityState(&tv->map.spawnstatic[tv->map.spawnstatic_count], m); ParseEntityState(tv, &tv->map.spawnstatic[tv->map.spawnstatic_count], m);
tv->map.spawnstatic_count++; tv->map.spawnstatic_count++;
@ -679,9 +679,9 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
{ {
flags = (unsigned short)ReadShort (m); flags = (unsigned short)ReadShort (m);
tv->map.players[num].current.origin[0] = ReadShort (m); tv->map.players[num].current.origin[0] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[1] = ReadShort (m); tv->map.players[num].current.origin[1] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[2] = ReadShort (m); tv->map.players[num].current.origin[2] = ReadCoord (m, tv->pext);
tv->map.players[num].current.frame = ReadByte(m); tv->map.players[num].current.frame = ReadByte(m);
@ -754,7 +754,7 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
if (flags & (DF_ORIGIN << i)) if (flags & (DF_ORIGIN << i))
tv->map.players[num].current.origin[i] = ReadShort (m); tv->map.players[num].current.origin[i] = ReadCoord (m, tv->pext);
} }
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
@ -782,9 +782,9 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
} }
tv->map.players[num].leafcount = BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, tv->map.players[num].leafs, tv->map.players[num].leafcount = BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, tv->map.players[num].leafs,
tv->map.players[num].current.origin[0]/8.0f, tv->map.players[num].current.origin[0],
tv->map.players[num].current.origin[1]/8.0f, tv->map.players[num].current.origin[1],
tv->map.players[num].current.origin[2]/8.0f, 32); tv->map.players[num].current.origin[2], 32);
} }
static int readentitynum(netmsg_t *m, unsigned int *retflags) static int readentitynum(netmsg_t *m, unsigned int *retflags)
@ -837,26 +837,26 @@ static void ParseEntityDelta(sv_t *tv, netmsg_t *m, entity_state_t *old, entity_
new->effects = ReadByte(m); new->effects = ReadByte(m);
if (flags & U_ORIGIN1) if (flags & U_ORIGIN1)
new->origin[0] = ReadShort(m); new->origin[0] = ReadCoord(m, tv->pext);
if (flags & U_ANGLE1) if (flags & U_ANGLE1)
new->angles[0] = ReadByte(m); new->angles[0] = ReadAngle(m, tv->pext);
if (flags & U_ORIGIN2) if (flags & U_ORIGIN2)
new->origin[1] = ReadShort(m); new->origin[1] = ReadCoord(m, tv->pext);
if (flags & U_ANGLE2) if (flags & U_ANGLE2)
new->angles[1] = ReadByte(m); new->angles[1] = ReadAngle(m, tv->pext);
if (flags & U_ORIGIN3) if (flags & U_ORIGIN3)
new->origin[2] = ReadShort(m); new->origin[2] = ReadCoord(m, tv->pext);
if (flags & U_ANGLE3) if (flags & U_ANGLE3)
new->angles[2] = ReadByte(m); new->angles[2] = ReadAngle(m, tv->pext);
if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL))) if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL)))
{ {
ent->leafcount = ent->leafcount =
BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, ent->leafs, BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, ent->leafs,
new->origin[0]/8.0f, new->origin[0],
new->origin[1]/8.0f, new->origin[1],
new->origin[2]/8.0f, 32); new->origin[2], 32);
} }
} }
@ -1098,9 +1098,9 @@ return;
if ((flags & (U_ORIGIN1 | U_ORIGIN2 | U_ORIGIN3)) || forcerelink) if ((flags & (U_ORIGIN1 | U_ORIGIN2 | U_ORIGIN3)) || forcerelink)
tv->entity[entnum].leafcount = BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, tv->entity[entnum].leafs, tv->entity[entnum].leafcount = BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, tv->entity[entnum].leafs,
tv->entity[entnum].current.origin[0]/8.0f, tv->entity[entnum].current.origin[0],
tv->entity[entnum].current.origin[1]/8.0f, tv->entity[entnum].current.origin[1],
tv->entity[entnum].current.origin[2]/8.0f, 32); tv->entity[entnum].current.origin[2], 32);
} }
*/ */
} }
@ -1268,7 +1268,7 @@ static void ParseSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
channel &= 7; channel &= 7;
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
org[i] = ReadShort (m); org[i] = ReadCoord (m, tv->pext);
Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW); Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW);
@ -1307,9 +1307,9 @@ static void ParseDamage(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{ {
ReadByte (m); ReadByte (m);
ReadByte (m); ReadByte (m);
ReadShort (m); ReadCoord (m, tv->pext);
ReadShort (m); ReadCoord (m, tv->pext);
ReadShort (m); ReadCoord (m, tv->pext);
Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW); Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW);
} }
@ -1621,9 +1621,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
case svc_setangle: case svc_setangle:
if (!tv->usequakeworldprotocols) if (!tv->usequakeworldprotocols)
ReadByte(&buf); ReadByte(&buf);
tv->proxyplayerangles[0] = ReadByte(&buf)*360.0/255; tv->proxyplayerangles[0] = ReadAngle(&buf, tv->pext);
tv->proxyplayerangles[1] = ReadByte(&buf)*360.0/255; tv->proxyplayerangles[1] = ReadAngle(&buf, tv->pext);
tv->proxyplayerangles[2] = ReadByte(&buf)*360.0/255; tv->proxyplayerangles[2] = ReadAngle(&buf, tv->pext);
if (tv->usequakeworldprotocols && tv->controller) if (tv->usequakeworldprotocols && tv->controller)
SendBufferToViewer(tv->controller, (char*)buf.data+buf.startpos, buf.readpos - buf.startpos, true); SendBufferToViewer(tv->controller, (char*)buf.data+buf.startpos, buf.readpos - buf.startpos, true);
@ -1657,9 +1657,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
//#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte] //#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte]
case svc_particle: case svc_particle:
ReadShort(&buf); ReadCoord(&buf, tv->pext);
ReadShort(&buf); ReadCoord(&buf, tv->pext);
ReadShort(&buf); ReadCoord(&buf, tv->pext);
ReadByte(&buf); ReadByte(&buf);
ReadByte(&buf); ReadByte(&buf);
ReadByte(&buf); ReadByte(&buf);

View file

@ -336,15 +336,15 @@ typedef struct {
unsigned char modelindex; unsigned char modelindex;
unsigned char colormap; unsigned char colormap;
unsigned char skinnum; unsigned char skinnum;
short origin[3]; float origin[3];
char angles[3]; float angles[3];
unsigned char effects; unsigned char effects;
} entity_state_t; } entity_state_t;
typedef struct { typedef struct {
unsigned char frame; unsigned char frame;
unsigned char modelindex; unsigned char modelindex;
unsigned char skinnum; unsigned char skinnum;
short origin[3]; float origin[3];
short velocity[3]; short velocity[3];
short angles[3]; short angles[3];
unsigned char effects; unsigned char effects;
@ -810,6 +810,8 @@ unsigned short ReadShort(netmsg_t *b);
unsigned int ReadLong(netmsg_t *b); unsigned int ReadLong(netmsg_t *b);
float ReadFloat(netmsg_t *b); float ReadFloat(netmsg_t *b);
void ReadString(netmsg_t *b, char *string, int maxlen); void ReadString(netmsg_t *b, char *string, int maxlen);
float ReadCoord(netmsg_t *b, unsigned int pext);
float ReadAngle(netmsg_t *b, unsigned int pext);
unsigned int SwapLong(unsigned int val); unsigned int SwapLong(unsigned int val);
unsigned int BigLong(unsigned int val); unsigned int BigLong(unsigned int val);
@ -837,6 +839,8 @@ void WriteByte(netmsg_t *b, unsigned char c);
void WriteShort(netmsg_t *b, unsigned short l); void WriteShort(netmsg_t *b, unsigned short l);
void WriteLong(netmsg_t *b, unsigned int l); void WriteLong(netmsg_t *b, unsigned int l);
void WriteFloat(netmsg_t *b, float f); void WriteFloat(netmsg_t *b, float f);
void WriteCoord(netmsg_t *b, float c, unsigned int pext);
void WriteAngle(netmsg_t *b, float a, unsigned int pext);
void WriteString2(netmsg_t *b, const char *str); void WriteString2(netmsg_t *b, const char *str);
void WriteString(netmsg_t *b, const char *str); void WriteString(netmsg_t *b, const char *str);
void WriteData(netmsg_t *b, const void *data, int length); void WriteData(netmsg_t *b, const void *data, int length);

View file

@ -467,7 +467,7 @@ int SendCurrentUserinfos(sv_t *tv, int cursize, netmsg_t *msg, int i, int thispl
return i; return i;
} }
void WriteEntityState(netmsg_t *msg, entity_state_t *es) void WriteEntityState(netmsg_t *msg, entity_state_t *es, unsigned int pext)
{ {
int i; int i;
WriteByte(msg, es->modelindex); WriteByte(msg, es->modelindex);
@ -476,8 +476,8 @@ void WriteEntityState(netmsg_t *msg, entity_state_t *es)
WriteByte(msg, es->skinnum); WriteByte(msg, es->skinnum);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
WriteShort(msg, es->origin[i]); WriteCoord(msg, es->origin[i], pext);
WriteByte(msg, es->angles[i]); WriteAngle(msg, es->angles[i], pext);
} }
} }
int SendCurrentBaselines(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize, int i) int SendCurrentBaselines(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize, int i)
@ -497,7 +497,7 @@ int SendCurrentBaselines(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize
{ {
WriteByte(msg, svc_spawnbaseline); WriteByte(msg, svc_spawnbaseline);
WriteShort(msg, i); WriteShort(msg, i);
WriteEntityState(msg, &tv->map.entity[i].baseline); WriteEntityState(msg, &tv->map.entity[i].baseline, tv->pext);
} }
} }
@ -535,9 +535,9 @@ int SendStaticSounds(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize, in
continue; continue;
WriteByte(msg, svc_spawnstaticsound); WriteByte(msg, svc_spawnstaticsound);
WriteShort(msg, tv->map.staticsound[i].origin[0]); WriteCoord(msg, tv->map.staticsound[i].origin[0], tv->pext);
WriteShort(msg, tv->map.staticsound[i].origin[1]); WriteCoord(msg, tv->map.staticsound[i].origin[1], tv->pext);
WriteShort(msg, tv->map.staticsound[i].origin[2]); WriteCoord(msg, tv->map.staticsound[i].origin[2], tv->pext);
WriteByte(msg, tv->map.staticsound[i].soundindex); WriteByte(msg, tv->map.staticsound[i].soundindex);
WriteByte(msg, tv->map.staticsound[i].volume); WriteByte(msg, tv->map.staticsound[i].volume);
WriteByte(msg, tv->map.staticsound[i].attenuation); WriteByte(msg, tv->map.staticsound[i].attenuation);
@ -560,7 +560,7 @@ int SendStaticEntities(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize,
continue; continue;
WriteByte(msg, svc_spawnstatic); WriteByte(msg, svc_spawnstatic);
WriteEntityState(msg, &tv->map.spawnstatic[i]); WriteEntityState(msg, &tv->map.spawnstatic[i], tv->pext);
} }
return i; return i;
@ -1248,7 +1248,7 @@ void ConnectionlessPacket(cluster_t *cluster, netadr_t *from, netmsg_t *m)
} }
void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t *to, netmsg_t *msg, qboolean force) void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t *to, netmsg_t *msg, qboolean force, unsigned int pext)
{ {
unsigned int i; unsigned int i;
unsigned int bits; unsigned int bits;
@ -1311,17 +1311,17 @@ void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t
if (bits & U_EFFECTS) if (bits & U_EFFECTS)
WriteByte (msg, to->effects&0x00ff); WriteByte (msg, to->effects&0x00ff);
if (bits & U_ORIGIN1) if (bits & U_ORIGIN1)
WriteShort (msg, to->origin[0]); WriteCoord(msg, to->origin[0], pext);
if (bits & U_ANGLE1) if (bits & U_ANGLE1)
WriteByte(msg, to->angles[0]); WriteAngle(msg, to->angles[0], pext);
if (bits & U_ORIGIN2) if (bits & U_ORIGIN2)
WriteShort (msg, to->origin[1]); WriteCoord(msg, to->origin[1], pext);
if (bits & U_ANGLE2) if (bits & U_ANGLE2)
WriteByte(msg, to->angles[1]); WriteAngle(msg, to->angles[1], pext);
if (bits & U_ORIGIN3) if (bits & U_ORIGIN3)
WriteShort (msg, to->origin[2]); WriteCoord(msg, to->origin[2], pext);
if (bits & U_ANGLE3) if (bits & U_ANGLE3)
WriteByte(msg, to->angles[2]); WriteAngle(msg, to->angles[2], pext);
} }
const entity_state_t nullentstate = {0}; const entity_state_t nullentstate = {0};
@ -1365,7 +1365,7 @@ void SV_EmitPacketEntities (const sv_t *qtv, const viewer_t *v, const packet_ent
if (newnum == oldnum) if (newnum == oldnum)
{ // delta update from old position { // delta update from old position
//Con_Printf ("delta %i\n", newnum); //Con_Printf ("delta %i\n", newnum);
SV_WriteDelta (newnum, &from->ents[oldindex], &to->ents[newindex], msg, false); SV_WriteDelta (newnum, &from->ents[oldindex], &to->ents[newindex], msg, false, qtv->pext);
oldindex++; oldindex++;
newindex++; newindex++;
@ -1376,7 +1376,7 @@ void SV_EmitPacketEntities (const sv_t *qtv, const viewer_t *v, const packet_ent
{ // this is a new entity, send it from the baseline { // this is a new entity, send it from the baseline
baseline = &qtv->map.entity[newnum].baseline; baseline = &qtv->map.entity[newnum].baseline;
//Con_Printf ("baseline %i\n", newnum); //Con_Printf ("baseline %i\n", newnum);
SV_WriteDelta (newnum, baseline, &to->ents[newindex], msg, true); SV_WriteDelta (newnum, baseline, &to->ents[newindex], msg, true, qtv->pext);
newindex++; newindex++;
continue; continue;
@ -1403,7 +1403,7 @@ void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg)
for (i = 0; i < frame->numents; i++) for (i = 0; i < frame->numents; i++)
{ {
entnum = frame->entnums[i]; entnum = frame->entnums[i];
SV_WriteDelta(entnum, &qtv->map.entity[entnum].baseline, &frame->ents[i], msg, true); SV_WriteDelta(entnum, &qtv->map.entity[entnum].baseline, &frame->ents[i], msg, true, qtv->pext);
} }
WriteShort(msg, 0); WriteShort(msg, 0);
} }
@ -1448,9 +1448,9 @@ void SendLocalPlayerState(sv_t *tv, viewer_t *v, int playernum, netmsg_t *msg)
flags |= (PF_VELOCITY1<<j); flags |= (PF_VELOCITY1<<j);
WriteShort(msg, flags); WriteShort(msg, flags);
WriteShort(msg, tv->map.players[tv->map.thisplayer].current.origin[0]); WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[0], tv->pext);
WriteShort(msg, tv->map.players[tv->map.thisplayer].current.origin[1]); WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[1], tv->pext);
WriteShort(msg, tv->map.players[tv->map.thisplayer].current.origin[2]); WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[2], tv->pext);
WriteByte(msg, tv->map.players[tv->map.thisplayer].current.frame); WriteByte(msg, tv->map.players[tv->map.thisplayer].current.frame);
for (j=0 ; j<3 ; j++) for (j=0 ; j<3 ; j++)
@ -1475,9 +1475,9 @@ void SendLocalPlayerState(sv_t *tv, viewer_t *v, int playernum, netmsg_t *msg)
flags |= (PF_VELOCITY1<<j); flags |= (PF_VELOCITY1<<j);
WriteShort(msg, flags); WriteShort(msg, flags);
WriteShort(msg, v->origin[0]*8); WriteCoord(msg, v->origin[0], tv->pext);
WriteShort(msg, v->origin[1]*8); WriteCoord(msg, v->origin[1], tv->pext);
WriteShort(msg, v->origin[2]*8); WriteCoord(msg, v->origin[2], tv->pext);
WriteByte(msg, 0); WriteByte(msg, 0);
for (j=0 ; j<3 ; j++) for (j=0 ; j<3 ; j++)
@ -1628,7 +1628,7 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
usercmd_t to; usercmd_t to;
float lerp; float lerp;
int bits; int bits;
unsigned short org[3]; float org[3];
entity_t *ent; entity_t *ent;
playerinfo_t *pl; playerinfo_t *pl;
@ -1712,17 +1712,17 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (bits & UNQ_EFFECTS) if (bits & UNQ_EFFECTS)
WriteByte (msg, 0); WriteByte (msg, 0);
if (bits & UNQ_ORIGIN1) if (bits & UNQ_ORIGIN1)
WriteShort (msg, v->origin[0]*8); WriteCoord (msg, v->origin[0], tv->pext);
if (bits & UNQ_ANGLE1) if (bits & UNQ_ANGLE1)
WriteByte(msg, -(v->ucmds[2].angles[0]>>8)); WriteAngle(msg, -(360.0*v->ucmds[2].angles[0])/0x10000, tv->pext);
if (bits & UNQ_ORIGIN2) if (bits & UNQ_ORIGIN2)
WriteShort (msg, v->origin[1]*8); WriteCoord (msg, v->origin[1], tv->pext);
if (bits & UNQ_ANGLE2) if (bits & UNQ_ANGLE2)
WriteByte(msg, v->ucmds[2].angles[1]>>8); WriteAngle(msg, (360.0*v->ucmds[2].angles[1])/0x10000, tv->pext);
if (bits & UNQ_ORIGIN3) if (bits & UNQ_ORIGIN3)
WriteShort (msg, v->origin[2]*8); WriteCoord (msg, v->origin[2], tv->pext);
if (bits & UNQ_ANGLE3) if (bits & UNQ_ANGLE3)
WriteByte(msg, v->ucmds[2].angles[2]>>8); WriteAngle(msg, (360.0*v->ucmds[2].angles[2])/0x10000, tv->pext);
continue; continue;
} }
@ -1800,17 +1800,17 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (bits & UNQ_EFFECTS) if (bits & UNQ_EFFECTS)
WriteByte (msg, pl->current.effects); WriteByte (msg, pl->current.effects);
if (bits & UNQ_ORIGIN1) if (bits & UNQ_ORIGIN1)
WriteShort (msg, org[0]); WriteCoord (msg, org[0], tv->pext);
if (bits & UNQ_ANGLE1) if (bits & UNQ_ANGLE1)
WriteByte(msg, -(pl->current.angles[0]>>8)); WriteAngle(msg, -(360.0*pl->current.angles[0])/0x10000, tv->pext);
if (bits & UNQ_ORIGIN2) if (bits & UNQ_ORIGIN2)
WriteShort (msg, org[1]); WriteCoord (msg, org[1], tv->pext);
if (bits & UNQ_ANGLE2) if (bits & UNQ_ANGLE2)
WriteByte(msg, pl->current.angles[1]>>8); WriteAngle(msg, (360.0*pl->current.angles[1])/0x10000, tv->pext);
if (bits & UNQ_ORIGIN3) if (bits & UNQ_ORIGIN3)
WriteShort (msg, org[2]); WriteCoord (msg, org[2], tv->pext);
if (bits & UNQ_ANGLE3) if (bits & UNQ_ANGLE3)
WriteByte(msg, pl->current.angles[2]>>8); WriteAngle(msg, (360.0*pl->current.angles[2])/0x10000, tv->pext);
} }
@ -1928,9 +1928,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
WriteShort (msg,UNQ_MOREBITS|UNQ_MODEL|UNQ_ORIGIN1 | UNQ_ORIGIN2 | UNQ_ORIGIN3 | UNQ_SIGNAL); WriteShort (msg,UNQ_MOREBITS|UNQ_MODEL|UNQ_ORIGIN1 | UNQ_ORIGIN2 | UNQ_ORIGIN3 | UNQ_SIGNAL);
WriteByte (msg, v->thisplayer+1); WriteByte (msg, v->thisplayer+1);
WriteByte (msg, 2); //model WriteByte (msg, 2); //model
WriteShort (msg, v->origin[0]); WriteCoord (msg, v->origin[0], tv->pext);
WriteShort (msg, v->origin[1]); WriteCoord (msg, v->origin[1], tv->pext);
WriteShort (msg, v->origin[2]); WriteCoord (msg, v->origin[2], tv->pext);
} }
} }
@ -1961,7 +1961,7 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg)
int i; int i;
usercmd_t to; usercmd_t to;
unsigned short flags; unsigned short flags;
short interp; float interp;
float lerp; float lerp;
int track; int track;
@ -2065,18 +2065,18 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg)
(tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1])*(tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1]) > snapdist || (tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1])*(tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1]) > snapdist ||
(tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2])*(tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2]) > snapdist) (tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2])*(tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2]) > snapdist)
{ //teleported (or respawned), so don't interpolate { //teleported (or respawned), so don't interpolate
WriteShort(msg, tv->map.players[i].current.origin[0]); WriteCoord(msg, tv->map.players[i].current.origin[0], tv->pext);
WriteShort(msg, tv->map.players[i].current.origin[1]); WriteCoord(msg, tv->map.players[i].current.origin[1], tv->pext);
WriteShort(msg, tv->map.players[i].current.origin[2]); WriteCoord(msg, tv->map.players[i].current.origin[2], tv->pext);
} }
else else
{ //send interpolated angles { //send interpolated angles
interp = (lerp)*tv->map.players[i].current.origin[0] + (1-lerp)*tv->map.players[i].old.origin[0]; interp = (lerp)*tv->map.players[i].current.origin[0] + (1-lerp)*tv->map.players[i].old.origin[0];
WriteShort(msg, interp); WriteCoord(msg, interp, tv->pext);
interp = (lerp)*tv->map.players[i].current.origin[1] + (1-lerp)*tv->map.players[i].old.origin[1]; interp = (lerp)*tv->map.players[i].current.origin[1] + (1-lerp)*tv->map.players[i].old.origin[1];
WriteShort(msg, interp); WriteCoord(msg, interp, tv->pext);
interp = (lerp)*tv->map.players[i].current.origin[2] + (1-lerp)*tv->map.players[i].old.origin[2]; interp = (lerp)*tv->map.players[i].current.origin[2] + (1-lerp)*tv->map.players[i].old.origin[2];
WriteShort(msg, interp); WriteCoord(msg, interp, tv->pext);
} }
WriteByte(msg, tv->map.players[i].current.frame); WriteByte(msg, tv->map.players[i].current.frame);
@ -2329,13 +2329,13 @@ void PMove(viewer_t *v, usercmd_t *cmd)
pmove_t pmove; pmove_t pmove;
if (v->server && v->server->controller == v) if (v->server && v->server->controller == v)
{ {
v->origin[0] = v->server->map.players[v->server->map.thisplayer].current.origin[0]/8.0f; v->origin[0] = v->server->map.players[v->server->map.thisplayer].current.origin[0];
v->origin[1] = v->server->map.players[v->server->map.thisplayer].current.origin[1]/8.0f; v->origin[1] = v->server->map.players[v->server->map.thisplayer].current.origin[1];
v->origin[2] = v->server->map.players[v->server->map.thisplayer].current.origin[2]/8.0f; v->origin[2] = v->server->map.players[v->server->map.thisplayer].current.origin[2];
v->velocity[0] = v->server->map.players[v->server->map.thisplayer].current.velocity[2]/8.0f; v->velocity[0] = v->server->map.players[v->server->map.thisplayer].current.velocity[0];
v->velocity[1] = v->server->map.players[v->server->map.thisplayer].current.velocity[2]/8.0f; v->velocity[1] = v->server->map.players[v->server->map.thisplayer].current.velocity[1];
v->velocity[2] = v->server->map.players[v->server->map.thisplayer].current.velocity[2]/8.0f; v->velocity[2] = v->server->map.players[v->server->map.thisplayer].current.velocity[2];
return; return;
} }
pmove.origin[0] = v->origin[0]; pmove.origin[0] = v->origin[0];
@ -4230,6 +4230,7 @@ void QW_ProcessUDPPacket(cluster_t *cluster, netmsg_t *m, netadr_t from)
int passwd = ReadLong(m); int passwd = ReadLong(m);
//fte extension, sent so that dual-protocol servers will not create connections for dual-protocol clients //fte extension, sent so that dual-protocol servers will not create connections for dual-protocol clients
//the nqconnect command disables this (as well as the qw hand shake) if you really want to use nq protocols with fte clients
ReadString(m, tempbuffer, sizeof(tempbuffer)); ReadString(m, tempbuffer, sizeof(tempbuffer));
if (!strncmp(tempbuffer, "getchallenge", 12)) if (!strncmp(tempbuffer, "getchallenge", 12))
break; break;

View file

@ -937,7 +937,7 @@ static void SCR_NetStats(int x, int y, float period, vmnetinfo_t *netinfo)
static float ping_dev; static float ping_dev;
static float f_min, f_max, f_avg; static float f_min, f_max, f_avg;
static int lost_lost, lost_delta, lost_rate, lost_total; static int lost_lost, lost_delta, lost_rate, lost_total;
static int size_all, size_in, size_out; static int size_all, size_in, size_out, pps_in, pps_out;
static int bandwidth_all, bandwidth_in, bandwidth_out; static int bandwidth_all, bandwidth_in, bandwidth_out;
static int with_delta; static int with_delta;
@ -982,6 +982,9 @@ static void SCR_NetStats(int x, int y, float period, vmnetinfo_t *netinfo)
clamp(lost_delta, 0, 100); clamp(lost_delta, 0, 100);
clamp(lost_total, 0, 100); clamp(lost_total, 0, 100);
pps_in = netinfo->clrate.in_pps;
pps_out = netinfo->clrate.out_pps;
//per packet sizes //per packet sizes
size_in = (int)(netinfo->clrate.in_bps/netinfo->clrate.in_pps + 0.5); size_in = (int)(netinfo->clrate.in_bps/netinfo->clrate.in_pps + 0.5);
size_out = (int)(netinfo->clrate.out_bps/netinfo->clrate.out_pps + 0.5); size_out = (int)(netinfo->clrate.out_bps/netinfo->clrate.out_pps + 0.5);
@ -1047,15 +1050,15 @@ static void SCR_NetStats(int x, int y, float period, vmnetinfo_t *netinfo)
Draw_Alt_String(x+4, y, "packet size/BPS"); Draw_Alt_String(x+4, y, "packet size/BPS");
y+=12; y+=12;
snprintf(line, sizeof (line), "out %3d %5d", size_out, bandwidth_out); snprintf(line, sizeof (line), "out %3d %5d %d", size_out, bandwidth_out, pps_out);
Draw_String(x, y, line); Draw_String(x, y, line);
y+=8; y+=8;
snprintf(line, sizeof (line), "in %3d %5d", size_in, bandwidth_in); snprintf(line, sizeof (line), "in %3d %5d %3d", size_in, bandwidth_in, pps_in);
Draw_String(x, y, line); Draw_String(x, y, line);
y+=8; y+=8;
snprintf(line, sizeof (line), "total %3d %5d", size_all, bandwidth_all); snprintf(line, sizeof (line), "total %3d %5d %3d", size_all, bandwidth_all, pps_in+pps_out);
Draw_String(x, y, line); Draw_String(x, y, line);
y+=8; y+=8;
} }