qwsvdef.h is no more. Many files changed because of this.

enabled ssl support in windows for plugins.
updated jabber plugin.
tweaked downloading logic in an effort to end the madness.
Updated sql code to support sleeping the qc thread until query completion, as a more readable alternative to callbacks.
Client updates should be more explicit now, removing a potential bug.
networked terrain editing should now be in a better state.
updated the dir command to show paths too (so when the same file is listed twice, the pak its in will at least be different). Many files changed because of this.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4273 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-03-31 04:21:08 +00:00
parent fed1fb62a7
commit 6a831e2f99
84 changed files with 2998 additions and 2482 deletions

View file

@ -564,9 +564,21 @@ SERVERONLY_OBJS = \
WINDOWSSERVERONLY_OBJS = \ WINDOWSSERVERONLY_OBJS = \
svmodel.o \ svmodel.o \
net_ssl_winsspi.o \
sv_sys_win.o \ sv_sys_win.o \
sys_win_threads.o sys_win_threads.o
WINDOWS_OBJS = \
snd_win.o \
snd_directx.o \
cd_win.o \
fs_win32.o \
in_win.o \
sys_win.o \
sys_win_threads.o \
net_ssl_winsspi.o \
$(LTO_END) resources.o $(LTO_START)
COMMON_OBJS = \ COMMON_OBJS = \
gl_alias.o \ gl_alias.o \
gl_heightmap.o \ gl_heightmap.o \
@ -839,13 +851,13 @@ ifeq ($(FTE_TARGET),vc)
GLCL_DIR=glcl_vc$(BITS) GLCL_DIR=glcl_vc$(BITS)
GL_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows GL_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows
GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/" GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/"
GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) gl_vidnt.o snd_win.o snd_directx.o cd_win.o fs_win32.o in_win.o sys_win.o sys_win_threads.o resources.o GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS)
GL_OBJS= GL_OBJS=
MINGL_DIR=mingl_vc$(BITS) MINGL_DIR=mingl_vc$(BITS)
MINGL_EXE_NAME=../fteminglqw$(BITS).exe MINGL_EXE_NAME=../fteminglqw$(BITS).exe
D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS)
D3D_EXE_NAME=../fted3dqw$(BITS).exe D3D_EXE_NAME=../fted3dqw$(BITS).exe
D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe
D3D_LDFLAGS=$(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows D3D_LDFLAGS=$(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows
@ -854,7 +866,7 @@ ifeq ($(FTE_TARGET),vc)
D3DCL_DIR=d3dcl_vc$(BITS) D3DCL_DIR=d3dcl_vc$(BITS)
M_EXE_NAME=../fteqw$(BITS).exe M_EXE_NAME=../fteqw$(BITS).exe
MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(D3DQUAKE_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o resources.o MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(D3DQUAKE_OBJS) $(GLQUAKE_OBJS) gl_vidnt.o $(SPEEX_OBJS) $(WINDOWS_OBJS)
M_CFLAGS=$(D3DCFLAGS) $(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/" M_CFLAGS=$(D3DCFLAGS) $(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/"
MB_DIR=m_vc$(BITS) MB_DIR=m_vc$(BITS)
M_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows M_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows
@ -889,32 +901,32 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START)
GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START) GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS)
GL_EXE_NAME=../fteglqw$(BITS).exe GL_EXE_NAME=../fteglqw$(BITS).exe
GLCL_EXE_NAME=../fteglqwcl$(BITS).exe GLCL_EXE_NAME=../fteglqwcl$(BITS).exe
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows
GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS)
GLB_DIR=gl_mgw$(BITS) GLB_DIR=gl_mgw$(BITS)
GLCL_DIR=glcl_mgw$(BITS) GLCL_DIR=glcl_mgw$(BITS)
NPFTE_OBJS=httpclient.o image.o sys_win_threads.o sys_npfte.o sys_axfte.o sys_plugfte.o $(LTO_END) npplug.o ../../ftequake/npapi.def $(LTO_START) NPFTE_OBJS=httpclient.o image.o sys_win_threads.o sys_npfte.o sys_axfte.o sys_plugfte.o $(LTO_END) npplug.o ../../ftequake/npapi.def $(LTO_START)
NPFTE_DLL_NAME=../npfte$(BITS).dll NPFTE_DLL_NAME=../npfte$(BITS).dll
NPFTE_LDFLAGS=-Wl,--enable-stdcall-fixup $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -loleaut32 -luuid -lstdc++ -shared NPFTE_LDFLAGS=-Wl,--enable-stdcall-fixup $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -loleaut32 -luuid -lstdc++ -shared -Wl,--subsystem,windows
NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD
NPFTEB_DIR=npfte_mgw$(BITS) NPFTEB_DIR=npfte_mgw$(BITS)
MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START) MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS)
M_EXE_NAME=../fteqw$(BITS).exe M_EXE_NAME=../fteqw$(BITS).exe
MCL_EXE_NAME=../fteqwcl$(BITS).exe MCL_EXE_NAME=../fteqwcl$(BITS).exe
M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows
M_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) M_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS)
MB_DIR=m_mgw$(BITS) MB_DIR=m_mgw$(BITS)
MCL_DIR=mcl_mgw$(BITS) MCL_DIR=mcl_mgw$(BITS)
D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS)
D3D_EXE_NAME=../fted3dqw$(BITS).exe D3D_EXE_NAME=../fted3dqw$(BITS).exe
D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe
D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows
D3D_CFLAGS=$(D3DCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) D3D_CFLAGS=$(D3DCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS)
D3DB_DIR=d3d_mgw$(BITS) D3DB_DIR=d3d_mgw$(BITS)
D3DCL_DIR=d3dcl_mgw$(BITS) D3DCL_DIR=d3dcl_mgw$(BITS)

View file

@ -2066,7 +2066,7 @@ void CL_QTVPlay_f (void)
if (connrequest) if (connrequest)
host = connrequest+1; host = connrequest+1;
Q_strncpyz(qtvhostname, host, sizeof(qtvhostname)); Q_strncpyz(qtvhostname, host, sizeof(qtvhostname));
newf = FS_OpenTCP(qtvhostname); newf = FS_OpenTCP(qtvhostname, 27599);
if (!newf) if (!newf)
{ {
@ -2148,7 +2148,7 @@ void CL_QTVList_f (void)
{ {
char *connrequest; char *connrequest;
vfsfile_t *newf; vfsfile_t *newf;
newf = FS_OpenTCP(qtvhostname); newf = FS_OpenTCP(qtvhostname, 27599);
if (!newf) if (!newf)
{ {
@ -2182,7 +2182,7 @@ void CL_QTVDemos_f (void)
{ {
char *connrequest; char *connrequest;
vfsfile_t *newf; vfsfile_t *newf;
newf = FS_OpenTCP(Cmd_Argv(1)); newf = FS_OpenTCP(Cmd_Argv(1), 27599);
if (!newf) if (!newf)
{ {

View file

@ -971,7 +971,7 @@ void CL_IRCConnect_f (void)
{ {
CL_Disconnect_f (); CL_Disconnect_f ();
if (FTENET_AddToCollection(cls.sockets, "TCP", Cmd_Argv(2), FTENET_IRCConnect_EstablishConnection, false)) if (FTENET_AddToCollection(cls.sockets, "TCP", Cmd_Argv(2), NA_IRC, false))
{ {
char *server; char *server;
server = Cmd_Argv (1); server = Cmd_Argv (1);
@ -1307,7 +1307,7 @@ void CL_Disconnect (void)
#ifdef TCPCONNECT #ifdef TCPCONNECT
//disconnects it, without disconnecting the others. //disconnects it, without disconnecting the others.
FTENET_AddToCollection(cls.sockets, "TCP", NULL, NULL, false); FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, false);
#endif #endif
Cvar_ForceSet(&cl_servername, "none"); Cvar_ForceSet(&cl_servername, "none");
@ -2855,11 +2855,17 @@ qboolean CL_AllowArbitaryDownload(char *localfile)
{ {
char *ext = COM_FileExtension(localfile); char *ext = COM_FileExtension(localfile);
if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4")) if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4"))
allow = true; return true;
else else
allow = false; {
Con_Printf("Ignoring non-package download redirection to \"%s\"\n", localfile);
return false;
} }
return !!allow; }
if (allow)
return true;
Con_Printf("Ignoring download redirection to \"%s\". This server may require you to set cl_download_redirection to 2.\n", localfile);
return false;
} }
/* /*
@ -2952,10 +2958,7 @@ void CL_DownloadSize_f(void)
redirection = Cmd_Argv(3); redirection = Cmd_Argv(3);
if (!CL_AllowArbitaryDownload(redirection)) if (!CL_AllowArbitaryDownload(redirection))
{
Con_Printf("Ignoring redirection of %s to %s\n", rname, redirection);
return; return;
}
dl = CL_DownloadFailed(rname, false); dl = CL_DownloadFailed(rname, false);
Con_DPrintf("Download of \"%s\" redirected to \"%s\".\n", rname, redirection); Con_DPrintf("Download of \"%s\" redirected to \"%s\".\n", rname, redirection);

View file

@ -1650,6 +1650,8 @@ int CL_DownloadRate(void)
return cls.downloadedbytes/(Sys_DoubleTime() - cls.downloadstarttime); return cls.downloadedbytes/(Sys_DoubleTime() - cls.downloadstarttime);
} }
qboolean CL_AllowArbitaryDownload(char *localfile);
void CL_ParseChunkedDownload(void) void CL_ParseChunkedDownload(void)
{ {
qbyte *svname; qbyte *svname;
@ -1659,7 +1661,7 @@ void CL_ParseChunkedDownload(void)
char data[DLBLOCKSIZE]; char data[DLBLOCKSIZE];
chunknum = MSG_ReadLong(); chunknum = MSG_ReadLong();
if (chunknum < 0) if (chunknum == -1)
{ {
totalsize = MSG_ReadLong(); totalsize = MSG_ReadLong();
svname = MSG_ReadString(); svname = MSG_ReadString();
@ -1680,7 +1682,17 @@ void CL_ParseChunkedDownload(void)
if (totalsize < 0) if (totalsize < 0)
{ {
if (totalsize == -3) if (totalsize == -4)
{
if (CL_AllowArbitaryDownload(svname))
{
Con_Printf("Download of \"%s\" redirected to \"%s\"\n", cls.downloadremotename, svname);
if (CL_CheckOrEnqueDownloadFile(svname, NULL, 0))
Con_Printf("However, \"%s\" already exists. You may need to delete it.\n", svname);
}
svname = cls.downloadremotename;
}
else if (totalsize == -3)
Con_Printf("Server reported an error when downloading file \"%s\"\n", svname); Con_Printf("Server reported an error when downloading file \"%s\"\n", svname);
else if (totalsize == -2) else if (totalsize == -2)
Con_Printf("Server permissions deny downloading file \"%s\"\n", svname); Con_Printf("Server permissions deny downloading file \"%s\"\n", svname);
@ -1698,7 +1710,10 @@ void CL_ParseChunkedDownload(void)
Host_EndGame("Received second download - \"%s\"\n", svname); Host_EndGame("Received second download - \"%s\"\n", svname);
if (stricmp(cls.downloadremotename, svname)) if (stricmp(cls.downloadremotename, svname))
{
//fixme: we should allow extension changes, in the case of ogg/mp3/wav, or tga/png/jpg/pcx, or the addition of .gz or whatever
Host_EndGame("Server sent the wrong download - \"%s\" instead of \"%s\"\n", svname, cls.downloadremotename); Host_EndGame("Server sent the wrong download - \"%s\" instead of \"%s\"\n", svname, cls.downloadremotename);
}
//start the new download //start the new download
@ -1749,6 +1764,9 @@ void CL_ParseChunkedDownload(void)
MSG_ReadData(data, DLBLOCKSIZE); MSG_ReadData(data, DLBLOCKSIZE);
if (chunknum*DLBLOCKSIZE > downloadsize+DLBLOCKSIZE)
return;
if (!cls.downloadqw) if (!cls.downloadqw)
return; return;

View file

@ -141,7 +141,7 @@ void Plug_DrawReloadImages(void)
} }
} }
void Plug_FreePlugImages(plugin_t *plug) static void Plug_FreePlugImages(plugin_t *plug)
{ {
int i; int i;
for (i = 0; i < pluginimagearraylen; i++) for (i = 0; i < pluginimagearraylen; i++)
@ -277,8 +277,8 @@ qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qintptr_t
if (VM_OOB(arg[1], arg[2]*4)) if (VM_OOB(arg[1], arg[2]*4))
return 0; return 0;
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE || !cls.state)
return false; return 0;
max = pluginstats; max = pluginstats;
if (max > MAX_CL_STATS) if (max > MAX_CL_STATS)
@ -536,7 +536,12 @@ void Plug_Client_Close(plugin_t *plug)
} }
} }
void Plug_Client_Shutdown(void)
{
BZ_Free(pluginimagearray);
pluginimagearray = NULL;
pluginimagearraylen = 0;
}

View file

@ -768,7 +768,9 @@ extern cvar_t ruleset_allow_sensative_texture_replacements;
extern cvar_t ruleset_allow_localvolume; extern cvar_t ruleset_allow_localvolume;
extern cvar_t ruleset_allow_shaders; extern cvar_t ruleset_allow_shaders;
#ifndef SERVERONLY
extern client_state_t cl; extern client_state_t cl;
#endif
typedef struct typedef struct
{ {

View file

@ -810,7 +810,7 @@ static int numbootdownloads;
#include "fs.h" #include "fs.h"
#ifdef AVAIL_ZLIB #ifdef AVAIL_ZLIB
extern searchpathfuncs_t zipfilefuncs; extern searchpathfuncs_t zipfilefuncs;
static int CL_BootDownload_Extract(const char *fname, int fsize, void *ptr) static int CL_BootDownload_Extract(const char *fname, int fsize, void *ptr, void *spath)
{ {
char buffer[512*1024]; char buffer[512*1024];
int read; int read;

View file

@ -412,7 +412,7 @@ void M_Media_Draw (void)
char compleatenamepath[MAX_OSPATH]; char compleatenamepath[MAX_OSPATH];
char compleatenamename[MAX_OSPATH]; char compleatenamename[MAX_OSPATH];
qboolean compleatenamemultiple; qboolean compleatenamemultiple;
int Com_CompleatenameCallback(const char *name, int size, void *data) int Com_CompleatenameCallback(const char *name, int size, void *data, void *spath)
{ {
if (*compleatenamename) if (*compleatenamename)
compleatenamemultiple = true; compleatenamemultiple = true;
@ -431,8 +431,8 @@ void Com_CompleateOSFileName(char *name)
ending[-1] = '\0'; //strip a slash ending[-1] = '\0'; //strip a slash
*compleatenamename='\0'; *compleatenamename='\0';
Sys_EnumerateFiles(NULL, va("%s*", name), Com_CompleatenameCallback, NULL); Sys_EnumerateFiles(NULL, va("%s*", name), Com_CompleatenameCallback, NULL, NULL);
Sys_EnumerateFiles(NULL, va("%s*.*", name), Com_CompleatenameCallback, NULL); Sys_EnumerateFiles(NULL, va("%s*.*", name), Com_CompleatenameCallback, NULL, NULL);
if (*compleatenamename) if (*compleatenamename)
strcpy(name, compleatenamename); strcpy(name, compleatenamename);

View file

@ -188,7 +188,7 @@ typedef struct {
int match; int match;
} q2skinsearch_t; } q2skinsearch_t;
int q2skin_enumerate(const char *name, int fsize, void *parm) int q2skin_enumerate(const char *name, int fsize, void *parm, void *spath)
{ {
char blah[MAX_QPATH]; char blah[MAX_QPATH];
q2skinsearch_t *s = parm; q2skinsearch_t *s = parm;

View file

@ -494,7 +494,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key)
return false; return false;
} }
static int DemoAddItem(const char *filename, int size, void *parm) static int DemoAddItem(const char *filename, int size, void *parm, void *spath)
{ {
int extnum; int extnum;
demomenu_t *menu = parm; demomenu_t *menu = parm;
@ -667,7 +667,7 @@ static void ShowDemoMenu (menu_t *menu, char *path)
if (*path) if (*path)
{ {
Q_snprintfz(match, sizeof(match), "%s../", path); Q_snprintfz(match, sizeof(match), "%s../", path);
DemoAddItem(match, 0, menu->data); DemoAddItem(match, 0, menu->data, NULL);
} }
Q_snprintfz(match, sizeof(match), "%s*", path); Q_snprintfz(match, sizeof(match), "%s*", path);

View file

@ -176,6 +176,12 @@ typedef struct part_type_s {
int nummodels; int nummodels;
partmodels_t *models; partmodels_t *models;
char soundname[MAX_QPATH];
float soundvol;
float soundattn;
float sounddelay;
float soundpitch;
vec3_t rgb; //initial colour vec3_t rgb; //initial colour
float alpha; float alpha;
vec3_t rgbchange; //colour delta (per second) vec3_t rgbchange; //colour delta (per second)
@ -1401,6 +1407,23 @@ static void P_ParticleEffect_f(void)
else if (!strcmp(var, "nospreadlast")) else if (!strcmp(var, "nospreadlast"))
ptype->flags |= PT_NOSPREADLAST; ptype->flags |= PT_NOSPREADLAST;
else if (!strcmp(var, "sound"))
{
Q_strncpyz(ptype->soundname, value, sizeof(ptype->soundname));
ptype->soundvol = atof(Cmd_Argv(2));
if (!ptype->soundvol)
ptype->soundvol = 1;
ptype->soundattn = atof(Cmd_Argv(3));
if (!ptype->soundattn)
ptype->soundattn = 1;
ptype->soundpitch = atof(Cmd_Argv(4));
if (!ptype->soundpitch)
ptype->soundpitch = 100;
ptype->sounddelay = atof(Cmd_Argv(5));
if (!ptype->sounddelay)
ptype->sounddelay = 0;
}
else if (!strcmp(var, "lightradius")) else if (!strcmp(var, "lightradius"))
ptype->dl_radius = atof(value); ptype->dl_radius = atof(value);
else if (!strcmp(var, "lightradiusfade")) else if (!strcmp(var, "lightradiusfade"))
@ -1554,13 +1577,16 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen); Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen);
if (ptype->assoc != P_INVALID) if (ptype->assoc != P_INVALID)
Q_strncatz(outstr, va("assoc %s\n", part_type[ptype->assoc].name), outstrlen); Q_strncatz(outstr, va("assoc \"%s\"\n", part_type[ptype->assoc].name), outstrlen);
Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen); Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen);
Q_strncatz(outstr, va("rotationstart %g %g\n", ptype->rotationstartmin*180/M_PI, (ptype->rotationstartmin+ptype->rotationstartrand)*180/M_PI), outstrlen); Q_strncatz(outstr, va("rotationstart %g %g\n", ptype->rotationstartmin*180/M_PI, (ptype->rotationstartmin+ptype->rotationstartrand)*180/M_PI), outstrlen);
Q_strncatz(outstr, va("rotationspeed %g %g\n", ptype->rotationmin*180/M_PI, (ptype->rotationmin+ptype->rotationrand)*180/M_PI), outstrlen); Q_strncatz(outstr, va("rotationspeed %g %g\n", ptype->rotationmin*180/M_PI, (ptype->rotationmin+ptype->rotationrand)*180/M_PI), outstrlen);
if (ptype->soundvol)
Q_strncatz(outstr, va("sound \"%s\" %g %g %g %g\n", ptype->soundname, ptype->soundvol, ptype->soundattn, ptype->soundpitch, ptype->sounddelay), outstrlen);
if (ptype->dl_radius) if (ptype->dl_radius)
{ {
Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius), outstrlen); Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius), outstrlen);
@ -2994,6 +3020,10 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in
if (ptype->dl_cubemapnum) if (ptype->dl_cubemapnum)
snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum); snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum);
} }
if (*ptype->soundname)
{
S_StartSound(0, 0, S_PrecacheSound(ptype->soundname), org, ptype->soundvol, ptype->soundattn, ptype->sounddelay, ptype->soundpitch);
}
if (ptype->stain_radius) if (ptype->stain_radius)
R_AddStain(org, ptype->stain_rgb[0], ptype->stain_rgb[1], ptype->stain_rgb[2], ptype->stain_radius); R_AddStain(org, ptype->stain_rgb[0], ptype->stain_rgb[1], ptype->stain_rgb[2], ptype->stain_radius);
} }

View file

@ -1056,7 +1056,6 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (csqc_poly_flags & 4) if (csqc_poly_flags & 4)
{ {
mesh_t mesh; mesh_t mesh;
int i;
memset(&mesh, 0, sizeof(mesh)); memset(&mesh, 0, sizeof(mesh));
mesh.colors4f_array = cl_strisvertc + csqc_poly_startvert; mesh.colors4f_array = cl_strisvertc + csqc_poly_startvert;

View file

@ -211,7 +211,7 @@ cvar_t vid_width = CVARF ("vid_width", "0",
CVAR_ARCHIVE | CVAR_RENDERERLATCH); CVAR_ARCHIVE | CVAR_RENDERERLATCH);
cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context."); cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context.");
cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue. Value 4=red/green"); cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain.");
extern cvar_t r_dodgytgafiles; extern cvar_t r_dodgytgafiles;
extern cvar_t r_dodgypcxfiles; extern cvar_t r_dodgypcxfiles;

View file

@ -775,7 +775,7 @@ qboolean S_LoadSound (sfx_t *s)
return false; //it failed to load once before, don't bother trying again. return false; //it failed to load once before, don't bother trying again.
// see if still in memory // see if still in memory
if (s->decoder.buf) if (s->decoder.buf || s->decoder.decodedata)
return true; return true;
if (name[1] == ':' && name[2] == '\\') if (name[1] == ':' && name[2] == '\\')

View file

@ -468,7 +468,7 @@ void Sys_SaveClipboard(char *text)
{ {
} }
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
DIR *dir; DIR *dir;
char apath[MAX_OSPATH]; char apath[MAX_OSPATH];
@ -526,7 +526,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
{ {
Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":"");
if (!func(file, st.st_size, parm)) if (!func(file, st.st_size, parm, spath))
{ {
closedir(dir); closedir(dir);
return false; return false;

View file

@ -144,7 +144,7 @@ void Sys_Quit (void)
//SDL provides no file enumeration facilities. //SDL provides no file enumeration facilities.
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
HANDLE r; HANDLE r;
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;
@ -191,7 +191,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
if (wildcmp(match, fd.cFileName)) if (wildcmp(match, fd.cFileName))
{ {
Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
else else
@ -199,7 +199,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
if (wildcmp(match, fd.cFileName)) if (wildcmp(match, fd.cFileName))
{ {
Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
} }
@ -210,7 +210,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
} }
#elif defined(linux) || defined(__unix__) #elif defined(linux) || defined(__unix__)
#include <dirent.h> #include <dirent.h>
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
DIR *dir; DIR *dir;
char apath[MAX_OSPATH]; char apath[MAX_OSPATH];
@ -268,7 +268,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
{ {
Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":"");
if (!func(file, st.st_size, parm)) if (!func(file, st.st_size, parm, spath))
{ {
closedir(dir); closedir(dir);
return false; return false;
@ -284,7 +284,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
return true; return true;
} }
#else #else
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
Con_Printf("Warning: Sys_EnumerateFiles not implemented\n"); Con_Printf("Warning: Sys_EnumerateFiles not implemented\n");
return false; return false;

View file

@ -568,6 +568,7 @@ DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exception
BOOL (WINAPI *pIsDebuggerPresent)(void); BOOL (WINAPI *pIsDebuggerPresent)(void);
#ifdef PRINTGLARRAYS #ifdef PRINTGLARRAYS
if (qrenderer == QR_OPENGL)
DumpGLState(); DumpGLState();
#endif #endif
@ -750,7 +751,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname)
return !rename(oldfname, newfname); return !rename(oldfname, newfname);
} }
static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (*func)(const char *, int, void *), void *parm) static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath)
{ {
HANDLE r; HANDLE r;
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;
@ -771,7 +772,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart
char file[MAX_OSPATH]; char file[MAX_OSPATH];
if (!wild) if (!wild)
return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm); return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm, spath);
if (nest-neststart+1> MAX_OSPATH) if (nest-neststart+1> MAX_OSPATH)
return 1; return 1;
@ -802,7 +803,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart
Q_snprintfz(file, sizeof(file), "%s%s/", tmproot, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s/", tmproot, fd.cFileName);
newnest = strlen(file); newnest = strlen(file);
strcpy(file+newnest, match+nest); strcpy(file+newnest, match+nest);
go = Sys_EnumerateFiles2(file, matchstart, newnest, func, parm); go = Sys_EnumerateFiles2(file, matchstart, newnest, func, parm, spath);
} }
} }
} }
@ -835,7 +836,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart
if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH) if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH)
{ {
Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
} }
@ -846,7 +847,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart
if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH) if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH)
{ {
Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
} }
@ -856,7 +857,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart
return go; return go;
} }
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath)
{ {
char fullmatch[MAX_OSPATH]; char fullmatch[MAX_OSPATH];
int start; int start;
@ -869,7 +870,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
fullmatch[start++] = '/'; fullmatch[start++] = '/';
fullmatch[start] = 0; fullmatch[start] = 0;
strcat(fullmatch, match); strcat(fullmatch, match);
return Sys_EnumerateFiles2(fullmatch, start, start, func, parm); return Sys_EnumerateFiles2(fullmatch, start, start, func, parm, spath);
} }
/* /*
@ -1077,6 +1078,10 @@ void VARGS Sys_Printf (char *fmt, ...)
char text[1024]; char text[1024];
DWORD dummy; DWORD dummy;
conchar_t msg[1024], *end, *in;
wchar_t wide[1024], *out;
int wlen;
if (!houtput && !debugout) if (!houtput && !debugout)
return; return;
@ -1084,24 +1089,24 @@ void VARGS Sys_Printf (char *fmt, ...)
vsnprintf (text, sizeof(text), fmt, argptr); vsnprintf (text, sizeof(text), fmt, argptr);
va_end (argptr); va_end (argptr);
if (debugout)
{
//msvc debug output
conchar_t msg[1024], *end, *in;
wchar_t wide[1024], *out;
end = COM_ParseFunString(CON_WHITEMASK, text, msg, sizeof(msg), false); end = COM_ParseFunString(CON_WHITEMASK, text, msg, sizeof(msg), false);
out = wide; out = wide;
in = msg; in = msg;
wlen = 0;
for (in = msg; in < end; in++) for (in = msg; in < end; in++)
{ {
if (!(*in & CON_HIDDEN)) if (!(*in & CON_HIDDEN))
{
*out++ = dequake(*in & CON_CHARMASK); *out++ = dequake(*in & CON_CHARMASK);
wlen++;
}
} }
*out = 0; *out = 0;
if (debugout)
OutputDebugStringW(wide); OutputDebugStringW(wide);
}
if (houtput) if (houtput)
WriteFile (houtput, text, strlen(text), &dummy, NULL); WriteConsoleW(houtput, wide, wlen, &dummy, NULL);
} }
void Sys_Quit (void) void Sys_Quit (void)
@ -1435,8 +1440,8 @@ char *Sys_ConsoleInput (void)
} }
} else if (ch >= ' ') } else if (ch >= ' ')
{ {
i = utf8_encode(text+len, ch, sizeof(text)-1-len); wchar_t wch = ch;
WriteFile(houtput, text+len, i, &dummy, NULL); WriteConsoleW(houtput, &wch, 1, &dummy, NULL);
len += i; len += i;
} }

View file

@ -1193,6 +1193,8 @@ entity_t *CL_EntityNum(int num)
float CalcFov (float fov_x, float width, float height); float CalcFov (float fov_x, float width, float height);
void SCR_VRectForPlayer(vrect_t *vrect, int pnum) void SCR_VRectForPlayer(vrect_t *vrect, int pnum)
{ {
float ws;
extern cvar_t r_stereo_method, r_stereo_separation;
#if MAX_SPLITS > 4 #if MAX_SPLITS > 4
#pragma warning "Please change this function to cope with the new MAX_SPLITS value" #pragma warning "Please change this function to cope with the new MAX_SPLITS value"
#endif #endif
@ -1250,15 +1252,19 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum)
if (cl.playerview[pnum].stats[STAT_VIEWZOOM]) if (cl.playerview[pnum].stats[STAT_VIEWZOOM])
r_refdef.fov_x *= cl.playerview[pnum].stats[STAT_VIEWZOOM]/255.0f; r_refdef.fov_x *= cl.playerview[pnum].stats[STAT_VIEWZOOM]/255.0f;
if (vrect->width < (vrect->height*640)/432) ws = 1;
if (r_stereo_method.ival == 5 && r_stereo_separation.value)
ws = 0.5;
if (ws*vrect->width < (vrect->height*640)/432)
{ {
r_refdef.fov_y = CalcFov(r_refdef.fov_x, (vrect->width*vid.pixelwidth)/vid.width, (vrect->height*vid.pixelheight)/vid.height); r_refdef.fov_y = CalcFov(r_refdef.fov_x, (ws*vrect->width*vid.pixelwidth)/vid.width, (vrect->height*vid.pixelheight)/vid.height);
// r_refdef.fov_x = CalcFov(r_refdef.fov_y, 432, 640); // r_refdef.fov_x = CalcFov(r_refdef.fov_y, 432, 640);
} }
else else
{ {
r_refdef.fov_y = CalcFov(r_refdef.fov_x, 640, 432); r_refdef.fov_y = CalcFov(r_refdef.fov_x, 640, 432);
r_refdef.fov_x = CalcFov(r_refdef.fov_y, vrect->height, vrect->width); r_refdef.fov_x = CalcFov(r_refdef.fov_y, vrect->height, vrect->width*ws);
} }
} }

View file

@ -103,6 +103,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AVAIL_D3D #define AVAIL_D3D
#endif #endif
#if defined(_WIN32) && !defined(_SDL)
#define HAVE_SSL
#endif
//#define DYNAMIC_ZLIB //#define DYNAMIC_ZLIB
//#define DYNAMIC_LIBPNG //#define DYNAMIC_LIBPNG
//#define DYNAMIC_LIBJPEG //#define DYNAMIC_LIBJPEG

View file

@ -2115,7 +2115,7 @@ static qboolean VARGS Mod_TryAddSkin(const char *skinname, ...)
return true; return true;
} }
int Mod_EnumerateSkins(const char *name, int size, void *param) int Mod_EnumerateSkins(const char *name, int size, void *param, void *spath)
{ {
Mod_TryAddSkin(name); Mod_TryAddSkin(name);
return true; return true;

View file

@ -2469,7 +2469,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
int decodeerror; int decodeerror;
char *end; char *end;
uc = utf8_decode(&decodeerror, str, &end); uc = utf8_decode(&decodeerror, str, &end);
if (decodeerror) if (decodeerror && !(utf8 & 2))
{ {
utf8 &= ~1; utf8 &= ~1;
//malformed encoding we just drop through and stop trying to decode. //malformed encoding we just drop through and stop trying to decode.
@ -2486,7 +2486,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
continue; continue;
} }
} }
if (*str == '^') if (*str == '^' && !(flags & PFS_NOMARKUP))
{ {
if (str[1] >= '0' && str[1] <= '9') if (str[1] >= '0' && str[1] <= '9')
{ {
@ -2664,7 +2664,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
continue; continue;
} }
} }
else if (*str == '&' && str[1] == 'c') else if (*str == '&' && str[1] == 'c' && !(flags & PFS_NOMARKUP))
{ {
// ezQuake color codes // ezQuake color codes
@ -2704,7 +2704,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
} }
} }
} }
else if (*str == '&' && str[1] == 'r') else if (*str == '&' && str[1] == 'r' && !(flags & PFS_NOMARKUP))
{ {
ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR)); ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR));
if (!keepmarkup) if (!keepmarkup)

View file

@ -292,8 +292,9 @@ void COM_ParsePlusSets (void);
typedef unsigned int conchar_t; typedef unsigned int conchar_t;
char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags); char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags);
#define PFS_KEEPMARKUP 1 #define PFS_KEEPMARKUP 1 //leave markup in the final string (but do parse it)
#define PFS_FORCEUTF8 2 #define PFS_FORCEUTF8 2 //force utf-8 decoding
#define PFS_NOMARKUP 4 //strip markup completely
conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator
unsigned int utf8_decode(int *error, const void *in, char **out); unsigned int utf8_decode(int *error, const void *in, char **out);
unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen); unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen);
@ -406,7 +407,7 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out
qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto); qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto);
vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
vfsfile_t *FS_OpenTemp(void); vfsfile_t *FS_OpenTemp(void);
vfsfile_t *FS_OpenTCP(const char *name); vfsfile_t *FS_OpenTCP(const char *name, int defaultport);
void FS_UnloadPackFiles(void); void FS_UnloadPackFiles(void);
void FS_ReloadPackFiles(void); void FS_ReloadPackFiles(void);
char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum);
@ -441,7 +442,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk);
qboolean COM_LoadMapPackFile(const char *name, int offset); qboolean COM_LoadMapPackFile(const char *name, int offset);
void COM_FlushTempoaryPacks(void); void COM_FlushTempoaryPacks(void);
void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm); void COM_EnumerateFiles (const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm);
extern struct cvar_s registered; extern struct cvar_s registered;
extern qboolean standard_quake; //fixme: remove extern qboolean standard_quake; //fixme: remove

View file

@ -227,9 +227,19 @@ COM_Dir_f
============ ============
*/ */
static int COM_Dir_List(const char *name, int size, void *parm) static int COM_Dir_List(const char *name, int size, void *parm, void *spath)
{ {
Con_Printf("%s (%i)\n", name, size); char pbuf[MAX_OSPATH] = "??";
searchpath_t *s;
for (s=com_searchpaths ; s ; s=s->next)
{
if (s->handle == spath)
{
s->funcs->GetDisplayPath(s->handle, pbuf, sizeof(pbuf));
break;
}
}
Con_Printf("%s (%i) (%s)\n", name, size, pbuf);
return 1; return 1;
} }
@ -693,7 +703,7 @@ char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean
// '*' prefix is meant to mean 'referenced'. // '*' prefix is meant to mean 'referenced'.
//really all that means to the client is that it definitely wants to download it. //really all that means to the client is that it definitely wants to download it.
//if its copyrighted, the client shouldn't try to do so, as it won't be allowed. //if its copyrighted, the client shouldn't try to do so, as it won't be allowed.
if (search->copyprotected) if (!search->copyprotected)
Q_strncatz(buffer, "*", buffersize); Q_strncatz(buffer, "*", buffersize);
} }
@ -1214,7 +1224,7 @@ void FS_FreeFile(void *file)
void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm) void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, void *), void *parm)
{ {
searchpath_t *search; searchpath_t *search;
for (search = com_searchpaths; search ; search = search->next) for (search = com_searchpaths; search ; search = search->next)
@ -1338,7 +1348,7 @@ typedef struct {
const char *puredesc; const char *puredesc;
} wildpaks_t; } wildpaks_t;
static int FS_AddWildDataFiles (const char *descriptor, int size, void *vparam) static int FS_AddWildDataFiles (const char *descriptor, int size, void *vparam, struct searchpath_s *path)
{ {
wildpaks_t *param = vparam; wildpaks_t *param = vparam;
vfsfile_t *vfs; vfsfile_t *vfs;

View file

@ -8,7 +8,7 @@ extern hashtable_t filesystemhash; //this table is the one to build your hash re
extern int fs_hash_dups; //for tracking efficiency. no functional use. extern int fs_hash_dups; //for tracking efficiency. no functional use.
extern int fs_hash_files; //for tracking efficiency. no functional use. extern int fs_hash_files; //for tracking efficiency. no functional use.
struct searchpath_s;
typedef struct { typedef struct {
void (*GetDisplayPath)(void *handle, char *outpath, unsigned int pathsize); void (*GetDisplayPath)(void *handle, char *outpath, unsigned int pathsize);
void (*ClosePath)(void *handle); void (*ClosePath)(void *handle);
@ -17,7 +17,7 @@ typedef struct {
//note that if rawfile and offset are set, many Com_FileOpens will read the raw file //note that if rawfile and offset are set, many Com_FileOpens will read the raw file
//otherwise ReadFile will be called instead. //otherwise ReadFile will be called instead.
void (*ReadFile)(void *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives) void (*ReadFile)(void *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives)
int (*EnumerateFiles)(void *handle, const char *match, int (*func)(const char *, int, void *), void *parm); int (*EnumerateFiles)(void *handle, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm);
void *(*OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path void *(*OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path

View file

@ -126,7 +126,7 @@ qboolean FSPAK_FLocate(void *handle, flocation_t *loc, const char *filename, voi
} }
return false; return false;
} }
int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm)
{ {
pack_t *pak = handle; pack_t *pak = handle;
int num; int num;
@ -135,7 +135,7 @@ int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const cha
{ {
if (wildcmp(match, pak->files[num].name)) if (wildcmp(match, pak->files[num].name))
{ {
if (!func(pak->files[num].name, pak->files[num].filelen, parm)) if (!func(pak->files[num].name, pak->files[num].filelen, parm, handle))
return false; return false;
} }
} }

View file

@ -240,7 +240,7 @@ static void *FSSTDIO_OpenPath(vfsfile_t *mustbenull, const char *desc)
} }
return np; return np;
} }
static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data) static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data, void *spath)
{ {
stdiopath_t *sp = data; stdiopath_t *sp = data;
if (filename[strlen(filename)-1] == '/') if (filename[strlen(filename)-1] == '/')
@ -248,7 +248,7 @@ static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data)
char childpath[256]; char childpath[256];
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
Sys_EnumerateFiles(sp->rootpath, childpath, FSSTDIO_RebuildFSHash, data); Sys_EnumerateFiles(sp->rootpath, childpath, FSSTDIO_RebuildFSHash, data, spath);
return true; return true;
} }
FS_AddFileHash(sp->depth, filename, NULL, sp); FS_AddFileHash(sp->depth, filename, NULL, sp);
@ -258,7 +258,7 @@ static void FSSTDIO_BuildHash(void *handle, int depth)
{ {
stdiopath_t *sp = handle; stdiopath_t *sp = handle;
sp->depth = depth; sp->depth = depth;
Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, handle); Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, handle, handle);
} }
static qboolean FSSTDIO_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult) static qboolean FSSTDIO_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult)
{ {
@ -326,10 +326,10 @@ static void FSSTDIO_ReadFile(void *handle, flocation_t *loc, char *buffer)
fclose(f); fclose(f);
} }
static int FSSTDIO_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) static int FSSTDIO_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm)
{ {
stdiopath_t *sp = handle; stdiopath_t *sp = handle;
return Sys_EnumerateFiles(sp->rootpath, match, func, parm); return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle);
} }
searchpathfuncs_t stdiofilefuncs = { searchpathfuncs_t stdiofilefuncs = {

View file

@ -243,7 +243,7 @@ static void *VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc)
} }
return np; return np;
} }
static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle) static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle, void *spath)
{ {
vfsw32path_t *wp = handle; vfsw32path_t *wp = handle;
if (filename[strlen(filename)-1] == '/') if (filename[strlen(filename)-1] == '/')
@ -251,7 +251,7 @@ static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle
char childpath[256]; char childpath[256];
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
Sys_EnumerateFiles(wp->rootpath, childpath, VFSW32_RebuildFSHash, wp); Sys_EnumerateFiles(wp->rootpath, childpath, VFSW32_RebuildFSHash, wp, handle);
return true; return true;
} }
@ -262,7 +262,7 @@ static void VFSW32_BuildHash(void *handle, int hashdepth)
{ {
vfsw32path_t *wp = handle; vfsw32path_t *wp = handle;
wp->hashdepth = hashdepth; wp->hashdepth = hashdepth;
Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, handle); Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, handle, handle);
} }
static qboolean VFSW32_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult) static qboolean VFSW32_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult)
{ {
@ -315,10 +315,10 @@ static void VFSW32_ReadFile(void *handle, flocation_t *loc, char *buffer)
fread(buffer, 1, loc->len, f); fread(buffer, 1, loc->len, f);
fclose(f); fclose(f);
} }
static int VFSW32_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) static int VFSW32_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm)
{ {
vfsw32path_t *wp = handle; vfsw32path_t *wp = handle;
return Sys_EnumerateFiles(wp->rootpath, match, func, parm); return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle);
} }

View file

@ -337,7 +337,7 @@ static void FSZIP_ReadFile(void *handle, flocation_t *loc, char *buffer)
return; return;
} }
static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm)
{ {
zipfile_t *zip = handle; zipfile_t *zip = handle;
int num; int num;
@ -346,7 +346,7 @@ static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(co
{ {
if (wildcmp(match, zip->files[num].name)) if (wildcmp(match, zip->files[num].name))
{ {
if (!func(zip->files[num].name, zip->files[num].filelen, parm)) if (!func(zip->files[num].name, zip->files[num].filelen, parm, handle))
return false; return false;
} }
} }

View file

@ -25,7 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define HAVE_WEBSOCKCL #define HAVE_WEBSOCKCL
#endif #endif
typedef enum {NA_INVALID, NA_LOOPBACK, NA_IP, NA_IPV6, NA_IPX, NA_BROADCAST_IP, NA_BROADCAST_IP6, NA_BROADCAST_IPX, NA_TCP, NA_TCPV6, NA_IRC, NA_WEBSOCKET} netadrtype_t; //FIXME: should split this into loopback/dgram/stream/irc
//with the ipv4/v6/x as a separate parameter
typedef enum {NA_INVALID, NA_LOOPBACK, NA_IP, NA_IPV6, NA_IPX, NA_BROADCAST_IP, NA_BROADCAST_IP6, NA_BROADCAST_IPX, NA_TCP, NA_TCPV6, NA_IRC, NA_WEBSOCKET, NA_NATPMP} netadrtype_t;
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t; typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
@ -80,8 +82,10 @@ int TCP_OpenStream (netadr_t remoteaddr); //makes things easier
struct ftenet_connections_s; struct ftenet_connections_s;
void NET_Init (void); void NET_Init (void);
void SVNET_RegisterCvars(void);
void NET_InitClient (void); void NET_InitClient (void);
void NET_InitServer (void); void NET_InitServer (void);
qboolean NET_WasSpecialPacket(void);
void NET_CloseServer (void); void NET_CloseServer (void);
void UDP_CloseSocket (int socket); void UDP_CloseSocket (int socket);
void NET_Shutdown (void); void NET_Shutdown (void);
@ -98,6 +102,7 @@ char *NET_AdrToString (char *s, int len, netadr_t a);
char *NET_BaseAdrToString (char *s, int len, netadr_t a); char *NET_BaseAdrToString (char *s, int len, netadr_t a);
qboolean NET_StringToSockaddr (const char *s, int defaultport, struct sockaddr_qstorage *sadr, int *addrfamily, int *addrsize); qboolean NET_StringToSockaddr (const char *s, int defaultport, struct sockaddr_qstorage *sadr, int *addrfamily, int *addrsize);
qboolean NET_StringToAdr (const char *s, int defaultport, netadr_t *a); qboolean NET_StringToAdr (const char *s, int defaultport, netadr_t *a);
qboolean NET_PortToAdr (int adrfamily, const char *s, netadr_t *a);
qboolean NET_IsClientLegal(netadr_t *adr); qboolean NET_IsClientLegal(netadr_t *adr);
qboolean NET_IsLoopBackAddress (netadr_t adr); qboolean NET_IsLoopBackAddress (netadr_t adr);
@ -107,9 +112,7 @@ char *NET_AdrToStringMasked (char *s, int len, netadr_t a, netadr_t amask);
void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits); void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits);
qboolean NET_CompareAdrMasked(netadr_t a, netadr_t b, netadr_t mask); qboolean NET_CompareAdrMasked(netadr_t a, netadr_t b, netadr_t mask);
qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, qboolean islisten);
struct ftenet_generic_connection_s *FTENET_IRCConnect_EstablishConnection(qboolean isserver, const char *address);
qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, struct ftenet_generic_connection_s *(*establish)(qboolean isserver, const char *address), qboolean islisten);
//============================================================================ //============================================================================

View file

@ -0,0 +1,624 @@
#include "quakedef.h"
#if defined(_WIN32) && !defined(_SDL) && defined(HAVE_SSL)
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
#include <sspi.h>
#include <schannel.h>
//hungarian ensures we hit no macros.
static struct
{
void *lib;
SECURITY_STATUS (WINAPI *pDecryptMessage) (PCtxtHandle,PSecBufferDesc,ULONG,PULONG);
SECURITY_STATUS (WINAPI *pEncryptMessage) (PCtxtHandle,ULONG,PSecBufferDesc,ULONG);
SECURITY_STATUS (WINAPI *pAcquireCredentialsHandleA) (SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp);
SECURITY_STATUS (WINAPI *pInitializeSecurityContextA) (PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
SECURITY_STATUS (WINAPI *pCompleteAuthToken) (PCtxtHandle,PSecBufferDesc);
SECURITY_STATUS (WINAPI *pQueryContextAttributesA) (PCtxtHandle,ULONG,PVOID);
SECURITY_STATUS (WINAPI *pFreeCredentialsHandle) (PCredHandle);
SECURITY_STATUS (WINAPI *pDeleteSecurityContext) (PCtxtHandle);
} secur;
static struct
{
void *lib;
BOOL (WINAPI *pCertGetCertificateChain) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*);
BOOL (WINAPI *pCertVerifyCertificateChainPolicy) (LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS);
void (WINAPI *pCertFreeCertificateChain) (PCCERT_CHAIN_CONTEXT);
} crypt;
static qboolean SSL_Init(void)
{
dllfunction_t secur_functable[] =
{
{(void**)&secur.pDecryptMessage, "DecryptMessage"},
{(void**)&secur.pEncryptMessage, "EncryptMessage"},
{(void**)&secur.pAcquireCredentialsHandleA, "AcquireCredentialsHandleA"},
{(void**)&secur.pInitializeSecurityContextA, "InitializeSecurityContextA"},
{(void**)&secur.pCompleteAuthToken, "CompleteAuthToken"},
{(void**)&secur.pQueryContextAttributesA, "QueryContextAttributesA"},
{(void**)&secur.pFreeCredentialsHandle, "FreeCredentialsHandle"},
{(void**)&secur.pDeleteSecurityContext, "DeleteSecurityContext"},
{NULL, NULL}
};
dllfunction_t crypt_functable[] =
{
{(void**)&crypt.pCertGetCertificateChain, "CertGetCertificateChain"},
{(void**)&crypt.pCertVerifyCertificateChainPolicy, "CertVerifyCertificateChainPolicy"},
{(void**)&crypt.pCertFreeCertificateChain, "CertFreeCertificateChain"},
{NULL, NULL}
};
if (!secur.lib)
secur.lib = Sys_LoadLibrary("secur32.dll", secur_functable);
if (!crypt.lib)
crypt.lib = Sys_LoadLibrary("crypt32.dll", crypt_functable);
return !!secur.lib && !!crypt.lib;
}
#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION)
struct sslbuf
{
char data[8192];
int avail;
int newd;
};
typedef struct {
vfsfile_t funcs;
vfsfile_t *stream;
wchar_t wpeername[256];
enum
{
HS_ESTABLISHED,
HS_STARTCLIENT,
HS_CLIENT,
HS_STARTSERVER,
HS_SERVER
} handshaking;
struct sslbuf outraw;
struct sslbuf outcrypt;
struct sslbuf inraw;
struct sslbuf incrypt;
CredHandle cred;
SecHandle sechnd;
int headersize, footersize;
char headerdata[1024], footerdata[1024];
} sslfile_t;
static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes)
{
if (bytes > sizeof(buf->data) - buf->avail)
bytes = sizeof(buf->data) - buf->avail;
memcpy(buf->data + buf->avail, data, bytes);
buf->avail += bytes;
return bytes;
}
static void SSPI_Error(sslfile_t *f, char *error)
{
Sys_Printf("%s", error);
if (f->stream)
VFS_CLOSE(f->stream);
secur.pDeleteSecurityContext(&f->sechnd);
secur.pFreeCredentialsHandle(&f->cred);
f->stream = NULL;
}
static void SSPI_TryFlushCryptOut(sslfile_t *f)
{
int sent;
if (f->outcrypt.avail)
sent = VFS_WRITE(f->stream, f->outcrypt.data, f->outcrypt.avail);
else
return;
if (sent > 0)
{
memmove(f->outcrypt.data, f->outcrypt.data + sent, f->outcrypt.avail - sent);
f->outcrypt.avail -= sent;
}
}
static int SSPI_CheckNewInCrypt(sslfile_t *f)
{
int newd;
if (!f->stream)
return -1;
newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, sizeof(f->incrypt.data) - f->incrypt.avail);
if (newd < 0)
return newd;
else
f->incrypt.avail += newd;
return 0;
}
//convert inbound crypt->data
static void SSPI_Decode(sslfile_t *f)
{
SECURITY_STATUS ss;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[4];
ULONG ulQop = 0;
SecBuffer *data = NULL;
SecBuffer *extra = NULL;
int i;
if (!f->incrypt.avail)
return;
BuffDesc.ulVersion = SECBUFFER_VERSION;
BuffDesc.cBuffers = 4;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].BufferType = SECBUFFER_DATA;
SecBuff[0].cbBuffer = f->incrypt.avail;
SecBuff[0].pvBuffer = f->incrypt.data;
SecBuff[1].BufferType = SECBUFFER_EMPTY; //space for header
SecBuff[2].BufferType = SECBUFFER_EMPTY; //space for footer
SecBuff[3].BufferType = SECBUFFER_EMPTY; //space for extra marker
ss = secur.pDecryptMessage(&f->sechnd, &BuffDesc, 0, &ulQop);
if (ss < 0)
{
SSPI_Error(f, "DecryptMessage failed");
return;
}
for (i = 0; i < BuffDesc.cBuffers; i++)
{
if (SecBuff[i].BufferType == SECBUFFER_DATA && !data)
data = &SecBuff[i];
if (SecBuff[i].BufferType == SECBUFFER_EXTRA && !extra)
extra = &SecBuff[i];
}
//copy the data out to the result, yay.
if (data)
SSPI_CopyIntoBuffer(&f->inraw, data->pvBuffer, data->cbBuffer);
//retain the extra. if there's no extra then mark it so.
if (extra)
{
memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - extra->cbBuffer), extra->cbBuffer);
f->incrypt.avail = extra->cbBuffer;
}
else
f->incrypt.avail = 0;
}
//convert outgoing data->crypt
static void SSPI_Encode(sslfile_t *f)
{
SECURITY_STATUS ss;
SecBufferDesc BuffDesc;
SecBuffer SecBuff[4];
ULONG ulQop = 0;
if (f->outcrypt.avail)
{
SSPI_TryFlushCryptOut(f);
if (f->outcrypt.avail)
return; //don't flood too much
}
//don't corrupt the handshake data.
if (f->handshaking)
return;
if (!f->outraw.avail)
return;
BuffDesc.ulVersion = SECBUFFER_VERSION;
BuffDesc.cBuffers = 4;
BuffDesc.pBuffers = SecBuff;
SecBuff[0].BufferType = SECBUFFER_STREAM_HEADER;
SecBuff[0].cbBuffer = f->headersize;
SecBuff[0].pvBuffer = f->headerdata;
SecBuff[1].BufferType = SECBUFFER_DATA;
SecBuff[1].cbBuffer = f->outraw.avail;
SecBuff[1].pvBuffer = f->outraw.data;
SecBuff[2].BufferType = SECBUFFER_STREAM_TRAILER;
SecBuff[2].cbBuffer = f->footersize;
SecBuff[2].pvBuffer = f->footerdata;
SecBuff[3].BufferType = SECBUFFER_EMPTY;
ss = secur.pEncryptMessage(&f->sechnd, ulQop, &BuffDesc, 0);
if (ss < 0)
{
SSPI_Error(f, "EncryptMessage failed");
return;
}
f->outraw.avail = 0;
//fixme: these should be made non-fatal.
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer) < SecBuff[0].cbBuffer)
{
SSPI_Error(f, "crypt buffer overflowed");
return;
}
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer) < SecBuff[1].cbBuffer)
{
SSPI_Error(f, "crypt buffer overflowed");
return;
}
if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer) < SecBuff[2].cbBuffer)
{
SSPI_Error(f, "crypt buffer overflowed");
return;
}
SSPI_TryFlushCryptOut(f);
}
static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags)
{
HTTPSPolicyCallbackData polHttps;
CERT_CHAIN_POLICY_PARA PolicyPara;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
CERT_CHAIN_PARA ChainPara;
PCCERT_CHAIN_CONTEXT pChainContext;
DWORD Status;
LPSTR rgszUsages[] =
{
szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE
};
DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
if(pServerCert == NULL)
return SEC_E_WRONG_PRINCIPAL;
if(!*pwszServerName)
return SEC_E_WRONG_PRINCIPAL;
// Build certificate chain.
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
if (!crypt.pCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext))
{
Status = GetLastError();
Sys_Printf("Error 0x%x returned by CertGetCertificateChain!\n", Status);
}
else
{
// Validate certificate chain.
memset(&polHttps, 0, sizeof(HTTPSPolicyCallbackData));
polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
polHttps.dwAuthType = AUTHTYPE_SERVER;
polHttps.fdwChecks = dwCertFlags;
polHttps.pwszServerName = pwszServerName;
memset(&PolicyPara, 0, sizeof(PolicyPara));
PolicyPara.cbSize = sizeof(PolicyPara);
PolicyPara.pvExtraPolicyPara = &polHttps;
memset(&PolicyStatus, 0, sizeof(PolicyStatus));
PolicyStatus.cbSize = sizeof(PolicyStatus);
if (!crypt.pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus))
{
Status = GetLastError();
Sys_Printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!\n", Status);
}
else
{
if (PolicyStatus.dwError)
{
char *err;
Status = PolicyStatus.dwError;
switch (Status)
{
case CERT_E_EXPIRED: err = "CERT_E_EXPIRED"; break;
case CERT_E_VALIDITYPERIODNESTING: err = "CERT_E_VALIDITYPERIODNESTING"; break;
case CERT_E_ROLE: err = "CERT_E_ROLE"; break;
case CERT_E_PATHLENCONST: err = "CERT_E_PATHLENCONST"; break;
case CERT_E_CRITICAL: err = "CERT_E_CRITICAL"; break;
case CERT_E_PURPOSE: err = "CERT_E_PURPOSE"; break;
case CERT_E_ISSUERCHAINING: err = "CERT_E_ISSUERCHAINING"; break;
case CERT_E_MALFORMED: err = "CERT_E_MALFORMED"; break;
case CERT_E_UNTRUSTEDROOT: err = "CERT_E_UNTRUSTEDROOT"; break;
case CERT_E_CHAINING: err = "CERT_E_CHAINING"; break;
case TRUST_E_FAIL: err = "TRUST_E_FAIL"; break;
case CERT_E_REVOKED: err = "CERT_E_REVOKED"; break;
case CERT_E_UNTRUSTEDTESTROOT: err = "CERT_E_UNTRUSTEDTESTROOT"; break;
case CERT_E_REVOCATION_FAILURE: err = "CERT_E_REVOCATION_FAILURE"; break;
case CERT_E_CN_NO_MATCH: err = "CERT_E_CN_NO_MATCH"; break;
case CERT_E_WRONG_USAGE: err = "CERT_E_WRONG_USAGE"; break;
default: err = "(unknown)"; break;
}
Sys_Printf("Error verifying certificate for %s: %s\n", pwszServerName, err);
}
else
Status = SEC_E_OK;
}
crypt.pCertFreeCertificateChain(pChainContext);
}
return Status;
}
static void SSPI_Handshake (sslfile_t *f)
{
SECURITY_STATUS ss;
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff[2];
ULONG ContextAttributes;
SCHANNEL_CRED SchannelCred;
if (f->outcrypt.avail)
{
//don't let things build up too much
SSPI_TryFlushCryptOut(f);
if (f->outcrypt.avail)
return;
}
OutBuffDesc.ulVersion = SECBUFFER_VERSION;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.cbBuffer = sizeof(f->outcrypt.data) - f->outcrypt.avail;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = f->outcrypt.data + f->outcrypt.avail;
if (f->handshaking == HS_STARTCLIENT)
{
//no input data yet.
f->handshaking = HS_CLIENT;
memset(&SchannelCred, 0, sizeof(SchannelCred));
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1 | SP_PROT_SSL3;
SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; /*don't use windows login info or anything*/
ss = secur.pAcquireCredentialsHandleA (NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &f->cred, &Lifetime);
if (ss < 0)
{
SSPI_Error(f, "AcquireCredentialsHandle failed\n");
return;
}
ss = secur.pInitializeSecurityContextA (&f->cred, NULL, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
}
else
{
//only if we actually have data.
if (!f->incrypt.avail)
return;
InBuffDesc.ulVersion = SECBUFFER_VERSION;
InBuffDesc.cBuffers = 2;
InBuffDesc.pBuffers = InSecBuff;
InSecBuff[0].BufferType = SECBUFFER_TOKEN;
InSecBuff[0].cbBuffer = f->incrypt.avail;
InSecBuff[0].pvBuffer = f->incrypt.data;
InSecBuff[1].BufferType = SECBUFFER_EMPTY;
InSecBuff[1].pvBuffer = NULL;
InSecBuff[1].cbBuffer = 0;
ss = secur.pInitializeSecurityContextA (&f->cred, &f->sechnd, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
if (ss == SEC_E_INCOMPLETE_MESSAGE)
return;
//any extra data should still remain for the next time around. this might be more handshake data or payload data.
if (InSecBuff[1].BufferType == SECBUFFER_EXTRA)
{
memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - InSecBuff[1].cbBuffer), InSecBuff[1].cbBuffer);
f->incrypt.avail = InSecBuff[1].cbBuffer;
}
else f->incrypt.avail = 0;
}
if (ss == SEC_I_INCOMPLETE_CREDENTIALS)
{
SSPI_Error(f, "server requires credentials\n");
return;
}
if (ss < 0)
{
SSPI_Error(f, "InitializeSecurityContext failed\n");
return;
}
if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss))
{
ss = secur.pCompleteAuthToken (&f->sechnd, &OutBuffDesc);
if (ss < 0)
{
SSPI_Error(f, "CompleteAuthToken failed\n");
return;
}
}
if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer) < OutSecBuff.cbBuffer)
{
SSPI_Error(f, "crypt overflow\n");
return;
}
//send early, send often.
SSPI_TryFlushCryptOut(f);
//its all okay and established if we get this far.
if (ss == SEC_E_OK)
{
SecPkgContext_StreamSizes strsizes;
CERT_CONTEXT *remotecert;
secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_STREAM_SIZES, &strsizes);
f->headersize = strsizes.cbHeader;
f->footersize = strsizes.cbTrailer;
f->handshaking = HS_ESTABLISHED;
if (*f->wpeername)
{
ss = secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &remotecert);
if (ss != SEC_E_OK)
{
SSPI_Error(f, "unable to read server's certificate\n");
return;
}
if (VerifyServerCertificate(remotecert, f->wpeername, 0))
SSPI_Error(f, "Error validating certificante");
}
else
Sys_Printf("SSL/TLS Server name not specified, skipping verification\n");
SSPI_Encode(f);
}
}
static int SSPI_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
{
sslfile_t *f = (sslfile_t *)file;
int err = SSPI_CheckNewInCrypt(f);
if (f->handshaking)
{
SSPI_Handshake(f);
return err;
}
SSPI_Encode(f);
SSPI_Decode(f);
bytestoread = min(bytestoread, f->inraw.avail);
if (bytestoread)
{
memcpy(buffer, f->inraw.data, bytestoread);
f->inraw.avail -= bytestoread;
memmove(f->inraw.data, f->inraw.data + bytestoread, f->inraw.avail);
}
else
{
if (err)
return err;
}
return bytestoread;
}
static int SSPI_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite)
{
sslfile_t *f = (sslfile_t *)file;
bytestowrite = SSPI_CopyIntoBuffer(&f->outraw, buffer, bytestowrite);
if (f->handshaking)
{
SSPI_CheckNewInCrypt(f); //make sure its ticking over
SSPI_Handshake(f);
}
else
{
SSPI_Encode(f);
}
return bytestowrite;
}
static qboolean SSPI_Seek (struct vfsfile_s *file, unsigned long pos)
{
SSPI_Error((sslfile_t*)file, "unable to seek on streams");
return false;
}
static unsigned long SSPI_Tell (struct vfsfile_s *file)
{
SSPI_Error((sslfile_t*)file, "unable to seek on streams");
return 0;
}
static unsigned long SSPI_GetLen (struct vfsfile_s *file)
{
return 0;
}
static void SSPI_Close (struct vfsfile_s *file)
{
SSPI_Error((sslfile_t*)file, "");
Z_Free(file);
}
#include <wchar.h>
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server)
{
sslfile_t *newf;
int i = 0;
int err;
unsigned int c;
if (!source || !SSL_Init())
{
VFS_CLOSE(source);
return NULL;
}
if (!hostname)
hostname = "";
if (server) //unsupported
{
VFS_CLOSE(source);
return NULL;
}
newf = Z_Malloc(sizeof(*newf));
while(*hostname)
{
c = utf8_decode(&err, hostname, (void*)&hostname);
if (c > WCHAR_MAX)
err = true; //no 16bit surrogates. they're evil.
else if (i == sizeof(newf->wpeername)/sizeof(newf->wpeername[0]) - 1)
err = true; //no space to store it
else
newf->wpeername[i++] = c;
if (err)
{
Z_Free(newf);
VFS_CLOSE(source);
return NULL;
}
}
newf->wpeername[i] = 0;
newf->handshaking = server?HS_STARTSERVER:HS_STARTCLIENT;
newf->stream = source;
newf->funcs.Close = SSPI_Close;
newf->funcs.Flush = NULL;
newf->funcs.GetLen = SSPI_GetLen;
newf->funcs.ReadBytes = SSPI_ReadBytes;
newf->funcs.Seek = SSPI_Seek;
newf->funcs.Tell = SSPI_Tell;
newf->funcs.WriteBytes = SSPI_WriteBytes;
newf->funcs.seekingisabadplan = true;
return &newf->funcs;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -344,7 +344,7 @@ plugin_t *Plug_Load(char *file)
return newplug; return newplug;
} }
static int Plug_Emumerated (const char *name, int size, void *param) static int Plug_Emumerated (const char *name, int size, void *param, struct searchpath_s *spath)
{ {
char vmname[MAX_QPATH]; char vmname[MAX_QPATH];
Q_strncpyz(vmname, name, sizeof(vmname)); Q_strncpyz(vmname, name, sizeof(vmname));
@ -745,14 +745,14 @@ typedef enum{
STREAM_NONE, STREAM_NONE,
STREAM_SOCKET, STREAM_SOCKET,
STREAM_TLS, STREAM_TLS,
STREAM_OSFILE, STREAM_VFS
STREAM_FILE
} plugstream_e; } plugstream_e;
typedef struct { typedef struct {
plugin_t *plugin; plugin_t *plugin;
plugstream_e type; plugstream_e type;
int socket; int socket;
vfsfile_t *vfs;
struct { struct {
char filename[MAX_QPATH]; char filename[MAX_QPATH];
qbyte *buffer; qbyte *buffer;
@ -770,7 +770,7 @@ int pluginstreamarraylen;
static int Plug_NewStreamHandle(plugstream_e type) static int Plug_NewStreamHandle(plugstream_e type)
{ {
int i; int i;
for (i = 1; i < pluginstreamarraylen; i++) for (i = 0; i < pluginstreamarraylen; i++)
{ {
if (!pluginstreamarray[i].plugin) if (!pluginstreamarray[i].plugin)
break; break;
@ -906,50 +906,49 @@ qintptr_t VARGS Plug_Net_TCPConnect(void *offset, quintptr_t mask, const qintptr
unsigned short remoteport = VM_LONG(arg[1]); unsigned short remoteport = VM_LONG(arg[1]);
int handle; int handle;
struct sockaddr_qstorage to, from; vfsfile_t *stream = FS_OpenTCP(remoteip, remoteport);
int sock; if (!stream)
int _true = 1;
netadr_t a;
if (!NET_StringToAdr(remoteip, remoteport, &a))
return -1; return -1;
NetadrToSockadr(&a, &to); handle = Plug_NewStreamHandle(STREAM_VFS);
pluginstreamarray[handle].vfs = stream;
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
return -2;
}
memset(&from, 0, sizeof(from));
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&to)->sa_family;
if (bind(sock, (struct sockaddr *)&from, sizeof(from)) == -1)
{
return -2;
}
//not yet blocking. So no frequent attempts please...
//non blocking prevents connect from returning worthwhile sensible value.
if (connect(sock, (struct sockaddr *)&to, sizeof(to)) == -1)
{
closesocket(sock);
return -2;
}
if (ioctlsocket (sock, FIONBIO, (u_long *)&_true) == -1) //now make it non blocking.
{
return -1;
}
handle = Plug_NewStreamHandle(STREAM_SOCKET);
pluginstreamarray[handle].socket = sock;
return handle; return handle;
} }
void Plug_Net_Close_Internal(int handle);
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server);
#ifdef HAVE_SSL
qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintptr_t *arg)
{
pluginstream_t *stream;
int handle = VM_LONG(arg[0]);
qboolean anon = false;
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
{
Con_Printf("Plug_Net_SetTLSClient: socket does not belong to you (or is invalid)\n");
return -2;
}
stream = &pluginstreamarray[handle];
if (stream->type != STREAM_VFS)
{ //not a socket - invalid
Con_Printf("Plug_Net_SetTLSClient: Not a socket handle\n");
return -2;
}
stream->vfs = FS_OpenSSL(VM_POINTER(arg[1]), stream->vfs, false);
if (!stream->vfs)
{
Plug_Net_Close_Internal(handle);
return -1;
}
return 0;
}
#endif
#ifdef GNUTLS #ifdef GNUTLS
qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, unsigned int mask, const qintptr_t *arg) qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
static gnutls_anon_client_credentials anoncred; static gnutls_anon_client_credentials anoncred;
static gnutls_certificate_credentials xcred; static gnutls_certificate_credentials xcred;
@ -1058,48 +1057,33 @@ qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg
int handle; int handle;
int *ret; int *ret;
char *data; //char *data;
char *mode;
vfsfile_t *f;
if (VM_OOB(arg[1], sizeof(int))) if (VM_OOB(arg[1], sizeof(int)))
return -2; return -2;
ret = VM_POINTER(arg[1]); ret = VM_POINTER(arg[1]);
if (arg[2] == 1) switch(arg[2])
{ {
FS_LoadFile(VM_POINTER(arg[0]), (void**)&data); case 1:
if (!data) mode = "rb";
return -1; break;
case 2:
handle = Plug_NewStreamHandle(STREAM_FILE); mode = "wb";
pluginstreamarray[handle].file.buffer = data; break;
pluginstreamarray[handle].file.curpos = 0; default:
pluginstreamarray[handle].file.curlen = com_filesize;
pluginstreamarray[handle].file.buflen = com_filesize;
*ret = handle;
return com_filesize;
}
else if (arg[2] == 2)
{
data = BZ_Malloc(8192);
if (!data)
return -1;
handle = Plug_NewStreamHandle(STREAM_FILE);
Q_strncpyz(pluginstreamarray[handle].file.filename, VM_POINTER(arg[0]), MAX_QPATH);
pluginstreamarray[handle].file.buffer = data;
pluginstreamarray[handle].file.curpos = 0;
pluginstreamarray[handle].file.curlen = 0;
pluginstreamarray[handle].file.buflen = 8192;
*ret = handle;
return com_filesize;
}
else
return -2; return -2;
} }
f = FS_OpenVFS(VM_POINTER(arg[0]), mode, FS_GAME);
if (!f)
return -1;
handle = Plug_NewStreamHandle(STREAM_VFS);
pluginstreamarray[handle].vfs = f;
*ret = handle;
return VFS_GETLEN(pluginstreamarray[handle].vfs);
}
qintptr_t VARGS Plug_memset(void *offset, quintptr_t mask, const qintptr_t *arg) qintptr_t VARGS Plug_memset(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
@ -1171,6 +1155,34 @@ qintptr_t VARGS Plug_atan2(void *offset, quintptr_t mask, const qintptr_t *arg)
return ret; return ret;
} }
void Plug_Net_Close_Internal(int handle)
{
switch(pluginstreamarray[handle].type)
{
case STREAM_NONE:
break;
case STREAM_VFS:
if (pluginstreamarray[handle].vfs)
VFS_CLOSE(pluginstreamarray[handle].vfs);
pluginstreamarray[handle].vfs = NULL;
break;
case STREAM_SOCKET:
#ifndef NACL
closesocket(pluginstreamarray[handle].socket);
#endif
break;
case STREAM_TLS:
#ifdef GNUTLS
gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR);
pluginstreamarray[handle].type = STREAM_SOCKET;
Plug_Net_Close_Internal(handle);
return;
#endif
break;
}
pluginstreamarray[handle].plugin = NULL;
}
qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *arg) qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int read; int read;
@ -1217,16 +1229,8 @@ qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *ar
return -2; //closed by remote connection. return -2; //closed by remote connection.
return read; return read;
#endif #endif
case STREAM_FILE: case STREAM_VFS:
if (pluginstreamarray[handle].file.curlen - pluginstreamarray[handle].file.curpos < destlen) return VFS_READ(pluginstreamarray[handle].vfs, dest, destlen);
{
destlen = pluginstreamarray[handle].file.curlen - pluginstreamarray[handle].file.curpos;
if (destlen < 0)
return -2;
}
memcpy(dest, pluginstreamarray[handle].file.buffer + pluginstreamarray[handle].file.curpos, destlen);
pluginstreamarray[handle].file.curpos += destlen;
return destlen;
default: default:
return -2; return -2;
} }
@ -1273,18 +1277,8 @@ qintptr_t VARGS Plug_Net_Send(void *offset, quintptr_t mask, const qintptr_t *ar
return -2; //closed by remote connection. return -2; //closed by remote connection.
return written; return written;
#endif #endif
case STREAM_FILE: case STREAM_VFS:
if (pluginstreamarray[handle].file.buflen < pluginstreamarray[handle].file.curpos + srclen) return VFS_WRITE(pluginstreamarray[handle].vfs, src, srclen);
{
pluginstreamarray[handle].file.buflen = pluginstreamarray[handle].file.curpos + srclen+8192;
pluginstreamarray[handle].file.buffer =
BZ_Realloc(pluginstreamarray[handle].file.buffer, pluginstreamarray[handle].file.buflen);
}
memcpy(pluginstreamarray[handle].file.buffer + pluginstreamarray[handle].file.curpos, src, srclen);
pluginstreamarray[handle].file.curpos += srclen;
if (pluginstreamarray[handle].file.curpos > pluginstreamarray[handle].file.curlen)
pluginstreamarray[handle].file.curlen = pluginstreamarray[handle].file.curpos;
return -2;
default: default:
return -2; return -2;
@ -1331,41 +1325,6 @@ qintptr_t VARGS Plug_Net_SendTo(void *offset, quintptr_t mask, const qintptr_t *
return -2; return -2;
} }
} }
void Plug_Net_Close_Internal(int handle)
{
switch(pluginstreamarray[handle].type)
{
case STREAM_FILE:
if (*pluginstreamarray[handle].file.filename)
{
COM_WriteFile(pluginstreamarray[handle].file.filename, pluginstreamarray[handle].file.buffer, pluginstreamarray[handle].file.curlen);
BZ_Free(pluginstreamarray[handle].file.buffer);
}
else
FS_FreeFile(pluginstreamarray[handle].file.buffer);
break;
case STREAM_NONE:
break;
case STREAM_OSFILE:
break;
case STREAM_SOCKET:
#ifndef NACL
closesocket(pluginstreamarray[handle].socket);
#endif
break;
case STREAM_TLS:
#ifdef GNUTLS
gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR);
pluginstreamarray[handle].type = STREAM_SOCKET;
Plug_Net_Close_Internal(handle);
return;
#endif
break;
}
pluginstreamarray[handle].plugin = NULL;
}
qintptr_t VARGS Plug_Net_Close(void *offset, quintptr_t mask, const qintptr_t *arg) qintptr_t VARGS Plug_Net_Close(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int handle = VM_LONG(arg[0]); int handle = VM_LONG(arg[0]);
@ -1484,6 +1443,9 @@ void Plug_Init(void)
#ifdef GNUTLS #ifdef GNUTLS
if (Init_GNUTLS()) if (Init_GNUTLS())
Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0); Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0);
#endif
#ifdef HAVE_SSL
Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0);
#endif #endif
Plug_RegisterBuiltin("Net_Recv", Plug_Net_Recv, 0); Plug_RegisterBuiltin("Net_Recv", Plug_Net_Recv, 0);
Plug_RegisterBuiltin("Net_Send", Plug_Net_Send, 0); Plug_RegisterBuiltin("Net_Send", Plug_Net_Send, 0);
@ -1775,6 +1737,7 @@ qboolean Plug_CenterPrintMessage(char *buffer, int clientnum)
void Plug_Close(plugin_t *plug) void Plug_Close(plugin_t *plug)
{ {
int i;
if (plug->blockcloses) if (plug->blockcloses)
{ {
Con_Printf("Plugin %s provides driver features, and cannot safely be unloaded\n", plug->name); Con_Printf("Plugin %s provides driver features, and cannot safely be unloaded\n", plug->name);
@ -1804,6 +1767,14 @@ void Plug_Close(plugin_t *plug)
VM_Call(plug->vm, plug->shutdown); VM_Call(plug->vm, plug->shutdown);
VM_Destroy(plug->vm); VM_Destroy(plug->vm);
for (i = 0; i < pluginstreamarraylen; i++)
{
if (pluginstreamarray[i].plugin == plug)
{
Plug_Net_Close_Internal(i);
}
}
Plug_FreeConCommands(plug); Plug_FreeConCommands(plug);
Plug_Client_Close(plug); Plug_Client_Close(plug);
@ -1883,6 +1854,10 @@ void Plug_Shutdown(void)
Plug_Close(plugs); Plug_Close(plugs);
} }
BZ_Free(pluginstreamarray);
pluginstreamarray = NULL;
pluginstreamarraylen = 0;
numplugbuiltins = 0; numplugbuiltins = 0;
BZ_Free(plugbuiltins); BZ_Free(plugbuiltins);
plugbuiltins = NULL; plugbuiltins = NULL;
@ -1894,6 +1869,10 @@ void Plug_Shutdown(void)
plugincommandarraylen = 0; plugincommandarraylen = 0;
BZ_Free(plugincommandarray); BZ_Free(plugincommandarray);
plugincommandarray = NULL; plugincommandarray = NULL;
#ifndef SERVERONLY
Plug_Client_Shutdown();
#endif
} }
#endif #endif

View file

@ -1426,7 +1426,7 @@ void search_close_progs(pubprogfuncs_t *prinst, qboolean complain)
prvm_nextsearchhandle = 0; //might as well. prvm_nextsearchhandle = 0; //might as well.
} }
int search_enumerate(const char *name, int fsize, void *parm) int search_enumerate(const char *name, int fsize, void *parm, struct searchpath_s *spath)
{ {
prvmsearch_t *s = parm; prvmsearch_t *s = parm;

View file

@ -206,8 +206,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define svc_muzzleflash 39 // [short] entity #define svc_muzzleflash 39 // [short] entity
#define svc_updateuserinfo 40 // [qbyte] slot [long] uid #define svc_updateuserinfo 40 // [qbyte] slot [long] uid [string] userinfo
// [string] userinfo
#define svc_download 41 // [short] size [size bytes] #define svc_download 41 // [short] size [size bytes]
#define svc_playerinfo 42 // variable #define svc_playerinfo 42 // variable
@ -260,6 +259,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define svcfte_movepic 71 #define svcfte_movepic 71
#define svcfte_updatepic 72 #define svcfte_updatepic 72
//73
#define svcfte_effect 74 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate #define svcfte_effect 74 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
#define svcfte_effect2 75 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate #define svcfte_effect2 75 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate

View file

@ -186,7 +186,7 @@ typedef struct {
int bufferleft; int bufferleft;
int skip; int skip;
} vmsearch_t; } vmsearch_t;
static int VMEnum(const char *match, int size, void *args) static int VMEnum(const char *match, int size, void *args, void *spath)
{ {
char *check; char *check;
int newlen; int newlen;
@ -210,13 +210,13 @@ static int VMEnum(const char *match, int size, void *args)
return true; return true;
} }
static int IfFound(const char *match, int size, void *args) static int IfFound(const char *match, int size, void *args, void *spath)
{ {
*(qboolean*)args = true; *(qboolean*)args = true;
return true; return true;
} }
static int VMEnumMods(const char *match, int size, void *args) static int VMEnumMods(const char *match, int size, void *args, void *spath)
{ {
char *check; char *check;
char desc[1024]; char desc[1024];
@ -238,7 +238,7 @@ static int VMEnumMods(const char *match, int size, void *args)
return true; //we don't want baseq3 return true; //we don't want baseq3
foundone = false; foundone = false;
Sys_EnumerateFiles(va("%s%s/", ((vmsearch_t *)args)->dir, match), "*.pk3", IfFound, &foundone); Sys_EnumerateFiles(va("%s%s/", ((vmsearch_t *)args)->dir, match), "*.pk3", IfFound, &foundone, spath);
if (foundone == false) if (foundone == false)
return true; //we only count directories with a pk3 file return true; //we only count directories with a pk3 file
@ -286,9 +286,9 @@ int VM_GetFileList(char *path, char *ext, char *output, int buffersize)
if (!strcmp(path, "$modlist")) if (!strcmp(path, "$modlist"))
{ {
vms.skip=0; vms.skip=0;
Sys_EnumerateFiles((vms.dir=com_quakedir), "*", VMEnumMods, &vms); Sys_EnumerateFiles((vms.dir=com_quakedir), "*", VMEnumMods, &vms, NULL);
if (*com_homedir) if (*com_homedir)
Sys_EnumerateFiles((vms.dir=com_homedir), "*", VMEnumMods, &vms); Sys_EnumerateFiles((vms.dir=com_homedir), "*", VMEnumMods, &vms, NULL);
} }
else if (*(char *)ext == '.' || *(char *)ext == '/') else if (*(char *)ext == '.' || *(char *)ext == '/')
COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms);

View file

@ -83,7 +83,7 @@ void Sys_ServerActivity(void);
void Sys_SendKeyEvents (void); void Sys_SendKeyEvents (void);
// Perform Key_Event () callbacks until the input que is empty // Perform Key_Event () callbacks until the input que is empty
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm); int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath);
void Sys_Vibrate(int count); void Sys_Vibrate(int count);

View file

@ -72,6 +72,10 @@
RelativePath="..\droid\src\com\fteqw\FTEDroidEngine.java" RelativePath="..\droid\src\com\fteqw\FTEDroidEngine.java"
> >
</File> </File>
<File
RelativePath="..\client\in_generic.c"
>
</File>
<File <File
RelativePath="..\client\snd_droid.c" RelativePath="..\client\snd_droid.c"
> >

View file

@ -2,6 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005 # Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080}
EndProjectSection EndProjectSection
EndProject EndProject
@ -30,6 +31,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avplug", "..\..\plugins\avp
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "droid", "droid.vcproj", "{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "droid", "droid.vcproj", "{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{8CED01C6-2C61-4EC5-90B6-574D9756D773}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jabbercl", "..\..\plugins\jabber\jabbercl.vcproj", "{9767E236-8454-44E9-8999-CD5BDAFBE9BA}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
D3DDebug|Win32 = D3DDebug|Win32 D3DDebug|Win32 = D3DDebug|Win32
@ -437,10 +442,52 @@ Global
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.ActiveCfg = Release|Win32 {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.ActiveCfg = Release|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.Build.0 = Release|Win32 {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.Build.0 = Release|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|x64.ActiveCfg = Release|Win32 {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|x64.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|Win32.Build.0 = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4877586B-E85B-4DF8-BCCE-59D31514D240} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{32B12987-DF8C-4E40-B07C-B18586A4CA65} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{873CCE24-3549-49D4-A4B4-653F91B1532A} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {8CED01C6-2C61-4EC5-90B6-574D9756D773}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw
EndGlobalSection EndGlobalSection

File diff suppressed because it is too large Load diff

View file

@ -176,7 +176,7 @@ typedef struct heightmap_s
static void ted_dorelight(heightmap_t *hm); static void ted_dorelight(heightmap_t *hm);
static void Terr_Collect(heightmap_t *hm); static qboolean Terr_Collect(heightmap_t *hm);
#ifndef SERVERONLY #ifndef SERVERONLY
@ -241,7 +241,7 @@ static void Terr_InitLightmap(hmsection_t *s)
lm = Surf_NewLightmaps(1, SECTTEXSIZE*LMCHUNKS, SECTTEXSIZE*LMCHUNKS, false); lm = Surf_NewLightmaps(1, SECTTEXSIZE*LMCHUNKS, SECTTEXSIZE*LMCHUNKS, false);
for (i = 0; i < LMCHUNKS*LMCHUNKS; i++) for (i = 0; i < LMCHUNKS*LMCHUNKS; i++)
{ {
lms = malloc(sizeof(*lms)); lms = BZ_Malloc(sizeof(*lms));
lms->lm = lm; lms->lm = lm;
lms->x = (i & (LMCHUNKS-1))*SECTTEXSIZE; lms->x = (i & (LMCHUNKS-1))*SECTTEXSIZE;
lms->y = (i / LMCHUNKS)*SECTTEXSIZE; lms->y = (i / LMCHUNKS)*SECTTEXSIZE;
@ -257,7 +257,7 @@ static void Terr_InitLightmap(hmsection_t *s)
s->lmx = lms->x; s->lmx = lms->x;
s->lmy = lms->y; s->lmy = lms->y;
free(lms); Z_Free(lms);
} }
#endif #endif
@ -344,7 +344,7 @@ static qboolean Terr_IsSectionFName(heightmap_t *hm, char *fname, int *sx, int *
} }
static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, dsection_t *ds, unsigned int dslen) static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, dsection_t *ds, unsigned int dslen)
{ {
int i; int i, j;
#ifndef SERVERONLY #ifndef SERVERONLY
dsmesh_t *dm; dsmesh_t *dm;
unsigned char *lm; unsigned char *lm;
@ -365,13 +365,12 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in
if (!s) if (!s)
{ {
s = malloc(sizeof(*s)); s = Z_Malloc(sizeof(*s));
if (!s) if (!s)
{ {
FS_FreeFile(ds); FS_FreeFile(ds);
return NULL; return NULL;
} }
memset(s, 0, sizeof(*s));
InsertLinkBefore(&s->recycle, &hm->recycle); InsertLinkBefore(&s->recycle, &hm->recycle);
s->sx = sx; s->sx = sx;
@ -468,12 +467,11 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in
s->numents = ds->ents_num; s->numents = ds->ents_num;
s->maxents = s->numents; s->maxents = s->numents;
if (s->maxents) if (s->maxents)
s->ents = malloc(sizeof(*s->ents) * s->maxents); s->ents = Z_Malloc(sizeof(*s->ents) * s->maxents);
else else
s->ents = NULL; s->ents = NULL;
if (!s->ents) if (!s->ents)
s->numents = s->maxents = 0; s->numents = s->maxents = 0;
memset(s->ents, 0, sizeof(*s->ents) * s->maxents);
for (i = 0, dm = (dsmesh_t*)ptr; i < s->numents; i++, dm = (dsmesh_t*)((qbyte*)dm + dm->size)) for (i = 0, dm = (dsmesh_t*)ptr; i < s->numents; i++, dm = (dsmesh_t*)((qbyte*)dm + dm->size))
{ {
s->ents[i].model = Mod_ForName((char*)(dm + 1), false); s->ents[i].model = Mod_ForName((char*)(dm + 1), false);
@ -499,7 +497,7 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in
} }
else else
{ {
s->flags |= TSF_RELIGHT; // s->flags |= TSF_RELIGHT;
#ifndef SERVERONLY #ifndef SERVERONLY
if (s->lightmap >= 0) if (s->lightmap >= 0)
@ -508,7 +506,13 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in
lm += (s->lmy * HMLMSTRIDE + s->lmx) * lightmap_bytes; lm += (s->lmy * HMLMSTRIDE + s->lmx) * lightmap_bytes;
for (i = 0; i < SECTTEXSIZE; i++) for (i = 0; i < SECTTEXSIZE; i++)
{ {
memset(lm, 0, sizeof(byte_vec4_t)*SECTTEXSIZE); for (j = 0; j < SECTTEXSIZE; j++)
{
lm[j*4+0] = 0;
lm[j*4+0] = 0;
lm[j*4+0] = 0;
lm[j*4+3] = 255;
}
lm += (HMLMSTRIDE)*lightmap_bytes; lm += (HMLMSTRIDE)*lightmap_bytes;
} }
lightmap[s->lightmap]->modified = true; lightmap[s->lightmap]->modified = true;
@ -644,13 +648,10 @@ qboolean Terr_DownloadedSection(char *fname)
hmcluster_t *cluster = hm->cluster[cx + cy*MAXSECTIONS]; hmcluster_t *cluster = hm->cluster[cx + cy*MAXSECTIONS];
if (!cluster) if (!cluster)
{ {
cluster = malloc(sizeof(*cluster)); cluster = Z_Malloc(sizeof(*cluster));
if (cluster) if (cluster)
{
memset(cluster, 0, sizeof(*cluster));
hm->cluster[cx + cy*MAXSECTIONS] = cluster; hm->cluster[cx + cy*MAXSECTIONS] = cluster;
} }
}
if (cluster) if (cluster)
cluster->section[sx + sy*MAXSECTIONS] = Terr_ReadSection(hm, cluster->section[sx + sy*MAXSECTIONS], x, y, fileptr, len); cluster->section[sx + sy*MAXSECTIONS] = Terr_ReadSection(hm, cluster->section[sx + sy*MAXSECTIONS], x, y, fileptr, len);
} }
@ -663,7 +664,7 @@ qboolean Terr_DownloadedSection(char *fname)
} }
#endif #endif
static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, qboolean force)
{ {
hmsection_t *sect; hmsection_t *sect;
void *diskimage; void *diskimage;
@ -685,9 +686,7 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
/*queue the file for download if we don't have it yet*/ /*queue the file for download if we don't have it yet*/
if (len < 0) if (len < 0)
{ {
#ifndef CLIENTONLY if (!force)
if (!sv.state) //server ignores any load errors, and will load a dummy section.
#endif
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
if (!cl.downloadlist) if (!cl.downloadlist)
@ -805,7 +804,10 @@ static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy
} }
/*convienience function*/ /*convienience function*/
static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean doload) #define TGS_NOLOAD 0
#define TGS_LOAD 1
#define TGS_FORCELOAD 2
static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, unsigned int flags)
{ {
hmcluster_t *cluster; hmcluster_t *cluster;
hmsection_t *section; hmsection_t *section;
@ -816,12 +818,11 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo
cluster = hm->cluster[cx + cy*MAXSECTIONS]; cluster = hm->cluster[cx + cy*MAXSECTIONS];
if (!cluster) if (!cluster)
{ {
if (doload) if (flags & (TGS_LOAD|TGS_FORCELOAD))
{ {
cluster = malloc(sizeof(*cluster)); cluster = Z_Malloc(sizeof(*cluster));
if (!cluster) if (!cluster)
return NULL; return NULL;
memset(cluster, 0, sizeof(*cluster));
hm->cluster[cx + cy*MAXSECTIONS] = cluster; hm->cluster[cx + cy*MAXSECTIONS] = cluster;
} }
else else
@ -830,13 +831,27 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo
section = cluster->section[sx + sy*MAXSECTIONS]; section = cluster->section[sx + sy*MAXSECTIONS];
if (!section) if (!section)
{ {
if (doload) if (flags & (TGS_LOAD|TGS_FORCELOAD))
{ {
// while (hm->activesections > TERRAINACTIVESECTIONS) // while (hm->activesections > TERRAINACTIVESECTIONS)
// Terr_Collect(hm); // Terr_Collect(hm);
section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y); section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y, !!(flags & TGS_FORCELOAD));
} }
} }
#ifndef SERVERONLY
//when using networked terrain, the client will never load a section from disk, but only loading it from the server
if (section && (section->flags & TSF_NOTIFY) && mod_terrain_networked.ival && !sv.state)
{
//try to download it now...
if (!cl.downloadlist)
{
CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, x, y), Terr_TempDiskSectionName(hm, x, y), DLLF_OVERWRITE|DLLF_TEMPORARY);
section->flags &= ~TSF_NOTIFY;
}
}
#endif
return section; return section;
} }
@ -850,7 +865,7 @@ int Heightmap_Save(heightmap_t *hm)
{ {
for (y = hm->firstsegy; y < hm->maxsegy; y++) for (y = hm->firstsegy; y < hm->maxsegy; y++)
{ {
s = Terr_GetSection(hm, x, y, false); s = Terr_GetSection(hm, x, y, TGS_NOLOAD);
if (!s) if (!s)
continue; continue;
if (s->flags & TSF_EDITED) if (s->flags & TSF_EDITED)
@ -868,16 +883,6 @@ int Heightmap_Save(heightmap_t *hm)
} }
#ifndef CLIENTONLY #ifndef CLIENTONLY
static int dehex(int i)
{
if (i >= '0' && i <= '9')
return (i-'0');
else if (i >= 'A' && i <= 'F')
return (i-'A'+10);
else
return (i-'a'+10);
}
//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(char *name, flocation_t *loc)
{ {
@ -896,22 +901,11 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc)
if (!Terr_IsSectionFName(hm, name, &x, &y)) if (!Terr_IsSectionFName(hm, name, &x, &y))
return false; return false;
x = dehex(name[nlen-17+ 6])<<8;
x|= dehex(name[nlen-17+ 7])<<4;
x|= dehex(name[nlen-17+ 8])<<0;
y = dehex(name[nlen-17+10])<<8;
y|= dehex(name[nlen-17+11])<<4;
y|= dehex(name[nlen-17+12])<<0;
x += CHUNKBIAS;
y += CHUNKBIAS;
//verify that its valid //verify that its valid
if (strcmp(name, Terr_DiskSectionName(hm, x, y))) if (strcmp(name, Terr_DiskSectionName(hm, x, y)))
return false; return false;
s = Terr_GetSection(hm, x, y, false); s = Terr_GetSection(hm, x, y, TGS_NOLOAD);
if (!s || !(s->flags & TSF_EDITED)) if (!s || !(s->flags & TSF_EDITED))
return false; //its not been edited, might as well just use the regular file return false; //its not been edited, might as well just use the regular file
@ -931,7 +925,7 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
{ {
struct lmsect_s *lms; struct lmsect_s *lms;
lms = malloc(sizeof(*lms)); lms = BZ_Malloc(sizeof(*lms));
lms->lm = s->lightmap; lms->lm = s->lightmap;
lms->x = s->lmx; lms->x = s->lmx;
lms->y = s->lmy; lms->y = s->lmy;
@ -950,18 +944,56 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
} }
#endif #endif
free(s->ents); Z_Free(s->ents);
free(s->mesh.xyz_array); Z_Free(s->mesh.xyz_array);
free(s->mesh.indexes); Z_Free(s->mesh.indexes);
#endif #endif
free(s); Z_Free(s);
hm->activesections--; hm->activesections--;
} }
static void Terr_DoEditNotify(heightmap_t *hm)
{
int i;
char *cmd;
hmsection_t *s;
link_t *ln = &hm->recycle;
if (!sv.state)
return;
for (i = 0; i < sv.allocated_client_slots; i++)
{
if (svs.clients[i].state > cs_zombie && svs.clients[i].netchan.remote_address.type != NA_LOOPBACK)
{
if (svs.clients[i].backbuf.cursize)
return;
}
}
for (ln = &hm->recycle; ln->next != &hm->recycle; ln = &s->recycle)
{
s = (hmsection_t*)ln->next;
if (s->flags & TSF_NOTIFY)
{
s->flags &= ~TSF_NOTIFY;
cmd = va("mod_terrain_reload %s %i %i\n", hm->path, s->sx - CHUNKBIAS, s->sy - CHUNKBIAS);
for (i = 0; i < sv.allocated_client_slots; i++)
{
if (svs.clients[i].state > cs_zombie && svs.clients[i].netchan.remote_address.type != NA_LOOPBACK)
{
SV_StuffcmdToClient(&svs.clients[i], cmd);
}
}
return;
}
}
}
//garbage collect the oldest section, to make space for another //garbage collect the oldest section, to make space for another
static void Terr_Collect(heightmap_t *hm) static qboolean Terr_Collect(heightmap_t *hm)
{ {
hmcluster_t *c; hmcluster_t *c;
hmsection_t *s; hmsection_t *s;
@ -986,9 +1018,10 @@ static void Terr_Collect(heightmap_t *hm)
c->section[sx+sy*MAXSECTIONS] = NULL; c->section[sx+sy*MAXSECTIONS] = NULL;
Terr_DestroySection(hm, s, true); Terr_DestroySection(hm, s, true);
return; return true;
} }
} }
return false;
} }
/*purge all sections /*purge all sections
@ -1034,7 +1067,7 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light
if (!lightmapsonly) if (!lightmapsonly)
{ {
hm->cluster[cx + cy*MAXSECTIONS] = NULL; hm->cluster[cx + cy*MAXSECTIONS] = NULL;
free(c); BZ_Free(c);
} }
} }
#ifndef SERVERONLY #ifndef SERVERONLY
@ -1045,7 +1078,7 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light
struct lmsect_s *lms; struct lmsect_s *lms;
lms = hm->unusedlmsects; lms = hm->unusedlmsects;
hm->unusedlmsects = lms->next; hm->unusedlmsects = lms->next;
free(lms); BZ_Free(lms);
} }
} }
#endif #endif
@ -1528,11 +1561,11 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h)
if (R_CullBox(mins, maxs)) if (R_CullBox(mins, maxs))
return; return;
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_LOAD);
if (!s) if (!s)
return; return;
if (s->lightmap < 0) if (s->lightmap < 0)
Terr_LoadSection(hm, s, x, y); Terr_LoadSection(hm, s, x, y, false);
if (s->flags & TSF_RELIGHT) if (s->flags & TSF_RELIGHT)
{ {
@ -1644,8 +1677,15 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
struct tdibctx tdibctx; struct tdibctx tdibctx;
if (!r_refdef.recurse) if (!r_refdef.recurse)
{
Terr_DoEditNotify(hm);
// while (hm->activesections > 0)
// if (!Terr_Collect(hm))
// break;
while (hm->activesections > TERRAINACTIVESECTIONS) while (hm->activesections > TERRAINACTIVESECTIONS)
Terr_Collect(hm); if (!Terr_Collect(hm))
break;
}
if (hm->relight) if (hm->relight)
ted_dorelight(hm); ted_dorelight(hm);
@ -1729,7 +1769,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
mins[1] = (y+0 - CHUNKBIAS)*hm->sectionsize; mins[1] = (y+0 - CHUNKBIAS)*hm->sectionsize;
maxs[1] = (y+1 - CHUNKBIAS)*hm->sectionsize; maxs[1] = (y+1 - CHUNKBIAS)*hm->sectionsize;
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_LOAD);
if (!s) if (!s)
continue; continue;
if (s->lightmap < 0) if (s->lightmap < 0)
@ -1829,7 +1869,7 @@ void Terrain_ClipDecal(fragmentdecal_t *dec, float *center, float radius, model_
{ {
for (x = min[0]; x < max[0]; x++) for (x = min[0]; x < max[0]; x++)
{ {
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_LOAD);
if (!s) if (!s)
continue; continue;
@ -1912,7 +1952,7 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t
return hm->exteriorcontents; return hm->exteriorcontents;
if (sx >= hm->maxsegx || sy >= hm->maxsegy) if (sx >= hm->maxsegx || sy >= hm->maxsegy)
return hm->exteriorcontents; return hm->exteriorcontents;
s = Terr_GetSection(hm, sx, sy, true); s = Terr_GetSection(hm, sx, sy, TGS_LOAD);
if (!s) if (!s)
{ {
return FTECONTENTS_SOLID; return FTECONTENTS_SOLID;
@ -2002,7 +2042,7 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
return; return;
if (sx >= hm->maxsegx || sy >= hm->maxsegy) if (sx >= hm->maxsegx || sy >= hm->maxsegy)
return; return;
s = Terr_GetSection(hm, sx, sy, true); s = Terr_GetSection(hm, sx, sy, TGS_LOAD);
if (!s) if (!s)
return; return;
@ -2152,7 +2192,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
else if (sy < tr->hm->firstsegy || sy >= tr->hm->maxsegy) else if (sy < tr->hm->firstsegy || sy >= tr->hm->maxsegy)
s = NULL; s = NULL;
else else
s = Terr_GetSection(tr->hm, sx, sy, true); s = Terr_GetSection(tr->hm, sx, sy, TGS_LOAD);
if (!s) if (!s)
{ {
@ -2501,7 +2541,7 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx)
int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE; int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE;
if (s->lightmap < 0) if (s->lightmap < 0)
{ {
Terr_LoadSection(s->hmmod, s, x, y); Terr_LoadSection(s->hmmod, s, x, y, true);
if (s->lightmap < 0) if (s->lightmap < 0)
Terr_InitLightmap(s); Terr_InitLightmap(s);
} }
@ -2832,7 +2872,7 @@ static void ted_itterate(heightmap_t *hm, int distribution, float *pos, float ra
{ {
for (sx = min[0]; sx < max[0]; sx++) for (sx = min[0]; sx < max[0]; sx++)
{ {
s = Terr_GetSection(hm, sx, sy, true); s = Terr_GetSection(hm, sx, sy, TGS_FORCELOAD);
if (!s) if (!s)
continue; continue;
@ -2907,7 +2947,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx*4, x, hm->maxsegy*4-1); x = bound(hm->firstsegx*4, x, hm->maxsegy*4-1);
y = bound(hm->firstsegy*4, y, hm->maxsegy*4-1); y = bound(hm->firstsegy*4, y, hm->maxsegy*4-1);
s = Terr_GetSection(hm, x/4, y/4, true); s = Terr_GetSection(hm, x/4, y/4, TGS_FORCELOAD);
if (!s) if (!s)
return; return;
ted_sethole(&quant, s, (x&3) + (y&3)*4, x/4, y/4, 0); ted_sethole(&quant, s, (x&3) + (y&3)*4, x/4, y/4, 0);
@ -2953,7 +2993,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx, x, hm->maxsegy-1); x = bound(hm->firstsegx, x, hm->maxsegy-1);
y = bound(hm->firstsegy, y, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1);
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_LOAD);
if (!s) if (!s)
return; return;
s->flags |= TSF_HASWATER|TSF_EDITED; s->flags |= TSF_HASWATER|TSF_EDITED;
@ -2995,7 +3035,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx, x, hm->maxsegy-1); x = bound(hm->firstsegx, x, hm->maxsegy-1);
y = bound(hm->firstsegy, y, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1);
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_LOAD);
if (!s) if (!s)
return; return;
x = bound(0, quant, 3); x = bound(0, quant, 3);
@ -3012,7 +3052,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx, x, hm->maxsegy-1); x = bound(hm->firstsegx, x, hm->maxsegy-1);
y = bound(hm->firstsegy, y, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1);
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_FORCELOAD);
if (!s) if (!s)
return; return;
s->flags |= TSF_EDITED; s->flags |= TSF_EDITED;
@ -3070,7 +3110,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx, x, hm->maxsegy-1); x = bound(hm->firstsegx, x, hm->maxsegy-1);
y = bound(hm->firstsegy, y, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1);
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_FORCELOAD);
if (!s) if (!s)
return; return;
@ -3106,7 +3146,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
x = bound(hm->firstsegx, x, hm->maxsegy-1); x = bound(hm->firstsegx, x, hm->maxsegy-1);
y = bound(hm->firstsegy, y, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1);
s = Terr_GetSection(hm, x, y, true); s = Terr_GetSection(hm, x, y, TGS_FORCELOAD);
if (!s) if (!s)
return; return;
@ -3354,8 +3394,70 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname)
return hm; return hm;
} }
void Mod_Terrain_Create_f(void)
{
char *mname;
char *mdata;
mname = va("maps/%s.hmp", Cmd_Argv(1));
mdata = va(
"terrain\n"
"{\n"
"classname worldspawn\n"
"_segmentsize 1024\n"
"_minxsegment -2048\n"
"_minysegment -2048\n"
"_maxxsegment 2048\n"
"_maxysegment 2048\n"
"_segmentsize 1024\n"
// "_tiles 64 64 8 8\n"
"}\n"
"{\n"
"classname info_player_start\n"
"origin \"0 0 1024\"\n"
"}\n"
, mname);
COM_WriteFile(mname, mdata, strlen(mdata));
}
void Mod_Terrain_Reload_f(void)
{
model_t *mod;
heightmap_t *hm;
if (Cmd_Argc() >= 2)
mod = Mod_FindName(va("maps/%s.hmp", Cmd_Argv(1)));
#ifndef SERVERONLY
else if (cls.state)
mod = cl.worldmodel;
#endif
else
mod = NULL;
if (!mod || mod->type == mod_dummy)
return;
hm = mod->terrain;
if (!hm)
return;
if (Cmd_Argc() >= 4)
{
hmsection_t *s;
int sx = atoi(Cmd_Argv(2)) + CHUNKBIAS;
int sy = atoi(Cmd_Argv(3)) + CHUNKBIAS;
if (hm)
{
s = Terr_GetSection(hm, sx, sy, TGS_NOLOAD);
if (s)
{
s->flags |= TSF_NOTIFY;
}
}
}
else
Terr_PurgeTerrainModel(mod, false, true);
}
void Terr_Init(void) void Terr_Init(void)
{ {
Cvar_Register(&mod_terrain_networked, "Terrain"); Cvar_Register(&mod_terrain_networked, "Terrain");
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
} }
#endif #endif

View file

@ -4686,7 +4686,7 @@ typedef struct {
short xpos; short xpos;
short ypos; short ypos;
} doomimage_t; } doomimage_t;
static int FindDoomSprites(const char *name, int size, void *param) static int FindDoomSprites(const char *name, int size, void *param, void *spath)
{ {
if (*(int *)param + strlen(name)+1 > 16000) if (*(int *)param + strlen(name)+1 > 16000)
Sys_Error("Too many doom sprites\n"); Sys_Error("Too many doom sprites\n");

View file

@ -401,6 +401,16 @@ void R_SetupGL (float stereooffset)
w = x2 - x; w = x2 - x;
h = y - y2; h = y - y2;
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
if (stereooffset && r_stereo_method.ival == 5)
{
w /= 2;
if (stereooffset > 0)
x += vid.pixelwidth/2;
}
r_refdef.pxrect.x = x; r_refdef.pxrect.x = x;
r_refdef.pxrect.y = y; r_refdef.pxrect.y = y;
r_refdef.pxrect.width = w; r_refdef.pxrect.width = w;
@ -408,9 +418,6 @@ void R_SetupGL (float stereooffset)
qglViewport (x, y2, w, h); qglViewport (x, y2, w, h);
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
if (r_waterwarp.value<0 && (r_viewcontents & FTECONTENTS_FLUID)) if (r_waterwarp.value<0 && (r_viewcontents & FTECONTENTS_FLUID))
{ {
fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
@ -556,7 +563,8 @@ void R_RenderScene (void)
else else
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE); qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
break; break;
case 5: //eyestrain
break;
} }
if (i) if (i)
qglClear (GL_DEPTH_BUFFER_BIT); qglClear (GL_DEPTH_BUFFER_BIT);
@ -595,12 +603,20 @@ void R_RenderScene (void)
case 1: case 1:
qglDrawBuffer(GL_BACK); qglDrawBuffer(GL_BACK);
break; break;
case 2:
case 3: case 3:
case 4: qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
qglClear(GL_COLOR_BUFFER_BIT);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
break; break;
case 4:
qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
qglClear(GL_COLOR_BUFFER_BIT);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
case 2:
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
break;
case 5:
break;
} }
} }
/*generates a new modelview matrix, as well as vpn vectors*/ /*generates a new modelview matrix, as well as vpn vectors*/

View file

@ -2977,7 +2977,7 @@ void Shader_Free (shader_t *shader)
int Shader_InitCallback (const char *name, int size, void *param) int Shader_InitCallback (const char *name, int size, void *param, void *spath)
{ {
strcpy(shaderbuf+shaderbuflen, name); strcpy(shaderbuf+shaderbuflen, name);
Shader_MakeCache(shaderbuf+shaderbuflen); Shader_MakeCache(shaderbuf+shaderbuflen);

View file

@ -54,13 +54,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"uniform sampler2D s_t2; //diffuse/reflection\n" "uniform sampler2D s_t2; //diffuse/reflection\n"
"#ifdef DEPTH\n" "#ifdef DEPTH\n"
"uniform sampler2D s_t3; //refraction depth\n" "uniform sampler2D s_t3; //refraction depth\n"
"#ifdef RIPPLEMAP\n" "#define s_ripplemap s_t4\n"
"uniform sampler2D s_t4; //ripplemap\n"
"#endif\n"
"#else\n" "#else\n"
"#ifdef RIPPLEMAP\n" "#define s_ripplemap s_t3\n"
"uniform sampler2D s_t3; //ripplemap\n"
"#endif\n" "#endif\n"
"#ifdef RIPPLEMAP\n"
"uniform sampler2D s_ripplemap; //ripplemap\n"
"#endif\n" "#endif\n"
"uniform float e_time;\n" "uniform float e_time;\n"
@ -84,7 +83,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"n -= 1.0 - 4.0/256.0;\n" "n -= 1.0 - 4.0/256.0;\n"
"#ifdef RIPPLEMAP\n" "#ifdef RIPPLEMAP\n"
"n += texture2D(s_t4, stc).rgb*3.0;\n" "n += texture2D(s_ripplemap, stc).rgb*3.0;\n"
"#endif\n" "#endif\n"
//the fresnel term decides how transparent the water should be //the fresnel term decides how transparent the water should be
@ -543,7 +542,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec4 col, sp;\n" "vec4 col, sp;\n"
"#ifdef OFFSETMAPPING\n" "#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_t4, tcbase, eyevector);\n" "vec2 tcoffsetmap = offsetmap(s_t4, tc, eyevector);\n"
"#define tc tcoffsetmap\n" "#define tc tcoffsetmap\n"
"#endif\n" "#endif\n"

View file

@ -128,7 +128,7 @@ void FTP_ServerShutdown(void)
} }
//we ought to filter this to remove duplicates. //we ought to filter this to remove duplicates.
static int SendFileNameTo(const char *rawname, int size, void *param) static int SendFileNameTo(const char *rawname, int size, void *param, struct searchpath_s *spath)
{ {
int socket = *(int*)param; int socket = *(int*)param;
// int i; // int i;

View file

@ -68,9 +68,9 @@ iwboolean IWebAllowUpLoad(char *fname, char *uname);
vfsfile_t *IWebGenerateFile(char *name, char *content, int contentlength); vfsfile_t *IWebGenerateFile(char *name, char *content, int contentlength);
char *COM_ParseOut (const char *data, char *out, int outlen); char *COM_ParseOut (const char *data, char *out, int outlen);
void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm); //struct searchpath_s;
//void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, struct searchpath_s *), void *parm);
char *Q_strcpyline(char *out, const char *in, int maxlen); char *Q_strcpyline(char *out, const char *in, int maxlen);

View file

@ -345,7 +345,7 @@ static void FSPPAPI_ClosePath(void *handle)
Z_Free(handle); Z_Free(handle);
} }
int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
int rootlen = strlen(rootpath); int rootlen = strlen(rootpath);
char *sub; char *sub;
@ -362,33 +362,33 @@ int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(con
sub++; sub++;
if (wildcmp(match, sub)) if (wildcmp(match, sub))
{ {
if (!func(sub, f->length, parm)) if (!func(sub, f->length, parm, spath))
return false; return false;
} }
} }
return true; return true;
} }
static int FSPPAPI_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) static int FSPPAPI_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath)
{ {
return Sys_EnumerateFiles((char*)handle, match, func, parm); return Sys_EnumerateFiles((char*)handle, match, func, parm, spath);
} }
static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data) static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data, void *handle)
{ {
if (filename[strlen(filename)-1] == '/') if (filename[strlen(filename)-1] == '/')
{ //this is actually a directory { //this is actually a directory
char childpath[256]; char childpath[256];
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
Sys_EnumerateFiles((char*)data, childpath, FSPPAPI_RebuildFSHash, data); Sys_EnumerateFiles((char*)data, childpath, FSPPAPI_RebuildFSHash, data, handle);
return true; return true;
} }
FS_AddFileHash(0, filename, NULL, data); FS_AddFileHash(0, filename, NULL, handle);
return true; return true;
} }
static void FSPPAPI_BuildHash(void *handle, int depth) static void FSPPAPI_BuildHash(void *handle, int depth)
{ {
Sys_EnumerateFiles(handle, "*", FSPPAPI_RebuildFSHash, handle); Sys_EnumerateFiles(handle, "*", FSPPAPI_RebuildFSHash, handle, handle);
} }
/* /*

View file

@ -3847,8 +3847,8 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could
//note that we don't allow passing 0.0f for null. //note that we don't allow passing 0.0f for null.
//WARNING: field 0 is actually a valid field, and is commonly modelindex. //WARNING: field 0 is actually a valid field, and is commonly modelindex.
} }
else if (p->type == ev_field && e->type->type == ev_field && (p->aux_type->type == ev_variant || e->type->aux_type->type == ev_variant)) else if ((p->type == ev_field || p->type == ev_pointer) && e->type->type == p->type && (p->aux_type->type == ev_variant || e->type->aux_type->type == ev_variant || p->aux_type->type == ev_void || e->type->aux_type->type == ev_void))
{ //allow passing variant fields etc { //allow passing variant fields etc (also allow .void or *void as universal/variant field/pointer types)
} }
else if ((p->type == ev_vector) && e->type->type == ev_integer && e->constant && !((int*)qcc_pr_globals)[e->ofs]) else if ((p->type == ev_vector) && e->type->type == ev_integer && e->constant && !((int*)qcc_pr_globals)[e->ofs])
{ {

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
/*Testing this code should typically be done with the three following mods: /*Testing this code should typically be done with the three following mods:

View file

@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#ifdef SQL #ifdef SQL
#include "sv_sql.h" #include "sv_sql.h"
@ -105,6 +105,21 @@ void PF_InitTempStrings(pubprogfuncs_t *prinst);
void PR_DumpPlatform_f(void); void PR_DumpPlatform_f(void);
typedef struct qcstate_s
{
float resumetime;
qboolean waiting;
struct qcthread_s *thread;
int self;
int selfid;
int other;
int otherid;
float returnval;
struct qcstate_s *next;
} qcstate_t;
qcstate_t *qcthreads;
typedef struct { typedef struct {
//for func finding and swapping. //for func finding and swapping.
char *name; char *name;
@ -163,9 +178,22 @@ progstype_t progstype;
void PR_RegisterFields(void); void PR_RegisterFields(void);
void PR_ResetBuiltins(progstype_t type); void PR_ResetBuiltins(progstype_t type);
char *QC_ProgsNameForEnt(edict_t *ent) static qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait)
{ {
return "?"; qcstate_t *state;
state = prinst->parms->memalloc(sizeof(qcstate_t));
state->next = qcthreads;
qcthreads = state;
state->resumetime = resumetime;
state->self = NUM_FOR_EDICT(prinst, PROG_TO_EDICT(prinst, pr_global_struct->self));
state->selfid = PROG_TO_EDICT(prinst, state->self)->xv->uniquespawnid;
state->other = NUM_FOR_EDICT(prinst, PROG_TO_EDICT(prinst, pr_global_struct->other));
state->otherid = PROG_TO_EDICT(prinst, state->other)->xv->uniquespawnid;
state->thread = prinst->Fork(prinst);
state->waiting = wait;
state->returnval = retval;
return state;
} }
void PDECL ED_Spawned (struct edict_s *ent, int loading) void PDECL ED_Spawned (struct edict_s *ent, int loading)
@ -5550,35 +5578,83 @@ void QCBUILTIN PF_sqldisconnect (pubprogfuncs_t *prinst, struct globalvars_s *pr
} }
} }
static qboolean PR_SQLResultAvailable(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
edict_t *ent;
pubprogfuncs_t *prinst = svprogfuncs;
struct globalvars_s *pr_globals = PR_globals(prinst, PR_CURRENT);
if (req->user.qccallback)
{
G_FLOAT(OFS_PARM0) = req->srvid;
G_FLOAT(OFS_PARM1) = req->num;
G_FLOAT(OFS_PARM2) = numrows;
G_FLOAT(OFS_PARM3) = numcols;
G_FLOAT(OFS_PARM4) = eof;
G_FLOAT(OFS_PARM5) = firstrow;
// recall self and other references
ent = PROG_TO_EDICT(prinst, req->user.selfent);
if (ent->isfree || ent->xv->uniquespawnid != req->user.selfid)
pr_global_struct->self = pr_global_struct->world;
else
pr_global_struct->self = req->user.selfent;
ent = PROG_TO_EDICT(prinst, req->user.otherent);
if (ent->isfree || ent->xv->uniquespawnid != req->user.otherid)
pr_global_struct->other = pr_global_struct->world;
else
pr_global_struct->other = req->user.otherent;
PR_ExecuteProgram(svprogfuncs, req->user.qccallback);
}
if (eof && req->user.thread)
{
qcstate_t *thread = req->user.thread;
req->user.thread = NULL;
if (thread)
thread->waiting = false;
}
return req->user.persistant;
}
void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
sqlserver_t *server; sqlserver_t *server;
int callfunc = G_INT(OFS_PARM1); int callfunc = G_INT(OFS_PARM1);
int querytype = G_FLOAT(OFS_PARM2); int querytype = G_FLOAT(OFS_PARM2);
char *querystr = PF_VarString(prinst, 3, pr_globals); char *querystr = PF_VarString(prinst, 3, pr_globals);
int qself, qother;
float qselfid, qotherid;
if (SQL_Available()) if (SQL_Available())
{ {
server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); server = SQL_GetServer(G_FLOAT(OFS_PARM0), false);
if (server) if (server)
{ {
// save self and other references queryrequest_t *qreq;
if (PROG_TO_EDICT(prinst, pr_global_struct->self)->isfree)
qself = pr_global_struct->world;
else
qself = pr_global_struct->self;
qselfid = PROG_TO_EDICT(prinst, qself)->xv->uniquespawnid;
if (PROG_TO_EDICT(prinst, pr_global_struct->other)->isfree)
qother = pr_global_struct->world;
else
qother = pr_global_struct->other;
qotherid = PROG_TO_EDICT(prinst, qother)->xv->uniquespawnid;
Con_DPrintf("SQL Query: %s\n", querystr); Con_DPrintf("SQL Query: %s\n", querystr);
G_FLOAT(OFS_RETURN) = SQL_NewQuery(server, callfunc, querytype, qself, qselfid, qother, qotherid, querystr); G_FLOAT(OFS_RETURN) = SQL_NewQuery(server, PR_SQLResultAvailable, querystr, &qreq);
if (qreq)
{
//so our C callback knows what to do
qreq->user.persistant = querytype > 0;
qreq->user.qccallback = callfunc;
// save self and other references
qreq->user.selfent = PROG_TO_EDICT(prinst, pr_global_struct->self)->isfree?pr_global_struct->world:pr_global_struct->self;
qreq->user.selfid = PROG_TO_EDICT(prinst, qreq->user.selfent)->xv->uniquespawnid;
qreq->user.otherent = PROG_TO_EDICT(prinst, pr_global_struct->other)->isfree?pr_global_struct->world:pr_global_struct->other;
qreq->user.otherid = PROG_TO_EDICT(prinst, qreq->user.otherent)->xv->uniquespawnid;
if (querytype & 2)
{
qreq->user.thread = PR_CreateThread(prinst, G_FLOAT(OFS_RETURN), 0, true);
svprogfuncs->AbortStack(prinst);
}
}
return; return;
} }
} }
@ -5589,20 +5665,21 @@ void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_sqlclosequery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_sqlclosequery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
sqlserver_t *server; sqlserver_t *server;
queryresult_t *qres; queryrequest_t *qreq;
if (SQL_Available()) if (SQL_Available())
{ {
server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); server = SQL_GetServer(G_FLOAT(OFS_PARM0), false);
if (server) if (server)
{ {
qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); qreq = SQL_GetQueryRequest(server, G_FLOAT(OFS_PARM1));
if (qres) if (qreq)
{ {
// TODO: partial resultset logic not implemented yet SQL_CloseRequest(server, qreq, false);
SQL_CloseResult(server, qres);
return; return;
} }
else
Con_Printf("Invalid sql request\n");
} }
} }
// else nothing to close // else nothing to close
@ -5619,7 +5696,7 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_
server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); server = SQL_GetServer(G_FLOAT(OFS_PARM0), false);
if (server) if (server)
{ {
qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
if (qres) if (qres)
{ {
data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true); data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true);
@ -5629,6 +5706,10 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_
return; return;
} }
} }
else
{
Con_Printf("Invalid sql request/row\n");
}
} }
} }
// else we failed to get anything // else we failed to get anything
@ -5638,6 +5719,7 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
sqlserver_t *server; sqlserver_t *server;
queryrequest_t *qreq;
queryresult_t *qres; queryresult_t *qres;
char *data; char *data;
@ -5646,9 +5728,39 @@ void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_
server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); server = SQL_GetServer(G_FLOAT(OFS_PARM0), false);
if (server) if (server)
{ {
qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); if (G_FLOAT(OFS_PARM2) < 0)
{
qreq = SQL_GetQueryRequest(server, G_FLOAT(OFS_PARM1));
if (qreq->results)
{
if (G_FLOAT(OFS_PARM2) == -2)
G_FLOAT(OFS_RETURN) = qreq->results->columns;
else if (G_FLOAT(OFS_PARM2) == -3)
G_FLOAT(OFS_RETURN) = qreq->results->rows + qreq->results->firstrow;
else
{
Con_Printf("Invalid sql row\n");
G_FLOAT(OFS_RETURN) = 0;
}
return;
}
}
else
{
qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
if (qres) if (qres)
{ {
if (G_FLOAT(OFS_PARM2) == -1)
{
G_FLOAT(OFS_RETURN) = qres->columns;
return;
}
if (G_FLOAT(OFS_PARM2) == -2)
{
G_FLOAT(OFS_RETURN) = qres->rows;
return;
}
data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true); data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true);
if (data) if (data)
{ {
@ -5656,6 +5768,11 @@ void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_
return; return;
} }
} }
else
{
Con_Printf("Invalid sql request/row\n");
}
}
} }
} }
// else we failed to get anything // else we failed to get anything
@ -5676,7 +5793,7 @@ void QCBUILTIN PF_sqlerror (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{ // query-specific error request { // query-specific error request
if (server->active) // didn't check this earlier so check it now if (server->active) // didn't check this earlier so check it now
{ {
queryresult_t *qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); queryresult_t *qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2));
if (qres) if (qres)
{ {
RETURN_TSTRING(qres->error); RETURN_TSTRING(qres->error);
@ -5738,14 +5855,9 @@ void QCBUILTIN PF_sqlversion (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
void PR_SQLCycle(void) void PR_SQLCycle(void)
{ {
globalvars_t *pr_globals; if (!SQL_Available())
if (!SQL_Available() || !svprogfuncs)
return; return;
SQL_ServerCycle();
pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
SQL_ServerCycle(svprogfuncs, pr_globals);
} }
#endif #endif
@ -7653,17 +7765,6 @@ static void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct global
#endif #endif
} }
typedef struct qcstate_s {
float resumetime;
struct qcthread_s *thread;
int self;
int other;
struct qcstate_s *next;
} qcstate_t;
qcstate_t *qcthreads;
void PRSV_RunThreads(void) void PRSV_RunThreads(void)
{ {
struct globalvars_s *pr_globals; struct globalvars_s *pr_globals;
@ -7674,7 +7775,7 @@ void PRSV_RunThreads(void)
{ {
next = state->next; next = state->next;
if (state->resumetime > sv.time) if (state->resumetime > sv.time || state->waiting)
{ //not time yet, reform original list. { //not time yet, reform original list.
state->next = qcthreads; state->next = qcthreads;
qcthreads = state; qcthreads = state;
@ -7685,7 +7786,7 @@ void PRSV_RunThreads(void)
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->self)); pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->self));
pr_global_struct->other = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->other)); pr_global_struct->other = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->other));
G_FLOAT(OFS_RETURN) = 1; G_FLOAT(OFS_RETURN) = state->returnval;
svprogfuncs->RunThread(svprogfuncs, state->thread); svprogfuncs->RunThread(svprogfuncs, state->thread);
svprogfuncs->parms->memfree(state->thread); svprogfuncs->parms->memfree(state->thread);
@ -7713,29 +7814,17 @@ static void PRSV_ClearThreads(void)
static void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
qcstate_t *state;
struct qcthread_s *thread;
float sleeptime; float sleeptime;
sleeptime = G_FLOAT(OFS_PARM0); sleeptime = G_FLOAT(OFS_PARM0);
thread = svprogfuncs->Fork(svprogfuncs); PR_CreateThread(prinst, 1, sv.time + sleeptime, false);
state = svprogfuncs->parms->memalloc(sizeof(qcstate_t)); prinst->AbortStack(prinst);
state->next = qcthreads;
qcthreads = state;
state->resumetime = sv.time + sleeptime;
state->self = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->self));
state->other = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->other));
state->thread = thread;
svprogfuncs->AbortStack(svprogfuncs);
} }
static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
qcstate_t *state;
struct qcthread_s *thread;
float sleeptime; float sleeptime;
if (svprogfuncs->callargc >= 1) if (svprogfuncs->callargc >= 1)
@ -7743,15 +7832,7 @@ static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
else else
sleeptime = 0; sleeptime = 0;
thread = svprogfuncs->Fork(svprogfuncs); PR_CreateThread(prinst, 1, sv.time + sleeptime, false);
state = svprogfuncs->parms->memalloc(sizeof(qcstate_t));
state->next = qcthreads;
qcthreads = state;
state->resumetime = sv.time + sleeptime;
state->self = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->self));
state->other = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->other));
state->thread = thread;
PRSV_RunThreads(); PRSV_RunThreads();

View file

@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "quakedef.h" #include "quakedef.h"
#include "qwsvdef.h"
#ifdef VM_Q1 #ifdef VM_Q1

View file

@ -1,106 +0,0 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// quakedef.h -- primary header for server
#define QUAKEDEF_H__
#if 1//ndef SERVERONLY
#include "../client/quakedef.h"
#else
#define QUAKE_GAME // as opposed to utilities
//define PARANOID // speed sapping error checking
#include <math.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <ctype.h>
#include "bothdefs.h"
#ifdef MSVCDISABLEWARNINGS
#pragma warning( disable : 4244 4127 4201 4214 4514 4305 4115 4018)
#endif
#include "translate.h"
#include "common.h"
#include "bspfile.h"
#include "sys.h"
#include "zone.h"
#include "mathlib.h"
#include "cvar.h"
#include "net.h"
#include "protocol.h"
#include "cmd.h"
#include "model.h"
#include "crc.h"
#include "progtype.h"
#include "progdefs.h"
#include "progs.h"
#include "q2game.h"
#include "server.h"
#include "world.h"
#include "pmove.h"
//=============================================================================
// the host system specifies the base of the directory tree, the
// command line parms passed to the program, and the amount of memory
// available for the program to use
typedef struct quakeparms_s
{
char *basedir;
int argc;
char **argv;
void *membase;
int memsize;
} quakeparms_t;
//=============================================================================
//
// host
//
extern quakeparms_t host_parms;
extern cvar_t sys_nostdout;
extern cvar_t developer;
extern qboolean host_initialized; // true if into command execution
extern double host_frametime;
extern double realtime; // not bounded in any way, changed at
// start of every frame, never reset
void SV_Error (char *error, ...) LIKEPRINTF(1);
void SV_Init (struct quakeparms_s *parms);
void Con_Printf (char *fmt, ...) LIKEPRINTF(1);
void Con_TPrintf (translation_t fmt, ...);
void Con_DPrintf (char *fmt, ...) LIKEPRINTF(1);
#endif

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY

View file

@ -941,9 +941,7 @@ struct quakeparms_s;
void SV_Init (struct quakeparms_s *parms); void SV_Init (struct quakeparms_s *parms);
int SV_CalcPing (client_t *cl, qboolean forcecalc); int SV_CalcPing (client_t *cl, qboolean forcecalc);
void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext); void SV_FullClientUpdate (client_t *client, client_t *to);
void SV_FullClientUpdateToClient (client_t *client, client_t *cl);
void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf);
int SV_ModelIndex (char *name); int SV_ModelIndex (char *name);

View file

@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -374,7 +374,7 @@ void SV_Give_f (void)
} }
} }
int ShowMapList (const char *name, int flags, void *parm) int ShowMapList (const char *name, int flags, void *parm, struct searchpath_s *spath)
{ {
if (name[5] == 'b' && name[6] == '_') //skip box models if (name[5] == 'b' && name[6] == '_') //skip box models
return true; return true;
@ -1454,6 +1454,18 @@ void SV_Status_f (void)
Con_Printf ("current map : %s\n", sv.name); Con_Printf ("current map : %s\n", sv.name);
Con_Printf("entities : %i/%i\n", sv.world.num_edicts, sv.world.max_edicts); Con_Printf("entities : %i/%i\n", sv.world.num_edicts, sv.world.max_edicts);
if (svs.gametype == GT_PROGS)
{
int count = 0;
for (count = 1; count < MAX_MODELS; count++)
if (!sv.strings.model_precache[count])
break;
Con_Printf("models : %i/%i\n", count, MAX_MODELS);
for (count = 1; count < MAX_SOUNDS; count++)
if (!*sv.strings.sound_precache[count])
break;
Con_Printf("sounds : %i/%i\n", count, MAX_SOUNDS);
}
Con_Printf("gamedir : %s\n", FS_GetGamedir()); Con_Printf("gamedir : %s\n", FS_GetGamedir());
if (sv.csqcdebug) if (sv.csqcdebug)
Con_Printf("csqc debug : true\n"); Con_Printf("csqc debug : true\n");

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
/* /*
NPC chat: NPC chat:

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
#ifdef SERVER_DEMO_PLAYBACK #ifdef SERVER_DEMO_PLAYBACK

View file

@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#include "pr_common.h" #include "pr_common.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -436,7 +436,7 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence)
int m; int m;
if (!client->frameunion.frames) if (!client->frameunion.frames)
{ {
Con_Printf("BLAME %s\n", client->state?client->name:"a zombie"); Con_Printf("Server bug: No frames!\n");
return; return;
} }

View file

@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
extern int total_loading_size, current_loading_size, loading_stage; extern int total_loading_size, current_loading_size, loading_stage;
char *T_GetString(int num); char *T_GetString(int num);

View file

@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#include "netinc.h" #include "netinc.h"
#include <sys/types.h> #include <sys/types.h>
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -150,22 +150,6 @@ cvar_t sv_masterport = CVAR("sv_masterport", "0");
cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1"); cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1");
cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0");
cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat");
#ifdef TCPCONNECT
cvar_t sv_port_tcp = CVARC("sv_port_tcp", "", SV_Tcpport_Callback);
#ifdef IPPROTO_IPV6
cvar_t sv_port_tcp6 = CVARC("sv_port_tcp6", "", SV_Tcpport6_Callback);
#endif
#endif
#ifdef HAVE_IPV4
cvar_t sv_port_ipv4 = CVARC("sv_port", "27500", SV_Port_Callback);
#endif
#ifdef IPPROTO_IPV6
cvar_t sv_port_ipv6 = CVARC("sv_port_ipv6", "", SV_PortIPv6_Callback);
#endif
#ifdef USEIPX
cvar_t sv_port_ipx = CVARC("sv_port_ipx", "", SV_PortIPX_Callback);
#endif
cvar_t pausable = CVAR("pausable", "1"); cvar_t pausable = CVAR("pausable", "1");
@ -646,10 +630,7 @@ void SV_DropClient (client_t *drop)
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us. if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us.
{ {
// send notification to all remaining clients // send notification to all remaining clients
SV_FullClientUpdate (drop, &sv.reliable_datagram, 0); SV_FullClientUpdate (drop, NULL);
#ifdef NQPROT
SVNQ_FullClientUpdate (drop, &sv.nqreliable_datagram);
#endif
SV_MVD_FullClientUpdate(NULL, drop); SV_MVD_FullClientUpdate(NULL, drop);
} }
@ -732,10 +713,10 @@ void PIN_SaveMessages(void)
pinnedmessages_t *p; pinnedmessages_t *p;
vfsfile_t *f; vfsfile_t *f;
f = FS_OpenVFS("pinned.txt", "wt", FS_GAMEONLY); f = FS_OpenVFS("pinned.txt", "wb", FS_GAMEONLY);
if (!f) if (!f)
{ {
Con_Printf("couldn't write anything\n"); Con_Printf("couldn't write to %s\n", "pinned.txt");
return; return;
} }
@ -746,7 +727,11 @@ void PIN_SaveMessages(void)
} }
void PIN_DeleteOldestMessage(void) void PIN_DeleteOldestMessage(void)
{ {
pinnedmessages_t *old = pinned; pinnedmessages_t *old;
if (dopinnedload)
PIN_LoadMessages();
old = pinned;
if (old) if (old)
{ {
pinned = pinned->next; pinned = pinned->next;
@ -758,6 +743,9 @@ void PIN_MakeMessage(char *from, char *msg)
pinnedmessages_t *p; pinnedmessages_t *p;
pinnedmessages_t *newp; pinnedmessages_t *newp;
if (dopinnedload)
PIN_LoadMessages();
newp = BZ_Malloc(sizeof(pinnedmessages_t)); newp = BZ_Malloc(sizeof(pinnedmessages_t));
Q_strncpyz(newp->setby, from, sizeof(newp->setby)); Q_strncpyz(newp->setby, from, sizeof(newp->setby));
Q_strncpyz(newp->message, msg, sizeof(newp->message)); Q_strncpyz(newp->message, msg, sizeof(newp->message));
@ -884,101 +872,72 @@ void SV_GenerateBasicUserInfo(client_t *cl)
=================== ===================
SV_FullClientUpdate SV_FullClientUpdate
Writes all update values to a sizebuf Writes all update values to client. use to=NULL to broadcast.
=================== ===================
*/ */
void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext) void SV_FullClientUpdate (client_t *client, client_t *to)
{ {
int i; int i;
char info[MAX_INFO_STRING]; char info[MAX_INFO_STRING];
i = client - svs.clients; if (!to)
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{ {
MSG_WriteByte (buf, svc_updatefrags); for (i = 0; i < sv.allocated_client_slots; i++)
MSG_WriteByte (buf, i); {
MSG_WriteShort (buf, sv.recordedplayer[i].frags); SV_FullClientUpdate(client, &svs.clients[i]);
}
MSG_WriteByte (buf, svc_updateping);
MSG_WriteByte (buf, i);
MSG_WriteShort (buf, sv.recordedplayer[i].ping);
MSG_WriteByte (buf, svc_updatepl);
MSG_WriteByte (buf, i);
MSG_WriteByte (buf, sv.recordedplayer[i].pl);
MSG_WriteByte (buf, svc_updateentertime);
MSG_WriteByte (buf, i);
MSG_WriteFloat (buf, 0);
Q_strncpyz (info, sv.recordedplayer[i].userinfo, sizeof(info));
Info_RemoveKey(info, "password"); //main password key
Info_RemoveKey(info, "*ip"); //don't broadcast this in playback
Info_RemovePrefixedKeys (info, '_'); // server passwords, etc
MSG_WriteByte (buf, svc_updateuserinfo);
MSG_WriteByte (buf, i);
MSG_WriteLong (buf, sv.recordedplayer[i].userid);
MSG_WriteString (buf, info);
return; return;
} }
#endif
i = client - svs.clients;
//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i); //Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i);
MSG_WriteByte (buf, svc_updatefrags); if (ISQWCLIENT(to))
MSG_WriteByte (buf, i); {
MSG_WriteShort (buf, client->old_frags); ClientReliableWrite_Begin(to, svc_updatefrags, 4);
ClientReliableWrite_Byte (to, i);
ClientReliableWrite_Short(to, client->old_frags);
MSG_WriteByte (buf, svc_updateping); ClientReliableWrite_Begin (to, svc_updateping, 4);
MSG_WriteByte (buf, i); ClientReliableWrite_Byte (to, i);
MSG_WriteShort (buf, SV_CalcPing (client, false)); ClientReliableWrite_Short (to, SV_CalcPing (client, false));
MSG_WriteByte (buf, svc_updatepl); ClientReliableWrite_Begin (to, svc_updatepl, 3);
MSG_WriteByte (buf, i); ClientReliableWrite_Byte (to, i);
MSG_WriteByte (buf, client->lossage); ClientReliableWrite_Byte (to, client->lossage);
MSG_WriteByte (buf, svc_updateentertime); ClientReliableWrite_Begin (to, svc_updateentertime, 6);
MSG_WriteByte (buf, i); ClientReliableWrite_Byte (to, i);
MSG_WriteFloat (buf, realtime - client->connection_started); ClientReliableWrite_Float (to, realtime - client->connection_started);
#ifdef warningmsg if ((to->fteprotocolextensions) & PEXT_BIGUSERINFOS)
#pragma warningmsg("this is a bug: it can be broadcast to all qw clients")
#endif
if (ftepext & PEXT_BIGUSERINFOS)
Q_strncpyz (info, client->userinfo, sizeof(info)); Q_strncpyz (info, client->userinfo, sizeof(info));
else else
Q_strncpyz (info, client->userinfobasic, sizeof(info)); Q_strncpyz (info, client->userinfobasic, sizeof(info));
Info_RemoveKey(info, "password"); //main password key Info_RemoveKey(info, "password"); //main password key
Info_RemovePrefixedKeys (info, '_'); // server passwords, etc Info_RemovePrefixedKeys (info, '_'); // server passwords, etc
MSG_WriteByte (buf, svc_updateuserinfo); ClientReliableWrite_Begin(to, svc_updateuserinfo, 7 + strlen(info));
MSG_WriteByte (buf, i); ClientReliableWrite_Byte (to, i);
MSG_WriteLong (buf, client->userid); ClientReliableWrite_Long (to, client->userid);
MSG_WriteString (buf, info); ClientReliableWrite_String(to, info);
} }
#ifdef NQPROT else if (ISNQCLIENT(to))
void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf)
{ {
int playercolor, top, bottom; int top, bottom, playercolor;
int i; char *nam = Info_ValueForKey(client->userinfo, "name");
i = client - svs.clients;
if (i >= 16) if (i >= 16)
return; return; //NQ clients will crash if they see a player index above 16.
//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i); ClientReliableWrite_Begin(to, svc_updatefrags, 4);
ClientReliableWrite_Byte (to, i);
ClientReliableWrite_Short(to, client->old_frags);
MSG_WriteByte (buf, svc_updatefrags); ClientReliableWrite_Begin(to, svc_updatename, 3 + strlen(nam));
MSG_WriteByte (buf, i); ClientReliableWrite_Byte (to, i);
MSG_WriteShort (buf, client->old_frags); ClientReliableWrite_String(to, nam);
MSG_WriteByte (buf, svc_updatename);
MSG_WriteByte (buf, i);
MSG_WriteString (buf, Info_ValueForKey(client->userinfo, "name"));
top = atoi(Info_ValueForKey(client->userinfo, "topcolor")); top = atoi(Info_ValueForKey(client->userinfo, "topcolor"));
bottom = atoi(Info_ValueForKey(client->userinfo, "bottomcolor")); bottom = atoi(Info_ValueForKey(client->userinfo, "bottomcolor"));
@ -989,51 +948,13 @@ void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf)
if (bottom > 13) if (bottom > 13)
bottom = 13; bottom = 13;
playercolor = top*16 + bottom; playercolor = top*16 + bottom;
MSG_WriteByte (buf, svc_updatecolors);
MSG_WriteByte (buf, i);
MSG_WriteByte (buf, playercolor);
}
#endif
/*
===================
SV_FullClientUpdateToClient
Writes all update values to a client's reliable stream ClientReliableWrite_Begin (to, svc_updatecolors, 3);
=================== ClientReliableWrite_Byte (to, i);
*/ ClientReliableWrite_Byte (to, playercolor);
void SV_FullClientUpdateToClient (client_t *client, client_t *cl)
{
#ifdef NQPROT
if (!ISQWCLIENT(cl))
{
ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo));
if (cl->num_backbuf) {
SVNQ_FullClientUpdate (client, &cl->backbuf);
ClientReliable_FinishWrite(cl);
} else
SVNQ_FullClientUpdate (client, &cl->netchan.message);
}
else
#endif
{
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demofile)
{
int i = client - svs.clients;
ClientReliableCheckBlock(cl, 24 + strlen(sv.recordedplayer[i].userinfo));
}
else
#endif
ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo));
if (cl->num_backbuf) {
SV_FullClientUpdate (client, &cl->backbuf, cl->fteprotocolextensions);
ClientReliable_FinishWrite(cl);
} else
SV_FullClientUpdate (client, &cl->netchan.message, cl->fteprotocolextensions);
} }
} }
/* /*
============================================================================== ==============================================================================
@ -3101,7 +3022,7 @@ qboolean SV_ConnectionlessPacket (void)
} }
#ifdef NQPROT #ifdef NQPROT
void SVNQ_ConnectionlessPacket(void) qboolean SVNQ_ConnectionlessPacket(void)
{ {
sizebuf_t sb; sizebuf_t sb;
int header; int header;
@ -3113,15 +3034,16 @@ void SVNQ_ConnectionlessPacket(void)
char buffer[256], buffer2[256]; char buffer[256], buffer2[256];
netadr_t localaddr; netadr_t localaddr;
if (net_from.type == NA_LOOPBACK) if (net_from.type == NA_LOOPBACK)
return; return false;
if (!sv_listen_nq.value) if (!sv_listen_nq.value)
return; return false;
MSG_BeginReading(svs.netprim); MSG_BeginReading(svs.netprim);
header = LongSwap(MSG_ReadLong()); header = LongSwap(MSG_ReadLong());
if (!(header & NETFLAG_CTL)) if (!(header & NETFLAG_CTL))
{ {
//this nasty chunk of code is to try to handle challenges with nq's challengeless protocol, by using stringcmds. woo. evil hacks.
if (sv_listen_nq.ival == 2) if (sv_listen_nq.ival == 2)
if ((header & (NETFLAG_DATA|NETFLAG_EOM)) == (NETFLAG_DATA|NETFLAG_EOM)) if ((header & (NETFLAG_DATA|NETFLAG_EOM)) == (NETFLAG_DATA|NETFLAG_EOM))
{ {
@ -3154,7 +3076,7 @@ void SVNQ_ConnectionlessPacket(void)
newcl->netchan.incoming_reliable_sequence = sequence; newcl->netchan.incoming_reliable_sequence = sequence;
/*if there is anything else in the packet, we don't actually care. its reliable, so they'll resend*/ /*if there is anything else in the packet, we don't actually care. its reliable, so they'll resend*/
return; return true;
} }
else else
MSG_ReadString(); MSG_ReadString();
@ -3193,15 +3115,17 @@ void SVNQ_ConnectionlessPacket(void)
*(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
return true;
} }
} }
} }
return; //no idea what it is. return false; //no idea what it is.
} }
length = header & NETFLAG_LENGTH_MASK; length = header & NETFLAG_LENGTH_MASK;
if (length != net_message.cursize) if (length != net_message.cursize)
return; //corrupt or not ours return false; //corrupt or not ours
switch(MSG_ReadByte()) switch(MSG_ReadByte())
{ {
@ -3216,7 +3140,7 @@ void SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, "Incorrect game\n"); MSG_WriteString(&sb, "Incorrect game\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
return; //not our game. return false; //not our game.
} }
if (MSG_ReadByte() != NET_PROTOCOL_VERSION) if (MSG_ReadByte() != NET_PROTOCOL_VERSION)
{ {
@ -3226,7 +3150,7 @@ void SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, "Incorrect version\n"); MSG_WriteString(&sb, "Incorrect version\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
return; //not our version... return false; //not our version...
} }
mod = MSG_ReadByte(); mod = MSG_ReadByte();
modver = MSG_ReadByte(); modver = MSG_ReadByte();
@ -3272,10 +3196,10 @@ void SVNQ_ConnectionlessPacket(void)
SVC_DirectConnect(); SVC_DirectConnect();
} }
} }
break; return true;
case CCREQ_SERVER_INFO: case CCREQ_SERVER_INFO:
if (Q_strcmp (MSG_ReadString(), NET_GAMENAME_NQ) != 0) if (Q_strcmp (MSG_ReadString(), NET_GAMENAME_NQ) != 0)
break; return false;
sb.maxsize = sizeof(buffer); sb.maxsize = sizeof(buffer);
sb.data = buffer; sb.data = buffer;
@ -3298,7 +3222,7 @@ void SVNQ_ConnectionlessPacket(void)
MSG_WriteByte (&sb, NET_PROTOCOL_VERSION); MSG_WriteByte (&sb, NET_PROTOCOL_VERSION);
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
break; return true;
case CCREQ_PLAYER_INFO: case CCREQ_PLAYER_INFO:
/*one request per player, ouch ouch ouch, what will it make of 32 players, I wonder*/ /*one request per player, ouch ouch ouch, what will it make of 32 players, I wonder*/
sb.maxsize = sizeof(buffer); sb.maxsize = sizeof(buffer);
@ -3326,7 +3250,7 @@ void SVNQ_ConnectionlessPacket(void)
} }
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
break; return true;
case CCREQ_RULE_INFO: case CCREQ_RULE_INFO:
/*lol, nq is evil*/ /*lol, nq is evil*/
sb.maxsize = sizeof(buffer); sb.maxsize = sizeof(buffer);
@ -3366,8 +3290,9 @@ void SVNQ_ConnectionlessPacket(void)
} }
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from);
break; return true;
} }
return false;
} }
#endif #endif
@ -3476,7 +3401,6 @@ SV_ReadPackets
//FIMXE: move to header //FIMXE: move to header
qboolean SV_GetPacket (void); qboolean SV_GetPacket (void);
#endif #endif
qboolean SV_ReadPackets (float *delay) qboolean SV_ReadPackets (float *delay)
{ {
int i; int i;
@ -3518,7 +3442,7 @@ qboolean SV_ReadPackets (float *delay)
if (ISNQCLIENT(cl)) if (ISNQCLIENT(cl))
{ {
if (cl->state != cs_zombie) if (cl->state > cs_zombie)
{ {
if (NQNetChan_Process(&cl->netchan)) if (NQNetChan_Process(&cl->netchan))
{ {
@ -3695,9 +3619,13 @@ dominping:
#endif #endif
#ifdef NQPROT #ifdef NQPROT
SVNQ_ConnectionlessPacket(); if (SVNQ_ConnectionlessPacket())
continue;
#endif #endif
if (NET_WasSpecialPacket())
continue;
// packet is not from a known client // packet is not from a known client
// Con_Printf ("%s:sequenced packet without connection\n" // Con_Printf ("%s:sequenced packet without connection\n"
// ,NET_AdrToString(net_from)); // ,NET_AdrToString(net_from));
@ -4297,26 +4225,7 @@ void SV_InitLocal (void)
Cvar_Register (&sv_listen_q3, cvargroup_servercontrol); Cvar_Register (&sv_listen_q3, cvargroup_servercontrol);
sv_listen_qw.restriction = RESTRICT_MAX; sv_listen_qw.restriction = RESTRICT_MAX;
#ifdef TCPCONNECT SVNET_RegisterCvars();
Cvar_Register (&sv_port_tcp, cvargroup_servercontrol);
sv_port_tcp.restriction = RESTRICT_MAX;
#ifdef IPPROTO_IPV6
Cvar_Register (&sv_port_tcp6, cvargroup_servercontrol);
sv_port_tcp6.restriction = RESTRICT_MAX;
#endif
#endif
#ifdef IPPROTO_IPV6
Cvar_Register (&sv_port_ipv6, cvargroup_servercontrol);
sv_port_ipv6.restriction = RESTRICT_MAX;
#endif
#ifdef USEIPX
Cvar_Register (&sv_port_ipx, cvargroup_servercontrol);
sv_port_ipx.restriction = RESTRICT_MAX;
#endif
#ifdef HAVE_IPV4
Cvar_Register (&sv_port_ipv4, cvargroup_servercontrol);
sv_port_ipv4.restriction = RESTRICT_MAX;
#endif
Cvar_Register (&sv_reportheartbeats, cvargroup_servercontrol); Cvar_Register (&sv_reportheartbeats, cvargroup_servercontrol);
@ -4397,32 +4306,7 @@ void SV_InitLocal (void)
svs.log[1].cursize = 0; svs.log[1].cursize = 0;
svs.log[1].allowoverflow = true; svs.log[1].allowoverflow = true;
svs.free_lagged_packet = NULL; svs.free_lagged_packet = NULL;
// parse params for cvars
p = COM_CheckParm ("-port");
if (!p)
p = COM_CheckParm ("-svport");
if (p && p < com_argc)
{
int port = atoi(com_argv[p+1]);
if (!port)
port = PORT_QWSERVER;
#ifdef HAVE_IPV4
if (*sv_port_ipv4.string)
Cvar_SetValue(&sv_port_ipv4, port);
#endif
#ifdef IPPROTO_IPV6
if (*sv_port_ipv6.string)
Cvar_SetValue(&sv_port_ipv6, port);
#endif
#ifdef USEIPX
if (*sv_port_ipx.string)
Cvar_SetValue(&sv_port_ipx, port);
#endif
}
} }

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifdef SV_MASTER #ifdef SV_MASTER

View file

@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
#include "winquake.h" #include "winquake.h"
@ -683,7 +683,7 @@ typedef struct
#define SORT_NO 0 #define SORT_NO 0
#define SORT_BY_DATE 1 #define SORT_BY_DATE 1
int Sys_listdirFound(const char *fname, int fsize, void *uptr) int Sys_listdirFound(const char *fname, int fsize, void *uptr, struct searchpath_s *spath)
{ {
file_t *f; file_t *f;
dir_t *dir = uptr; dir_t *dir = uptr;

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// sv_nchan.c, user reliable data stream writes // sv_nchan.c, user reliable data stream writes
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
// check to see if client block will fit, if not, rotate buffers // check to see if client block will fit, if not, rotate buffers

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// sv_phys.c // sv_phys.c
#include "qwsvdef.h" #include "quakedef.h"
#if !defined(CLIENTONLY) || defined(CSQC_DAT) #if !defined(CLIENTONLY) || defined(CSQC_DAT)
#include "pr_common.h" #include "pr_common.h"

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// sv_main.c -- server main program // sv_main.c -- server main program
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -2147,7 +2147,7 @@ void SV_UpdateToReliableMessages (void)
if (host_client->sendinfo) if (host_client->sendinfo)
{ {
host_client->sendinfo = false; host_client->sendinfo = false;
SV_FullClientUpdate (host_client, &sv.reliable_datagram, host_client->fteprotocolextensions); SV_FullClientUpdate (host_client, NULL);
} }
if (host_client->old_frags != curfrags) if (host_client->old_frags != curfrags)
{ {

View file

@ -131,27 +131,30 @@ queryresult_t *SQL_PullResult(sqlserver_t *server)
return qres; return qres;
} }
//called by main thread
void SQL_PushRequest(sqlserver_t *server, queryrequest_t *qreq) void SQL_PushRequest(sqlserver_t *server, queryrequest_t *qreq)
{ {
qreq->state = SR_PENDING;
Sys_LockConditional(server->requestcondv); Sys_LockConditional(server->requestcondv);
qreq->next = NULL; qreq->nextqueue = NULL;
if (!server->requestslast) if (!server->requestslast)
server->requests = server->requestslast = qreq; server->requestqueue = server->requestslast = qreq;
else else
server->requestslast = server->requestslast->next = qreq; server->requestslast = server->requestslast->nextqueue = qreq;
Sys_UnlockConditional(server->requestcondv); Sys_UnlockConditional(server->requestcondv);
} }
//called by sql worker thread
queryrequest_t *SQL_PullRequest(sqlserver_t *server, qboolean lock) queryrequest_t *SQL_PullRequest(sqlserver_t *server, qboolean lock)
{ {
queryrequest_t *qreq; queryrequest_t *qreq;
if (lock) if (lock)
Sys_LockConditional(server->requestcondv); Sys_LockConditional(server->requestcondv);
qreq = server->requests; qreq = server->requestqueue;
if (qreq) if (qreq)
{ {
server->requests = qreq->next; server->requestqueue = qreq->nextqueue;
if (!server->requests) if (!server->requestqueue)
server->requestslast = NULL; server->requestslast = NULL;
} }
Sys_UnlockConditional(server->requestcondv); Sys_UnlockConditional(server->requestcondv);
@ -249,7 +252,7 @@ int sql_serverworker(void *sref)
while (allokay) while (allokay)
{ {
Sys_LockConditional(server->requestcondv); Sys_LockConditional(server->requestcondv);
if (!server->requests) // this is needed for thread startup and to catch any "lost" changes if (!server->requestqueue) // this is needed for thread startup and to catch any "lost" changes
Sys_ConditionWait(server->requestcondv); Sys_ConditionWait(server->requestcondv);
needlock = false; // so we don't try to relock first round needlock = false; // so we don't try to relock first round
@ -313,7 +316,6 @@ int sql_serverworker(void *sref)
qres->columns = columns; qres->columns = columns;
qres->request = qreq; qres->request = qreq;
qres->eof = true; // store result has no more rows to read afterwards qres->eof = true; // store result has no more rows to read afterwards
qreq->next = NULL;
SQL_PushResult(server, qres); SQL_PushResult(server, qres);
} }
@ -363,7 +365,7 @@ int sql_serverworker(void *sref)
qres->request = qreq; qres->request = qreq;
qres->firstrow = totalrows; qres->firstrow = totalrows;
qres->eof = false; qres->eof = false;
qreq->next = NULL; qreq->nextqueue = NULL;
//headers technically take a row. //headers technically take a row.
for (i = 0; i < columns; i++) for (i = 0; i < columns; i++)
@ -428,7 +430,7 @@ int sql_serverworker(void *sref)
qres->firstrow = totalrows; qres->firstrow = totalrows;
qres->request = qreq; qres->request = qreq;
qres->eof = true; qres->eof = true;
qreq->next = NULL; qreq->nextqueue = NULL;
SQL_PushResult(server, qres); SQL_PushResult(server, qres);
} }
@ -495,16 +497,26 @@ sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives)
return sqlservers[serveridx]; return sqlservers[serveridx];
} }
queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx) queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx)
{
queryrequest_t *qreq;
for (qreq = server->requests; qreq; qreq = qreq->nextreq)
{
if (qreq->num == queryidx)
return qreq;
}
return NULL;
}
queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx, int row)
{ {
queryresult_t *qres; queryresult_t *qres;
queryrequest_t *qreq;
qres = server->currentresult; qreq = SQL_GetQueryRequest(server, queryidx);
if (qres && qres->request && qres->request->num == queryidx) for (qres = qreq->results; qres; qres = qres->next)
return qres; if (qres->request && qres->request->num == queryidx && row >= qres->firstrow && row < qres->firstrow + qres->rows)
for (qres = server->persistresults; qres; qres = qres->next)
if (qres->request && qres->request->num == queryidx)
return qres; return qres;
return NULL; return NULL;
@ -533,20 +545,18 @@ static void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres)
break; break;
#endif #endif
} }
if (qres->request)
Z_Free(qres->request);
Z_Free(qres); Z_Free(qres);
} }
void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres) static void SQL_CloseRequestResult(sqlserver_t *server, queryresult_t *qres)
{ {
queryresult_t *prev, *cur; queryresult_t *prev, *cur;
prev = server->persistresults; prev = qres->request->results;
if (prev == qres) if (prev == qres)
{ {
server->persistresults = prev->next; qres->request->results = prev->next;
SQL_DeallocResult(server, prev); SQL_DeallocResult(server, prev);
return; return;
} }
@ -562,25 +572,62 @@ void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres)
} }
} }
//MT only. flush a result without discarding the request. will result in gaps.
void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres) void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres)
{ {
if (!qres) if (!qres)
return; return;
if (qres == server->currentresult) /* if (qres == server->currentresult)
{ {
SQL_DeallocResult(server, server->currentresult); SQL_DeallocResult(server, server->currentresult);
server->currentresult = NULL; server->currentresult = NULL;
return; return;
} }
*/
// else we have a persistant query // else we have a persistant query
SQL_ClosePersistantResult(server, qres); SQL_CloseRequestResult(server, qres);
} }
void SQL_CloseAllResults(sqlserver_t *server) //MT only. releases the request.
void SQL_CloseRequest(sqlserver_t *server, queryrequest_t *qreq, qboolean force)
{
while(qreq->results)
{
SQL_CloseResult(server, qreq->results);
}
//if the worker thread is still active with it for whatever reason, flag it as aborted but keep it otherwise valid. actually close it later on when we get the results back.
if (qreq->state != SR_FINISHED && qreq->state != SR_NEW)
qreq->state = SR_ABORTED;
else
{
queryrequest_t *prev, *cur;
//unlink and free it now that its complete.
prev = server->requests;
if (prev == qreq)
server->requests = prev->nextreq;
else
{
for (cur = prev->nextreq; cur; prev = cur, cur = prev->nextreq)
{
if (cur == qreq)
{
prev->nextreq = cur->nextreq;
break;
}
}
}
Z_Free(qreq);
}
}
void SQL_CloseAllRequests(sqlserver_t *server)
{ {
queryresult_t *oldqres, *qres; queryresult_t *oldqres, *qres;
// close orphaned results (we assume the lock is active or non-existant at this point) //we assume lock is either held or the thread has already died. this function isn't (worker)thread safe.
// close pending results
qres = server->results; qres = server->results;
while (qres) while (qres)
{ {
@ -588,21 +635,13 @@ void SQL_CloseAllResults(sqlserver_t *server)
qres = qres->next; qres = qres->next;
SQL_DeallocResult(server, oldqres); SQL_DeallocResult(server, oldqres);
} }
// close current
if (server->currentresult) //now terminate all the requests
while(server->requests)
{ {
SQL_DeallocResult(server, server->currentresult); SQL_CloseRequest(server, server->requests, true);
server->currentresult = NULL;
} }
// close persistant results
qres = server->persistresults;
while (qres)
{
oldqres = qres;
qres = qres->next;
SQL_DeallocResult(server, oldqres);
}
server->persistresults = NULL;
// close server result // close server result
if (server->serverresult) if (server->serverresult)
{ {
@ -613,10 +652,11 @@ void SQL_CloseAllResults(sqlserver_t *server)
char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields) char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields)
{ {
if (!qres->result) // TODO: partial resultset logic not implemented yet if (!qres->result)
return NULL; return NULL;
else else
{ // store_result query { // store_result query
row -= qres->firstrow;
if (qres->rows < row || qres->columns < col || col < 0) if (qres->rows < row || qres->columns < col || col < 0)
return NULL; return NULL;
@ -705,15 +745,15 @@ void SQL_CleanupServer(sqlserver_t *server)
Sys_DestroyMutex(server->resultlock); Sys_DestroyMutex(server->resultlock);
// close orphaned requests // close orphaned requests
qreq = server->requests; qreq = server->requestqueue;
while (qreq) while (qreq)
{ {
oldqreq = qreq; oldqreq = qreq;
qreq = qreq->next; qreq = qreq->nextqueue;
Z_Free(oldqreq); Z_Free(oldqreq);
} }
SQL_CloseAllResults(server); SQL_CloseAllRequests(server);
for (i = SQL_CONNECT_STRUCTPARAMS; i < SQL_CONNECT_PARAMS; i++) for (i = SQL_CONNECT_STRUCTPARAMS; i < SQL_CONNECT_PARAMS; i++)
Z_Free(server->connectparams[i]); Z_Free(server->connectparams[i]);
@ -833,7 +873,7 @@ int SQL_NewServer(char *driver, char **paramstr)
return serverref; return serverref;
} }
int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float selfid, int other, float otherid, char *str) int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof), char *str, queryrequest_t **reqout)
{ {
int qsize = Q_strlen(str); int qsize = Q_strlen(str);
queryrequest_t *qreq; queryrequest_t *qreq;
@ -842,27 +882,32 @@ int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float se
qreq = (queryrequest_t *)ZF_Malloc(sizeof(queryrequest_t) + qsize); qreq = (queryrequest_t *)ZF_Malloc(sizeof(queryrequest_t) + qsize);
if (qreq) if (qreq)
{ {
qreq->persistant = (type == 1); qreq->state = SR_NEW;
qreq->callback = callfunc;
qreq->selfent = self;
qreq->selfid = selfid;
qreq->otherent = other;
qreq->otherid = otherid;
querynum = qreq->num = server->querynum; querynum = qreq->num = server->querynum;
// prevent the reference num from getting too big to prevent FP problems // prevent the reference num from getting too big to prevent FP problems
if (++server->querynum > 1000000) while(1)
{
if (++server->querynum > (1<<21))
server->querynum = 1; server->querynum = 1;
if (!SQL_GetQueryRequest(server, server->querynum))
break;
}
qreq->callback = callback;
Q_strncpy(qreq->query, str, qsize); Q_strncpy(qreq->query, str, qsize);
qreq->nextreq = server->requests;
server->requests = qreq;
SQL_PushRequest(server, qreq); SQL_PushRequest(server, qreq);
Sys_ConditionSignal(server->requestcondv); Sys_ConditionSignal(server->requestcondv);
*reqout = qreq;
return querynum; return querynum;
} }
*reqout = NULL;
return -1; return -1;
} }
@ -945,6 +990,7 @@ qboolean SQL_Available(void)
void SQL_Status_f(void) void SQL_Status_f(void)
{ {
int i; int i;
char *stat;
if (!SQL_Available()) if (!SQL_Available())
Con_Printf("No SQL library available.\n"); Con_Printf("No SQL library available.\n");
@ -964,7 +1010,7 @@ void SQL_Status_f(void)
Sys_LockMutex(server->resultlock); Sys_LockMutex(server->resultlock);
Sys_LockConditional(server->requestcondv); Sys_LockConditional(server->requestcondv);
for (qreq = server->requests; qreq; qreq = qreq->next) for (qreq = server->requests; qreq; qreq = qreq->nextreq)
reqnum++; reqnum++;
for (qres = server->results; qres; qres = qres->next) for (qres = server->results; qres; qres = qres->next)
resnum++; resnum++;
@ -988,11 +1034,21 @@ void SQL_Status_f(void)
if (reqnum) if (reqnum)
{ {
Con_Printf ("- %i requests\n"); Con_Printf ("- %i requests\n", reqnum);
for (qreq = server->requests; qreq; qreq = qreq->next) for (qreq = server->requests; qreq; qreq = qreq->nextqueue)
{ {
Con_Printf (" query #%i: %s\n", switch (qreq->state)
{
case SR_NEW: stat = "new"; break;
case SR_PENDING: stat = "pending"; break;
case SR_PARTIAL: stat = "partial"; break;
case SR_FINISHED: stat = "finished"; break;
case SR_ABORTED: stat = "aborted"; break;
default: stat = "???"; break;
}
Con_Printf (" query #%i (%s): %s\n",
qreq->num, qreq->num,
stat,
qreq->query); qreq->query);
// TODO: function lookup? // TODO: function lookup?
} }
@ -1000,7 +1056,7 @@ void SQL_Status_f(void)
if (resnum) if (resnum)
{ {
Con_Printf ("- %i results\n"); Con_Printf ("- %i pending results\n", resnum);
for (qres = server->results; qres; qres = qres->next) for (qres = server->results; qres; qres = qres->next)
{ {
Con_Printf (" * %i rows, %i columns", Con_Printf (" * %i rows, %i columns",
@ -1047,7 +1103,7 @@ void SQL_Killall_f (void)
SQL_KillServers(); SQL_KillServers();
} }
void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void SQL_ServerCycle (void)
{ {
int i; int i;
@ -1055,69 +1111,61 @@ void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
sqlserver_t *server = sqlservers[i]; sqlserver_t *server = sqlservers[i];
queryresult_t *qres; queryresult_t *qres;
queryrequest_t *qreq;
if (!server) if (!server)
continue; continue;
while (qres = SQL_PullResult(server))
{
qreq = qres->request;
qres->next = NULL;
if (qreq && qreq->callback)
{
qboolean persist;
//save it for later.
qres->next = qreq->results;
qreq->results = qres;
if (qreq->state == SR_ABORTED)
{
persist = false;
if (qres->eof)
SQL_CloseRequest(server, qreq, true);
}
else
{
if (qreq->state == SR_FINISHED)
Sys_Error("SQL: Results after finished!\n");
if (qreq->state == SR_PENDING)
qreq->state = SR_PARTIAL;
if (qres->eof)
qreq->state = SR_FINISHED;
persist = qreq->callback(qreq, qres->firstrow, qres->rows, qres->columns, qres->eof);
}
if (!persist)
{
SQL_CloseResult(server, qres);
if (qreq->state == SR_FINISHED)
SQL_CloseRequest(server, qreq, false);
}
}
else // error or server-only result
{
if (server->serverresult)
SQL_CloseResult(server, server->serverresult);
server->serverresult = qres;
}
}
if (server->terminated) if (server->terminated)
{ {
sqlservers[i] = NULL; sqlservers[i] = NULL;
SQL_CleanupServer(server); SQL_CleanupServer(server);
continue; continue;
} }
while (qres = SQL_PullResult(server))
{
qres->next = NULL;
if (qres->request && qres->request->callback)
{
if (server->active)
{ // only process results to callback if server is active
edict_t *ent;
server->currentresult = qres;
G_FLOAT(OFS_PARM0) = i;
G_FLOAT(OFS_PARM1) = qres->request->num;
G_FLOAT(OFS_PARM2) = qres->rows;
G_FLOAT(OFS_PARM3) = qres->columns;
G_FLOAT(OFS_PARM4) = qres->eof;
G_FLOAT(OFS_PARM5) = qres->firstrow;
// recall self and other references
ent = PROG_TO_EDICT(prinst, qres->request->selfent);
if (ent->isfree || ent->xv->uniquespawnid != qres->request->selfid)
pr_global_struct->self = pr_global_struct->world;
else
pr_global_struct->self = qres->request->selfent;
ent = PROG_TO_EDICT(prinst, qres->request->otherent);
if (ent->isfree || ent->xv->uniquespawnid != qres->request->otherid)
pr_global_struct->other = pr_global_struct->world;
else
pr_global_struct->other = qres->request->otherent;
PR_ExecuteProgram(prinst, qres->request->callback);
if (server->currentresult)
{
if (server->currentresult->request && server->currentresult->request->persistant)
{
// move into persistant list
server->currentresult->next = server->persistresults;
server->persistresults = server->currentresult;
}
else // just close the query
SQL_CloseResult(server, server->currentresult);
}
}
}
else // error or server-only result
{
if (server->serverresult)
Z_Free(server->serverresult);
server->serverresult = qres;
}
}
server->currentresult = NULL;
} }
} }

View file

@ -20,14 +20,30 @@ typedef enum
typedef struct queryrequest_s typedef struct queryrequest_s
{ {
int srvid;
int num; /* query number reference */ int num; /* query number reference */
struct queryrequest_s *nextqueue; /* next request in queue */
struct queryrequest_s *nextreq; /* next request in queue */
struct queryresult_s *results; /* chain of received results */
enum
{
SR_NEW,
SR_PENDING,
SR_PARTIAL, //
SR_FINISHED, //waiting for close
SR_ABORTED //don't notify. destroy on finish.
} state; //maintained by main thread. worker *may* check for aborted state as a way to quickly generate an error.
qboolean (*callback)(struct queryrequest_s *req, int firstrow, int numrows, int numcols, qboolean eof); /* called on main thread once complete */
struct
{
qboolean persistant; /* persistant query */ qboolean persistant; /* persistant query */
struct queryrequest_s *next; /* next request in queue */ int qccallback; /* callback function reference */
int callback; /* callback function reference */
int selfent; /* self entity on call */ int selfent; /* self entity on call */
float selfid; /* self entity id on call */ float selfid; /* self entity id on call */
int otherent; /* other entity on call */ int otherent; /* other entity on call */
float otherid; /* other entity id on call */ float otherid; /* other entity id on call */
void *thread;
} user; /* sql code does not write anything in this struct */
char query[1]; /* query to run */ char query[1]; /* query to run */
} queryrequest_t; } queryrequest_t;
@ -61,13 +77,12 @@ typedef struct sqlserver_s
void *requestcondv; /* lock and conditional variable for queue read/write */ void *requestcondv; /* lock and conditional variable for queue read/write */
void *resultlock; /* mutex for queue read/write */ void *resultlock; /* mutex for queue read/write */
int querynum; /* next reference number for queries */ int querynum; /* next reference number for queries */
queryrequest_t *requests; /* query requests queue */ queryrequest_t *requests; /* list of pending and persistant requests */
queryrequest_t *requestqueue; /* query requests queue */
queryrequest_t *requestslast; /* query requests queue last link */ queryrequest_t *requestslast; /* query requests queue last link */
queryresult_t *results; /* query results queue */ queryresult_t *results; /* query results queue */
queryresult_t *resultslast; /* query results queue last link */ queryresult_t *resultslast; /* query results queue last link */
queryresult_t *currentresult; /* current called result */ queryresult_t *serverresult; /* most recent (orphaned) server error result */
queryresult_t *persistresults; /* list of persistant results */
queryresult_t *serverresult; /* server error results */
char **connectparams; /* connect parameters (0 = host, 1 = user, 2 = pass, 3 = defaultdb) */ char **connectparams; /* connect parameters (0 = host, 1 = user, 2 = pass, 3 = defaultdb) */
} sqlserver_t; } sqlserver_t;
@ -77,19 +92,21 @@ void SQL_KillServers(void);
void SQL_DeInit(void); void SQL_DeInit(void);
sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives); sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives);
queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx); queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx);
queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx, int row);
//void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres); //void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres);
void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres); void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres);
void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres); void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres);
void SQL_CloseRequest(sqlserver_t *server, queryrequest_t *qres, qboolean force);
void SQL_CloseAllResults(sqlserver_t *server); void SQL_CloseAllResults(sqlserver_t *server);
char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields); char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields);
int SQL_NewServer(char *driver, char **paramstr); int SQL_NewServer(char *driver, char **paramstr);
int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float selfid, int other, float otherid, char *str); int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof), char *str, queryrequest_t **reqout); //callback will be called on the main thread once the result is back
void SQL_Disconnect(sqlserver_t *server); void SQL_Disconnect(sqlserver_t *server);
void SQL_Escape(sqlserver_t *server, char *src, char *dst, int dstlen); void SQL_Escape(sqlserver_t *server, char *src, char *dst, int dstlen);
const char *SQL_Info(sqlserver_t *server); const char *SQL_Info(sqlserver_t *server);
qboolean SQL_Available(void); qboolean SQL_Available(void);
void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void SQL_ServerCycle (void);
extern cvar_t sql_driver; extern cvar_t sql_driver;
extern cvar_t sql_host; extern cvar_t sql_host;

View file

@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "qwsvdef.h" #include "quakedef.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/timeb.h> #include <sys/timeb.h>
@ -425,7 +425,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname)
return !rename(oldfname, newfname); return !rename(oldfname, newfname);
} }
int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath)
{ {
HANDLE r; HANDLE r;
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;
@ -457,13 +457,13 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
if (*fd.cFileName != '.') if (*fd.cFileName != '.')
{ {
Q_snprintfz(file, sizeof(file), "%s%s/", apath, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s/", apath, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
else else
{ {
Q_snprintfz(file, sizeof(file), "%s%s", apath, fd.cFileName); Q_snprintfz(file, sizeof(file), "%s%s", apath, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm); go = func(file, fd.nFileSizeLow, parm, spath);
} }
} }
while(FindNextFile(r, &fd) && go); while(FindNextFile(r, &fd) && go);
@ -731,11 +731,15 @@ void ApplyColour(unsigned int chr)
void Sys_PrintColouredChar(unsigned int chr) void Sys_PrintColouredChar(unsigned int chr)
{ {
DWORD dummy;
wchar_t wc;
if (chr & CON_HIDDEN) if (chr & CON_HIDDEN)
return; return;
ApplyColour(chr); ApplyColour(chr);
printf("%c", chr & CON_CHARMASK); wc = chr & CON_CHARMASK;
WriteConsoleW(hconsoleout, &wc, 1, &dummy, NULL);
} }
/* /*
@ -1003,6 +1007,9 @@ void Sys_Init (void)
Cmd_AddCommand("hide", Sys_HideConsole); Cmd_AddCommand("hide", Sys_HideConsole);
hconsoleout = GetStdHandle(STD_OUTPUT_HANDLE); hconsoleout = GetStdHandle(STD_OUTPUT_HANDLE);
// SetConsoleCP(CP_UTF8);
// SetConsoleOutputCP(CP_UTF8);
} }
void Sys_Shutdown (void) void Sys_Shutdown (void)
@ -1336,4 +1343,28 @@ void Sys_Sleep (double seconds)
{ {
Sleep(seconds * 1000); Sleep(seconds * 1000);
} }
/*
================
Sys_RandomBytes
================
*/
#include <wincrypt.h>
qboolean Sys_RandomBytes(qbyte *string, int len)
{
HCRYPTPROV prov;
if(!CryptAcquireContext( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
return false;
}
if(!CryptGenRandom(prov, len, (BYTE *)string))
{
CryptReleaseContext( prov, 0);
return false;
}
CryptReleaseContext(prov, 0);
return true;
}
#endif #endif

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// sv_user.c -- server code for moving users // sv_user.c -- server code for moving users
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY
#include "pr_common.h" #include "pr_common.h"
@ -1458,7 +1458,7 @@ void SVQW_Spawn_f (void)
// normally this could overflow, but no need to check due to backbuf // normally this could overflow, but no need to check due to backbuf
for (i=0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++) for (i=0, client = svs.clients ; i<MAX_CLIENTS ; i++, client++)
SV_FullClientUpdateToClient (client, host_client); SV_FullClientUpdate(client, host_client);
SV_MVD_FullClientUpdate(NULL, host_client); SV_MVD_FullClientUpdate(NULL, host_client);
// send all current light styles // send all current light styles
@ -2797,6 +2797,7 @@ void SV_BeginDownload_f(void)
if (result == -5) if (result == -5)
{ {
//package download
result = 0; result = 0;
host_client->download = FS_OpenVFS(name+8, "rb", FS_ROOT); host_client->download = FS_OpenVFS(name+8, "rb", FS_ROOT);
} }
@ -2805,6 +2806,15 @@ void SV_BeginDownload_f(void)
//redirection protocol-specific code goes here. //redirection protocol-specific code goes here.
if (result == -4) if (result == -4)
{ {
#ifdef PEXT_CHUNKEDDOWNLOADS
if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS)
{
//redirect the client (before the message saying download failed)
char *s = va("dlsize \"%s\" r \"%s\"\n", name, redirection);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String (host_client, s);
}
#endif
} }
if (result == 0) if (result == 0)
@ -2830,18 +2840,11 @@ void SV_BeginDownload_f(void)
break; break;
case -4: case -4:
result = -1; result = -1;
error = ""; error = "Package contents not available individually\n";
break; break;
} }
if (ISNQCLIENT(host_client))
{
SV_PrintToClient(host_client, PRINT_HIGH, error);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12);
ClientReliableWrite_String (host_client, "\nstopdownload\n");
}
#ifdef PEXT_CHUNKEDDOWNLOADS #ifdef PEXT_CHUNKEDDOWNLOADS
else if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS)
{ {
ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(name)); ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(name));
ClientReliableWrite_Long (host_client, -1); ClientReliableWrite_Long (host_client, -1);
@ -2850,6 +2853,14 @@ void SV_BeginDownload_f(void)
} }
else else
#endif #endif
if (ISNQCLIENT(host_client))
{
SV_PrintToClient(host_client, PRINT_HIGH, error);
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12);
ClientReliableWrite_String (host_client, "\nstopdownload\n");
}
else
{ {
SV_PrintToClient(host_client, PRINT_HIGH, error); SV_PrintToClient(host_client, PRINT_HIGH, error);
@ -2857,15 +2868,6 @@ void SV_BeginDownload_f(void)
ClientReliableWrite_Short (host_client, -1); ClientReliableWrite_Short (host_client, -1);
ClientReliableWrite_Byte (host_client, 0); ClientReliableWrite_Byte (host_client, 0);
} }
//it errored because it was a redirection.
//ask the client to grab the alternate file instead.
if (redirection)
{
//tell the client to download the new one.
ClientReliableWrite_Begin (host_client, ISQ2CLIENT(host_client)?svcq2_stufftext:svc_stufftext, 2+strlen(redirection));
ClientReliableWrite_String (host_client, va("\ndownload \"%s\"\n", redirection));
}
return; return;
} }
@ -4418,7 +4420,7 @@ void SVNQ_Spawn_f (void)
// normally this could overflow, but no need to check due to backbuf // normally this could overflow, but no need to check due to backbuf
for (i=0, client = svs.clients; i<sv.allocated_client_slots ; i++, client++) for (i=0, client = svs.clients; i<sv.allocated_client_slots ; i++, client++)
SV_FullClientUpdateToClient (client, host_client); SV_FullClientUpdate(client, host_client);
SV_MVD_FullClientUpdate(NULL, host_client); SV_MVD_FullClientUpdate(NULL, host_client);
// send all current light styles // send all current light styles

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
/* /*
I think globals.maxentities is the hard cap, rather than current max like in q1. I think globals.maxentities is the hard cap, rather than current max like in q1.

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// sv_phys.c // sv_phys.c
#include "qwsvdef.h" #include "quakedef.h"
#ifdef HLSERVER #ifdef HLSERVER

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// world.c -- world query functions // world.c -- world query functions
#include "qwsvdef.h" #include "quakedef.h"
#ifdef HLSERVER #ifdef HLSERVER
#include "svhl_gcapi.h" #include "svhl_gcapi.h"

View file

@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
// models.c -- model loading and caching // models.c -- model loading and caching
#include "qwsvdef.h" #include "quakedef.h"
#ifdef SERVERONLY #ifdef SERVERONLY
model_t *loadmodel; model_t *loadmodel;

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#ifndef CLIENTONLY #ifndef CLIENTONLY

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
#define Q2NUM_FOR_EDICT(ent) (((char *)ent - (char *)ge->edicts) / ge->edict_size) #define Q2NUM_FOR_EDICT(ent) (((char *)ent - (char *)ge->edicts) / ge->edict_size)

View file

@ -1,4 +1,4 @@
#include "qwsvdef.h" #include "quakedef.h"
//An implementation of a Q3 server... //An implementation of a Q3 server...
//requires qvm implementation and existing q3 client stuff (or at least the overlapping stuff in q3common.c). //requires qvm implementation and existing q3 client stuff (or at least the overlapping stuff in q3common.c).

View file

@ -229,6 +229,7 @@ void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, net
} }
} }
#if 0
int Netchan_IsLocal (netadr_t adr) int Netchan_IsLocal (netadr_t adr)
{ {
struct sockaddr_in *sadr = (struct sockaddr_in *)&adr; struct sockaddr_in *sadr = (struct sockaddr_in *)&adr;
@ -267,7 +268,7 @@ int Netchan_IsLocal (netadr_t adr)
return false; return false;
} }
} }
#endif

View file

@ -862,7 +862,7 @@ void PM_PlayerMove (pmove_t *pmove);
void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient); void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient);
void Netchan_OutOfBandPrint (cluster_t *cluster, netadr_t adr, char *format, ...) PRINTFWARNING(3); void Netchan_OutOfBandPrint (cluster_t *cluster, netadr_t adr, char *format, ...) PRINTFWARNING(3);
int Netchan_IsLocal (netadr_t adr); //int Netchan_IsLocal (netadr_t adr);
void NET_InitUDPSocket(cluster_t *cluster, int port, qboolean ipv6); void NET_InitUDPSocket(cluster_t *cluster, int port, qboolean ipv6);
void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr); void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr);
SOCKET NET_ChooseSocket(SOCKET sock[], netadr_t *adr); SOCKET NET_ChooseSocket(SOCKET sock[], netadr_t *adr);

View file

@ -2770,13 +2770,13 @@ I've removed the following from this function as it covered the menu (~Moodles):
tuiadmin: tuiadmin:
if (!*cluster->adminpassword) if (!*cluster->adminpassword)
{ {
if (Netchan_IsLocal(v->netchan.remote_address)) /*if (Netchan_IsLocal(v->netchan.remote_address))
{ {
Sys_Printf(cluster, "Local player %s logs in as admin\n", v->name); Sys_Printf(cluster, "Local player %s logs in as admin\n", v->name);
QW_SetMenu(v, MENU_ADMIN); QW_SetMenu(v, MENU_ADMIN);
v->isadmin = true; v->isadmin = true;
} }
else else*/
QW_PrintfToViewer(v, "There is no admin password set\nYou may not log in.\n"); QW_PrintfToViewer(v, "There is no admin password set\nYou may not log in.\n");
} }
else if (v->isadmin) else if (v->isadmin)

View file

@ -1,16 +1,22 @@
//Released under the terms of the gpl as this file uses a bit of quake derived code. All sections of the like are marked as such //Released under the terms of the gpl as this file uses a bit of quake derived code. All sections of the like are marked as such
#include "../plugin.h" #include "../plugin.h"
#include <time.h>
#define Q_strncpyz(o, i, l) do {strncpy(o, i, l-1);o[l-1]='\0';}while(0) #define Q_strncpyz(o, i, l) do {strncpy(o, i, l-1);o[l-1]='\0';}while(0)
#define JCL_BUILD "1" #define JCL_BUILD "2"
#define ARGNAMES ,sock #define ARGNAMES ,sock,certhostname
BUILTINR(int, Net_SetTLSClient, (qhandle_t sock)); BUILTINR(int, Net_SetTLSClient, (qhandle_t sock, const char *certhostname));
#undef ARGNAMES #undef ARGNAMES
void (*Con_TrySubPrint)(const char *conname, const char *message);
void Fallback_ConPrint(const char *conname, const char *message)
{
Con_Print(message);
}
void Con_SubPrintf(char *subname, char *format, ...) void Con_SubPrintf(char *subname, char *format, ...)
{ {
@ -21,7 +27,7 @@ void Con_SubPrintf(char *subname, char *format, ...)
vsnprintf (string, sizeof(string), format,argptr); vsnprintf (string, sizeof(string), format,argptr);
va_end (argptr); va_end (argptr);
Con_SubPrint(subname, string); Con_TrySubPrint(subname, string);
} }
@ -123,7 +129,7 @@ void Con_SubPrintf(char *subname, char *format, ...)
void JCL_Command(void); void JCL_Command(void);
int JCL_ExecuteCommand(int *args) qintptr_t JCL_ExecuteCommand(qintptr_t *args)
{ {
char cmd[256]; char cmd[256];
Cmd_Argv(0, cmd, sizeof(cmd)); Cmd_Argv(0, cmd, sizeof(cmd));
@ -135,13 +141,11 @@ int JCL_ExecuteCommand(int *args)
return false; return false;
} }
int JCL_ConExecuteCommand(int *args); qintptr_t JCL_ConExecuteCommand(qintptr_t *args);
int JCL_Frame(int *args); qintptr_t JCL_Frame(qintptr_t *args);
int (*Con_TrySubPrint)(char *conname, char *message); qintptr_t Plug_Init(qintptr_t *args)
int Plug_Init(int *args)
{ {
if ( Plug_Export("Tick", JCL_Frame) && if ( Plug_Export("Tick", JCL_Frame) &&
Plug_Export("ExecuteCommand", JCL_ExecuteCommand)) Plug_Export("ExecuteCommand", JCL_ExecuteCommand))
@ -155,7 +159,7 @@ int Plug_Init(int *args)
if (!Plug_Export("ConExecuteCommand", JCL_ConExecuteCommand)) if (!Plug_Export("ConExecuteCommand", JCL_ConExecuteCommand))
{ {
Con_Printf("Jabber client plugin in single-console mode\n"); Con_Printf("Jabber client plugin in single-console mode\n");
Con_TrySubPrint = Con_Print; Con_TrySubPrint = Fallback_ConPrint;
} }
else else
Con_TrySubPrint = Con_SubPrint; Con_TrySubPrint = Con_SubPrint;
@ -182,7 +186,7 @@ int Plug_Init(int *args)
//but never used cos it breaks strings //but never used cos it breaks strings
#define JCL_MAXMSGLEN 2048 #define JCL_MAXMSGLEN 10000
typedef struct { typedef struct {
@ -193,7 +197,9 @@ typedef struct {
qhandle_t inlog; qhandle_t inlog;
qhandle_t outlog; qhandle_t outlog;
char bufferedinmessage[JCL_MAXMSGLEN+1]; //there is a max size for protocol. (conveinient eh?) (and it's text format) char bufferedinmessage[JCL_MAXMSGLEN+1]; //servers are required to be able to handle messages no shorter than a specific size.
//which means we need to be able to handle messages when they get to us.
//servers can still handle larger messages if they choose, so this might not be enough.
int bufferedinammount; int bufferedinammount;
char defaultdest[256]; char defaultdest[256];
@ -207,12 +213,16 @@ typedef struct {
int openbracket; int openbracket;
int instreampos; int instreampos;
qboolean noplain; qboolean connected; //fully on server and authed and everything.
qboolean issecure; qboolean noplain; //block plain-text password exposure
qboolean issecure; //tls enabled
char curquakeserver[2048];
char defaultnamespace[2048]; //should be 'jabber:client' or blank (and spammy with all the extra xmlns attribs)
} jclient_t; } jclient_t;
jclient_t *jclient; jclient_t *jclient;
int JCL_ConExecuteCommand(int *args) qintptr_t JCL_ConExecuteCommand(qintptr_t *args)
{ {
if (!jclient) if (!jclient)
{ {
@ -229,7 +239,7 @@ int JCL_ConExecuteCommand(int *args)
void JCL_AddClientMessage(jclient_t *jcl, char *msg, int datalen) void JCL_AddClientMessage(jclient_t *jcl, char *msg, int datalen)
{ {
Net_Send(jcl->socket, msg, datalen); //FIXME: This needs rewriting to cope with errors. Net_Send(jcl->socket, msg, datalen); //FIXME: This needs rewriting to cope with errors.
Con_Printf(COLOURYELLOW "<< %s \n",msg); Con_SubPrintf("xmppout", COLOURYELLOW "%s \n",msg);
} }
void JCL_AddClientMessageString(jclient_t *jcl, char *msg) void JCL_AddClientMessageString(jclient_t *jcl, char *msg)
{ {
@ -275,7 +285,7 @@ jclient_t *JCL_Connect(char *server, int defport, qboolean usesecure, char *acco
if (usesecure) if (usesecure)
{ {
if (Net_SetTLSClient(jcl->socket)<0) if (Net_SetTLSClient(jcl->socket, server)<0)
{ {
Net_Close(jcl->socket); Net_Close(jcl->socket);
free(jcl); free(jcl);
@ -299,7 +309,7 @@ jclient_t *JCL_Connect(char *server, int defport, qboolean usesecure, char *acco
strlcpy(jcl->domain, at+1, sizeof(jcl->domain)); strlcpy(jcl->domain, at+1, sizeof(jcl->domain));
strlcpy(jcl->password, password, sizeof(jcl->password)); strlcpy(jcl->password, password, sizeof(jcl->password));
strcpy(jcl->resource, "Quake"); strlcpy(jcl->resource, "Quake", sizeof(jcl->password));
Con_Printf("Trying to connect\n"); Con_Printf("Trying to connect\n");
JCL_AddClientMessageString(jcl, JCL_AddClientMessageString(jcl,
@ -320,6 +330,8 @@ typedef struct xmlparams_s {
typedef struct subtree_s { typedef struct subtree_s {
char name[64]; char name[64];
char xmlns[64]; //namespace of the element
char xmlns_dflt[64]; //default namespace of children
char body[2048]; char body[2048];
xmlparams_t *params; xmlparams_t *params;
@ -329,7 +341,18 @@ typedef struct subtree_s {
} xmltree_t; } xmltree_t;
void XML_Destroy(xmltree_t *t); void XML_Destroy(xmltree_t *t);
xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronly)
char *XML_ParameterOfTree(xmltree_t *t, char *paramname)
{
xmlparams_t *p;
for (p = t->params; p; p = p->next)
if (!strcmp(p->name, paramname))
return p->val;
return NULL;
}
//fixme: we should accept+parse the default namespace
xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronly, char *defaultnamespace)
{ {
xmlparams_t *p; xmlparams_t *p;
xmltree_t *child; xmltree_t *child;
@ -338,6 +361,7 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
int pos; int pos;
char *tagend; char *tagend;
char *tagstart; char *tagstart;
char *ns;
pos = *startpos; pos = *startpos;
while (buffer[pos] >= '\0' && buffer[pos] <= ' ') while (buffer[pos] >= '\0' && buffer[pos] <= ' ')
{ {
@ -346,6 +370,12 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
pos++; pos++;
} }
if (pos == maxpos)
{
*startpos = pos;
return NULL; //nothing anyway.
}
//expect a < //expect a <
if (buffer[pos] != '<') if (buffer[pos] != '<')
@ -384,9 +414,23 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
ret = malloc(sizeof(xmltree_t)); ret = malloc(sizeof(xmltree_t));
memset(ret, 0, sizeof(*ret)); memset(ret, 0, sizeof(*ret));
strlcpy(ret->name, com_token, sizeof(ret->name));
// FIXME:parse the parameters ns = strchr(com_token, ':');
if (ns)
{
*ns = 0;
ns++;
memcpy(ret->xmlns, "xmlns:", 6);
strlcpy(ret->xmlns+6, com_token, sizeof(ret->xmlns)-6);
strlcpy(ret->name, ns, sizeof(ret->name));
}
else
{
strlcpy(ret->xmlns, "xmlns", sizeof(ret->xmlns));
strlcpy(ret->name, com_token, sizeof(ret->name));
}
while(*tagstart) while(*tagstart)
{ {
int nlen; int nlen;
@ -463,6 +507,12 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
ret->params = p; ret->params = p;
} }
ns = XML_ParameterOfTree(ret, ret->xmlns);
strlcpy(ret->xmlns, ns?ns:"", sizeof(ret->xmlns));
ns = XML_ParameterOfTree(ret, "xmlns");
strlcpy(ret->xmlns_dflt, ns?ns:defaultnamespace, sizeof(ret->xmlns_dflt));
tagend[-1] = '>'; tagend[-1] = '>';
if (tagend[-2] == '/') if (tagend[-2] == '/')
@ -516,7 +566,7 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
break; break;
} }
child = XML_Parse(buffer, &pos, maxpos, false); child = XML_Parse(buffer, &pos, maxpos, false, ret->xmlns_dflt);
if (!child) if (!child)
{ {
Con_Printf("Child block is unparsable\n"); Con_Printf("Child block is unparsable\n");
@ -527,7 +577,11 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
ret->child = child; ret->child = child;
} }
else else
ret->body[bodypos++] = buffer[pos++]; {
char c = buffer[pos++];
if (bodypos < sizeof(ret->body)-1)
ret->body[bodypos++] = c;
}
} }
ret->body[bodypos++] = '\0'; ret->body[bodypos++] = '\0';
@ -536,15 +590,6 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl
return ret; return ret;
} }
char *XML_ParameterOfTree(xmltree_t *t, char *paramname)
{
xmlparams_t *p;
for (p = t->params; p; p = p->next)
if (!strcmp(p->name, paramname))
return p->val;
return NULL;
}
void XML_Destroy(xmltree_t *t) void XML_Destroy(xmltree_t *t)
{ {
xmlparams_t *p, *np; xmlparams_t *p, *np;
@ -631,7 +676,7 @@ void Base64_Byte(unsigned int byt)
base64[base64_len++] = Base64_From64((base64_cur>>6)&63); base64[base64_len++] = Base64_From64((base64_cur>>6)&63);
base64[base64_len++] = Base64_From64((base64_cur>>0)&63); base64[base64_len++] = Base64_From64((base64_cur>>0)&63);
base64[base64_len] = '\0'; base64[base64_len] = '\0';
Con_Printf("base64: %s\n", base64+base64_len-4); // Con_Printf("base64: %s\n", base64+base64_len-4);
base64_bits = 0; base64_bits = 0;
base64_cur = 0; base64_cur = 0;
} }
@ -713,27 +758,24 @@ int JCL_ClientFrame(jclient_t *jcl)
ret = Net_Recv(jcl->socket, jcl->bufferedinmessage+jcl->bufferedinammount, sizeof(jcl->bufferedinmessage)-1 - jcl->bufferedinammount); ret = Net_Recv(jcl->socket, jcl->bufferedinmessage+jcl->bufferedinammount, sizeof(jcl->bufferedinmessage)-1 - jcl->bufferedinammount);
if (ret == 0) if (ret == 0)
{
Con_Printf("JCL: Remote host disconnected\n");
return JCL_KILL;
}
if (ret < 0)
{
if (ret == N_WOULDBLOCK)
{ {
if (!jcl->bufferedinammount) //if we are half way through a message, read any possible conjunctions. if (!jcl->bufferedinammount) //if we are half way through a message, read any possible conjunctions.
return JCL_DONE; //remove return JCL_DONE; //remove
} }
else if (ret < 0)
{ {
Con_Printf("JCL: socket error\n"); Con_Printf("JCL: socket error\n");
return JCL_KILL; return JCL_KILL;
} }
}
if (ret>0) if (ret>0)
{
jcl->bufferedinammount+=ret; jcl->bufferedinammount+=ret;
jcl->bufferedinmessage[jcl->bufferedinammount] = 0;
Con_TrySubPrint("xmppin", jcl->bufferedinmessage+jcl->bufferedinammount-ret);
}
olddepth = jcl->tagdepth; olddepth = jcl->tagdepth;
//we never end parsing in the middle of a < > //we never end parsing in the middle of a < >
@ -771,11 +813,11 @@ int JCL_ClientFrame(jclient_t *jcl)
{ //first bit of info { //first bit of info
pos = 0; pos = 0;
tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true); tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, "");
while (tree && !strcmp(tree->name, "?xml")) while (tree && !strcmp(tree->name, "?xml"))
{ {
XML_Destroy(tree); XML_Destroy(tree);
tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true); tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, "");
} }
if (!tree) if (!tree)
@ -783,17 +825,19 @@ int JCL_ClientFrame(jclient_t *jcl)
Con_Printf("Not an xml stream\n"); Con_Printf("Not an xml stream\n");
return JCL_KILL; return JCL_KILL;
} }
if (strcmp(tree->name, "stream:stream")) if (strcmp(tree->name, "stream") || strcmp(tree->xmlns, "http://etherx.jabber.org/streams"))
{ {
Con_Printf("Not an xmpp stream\n"); Con_Printf("Not an xmpp stream\n");
return JCL_KILL; return JCL_KILL;
} }
strlcpy(jcl->defaultnamespace, tree->xmlns_dflt, sizeof(jcl->defaultnamespace));
ot = tree; ot = tree;
tree = tree->child; tree = tree->child;
ot->child = NULL; ot->child = NULL;
Con_Printf("Discard\n");
XML_ConPrintTree(ot, 0); // Con_Printf("Discard\n");
// XML_ConPrintTree(ot, 0);
XML_Destroy(ot); XML_Destroy(ot);
if (!tree) if (!tree)
@ -818,7 +862,7 @@ int JCL_ClientFrame(jclient_t *jcl)
} }
pos = 0; pos = 0;
tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false); tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false, jcl->defaultnamespace);
if (!tree) if (!tree)
{ {
@ -827,12 +871,12 @@ int JCL_ClientFrame(jclient_t *jcl)
} }
} }
Con_Printf("read\n"); // Con_Printf("read\n");
XML_ConPrintTree(tree, 0); // XML_ConPrintTree(tree, 0);
unparsable = true; unparsable = true;
if (!strcmp(tree->name, "stream:features")) if (!strcmp(tree->name, "features"))
{ {
if ((ot=XML_ChildOfTree(tree, "bind", 0))) if ((ot=XML_ChildOfTree(tree, "bind", 0)))
{ {
@ -846,6 +890,9 @@ int JCL_ClientFrame(jclient_t *jcl)
unparsable = false; unparsable = false;
JCL_AddClientMessageString(jcl, "<iq type='set' id='H_1'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>"); JCL_AddClientMessageString(jcl, "<iq type='set' id='H_1'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>");
JCL_AddClientMessageString(jcl, "<presence/>"); JCL_AddClientMessageString(jcl, "<presence/>");
jcl->connected = true;
JCL_AddClientMessageString(jcl, "<iq type='get' to='gmail.com' id='H_2'><query xmlns='http://jabber.org/protocol/disco#info'/></iq>");
} }
@ -853,6 +900,7 @@ int JCL_ClientFrame(jclient_t *jcl)
{ {
if ((!jclient->issecure) && BUILTINISVALID(Net_SetTLSClient) && XML_ChildOfTree(tree, "starttls", 0) != NULL) if ((!jclient->issecure) && BUILTINISVALID(Net_SetTLSClient) && XML_ChildOfTree(tree, "starttls", 0) != NULL)
{ {
Con_Printf("Attempting to switch to TLS\n");
JCL_AddClientMessageString(jcl, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />"); JCL_AddClientMessageString(jcl, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' />");
unparsable = false; unparsable = false;
} }
@ -862,24 +910,28 @@ int JCL_ClientFrame(jclient_t *jcl)
{ {
if (!strcmp(ot->body, "PLAIN")) if (!strcmp(ot->body, "PLAIN"))
{ {
char msg[2048];
if (jclient->noplain && !jclient->issecure) //probably don't send plain without tls. if (jclient->noplain && !jclient->issecure) //probably don't send plain without tls.
{ {
//plain can still be read with man-in-the-middle attacks, of course, even with stl. //plain can still be read with man-in-the-middle attacks, of course, even with stl.
Con_Printf("Ignoring auth \'%s\'\n", ot->body); Con_Printf("Ignoring auth \'%s\'\n", ot->body);
continue; continue;
} }
Con_Printf("Authing with \'%s\'\n", ot->body); Con_Printf("Authing with \'%s\'%s\n", ot->body, jclient->issecure?" over tls/ssl":"");
JCL_AddClientMessageString(jcl, "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>");
Base64_Add(jclient->username, strlen(jcl->username)); // Base64_Add(jclient->username, strlen(jcl->username));
Base64_Add("@", 1); // Base64_Add("@", 1);
Base64_Add(jclient->domain, strlen(jcl->domain)); // Base64_Add(jclient->domain, strlen(jcl->domain));
Base64_Add("", 1); Base64_Add("", 1);
Base64_Add(jclient->username, strlen(jcl->username)); Base64_Add(jclient->username, strlen(jcl->username));
Base64_Add("", 1); Base64_Add("", 1);
Base64_Add(jcl->password, strlen(jcl->password)); Base64_Add(jcl->password, strlen(jcl->password));
Base64_Finish(); Base64_Finish();
JCL_AddClientMessageString(jcl, base64); snprintf(msg, sizeof(msg), "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>%s</auth>", base64);
JCL_AddClientMessageString(jcl, "</auth>"); JCL_AddClientMessageString(jcl, msg);
// JCL_AddClientMessageString(jcl, "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>");
// JCL_AddClientMessageString(jcl, base64);
// JCL_AddClientMessageString(jcl, "</auth>");
unparsable = false; unparsable = false;
break; break;
} }
@ -911,12 +963,14 @@ int JCL_ClientFrame(jclient_t *jcl)
if (!BUILTINISVALID(Net_SetTLSClient)) if (!BUILTINISVALID(Net_SetTLSClient))
{ {
Con_Printf("JCL: proceed without TLS\n"); Con_Printf("JCL: proceed without TLS\n");
XML_Destroy(tree);
return JCL_KILL; return JCL_KILL;
} }
if (Net_SetTLSClient(jcl->socket)<0) if (Net_SetTLSClient(jcl->socket, jcl->domain)<0)
{ {
Con_Printf("JCL: failed to switch to TLS\n"); Con_Printf("JCL: failed to switch to TLS\n");
XML_Destroy(tree);
return JCL_KILL; return JCL_KILL;
} }
jclient->issecure = true; jclient->issecure = true;
@ -927,6 +981,7 @@ int JCL_ClientFrame(jclient_t *jcl)
JCL_AddClientMessageString(jcl, jcl->domain); JCL_AddClientMessageString(jcl, jcl->domain);
JCL_AddClientMessageString(jcl, "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"); JCL_AddClientMessageString(jcl, "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>");
XML_Destroy(tree);
return JCL_DONE; return JCL_DONE;
} }
else if (!strcmp(tree->name, "stream:error")) else if (!strcmp(tree->name, "stream:error"))
@ -938,6 +993,7 @@ int JCL_ClientFrame(jclient_t *jcl)
Con_Printf("JCL: Failure: %s\n", tree->child->name); Con_Printf("JCL: Failure: %s\n", tree->child->name);
else else
Con_Printf("JCL: Unknown failure\n"); Con_Printf("JCL: Unknown failure\n");
XML_Destroy(tree);
return JCL_KILL; return JCL_KILL;
} }
else if (!strcmp(tree->name, "success")) else if (!strcmp(tree->name, "success"))
@ -960,7 +1016,6 @@ int JCL_ClientFrame(jclient_t *jcl)
char *from; char *from;
char *to; char *to;
char *id; char *id;
unparsable = false;
id = XML_ParameterOfTree(tree, "id"); id = XML_ParameterOfTree(tree, "id");
from = XML_ParameterOfTree(tree, "from"); from = XML_ParameterOfTree(tree, "from");
@ -972,55 +1027,213 @@ int JCL_ClientFrame(jclient_t *jcl)
ot = XML_ChildOfTree(tree, "query", 0); ot = XML_ChildOfTree(tree, "query", 0);
if (ot) if (ot)
{ {
f = XML_ParameterOfTree(tree, "xmlns"); if (from && !strcmp(ot->xmlns, "http://jabber.org/protocol/disco#info"))
if (f && to && from && !strcmp(f, "jabber:iq:version")) { //http://xmpp.org/extensions/xep-0030.html
{ //client->client version request char msg[2048];
JCL_AddClientMessageString(jcl, "<iq type='result' to='"); int idletime = 0;
JCL_AddClientMessageString(jcl, from); unparsable = false;
JCL_AddClientMessageString(jcl, "' from='");
JCL_AddClientMessageString(jcl, to);
JCL_AddClientMessageString(jcl, "' id='");
JCL_AddClientMessageString(jcl, id);
JCL_AddClientMessageString(jcl, "'>");
JCL_AddClientMessageString(jcl, "<query xmlns='jabber:iq:version'>" snprintf(msg, sizeof(msg),
"<iq type='result' to='%s' id='%s'>"
"<query xmlns='http://jabber.org/protocol/disco#info'>"
"<identity category='client' type='pc' name='FTEQW'/>"
"<feature var='jabber:iq:version'/>"
#ifndef Q3_VM
"<feature var='urn:xmpp:time'/>"
#endif
"</query>"
"</iq>", from, id, idletime);
JCL_AddClientMessageString(jcl, msg);
}
else if (from && !strcmp(ot->xmlns, "jabber:iq:version"))
{ //client->client version request
char msg[2048];
unparsable = false;
snprintf(msg, sizeof(msg),
"<iq type='result' to='%s' id='%s'>"
"<query xmlns='jabber:iq:version'>"
"<name>FTEQW Jabber Plugin</name>" "<name>FTEQW Jabber Plugin</name>"
"<version>"JCL_BUILD"</version>" "<version>V"JCL_BUILD"</version>"
#ifdef Q3_VM #ifdef Q3_VM
"<os>QVM plugin</os>" "<os>QVM plugin</os>"
#endif #endif
"</query>"); "</query>"
"</iq>", from, id);
JCL_AddClientMessageString(jcl, "</iq>"); JCL_AddClientMessageString(jcl, msg);
}
/* else if (from && !strcmp(ot->xmlns, "jabber:iq:last"))
{ //http://xmpp.org/extensions/xep-0012.html
char msg[2048];
int idletime = 0;
unparsable = false;
//last activity
snprintf(msg, sizeof(msg),
"<iq type='result' to='%s' id='%s'>"
"<query xmlns='jabber:iq:last' seconds='%i'/>"
"</iq>", from, id, idletime);
JCL_AddClientMessageString(jcl, msg);
}
*/
}
#ifndef Q3_VM
ot = XML_ChildOfTree(tree, "time", 0);
if (ot && !strcmp(ot->xmlns, "urn:xmpp:time"))
{ //http://xmpp.org/extensions/xep-0202.html
char msg[2048];
char tz[256];
char timestamp[256];
int idletime = 0;
struct tm * timeinfo;
int tzs;
time_t rawtime;
time (&rawtime);
timeinfo = gmtime (&rawtime);
tzs = _timezone;
tzs *= -1;
snprintf(tz, sizeof(tz), "%+i:%i", tzs/(60*60), abs(tzs/60) % 60);
strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%SZ", timeinfo);
unparsable = false;
//strftime
snprintf(msg, sizeof(msg),
"<iq type='result' to='%s' id='%s'>"
"<time xmlns='urn:xmpp:time'>"
"<tzo>+00:00</tzo>"
"<utc>2006-12-19T17:58:35Z</utc>"
"</time>"
"</iq>", from, id, tz, timestamp);
JCL_AddClientMessageString(jcl, msg);
}
#endif
if (unparsable)
{ //unsupported stuff
char msg[2048];
unparsable = false;
Con_Print("Unsupported iq get\n");
XML_ConPrintTree(tree, 0);
//tell them OH NOES, instead of requiring some timeout.
snprintf(msg, sizeof(msg),
"<iq type='error' to='%s' id='%s'>"
"<error type='cancel'>"
"<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
"</error>"
"</iq>", from, id);
JCL_AddClientMessageString(jcl, msg);
} }
} }
else if (f && !strcmp(f, "result"))
{
xmltree_t *c, *v;
unparsable = false;
c = XML_ChildOfTree(tree, "bind", 0);
if (c)
{
v = XML_ChildOfTree(c, "jid", 0);
if (v)
Con_Printf("Bound to jid \"%s\"\n", v->body);
} }
else else
{
Con_Print("Unrecognised iq result\n");
XML_ConPrintTree(tree, 0);
}
}
if (unparsable)
{
unparsable = false;
Con_Print("Unrecognised iq type\n"); Con_Print("Unrecognised iq type\n");
XML_ConPrintTree(tree, 0);
}
} }
else if (!strcmp(tree->name, "message")) else if (!strcmp(tree->name, "message"))
{
unparsable = false;
ot = XML_ChildOfTree(tree, "body", 0);
if (ot)
{ {
f = XML_ParameterOfTree(tree, "from"); f = XML_ParameterOfTree(tree, "from");
if (f) if (f)
{ {
strlcpy(jcl->defaultdest, f, sizeof(jcl->defaultdest)); strlcpy(jcl->defaultdest, f, sizeof(jcl->defaultdest));
RenameConsole(f); RenameConsole(f);
Con_SubPrintf(f, "%s: %s\n", f, ot->body);
} }
if (f)
{
ot = XML_ChildOfTree(tree, "composing", 0);
if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates"))
{
unparsable = false;
Con_SubPrintf(f, "%s is typing\r", f);
}
ot = XML_ChildOfTree(tree, "paused", 0);
if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates"))
{
unparsable = false;
Con_SubPrintf(f, "%s has stopped typing\r", f);
}
ot = XML_ChildOfTree(tree, "inactive", 0);
if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates"))
{
unparsable = false;
Con_SubPrintf(f, "%s has become inactive\r", f);
}
ot = XML_ChildOfTree(tree, "active", 0);
if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates"))
{
unparsable = false;
Con_SubPrintf(f, "\r", f);
}
ot = XML_ChildOfTree(tree, "gone", 0);
if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates"))
{
unparsable = false;
Con_SubPrintf(f, "%s has gone away\r", f);
}
}
ot = XML_ChildOfTree(tree, "body", 0);
if (ot)
{
unparsable = false;
if (f)
Con_SubPrintf(f, "%s: %s\n", f, ot->body);
else else
Con_Print(ot->body); Con_Print(ot->body);
LocalSound("misc/talk.wav"); LocalSound("misc/talk.wav");
} }
else
if (unparsable)
{
unparsable = false;
Con_Print("Received a message without a body\n"); Con_Print("Received a message without a body\n");
XML_ConPrintTree(tree, 0);
}
} }
else if (!strcmp(tree->name, "presence")) else if (!strcmp(tree->name, "presence"))
{ {
char *from = XML_ParameterOfTree(tree, "from");
xmltree_t *show = XML_ChildOfTree(tree, "show", 0);
xmltree_t *status = XML_ChildOfTree(tree, "status", 0);
xmltree_t *quake = XML_ChildOfTree(tree, "quake", 0);
xmltree_t *serverip = NULL;
if (quake && !strcmp(quake->xmlns, "fteqw.com:game"))
serverip = XML_ChildOfTree(quake, "serverip", 0);
if (serverip && *serverip->body)
Con_Printf("%s is now playing quake! ^[JOIN THEM!\\join\\%s^]\n", from, serverip->body);
else if (status && *status->body)
Con_Printf("%s is now %s: %s\n", from, show?show->body:"present", status->body);
else
Con_Printf("%s is now %s\n", from, show?show->body:"present");
//we should keep a list of the people that we know of. //we should keep a list of the people that we know of.
unparsable = false; unparsable = false;
} }
@ -1054,11 +1267,40 @@ void JCL_CloseConnection(jclient_t *jcl)
//functions above this line allow connections to multiple servers. //functions above this line allow connections to multiple servers.
//it is just the control functions that only allow one server. //it is just the control functions that only allow one server.
int JCL_Frame(int *args) qintptr_t JCL_Frame(qintptr_t *args)
{ {
int stat = JCL_CONTINUE; int stat = JCL_CONTINUE;
if (jclient) if (jclient)
{ {
if (jclient->connected)
{
int dummystat;
char serveraddr[1024*16];
//get the last server address
if (!Cvar_GetString("cl_serveraddress", serveraddr, sizeof(serveraddr)))
serveraddr[0] = 0;
//if we can't get any stats, its because we're not actually on the server.
if (!CL_GetStats(0, &dummystat, 1))
serveraddr[0] = 0;
if (strcmp(jclient->curquakeserver, serveraddr))
{
char msg[1024];
strlcpy(jclient->curquakeserver, serveraddr, sizeof(jclient->curquakeserver));
if (!*jclient->curquakeserver)
strlcpy(msg, "<presence/>", sizeof(msg));
else
snprintf(msg, sizeof(msg),
"<presence>"
"<quake xmlns='fteqw.com:game'>"
"<serverip>sha1-hash-of-image</serverip>"
"</quake>"
"</presence>"
);
JCL_AddClientMessageString(jclient, msg);
}
}
while(stat == JCL_CONTINUE) while(stat == JCL_CONTINUE)
stat = JCL_ClientFrame(jclient); stat = JCL_ClientFrame(jclient);
if (stat == JCL_KILL) if (stat == JCL_KILL)
@ -1163,6 +1405,10 @@ void JCL_Command(void)
Con_SubPrintf(jclient->defaultdest, "%s: "COLOURYELLOW"%s\n", ">>", msg); Con_SubPrintf(jclient->defaultdest, "%s: "COLOURYELLOW"%s\n", ">>", msg);
} }
else if (!strcmp(arg[0]+1, "raw"))
{
JCL_AddClientMessageString(jclient, arg[1]);
}
else else
Con_Printf("Unrecognised command: %s\n", arg[0]); Con_Printf("Unrecognised command: %s\n", arg[0]);
} }

View file

@ -55,7 +55,7 @@ BUILTIN(void, Con_Print, (const char *text)); //on to main console.
#undef ARGNAMES #undef ARGNAMES
#define ARGNAMES ,conname,text #define ARGNAMES ,conname,text
BUILTIN(void, Con_SubPrint, (char *conname, char *text)); //on to named sub console (creating it too). BUILTIN(void, Con_SubPrint, (const char *conname, const char *text)); //on to named sub console (creating it too).
#undef ARGNAMES #undef ARGNAMES
#define ARGNAMES ,old,new #define ARGNAMES ,old,new
BUILTIN(void, Con_RenameSub, (char *old, char *new)); //rename a subconsole BUILTIN(void, Con_RenameSub, (char *old, char *new)); //rename a subconsole
@ -120,7 +120,7 @@ BUILTINR(int, Cvar_Update, (qhandle_t handle, int *modificationcount, char *stri
#undef ARGNAMES #undef ARGNAMES
#define ARGNAMES ,pnum,stats,maxstats #define ARGNAMES ,pnum,stats,maxstats
BUILTIN(void, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); BUILTINR(int, CL_GetStats, (int pnum, unsigned int *stats, int maxstats));
#undef ARGNAMES #undef ARGNAMES
#define ARGNAMES ,pnum,info #define ARGNAMES ,pnum,info
BUILTINR(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info)); BUILTINR(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info));

View file

@ -6,6 +6,9 @@
typedef int qintptr_t; typedef int qintptr_t;
typedef unsigned int quintptr_t; typedef unsigned int quintptr_t;
typedef unsigned int size_t;
typedef signed int ssize_t;
#define TESTBI 1 #define TESTBI 1
#ifdef TESTBI #ifdef TESTBI
# define EBUILTIN(t, n, args) extern t (*n) args # define EBUILTIN(t, n, args) extern t (*n) args
@ -139,7 +142,7 @@ EBUILTIN(qboolean, Plug_ExportNative, (const char *funcname, void *func)); //set
#endif #endif
EBUILTIN(void, Con_Print, (const char *text)); //on to main console. EBUILTIN(void, Con_Print, (const char *text)); //on to main console.
EBUILTIN(void, Con_SubPrint, (char *subname, char *text)); //on to sub console. EBUILTIN(void, Con_SubPrint, (const char *subname, const char *text)); //on to sub console.
EBUILTIN(void, Con_RenameSub, (char *oldname, char *newname)); //rename a console. EBUILTIN(void, Con_RenameSub, (char *oldname, char *newname)); //rename a console.
EBUILTIN(int, Con_IsActive, (char *conname)); EBUILTIN(int, Con_IsActive, (char *conname));
EBUILTIN(void, Con_SetActive, (char *conname)); EBUILTIN(void, Con_SetActive, (char *conname));
@ -165,7 +168,7 @@ EBUILTIN(int, Cvar_Update, (qhandle_t handle, int *modificationcount, char *stri
EBUILTIN(void, GetPluginName, (int plugnum, char *buffer, int bufsize)); EBUILTIN(void, GetPluginName, (int plugnum, char *buffer, int bufsize));
EBUILTIN(void, LocalSound, (char *soundname)); EBUILTIN(void, LocalSound, (char *soundname));
EBUILTIN(void, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); EBUILTIN(int, CL_GetStats, (int pnum, unsigned int *stats, int maxstats));
EBUILTIN(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info)); EBUILTIN(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info));
EBUILTIN(int, LocalPlayerNumber, (void)); EBUILTIN(int, LocalPlayerNumber, (void));

View file

@ -57,7 +57,7 @@ retry:
precision=precision*10+*format-'0'; precision=precision*10+*format-'0';
goto retry; goto retry;
case '%': /*emit a %*/ case '%': /*emit a %*/
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *format; *buffer++ = *format;
break; break;
@ -69,7 +69,7 @@ retry:
{ {
while (*string && precision--) while (*string && precision--)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -78,7 +78,7 @@ retry:
{ {
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -87,7 +87,7 @@ retry:
break; break;
case 'c': case 'c':
_int = va_arg(vargs, int); _int = va_arg(vargs, int);
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = _int; *buffer++ = _int;
tokens++; tokens++;
@ -96,7 +96,7 @@ retry:
_int = va_arg(vargs, int); _int = va_arg(vargs, int);
if (_int < 0) if (_int < 0)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = '-'; *buffer++ = '-';
_int *= -1; _int *= -1;
@ -134,7 +134,7 @@ retry:
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -178,7 +178,7 @@ Con_Printf("%i bytes left\n", maxlen);
*/ */
if (_int < 0) if (_int < 0)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = '-'; *buffer++ = '-';
_int *= -1; _int *= -1;
@ -211,7 +211,7 @@ Con_Printf("%i bytes left\n", maxlen);
*/ */
while(precision>0) while(precision>0)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
if (use0s) if (use0s)
*buffer++ = '0'; *buffer++ = '0';
@ -222,7 +222,7 @@ Con_Printf("%i bytes left\n", maxlen);
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -235,7 +235,7 @@ Con_Printf("%i bytes left\n", maxlen);
_int = (int)_float; _int = (int)_float;
if (_int < 0) if (_int < 0)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = '-'; *buffer++ = '-';
_int *= -1; _int *= -1;
@ -257,7 +257,7 @@ Con_Printf("%i bytes left\n", maxlen);
string = tempbuffer+i+1; string = tempbuffer+i+1;
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -287,7 +287,7 @@ Con_Printf("%i bytes left\n", maxlen);
string = tempbuffer; string = tempbuffer;
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -298,7 +298,7 @@ Con_Printf("%i bytes left\n", maxlen);
string = "ERROR IN FORMAT"; string = "ERROR IN FORMAT";
while (*string) while (*string)
{ {
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *string++; *buffer++ = *string++;
} }
@ -306,7 +306,7 @@ Con_Printf("%i bytes left\n", maxlen);
} }
break; break;
default: default:
if (--maxlen < 0) if (maxlen-- == 0)
{*buffer++='\0';return tokens;} {*buffer++='\0';return tokens;}
*buffer++ = *format; *buffer++ = *format;
break; break;