diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index af31e3a5..50f9998e 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 2b5ed6a6..a2798b3a 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 3b34bd57..8708bc81 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 a303ca4b..c42d7c53 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 815341f2..51439d37 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 2e99d51a..a6fbe5cb 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 c95547a7..3f94a834 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 723c7dd7..46b3f7ca 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 3171a6b5..dd78a64e 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 b58e9768..faa05031 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 b10a1c12..9f822c1b 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 35742f35..5cbd3b49 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 c644f8af..359780e8 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 c2267aa9..82a7aa15 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 edc294cf..4b485872 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 5c1a18ea..d94b3535 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 0a43c11d..f115d5c4 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 0bc8274d..041dd179 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 66a04044..b849455f 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 249299b2..2b860a55 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 0f4aa818..e3fed48a 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 54baf532..993fd7c5 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 ab146a28..a4612c48 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 efaa9b40..9c9b538e 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 8df0aaa5..18bf318d 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 57f828fd..22108eff 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 29326c5e..e515f167 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 2eefe82d..78f19e4f 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 c5c14df2..81525c51 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 d8e6ff4e..df7f32e2 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 927fcb3a..71416f72 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 26f60c18..e419ed0d 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 b1299769..f5ca0fa4 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 8fd9ea7c..328acffb 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 652e5b6f..03e79841 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 c4d7cc10..fb048208 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.