From 630af9dc7ce5fce09c570a070e18bf6c4ae059bd Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 12 Mar 2013 22:44:00 +0000 Subject: [PATCH] ------------------------------------------------------------------------ r4187 | acceptthis | 2013-02-04 04:52:32 +0000 (Mon, 04 Feb 2013) | 9 lines fix particle effect index insanity. .modelflags support. fix laggy mvds issue. replacementdeltas works in mvds. fix issues with not knowing which mvd is currently being recorded. input line now permanently functions as utf-8. cope with double-chevron links in the input line. Add support for ^{xxxx}, but don't generate it. can only cope with 16bit anyway. fix skins issues. ------------------------------------------------------------------------ git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4185 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_demo.c | 44 ++++-- engine/client/cl_ents.c | 43 ++++-- engine/client/cl_input.c | 2 + engine/client/cl_main.c | 30 +++- engine/client/cl_parse.c | 43 ++++-- engine/client/cl_pred.c | 2 +- engine/client/cl_tent.c | 37 ++++- engine/client/client.h | 18 +-- engine/client/console.c | 11 +- engine/client/keys.c | 98 ++++++++----- engine/client/net_master.c | 6 +- engine/client/pr_csqc.c | 62 +++++--- engine/client/pr_menu.c | 30 ++++ engine/client/r_surf.c | 2 +- engine/client/renderer.c | 4 +- engine/client/sys_win.c | 8 +- engine/client/zqtp.c | 11 +- engine/common/bothdefs.h | 4 +- engine/common/common.c | 243 ++++++++++++++++++++----------- engine/common/common.h | 6 +- engine/common/console.h | 2 +- engine/common/net_wins.c | 13 +- engine/common/pr_bgcmd.c | 8 +- engine/common/protocol.h | 9 +- engine/gl/gl_alias.c | 19 ++- engine/gl/gl_font.c | 138 +++++++++++------- engine/gl/gl_model.h | 4 +- engine/gl/gl_shader.c | 3 + engine/qclib/execloop.h | 1 + engine/qclib/qcc_pr_comp.c | 3 + engine/server/pr_cmds.c | 227 ++++++++++++++++++++++++----- engine/server/pr_q1qvm.c | 2 +- engine/server/q3g_public.h | 2 +- engine/server/server.h | 4 +- engine/server/sv_ents.c | 2 +- engine/server/sv_main.c | 15 +- engine/server/sv_mvd.c | 97 ++++++------ engine/server/sv_send.c | 26 ++-- engine/server/sv_user.c | 38 ++++- fteqtv/dotnet2005/qtvprox.vcproj | 20 +++ plugins/berkelium/plugapi.cpp | 8 +- 41 files changed, 952 insertions(+), 393 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index af31e3a5d..50f9998ed 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -256,7 +256,7 @@ int readdemobytes(int *readpos, void *data, int len) endofdemo = true; return 0; } - len = demobuffersize; +// len = demobuffersize; return 0; } memcpy(data, demobuffer+*readpos, len); @@ -503,6 +503,7 @@ readnext: demo_flushbytes(demopos); demopos = 0; } + // read the time from the packet if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { @@ -521,6 +522,7 @@ readnext: Con_DPrintf("Not enough buffered\n"); demotime = olddemotime; nextdemotime = demotime; + return 0; } else { @@ -596,8 +598,11 @@ readnext: { if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime) { - cls.netchan.incoming_sequence++; - cls.netchan.incoming_acknowledged++; + if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) + { + cls.netchan.incoming_sequence++; + cls.netchan.incoming_acknowledged++; + } cls.netchan.frame_latency = 0; cls.netchan.last_received = realtime; // just to happy timeout check } @@ -607,18 +612,21 @@ readnext: Host_Error ("CL_GetDemoMessage: cls.state != ca_active"); // get the msg type - if (!readdemobytes (&demopos, &c, sizeof(c))) + if (readdemobytes (&demopos, &c, sizeof(c)) != sizeof(c)) { Con_DPrintf("Not enough buffered\n"); olddemotime = demtime+1; return 0; } -// Con_Printf("demo packet %x\n", (int)c); switch (c&7) { case dem_cmd : -/* if (cls.demoplayback == DPB_MVD) + if (cls.demoplayback == DPB_MVD) { + Con_Printf("mvd demos/qtv streams should not contain dem_cmd\n"); + olddemotime = demtime+1; + CL_StopPlayback (); + /* unsigned short samps; unsigned char bits; unsigned char rateid; @@ -653,11 +661,11 @@ readnext: } } } - +*/ return 0; } else - {*/ + { // user sent input i = cls.netchan.outgoing_sequence & UPDATE_MASK; pcmd = &cl.frames[i].cmd[0]; @@ -691,7 +699,7 @@ readnext: cl.playerview[0].viewangles[i] = LittleFloat (f); } goto readnext; -/* }*/ + } break; case dem_read: @@ -755,9 +763,17 @@ readit: break; case dem_set : - readdemobytes (&demopos, &i, 4); - cls.netchan.outgoing_sequence = LittleLong(i); - readdemobytes (&demopos, &i, 4); + if (readdemobytes (&demopos, &j, 4) != 4) + { + olddemotime = demtime; + return 0; + } + if (readdemobytes (&demopos, &i, 4) != 4) + { + olddemotime = demtime; + return 0; + } + cls.netchan.outgoing_sequence = LittleLong(j); cls.netchan.incoming_sequence = LittleLong(i); if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) @@ -1307,7 +1323,7 @@ void CL_Record_f (void) continue; #ifdef PEXT_LIGHTSTYLECOL - if ((cls.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && cl_lightstyle[i].colour!=7) + if ((cls.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && cl_lightstyle[i].colour!=7 && *cl_lightstyle[i].map) { MSG_WriteByte (&buf, svcfte_lightstylecol); MSG_WriteByte (&buf, (unsigned char)i); @@ -1766,7 +1782,7 @@ void CL_QTVPoll (void) if (*colon) Con_Printf("streaming \"%s\" from qtv\n", colon); else - Con_Printf("qtv connection established to %s\n", colon); + Con_Printf("qtv connection established to %s\n", qtvhostname); streamavailable = true; } diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 2b5ed6a61..a2798b3ad 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -726,8 +726,13 @@ void CLFTE_ParseEntities(void) // Con_Printf("CL: Dropped %i\n", i); // } + if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) + { + cls.netchan.incoming_sequence++; + cls.netchan.incoming_acknowledged++; + } #ifdef NQPROT - if (cls.protocol == CP_NETQUAKE) + else if (cls.protocol == CP_NETQUAKE) { int i; for (i = 0; i < MAX_SPLITS; i++) @@ -740,12 +745,15 @@ void CLFTE_ParseEntities(void) if (cl.numackframes == sizeof(cl.ackframes)/sizeof(cl.ackframes[0])) cl.numackframes--; - cl.ackframes[cl.numackframes++] = cls.netchan.incoming_sequence; + if (!cl.validsequence) + cl.ackframes[cl.numackframes++] = -1; + else + cl.ackframes[cl.numackframes++] = cls.netchan.incoming_sequence; cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].receivedtime = realtime; - if (cl.validsequence != cls.netchan.incoming_sequence-1) - Con_Printf("CLIENT: Dropped a frame\n"); +// if (cl.validsequence != cls.netchan.incoming_sequence-1) +// Con_Printf("CLIENT: Dropped a frame\n"); } #endif @@ -2977,7 +2985,7 @@ void CL_TransitionEntities (void) packnew = &cl.frames[newf].packet_entities; packold = &cl.frames[oldf].packet_entities; -// Con_Printf("%f %f %f\n", packold->servertime, servertime, packnew->servertime); +// Con_Printf("%f %f %f (%i)\n", packold->servertime, servertime, packnew->servertime, newff); // Con_Printf("%f %f %f\n", cl.oldgametime, servertime, cl.gametime); CL_TransitionPacketEntities(newff, packnew, packold, servertime); @@ -3053,6 +3061,7 @@ void CL_LinkPacketEntities (void) static int flickertime; static int flicker; int trailef; + int modelflags; pack = cl.currentpackentities; if (!pack) @@ -3189,6 +3198,14 @@ void CL_LinkPacketEntities (void) Con_DPrintf("Bad modelindex (%i)\n", state->modelindex); continue; } + + //DP extension. .modelflags (which is sent in the high parts of effects) allows to specify exactly the q1-compatible flags. + //the extra bit allows for setting to 0. + //note that hexen2 has additional flags which cannot be expressed. + if (state->effects & 0xff800000) + modelflags = state->effects>>24; + else + modelflags = model->flags; if (cl.model_precache_vwep[0]) { @@ -3276,7 +3293,7 @@ void CL_LinkPacketEntities (void) #endif // rotate binary objects locally - if (model && model->flags & MF_ROTATE) + if (modelflags & MF_ROTATE) { angles[0] = 0; angles[1] = autorotate; @@ -3337,10 +3354,10 @@ void CL_LinkPacketEntities (void) CL_AddVWeapModel (ent, model2); // add automatic particle trails - if (!model || (!(model->flags&~MF_ROTATE) && model->particletrail<0 && model->particleeffect<0 && state->u.q1.traileffectnum==0)) + if (!model || (!(modelflags&~MF_ROTATE) && model->particletrail<0 && model->particleeffect<0 && state->u.q1.traileffectnum==0)) continue; - if (!cls.allow_anyparticles && !(model->flags & ~MF_ROTATE)) + if (!cls.allow_anyparticles && !(modelflags & ~MF_ROTATE)) continue; if (le->isnew) @@ -3387,7 +3404,7 @@ void CL_LinkPacketEntities (void) dclr[1] = 1.0; dclr[2] = 0.25; - if (model->flags & MF_ROCKET) + if (modelflags & MF_ROCKET) { #ifdef warningmsg #pragma warningmsg("Replace this flag on load for hexen2 models") @@ -3398,17 +3415,17 @@ void CL_LinkPacketEntities (void) rad += r_lightflicker.value?((flicker + state->number)&31):0; } } - else if (model->flags & MFH2_FIREBALL) + else if (modelflags & MFH2_FIREBALL) { rad = 120 - (rand() % 20); } - else if (model->flags & MFH2_ACIDBALL) + else if (modelflags & MFH2_ACIDBALL) { rad = 120 - (rand() % 20); dclr[0] = 0.1; dclr[1] = 0.2; } - else if (model->flags & MFH2_SPIT) + else if (modelflags & MFH2_SPIT) { // as far as I can tell this effect inverses the light... dclr[0] = -dclr[0]; @@ -3423,7 +3440,7 @@ void CL_LinkPacketEntities (void) memcpy(dl->axis, ent->axis, sizeof(dl->axis)); VectorCopy (ent->origin, dl->origin); dl->die = (float)cl.time; - if (model->flags & MF_ROCKET) + if (modelflags & MF_ROCKET) dl->origin[2] += 1; // is this even necessary dl->radius = rad * r_rocketlight.value; VectorCopy(dclr, dl->color); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 3b34bd578..8708bc81f 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -102,6 +102,8 @@ void CL_SplitA_f(void) char *c, *args; c = Cmd_Argv(0); args = COM_Parse(Cmd_Args()); + if (!args) + return; while(*args == ' ' || *args == '\t') args++; tmp = con_splitmodifier; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index a303ca4b0..c42d7c539 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -140,7 +140,7 @@ cvar_t cl_gunangley = SCVAR("cl_gunangley", "0"); cvar_t cl_gunanglez = SCVAR("cl_gunanglez", "0"); cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available."); -cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "0", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files."); +cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. 2 allows redirection only to named packages files."); cvar_t cl_download_mapsrc = CVARD("cl_download_mapsrc", "", "Specifies an http location prefix for map downloads. EG: \"http://bigfoot.morphos-team.net/misc/quakemaps/\""); cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)"); cvar_t requiredownloads = CVARFD("requiredownloads","1", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining."); @@ -2900,7 +2900,7 @@ void CL_Download_f (void) if (Cmd_IsInsecure()) //mark server specified downloads. { - if (!strnicmp(url, "game", 4) || !stricmp(url, "progs.dat") || !stricmp(url, "menu.dat") || !stricmp(url, "csprogs.dat") || !stricmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".dll") || strstr(url, ".so")) + if (!strnicmp(url, "game", 4) || !stricmp(url, "progs.dat") || !stricmp(url, "menu.dat") || !stricmp(url, "csprogs.dat") || !stricmp(url, "qwprogs.dat") || strstr(url, "..") || strstr(url, ".qvm") || strstr(url, ".dll") || strstr(url, ".so")) { //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar) Con_Printf("Ignoring stuffed download of \"%s\" due to possible security risk\n", url); return; @@ -2941,18 +2941,27 @@ void CL_DownloadSize_f(void) } } else if (!strcmp(size, "r")) - { + { //'download this file instead' + int allow = cl_download_redirection.ival; redirection = Cmd_Argv(3); dl = CL_DownloadFailed(rname, false); - if (cl_download_redirection.ival) + if (allow == 2) + { + char *ext = COM_FileExtension(redirection); + if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4")) + allow = true; + else + allow = false; + } + if (allow) { Con_DPrintf("Download of \"%s\" redirected to \"%s\".\n", rname, redirection); CL_CheckOrEnqueDownloadFile(redirection, NULL, dl->flags); } else - Con_Printf("Download of \"%s\" redirected to \"%s\". Prevented by allow_download_redirection.\n", rname, redirection); + Con_Printf("Download of \"%s\" redirected to \"%s\". Prevented by cl_download_redirection.\n", rname, redirection); } else { @@ -3111,10 +3120,18 @@ void CL_Init (void) extern void CL_SayTeam_f (void); extern cvar_t baseskin; extern cvar_t noskins; + char *ver; cls.state = ca_disconnected; - Info_SetValueForStarKey (cls.userinfo[0], "*ver", version_string(), sizeof(cls.userinfo[0])); +#ifdef SVNREVISION + if (strcmp(SVNREVISION, "-")) + ver = va("%s v%i.%02i %s", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR, SVNREVISION); + else +#endif + ver = va("%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR); + + Info_SetValueForStarKey (cls.userinfo[0], "*ver", ver, sizeof(cls.userinfo[0])); Info_SetValueForStarKey (cls.userinfo[1], "*ss", "1", sizeof(cls.userinfo[1])); Info_SetValueForStarKey (cls.userinfo[2], "*ss", "1", sizeof(cls.userinfo[2])); Info_SetValueForStarKey (cls.userinfo[3], "*ss", "1", sizeof(cls.userinfo[3])); @@ -3159,6 +3176,7 @@ void CL_Init (void) Cvar_Register (&cl_anglespeedkey, cl_inputgroup); Cvar_Register (&cl_shownet, cl_screengroup); Cvar_Register (&cl_sbar, cl_screengroup); + Cvar_Register (&cl_pure, cl_screengroup); Cvar_Register (&cl_hudswap, cl_screengroup); Cvar_Register (&cl_maxfps, cl_screengroup); Cvar_Register (&cl_idlefps, cl_screengroup); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 815341f2e..51439d375 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -678,7 +678,7 @@ void CL_DownloadFinished(void) break; } } - for (i = 0; i < MAX_CSQCMODELS; i++) //go and load this model now. + for (i = 0; i < MAX_CSMODELS; i++) //go and load this model now. { if (!strcmp(cl.model_csqcname[i], filename)) { @@ -1186,7 +1186,7 @@ int CL_LoadModels(int stage, qboolean dontactuallyload) endstage(); } - for (i=1 ; i msg && t[-1] == '^') + { + for (c = 1; t-c > msg; c++) + { + if (t[-c] == '^') + break; + } + if (c & 1) + { + *t = '\0'; + Q_strncatz(fullchatmessage, va("%s{", msg), sizeof(fullchatmessage)); + msg = t+1; + continue; + } + } + u = strchr(t, '}'); if (u) { *t = 0; @@ -5143,10 +5159,10 @@ void CL_ParsePrecache(void) { int i, code = (unsigned short)MSG_ReadShort(); char *s = MSG_ReadString(); - i = code & 0x1fff; - switch(code & 0xe000) + i = code & ~PC_TYPE; + switch(code & PC_TYPE) { - case 0x0000: + case PC_MODEL: if (i >= 1 && i < MAX_MODELS) { model_t *model; @@ -5162,9 +5178,9 @@ void CL_ParsePrecache(void) else Con_Printf("svc_precache: model index %i outside range %i...%i\n", i, 1, MAX_MODELS); break; - case 0x4000: + case PC_UNUSED: break; - case 0x8000: + case PC_SOUND: if (i >= 1 && i < MAX_SOUNDS) { sfx_t *sfx; @@ -5179,10 +5195,17 @@ void CL_ParsePrecache(void) else Con_Printf("svc_precache: sound index %i outside range %i...%i\n", i, 1, MAX_SOUNDS); break; - case 0xC000: - if (i >= 1 && i < 1024) + case PC_PARTICLE: + if (i >= 1 && i < MAX_SSPARTICLESPRE) { + if (cl.particle_ssname[i]) + free(cl.particle_ssname[i]); + cl.particle_ssname[i] = strdup(s); + cl.particle_ssprecache[i] = 1+P_FindParticleType(s); + cl.particle_ssprecaches = true; } + else + Con_Printf("svc_precache: particle index %i outside range %i...%i\n", i, 1, MAX_SSPARTICLESPRE); break; } } diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 2e99d51af..a6fbe5cb6 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -639,7 +639,7 @@ void CL_CalcClientTime(void) { float oldst = realtime; - if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD) + if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD && !(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) { extern float nextdemotime, olddemotime, demtime; float f; diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index c95547a7b..3f94a834b 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -1879,6 +1879,23 @@ void CL_RefreshCustomTEnts(void) int i; for (i = 0; i < sizeof(customtenttype)/sizeof(customtenttype[0]); i++) customtenttype[i].particleeffecttype = (!*customtenttype[i].name)?-1:P_FindParticleType(customtenttype[i].name); + + if (cl.particle_ssprecaches) + { + for (i = 0; i <= MAX_SSPARTICLESPRE; i++) + { + if (cl.particle_ssname[i]) + cl.particle_ssprecache[i] = 1+P_FindParticleType(cl.particle_ssname[i]); + } + } + if (cl.particle_csprecaches) + { + for (i = 0; i <= MAX_CSPARTICLESPRE; i++) + { + if (cl.particle_csname[i]) + cl.particle_csprecache[i] = 1+P_FindParticleType(cl.particle_csname[i]); + } + } } void CL_ClearCustomTEnts(void) { @@ -1897,18 +1914,26 @@ void CL_ClearCustomTEnts(void) } } -int CL_TranslateParticleFromServer(int sveffect) +int CL_TranslateParticleFromServer(int qceffect) { - if (cl.maxparticleprecaches) + if (cl.particle_ssprecaches && qceffect >= 0 && qceffect < MAX_SSPARTICLESPRE) { /*proper precaches*/ - return cl.particle_precache[sveffect].num; + return cl.particle_ssprecache[qceffect]-1; + } + else if (-qceffect >= 0 && -qceffect < MAX_CSPARTICLESPRE) + { + qceffect = -qceffect; + return cl.particle_csprecache[qceffect]-1; } else - { + return -1; + +// else +// { /*server and client must share an identical effectinfo list file (just "effect $name\n" lines)*/ - return P_FindParticleType(COM_Effectinfo_ForNumber(sveffect)); - } +// return P_FindParticleType(COM_Effectinfo_ForNumber(qceffect)); +// } } void CL_ParseTrailParticles(void) diff --git a/engine/client/client.h b/engine/client/client.h index 723c7dd76..46b3f7caa 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -630,24 +630,22 @@ typedef struct char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH]; char model_name[MAX_MODELS][MAX_QPATH]; char sound_name[MAX_SOUNDS][MAX_QPATH]; + char *particle_ssname[MAX_SSPARTICLESPRE]; char image_name[Q2MAX_IMAGES][MAX_QPATH]; struct model_s *model_precache_vwep[MAX_VWEP_MODELS]; struct model_s *model_precache[MAX_MODELS]; struct sfx_s *sound_precache[MAX_SOUNDS]; + int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat. - char model_csqcname[MAX_CSQCMODELS][MAX_QPATH]; - struct model_s *model_csqcprecache[MAX_CSQCMODELS]; + char model_csqcname[MAX_CSMODELS][MAX_QPATH]; + struct model_s *model_csqcprecache[MAX_CSMODELS]; + char *particle_csname[MAX_CSPARTICLESPRE]; + int particle_csprecache[MAX_CSPARTICLESPRE]; //these are actually 1-based, so we can be lazy and do a simple negate. qboolean model_precaches_added; - - struct - { - int num; - char *name; - } *particle_precache; - unsigned int maxparticleprecaches; - + qboolean particle_ssprecaches; //says to not try to do any dp-compat hacks. + qboolean particle_csprecaches; //says to not try to do any dp-compat hacks. //used for q2 sky/configstrings char skyname[MAX_QPATH]; diff --git a/engine/client/console.c b/engine/client/console.c index 3171a6b50..dd78a64e6 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -949,9 +949,10 @@ int Con_DrawInput (int left, int right, int y, qboolean selactive, int selsx, in i = text[key_linepos]; text[key_linepos] = 0; - cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true); + cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), PFS_KEEPMARKUP | PFS_FORCEUTF8); text[key_linepos] = i; - endmtext = COM_ParseFunString(CON_WHITEMASK, text+key_linepos, cursor, ((char*)maskedtext)+sizeof(maskedtext) - (char*)(cursor+1), true); + endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), PFS_KEEPMARKUP | PFS_FORCEUTF8); +// endmtext = COM_ParseFunString(CON_WHITEMASK, text+key_linepos, cursor, ((char*)maskedtext)+sizeof(maskedtext) - (char*)(cursor+1), PFS_KEEPMARKUP | PFS_FORCEUTF8); endmtext[1] = 0; @@ -1055,7 +1056,11 @@ int Con_DrawInput (int left, int right, int y, qboolean selactive, int selsx, in { cmd = Cmd_CompleteCommand (text+cmdstart, true, true, i, NULL); if (!cmd) + { + if (i <= 2) + con_commandmatch = 0; break; + } end = COM_ParseFunString((COLOR_GREEN< linelength) + selendoffset = linelength; } if (y <= selsy) { diff --git a/engine/client/keys.c b/engine/client/keys.c index b58e97681..faa05031f 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -352,6 +352,24 @@ void CompleteCommand (qboolean force) void Con_ExecuteLine(console_t *con, char *line) { qboolean waschat = false; + char deutf8[1024]; + extern cvar_t com_parseutf8; + if (com_parseutf8.ival <= 0) + { + unsigned int unicode; + int err; + int len = 0; + while(*line) + { + unicode = utf8_decode(&err, line, &line); + if (com_parseutf8.ival < 0) + len += iso88591_encode(deutf8+len, unicode, sizeof(deutf8)-1 - len); + else + len += qchar_encode(deutf8+len, unicode, sizeof(deutf8)-1 - len); + } + deutf8[len] = 0; + line = deutf8; + } con_commandmatch=1; Con_Footerf(false, ""); @@ -754,14 +772,26 @@ void Key_ConsoleRelease(int key, int unicode) } } - -//move the cursor one char to the left. cursor must be within the 'start' string. -unsigned char *utf_left(unsigned char *start, unsigned char *cursor) +//if the referenced (trailing) chevron is doubled up, then it doesn't act as part of any markup and should be ignored for such things. +static qboolean utf_specialchevron(unsigned char *start, unsigned char *chev) { - extern cvar_t com_parseutf8; + int count = 0; + while (chev >= start) + { + if (*chev-- == '^') + count++; + else + break; + } + return count&1; +} +//move the cursor one char to the left. cursor must be within the 'start' string. +static unsigned char *utf_left(unsigned char *start, unsigned char *cursor) +{ +// extern cvar_t com_parseutf8; if (cursor == start) return cursor; - if (com_parseutf8.ival>0) + if (1)//com_parseutf8.ival>0) { cursor--; while ((*cursor & 0xc0) == 0x80 && cursor > start) @@ -770,14 +800,16 @@ unsigned char *utf_left(unsigned char *start, unsigned char *cursor) else cursor--; - if (*cursor == ']' && cursor > start && cursor[-1] == '^') + //FIXME: should verify that the ^ isn't doubled. + if (*cursor == ']' && cursor > start && utf_specialchevron(start, cursor-1)) { //just stepped onto a link unsigned char *linkstart; linkstart = cursor-1; while(linkstart >= start) { - if (linkstart[0] == '^' && linkstart[1] == '[') + //FIXME: should verify that the ^ isn't doubled. + if (utf_specialchevron(start, linkstart) && linkstart[1] == '[') return linkstart; linkstart--; } @@ -787,20 +819,19 @@ unsigned char *utf_left(unsigned char *start, unsigned char *cursor) } //move the cursor one char to the right. -unsigned char *utf_right(unsigned char *cursor) +static unsigned char *utf_right(unsigned char *start, unsigned char *cursor) { - extern cvar_t com_parseutf8; +// extern cvar_t com_parseutf8; - if (*cursor == '^' && cursor[1] == '[') + //FIXME: should make sure this is not doubled. + if (utf_specialchevron(start, cursor) && cursor[1] == '[') { //just stepped over a link char *linkend; linkend = cursor+2; while(*linkend) { - if (linkend[0] == '^' && linkend[1] == '^') - linkend += 2; - else if (linkend[0] == '^' && linkend[1] == ']') + if (utf_specialchevron(start, linkend) && linkend[1] == ']') return linkend+2; else linkend++; @@ -808,7 +839,7 @@ unsigned char *utf_right(unsigned char *cursor) return linkend; } - if (com_parseutf8.ival>0) + if (1)//com_parseutf8.ival>0) { int skip = 1; //figure out the length of the char @@ -851,6 +882,7 @@ void Key_Console (unsigned int unicode, int key) { extern cvar_t com_parseutf8; char *clipText; + char utf8[8]; if (con_current->redirect) { @@ -914,6 +946,7 @@ void Key_Console (unsigned int unicode, int key) if (con_current->linebuffered) con_current->linebuffered(con_current, key_lines[oldl]+1); + con_commandmatch = 0; return; } @@ -954,7 +987,7 @@ void Key_Console (unsigned int unicode, int key) { if (key_lines[edit_line][key_linepos]) { - key_linepos = utf_right(key_lines[edit_line] + key_linepos) - key_lines[edit_line]; + key_linepos = utf_right(key_lines[edit_line]+1, key_lines[edit_line] + key_linepos) - key_lines[edit_line]; return; } else @@ -965,7 +998,7 @@ void Key_Console (unsigned int unicode, int key) { if (key_lines[edit_line][key_linepos]) { - int charlen = utf_right(key_lines[edit_line] + key_linepos) - (key_lines[edit_line] + key_linepos); + int charlen = utf_right(key_lines[edit_line]+1, key_lines[edit_line] + key_linepos) - (key_lines[edit_line] + key_linepos); memmove(key_lines[edit_line]+key_linepos, key_lines[edit_line]+key_linepos+charlen, strlen(key_lines[edit_line]+key_linepos+charlen)+1); return; } @@ -981,6 +1014,8 @@ void Key_Console (unsigned int unicode, int key) memmove(key_lines[edit_line]+key_linepos-charlen, key_lines[edit_line]+key_linepos, strlen(key_lines[edit_line]+key_linepos)+1); key_linepos -= charlen; } + if (!key_lines[edit_line][1]) + con_commandmatch = 0; return; } @@ -997,6 +1032,8 @@ void Key_Console (unsigned int unicode, int key) key_linepos = Q_strlen(key_lines[edit_line]); key_lines[edit_line][0] = ']'; + if (!key_lines[edit_line][1]) + con_commandmatch = 0; return; } @@ -1007,6 +1044,7 @@ void Key_Console (unsigned int unicode, int key) key_lines[edit_line][0] = ']'; key_lines[edit_line][1] = '\0'; key_linepos=1; + con_commandmatch = 0; return; } do @@ -1136,32 +1174,12 @@ void Key_Console (unsigned int unicode, int key) unicode |= 0xe080; // red char } - if (com_parseutf8.ival>0 && unicode > 127) + unicode = utf8_encode(utf8, unicode, sizeof(utf8)-1); + if (unicode) { - char utf8[8]; - int l = utf8_encode(utf8, unicode, sizeof(utf8)-1); - if (l) - { - utf8[l] = 0; - Key_ConsoleInsert(utf8); - return; - } - unicode = '?'; + utf8[unicode] = 0; + Key_ConsoleInsert(utf8); } - else if (unicode >= 0xe000 && unicode <= 0xe0ff && !com_parseutf8.ival) - unicode -= 0xe000; //text line is quake-safe - else if (unicode >= ((com_parseutf8.ival<0)?256:128)) - { - unicode = '?'; //sorry, char cannot be expressed using this encoding. - } - - if (strlen(key_lines[edit_line])+1 < MAXCMDLINE-1) - { - memmove(key_lines[edit_line]+key_linepos+1, key_lines[edit_line]+key_linepos, strlen(key_lines[edit_line]+key_linepos)+1); - key_lines[edit_line][key_linepos] = unicode; - key_linepos++; - } - } //============================================================================ diff --git a/engine/client/net_master.c b/engine/client/net_master.c index b10a1c12c..9f822c1ba 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1550,7 +1550,7 @@ void MasterInfo_Refresh(void) //Master_AddMaster("telefrag.me:27000",MT_MASTERQW, "Telefrag.ME"); //Master_AddMaster("master.teamdamage.com:27000", MT_MASTERQW, "TeamDamage"); Master_AddMaster("master.quakeservers.net:27000", MT_MASTERQW, "QuakeServers.net"); - Master_AddMaster("masterserver.exhale.de:27000", MT_MASTERQW, "team exhale"); +// Master_AddMaster("masterserver.exhale.de:27000", MT_MASTERQW, "team exhale"); Master_AddMaster("qwmaster.fodquake.net:27000", MT_MASTERQW, "Fodquake master server."); Master_AddMaster("qwmaster.ocrana.de:27000", MT_MASTERQW, "Ocrana2 master server."); Master_AddMaster("255.255.255.255:27500", MT_BCASTQW, "Nearby QuakeWorld UDP servers."); @@ -1578,7 +1578,7 @@ void MasterInfo_Refresh(void) //Master_AddMaster("master.planetgloom.com:27900",MT_MASTERQ2, "Planetgloom.com"); //Master_AddMaster("master.q2servers.com:27900", MT_MASTERQ2, "q2servers.com"); Master_AddMaster("netdome.biz:27900", MT_MASTERQ2, "Netdome.biz"); - Master_AddMaster("masterserver.exhale.de:27900",MT_MASTERQ2, "team exhale"); +// Master_AddMaster("masterserver.exhale.de:27900",MT_MASTERQ2, "team exhale"); Master_AddMaster("255.255.255.255:27910", MT_BCASTQ2, "Nearby Quake2 UDP servers."); #ifdef USEIPX Master_AddMaster("00000000:ffffffffffff:27910", MT_BCASTQ2, "Nearby Quake2 IPX servers."); @@ -1589,7 +1589,7 @@ void MasterInfo_Refresh(void) { //Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTPQW, "gameaholic's Q3 master"); Master_AddMaster("master.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master server."); - Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERQ3, "team exhale"); +// Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERQ3, "team exhale"); //Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master3 server."); Master_AddMaster("255.255.255.255:27960", MT_BCASTQ3, "Nearby Quake3 UDP servers."); } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 35742f35b..5cbd3b49e 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -559,7 +559,7 @@ static model_t *CSQC_GetModelForIndex(int index) return NULL; else if (index > 0 && index < MAX_MODELS) return cl.model_precache[index]; - else if (index < 0 && index > -MAX_CSQCMODELS) + else if (index < 0 && index > -MAX_CSMODELS) { if (!cl.model_csqcprecache[-index]) cl.model_csqcprecache[-index] = Mod_ForName(cl.model_csqcname[-index], false); @@ -1391,7 +1391,7 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars case VF_VIEWPORT: r_refdef.vrect.x = p[0]; r_refdef.vrect.y = p[1]; - p+=3; + p = G_VECTOR(OFS_PARM2); r_refdef.vrect.width = p[0]; r_refdef.vrect.height = p[1]; break; @@ -1701,7 +1701,7 @@ static int FindModel(char *name, int *free) if (!name || !*name) return 0; - for (i = 1; i < MAX_CSQCMODELS; i++) + for (i = 1; i < MAX_CSMODELS; i++) { if (!*cl.model_csqcname[i]) { @@ -1726,7 +1726,7 @@ static void csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int modelind ent->v->modelindex = modelindex; if (modelindex < 0) { - if (modelindex <= -MAX_CSQCMODELS) + if (modelindex <= -MAX_CSMODELS) return; ent->v->model = PR_SetString(prinst, cl.model_csqcname[-modelindex]); if (!cl.model_csqcprecache[-modelindex]) @@ -1936,6 +1936,7 @@ static void QCBUILTIN PF_cs_pointparticles (pubprogfuncs_t *prinst, struct globa if (prinst->callargc < 4) count = 1; + effectnum = CL_TranslateParticleFromServer(effectnum); P_RunParticleEffectType(org, vel, count, effectnum); } @@ -1950,14 +1951,13 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa { efnum = G_FLOAT(OFS_PARM1); ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); - - efnum = CL_TranslateParticleFromServer(efnum); } else { efnum = G_FLOAT(OFS_PARM0)-1; ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); } + efnum = CL_TranslateParticleFromServer(efnum); if (!ent->entnum) //world trails are non-state-based. pe->ParticleTrail(start, end, efnum, 0, NULL); @@ -1967,8 +1967,35 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa static void QCBUILTIN PF_cs_particleeffectnum (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + int i; char *effectname = PR_GetStringOfs(prinst, OFS_PARM0); + //use the server's index first. + for (i = 1; i < MAX_SSPARTICLESPRE && cl.particle_ssname[i]; i++) + { + if (!strcmp(cl.particle_ssname[i], effectname)) + { + G_FLOAT(OFS_RETURN) = i; + return; + } + } + //use the server's index first. + for (i = 1; i < MAX_CSPARTICLESPRE && cl.particle_csname[i]; i++) + { + if (!strcmp(cl.particle_csname[i], effectname)) + { + G_FLOAT(OFS_RETURN) = -i; + return; + } + } + if (i < MAX_CSPARTICLESPRE) + { + free(cl.particle_csname[i]); + cl.particle_csname[i] = NULL; + cl.particle_csprecache[i] = 1+P_FindParticleType(effectname); + if (cl.particle_csprecache[i]) + cl.particle_csname[i] = strdup(effectname); + } if (csqc_isdarkplaces) { //keep the effectinfo synced between server and client. @@ -1986,13 +2013,7 @@ static void QCBUILTIN PF_cs_particleeffectquery (pubprogfuncs_t *prinst, struct qboolean body = G_FLOAT(OFS_PARM1); char retstr[8192]; - if (csqc_isdarkplaces) - { - //keep the effectinfo synced between server and client. - id = CL_TranslateParticleFromServer(id); - } - else - id = id - 1; + id = CL_TranslateParticleFromServer(id); if (pe->ParticleQuery && pe->ParticleQuery(id, body, retstr, sizeof(retstr))) { @@ -2370,7 +2391,7 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv if (pnum < 0 || pnum >= cl.allocated_client_slots) ret = ""; - else if (!strcmp(keyname, "viewentity")) //compat with DP. Yes, I know this is in the wrong place. + else if (!strcmp(keyname, "viewentity")) //compat with DP. Yes, I know this is in the wrong place. This is an evil hack. { ret = buffer; sprintf(ret, "%i", pnum+1); @@ -2389,6 +2410,11 @@ static void QCBUILTIN PF_cs_getplayerkey (pubprogfuncs_t *prinst, struct globalv ret = buffer; sprintf(ret, "%i", cl.players[pnum].frags); } + else if (!strcmp(keyname, "userid")) + { + ret = buffer; + sprintf(ret, "%i", cl.players[pnum].userid); + } else if (!strcmp(keyname, "pl")) //packet loss { CheckSendPings(); @@ -4255,7 +4281,7 @@ static struct { {"drawline", PF_CL_drawline, 315}, // #315 void(float width, vector pos1, vector pos2) drawline (EXT_CSQC) {"iscachedpic", PF_CL_is_cached_pic, 316}, // #316 float(string name) iscachedpic (EXT_CSQC) {"precache_pic", PF_CL_precache_pic, 317}, // #317 string(string name, float trywad) precache_pic (EXT_CSQC) - {"draw_getimagesize", PF_CL_drawgetimagesize, 318}, // #318 vector(string picname) draw_getimagesize (EXT_CSQC) + {"drawgetimagesize", PF_CL_drawgetimagesize, 318}, // #318 vector(string picname) draw_getimagesize (EXT_CSQC) {"freepic", PF_CL_free_pic, 319}, // #319 void(string name) freepic (EXT_CSQC) //320 {"drawcharacter", PF_CL_drawcharacter, 320}, // #320 float(vector position, float character, vector scale, vector rgb, float alpha [, float flag]) drawcharacter (EXT_CSQC, [EXT_CSQC_???]) @@ -5085,7 +5111,7 @@ void CSQC_RendererRestarted(void) csqc_world.worldmodel = cl.worldmodel; - for (i = 0; i < MAX_CSQCMODELS; i++) + for (i = 0; i < MAX_CSMODELS; i++) { cl.model_csqcprecache[i] = NULL; } @@ -5303,6 +5329,8 @@ qboolean CSQC_DrawView(void) float mintic = 0.01; double clframetime = host_frametime; + csqc_resortfrags = true; + if (!csqcg.draw_function || !csqcprogs || !cl.worldmodel) return false; @@ -5341,8 +5369,6 @@ qboolean CSQC_DrawView(void) if (cl.worldmodel) R_LessenStains(); - csqc_resortfrags = true; - if (!cl.paused) { if (csqcg.clientcommandframe) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index c644f8afd..359780e82 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -674,6 +674,10 @@ static void QCBUILTIN PF_menu_cvar (pubprogfuncs_t *prinst, struct globalvars_s G_FLOAT(OFS_RETURN) = vid.width; else if (!strcmp(str, "vid_conheight")) G_FLOAT(OFS_RETURN) = vid.height; + else if (!strcmp(str, "vid_pixwidth")) + G_FLOAT(OFS_RETURN) = vid.pixelwidth; + else if (!strcmp(str, "vid_pixheight")) + G_FLOAT(OFS_RETURN) = vid.pixelheight; else { str = RemapCvarNameFromDPToFTE(str); @@ -884,6 +888,7 @@ static void QCBUILTIN PF_Remove_ (pubprogfuncs_t *prinst, struct globalvars_s *p if (ed->isfree) { Con_DPrintf("Tried removing free entity\n"); + PR_StackTrace(prinst); return; } @@ -1899,11 +1904,36 @@ void MP_Reload_f(void) M_Reinit(); } +void MP_Breakpoint_f(void) +{ + int wasset; + int isset; + char *filename = Cmd_Argv(1); + int line = atoi(Cmd_Argv(2)); + + if (!menuprogs) + { + Con_Printf("Menu not running\n"); + return; + } + wasset = menuprogs->ToggleBreak(menuprogs, filename, line, 3); + isset = menuprogs->ToggleBreak(menuprogs, filename, line, 2); + + if (wasset == isset) + Con_Printf("Breakpoint was not valid\n"); + else if (isset) + Con_Printf("Breakpoint has been set\n"); + else + Con_Printf("Breakpoint has been cleared\n"); + +} + void MP_RegisterCvarsAndCmds(void) { Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f); Cmd_AddCommand("menu_restart", MP_Reload_f); Cmd_AddCommand("menu_cmd", MP_GameCommand_f); + Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f); Cvar_Register(&forceqmenu, MENUPROGSGROUP); Cvar_Register(&pr_menuqc_coreonerror, MENUPROGSGROUP); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index c2267aa9e..82a7aa159 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2710,7 +2710,7 @@ void Surf_BuildLightmaps (void) break; Surf_BuildModelLightmaps(m); } - for (j=1 ; j -MAX_CSQCMODELS) + if (cl_static_entities[i].mdlidx > -MAX_CSMODELS) cl_static_entities[i].ent.model = cl.model_csqcprecache[-cl_static_entities[i].mdlidx]; } else diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index edc294cf1..4b485872c 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -733,7 +733,13 @@ void Sys_mkdir (char *path) qboolean Sys_remove (char *path) { - remove (path); + if (remove (path) != 0) + { + int e = errno; + if (e == ENOENT) + return true; //return success if it doesn't already exist. + return false; + } return true; } diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 5c1a18ea7..d94b35355 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -1281,7 +1281,7 @@ TP_ParseFunChars Doesn't check for overflows, so strlen(s) should be < MAX_MACRO_STRING ============== */ -static char *TP_ParseFunChars (char *s, qbool chat) +static char *TP_ParseFunChars (char *s) { static char buf[MAX_MACRO_STRING]; char *out = buf; @@ -1346,11 +1346,6 @@ static char *TP_ParseFunChars (char *s, qbool chat) continue; } } - if (!chat && *s == '^' && s[1] && s[1] != ' ') { - *out++ = s[1] | CON_HIGHCHARSMASK; - s += 2; - continue; - } skip: *out++ = *s++; } @@ -3453,7 +3448,7 @@ void CL_Say (qboolean team, char *extra) suppress = false; s = TP_ParseMacroString (Cmd_Args()); - Q_strncpyz (text, TP_ParseFunChars (s, true), sizeof(text)); + Q_strncpyz (text, TP_ParseFunChars (s), sizeof(text)); sendtext[0] = 0; if (team && !cl.spectator && cl_fakename.string[0] && @@ -3462,7 +3457,7 @@ void CL_Say (qboolean team, char *extra) char buf[1024]; Cmd_ExpandString (cl_fakename.string, buf, sizeof(buf), Cmd_ExecLevel, true, true); strcpy (buf, TP_ParseMacroString (buf)); - Q_snprintfz (sendtext, sizeof(sendtext), "\x0d%s: ", TP_ParseFunChars(buf, true)); + Q_snprintfz (sendtext, sizeof(sendtext), "\x0d%s: ", TP_ParseFunChars(buf)); } strlcat (sendtext, text, sizeof(sendtext)); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 0a43c11da..f115d5c46 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -520,9 +520,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_STANDARDLIGHTSTYLES 64 #define MAX_MODELS 1024 // these are sent over the net as bytes #define MAX_SOUNDS 1024 // so they cannot be blindly increased +#define MAX_SSPARTICLESPRE 1024 // precached particle effect names, for server-side pointparticles/trailparticles. #define MAX_VWEP_MODELS 32 -#define MAX_CSQCMODELS 256 // these live entirly clientside +#define MAX_CSMODELS 512 // these live entirly clientside +#define MAX_CSPARTICLESPRE 1024 #define SAVEGAME_COMMENT_LENGTH 39 diff --git a/engine/common/common.c b/engine/common/common.c index 0bc8274da..041dd1796 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2113,6 +2113,115 @@ unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen) return bcount; } +unsigned int qchar_encode(char *out, unsigned int unicode, int maxlen) +{ + static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if (((unicode >= 32 || unicode == '\n' || unicode == '\t' || unicode == '\r') && unicode < 128) || unicode >= 0xe000 && unicode <= 0xe0ff) + { //quake compatible chars + if (maxlen < 1) + return 0; + *out++ = unicode; + return 1; + } + else if (unicode > 0xffff) + { //chars longer than 16 bits + char *o = out; + if (maxlen < 11) + return 0; + *out++ = '^'; + *out++ = '{'; + if (unicode > 0xfffffff) + *out++ = hex[(unicode>>28)&15]; + if (unicode > 0xffffff) + *out++ = hex[(unicode>>24)&15]; + if (unicode > 0xfffff) + *out++ = hex[(unicode>>20)&15]; + if (unicode > 0xffff) + *out++ = hex[(unicode>>16)&15]; + if (unicode > 0xfff) + *out++ = hex[(unicode>>12)&15]; + if (unicode > 0xff) + *out++ = hex[(unicode>>8)&15]; + if (unicode > 0xf) + *out++ = hex[(unicode>>4)&15]; + if (unicode > 0x0) + *out++ = hex[(unicode>>0)&15]; + *out++ = '}'; + return out - o; + } + else + { //16bit chars + if (maxlen < 6) + return 0; + *out++ = '^'; + *out++ = 'U'; + *out++ = hex[(unicode>>12)&15]; + *out++ = hex[(unicode>>8)&15]; + *out++ = hex[(unicode>>4)&15]; + *out++ = hex[(unicode>>0)&15]; + return 6; + } +} + +unsigned int iso88591_encode(char *out, unsigned int unicode, int maxlen) +{ + static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if (unicode < 256) + { //iso8859-1 compatible chars + if (maxlen < 1) + return 0; + *out++ = unicode; + return 1; + } + else if (unicode > 0xffff) + { //chars longer than 16 bits + char *o = out; + if (maxlen < 11) + return 0; + *out++ = '^'; + *out++ = '{'; + if (unicode > 0xfffffff) + *out++ = hex[(unicode>>28)&15]; + if (unicode > 0xffffff) + *out++ = hex[(unicode>>24)&15]; + if (unicode > 0xfffff) + *out++ = hex[(unicode>>20)&15]; + if (unicode > 0xffff) + *out++ = hex[(unicode>>16)&15]; + if (unicode > 0xfff) + *out++ = hex[(unicode>>12)&15]; + if (unicode > 0xff) + *out++ = hex[(unicode>>8)&15]; + if (unicode > 0xf) + *out++ = hex[(unicode>>4)&15]; + if (unicode > 0x0) + *out++ = hex[(unicode>>0)&15]; + *out++ = '}'; + return out - o; + } + else + { //16bit chars + if (maxlen < 6) + return 0; + *out++ = '^'; + *out++ = 'U'; + *out++ = hex[(unicode>>12)&15]; + *out++ = hex[(unicode>>8)&15]; + *out++ = hex[(unicode>>4)&15]; + *out++ = hex[(unicode>>0)&15]; + return 6; + } +} + +unsigned int unicode_encode(char *out, unsigned int unicode, int maxlen) +{ + if (com_parseutf8.ival > 0) + return utf8_encode(out, unicode, maxlen); + else if (com_parseutf8.ival) + return iso88591_encode(out, unicode, maxlen); + else + return qchar_encode(out, unicode, maxlen); +} ///===================================== @@ -2291,61 +2400,11 @@ char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, q if (ignoreflags && (*str & CON_HIDDEN)) continue; - c = *str++ & 0xffff; - if (com_parseutf8.ival > 0) - { - c = utf8_encode(out, c, outsize); - if (!c) - break; - outsize -= c; - out += c; - } - else if (com_parseutf8.ival) - { - //iso8859-1 - if ((c >= 0 && c < 255) || (c >= 0xe000+32 && c < 0xe000+127)) //quake chars between 32 and 127 are identical to iso8859-1 - { - if (!--outsize) - break; - *out++ = (unsigned char)(c&255); - } - else //any other (quake?) char is not iso8859-1 - { - const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - if (outsize<=6) - break; - outsize -= 6; - *out++ = '^'; - *out++ = 'U'; - *out++ = hex[(c>>12)&15]; - *out++ = hex[(c>>8)&15]; - *out++ = hex[(c>>4)&15]; - *out++ = hex[(c>>0)&15]; - } - } - else - { - //quake chars - if (c == '\n' || c == '\r' || c == '\t' || (c >= 32 && c < 127) || (c >= 0xe000 && c < 0xe100)) //quake chars between 32 and 127 are identical to iso8859-1 - { - if (!--outsize) - break; - *out++ = (unsigned char)(c&255); - } - else //any other char is not quake - { - const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - if (outsize<=6) - break; - outsize -= 6; - *out++ = '^'; - *out++ = 'U'; - *out++ = hex[(c>>12)&15]; - *out++ = hex[(c>>8)&15]; - *out++ = hex[(c>>4)&15]; - *out++ = hex[(c>>0)&15]; - } - } + c = unicode_encode(out, (*str++ & CON_CHARMASK), outsize-1); + if (!c) + break; + outsize -= c; + out += c; } *out = 0; } @@ -2364,18 +2423,22 @@ static int dehex(int i) //Takes a q3-style fun string, and returns an expanded string-with-flags (actual return value is the null terminator) //outsize parameter is in _BYTES_ (so sizeof is safe). -conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, qboolean keepmarkup) +conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int flags) { conchar_t extstack[4]; int extstackdepth = 0; unsigned int uc; int utf8 = com_parseutf8.ival; conchar_t linkinitflags = CON_WHITEMASK;/*doesn't need the init, but msvc is stupid*/ + qboolean keepmarkup = flags & PFS_KEEPMARKUP; qboolean linkkeep = keepmarkup; conchar_t *linkstart = NULL; conchar_t ext; + if (flags & PFS_FORCEUTF8) + utf8 = 2; + outsize /= sizeof(conchar_t); if (!outsize) return out; @@ -2392,10 +2455,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t if (*str == 1 || *str == 2) { - if (com_parseutf8.ival) - defaultflags = (defaultflags&~CON_FGMASK) | ((com_highlightcolor.ival&15)< 0xffff) + if (uc > CON_CHARMASK) uc = 0xfffd; if (!--outsize) break; @@ -2514,21 +2574,9 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t ext = defaultflags; } else if (str[1] == 'm') - { - if (com_parseutf8.ival) - { - if ((ext & CON_FGMASK) != (COLOR_MAGENTA<= '0' && str[len] <= '9') || (str[len] >= 'a' && str[len] <= 'f') || (str[len] >= 'A' && str[len] <= 'F'); len++) + { + uc <<= 4; + uc |= dehex(str[len]); + } + + //and eat the close too. oh god I hope its there. + if (str[len] == '}') + len++; + + if (uc > CON_CHARMASK) + uc = 0xfffd; + + if (!--outsize) + break; + *out++ = uc | ext; + str += len; + + continue; + } + } else if (str[1] == '^') { if (keepmarkup) { if (!--outsize) break; - if (com_parseutf8.ival) - *out++ = (unsigned char)(*str) | ext; - else - *out++ = (unsigned char)(*str) | ext | 0xe000; + *out++ = (unsigned char)(*str) | ext; } str++; @@ -2647,16 +2719,19 @@ messedup: break; uc = (unsigned char)(*str++); if (utf8) + { + //utf8/iso8859-1 has it easy. *out++ = uc | ext; + } else { if (uc == '\n' || uc == '\r' || uc == '\t' || uc == ' ') - *out++ = uc | (ext&~CON_HIGHCHARSMASK); - else if (uc >= 32 && uc < 127 && !(ext&CON_HIGHCHARSMASK)) *out++ = uc | ext; - else if (uc >= 0x80+32 && uc < 0x80+127) - *out++ = (uc&127) | ext ^ CON_2NDCHARSETTEXT; - else + else if (uc >= 32 && uc < 127) + *out++ = uc | ext; + else if (uc >= 0x80+32 && uc <= 0xff) //anything using high chars is ascii, with the second charset + *out++ = ((uc&127) | ext) | CON_2NDCHARSETTEXT; + else //(other) control chars are regular printables in quake, and are not ascii. These ALWAYS use the bitmap/fallback font. *out++ = uc | ext | 0xe000; } } diff --git a/engine/common/common.h b/engine/common/common.h index 66a040448..b849455fb 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -292,9 +292,13 @@ void COM_ParsePlusSets (void); typedef unsigned int conchar_t; char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags); -conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, qboolean keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator +#define PFS_KEEPMARKUP 1 +#define PFS_FORCEUTF8 2 +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_encode(void *out, unsigned int unicode, int maxlen); +unsigned int iso88591_encode(char *out, unsigned int unicode, int maxlen); +unsigned int qchar_encode(char *out, unsigned int unicode, int maxlen); char *COM_SkipPath (const char *pathname); void COM_StripExtension (const char *in, char *out, int outlen); diff --git a/engine/common/console.h b/engine/common/console.h index 249299b2c..2b860a554 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -39,7 +39,7 @@ extern conchar_t q3codemasks[MAXQ3COLOURS]; #define CON_BLINKTEXT 0x00040000 #define CON_2NDCHARSETTEXT 0x00020000 #define CON_RICHFORECOLOUR 0x00010000 // -#define CON_HIGHCHARSMASK 0x00000080 // Quake's alternative mask +//#define CON_HIGHCHARSMASK 0x00000080 // Quake's alternative mask #define CON_FLAGSMASK 0xFFFF0000 #define CON_CHARMASK 0x0000FFFF diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 0f4aa818c..e3fed48a6 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -3945,7 +3945,18 @@ int TCP_OpenStream (netadr_t remoteaddr) if (connect(newsocket, (struct sockaddr *)&qs, temp) == INVALID_SOCKET) { - Con_Printf ("TCP_OpenStream: connect: error %i\n", qerrno); + int err = qerrno; + if (err == EADDRNOTAVAIL) + { + char buf[128]; + NET_AdrToString(buf, sizeof(buf), remoteaddr); + if (remoteaddr.port == 0 && (remoteaddr.type == NA_IP || remoteaddr.type == NA_IPV6)) + Con_Printf ("TCP_OpenStream: no port specified\n"); + else + Con_Printf ("TCP_OpenStream: invalid address trying to connect to %s\n", buf); + } + else + Con_Printf ("TCP_OpenStream: connect: error %i\n", err); closesocket(newsocket); return INVALID_SOCKET; } diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 54baf5326..993fd7c58 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -3994,7 +3994,7 @@ void PR_AutoCvar(pubprogfuncs_t *prinst, cvar_t *var) } } -void PDECL PR_FoundPrefixedGlobals(pubprogfuncs_t *progfuncs, char *name, eval_t *val, etype_t type) +void PDECL PR_FoundAutoCvarGlobal(pubprogfuncs_t *progfuncs, char *name, eval_t *val, etype_t type) { cvar_t *var; char *vals; @@ -4009,13 +4009,13 @@ void PDECL PR_FoundPrefixedGlobals(pubprogfuncs_t *progfuncs, char *name, eval_t if(nlen >= 2 && name[nlen-2] == '_' && (name[nlen-1] == 'x' || name[nlen-1] == 'y' || name[nlen-1] == 'z')) return; - vals = va("%f", val->_float); + vals = va("%g", val->_float); break; case ev_integer: vals = va("%i", val->_int); break; case ev_vector: - vals = va("%f %f %f", val->_vector[0], val->_vector[1], val->_vector[2]); + vals = va("%g %g %g", val->_vector[0], val->_vector[1], val->_vector[2]); break; case ev_string: vals = PR_GetString(progfuncs, val->string); @@ -4035,7 +4035,7 @@ void PDECL PR_FoundPrefixedGlobals(pubprogfuncs_t *progfuncs, char *name, eval_t void PR_AutoCvarSetup(pubprogfuncs_t *prinst) { - prinst->FindPrefixGlobals (prinst, "autocvar_", PR_FoundPrefixedGlobals); + prinst->FindPrefixGlobals (prinst, "autocvar_", PR_FoundAutoCvarGlobal); } lh_extension_t QSG_Extensions[] = { diff --git a/engine/common/protocol.h b/engine/common/protocol.h index ab146a282..a4612c489 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -369,9 +369,16 @@ enum clcq2_ops_e #define clc_prydoncursor 82 #define clc_voicechat 83 - //============================================== +//these flags are sent as part of the svc_precache index, for any-time precaches. using the upper two bits means we still have 16k available models/sounds/etc +#define PC_TYPE 0xc000 +#define PC_MODEL 0x0000 +#define PC_SOUND 0x8000 +#define PC_PARTICLE 0x4000 +#define PC_UNUSED 0xc000 + + // playerinfo flags from server // playerinfo always sends: playernum, flags, origin[] and framenumber diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index efaa9b400..9c9b538e4 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -231,7 +231,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e bc = e->bottomcolour; pc = e->h2playerclass; - if (forced || tc != 1 || bc != 1 || plskin) + if (forced || tc != TOP_DEFAULT || bc != BOTTOM_DEFAULT || plskin) { int inwidth, inheight; int tinwidth, tinheight; @@ -532,10 +532,15 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e frac += fracstep; } } - cm->texnum.base = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, IF_NOMIPMAP); + cm->texnum.base = R_LoadTexture(va("base$%x$%x$%i$%i$%i$%s", tc, bc, cm->skinnum, subframe, pc, cm->name), + scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, IF_NOMIPMAP); - if (!h2playertranslations) + cm->texnum.bump = shader->defaulttextures.bump; + cm->texnum.fullbright = shader->defaulttextures.fullbright; + cm->texnum.specular = shader->defaulttextures.specular; + /*if (!h2playertranslations) { + qboolean valid = false; //now do the fullbrights. out = pixels; fracstep = tinwidth*0x10000/scaled_width; @@ -547,11 +552,15 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e { if (inrow[frac>>16] < 255-vid.fullbright) ((char *) (&out[j]))[3] = 0; //alpha 0 + else + valid = true; frac += fracstep; } } - cm->texnum.fullbright = R_LoadTexture(cm->name, scaled_width, scaled_height, h2playertranslations?TF_RGBA32:TF_RGBX32, pixels, IF_NOMIPMAP); - } + if (valid) + cm->texnum.fullbright = R_LoadTexture(va("fb$%x$%x$%i$%i$%i$%s", tc, bc, cm->skinnum, subframe, pc, cm->name), + scaled_width, scaled_height, TF_RGBA32, pixels, IF_NOMIPMAP); + }*/ } else { diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 8df0aaa52..18bf318dc 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -381,18 +381,6 @@ void Font_FlushPlane(font_t *f) fontplanes.newestchar = NULL; } -//obtains a cached char, null if not cached -static struct charcache_s *Font_GetChar(font_t *f, CHARIDXTYPE charidx) -{ - struct charcache_s *c = &f->chars[charidx]; - if (c->texplane == INVALIDPLANE) - { - //not cached, can't get. - return NULL; - } - return c; -} - //loads a new image into a given character slot for the given font. //note: make sure it doesn't already exist or things will get cyclic //alphaonly says if its a greyscale image. false means rgba. @@ -607,6 +595,33 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) return NULL; } +//obtains a cached char, null if not cached +static struct charcache_s *Font_GetChar(font_t *f, CHARIDXTYPE charidx) +{ + struct charcache_s *c = &f->chars[charidx]; + if (c->texplane == INVALIDPLANE) + { + //not cached, can't get. + c = Font_TryLoadGlyph(f, charidx); + + if (!c) + { + charidx = 0xfffd; //unicode's replacement char + c = &f->chars[charidx]; + if (c->texplane == INVALIDPLANE) + c = Font_TryLoadGlyph(f, charidx); + } + if (!c) + { + charidx = '?'; //meh + c = &f->chars[charidx]; + if (c->texplane == INVALIDPLANE) + c = Font_TryLoadGlyph(f, charidx); + } + } + return c; +} + qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename) { #ifdef AVAIL_FREETYPE @@ -695,9 +710,9 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename) } if (*fontdir) { - error = pFT_New_Face(fontlib, va("%s/%s.ttf", fontdir, fontfilename), 0, &face); + error = pFT_New_Face(fontlib, va("%s/%s", fontdir, fontfilename), 0, &face); if (error) - error = pFT_New_Face(fontlib, va("%s/%s", fontdir, fontfilename), 0, &face); + error = pFT_New_Face(fontlib, va("%s/%s.ttf", fontdir, fontfilename), 0, &face); } } #endif @@ -1073,11 +1088,16 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) } if (!Font_LoadFreeTypeFont(f, height, fontfilename)) { + //default to only map the ascii-compatible chars from the quake font. if (*fontfilename) f->singletexture = R_LoadHiResTexture(fontfilename, "fonts", IF_2D|IF_NOMIPMAP); + for ( ; i < 32; i++) + { + f->chars[i].texplane = INVALIDPLANE; + } /*force it to load, even if there's nothing there*/ - for (; i < 256; i++) + for ( ; i < 128; i++) { f->chars[i].advance = f->charheight; f->chars[i].bmh = PLANEWIDTH/16; @@ -1233,20 +1253,13 @@ int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode) if ((charcode&CON_CHARMASK) == '\t') return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH); - if (charcode & CON_2NDCHARSETTEXT) - { - if (font->alt) - font = font->alt; - else if ((charcode & CON_CHARMASK) >= 0x20 && (charcode&CON_CHARMASK) < 0x80) - charcode |= 0xe000; - } + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) { - c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); - if (!c) - return x+0; + return x+0; } return x+c->advance; @@ -1259,20 +1272,13 @@ int Font_CharWidth(unsigned int charcode) struct font_s *font = curfont; if (charcode&CON_HIDDEN) return 0; - if (charcode & CON_2NDCHARSETTEXT) - { - if (font->alt) - font = font->alt; - else if ((charcode & CON_CHARMASK) >= 0x20 && (charcode&CON_CHARMASK) < 0x80) - charcode |= 0xe000; - } + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) + font = font->alt; c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) { - c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); - if (!c) - return 0; + return 0; } return c->advance; @@ -1396,19 +1402,18 @@ int Font_DrawChar(int px, int py, unsigned int charcode) if (charcode & CON_2NDCHARSETTEXT) { if (font->alt) + { font = font->alt; - else if ((charcode & CON_CHARMASK) >= 0x20 && (charcode&CON_CHARMASK) < 0x80) - charcode |= 0xe000; + charcode &= ~CON_2NDCHARSETTEXT; + } + else if ((charcode&CON_CHARMASK) >= 0xe000 && (charcode&CON_CHARMASK) <= 0xe0ff) + charcode &= ~CON_2NDCHARSETTEXT; //don't double-dip } //crash if there is no current font. c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) - { - c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); - if (!c) - return px; - } + return px; nextx = px + c->advance; @@ -1426,7 +1431,7 @@ int Font_DrawChar(int px, int py, unsigned int charcode) if (charcode & CON_RICHFORECOLOUR) { - col = charcode & (CON_RICHFORECOLOUR|(0xfff<alt) + { font = font->alt; - else if ((charcode & CON_CHARMASK) >= 0x20 && (charcode&CON_CHARMASK) < 0x80) - charcode |= 0xe000; + charcode &= ~CON_2NDCHARSETTEXT; + } + else if ((charcode&CON_CHARMASK) >= 0xe000 && (charcode&CON_CHARMASK) <= 0xe0ff) + charcode &= ~CON_2NDCHARSETTEXT; //don't double-dip } cw = curfont_scale[0]; @@ -1564,11 +1586,7 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) //crash if there is no current font. c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if (!c) - { - c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK)); - if (!c) - return px; - } + return px; nextx = px + c->advance*cw; @@ -1584,7 +1602,7 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) if (charcode & CON_RICHFORECOLOUR) { - col = charcode & (CON_RICHFORECOLOUR|(0xfff<arraysize*array->type->size; numslots = (numslots+2)/3; + s_file = array->s_file; func = QCC_PR_GetDef(type_function, qcva("ArrayGetVec*%s", array->name), NULL, true, 0, false); pr_scope = func; @@ -8143,6 +8144,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, char *arrayname) else fasttrackpossible = NULL; + s_file = scope->s_file; def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0, false); if (def->type->type == ev_vector) @@ -8316,6 +8318,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, char *arrayname) else fasttrackpossible = NULL; + s_file = scope->s_file; def = QCC_PR_GetDef(NULL, arrayname, NULL, false, 0, false); pr_scope = scope; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 57f828fd2..22108eff3 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -73,6 +73,7 @@ cvar_t pr_maxedicts = CVARAFD("pr_maxedicts", "32768", "max_edicts", CVAR_LATCH, cvar_t pr_no_playerphysics = CVARFD("pr_no_playerphysics", "0", CVAR_LATCH, "Prevents support of the 'SV_PlayerPhysics' QC function. This allows servers to prevent needless breakage of player prediction."); cvar_t pr_no_parsecommand = CVARFD("pr_no_parsecommand", "0", 0, "Provides a way around invalid mod usage of SV_ParseClientCommand, eg xonotic."); +cvar_t pr_sourcedir = CVARD("pr_sourcedir", "src", "Subdirectory where your qc source is located. Used by the internal compiler and qc debugging functionality."); cvar_t pr_ssqc_progs = CVARAF("progs", "", "sv_progs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOTFROMSERVER); cvar_t qc_nonetaccess = CVAR("qc_nonetaccess", "0"); //prevent write_... builtins from doing anything. This means we can run any mod, specific to any engine, on the condition that it also has a qw or nq crc. cvar_t qc_netpreparse = CVAR("qc_netpreparse", "1"); //server-side writebyte protocol translation @@ -140,6 +141,7 @@ struct { func_t ClassChangeWeapon;//hexen2 support func_t AddDebugPolygons; + func_t CheckRejectConnection; } gfuncs; func_t SpectatorConnect; //QW func_t SpectatorThink; //QW @@ -446,7 +448,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, char *filename, int line, int statem f = NULL; //faster. if (!f) { - Q_snprintfz(buffer, sizeof(buffer), "src/%s", filename); + Q_snprintfz(buffer, sizeof(buffer), "%s/%s", pr_sourcedir.string, filename); f = FS_OpenVFS(buffer, "rb", FS_GAME); } if (!f) @@ -797,6 +799,7 @@ void PR_LoadGlabalStruct(void) gfuncs.ClassChangeWeapon = PR_FindFunction(svprogfuncs, "ClassChangeWeapon", PR_ANY); gfuncs.RunClientCommand = PR_FindFunction(svprogfuncs, "SV_RunClientCommand", PR_ANY); gfuncs.AddDebugPolygons = PR_FindFunction(svprogfuncs, "SV_AddDebugPolygons", PR_ANY); + gfuncs.CheckRejectConnection = PR_FindFunction(svprogfuncs, "SV_CheckRejectConnection", PR_ANY); if (pr_no_playerphysics.ival) SV_PlayerPhysicsQC = 0; @@ -1025,7 +1028,7 @@ void PR_Compile_f(void) { int argc=3; double time = Sys_DoubleTime(); - char *argv[64] = {"", "-src", "src", "-srcfile", "progs.src"}; + char *argv[64] = {"", "-src", pr_sourcedir.string, "-srcfile", "progs.src"}; if (Cmd_Argc()>2) { @@ -1235,6 +1238,7 @@ void PR_Init(void) Cvar_Register(&pr_imitatemvdsv, cvargroup_progs); Cvar_Register(&pr_fixbrokenqccarrays, cvargroup_progs); + Cvar_Register(&pr_sourcedir, cvargroup_progs); Cvar_Register(&pr_maxedicts, cvargroup_progs); Cvar_Register(&pr_no_playerphysics, cvargroup_progs); Cvar_Register(&pr_no_parsecommand, cvargroup_progs); @@ -3639,13 +3643,67 @@ void PR_CheckEmptyString (char *s) PR_RunError ("Bad string"); } */ + +//float(string effectname) particleeffectnum (EXT_CSQC) +static void QCBUILTIN PF_sv_particleeffectnum(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + char *s = PR_GetStringOfs(prinst, OFS_PARM0); +/* +#ifdef PEXT_CSQC +#ifdef warningmsg +#pragma warningmsg("PF_sv_particleeffectnum: which effect index values to use?") +#endif + char *efname = PR_GetStringOfs(prinst, OFS_PARM0); + G_FLOAT(OFS_RETURN) = COM_Effectinfo_ForName(efname); +#else + G_FLOAT(OFS_RETURN) = -1; +#endif +*/ + int i; + + if (s[0] <= ' ') + { + PR_BIError (prinst, "PF_precache_particles: Bad string"); + return; + } + + G_FLOAT(OFS_RETURN) = 0; + + for (i=1 ; iself = EDICT_TO_PROG(svprogfuncs, sv.world.edicts); + G_INT(OFS_PARM0) = (int)PR_TempString(svprogfuncs, addrstr); + G_INT(OFS_PARM1) = (int)PR_TempString(svprogfuncs, uinfo); + G_INT(OFS_PARM2) = (int)PR_TempString(svprogfuncs, clfeatures); + PR_ExecuteProgram (svprogfuncs, gfuncs.CheckRejectConnection); + ret = PR_GetStringOfs(svprogfuncs, OFS_RETURN); + if (!*ret) + ret = NULL; + } + return ret; +} void SV_AddDebugPolygons(void) { int i; @@ -7381,19 +7537,6 @@ static void QCBUILTIN PF_CustomTEnt(pubprogfuncs_t *prinst, struct globalvars_s SV_MulticastProtExt (org, mcd, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will. } -//float(string effectname) particleeffectnum (EXT_CSQC) -static void QCBUILTIN PF_sv_particleeffectnum(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ -#ifdef PEXT_CSQC -#ifdef warningmsg -#pragma warningmsg("PF_sv_particleeffectnum: which effect index values to use?") -#endif - char *efname = PR_GetStringOfs(prinst, OFS_PARM0); - G_FLOAT(OFS_RETURN) = COM_Effectinfo_ForName(efname); -#else - G_FLOAT(OFS_RETURN) = -1; -#endif -} //void(float effectnum, entity ent, vector start, vector end) trailparticles (EXT_CSQC), static void QCBUILTIN PF_sv_trailparticles(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -7444,13 +7587,13 @@ static void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct global #ifdef PEXT_CSQC int efnum = G_FLOAT(OFS_PARM0); float *org = G_VECTOR(OFS_PARM1); - float *vel = G_VECTOR(OFS_PARM2); - int count = G_FLOAT(OFS_PARM3); + float *vel = (prinst->callargc < 3)?vec3_origin:G_VECTOR(OFS_PARM2); + int count = (prinst->callargc < 4)?1:G_FLOAT(OFS_PARM3); if (count > 65535) count = 65535; - if (count == 1 && DotProduct(org, org) == 0) + if (count == 1 && DotProduct(vel, vel) == 0) { MSG_WriteByte(&sv.multicast, svcfte_pointparticles1); MSG_WriteShort(&sv.multicast, efnum); @@ -9221,7 +9364,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"drawline", PF_Fixme, 0, 0, 0, 315, "void(float width, vector pos1, vector pos2)"},// (EXT_CSQC) {"iscachedpic", PF_Fixme, 0, 0, 0, 316, "float(string name)"},// (EXT_CSQC) {"precache_pic", PF_Fixme, 0, 0, 0, 317, "string(string name, optional float trywad)"},// (EXT_CSQC) - {"draw_getimagesize",PF_Fixme, 0, 0, 0, 318, "vector(string picname)"},// (EXT_CSQC) + {"drawgetimagesize",PF_Fixme, 0, 0, 0, 318, "#define draw_getimagesize drawgetimagesize\nvector(string picname)"},// (EXT_CSQC) {"freepic", PF_Fixme, 0, 0, 0, 319, "void(string name)"},// (EXT_CSQC) //320 {"drawcharacter", PF_Fixme, 0, 0, 0, 320, "float(vector position, float character, vector scale, vector rgb, float alpha, optional float flag)"},// (EXT_CSQC, [EXT_CSQC_???]) @@ -10074,7 +10217,7 @@ void PR_DumpPlatform_f(void) {"SpectatorConnect", "noref void()", QW|NQ}, {"SpectatorDisconnect", "noref void()", QW|NQ}, {"SpectatorThink", "noref void()", QW|NQ}, - {"SV_ParseClientCommand", "noref void()", QW|NQ}, + {"SV_ParseClientCommand", "noref void(string cmd)", QW|NQ}, {"SV_ParseConnectionlessPacket", "noref void()", QW|NQ}, {"SV_PausedTic", "noref void()", QW|NQ}, {"SV_ShouldPause", "noref void()", QW|NQ}, @@ -10083,6 +10226,7 @@ void PR_DumpPlatform_f(void) {"SV_AddDebugPolygons", "noref void()", QW|NQ}, {"SV_PlayerPhysics", "noref void()", QW|NQ}, {"EndFrame", "noref void()", QW|NQ}, + {"SV_CheckRejectConnection","noref string(string addr, string uinfo, string features) ", QW|NQ}, /* //mvdsv compat {"UserInfo_Changed", "//noref void()", QW}, {"localinfoChanged", "//noref void()", QW}, @@ -10247,17 +10391,28 @@ void PR_DumpPlatform_f(void) {"MOVE_LAGGED", "const float", QW|NQ, MOVE_LAGGED}, {"MOVE_ENTCHAIN", "const float", QW|NQ|CS, MOVE_ENTCHAIN}, - {"EF_BRIGHTFIELD", "const float", QW|NQ|CS, EF_BRIGHTFIELD}, - {"EF_MUZZLEFLASH", "const float", NQ|CS, EF_MUZZLEFLASH}, - {"EF_BRIGHTLIGHT", "const float", QW|NQ|CS, EF_BRIGHTLIGHT}, - {"EF_DIMLIGHT", "const float", QW|NQ|CS, EF_DIMLIGHT}, - {"EF_FLAG1", "const float", QW , QWEF_FLAG1}, - {"EF_FLAG2", "const float", QW , QWEF_FLAG2}, - {"EF_ADDITIVE", "const float", NQ|CS, NQEF_ADDITIVE}, - {"EF_BLUE", "const float", QW|NQ|CS, EF_BLUE}, - {"EF_RED", "const float", QW|NQ|CS, EF_RED}, - {"EF_FULLBRIGHT", "const float", QW|NQ|CS, EF_FULLBRIGHT}, - {"EF_NODEPTHTEST", "const float", QW|NQ|CS, EF_NODEPTHTEST}, + {"EF_BRIGHTFIELD", "const float", QW|NQ|CS, EF_BRIGHTFIELD}, + {"EF_MUZZLEFLASH", "const float", NQ|CS, EF_MUZZLEFLASH}, + {"EF_BRIGHTLIGHT", "const float", QW|NQ|CS, EF_BRIGHTLIGHT}, + {"EF_DIMLIGHT", "const float", QW|NQ|CS, EF_DIMLIGHT}, + {"EF_FLAG1", "const float", QW , QWEF_FLAG1}, + {"EF_FLAG2", "const float", QW , QWEF_FLAG2}, + {"EF_ADDITIVE", "const float", NQ|CS, NQEF_ADDITIVE}, + {"EF_BLUE", "const float", QW|NQ|CS, EF_BLUE}, + {"EF_RED", "const float", QW|NQ|CS, EF_RED}, + {"EF_FULLBRIGHT", "const float", QW|NQ|CS, EF_FULLBRIGHT}, + {"EF_NODEPTHTEST", "const float", QW|NQ|CS, EF_NODEPTHTEST}, + + {"EF_NOMODELFLAGS", "const float", QW|NQ, EF_NOMODELFLAGS}, + + {"MF_ROCKET", "const float", QW|NQ, EF_MF_ROCKET>>24}, + {"MF_GRENADE", "const float", QW|NQ, EF_MF_GRENADE>>24}, + {"MF_GIB", "const float", QW|NQ, EF_MF_GIB>>24}, + {"MF_ROTATE", "const float", QW|NQ, EF_MF_ROTATE>>24}, + {"MF_TRACER", "const float", QW|NQ, EF_MF_TRACER>>24}, + {"MF_ZOMGIB", "const float", QW|NQ, EF_MF_ZOMGIB>>24}, + {"MF_TRACER2", "const float", QW|NQ, EF_MF_TRACER2>>24}, + {"MF_TRACER3", "const float", QW|NQ, EF_MF_TRACER3>>24}, {"STAT_HEALTH", "const float", CS, STAT_HEALTH}, {"STAT_WEAPON", "const float", CS, STAT_WEAPON}, @@ -10431,7 +10586,7 @@ void PR_DumpPlatform_f(void) if (!*fname) fname = "fteextensions"; - fname = va("src/%s.qc", fname); + fname = va("%s/%s.qc", pr_sourcedir.string, fname); FS_NativePath(fname, FS_GAMEONLY, dbgfname, sizeof(dbgfname)); FS_CreatePath(fname, FS_GAMEONLY); f = FS_OpenVFS(fname, "wb", FS_GAMEONLY); diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index 29326c5e8..e515f1671 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -191,7 +191,7 @@ typedef enum GAME_EDICT_BLOCKED, //(self,other) GAME_CLIENT_SAY, //(int isteam) GAME_PAUSED_TIC, //(int milliseconds) -} gameExport_t; +} q1qvmgameExport_t; typedef enum diff --git a/engine/server/q3g_public.h b/engine/server/q3g_public.h index 2eefe82d8..78f19e4f4 100644 --- a/engine/server/q3g_public.h +++ b/engine/server/q3g_public.h @@ -402,7 +402,7 @@ typedef enum { BOTLIB_PC_READ_TOKEN, BOTLIB_PC_SOURCE_FILE_AND_LINE -} gameImport_t; +} q3ggameImport_t; // diff --git a/engine/server/server.h b/engine/server/server.h index c5c14df23..81525c510 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -133,6 +133,7 @@ typedef struct struct { char *vw_model_precache[32]; char *model_precache[MAX_MODELS]; // NULL terminated + char particle_precache[MAX_SSPARTICLESPRE][MAX_QPATH]; // NULL terminated char sound_precache[MAX_SOUNDS][MAX_QPATH]; // NULL terminated char *lightstyles[MAX_LIGHTSTYLES]; char lightstylecolours[MAX_LIGHTSTYLES]; @@ -339,6 +340,7 @@ enum PRESPAWN_SOUNDLIST, //nq skips these PRESPAWN_MODELLIST, PRESPAWN_MAPCHECK, //wait for old prespawn command + PRESPAWN_PARTICLES, PRESPAWN_CUSTOMTENTS, PRESPAWN_SIGNON_BUF, PRESPAWN_SPAWNSTATIC, @@ -679,7 +681,6 @@ typedef struct qboolean fixangle[MAX_CLIENTS]; float fixangletime[MAX_CLIENTS]; vec3_t angles[MAX_CLIENTS]; - char name[MAX_OSPATH], path[MAX_OSPATH]; int parsecount; int lastwritten; demo_frame_t frames[DEMO_FRAMES]; @@ -925,6 +926,7 @@ extern vfsfile_t *sv_fraglogfile; //=========================================================== void SV_AddDebugPolygons(void); +char *SV_CheckRejectConnection(netadr_t adr, char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, char *guid); // // sv_main.c diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index d8e6ff4ea..df7f32e28 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -467,7 +467,7 @@ void SV_CSQC_DropAll(client_t *client) if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) { - Con_Printf("Reset all\n"); +// Con_Printf("Reset all\n"); client->pendingentbits[0] = UF_REMOVE; } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 927fcb3a2..71416f72a 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -2391,6 +2391,15 @@ client_t *SVC_DirectConnect(void) #endif temp.edict = ent; + { + char *reject = SV_CheckRejectConnection(adr, userinfo[0], protocol, protextsupported, protextsupported2, guid); + if (reject) + { + SV_RejectMessage(protocol, "%s", reject); + return NULL; + } + } + break; #ifdef Q2SERVER @@ -3116,10 +3125,10 @@ void SVNQ_ConnectionlessPacket(void) continue; case clc_stringcmd: numnonnops++; - Cmd_TokenizeString(MSG_ReadString(), false, false); - if (!strcmp("challengeconnect", Cmd_Argv(0))) + if (msg_readcount+17 <= net_message.cursize && !strncmp("challengeconnect ", &net_message.data[msg_readcount], 17)) { client_t *newcl; + Cmd_TokenizeString(MSG_ReadStringLine(), false, false); /*okay, so this is a reliable packet from a client, containing a 'cmd challengeconnect $challenge' response*/ str = va("connect %i %i %s \"\\name\\unconnected\\mod\\%s\\modver\\%s\\flags\\%s\\password\\%s\"", NET_PROTOCOL_VERSION, 0, Cmd_Argv(1), Cmd_Argv(2), Cmd_Argv(3), Cmd_Argv(4), Cmd_Argv(5)); Cmd_TokenizeString (str, false, false); @@ -3131,6 +3140,8 @@ void SVNQ_ConnectionlessPacket(void) /*if there is anything else in the packet, we don't actually care. its reliable, so they'll resend*/ return; } + else + MSG_ReadString(); continue; case -1: break; diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 26f60c186..e419ed0d0 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -70,9 +70,6 @@ int demomsgtype; int demomsgto; static char demomsgbuf[MAX_OVERALLMSGLEN]; -entity_state_t demo_entities[UPDATE_MASK+1][MAX_MVDPACKET_ENTITIES]; -client_frame_t demo_frames[UPDATE_MASK+1]; - mvddest_t *singledest; mvddest_t *SV_InitStream(int socket); @@ -80,6 +77,7 @@ static qboolean SV_MVD_Record (mvddest_t *dest); char *SV_MVDName2Txt(char *name); extern cvar_t qtv_password; +//does not unlink. void DestClose(mvddest_t *d, qboolean destroyfiles) { char path[MAX_OSPATH]; @@ -337,6 +335,8 @@ void SV_MVD_RunPendingConnections(void) //COMPRESSION: Suggests a compression method (multiple are allowed). You'll get a COMPRESSION response, and compression will begin with the binary data. start = start+1; + while(*start == ' ' || *start == '\t') + start++; Con_Printf("qtv, got (%s) (%s)\n", com_token, start); if (!strcmp(com_token, "VERSION")) { @@ -1292,6 +1292,25 @@ static char *SV_PrintTeams(void) return va("%s",buf); } + +mvddest_t *SV_FindRecordFile(char *match, mvddest_t ***link_out) +{ + mvddest_t **link, *f; + for (link = &demo.dest; *link; link = &(*link)->nextdest) + { + f = *link; + if (f->desttype == DEST_FILE || f->desttype == DEST_BUFFEREDFILE) + { + if (!match || !strcmp(match, f->name)) + { + if (link_out) + *link_out = link; + return f; + } + } + } + return NULL; +} /* ==================== SV_InitRecord @@ -1338,8 +1357,8 @@ mvddest_t *SV_InitRecordFile (char *name) Q_strncpyz(dst->name, s+1, sizeof(dst->name)); Q_strncpyz(dst->path, sv_demoDir.string, sizeof(dst->path)); - if (!*demo.path) - Q_strncpyz(demo.path, ".", MAX_OSPATH); + if (!*dst->path) + Q_strncpyz(dst->path, ".", MAX_OSPATH); SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording (%s):\n%s\n", (dst->desttype == DEST_BUFFEREDFILE) ? "memory" : "disk", name); Cvar_ForceSet(Cvar_Get("serverdemo", "", CVAR_NOSET, ""), SV_Demo_CurrentOutput()); @@ -1560,17 +1579,6 @@ void SV_WriteSetMVDMessage (void) void SV_MVD_SendInitialGamestate(mvddest_t *dest); static qboolean SV_MVD_Record (mvddest_t *dest) { -/* sizebuf_t buf; - char buf_data[MAX_QWMSGLEN]; - int n, i; - char *s, info[MAX_INFO_STRING]; - - client_t *player; - char *gamedir; - int seq = 1; -*/ - int i; - if (!dest) return false; @@ -1579,14 +1587,8 @@ static qboolean SV_MVD_Record (mvddest_t *dest) if (!sv.mvdrecording) { memset(&demo, 0, sizeof(demo)); - demo.recorder.frameunion.frames = demo_frames; demo.recorder.protocol = SCP_QUAKEWORLD; demo.recorder.netchan.netprim = sv.datagram.prim; - for (i = 0; i < UPDATE_BACKUP; i++) - { - demo.recorder.frameunion.frames[i].entities.max_entities = MAX_MVDPACKET_ENTITIES; - demo.recorder.frameunion.frames[i].entities.entities = demo_entities[i]; - } demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.data = demo.datagram_data; @@ -1604,7 +1606,7 @@ static qboolean SV_MVD_Record (mvddest_t *dest) else if (sv_demoExtensions.ival) { /*everything*/ demo.recorder.fteprotocolextensions = PEXT_CSQC | PEXT_COLOURMOD | PEXT_DPFLAGS | PEXT_CUSTOMTEMPEFFECTS | PEXT_ENTITYDBL | PEXT_ENTITYDBL2 | PEXT_FATNESS | PEXT_HEXEN2 | PEXT_HULLSIZE | PEXT_LIGHTSTYLECOL | PEXT_MODELDBL | PEXT_SCALE | PEXT_SETATTACHMENT | PEXT_SETVIEW | PEXT_SOUNDDBL | PEXT_SPAWNSTATIC2 | PEXT_TRANS | PEXT_VIEW2; - demo.recorder.fteprotocolextensions2 = PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_PRYDONCURSOR; + demo.recorder.fteprotocolextensions2 = PEXT2_VOICECHAT | PEXT2_SETANGLEDELTA | PEXT2_PRYDONCURSOR | PEXT2_REPLACEMENTDELTAS; /*assume that all playback will be done with a valid csprogs that can correctly decode*/ demo.recorder.csqcactive = true; /*enable these, because we might as well (stat ones are always useful)*/ @@ -1620,19 +1622,6 @@ static qboolean SV_MVD_Record (mvddest_t *dest) //pointless extensions that are redundant with mvds demo.recorder.fteprotocolextensions &= ~PEXT_ACCURATETIMINGS | PEXT_HLBSP|PEXT_Q2BSP|PEXT_Q3BSP; - demo.recorder.max_net_ents = 512; - if (demo.recorder.fteprotocolextensions & PEXT_ENTITYDBL) - demo.recorder.max_net_ents += 512; - if (demo.recorder.fteprotocolextensions & PEXT_ENTITYDBL2) - demo.recorder.max_net_ents += 1024; - - if (demo.recorder.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) - demo.recorder.max_net_ents = 32767; - - if (demo.recorder.fteprotocolextensions & PEXT_MODELDBL) - demo.recorder.maxmodels = MAX_MODELS; - else - demo.recorder.maxmodels = 256; } // else // SV_WriteRecordMVDMessage(&buf, dem_read); @@ -1640,9 +1629,12 @@ static qboolean SV_MVD_Record (mvddest_t *dest) dest->nextdest = demo.dest; demo.dest = dest; + SV_ClientProtocolExtensionsChanged(&demo.recorder); + SV_MVD_SendInitialGamestate(dest); return true; } +void SV_EnableClientsCSQC(void); void SV_MVD_SendInitialGamestate(mvddest_t *dest) { sizebuf_t buf; @@ -1658,6 +1650,10 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest) sv.mvdrecording = true; + host_client = &demo.recorder; + if (host_client->fteprotocolextensions & PEXT_CSQC) + SV_EnableClientsCSQC(); + demo.pingtime = demo.time = sv.time; @@ -1817,7 +1813,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest) if (demo.recorder.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) { MSG_WriteByte(&buf, svcfte_spawnbaseline2); - SVQW_WriteDelta(&from, state, &buf, true, demo.recorder.fteprotocolextensions); + SVFTE_EmitBaseline(state, true, &buf); } else if (!ent) { @@ -1917,7 +1913,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest) if (!sv.strings.lightstyles[i]) continue; #ifdef PEXT_LIGHTSTYLECOL - if ((demo.recorder.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && sv.strings.lightstylecolours[i]!=7) + if ((demo.recorder.fteprotocolextensions & PEXT_LIGHTSTYLECOL) && sv.strings.lightstylecolours[i]!=7 && sv.strings.lightstyles[i]) { MSG_WriteByte (&buf, svcfte_lightstylecol); MSG_WriteByte (&buf, (unsigned char)i); @@ -2588,6 +2584,7 @@ void SV_MVDRemove_f (void) char name[MAX_MVD_NAME], *ptr; char path[MAX_OSPATH]; int i; + mvddest_t *active; if (Cmd_Argc() != 2) { @@ -2610,7 +2607,8 @@ void SV_MVDRemove_f (void) { if (strstr(list->name, ptr)) { - if (sv.mvdrecording && !strcmp(list->name, demo.name)) + mvddest_t *active = SV_FindRecordFile(list->name, NULL); + if (active) SV_MVDStop_f(); // stop recording first; @@ -2643,7 +2641,8 @@ void SV_MVDRemove_f (void) snprintf(path, MAX_OSPATH, "%s/%s", sv_demoDir.string, name); - if (sv.mvdrecording && !strcmp(name, demo.name)) + active = SV_FindRecordFile(name, NULL); + if (active) SV_MVDStop_f(); if (FS_Remove(path, FS_GAMEONLY)) @@ -2680,7 +2679,8 @@ void SV_MVDRemoveNum_f (void) if (name != NULL) { - if (sv.mvdrecording && !strcmp(name, demo.name)) + mvddest_t *active = SV_FindRecordFile(name, NULL); + if (active) SV_MVDStop_f(); snprintf(path, MAX_OSPATH, "%s/%s", sv_demoDir.string, name); @@ -2710,13 +2710,14 @@ void SV_MVDInfoAdd_f (void) if (!strcmp(Cmd_Argv(1), "*")) { - if (!sv.mvdrecording) + mvddest_t *active = SV_FindRecordFile(NULL, NULL); + if (!active) { Con_Printf("Not recording demo!\n"); return; } - snprintf(path, MAX_OSPATH, "%s/%s", demo.path, SV_MVDName2Txt(demo.name)); + snprintf(path, MAX_OSPATH, "%s/%s", active->path, SV_MVDName2Txt(active->name)); } else { @@ -2761,13 +2762,14 @@ void SV_MVDInfoRemove_f (void) if (!strcmp(Cmd_Argv(1), "*")) { - if (!sv.mvdrecording) + mvddest_t *active = SV_FindRecordFile(NULL, NULL); + if (!active) { Con_Printf("Not recording demo!\n"); return; } - snprintf(path, MAX_OSPATH, "%s/%s", demo.path, SV_MVDName2Txt(demo.name)); + snprintf(path, MAX_OSPATH, "%s/%s", active->path, SV_MVDName2Txt(active->name)); } else { @@ -2802,13 +2804,14 @@ void SV_MVDInfo_f (void) if (!strcmp(Cmd_Argv(1), "*")) { - if (!sv.mvdrecording) + mvddest_t *active = SV_FindRecordFile(NULL, NULL); + if (!active) { Con_Printf("Not recording demo!\n"); return; } - snprintf(path, MAX_OSPATH, "%s/%s", demo.path, SV_MVDName2Txt(demo.name)); + snprintf(path, MAX_OSPATH, "%s/%s", active->path, SV_MVDName2Txt(active->name)); } else { diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index b12997691..f5ca0fa4e 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -2463,6 +2463,7 @@ void SV_SendClientMessages (void) #pragma optimize( "", on ) #endif +void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time); void DemoWriteQTVTimePad(int msecs); #define Max(a, b) ((a>b)?a:b) @@ -2618,29 +2619,34 @@ void SV_SendMVDMessage(void) if (!demo.recorder.delta_sequence) demo.recorder.delta_sequence = -1; - SV_WriteEntitiesToClient (&demo.recorder, &msg, true); - - dmsg = MVDWrite_Begin(dem_all, 0, msg.cursize); - SZ_Write (dmsg, msg.data, msg.cursize); // copy the accumulated multicast datagram // for this client out to the message - if (demo.datagram.cursize) + if (demo.datagram.cursize && sv.mvdrecording) { dmsg = MVDWrite_Begin(dem_all, 0, demo.datagram.cursize); SZ_Write (dmsg, demo.datagram.data, demo.datagram.cursize); SZ_Clear (&demo.datagram); } - demo.recorder.delta_sequence = demo.recorder.netchan.incoming_sequence&255; - demo.recorder.netchan.incoming_sequence++; - demo.frames[demo.parsecount&DEMO_FRAMES_MASK].time = demo.time = sv.time; - - if (demo.parsecount - demo.lastwritten > 60) // that's a backup of 3sec in 20fps, should be enough + while (demo.lastwritten < demo.parsecount-1 && sv.mvdrecording) { SV_MVDWritePackets(1); } + demo.recorder.delta_sequence = demo.recorder.netchan.incoming_sequence&255; + demo.recorder.netchan.incoming_sequence++; + demo.frames[demo.parsecount&DEMO_FRAMES_MASK].time = demo.time = sv.time; + + if (sv.mvdrecording) + { + SV_WriteEntitiesToClient (&demo.recorder, &msg, true); + SV_WriteMVDMessage(&msg, dem_all, 0, sv.time); +// dmsg = MVDWrite_Begin(dem_all, 0, msg.cursize); +// SZ_Write (dmsg, msg.data, msg.cursize); + } + demo.parsecount++; + // MVDSetMsgBuf(demo.dbuf,&demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf); } diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 8fd9ea7c8..328acffbd 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1092,6 +1092,27 @@ void SV_SendClientPrespawnInfo(client_t *client) return; } + if (client->prespawn_stage == PRESPAWN_PARTICLES) + { + while (client->netchan.message.cursize < (client->netchan.message.maxsize/2)) + { + if (client->prespawn_idx >= MAX_SSPARTICLESPRE) + { + client->prespawn_stage++; + client->prespawn_idx = 0; + break; + } + + if (*sv.strings.particle_precache[client->prespawn_idx]) + { + ClientReliableWrite_Begin (client, ISNQCLIENT(client)?svcdp_precache:svcfte_precache, 4 + strlen(sv.strings.particle_precache[client->prespawn_idx])); + ClientReliableWrite_Short (client, client->prespawn_idx | PC_PARTICLE); + ClientReliableWrite_String (client, sv.strings.particle_precache[client->prespawn_idx]); + } + client->prespawn_idx++; + } + } + if (client->prespawn_stage == PRESPAWN_CUSTOMTENTS) { while (client->netchan.message.cursize < (client->netchan.message.maxsize/2)) @@ -2482,7 +2503,7 @@ qboolean SV_AllowDownload (const char *name) name = cleanname; //allowed at all? - if (!allow_download.value) + if (!allow_download.ival) return false; //no subdirs? @@ -2499,11 +2520,11 @@ qboolean SV_AllowDownload (const char *name) { if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name))) { + if (!allow_download_packages.ival) + return false; /*do not permit 'id1/pak1.pak' or 'baseq3/pak0.pk3' or any similarly named packages. such packages would violate copyright, and must be obtained through other means (like buying the damn game)*/ if (FS_GetPackageDownloadable(name+8)) - return !!allow_download_packages.value; - else - return !!allow_download_copyrighted.ival; + return !!allow_download_packages.ival; } return false; } @@ -2579,7 +2600,10 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam if (!SV_AllowDownload(name)) + { + Sys_Printf ("%s denied download of %s due to path/name rules\n", host_client->name, name); return -2; //not permitted (even if it exists). + } //mvdsv demo downloading support demonum/ -> demos/XXXX (sets up the client paths) if (!strncmp(name, "demonum/", 8)) @@ -2662,7 +2686,10 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam if (protectedpak) { if (!allow_download_anymap.value && !strncmp(name, "maps/", 5)) + { + Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8); return -2; + } } if (replacementname) @@ -2685,7 +2712,10 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam if (protectedpak) { //if its in a pak file, don't allow downloads if we don't allow the contents of paks to be sent. if (!allow_download_pakcontents.value) + { + Sys_Printf ("%s denied download of %s - it is in a pak\n", host_client->name, name+8); return -2; + } } if (replacementname && *replacementname) diff --git a/fteqtv/dotnet2005/qtvprox.vcproj b/fteqtv/dotnet2005/qtvprox.vcproj index 652e5b6fb..03e798410 100644 --- a/fteqtv/dotnet2005/qtvprox.vcproj +++ b/fteqtv/dotnet2005/qtvprox.vcproj @@ -253,6 +253,26 @@ RelativePath="..\netchan.c" > + + + + + + + + diff --git a/plugins/berkelium/plugapi.cpp b/plugins/berkelium/plugapi.cpp index c4d7cc105..fb0482082 100644 --- a/plugins/berkelium/plugapi.cpp +++ b/plugins/berkelium/plugapi.cpp @@ -112,7 +112,7 @@ private: if (dy > 0) { //if we're moving downwards, we need to write the bottom before the top (so we don't overwrite the data before its copied) - for (y = h; y >= 0; y--) + for (y = h-1; y >= 0; y--) { memmove(ctx->buffer + (dl + (dt+y)*ctx->width), ctx->buffer + (sl + (st+y)*ctx->width), w*4); } @@ -244,7 +244,11 @@ static void Dec_GetSize (void *vctx, int *width, int *height) static qboolean Dec_SetSize (void *vctx, int width, int height) { decctx *ctx = (decctx*)vctx; - if (ctx->width == width || ctx->height == height) + if (width < 4) + width = 4; + if (height < 4) + height = 4; + if (ctx->width == width && ctx->height == height) return qtrue; //no point //there's no resize notification. apparently javascript cannot resize windows. yay.