diff --git a/engine/Makefile b/engine/Makefile index 6e64c994b..a11b8bd69 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -4,10 +4,20 @@ CPUOPTIMIZATIONS= BASE_DIR=. +#we only autodetect one cross target +#linux->win32 +#if you are cross compiling, you'll need to use FTE_TARGET=mytaget + + ifeq ($(FTE_TARGET),) #user didn't specify prefered target ifneq ($(shell gcc -v 2>&1 | grep mingw),) FTE_TARGET=win32 - else + endif + ifneq ($(shell gcc -v 2>&1 | grep cygwin),) + FTE_TARGET=cygwin + endif + ifeq ($(FTE_TARGET),) #still not set + ifeq ($(shell uname),Linux) FTE_TARGET=linux endif @@ -58,7 +68,7 @@ ifeq ($(USEASM),true) endif BASELDFLAGS=-lm #BASELDFLAGS=-lm -lz -GLXLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext -lpng -ljpeg -lXxf86vm +GLXLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext -lpng -ljpeg GLSLDFLAGS=-L/usr/X11R6/lib -lMesaGL -lglide -lvga XLDFLAGS=-L/usr/X11R6/lib -lX11 -lXext -lpng -ljpeg SLDFLAGS=-lvga @@ -396,7 +406,7 @@ else endif GL_EXE_NAME=../fteqw.gl GLCL_EXE_NAME=../fteqwcl.gl - GL_LDFLAGS= -L/usr/local/lib $(GLLDFLAGS) $(GLXLDFLAGS) + GL_LDFLAGS= -L/usr/local/lib $(GLLDFLAGS) $(GLXLDFLAGS) -lXxf86vm GL_CFLAGS=$(GLCFLAGS) -I/usr/local/include GLB_DIR=gl_bsd GLCL_DIR=glcl_bsd @@ -420,7 +430,7 @@ else endif M_EXE_NAME=../fteqw MCL_EXE_NAME=../fteqwcl - M_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) + M_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) -lXxf86vm M_CFLAGS=$(SWCFLAGS) $(GLCFLAGS) MB_DIR=m_bsd MCL_DIR=mcl_bsd @@ -437,7 +447,7 @@ else endif GL_EXE_NAME=../fteqw.gl GLCL_EXE_NAME=../fteqwcl.gl - GL_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) + GL_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) -lXxf86vm GL_CFLAGS=$(GLCFLAGS) GLB_DIR=gl_linux GLCL_DIR=glcl_linux @@ -461,7 +471,7 @@ else endif M_EXE_NAME=../fteqw MCL_EXE_NAME=../fteqwcl - M_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) + M_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) -lXxf86vm M_CFLAGS=$(SWCFLAGS) $(GLCFLAGS) MB_DIR=m_linux MCL_DIR=mcl_linux @@ -472,6 +482,53 @@ endif MINGL_DIR=mingl_linux endif +ifeq ($(FTE_TARGET),cygwin) + + SV_DIR=sv_cygwin + SV_LDFLAGS=-lz + +ifeq ($(USEASM),true) + GLCL_OBJS=$(GL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_dosa.o +else + GLCL_OBJS=$(GL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o +endif + GL_EXE_NAME=../fteqwglcyg.exe + GLCL_EXE_NAME=../fteqwclglcyg.exe + GL_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) + GL_CFLAGS=$(GLCFLAGS) + GLB_DIR=gl_cygwin + GLCL_DIR=glcl_cygwin + +ifeq ($(USEASM),true) + SWCL_OBJS=$(SOFTWARE_OBJS) vid_x.o snd_linux.o cd_null.o sys_linux.o sys_dosa.o +else + SWCL_OBJS=$(SOFTWARE_OBJS) vid_x.o snd_linux.o cd_null.o sys_linux.o +endif + SW_EXE_NAME=../fteqwswcyg.exe + SWCL_EXE_NAME=../fteqwclswcyg.exe + SW_LDFLAGS=$(SWLDFLAGS) $(XLDFLAGS) + SW_CFLAGS=$(SWCFLAGS) + SWB_DIR=sw_cygwin + SWCL_DIR=swcl_cygwin + +ifeq ($(USEASM),true) + MCL_OBJS=$(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidlinuxglx.o vid_x.o snd_linux.o cd_null.o sys_linux.o sys_dosa.o +else + MCL_OBJS=$(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidlinuxglx.o vid_x.o snd_linux.o cd_null.o sys_linux.o +endif + M_EXE_NAME=../fteqwcyg.exe + MCL_EXE_NAME=../fteqwclcyg.exe + M_LDFLAGS=$(GLLDFLAGS) $(GLXLDFLAGS) + M_CFLAGS=$(SWCFLAGS) $(GLCFLAGS) + MB_DIR=m_cygwin + MCL_DIR=mcl_cygwin + + + + MINGL_EXE_NAME=../fteqwminglcyg.exe + MINGL_DIR=mingl_cygwin +endif + SV_DIR?=sv_sdl .default: help @@ -542,7 +599,7 @@ _clsv-dbg: debugdir sv-tmp: reldir debugdir - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SV_EXE_NAME)" WCFLAGS="$(SV_CFLAGS)" LDFLAGS="$(SV_LDFLAGS)" OBJS="SV_OBJS" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SV_EXE_NAME)" WCFLAGS="$(SV_CFLAGS)" LDFLAGS="$(SV_LDFLAGS) $(LDFLAGS)" OBJS="SV_OBJS" sv-rel: $(MAKE) sv-tmp TYPE=_out-rel OUT_DIR="$(RELEASE_DIR)/$(SV_DIR)" sv-dbg: @@ -553,9 +610,9 @@ sv-dbg: glcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GLCL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS)" SOBJS="$(GLCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GLCL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" gl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS)" SOBJS="$(GLCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" glcl-rel: $(MAKE) glcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(GLCL_DIR)" @@ -568,15 +625,15 @@ gl-dbg: mingl-tmp: reldir - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MINGL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS) -DMINIMAL" LDFLAGS="$(GL_LDFLAGS)" SOBJS="$(GLCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MINGL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS) -DMINIMAL" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" mingl-rel: $(MAKE) mingl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MINGL_DIR)" swcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SWCL_EXE_NAME)" WCFLAGS="$(SW_CFLAGS)" LDFLAGS="$(SW_LDFLAGS)" SOBJS="$(SWCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SWCL_EXE_NAME)" WCFLAGS="$(SW_CFLAGS)" LDFLAGS="$(SW_LDFLAGS) $(LDFLAGS)" SOBJS="$(SWCL_OBJS)" sw-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SW_EXE_NAME)" WCFLAGS="$(SW_CFLAGS)" LDFLAGS="$(SW_LDFLAGS)" SOBJS="$(SWCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SW_EXE_NAME)" WCFLAGS="$(SW_CFLAGS)" LDFLAGS="$(SW_LDFLAGS) $(LDFLAGS)" SOBJS="$(SWCL_OBJS)" swcl-rel: $(MAKE) swcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(SWCL_DIR)" @@ -588,9 +645,9 @@ sw-dbg: $(MAKE) sw-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(SWB_DIR)" mcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MCL_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS)" SOBJS="$(MCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MCL_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" m-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(M_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS)" SOBJS="$(MCL_OBJS)" + $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(M_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" mcl-rel: $(MAKE) mcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MCL_DIR)" @@ -636,6 +693,10 @@ help: @-echo "gl" @-echo "sw" +install: + -cp debug/*.* /opt/quake/ + -cp release/*.* /opt/quake/ + clean: -rm -f -r $(RELEASE_DIR) -rm -f -r $(DEBUG_DIR) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index cd69e52b3..72510f009 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" void CL_FinishTimeDemo (void); +#define realtime demtime +float demtime; int cls_lastto; int cls_lasttype; @@ -184,6 +186,8 @@ qboolean CL_GetDemoMessage (void) usercmd_t *pcmd; q1usercmd_t q1cmd; + realtime += host_frametime *0.1; + #ifdef NQPROT if (cls.demoplayback == DPB_NETQUAKE || cls.demoplayback == DPB_QUAKE2) { //read the nq demo diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 27278a37d..e35fc3687 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2521,6 +2521,7 @@ void CL_Init (void) Cvar_Register (&cfg_save_name, cl_controlgroup); + cl_demospeed.name2 = "demo_setspeed"; Cvar_Register (&cl_demospeed, "Demo playback"); Cvar_Register (&cl_warncmd, "Warnings"); Cvar_Register (&cl_upspeed, cl_inputgroup); @@ -2916,7 +2917,7 @@ void Host_Frame (double time) */ Mod_Think(); //think even on idle (which means small walls and a fast cpu can get more surfaces done. - if (cl_maxfps.value>0 && cl_netfps.value>0) + if (cl_maxfps.value>0 && cl_netfps.value>0 || cls.demoplayback) { //limit the fps freely, and expect the netfps to cope. if ((realtime - oldrealtime) < 1/cl_maxfps.value) return; diff --git a/engine/client/menu.c b/engine/client/menu.c index b246ed6be..d11f18292 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -847,7 +847,9 @@ void M_Init_Internal (void) Cmd_AddRemCommand ("menu_options", M_Menu_Options_f); Cmd_AddRemCommand ("menu_video", M_Menu_Video_f); Cmd_AddRemCommand ("menu_audio", M_Menu_Audio_f); +#ifndef __CYGWIN__ Cmd_AddRemCommand ("menu_speakers", M_Menu_Audio_Speakers_f); +#endif Cmd_AddRemCommand ("menu_fps", M_Menu_FPS_f); Cmd_AddRemCommand ("menu_particles", M_Menu_Particles_f); Cmd_AddRemCommand ("menu_particlesets", M_Menu_ParticleSets_f); diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 1e7229e07..1fd66889c 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -112,8 +112,10 @@ void Master_SetupSockets(void) int i; for (i = 0; i < POLLUDPSOCKETS; i++) pollsocketsUDP[i] = INVALID_SOCKET; +#ifdef USEIPX for (i = 0; i < POLLIPXSOCKETS; i++) pollsocketsIPX[i] = INVALID_SOCKET; +#endif } void Master_HideServer(serverinfo_t *server) diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 0284fc2b6..393eb4a80 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -19,6 +19,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // quakedef.h -- primary header for client +#ifndef __QUAKEDEF_H__ +#define __QUAKEDEF_H__ + #include "bothdefs.h" //first thing included by ALL files. #if _MSC_VER @@ -251,3 +254,4 @@ extern qboolean isDedicated; } #endif +#endif //__QUAKEDEF_H__ diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index 9cf2a25f0..a812c85ba 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -519,7 +519,7 @@ int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum) char *buffer; if (COM_CheckParm("-wavonly")) - return; + return SND_NOMORE; sc->sn.numchannels = 2; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 5706b1bee..478368ccc 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MACOSX #endif -#if defined(__MINGW32_VERSION) || defined(__MINGW__) +#if defined(__MINGW32_VERSION) || defined(__MINGW__) || defined(__MINGW32__) #define MINGW #endif #if !defined(MINGW) && defined(__GNUC__) && defined(_WIN32) @@ -187,7 +187,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef IRCCLIENT #undef TEXTEDITOR #undef RUNTIMELIGHTING - #undef PLUGINS //we don't have any server side stuff. +// #undef PLUGINS //we don't have any server side stuff. #undef Q3SHADERS #undef TERRAIN #endif diff --git a/engine/common/common.h b/engine/common/common.h index d7faa6ff1..36a93ec81 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -269,6 +269,7 @@ extern char com_gamedir[MAX_OSPATH]; extern char *com_basedir; void COM_WriteFile (char *filename, void *data, int len); +FILE *COM_WriteFileOpen (char *filename); typedef struct { struct searchpath_s *search; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 261fb6f7b..06a30630b 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1052,7 +1052,7 @@ int TCP_OpenStream (netadr_t remoteaddr) struct sockaddr_qstorage qs; temp = NetadrToSockadr(&remoteaddr, &qs); - + if ((newsocket = socket (((struct sockaddr_in*)&qs)->sin_family, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return INVALID_SOCKET; diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 4d4b9c0a5..35f61b838 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -5,6 +5,95 @@ #include "quakedef.h" #ifdef PLUGINS +//#define GNUTLS +#ifdef GNUTLS + +#if defined(_WIN32) && !defined(MINGW) + + +//lets rip stuff out of the header and supply a seperate dll. +//gnutls is huge. +//also this helps get around the whole msvc/mingw thing. + +struct DSTRUCT; +typedef struct DSTRUCT* gnutls_certificate_credentials; +typedef gnutls_certificate_credentials gnutls_certificate_client_credentials; +typedef struct DSTRUCT* gnutls_anon_client_credentials; +struct gnutls_session_int; +typedef struct gnutls_session_int* gnutls_session; +typedef void * gnutls_transport_ptr; + +typedef enum gnutls_kx_algorithm { GNUTLS_KX_RSA=1, GNUTLS_KX_DHE_DSS, + GNUTLS_KX_DHE_RSA, GNUTLS_KX_ANON_DH, GNUTLS_KX_SRP, + GNUTLS_KX_RSA_EXPORT, GNUTLS_KX_SRP_RSA, GNUTLS_KX_SRP_DSS +} gnutls_kx_algorithm; +typedef enum gnutls_certificate_type { GNUTLS_CRT_X509=1, GNUTLS_CRT_OPENPGP +} gnutls_certificate_type; +typedef enum gnutls_connection_end { GNUTLS_SERVER=1, GNUTLS_CLIENT } gnutls_connection_end; +typedef enum gnutls_credentials_type { GNUTLS_CRD_CERTIFICATE=1, GNUTLS_CRD_ANON, GNUTLS_CRD_SRP } gnutls_credentials_type; +typedef enum gnutls_close_request { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } gnutls_close_request; + +#define GNUTLS_E_AGAIN -28 +#define GNUTLS_E_INTERRUPTED -52 + +int (VARGS *gnutls_bye)( gnutls_session session, gnutls_close_request how); +void (VARGS *gnutls_perror)( int error); +int (VARGS *gnutls_handshake)( gnutls_session session); +void (VARGS *gnutls_transport_set_ptr)(gnutls_session session, gnutls_transport_ptr ptr); +int (VARGS *gnutls_certificate_type_set_priority)( gnutls_session session, const int*); +int (VARGS *gnutls_credentials_set)( gnutls_session, gnutls_credentials_type type, void* cred); +int (VARGS *gnutls_kx_set_priority)( gnutls_session session, const int*); +int (VARGS *gnutls_init)(gnutls_session * session, gnutls_connection_end con_end); +int (VARGS *gnutls_set_default_priority)(gnutls_session session); +int (VARGS *gnutls_certificate_allocate_credentials)( gnutls_certificate_credentials *sc); +int (VARGS *gnutls_anon_allocate_client_credentials)( gnutls_anon_client_credentials *sc); +int (VARGS *gnutls_global_init)(void); +int (VARGS *gnutls_record_send)( gnutls_session session, const void *data, size_t sizeofdata); +int (VARGS *gnutls_record_recv)( gnutls_session session, void *data, size_t sizeofdata); + +qboolean Init_GNUTLS(void) +{ + HMODULE hmod; + hmod = LoadLibrary("gnutls.dll"); + if (!hmod) + return false; + + gnutls_bye = (void*)GetProcAddress(hmod, "gnutls_bye"); + gnutls_perror = (void*)GetProcAddress(hmod, "gnutls_perror"); + gnutls_handshake = (void*)GetProcAddress(hmod, "gnutls_handshake"); + gnutls_transport_set_ptr = (void*)GetProcAddress(hmod, "gnutls_transport_set_ptr"); + gnutls_certificate_type_set_priority = (void*)GetProcAddress(hmod, "gnutls_certificate_type_set_priority"); + gnutls_credentials_set = (void*)GetProcAddress(hmod, "gnutls_credentials_set"); + gnutls_kx_set_priority = (void*)GetProcAddress(hmod, "gnutls_kx_set_priority"); + gnutls_init = (void*)GetProcAddress(hmod, "gnutls_init"); + gnutls_set_default_priority = (void*)GetProcAddress(hmod, "gnutls_set_default_priority"); + gnutls_certificate_allocate_credentials = (void*)GetProcAddress(hmod, "gnutls_certificate_allocate_credentials"); + gnutls_anon_allocate_client_credentials = (void*)GetProcAddress(hmod, "gnutls_anon_allocate_client_credentials"); + gnutls_global_init = (void*)GetProcAddress(hmod, "gnutls_global_init"); + gnutls_record_send = (void*)GetProcAddress(hmod, "gnutls_record_send"); + gnutls_record_recv = (void*)GetProcAddress(hmod, "gnutls_record_recv"); + + if (!gnutls_bye || !gnutls_perror || !gnutls_handshake || !gnutls_transport_set_ptr + || !gnutls_certificate_type_set_priority || !gnutls_credentials_set + || !gnutls_kx_set_priority || !gnutls_init || !gnutls_set_default_priority + || !gnutls_certificate_allocate_credentials || !gnutls_anon_allocate_client_credentials + || !gnutls_global_init || !gnutls_record_send || !gnutls_record_recv) + { + Con_Printf("gnutls.dll doesn't contain all required exports\n"); + FreeLibrary(hmod); + return false; + } + + return true; +} + +#else +#include +qboolean Init_GNUTLS(void) {return true;} +#endif + +#endif + cvar_t plug_sbar = {"plug_sbar", "1"}; cvar_t plug_loaddefault = {"plug_loaddefault", "1"}; @@ -18,8 +107,10 @@ cvar_t plug_loaddefault = {"plug_loaddefault", "1"}; typedef struct plugin_s { char *name; vm_t *vm; + int tick; int executestring; +#ifndef SERVERONLY int conexecutecommand; int menufunction; int sbarlevel[3]; //0 - main sbar, 1 - supplementry sbar sections (make sure these can be switched off), 2 - overlays (scoreboard). menus kill all. @@ -27,7 +118,7 @@ typedef struct plugin_s { //protocol-in-a-plugin int connectionlessclientpacket; - +#endif int messagefunction; struct plugin_s *next; @@ -37,6 +128,16 @@ void Plug_SubConsoleCommand(console_t *con, char *line); plugin_t *currentplug; + + +#ifndef SERVERONLY +#include "cl_plugin.inc" +#else +void Plug_Client_Init(void){} +void Plug_Client_Close(plugin_t *plug) {} +#endif + + //custom plugin builtins. typedef int (VARGS *Plug_Builtin_t)(void *offset, unsigned int mask, const long *arg); void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags); @@ -52,8 +153,6 @@ void Plug_Shutdown(void); static plugin_t *plugs; -static plugin_t *menuplug; //plugin that has the current menu -static plugin_t *protocolclientplugin; typedef struct { @@ -68,7 +167,7 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags) { //randomize the order a little. int newnum; - + newnum = (rand()%128)+1; while(newnum < numplugbuiltins && plugbuiltins[newnum].func) newnum+=128; @@ -80,7 +179,7 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags) } //got an empty number. - Con_Printf("%s: %i\n", name, newnum); + Con_DPrintf("%s: %i\n", name, newnum); plugbuiltins[newnum].name = name; plugbuiltins[newnum].func = bi; plugbuiltins[newnum].flags = flags; @@ -91,7 +190,7 @@ static void Plug_RegisterBuiltinIndex(char *name, Plug_Builtin_t bi, int flags, { //randomize the order a little. int newnum; - + newnum = rand()%128; while(newnum+1 < numplugbuiltins && plugbuiltins[newnum+1].func) newnum+=128; @@ -189,7 +288,7 @@ plugin_t *Plug_Load(char *file) newplug = Z_Malloc(sizeof(plugin_t)+strlen(file)+1); newplug->name = (char*)(newplug+1); strcpy(newplug->name, file); - + newplug->vm = VM_Create(NULL, file, Plug_SystemCalls, Plug_SystemCallsEx); currentplug = newplug; if (newplug->vm) @@ -206,8 +305,10 @@ plugin_t *Plug_Load(char *file) return NULL; } +#ifndef SERVERONLY if (newplug->reschange) VM_Call(newplug->vm, newplug->reschange, vid.width, vid.height); +#endif } else { @@ -224,14 +325,19 @@ int Plug_Emumerated (char *name, int size, void *param) char vmname[MAX_QPATH]; strcpy(vmname, name); vmname[strlen(vmname) - strlen(param)] = '\0'; - Plug_Load(vmname); + if (!Plug_Load(vmname)) + Con_Printf("Couldn't load plugin %s\n", vmname); return true; } int VARGS Plug_Con_Print(void *offset, unsigned int mask, const long *arg) { +#ifndef SERVERONLY Con_Print((char*)VM_POINTER(arg[0])); +#else + Con_Printf("%s", (char*)VM_POINTER(arg[0])); +#endif return 0; } int VARGS Plug_Sys_Error(void *offset, unsigned int mask, const long *arg) @@ -250,6 +356,7 @@ int VARGS Plug_ExportToEngine(void *offset, unsigned int mask, const long *arg) currentplug->tick = arg[1]; else if (!strcmp(name, "ExecuteCommand")) currentplug->executestring = arg[1]; +#ifndef SERVERONLY else if (!strcmp(name, "ConExecuteCommand")) currentplug->conexecutecommand = arg[1]; else if (!strcmp(name, "MenuEvent")) @@ -266,11 +373,39 @@ int VARGS Plug_ExportToEngine(void *offset, unsigned int mask, const long *arg) currentplug->connectionlessclientpacket = arg[1]; else if (!strcmp(name, "MessageEvent")) currentplug->messagefunction = arg[1]; +#endif else return 0; return 1; } +//retrieve a plugin's name +int VARGS Plug_GetPluginName(void *offset, unsigned int mask, const long *arg) +{ + int plugnum = VM_LONG(arg[0]); + plugin_t *plug; + //int plugnum (0 for current), char *buffer, int bufferlen + + if (VM_OOB(arg[1], arg[2])) + return false; + + if (plugnum <= 0) + { + Q_strncpyz(VM_POINTER(arg[1]), currentplug->name, VM_LONG(arg[2])); + return true; + } + + for (plug = plugs; plug; plug = plug->next) + { + if (--plugnum == 0) + { + Q_strncpyz(VM_POINTER(arg[1]), plug->name, VM_LONG(arg[2])); + return true; + } + } + return false; +} + typedef void (*funcptr_t) (); int VARGS Plug_ExportNative(void *offset, unsigned int mask, const long *arg) { @@ -280,9 +415,11 @@ int VARGS Plug_ExportNative(void *offset, unsigned int mask, const long *arg) func = *(funcptr_t*)arg; +#ifndef SERVERONLY if (!strcmp(name, "S_LoadSound")) S_RegisterSoundInputPlugin(func); else +#endif return 0; return 1; } @@ -380,277 +517,6 @@ int VARGS Plug_Cmd_Argc(void *offset, unsigned int mask, const long *arg) return Cmd_Argc(); } -int VARGS Plug_Menu_Control(void *offset, unsigned int mask, const long *arg) -{ - switch(VM_LONG(arg[0])) - { - case 0: //take away all menus - case 1: - if (menuplug) - { - plugin_t *oldplug = currentplug; - currentplug = menuplug; - Plug_Menu_Event(3, 0); - menuplug = NULL; - currentplug = oldplug; - key_dest = key_game; - } - if (VM_LONG(arg[0]) != 1) - return 1; - //give us menu control - menuplug = currentplug; - key_dest = key_menu; - m_state = m_plugin; - return 1; - case 2: //weather it's us or not. - return currentplug == menuplug && m_state == m_plugin; - case 3: //weather a menu is active - return key_dest == key_menu; - default: - return 0; - } -} - -typedef struct { - //Make SURE that the engine has resolved all cvar pointers into globals before this happens. - plugin_t *plugin; - char name[64]; - qboolean picfromwad; - mpic_t *pic; -} pluginimagearray_t; -int pluginimagearraylen; -pluginimagearray_t *pluginimagearray; - -int VARGS Plug_Draw_LoadImage(void *offset, unsigned int mask, const long *arg) -{ - char *name = VM_POINTER(arg[0]); - qboolean fromwad = arg[1]; - int i; - - mpic_t *pic; - - for (i = 0; i < pluginimagearraylen; i++) - { - if (!pluginimagearray[i].plugin) - break; - if (pluginimagearray[i].plugin == currentplug) - { - if (!strcmp(name, pluginimagearray[i].name)) - break; - } - } - if (i == pluginimagearraylen) - { - pluginimagearraylen++; - pluginimagearray = BZ_Realloc(pluginimagearray, pluginimagearraylen*sizeof(pluginimagearray_t)); - } - - if (pluginimagearray[i].pic) - return i; //already loaded. - - if (qrenderer) - { - if (fromwad) - pic = Draw_SafePicFromWad(name); - else - { -#ifdef RGLQUAKE //GL saves images persistantly (so don't bother with cachepic stuff) - if (qrenderer == QR_OPENGL) - pic = Draw_SafeCachePic(name); - else -#endif - pic = NULL; - } - } - else - pic = NULL; - - Q_strncpyz(pluginimagearray[i].name, name, sizeof(pluginimagearray[i].name)); - pluginimagearray[i].picfromwad = fromwad; - pluginimagearray[i].pic = pic; - pluginimagearray[i].plugin = currentplug; - return i; -} - -void Plug_DrawReloadImages(void) -{ - int i; - for (i = 0; i < pluginimagearraylen; i++) - { - if (!pluginimagearray[i].plugin) - { - pluginimagearray[i].pic = NULL; - continue; - } - - if (pluginimagearray[i].picfromwad) - pluginimagearray[i].pic = Draw_SafePicFromWad(pluginimagearray[i].name); -#ifdef RGLQUAKE - else if (qrenderer == QR_OPENGL) - pluginimagearray[i].pic = Draw_SafeCachePic(pluginimagearray[i].name); -#endif - else - pluginimagearray[i].pic = NULL; - } -} - -void Plug_FreePlugImages(plugin_t *plug) -{ - int i; - for (i = 0; i < pluginimagearraylen; i++) - { - if (pluginimagearray[i].plugin == plug) - { - pluginimagearray[i].plugin = 0; - pluginimagearray[i].pic = NULL; - pluginimagearray[i].name[0] = '\0'; - } - } -} - -//int Draw_Image (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image) -int VARGS Plug_Draw_Image(void *offset, unsigned int mask, const long *arg) -{ - mpic_t *pic; - int i; - if (!qrenderer) - return 0; - if (!Draw_Image) - return 0; - - i = VM_LONG(arg[8]); - if (i < 0 || i >= pluginimagearraylen) - return -1; // you fool - if (pluginimagearray[i].plugin != currentplug) - return -1; - - if (pluginimagearray[i].pic) - pic = pluginimagearray[i].pic; - else if (pluginimagearray[i].picfromwad) - return 0; //wasn't loaded. - else - pic = Draw_CachePic(pluginimagearray[i].name); - - Draw_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), pic); - return 1; -} -//x1,y1,x2,y2 -int VARGS Plug_Draw_Line(void *offset, unsigned int mask, const long *arg) -{ - switch(qrenderer) //FIXME: I don't want qrenderer seen outside the refresh - { -#ifdef RGLQUAKE - case QR_OPENGL: - qglDisable(GL_TEXTURE_2D); - qglBegin(GL_LINES); - qglVertex2f(VM_FLOAT(arg[0]), VM_FLOAT(arg[1])); - qglVertex2f(VM_FLOAT(arg[2]), VM_FLOAT(arg[3])); - qglEnd(); - qglEnable(GL_TEXTURE_2D); - break; -#endif - } - return 1; -} - -int VARGS Plug_Draw_Character(void *offset, unsigned int mask, const long *arg) -{ - Draw_Character(arg[0], arg[1], (unsigned int)arg[2]); - return 0; -} - -int VARGS Plug_Draw_Fill(void *offset, unsigned int mask, const long *arg) -{ - float x, y, width, height; - x = VM_FLOAT(arg[0]); - y = VM_FLOAT(arg[1]); - width = VM_FLOAT(arg[2]); - height = VM_FLOAT(arg[3]); - switch(qrenderer) //FIXME: I don't want qrenderer seen outside the refresh - { -#ifdef RGLQUAKE - case QR_OPENGL: - qglDisable(GL_TEXTURE_2D); - qglBegin(GL_QUADS); - qglVertex2f(x, y); - qglVertex2f(x+width, y); - qglVertex2f(x+width, y+height); - qglVertex2f(x, y+height); - qglEnd(); - qglEnable(GL_TEXTURE_2D); - return 1; -#endif - default: - break; - } - return 0; -} - -int VARGS Plug_Draw_ColourP(void *offset, unsigned int mask, const long *arg) -{ - qbyte *pal = host_basepal + VM_LONG(arg[0])*3; - - if (arg[0]<0 || arg[0]>255) - return false; - - if (Draw_ImageColours) - { - Draw_ImageColours(pal[0]/255.0f, pal[1]/255.0f, pal[2]/255.0f, 1); - return 1; - } - return 0; -} - -int VARGS Plug_Draw_Colour3f(void *offset, unsigned int mask, const long *arg) -{ - if (Draw_ImageColours) - { - Draw_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), 1); - return 1; - } - return 0; -} -int VARGS Plug_Draw_Colour4f(void *offset, unsigned int mask, const long *arg) -{ - if (Draw_ImageColours) - { - Draw_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3])); - return 1; - } - return 0; -} - -int VARGS Plug_Media_ShowFrameRGBA_32(void *offset, unsigned int mask, const long *arg) -{ - void *src = VM_POINTER(arg[0]); - int srcwidth = VM_LONG(arg[1]); - int srcheight = VM_LONG(arg[2]); - int x = VM_LONG(arg[3]); - int y = VM_LONG(arg[4]); - int width = VM_LONG(arg[5]); - int height = VM_LONG(arg[6]); - - Media_ShowFrameRGBA_32(src, srcwidth, srcheight); - return 0; -} - -int VARGS Plug_LocalSound(void *offset, unsigned int mask, const long *arg) -{ - S_LocalSound(VM_POINTER(arg[0])); - return 0; -} -int VARGS Plug_SCR_CenterPrint(void *offset, unsigned int mask, const long *arg) -{ - SCR_CenterPrint(0, VM_POINTER(arg[0])); - return 0; -} - -int VARGS Plug_Key_GetKeyCode(void *offset, unsigned int mask, const long *arg) -{ - int modifier; - return Key_StringToKeynum(VM_POINTER(arg[0]), &modifier); -} - //void Cvar_SetString (char *name, char *value); int VARGS Plug_Cvar_SetString(void *offset, unsigned int mask, const long *arg) { @@ -800,68 +666,10 @@ void VARGS Plug_FreeConCommands(plugin_t *plug) } } -int VARGS Plug_CL_GetStats(void *offset, unsigned int mask, const long *arg) -{ - int i; - int pnum = VM_LONG(arg[0]); - unsigned int *stats = VM_POINTER(arg[1]); - int pluginstats = VM_LONG(arg[2]); - int max; - - if (VM_OOB(arg[1], arg[2]*4)) - return 0; - - max = pluginstats; - if (max > MAX_CL_STATS) - max = MAX_CL_STATS; - for (i = 0; i < max; i++) - { //fill stats with the right player's stats - stats[i] = cl.stats[pnum][i]; - } - for (; i < pluginstats; i++) //plugin has too many stats (wow) - stats[i] = 0; //fill the rest. - return max; -} - -int VARGS Plug_Con_SubPrint(void *offset, unsigned int mask, const long *arg) -{ - char *name = VM_POINTER(arg[0]); - char *text = VM_POINTER(arg[1]); - console_t *con; - con = Con_FindConsole(name); - if (!con) - { - con = Con_Create(name); - Con_SetVisible(con); - - if (currentplug->conexecutecommand) - { - con->userdata = currentplug; - con->linebuffered = Plug_SubConsoleCommand; - } - } - - Con_PrintCon(con, text); - - return 1; -} -int VARGS Plug_Con_RenameSub(void *offset, unsigned int mask, const long *arg) -{ - char *name = VM_POINTER(arg[0]); - console_t *con; - con = Con_FindConsole(name); - if (!con) - return 0; - - Q_strncpyz(con->name, name, sizeof(con->name)); - - return 1; -} - - typedef enum{ STREAM_NONE, STREAM_SOCKET, + STREAM_TLS, STREAM_OSFILE, STREAM_FILE } plugstream_e; @@ -877,6 +685,9 @@ typedef struct { int curlen; int curpos; } file; +#ifdef GNUTLS + gnutls_session session; +#endif } pluginstream_t; pluginstream_t *pluginstreamarray; int pluginstreamarraylen; @@ -913,7 +724,7 @@ int VARGS Plug_Net_TCPListen(void *offset, unsigned int mask, const long *arg) int sock; struct sockaddr_qstorage address; int _true = 1; - + char *localip = VM_POINTER(arg[0]); unsigned short localport = VM_LONG(arg[1]); int maxcount = VM_LONG(arg[2]); @@ -1047,7 +858,7 @@ int VARGS Plug_Net_TCPConnect(void *offset, unsigned int mask, const long *arg) closesocket(sock); return -2; } - + if (ioctlsocket (sock, FIONBIO, &_true) == -1) //now make it non blocking. { return -1; @@ -1058,6 +869,104 @@ int VARGS Plug_Net_TCPConnect(void *offset, unsigned int mask, const long *arg) return handle; } + +#ifdef GNUTLS + +int VARGS Plug_Net_SetTLSClient(void *offset, unsigned int mask, const long *arg) +{ + static gnutls_anon_client_credentials anoncred; + static gnutls_certificate_credentials xcred; + + int ret; + + long _false = false; + long _true = true; + + /* Need to enable anonymous KX specifically. */ + const int kx_prio[] = {GNUTLS_KX_ANON_DH, 0}; + const int cert_type_priority[3] = {GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0}; + + + 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_SOCKET) + { //not a socket - invalid + Con_Printf("Plug_Net_SetTLSClient: Not a socket handle\n"); + return -2; + } + + +{ + static qboolean needinit = true; + if (needinit) + { + gnutls_global_init (); + + gnutls_anon_allocate_client_credentials (&anoncred); + gnutls_certificate_allocate_credentials (&xcred); +// gnutls_certificate_set_x509_trust_file (xcred, "ca.pem", GNUTLS_X509_FMT_PEM); + + needinit = false; + } +} + + stream->type = STREAM_TLS; + + // Initialize TLS session + gnutls_init (&stream->session, GNUTLS_CLIENT); + + // Use default priorities + gnutls_set_default_priority (stream->session); + if (anon) + { + gnutls_kx_set_priority (stream->session, kx_prio); + gnutls_credentials_set (stream->session, GNUTLS_CRD_ANON, anoncred); + } + else + { + gnutls_certificate_type_set_priority (stream->session, cert_type_priority); + gnutls_credentials_set (stream->session, GNUTLS_CRD_CERTIFICATE, xcred); + } + + // connect to the peer + gnutls_transport_set_ptr (stream->session, (gnutls_transport_ptr) stream->socket); + + // Perform the TLS handshake + + ioctlsocket (stream->socket, FIONBIO, &_false); + + ret = GNUTLS_E_AGAIN; + while ((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) + { + ret = gnutls_handshake (stream->session); + } + + if (ret < 0) + { + Con_Printf ("^1*** TLS handshake failed\n"); + gnutls_perror (ret); + + stream->type = STREAM_SOCKET; //go back to regular socket + gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR); + + return -2; + } + + ioctlsocket (stream->socket, FIONBIO, &_true); + + + + return 0; +} +#endif + int VARGS Plug_FS_Open(void *offset, unsigned int mask, const long *arg) { //modes: @@ -1075,7 +984,7 @@ int VARGS Plug_FS_Open(void *offset, unsigned int mask, const long *arg) if (VM_OOB(arg[1], sizeof(int))) return -2; ret = VM_POINTER(arg[1]); - + if (arg[2] == 1) { data = COM_LoadMallocFile(VM_POINTER(arg[0])); @@ -1090,7 +999,7 @@ int VARGS Plug_FS_Open(void *offset, unsigned int mask, const long *arg) *ret = handle; - return com_filesize; + return com_filesize; } else if (arg[2] == 2) { @@ -1107,7 +1016,7 @@ int VARGS Plug_FS_Open(void *offset, unsigned int mask, const long *arg) *ret = handle; - return com_filesize; + return com_filesize; } else return -2; @@ -1193,6 +1102,23 @@ int VARGS Plug_Net_Recv(void *offset, unsigned int mask, const long *arg) else if (read == 0) return -2; //closed by remote connection. return read; +#ifdef GNUTLS + case STREAM_TLS: + read = gnutls_record_recv(pluginstreamarray[handle].session, dest, destlen); + if (read < 0) + { + if (read == GNUTLS_E_AGAIN || read == -9) + return -1; + else + { + Con_Printf("TLS Read Error %i (bufsize %i)\n", read, destlen); + return -2; + } + } + else if (read == 0) + return -2; //closed by remote connection. + return read; +#endif case STREAM_FILE: if (pluginstreamarray[handle].file.curlen - pluginstreamarray[handle].file.curpos < destlen) { @@ -1229,11 +1155,28 @@ int VARGS Plug_Net_Send(void *offset, unsigned int mask, const long *arg) else if (written == 0) return -2; //closed by remote connection. return written; +#ifdef GNUTLS + case STREAM_TLS: + written = gnutls_record_send(pluginstreamarray[handle].session, src, srclen); + if (written < 0) + { + if (written == GNUTLS_E_AGAIN || written == GNUTLS_E_INTERRUPTED) + return -1; + else + { + Con_Printf("TLS Send Error %i (%i bytes)\n", written, srclen); + return -2; + } + } + else if (written == 0) + return -2; //closed by remote connection. + return written; +#endif case STREAM_FILE: if (pluginstreamarray[handle].file.buflen < pluginstreamarray[handle].file.curpos + srclen) { pluginstreamarray[handle].file.buflen = pluginstreamarray[handle].file.curpos + srclen+8192; - pluginstreamarray[handle].file.buffer = + 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); @@ -1285,14 +1228,18 @@ int VARGS Plug_Net_SendTo(void *offset, unsigned int mask, const long *arg) return -2; } } -int VARGS Plug_Net_Close(void *offset, unsigned int mask, const long *arg) -{ - int handle = VM_LONG(arg[0]); - if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) - return -2; +void Plug_Net_Close_Internal(int handle) +{ switch(pluginstreamarray[handle].type) { +#ifdef GNUTLS + case STREAM_TLS: + gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR); + pluginstreamarray[handle].type = STREAM_SOCKET; + Plug_Net_Close_Internal(handle); + return; +#endif case STREAM_SOCKET: closesocket(pluginstreamarray[handle].socket); break; @@ -1304,7 +1251,14 @@ int VARGS Plug_Net_Close(void *offset, unsigned int mask, const long *arg) } pluginstreamarray[handle].plugin = NULL; +} +int VARGS Plug_Net_Close(void *offset, unsigned int mask, const long *arg) +{ + int handle = VM_LONG(arg[0]); + if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) + return -2; + Plug_Net_Close_Internal(handle); return 0; } @@ -1382,10 +1336,6 @@ void Plug_Init(void) Plug_RegisterBuiltin("Cmd_Argv", Plug_Cmd_Argv, 0); Plug_RegisterBuiltin("Cmd_AddText", Plug_Cmd_AddText, 0); - Plug_RegisterBuiltin("CL_GetStats", Plug_CL_GetStats, 0); - Plug_RegisterBuiltin("Menu_Control", Plug_Menu_Control, 0); - Plug_RegisterBuiltin("Key_GetKeyCode", Plug_Key_GetKeyCode, 0); - Plug_RegisterBuiltin("Cvar_Register", Plug_Cvar_Register, 0); Plug_RegisterBuiltin("Cvar_Update", Plug_Cvar_Update, 0); Plug_RegisterBuiltin("Cvar_SetString", Plug_Cvar_SetString, 0); @@ -1393,21 +1343,13 @@ void Plug_Init(void) Plug_RegisterBuiltin("Cvar_GetString", Plug_Cvar_GetString, 0); Plug_RegisterBuiltin("Cvar_GetFloat", Plug_Cvar_GetFloat, 0); - Plug_RegisterBuiltin("Draw_LoadImage", Plug_Draw_LoadImage, 0); - Plug_RegisterBuiltin("Draw_Image", Plug_Draw_Image, 0); - Plug_RegisterBuiltin("Draw_Character", Plug_Draw_Character, 0); - Plug_RegisterBuiltin("Draw_Fill", Plug_Draw_Fill, 0); - Plug_RegisterBuiltin("Draw_Line", Plug_Draw_Line, 0); - Plug_RegisterBuiltin("Draw_Colourp", Plug_Draw_ColourP, 0); - Plug_RegisterBuiltin("Draw_Colour3f", Plug_Draw_Colour3f, 0); - Plug_RegisterBuiltin("Draw_Colour4f", Plug_Draw_Colour4f, 0); - - Plug_RegisterBuiltin("Con_SubPrint", Plug_Con_SubPrint, 0); - Plug_RegisterBuiltin("Con_RenameSub", Plug_Con_RenameSub, 0); - Plug_RegisterBuiltin("Net_TCPListen", Plug_Net_TCPListen, 0); Plug_RegisterBuiltin("Net_Accept", Plug_Net_Accept, 0); Plug_RegisterBuiltin("Net_TCPConnect", Plug_Net_TCPConnect, 0); +#ifdef GNUTLS + if (Init_GNUTLS()) + Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0); +#endif Plug_RegisterBuiltin("Net_Recv", Plug_Net_Recv, 0); Plug_RegisterBuiltin("Net_Send", Plug_Net_Send, 0); Plug_RegisterBuiltin("Net_SendTo", Plug_Net_SendTo, 0); @@ -1427,10 +1369,9 @@ void Plug_Init(void) Plug_RegisterBuiltin("cos", Plug_cos, 0); Plug_RegisterBuiltin("atan2", Plug_atan2, 0); + Plug_RegisterBuiltin("GetPluginName", Plug_GetPluginName, 0); - Plug_RegisterBuiltin("LocalSound", Plug_LocalSound, 0); - Plug_RegisterBuiltin("SCR_CenterPrint", Plug_SCR_CenterPrint, 0); - Plug_RegisterBuiltin("Media_ShowFrameRGBA_32", Plug_Media_ShowFrameRGBA_32, 0); + Plug_Client_Init(); if (plug_loaddefault.value) { @@ -1456,6 +1397,7 @@ void Plug_Tick(void) currentplug = oldplug; } +#ifndef SERVERONLY void Plug_ResChanged(void) { plugin_t *oldplug = currentplug; @@ -1466,6 +1408,7 @@ void Plug_ResChanged(void) } currentplug = oldplug; } +#endif qboolean Plugin_ExecuteString(void) { @@ -1488,6 +1431,7 @@ qboolean Plugin_ExecuteString(void) return false; } +#ifndef SERVERONLY void Plug_SubConsoleCommand(console_t *con, char *line) { char buffer[2048]; @@ -1499,7 +1443,9 @@ void Plug_SubConsoleCommand(console_t *con, char *line) VM_Call(currentplug->vm, currentplug->conexecutecommand, 0); currentplug = oldplug; } +#endif +#ifndef SERVERONLY qboolean Plug_Menu_Event(int eventtype, int param) //eventtype = draw/keydown/keyup, param = time/key { plugin_t *oc=currentplug; @@ -1514,7 +1460,8 @@ qboolean Plug_Menu_Event(int eventtype, int param) //eventtype = draw/keydown/ke currentplug=oc; return ret; } - +#endif +#ifndef SERVERONLY int Plug_ConnectionlessClientPacket(char *buffer, int size) { for (currentplug = plugs; currentplug; currentplug = currentplug->next) @@ -1540,7 +1487,8 @@ int Plug_ConnectionlessClientPacket(char *buffer, int size) } return false; } - +#endif +#ifndef SERVERONLY void Plug_SBar(void) { plugin_t *oc=currentplug; @@ -1599,6 +1547,7 @@ void Plug_SBar(void) currentplug = oc; } +#endif int Plug_Message(int clientnum, int messagelevel, char *buffer) { @@ -1633,22 +1582,12 @@ void Plug_Close(plugin_t *plug) Con_Printf("Closing plugin %s\n", plug->name); VM_Destroy(plug->vm); - Plug_FreePlugImages(plug); Plug_FreeConCommands(plug); + Plug_Client_Close(plug); + if (currentplug == plug) currentplug = NULL; - if (menuplug == plug) - { - menuplug = NULL; - key_dest = key_game; - } - if (protocolclientplugin == plug) - { - protocolclientplugin = NULL; - if (cls.protocol == CP_PLUGIN) - cls.protocol = CP_UNKNOWN; - } } void Plug_Close_f(void) diff --git a/engine/common/qvm.c b/engine/common/qvm.c index daafdd911..1adc0f47a 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -142,7 +142,7 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int void (*dllEntry)(int (EXPORT_FN *syscall)(int arg, ... )); char dllname[MAX_OSPATH]; void *hVM; - + #ifdef __MORPHOS__ if (DynLoadBase == 0) return 0; @@ -163,12 +163,17 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int return NULL; // couldn't find one anywhere _snprintf (name, sizeof(name), "%s/%s", gpath, dllname); + Con_Printf("Loading native: %s\n", name); hVM = dlopen (name, RTLD_NOW); if (hVM) { - Con_DPrintf ("dlopen (%s)\n",name); + Con_DPrintf ("Sys_LoadDLL: dlopen (%s)\n",name); break; } + else + { + Con_DPrintf("Sys_LoadDLL: dlerror()=\"%s\"", dlerror()); + } } } @@ -177,6 +182,7 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int dllEntry=(void *)dlsym(hVM, "dllEntry"); if(!dllEntry) { + Con_Printf("Sys_LoadDLL: %s does not have a dllEntry function\n"); dlclose(hVM); return NULL; } @@ -186,6 +192,7 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int *vmMain=(void *)dlsym(hVM, "vmMain"); if(!*vmMain) { + Con_Printf("Sys_LoadDLL: %s does not have a vmMain function\n"); dlclose(hVM); return NULL; } @@ -519,7 +526,7 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall) void QVM_UnLoad(qvm_t *qvm) { Z_Free(qvm->mem_ptr); - Z_Free(qvm); + Z_Free(qvm); } @@ -1054,7 +1061,7 @@ qboolean VM_Restart(vm_t *vm) if(!vm) return false; // save params - Q_strncpyz(name, vm->name, sizeof(name)); + Q_strncpyz(name, vm->name, sizeof(name)); syscalldll=vm->syscalldll; syscallqvm=vm->syscallqvm; diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 4fd9ff968..a2675815d 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -2147,6 +2147,18 @@ void GLDraw_Image(float x, float y, float w, float h, float s1, float t1, float draw_mesh_st[3][0] = s1; draw_mesh_st[3][1] = t2; + if (gl_blend2d.value) + { + qglDisable(GL_ALPHA_TEST); + qglEnable(GL_BLEND); + } + else + { + qglEnable(GL_ALPHA_TEST); + qglDisable(GL_BLEND); + } + + GL_DrawMesh(&draw_mesh, gl->texnum); } diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 343eb54a6..f14239d06 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -41,7 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif -#define WITH_VMODE //undefine this if the following include fails. +#ifdef __linux__ + #define WITH_VMODE //undefine this if the following include fails. +#endif #ifdef WITH_VMODE #include #endif @@ -138,13 +140,13 @@ void GLX_CloseLibrary(void) qboolean GLX_InitLibrary(char *driver) { if (driver && *driver) - gllibrary = dlopen(driver, RTLD_LOCAL | RTLD_LAZY); + gllibrary = dlopen(driver, RTLD_LAZY); else gllibrary = NULL; if (!gllibrary) - gllibrary = dlopen("libGL.so", RTLD_LOCAL | RTLD_LAZY); + gllibrary = dlopen("libGL.so", RTLD_LAZY); if (!gllibrary) //I hate this. - gllibrary = dlopen("libGL.so.1", RTLD_LOCAL | RTLD_LAZY); + gllibrary = dlopen("libGL.so.1", RTLD_LAZY); if (!gllibrary) return false; @@ -427,13 +429,14 @@ static void GetEvent(void) b = 4; if (b>=0) Key_Event(K_MOUSE1 + b, true); - +#ifdef WITH_VMODE if (vidmode_ext && vidmode_usemode>=0) if (!ActiveApp) { //KDE doesn't seem to like us, in that you can't alt-tab back or click to activate. //This allows us to steal input focus back from the window manager XSetInputFocus(vid_dpy, vid_window, RevertToParent, CurrentTime); } +#endif break; case ButtonRelease: @@ -455,7 +458,7 @@ static void GetEvent(void) case FocusIn: v_gamma.modified = true; ActiveApp = true; - +#ifdef WITH_VMODE if (vidmode_ext && vidmode_usemode>=0) { if (!vidmode_active) @@ -467,7 +470,7 @@ static void GetEvent(void) } XF86VidModeSetViewPort(vid_dpy, scrnum, 0, 0); } - +#endif break; case FocusOut: #ifdef WITH_VMODE diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 323468b2c..cea51d58b 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -221,7 +221,7 @@ compiler_flag_t compiler_flag[] = { {&flag_laxcasts, FLAG_MIDCOMPILE,"lax", "Lax type checks", "Disables many errors (generating warnings instead) when function calls or operations refer to two normally incompatable types. This is required for reacc support, and can also allow certain (evil) mods to compile that were originally written for frikqcc."}, //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code. {&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"}, {&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions. This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"}, - {&flag_fasttrackarrays, FLAG_MIDCOMPILE,"fastarrays", "fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to al lor none."}, //correction for if(string) no-ifstring to get the standard behaviour. + {&flag_fasttrackarrays, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"fastarrays", "fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes only in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to all arrays or none."}, //correction for if(string) no-ifstring to get the standard behaviour. {NULL} }; diff --git a/engine/server/server.h b/engine/server/server.h index a5dc61ab4..627605797 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -348,6 +348,7 @@ typedef struct client_s int challenge; int userid; // identifying number + char userinfobasic[MAX_INFO_STRING]; char userinfo[EXTENDED_INFO_STRING]; // infostring usercmd_t lastcmd; // for filling in big drops and partial predictions @@ -875,7 +876,7 @@ struct quakeparms_s; void SV_Init (struct quakeparms_s *parms); int SV_CalcPing (client_t *cl); -void SV_FullClientUpdate (client_t *client, sizebuf_t *buf); +void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext); void SV_FullClientUpdateToClient (client_t *client, client_t *cl); void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf); diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 98d2b0576..bd9f76be8 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1639,6 +1639,32 @@ void SV_SendGameCommand_f(void) Con_Printf("This command requires a Q2 sever\n"); } + + + +void PIN_LoadMessages(void); +void PIN_SaveMessages(void); +void PIN_DeleteOldestMessage(void); +void PIN_MakeMessage(char *from, char *msg); + +void SV_Pin_Save_f(void) +{ + PIN_SaveMessages(); +} +void SV_Pin_Reload_f(void) +{ + PIN_LoadMessages(); +} +void SV_Pin_Delete_f(void) +{ + PIN_DeleteOldestMessage(); +} +void SV_Pin_Add_f(void) +{ + PIN_MakeMessage(Cmd_Argv(0), Cmd_Argv(1)); +} + + /* ================== SV_InitOperatorCommands @@ -1704,6 +1730,11 @@ void SV_InitOperatorCommands (void) Cmd_AddCommand ("sv_settimer", SV_SetTimer_f); Cmd_AddCommand ("stuffcmd", SV_StuffToClient_f); + Cmd_AddCommand ("pin_save", SV_Pin_Save_f); + Cmd_AddCommand ("pin_reload", SV_Pin_Reload_f); + Cmd_AddCommand ("pin_delete", SV_Pin_Delete_f); + Cmd_AddCommand ("pin_add", SV_Pin_Add_f); + cl_warncmd.value = 1; } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 4a129c5cd..668183f2e 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -469,6 +469,7 @@ void SV_DropClient (client_t *drop) drop->edict->v->frags = 0; drop->name[0] = 0; memset (drop->userinfo, 0, sizeof(drop->userinfo)); + memset (drop->userinfobasic, 0, sizeof(drop->userinfobasic)); if (drop->frames) //union of the same sort of structure { @@ -480,7 +481,7 @@ void SV_DropClient (client_t *drop) return; // send notification to all remaining clients - SV_FullClientUpdate (drop, &sv.reliable_datagram); + SV_FullClientUpdate (drop, &sv.reliable_datagram, 0); #ifdef NQPROT SVNQ_FullClientUpdate (drop, &sv.nqreliable_datagram); #endif @@ -493,6 +494,134 @@ void SV_DropClient (client_t *drop) } +//==================================================================== + +typedef struct pinnedmessages_s { + struct pinnedmessages_s *next; + char setby[64]; + char message[1024]; +} pinnedmessages_t; +pinnedmessages_t *pinned; +qboolean dopinnedload = true; +void PIN_DeleteOldestMessage(void); +void PIN_MakeMessage(char *from, char *msg); + +void PIN_LoadMessages(void) +{ + char setby[64]; + char message[1024]; + + int i; + char *file; + char *lstart; + + dopinnedload = false; + + while(pinned) + PIN_DeleteOldestMessage(); + + file = COM_LoadMallocFile("pinned.txt"); + if (!file) + return; + + lstart = file; + for(;;) + { + while (*lstart <= ' ' && *lstart) + lstart++; + + for (i = 0; *lstart && i < sizeof(message)-1; i++) + { + if (*lstart == '\n' || *lstart == '\r') + break; + message[i] = *lstart++; + } + message[i] = '\0'; + + while (*lstart <= ' ' && *lstart) + lstart++; + + for (i = 0; *lstart && i < sizeof(setby)-1; i++) + { + if (*lstart == '\n' || *lstart == '\r') + break; + setby[i] = *lstart++; + } + setby[i] = '\0'; + + if (!*setby) + break; + + PIN_MakeMessage(setby, message); + } + + BZ_Free(file); +} +void PIN_SaveMessages(void) +{ + pinnedmessages_t *p; + FILE *f; + + f = COM_WriteFileOpen("pinned.txt"); + if (!f) + { + Con_Printf("couldn't write anything\n"); + return; + } + + for (p = pinned; p; p = p->next) + fprintf(f, "%s\r\n\t%s\r\n\n", p->message, p->setby); + + fclose(f); +} +void PIN_DeleteOldestMessage(void) +{ + pinnedmessages_t *old = pinned; + pinned = pinned->next; + Z_Free(old); +} +void PIN_MakeMessage(char *from, char *msg) +{ + pinnedmessages_t *p; + pinnedmessages_t *new; + + new = BZ_Malloc(sizeof(pinnedmessages_t)); + Q_strncpyz(new->setby, from, sizeof(new->setby)); + Q_strncpyz(new->message, msg, sizeof(new->message)); + new->next = NULL; + + if (!pinned) + pinned = new; + else + { + for (p = pinned; ; p = p->next) + { + if (!p->next) + { + p->next = new; + break; + } + } + } +} +void PIN_ShowMessages(client_t *cl) +{ + pinnedmessages_t *p; + if (dopinnedload) + PIN_LoadMessages(); + + if (!pinned) + return; + + SV_ClientPrintf(cl, PRINT_HIGH, "\n\n\n"); + for (p = pinned; p; p = p->next) + { + SV_ClientPrintf(cl, PRINT_HIGH, "%s\n\n %s\n", p->message, p->setby); + SV_ClientPrintf(cl, PRINT_HIGH, "\n\n\n"); + } + +} + //==================================================================== /* @@ -536,6 +665,22 @@ int SV_CalcPing (client_t *cl) return 0; } +void SV_GenerateBasicUserInfo(client_t *cl) +{ + char *key, *s; + int i; + for (i= 1; (key = Info_KeyForNumber(cl->userinfo, i)); i++) + { + if (!*key) + break; + if (!SV_UserInfoIsBasic(key)) + continue; + + s = Info_ValueForKey(cl->userinfo, key); + Info_SetValueForStarKey (cl->userinfobasic, key, s, sizeof(cl->userinfobasic)); + } +} + /* =================== SV_FullClientUpdate @@ -543,7 +688,7 @@ SV_FullClientUpdate Writes all update values to a sizebuf =================== */ -void SV_FullClientUpdate (client_t *client, sizebuf_t *buf) +void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext) { int i; char info[MAX_INFO_STRING]; @@ -598,7 +743,10 @@ void SV_FullClientUpdate (client_t *client, sizebuf_t *buf) MSG_WriteByte (buf, i); MSG_WriteFloat (buf, realtime - client->connection_started); - strcpy (info, client->userinfo); + if (ftepext & PEXT_CSQC) + strcpy (info, client->userinfo); + else + strcpy (info, client->userinfobasic); Info_RemoveKey(info, "password"); //main password key Info_RemovePrefixedKeys (info, '_'); // server passwords, etc @@ -672,10 +820,10 @@ void SV_FullClientUpdateToClient (client_t *client, client_t *cl) else ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo)); if (cl->num_backbuf) { - SV_FullClientUpdate (client, &cl->backbuf); + SV_FullClientUpdate (client, &cl->backbuf, cl->fteprotocolextensions); ClientReliable_FinishWrite(cl); } else - SV_FullClientUpdate (client, &cl->netchan.message); + SV_FullClientUpdate (client, &cl->netchan.message, cl->fteprotocolextensions); } } @@ -1704,6 +1852,7 @@ client_t *SVC_DirectConnect(void) // parse some info from the info strings SV_ExtractFromUserinfo (newcl); + SV_GenerateBasicUserInfo (newcl); // JACK: Init the floodprot stuff. for (i=0; i<10; i++) @@ -1900,6 +2049,8 @@ client_t *SVC_DirectConnect(void) Sys_ServerActivity(); + PIN_ShowMessages(newcl); + if (ISNQCLIENT(newcl)) { newcl->netchan.message.maxsize = sizeof(newcl->netchan.message_buf); @@ -1907,6 +2058,8 @@ client_t *SVC_DirectConnect(void) SVNQ_New_f(); } + + return newcl; } @@ -2857,6 +3010,10 @@ void SV_MVDStream_Poll(void); if (isDedicated) #endif { +#ifdef PLUGINS + Plug_Tick(); +#endif + SV_GetConsoleCommands (); // process console commands @@ -3577,7 +3734,6 @@ void SV_ExtractFromUserinfo (client_t *cl) #endif } - //============================================================================ /* @@ -3664,11 +3820,17 @@ void SV_Init (quakeparms_t *parms) { Sys_Init (); PM_Init (); + +#ifdef PLUGINS + Plug_Init(); +#endif + Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); host_hunklevel = Hunk_LowMark (); host_initialized = true; + Con_TPrintf (TL_EXEDATETIME, __DATE__, __TIME__); Con_TPrintf (TL_HEAPSIZE,parms->memsize/ (1024*1024.0)); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index e25fa4c57..4bbb2cb61 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1569,7 +1569,7 @@ void SV_UpdateToReliableMessages (void) if (host_client->sendinfo) { host_client->sendinfo = false; - SV_FullClientUpdate (host_client, &sv.reliable_datagram); + SV_FullClientUpdate (host_client, &sv.reliable_datagram, host_client->fteprotocolextensions); } if (host_client->old_frags != (int)host_client->edict->v->frags) { diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 93fdac460..134524ea9 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -2239,6 +2239,27 @@ void SV_Msg_f (void) SV_ClientTPrintf (host_client, PRINT_HIGH, STL_MSGLEVELSET, host_client->messagelevel); } +qboolean SV_UserInfoIsBasic(char *infoname) +{ + int i; + char *basicinfos[] = { + + "name", + "team", + "skin", + "topcolor", + "bottomcolor", + + NULL}; + + for (i = 0; basicinfos[i]; i++) + { + if (!strcmp(infoname, basicinfos[i])) + return true; + } + return false; +} + /* ================== SV_SetInfo_f @@ -2248,9 +2269,11 @@ Allow clients to change userinfo */ void SV_SetInfo_f (void) { - int i; + int i, j; char oldval[MAX_INFO_STRING]; char *key, *val; + qboolean basic; //infos that we send to any old qw client. + client_t *client; if (Cmd_Argc() == 1) @@ -2269,6 +2292,9 @@ void SV_SetInfo_f (void) if (Cmd_Argv(1)[0] == '*') return; // don't set priveledged values + if (strstr(Cmd_Argv(1), "\\") || strstr(Cmd_Argv(2), "\\")) + return; // illegal char + strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1))); Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), sizeof(host_client->userinfo)); @@ -2294,10 +2320,33 @@ void SV_SetInfo_f (void) i = host_client - svs.clients; key = Cmd_Argv(1); val = Info_ValueForKey(host_client->userinfo, key); - MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); - MSG_WriteByte (&sv.reliable_datagram, i); - MSG_WriteString (&sv.reliable_datagram, key); - MSG_WriteString (&sv.reliable_datagram, val); + + basic = SV_UserInfoIsBasic(key); + + if (basic) + Info_SetValueForKey (host_client->userinfobasic, key, val, sizeof(host_client->userinfobasic)); + for (j = 0; j < MAX_CLIENTS; j++) + { + client = svs.clients+j; + if (client->state < cs_connected) + continue; // reliables go to all connected or spawned + if (client->controller) + continue; //splitscreen + + if (client->protocol == SCP_BAD) + continue; //botclient + + if (ISQWCLIENT(client)) + { + if (basic || (client->fteprotocolextensions & PEXT_CSQC)) + { + MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteString (&sv.reliable_datagram, key); + MSG_WriteString (&sv.reliable_datagram, val); + } + } + } if (sv.mvdrecording) {