Rewrote infostrings. Now using infobuffers, which allows for the use of arbitrary blobs, except not using the protocol extension yet in case it needs to be fixed.

Fix sound source issues in Q3.
Fix q2 air acceleration/prediction omission.
Don't change console completion while typing (while that option is still possible).
Shift+tab now cycles completion backwards (now ctrl+shift for cycle subconsoles).
Allow a few things to ignore sv_pure - including csprogs files (which is useful for all the mods that come with the csprogs.dat distributed separately).
clamp pitch values to the range documented by openal, to hopefully avoid error spam.
add some colour coding to the text editor when shader files are being edited/viewed.
Changed how overbrights are clamped on q3bsp.
Added portalfboscale for explicit texture scales on portal/refract/reflect fbos.
qc decompiler can now at least attempt to decompile qtest's qc.
fteqccgui can now be pointed at a .pak file, and decompile the progs.dat inside.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5269 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-07-05 16:21:44 +00:00
parent 34029c2434
commit d1d0d86fea
97 changed files with 4624 additions and 4539 deletions

View File

@ -100,6 +100,9 @@ ifneq (,$(findstring -Os,$(FTE_CONFIG_EXTRA)))
CPUOPTIMIZATIONS+=-Os
BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS))
endif
ifneq (,$(findstring DLINK_INTERNAL_BULLET,$(FTE_CONFIG_EXTRA)))
INTERNAL_BULLET=1 #bullet plugin will be built into the exe itself
endif
ifeq ($(BITS),64)
CC:=$(CC) -m64
@ -845,6 +848,9 @@ ifeq (1,$(USE_FREETYPE))
LIBFREETYPE_STATIC=-DFREETYPE_STATIC
LIBFREETYPE_LDFLAGS=-lfreetype
endif
ifeq (1,$(strip $(INTERNAL_BULLET)))
COMMON_OBJS+=com_phys_bullet.o
endif
COMMONLIBFLAGS=
CLIENTLIBFLAGS=$(COMMONLIBFLAGS) $(LIBOPUS_STATIC) $(LIBSPEEX_STATIC) $(OGGVORBISFILE_STATIC) $(LIBFREETYPE_STATIC)
@ -2171,3 +2177,4 @@ install: sv-rel gl-rel mingl-rel qcc-rel
$(INSTALL_PROGRAM) $(RELEASE_DIR)/$(EXE_NAME)-mingl $(DESTDIR)$(bindir)/$(EXE_NAME)-mingl
$(INSTALL_PROGRAM) $(RELEASE_DIR)/$(EXE_NAME)-sv $(DESTDIR)$(bindir)/$(EXE_NAME)-sv
$(INSTALL_PROGRAM) $(RELEASE_DIR)/fteqcc $(DESTDIR)$(bindir)/fteqcc

View File

@ -111,7 +111,7 @@ typedef struct {
const char *engine_version;
int (*checkextension) (const char *ext);
void (*error) (const char *err);
void (QDECL *error) (const char *err, ...);
void (*printf) (const char *text, ...);
void (*dprintf) (const char *text, ...);
void (*localcmd) (const char *cmd);
@ -129,7 +129,7 @@ typedef struct {
void (*localsound) (const char *sample, int channel, float volume);
// file input / search crap
struct vfsfile_s *(*fopen) (const char *filename, char *modestring, enum fs_relative fsroot); //modestring should be one of rb,r+b,wb,w+b,ab,wbp. Mostly use a root of FS_GAMEONLY for writes, otherwise FS_GAME for reads.
struct vfsfile_s *(*fopen) (const char *filename, const char *modestring, enum fs_relative fsroot); //modestring should be one of rb,r+b,wb,w+b,ab,wbp. Mostly use a root of FS_GAMEONLY for writes, otherwise FS_GAME for reads.
void (*fclose) (struct vfsfile_s *fhandle);
char *(*fgets) (struct vfsfile_s *fhandle, char *out, size_t outsize); //returns output buffer, or NULL
void (*fprintf) (struct vfsfile_s *fhandle, const char *s, ...);
@ -142,14 +142,14 @@ typedef struct {
qboolean (*drawgetimagesize)(struct shader_s *pic, int *x, int *y);
void (*drawquad) (const vec2_t position[4], const vec2_t texcoords[4], struct shader_s *pic, const vec4_t rgba, unsigned int be_flags);
float (*drawstring) (vec2_t position, const char *text, struct font_s *font, float height, const vec4_t rgba, unsigned int be_flags);
float (*drawstring) (const vec2_t position, const char *text, struct font_s *font, float height, const vec4_t rgba, unsigned int be_flags);
float (*stringwidth) (const char *text, struct font_s *font, float height);
struct font_s *(*loadfont) (const char *facename, float intendedheight); //with ttf fonts, you'll probably want one for each size.
void (*destroyfont) (struct font_s *font);
// 3D scene stuff
struct model_s *(*cachemodel)(const char *name);
void (*getmodelsize) (struct model_s *model, vec3_t out_mins, vec3_t out_maxs);
qboolean (*getmodelsize) (struct model_s *model, vec3_t out_mins, vec3_t out_maxs);
void (*renderscene) (menuscene_t *scene);
// Menu specific stuff

View File

@ -956,7 +956,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con
int inwater = VM_LONG(arg[3]);
cl.playerview[0].audio.defaulted = false;
cl.playerview[0].audio.entnum = VM_LONG(arg[0]);
cl.playerview[0].audio.entnum = VM_LONG(arg[0])+1;
VectorCopy(org, cl.playerview[0].audio.origin);
VectorCopy(axis[0], cl.playerview[0].audio.forward);
VectorCopy(axis[1], cl.playerview[0].audio.right);

View File

@ -1187,10 +1187,12 @@ void CL_RecordMap_f (void)
#endif
//qw-specific serverdata
static void CLQW_RecordServerData(sizebuf_t *buf)
static void CLQW_RecordServerData(sizebuf_t *buf, int *seq)
{
extern char gamedirfile[];
unsigned int i;
infosync_t sync;
char serverinfostring[1024];
// send the serverdata
MSG_WriteByte (buf, svc_serverdata);
@ -1246,31 +1248,79 @@ static void CLQW_RecordServerData(sizebuf_t *buf)
MSG_WriteFloat(buf, movevars.entgravity);
// send server info string
memset(&sync, 0, sizeof(sync));
InfoBuf_ToString(&cl.serverinfo, serverinfostring, sizeof(serverinfostring), NULL, NULL, NULL, &sync, NULL);
MSG_WriteByte (buf, svc_stufftext);
MSG_WriteString (buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) );
MSG_WriteString (buf, va("fullserverinfo \"%s\"\n", serverinfostring));
while(sync.numkeys)
{
char *keyname = sync.keys[0].name;
char enckey[2048], encdata[2048];
if (InfoBuf_EncodeString(keyname,strlen(keyname), enckey, sizeof(enckey)))
{
size_t k;
if (InfoBuf_FindKey(&cl.serverinfo, keyname, &k))
{
size_t offset, chunk;
qboolean final;
for (offset = 0 ; offset < cl.serverinfo.keys[k].size; offset += chunk)
{
chunk = cl.serverinfo.keys[k].size - offset;
if (chunk > 1024)
chunk = 1024;
if (!InfoBuf_EncodeString(cl.serverinfo.keys[k].value, chunk, encdata, sizeof(encdata)))
break; //shouldn't happen.
if (buf->cursize > 512)
CL_WriteRecordDemoMessage (buf, (*seq)++);
final = (offset+chunk == cl.serverinfo.keys[k].size) && !cl.serverinfo.keys[k].partial;
if (!offset && final)
{ //vanilla compat. we must just have a lot of data.
MSG_WriteByte(buf, svc_serverinfo);
MSG_WriteString(buf, enckey);
MSG_WriteString(buf, encdata);
}
else
{ //awkward stuff.
MSG_WriteByte(buf, svc_setinfo);
MSG_WriteByte(buf, 255); //special meaning to say that this is a partial update
MSG_WriteByte(buf, 255); //the serverinfo
MSG_WriteLong(buf, (final?0x80000000:0)|offset);
MSG_WriteString(buf, enckey);
MSG_WriteString(buf, encdata);
}
offset += chunk;
}
}
}
InfoSync_Remove(&sync, 0);
}
InfoSync_Clear(&sync);
}
#ifdef NQPROT
void CLNQ_WriteServerData(sizebuf_t *buf)
void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
{
unsigned int protmain;
unsigned int protfl = 0;
unsigned int i;
const char *val;
val = Info_ValueForKey(cl.serverinfo, "*csprogs");
val = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
if (*val)
{
MSG_WriteByte(buf, svc_stufftext);
MSG_WriteString(buf, va("csqc_progcrc \"%s\"\n", val));
}
val = Info_ValueForKey(cl.serverinfo, "*csprogssize");
val = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogssize");
if (*val)
{
MSG_WriteByte(buf, svc_stufftext);
MSG_WriteString(buf, va("csqc_progsize \"%s\"\n", val));
}
val = Info_ValueForKey(cl.serverinfo, "*csprogsname");
val = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname");
if (*val)
{
MSG_WriteByte(buf, svc_stufftext);
@ -1724,7 +1774,7 @@ void CL_Record_f (void)
cls.demorecording = DPB_QUAKEWORLD;
CLQW_RecordServerData(&buf);
CLQW_RecordServerData(&buf, &seq);
// send music
Media_WriteCurrentTrack(&buf);
@ -1881,19 +1931,21 @@ void CL_Record_f (void)
MSG_WriteByte (&buf, player->pl);
}
if (*player->userinfo)
if (player->userinfo.numkeys)
{
MSG_WriteByte (&buf, svc_updateentertime);
MSG_WriteByte (&buf, i);
MSG_WriteFloat (&buf, realtime - player->realentertime); //seconds since
}
if (*player->userinfo)
if (player->userinfo.numkeys)
{
char info[MAX_LOCALINFO_STRING];
InfoBuf_ToString(&player->userinfo, info, sizeof(info), basicuserinfos, NULL, NULL, NULL, NULL);
MSG_WriteByte (&buf, svc_updateuserinfo);
MSG_WriteByte (&buf, i);
MSG_WriteLong (&buf, player->userid);
MSG_WriteString (&buf, player->userinfo);
MSG_WriteString (&buf, info);
}
if (buf.cursize > buf.maxsize/2)
@ -2954,7 +3006,11 @@ void CL_QTVPlay_f (void)
{
Q_snprintfz(msg+msglen, sizeof(msg)-msglen,
"QTV_EZQUAKE_EXT: 3\n"
"USERINFO: %s\n", cls.userinfo[0]);
"USERINFO: ");
msglen += strlen(msg+msglen);
InfoBuf_ToString(&cls.userinfo[0], msg+msglen, sizeof(msg)-msglen-1, basicuserinfos, NULL, NULL, NULL, NULL);
msglen += strlen(msg+msglen);
Q_strncatz(msg+msglen, "\n", sizeof(msg)-msglen);
msglen += strlen(msg+msglen);
}

View File

@ -1416,23 +1416,23 @@ void CL_UpdateSeats(void)
{
char *ver;
char buffer[2048];
char newinfo[2048];
Q_strncpyz(newinfo, cls.userinfo[cl.splitclients], sizeof(newinfo));
char infostr[2048];
infobuf_t *info = &cls.userinfo[cl.splitclients];
//some userinfos should always have a value
if (!*Info_ValueForKey(newinfo, "name")) //$name-2
Info_SetValueForKey(newinfo, "name", va("%s-%i\n", Info_ValueForKey(cls.userinfo[0], "name"), cl.splitclients+1), sizeof(newinfo));
if (!*InfoBuf_ValueForKey(info, "name")) //$name-2
InfoBuf_SetKey(info, "name", va("%s-%i\n", InfoBuf_ValueForKey(&cls.userinfo[0], "name"), cl.splitclients+1));
if (cls.protocol != CP_QUAKE2)
{
if (!*Info_ValueForKey(newinfo, "team")) //put players on the same team by default. this avoids team damage in coop, and if you're playing on the same computer then you probably want to be on the same team anyway.
Info_SetValueForKey(newinfo, "team", Info_ValueForKey(cls.userinfo[0], "team"), sizeof(newinfo));
if (!*Info_ValueForKey(newinfo, "bottomcolor")) //bottom colour implies team in nq
Info_SetValueForKey(newinfo, "bottomcolor", Info_ValueForKey(cls.userinfo[0], "bottomcolor"), sizeof(newinfo));
if (!*Info_ValueForKey(newinfo, "topcolor")) //should probably pick a random top colour or something
Info_SetValueForKey(newinfo, "topcolor", Info_ValueForKey(cls.userinfo[0], "topcolor"), sizeof(newinfo));
if (!*InfoBuf_ValueForKey(info, "team")) //put players on the same team by default. this avoids team damage in coop, and if you're playing on the same computer then you probably want to be on the same team anyway.
InfoBuf_SetKey(info, "team", InfoBuf_ValueForKey(&cls.userinfo[0], "team"));
if (!*InfoBuf_ValueForKey(info, "bottomcolor")) //bottom colour implies team in nq
InfoBuf_SetKey(info, "bottomcolor", InfoBuf_ValueForKey(&cls.userinfo[0], "bottomcolor"));
if (!*InfoBuf_ValueForKey(info, "topcolor")) //should probably pick a random top colour or something
InfoBuf_SetKey(info, "topcolor", InfoBuf_ValueForKey(&cls.userinfo[0], "topcolor"));
}
if (!*Info_ValueForKey(newinfo, "skin")) //give players the same skin by default, because we can. q2 cares for teams. qw might as well (its not like anyone actually uses them thanks to enemy-skin forcing).
Info_SetValueForKey(newinfo, "skin", Info_ValueForKey(cls.userinfo[0], "skin"), sizeof(newinfo));
if (!*InfoBuf_ValueForKey(info, "skin")) //give players the same skin by default, because we can. q2 cares for teams. qw might as well (its not like anyone actually uses them thanks to enemy-skin forcing).
InfoBuf_SetKey(info, "skin", InfoBuf_ValueForKey(&cls.userinfo[0], "skin"));
#ifdef SVNREVISION
if (strcmp(STRINGIFY(SVNREVISION), "-"))
@ -1440,11 +1440,12 @@ void CL_UpdateSeats(void)
else
#endif
ver = va("%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR);
Info_SetValueForStarKey(newinfo, "*ver", ver, sizeof(newinfo));
InfoBuf_SetStarKey(info, "*ver", ver);
InfoBuf_ToString(info, infostr, sizeof(infostr), NULL, NULL, NULL, &cls.userinfosync, info);
CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(newinfo, buffer, sizeof(buffer), false));
CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(infostr, buffer, sizeof(buffer), false));
}
else if (cl.splitclients > targ)
else if (cl.splitclients > targ && targ >= 1)
CL_SendClientCommand(true, "addseat %i", targ);
}
}
@ -1510,13 +1511,6 @@ qboolean CLQ2_SendCmd (sizebuf_t *buf)
if (cmd->msec > 100)
cmd->msec = 100;
if (cls.resendinfo)
{
MSG_WriteByte (&cls.netchan.message, clcq2_userinfo);
MSG_WriteString (&cls.netchan.message, cls.userinfo[seat]);
cls.resendinfo = false;
}
MSG_WriteByte (buf, clcq2_move);
if (seat)
@ -1703,6 +1697,96 @@ qboolean CLQW_SendCmd (sizebuf_t *buf, qboolean actuallysend)
return dontdrop;
}
static void CL_SendUserinfoUpdate(void)
{
const char *key = cls.userinfosync.keys[0].name;
infobuf_t *info = cls.userinfosync.keys[0].context;
size_t bloboffset = cls.userinfosync.keys[0].syncpos;
unsigned int seat = info - cls.userinfo;
size_t blobsize;
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize);
size_t sendsize = blobsize - bloboffset;
const char *s;
qboolean final = true;
char enckey[2048];
char encval[2048];
//handle splitscreen
char pl[64];
if (seat)
Q_snprintfz(pl, sizeof(pl), "%i ", seat);
else
*pl = 0;
#ifdef Q3CLIENT
if (cls.protocol == CP_QUAKE3)
{ //q3 sends it all in one go
char userinfo[2048];
InfoBuf_ToString(info, userinfo, sizeof(userinfo), NULL, NULL, NULL, NULL, NULL);
CLQ3_SendClientCommand("userinfo \"%s\"", userinfo);
InfoSync_Strip(&cls.userinfosync, info); //can't track this stuff. all or nothing.
return;
}
#endif
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2 && !cls.fteprotocolextensions)
{
char userinfo[2048];
InfoSync_Strip(&cls.userinfosync, info); //can't track this stuff. all or nothing.
InfoBuf_ToString(info, userinfo, sizeof(userinfo), NULL, NULL, NULL, NULL, NULL);
MSG_WriteByte (&cls.netchan.message, clcq2_userinfo);
SZ_Write(&cls.netchan.message, pl, strlen(pl));
MSG_WriteString (&cls.netchan.message, userinfo);
return;
}
#endif
if (seat < max(1,cl.splitclients))
{
if (sendsize > 1023)
{
final = false;
sendsize = 1023; //should be a multiple of 3
}
if (!InfoBuf_EncodeString(key, strlen(key), enckey, sizeof(enckey)) ||
!InfoBuf_EncodeString(blobdata+bloboffset, sendsize, encval, sizeof(encval)))
{ //some buffer wasn't big enough... shouldn't happen.
InfoSync_Remove(&cls.userinfosync, 0);
return;
}
if (final && !bloboffset && *encval != '\xff' && *encval != '\xff')
{ //vanilla-compatible info.
s = va("%ssetinfo \"%s\" \"%s\"", pl, enckey, encval);
}
else if (cls.fteprotocolextensions2 & PEXT2_INFOBLOBS)
{ //only flood servers that actually support it.
if (final)
s = va("%ssetinfo \"%s\" \"%s\" %u", pl, enckey, encval, bloboffset);
else
s = va("%ssetinfo \"%s\" \"%s\" %u+", pl, enckey, encval, bloboffset);
}
else
{ //server doesn't support it, just ignore the key
InfoSync_Remove(&cls.userinfosync, 0);
return;
}
if (cls.protocol == CP_QUAKE2)
MSG_WriteByte (&cls.netchan.message, clcq2_stringcmd);
else
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, s);
}
if (bloboffset+sendsize == blobsize)
InfoSync_Remove(&cls.userinfosync, 0);
else
cls.userinfosync.keys[0].syncpos += sendsize;
}
void CL_SendCmd (double frametime, qboolean mainloop)
{
sizebuf_t buf;
@ -2001,6 +2085,10 @@ void CL_SendCmd (double frametime, qboolean mainloop)
Z_Free(clientcmdlist);
clientcmdlist = next;
}
//only start spamming userinfo blobs once we receive the initial serverinfo.
while (cls.userinfosync.numkeys && cls.netchan.message.cursize < 512 && (cl.haveserverinfo || cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3))
CL_SendUserinfoUpdate();
}
// if we're not doing clc_moves and etc, don't continue unless we wrote something previous

View File

@ -432,8 +432,6 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
cls.fteprotocolextensions2 = 0;
cls.ezprotocolextensions1 = 0;
cls.resendinfo = false;
connectinfo.time = realtime; // for retransmit requests
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string);
@ -619,8 +617,6 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
t2 = Sys_DoubleTime ();
cls.resendinfo = false;
connectinfo.time = realtime+t2-t1; // for retransmit requests
//fixme: we shouldn't cycle these so much
@ -652,7 +648,10 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
*a = '@';
}
//the info itself
Q_strncatz(data, cls.userinfo[0], sizeof(data));
{
static const char *prioritykeys[] = {"name", "password", "spectator", "lang", "rate", "team", "topcolor", "bottomcolor", "skin", "_", "*", NULL};
InfoBuf_ToString(&cls.userinfo[0], data+strlen(data), sizeof(data)-strlen(data), prioritykeys, NULL, NULL, &cls.userinfosync, &cls.userinfo[0]);
}
if (connectinfo.protocol == CP_QUAKEWORLD) //zquake extension info.
Q_strncatz(data, va("\\*z_ext\\%i", SUPPORTED_Z_EXTENSIONS), sizeof(data));
@ -1633,6 +1632,8 @@ void CL_ClearState (void)
Z_Free(cl.windowtitle);
InfoBuf_Clear(&cl.serverinfo, true);
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
@ -1647,7 +1648,7 @@ void CL_ClearState (void)
cl.allocated_client_slots = sv.allocated_client_slots;
#endif
SZ_Clear (&cls.netchan.message);
// SZ_Clear (&cls.netchan.message);
r_worldentity.model = NULL;
@ -1666,7 +1667,7 @@ void CL_ClearState (void)
cl.playerview[i].maxspeed = 320;
cl.playerview[i].entgravity = 1;
cl.playerview[i].chatstate = atoi(Info_ValueForKey(cls.userinfo[i], "chat"));
cl.playerview[i].chatstate = atoi(InfoBuf_ValueForKey(&cls.userinfo[i], "chat"));
}
#ifdef QUAKESTATS
for (i = 0; i < MAX_CLIENTS; i++) //in case some server doesn't support it
@ -1889,7 +1890,7 @@ void CL_User_f (void)
if (!cl.players[i].userinfovalid)
Con_Printf("name: %s\ncolour %i %i\nping: %i\n", cl.players[i].name, cl.players[i].rbottomcolor, cl.players[i].rtopcolor, cl.players[i].ping);
else
Info_Print (cl.players[i].userinfo, "");
InfoBuf_Print (&cl.players[i].userinfo, "");
found = true;
}
}
@ -1953,8 +1954,8 @@ void CL_Color_f (void)
if (Cmd_Argc() == 1)
{
char *t = Info_ValueForKey (cls.userinfo[pnum], "topcolor");
char *b = Info_ValueForKey (cls.userinfo[pnum], "bottomcolor");
char *t = InfoBuf_ValueForKey(&cls.userinfo[pnum], "topcolor");
char *b = InfoBuf_ValueForKey(&cls.userinfo[pnum], "bottomcolor");
if (!*t)
t = "0";
if (!*b)
@ -1973,10 +1974,10 @@ void CL_Color_f (void)
t = Cmd_Argv(1);
b = (Cmd_Argc()==2)?t:Cmd_Argv(2);
if (!strcmp(t, "-1"))
t = Info_ValueForKey (cls.userinfo[pnum], "topcolor");
t = InfoBuf_ValueForKey(&cls.userinfo[pnum], "topcolor");
top = CL_ParseColour(t);
if (!strcmp(b, "-1"))
b = Info_ValueForKey (cls.userinfo[pnum], "bottomcolor");
b = InfoBuf_ValueForKey(&cls.userinfo[pnum], "bottomcolor");
bottom = CL_ParseColour(b);
Q_snprintfz (num, sizeof(num), (top&0xff000000)?"0x%06x":"%i", top & 0xffffff);
@ -2049,7 +2050,7 @@ void CL_PakDownloads(int mode)
void CL_CheckServerPacks(void)
{
static int oldpure;
int pure = atof(Info_ValueForKey(cl.serverinfo, "sv_pure"));
int pure = atof(InfoBuf_ValueForKey(&cl.serverinfo, "sv_pure"));
if (pure < cl_pure.ival)
pure = cl_pure.ival;
pure = bound(0, pure, 2);
@ -2094,8 +2095,8 @@ void CL_CheckServerInfo(void)
spectating = false;
oldteamplay = cl.teamplay;
cl.teamplay = atoi(Info_ValueForKey(cl.serverinfo, "teamplay"));
cls.deathmatch = cl.deathmatch = atoi(Info_ValueForKey(cl.serverinfo, "deathmatch"));
cl.teamplay = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "teamplay"));
cls.deathmatch = cl.deathmatch = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "deathmatch"));
cls.allow_cheats = false;
cls.allow_semicheats=true;
@ -2106,16 +2107,16 @@ void CL_CheckServerInfo(void)
// cls.allow_overbrightlight;
cls.allow_csqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc")) || *Info_ValueForKey(cl.serverinfo, "*csprogs");
cl.csqcdebug = atoi(Info_ValueForKey(cl.serverinfo, "*csqcdebug"));
cls.allow_csqc = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "anycsqc")) || *InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
cl.csqcdebug = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "*csqcdebug"));
if (spectating || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "watervis")))
if (spectating || cls.demoplayback || atoi(InfoBuf_ValueForKey(&cl.serverinfo, "watervis")))
cls.allow_watervis=true;
if (spectating || cls.demoplayback || atoi(Info_ValueForKey(cl.serverinfo, "allow_skybox")) || atoi(Info_ValueForKey(cl.serverinfo, "allow_skyboxes")))
if (spectating || cls.demoplayback || atoi(InfoBuf_ValueForKey(&cl.serverinfo, "allow_skybox")) || atoi(InfoBuf_ValueForKey(&cl.serverinfo, "allow_skyboxes")))
cls.allow_skyboxes=true; //mostly obsolete.
s = Info_ValueForKey(cl.serverinfo, "fbskins");
s = InfoBuf_ValueForKey(&cl.serverinfo, "fbskins");
if (*s)
cls.allow_fbskins = atof(s);
else if (cl.teamfortress)
@ -2123,7 +2124,7 @@ void CL_CheckServerInfo(void)
else
cls.allow_fbskins = 1;
s = Info_ValueForKey(cl.serverinfo, "*cheats");
s = InfoBuf_ValueForKey(&cl.serverinfo, "*cheats");
if (spectating || cls.demoplayback || !stricmp(s, "on"))
cls.allow_cheats = true;
@ -2134,14 +2135,14 @@ void CL_CheckServerInfo(void)
cls.allow_cheats = true;
#endif
s = Info_ValueForKey(cl.serverinfo, "strict");
s = InfoBuf_ValueForKey(&cl.serverinfo, "strict");
if ((!spectating && !cls.demoplayback && *s && strcmp(s, "0")) || !ruleset_allow_semicheats.ival)
{
cls.allow_semicheats = false;
cls.allow_cheats = false;
}
cls.z_ext = atoi(Info_ValueForKey(cl.serverinfo, "*z_ext"));
cls.z_ext = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "*z_ext"));
#ifdef NQPROT
if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
@ -2151,22 +2152,22 @@ void CL_CheckServerInfo(void)
else
#endif
{
cls.maxfps = atof(Info_ValueForKey(cl.serverinfo, "maxfps"));
cls.maxfps = atof(InfoBuf_ValueForKey(&cl.serverinfo, "maxfps"));
if (cls.maxfps < 20)
cls.maxfps = 72;
// movement vars for prediction
cl.bunnyspeedcap = Q_atof(Info_ValueForKey(cl.serverinfo, "pm_bunnyspeedcap"));
movevars.slidefix = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_slidefix")) != 0);
movevars.airstep = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_airstep")) != 0);
movevars.stepdown = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_stepdown")) != 0);
movevars.walljump = (Q_atof(Info_ValueForKey(cl.serverinfo, "pm_walljump")));
movevars.ktjump = Q_atof(Info_ValueForKey(cl.serverinfo, "pm_ktjump"));
s = Info_ValueForKey(cl.serverinfo, "pm_stepheight");
cl.bunnyspeedcap = Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_bunnyspeedcap"));
movevars.slidefix = (Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_slidefix")) != 0);
movevars.airstep = (Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_airstep")) != 0);
movevars.stepdown = (Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_stepdown")) != 0);
movevars.walljump = (Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_walljump")));
movevars.ktjump = Q_atof(InfoBuf_ValueForKey(&cl.serverinfo, "pm_ktjump"));
s = InfoBuf_ValueForKey(&cl.serverinfo, "pm_stepheight");
movevars.stepheight = *s?Q_atof(s):PM_DEFAULTSTEPHEIGHT;
s = Info_ValueForKey(cl.serverinfo, "pm_watersinkspeed");
s = InfoBuf_ValueForKey(&cl.serverinfo, "pm_watersinkspeed");
movevars.watersinkspeed = *s?Q_atof(s):60;
s = Info_ValueForKey(cl.serverinfo, "pm_flyfriction");
s = InfoBuf_ValueForKey(&cl.serverinfo, "pm_flyfriction");
movevars.flyfriction = *s?Q_atof(s):4;
}
movevars.coordsize = cls.netchan.netprim.coordsize;
@ -2174,9 +2175,9 @@ void CL_CheckServerInfo(void)
// Initialize cl.maxpitch & cl.minpitch
if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE)
{
s = Info_ValueForKey (cl.serverinfo, "maxpitch");
s = InfoBuf_ValueForKey(&cl.serverinfo, "maxpitch");
cl.maxpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?90.0f:80.0f);
s = Info_ValueForKey (cl.serverinfo, "minpitch");
s = InfoBuf_ValueForKey(&cl.serverinfo, "minpitch");
cl.minpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?-90.0f:-70.0f);
if (cls.protocol == CP_NETQUAKE)
@ -2195,9 +2196,9 @@ void CL_CheckServerInfo(void)
cl.maxpitch = bound(-89.9, cl.maxpitch, 89.9);
cl.minpitch = bound(-89.9, cl.minpitch, 89.9);
cl.hexen2pickups = atoi(Info_ValueForKey(cl.serverinfo, "sv_pupglow"));
cl.hexen2pickups = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "sv_pupglow"));
allowed = atoi(Info_ValueForKey(cl.serverinfo, "allow"));
allowed = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "allow"));
if (allowed & 1)
cls.allow_watervis = true;
// if (allowed & 2)
@ -2224,14 +2225,14 @@ void CL_CheckServerInfo(void)
if (spectating || cls.demoplayback)
cl.fpd = 0;
else
cl.fpd = atoi(Info_ValueForKey(cl.serverinfo, "fpd"));
cl.fpd = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "fpd"));
cl.gamespeed = atof(Info_ValueForKey(cl.serverinfo, "*gamespeed"))/100.f;
cl.gamespeed = atof(InfoBuf_ValueForKey(&cl.serverinfo, "*gamespeed"))/100.f;
if (cl.gamespeed < 0.1)
cl.gamespeed = 1;
#ifdef QUAKESTATS
s = Info_ValueForKey(cl.serverinfo, "status");
s = InfoBuf_ValueForKey(&cl.serverinfo, "status");
oldstate = cl.matchstate;
if (!stricmp(s, "standby"))
cl.matchstate = MATCH_STANDBY;
@ -2253,7 +2254,7 @@ void CL_CheckServerInfo(void)
{
//always update it. this is to try to cope with overtime.
oldstate = cl.matchstate = MATCH_INPROGRESS;
cl.matchgametimestart = cl.gametime + time - 60*atof(Info_ValueForKey(cl.serverinfo, "timelimit"));
cl.matchgametimestart = cl.gametime + time - 60*atof(InfoBuf_ValueForKey(&cl.serverinfo, "timelimit"));
}
else
{
@ -2335,11 +2336,11 @@ void CL_FullInfo_f (void)
if (!stricmp(key, pmodel_name) || !stricmp(key, emodel_name))
continue;
Info_SetValueForKey (cls.userinfo[pnum], key, value, sizeof(cls.userinfo[pnum]));
InfoBuf_SetKey (&cls.userinfo[pnum], key, value);
}
}
void CL_SetInfo (int pnum, char *key, char *value)
void CL_SetInfoBlob (int pnum, const char *key, const char *value, size_t valuesize)
{
cvar_t *var;
if (!pnum)
@ -2352,25 +2353,11 @@ void CL_SetInfo (int pnum, char *key, char *value)
}
}
Info_SetValueForStarKey (cls.userinfo[pnum], key, value, sizeof(cls.userinfo[pnum]));
if (cls.state >= ca_connected && !cls.demoplayback)
{
if (pnum >= cl.splitclients)
return;
#ifdef Q2CLIENT
if ((cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) && !cls.fteprotocolextensions)
cls.resendinfo = true;
else
#endif
if (cls.protocol != CP_NETQUAKE || (cls.fteprotocolextensions & PEXT_BIGUSERINFOS))
{
if (pnum)
CL_SendClientCommand(true, "%i setinfo %s \"%s\"", pnum+1, key, value);
else
CL_SendClientCommand(true, "setinfo %s \"%s\"", key, value);
}
}
InfoBuf_SetStarBlobKey(&cls.userinfo[pnum], key, value, valuesize);
}
void CL_SetInfo (int pnum, const char *key, const char *value)
{
CL_SetInfoBlob(pnum, key, value, strlen(value));
}
/*
==================
@ -2385,7 +2372,8 @@ void CL_SetInfo_f (void)
int pnum = CL_TargettedSplit(true);
if (Cmd_Argc() == 1)
{
Info_Print (cls.userinfo[pnum], "");
InfoBuf_Print (&cls.userinfo[pnum], "");
Con_Printf("[%u]", (unsigned int)cls.userinfo[pnum].totalsize);
return;
}
if (Cmd_Argc() != 3)
@ -2402,18 +2390,18 @@ void CL_SetInfo_f (void)
if (!strcmp(Cmd_Argv(1), "*"))
if (!strcmp(Cmd_Argv(2), ""))
{ //clear it out
char *k;
const char *k;
for(i=0;;)
{
k = Info_KeyForNumber(cls.userinfo[pnum], i);
if (!*k)
k = InfoBuf_KeyForNumber(&cls.userinfo[pnum], i);
if (!k)
break; //no more.
else if (*k == '*')
i++; //can't remove * keys
else if ((var = Cvar_FindVar(k)) && var->flags&CVAR_USERINFO)
else if ((var = Cvar_FindVar(k)) && (var->flags&CVAR_USERINFO))
i++; //this one is a cvar.
else
Info_RemoveKey(cls.userinfo[pnum], k); //we can remove this one though, so yay.
InfoBuf_RemoveKey(&cls.userinfo[pnum], k); //we can remove this one though, so yay.
}
return;
@ -2422,10 +2410,49 @@ void CL_SetInfo_f (void)
return;
}
CL_SetInfo(pnum, Cmd_Argv(1), Cmd_Argv(2));
}
#ifdef _DEBUG
void CL_SetInfoBlob_f (void)
{
qofs_t fsize;
void *data;
int pnum = CL_TargettedSplit(true);
if (Cmd_Argc() == 1)
{
InfoBuf_Print (&cls.userinfo[pnum], "");
return;
}
if (Cmd_Argc() != 3)
{
Con_TPrintf ("usage: setinfo [ <key> <filename> ]\n");
return;
}
//user isn't allowed to set pmodel, emodel, *foo as these could break stuff.
if (!stricmp(Cmd_Argv(1), pmodel_name) || !strcmp(Cmd_Argv(1), emodel_name))
return;
if (Cmd_Argv(1)[0] == '*')
{
Con_Printf ("Can't set * keys\n");
return;
}
data = FS_MallocFile(Cmd_Argv(2), FS_GAME, &fsize);
if (!data)
{
Con_Printf ("Unable to read %s\n", Cmd_Argv(2));
return;
}
if (fsize > 64*1024*1024)
Con_Printf ("File is over 64mb\n");
else
CL_SetInfoBlob(pnum, Cmd_Argv(1), data, fsize);
FS_FreeFile(data);
}
#endif
void CL_SaveInfo(vfsfile_t *f)
{
int i;
@ -2435,12 +2462,12 @@ void CL_SaveInfo(vfsfile_t *f)
if (i)
{
VFS_WRITE(f, va("p%i setinfo * \"\"\n", i+1), 16);
Info_WriteToFile(f, cls.userinfo[i], va("p%i setinfo", i+1), 0);
InfoBuf_WriteToFile(f, &cls.userinfo[i], va("p%i setinfo", i+1), 0);
}
else
{
VFS_WRITE(f, "setinfo * \"\"\n", 13);
Info_WriteToFile(f, cls.userinfo[i], "setinfo", CVAR_USERINFO);
InfoBuf_WriteToFile(f, &cls.userinfo[i], "setinfo", CVAR_USERINFO);
}
}
}
@ -3921,10 +3948,8 @@ void CL_ServerInfo_f(void)
{
if (!sv.state && cls.state && Cmd_Argc() < 2)
{
if (cls.demoplayback || cls.protocol != CP_QUAKEWORLD)
{
Info_Print (cl.serverinfo, "");
}
if (cl.haveserverinfo)
InfoBuf_Print (&cl.serverinfo, "");
else
Cmd_ForwardToServer ();
}
@ -4117,6 +4142,12 @@ void CL_Demo_SetSpeed_f(void)
Con_Printf("demo playback speed %g%%\n", cl_demospeed.value * 100);
}
static void CL_UserinfoChanged(void *ctx, const char *keyname)
{
InfoSync_Add(&cls.userinfosync, ctx, keyname);
}
void CL_Skygroup_f(void);
/*
=================
@ -4133,6 +4164,7 @@ void CL_Init (void)
extern cvar_t noskins;
#endif
char *ver;
size_t seat;
cls.state = ca_disconnected;
@ -4143,7 +4175,12 @@ void CL_Init (void)
#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]));
for (seat = 0; seat < MAX_SPLITS; seat++)
{
cls.userinfo[seat].ChangeCTX = &cls.userinfo[seat];
cls.userinfo[seat].ChangeCB = CL_UserinfoChanged;
InfoBuf_SetStarKey (&cls.userinfo[seat], "*ver", ver);
}
InitValidation();
@ -4412,6 +4449,9 @@ void CL_Init (void)
Cmd_AddCommand ("user", CL_User_f);
Cmd_AddCommand ("users", CL_Users_f);
#ifdef _DEBUG
Cmd_AddCommand ("setinfoblob", CL_SetInfoBlob_f);
#endif
Cmd_AddCommand ("setinfo", CL_SetInfo_f);
Cmd_AddCommand ("fullinfo", CL_FullInfo_f);
@ -5756,7 +5796,7 @@ void CL_ReadCDKey(void)
{ //q3 cdkey
//you don't need one, just use a server without sv_strictauth set to 0.
char *buffer;
buffer = COM_LoadTempFile("q3key", NULL);
buffer = COM_LoadTempFile("q3key", FSLF_IGNOREPURE, NULL);
if (buffer) //a cdkey is meant to be 16 chars
{
char *chr;
@ -6221,6 +6261,7 @@ to run quit through here before the final handoff to the sys code.
*/
void Host_Shutdown(void)
{
size_t i;
if (!host_initialized)
return;
host_initialized = false;
@ -6290,6 +6331,10 @@ void Host_Shutdown(void)
Plug_Shutdown(true);
#endif
for (i = 0; i < MAX_SPLITS; i++)
InfoBuf_Clear(&cls.userinfo[i], true);
InfoSync_Clear(&cls.userinfosync);
Con_Shutdown();
COM_BiDi_Shutdown();
Memory_DeInit();

View File

@ -1235,10 +1235,10 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
qboolean anycsqc;
char *endptr;
unsigned int chksum;
anycsqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc"));
anycsqc = atoi(InfoBuf_ValueForKey(&cl.serverinfo, "anycsqc"));
if (cls.demoplayback)
anycsqc = true;
s = Info_ValueForKey(cl.serverinfo, "*csprogs");
s = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
chksum = strtoul(s, &endptr, 0);
if (*endptr)
{
@ -1515,7 +1515,7 @@ static void Sound_CheckDownloads (void)
// if (cls.fteprotocolextensions & PEXT_CSQC)
{
char *s;
s = Info_ValueForKey(cl.serverinfo, "*csprogs");
s = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs");
if (*s) //only allow csqc if the server says so, and the 'checksum' matches.
{
extern cvar_t cl_download_csprogs, cl_nocsqc;
@ -1640,6 +1640,8 @@ void CL_RequestNextDownload (void)
current_loading_size = cl.contentstage;
if (stage < 0)
return;
//if (cls.userinfosync.numkeys)
// return; //don't prespawn until we've actually sent all our initial userinfo.
if (requiredownloads.ival && COM_HasWork())
{
SCR_SetLoadingFile("loading content");
@ -2457,7 +2459,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype)
case DL_DARKPLACES:
case DL_QWCHUNKS:
{
char *serverversion = Info_ValueForKey(cl.serverinfo, "*version");
char *serverversion = InfoBuf_ValueForKey(&cl.serverinfo, "*version");
if (strncmp(serverversion , "MVDSV ", 6)) //don't tell mvdsv to stop, because it has retarded annoying clientprints that are spammy as fuck, and we don't want that.
CL_SendClientCommand(true, "stopdownload");
}
@ -3116,7 +3118,7 @@ static void CLQW_ParseServerData (void)
COM_FlushTempoaryPacks();
COM_Gamedir(str, NULL);
#ifndef CLIENTONLY
Info_SetValueForStarKey (svs.info, "*gamedir", str, MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey (&svs.info, "*gamedir", str);
#endif
}
@ -3676,7 +3678,7 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
COM_FlushTempoaryPacks();
COM_Gamedir(str, NULL);
#ifndef CLIENTONLY
Info_SetValueForStarKey (svs.info, "*gamedir", str, MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey (&svs.info, "*gamedir", str);
#endif
}
}
@ -3752,29 +3754,29 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
//fill in the csqc stuff
if (!cl_dp_csqc_progscrc)
{
Info_RemoveKey(cl.serverinfo, "*csprogs");
Info_RemoveKey(cl.serverinfo, "*csprogssize");
Info_RemoveKey(cl.serverinfo, "*csprogsname");
InfoBuf_RemoveKey(&cl.serverinfo, "*csprogs");
InfoBuf_RemoveKey(&cl.serverinfo, "*csprogssize");
InfoBuf_RemoveKey(&cl.serverinfo, "*csprogsname");
}
else
{
Info_SetValueForStarKey(cl.serverinfo, "*csprogs", va("%i", cl_dp_csqc_progscrc), sizeof(cl.serverinfo));
Info_SetValueForStarKey(cl.serverinfo, "*csprogssize", va("%i", cl_dp_csqc_progssize), sizeof(cl.serverinfo));
Info_SetValueForStarKey(cl.serverinfo, "*csprogsname", va("%s", cl_dp_csqc_progsname), sizeof(cl.serverinfo));
InfoBuf_SetStarKey(&cl.serverinfo, "*csprogs", va("%i", cl_dp_csqc_progscrc));
InfoBuf_SetStarKey(&cl.serverinfo, "*csprogssize", va("%i", cl_dp_csqc_progssize));
InfoBuf_SetStarKey(&cl.serverinfo, "*csprogsname", va("%s", cl_dp_csqc_progsname));
}
//update gamemode
if (gametype != GAME_COOP)
Info_SetValueForStarKey(cl.serverinfo, "deathmatch", "1", sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "deathmatch", "1");
else
Info_SetValueForStarKey(cl.serverinfo, "deathmatch", "0", sizeof(cl.serverinfo));
Info_SetValueForStarKey(cl.serverinfo, "teamplay", "0", sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "deathmatch", "0");
InfoBuf_SetKey(&cl.serverinfo, "teamplay", "0");
//allow some things by default that quakeworld bans by default
Info_SetValueForStarKey(cl.serverinfo, "watervis", "1", sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "watervis", "1");
//prohibit some things that QW/FTE has enabled by default, which would be frowned upon in NQ
Info_SetValueForStarKey(cl.serverinfo, "fbskins", "0", sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "fbskins", "0");
//pretend it came from the server, and update cheat/permissions/etc
CL_CheckServerInfo();
@ -3822,7 +3824,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
CL_SendClientCommand(true, "name \"%s\"\n", name.string);
CL_SendClientCommand(true, "color %i %i\n", topcolor.ival, bottomcolor.ival);
if (cl.haveserverinfo)
Info_Enumerate(cls.userinfo[0], NULL, CLNQ_SendInitialUserInfo);
InfoBuf_Enumerate(&cls.userinfo[0], NULL, CLNQ_SendInitialUserInfo);
else if (CPNQ_IS_DP)
{ //dp needs a couple of extras to work properly in certain cases. don't send them on other servers because that generally results in error messages.
CL_SendClientCommand(true, "rate %s", rate.string);
@ -4168,7 +4170,7 @@ static void CLQ2_ParseClientinfo(int i, char *s)
player = &cl.players[i];
*player->userinfo = '\0';
InfoBuf_Clear(&player->userinfo, true);
cl.players[i].userinfovalid = true;
model = strchr(s, '\\');
@ -4192,12 +4194,12 @@ static void CLQ2_ParseClientinfo(int i, char *s)
}
else
skin = "";
Info_SetValueForKey(player->userinfo, "model", model, MAX_INFO_STRING);
Info_SetValueForKey(player->userinfo, "skin", skin, MAX_INFO_STRING);
InfoBuf_SetValueForKey(&player->userinfo, "model", model);
InfoBuf_SetValueForKey(&player->userinfo, "skin", skin);
#else
Info_SetValueForKey(player->userinfo, "skin", model, sizeof(player->userinfo));
InfoBuf_SetValueForKey(&player->userinfo, "skin", model);
#endif
Info_SetValueForKey(player->userinfo, "name", name, sizeof(player->userinfo));
InfoBuf_SetValueForKey(&player->userinfo, "name", name);
cl.players[i].userid = i;
cl.players[i].rbottomcolor = 1;
@ -4288,6 +4290,8 @@ static void CLQ2_ParseConfigString (void)
{
Media_NamedTrack (s, NULL);
}
else if (i == Q2CS_AIRACCEL)
Q_strncpyz(cl.q2airaccel, s, sizeof(cl.q2airaccel));
else if (i >= Q2CS_MODELS && i < Q2CS_MODELS+Q2MAX_MODELS)
{
if (*s == '/')
@ -4756,7 +4760,7 @@ static void CLQ2_ParseStartSoundPacket(void)
{ //a 'sexed' sound
if (ent > 0 && ent <= MAX_CLIENTS)
{
char *model = Info_ValueForKey(cl.players[ent-1].userinfo, "skin");
char *model = InfoBuf_ValueForKey(&cl.players[ent-1].userinfo, "skin");
char *skin;
skin = strchr(model, '/');
if (skin)
@ -4975,7 +4979,7 @@ void CL_NewTranslation (int slot)
player->ttopcolor = TOP_DEFAULT;
player->tbottomcolor = BOTTOM_DEFAULT;
mod = Info_ValueForKey(player->userinfo, "skin");
mod = InfoBuf_ValueForKey(&player->userinfo, "skin");
skin = strchr(mod, '/');
if (skin)
*skin++ = 0;
@ -5077,22 +5081,22 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player)
int i;
char *col;
int ospec = player->spectator;
Q_strncpyz (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name));
Q_strncpyz (player->team, Info_ValueForKey (player->userinfo, "team"), sizeof(player->team));
Q_strncpyz (player->name, InfoBuf_ValueForKey (&player->userinfo, "name"), sizeof(player->name));
Q_strncpyz (player->team, InfoBuf_ValueForKey (&player->userinfo, "team"), sizeof(player->team));
col = Info_ValueForKey (player->userinfo, "topcolor");
col = InfoBuf_ValueForKey (&player->userinfo, "topcolor");
if (!strncmp(col, "0x", 2))
player->rtopcolor = 0xff000000|strtoul(col+2, NULL, 16);
else
player->rtopcolor = atoi(col);
col = Info_ValueForKey (player->userinfo, "bottomcolor");
col = InfoBuf_ValueForKey (&player->userinfo, "bottomcolor");
if (!strncmp(col, "0x", 2))
player->rbottomcolor = 0xff000000|strtoul(col+2, NULL, 16);
else
player->rbottomcolor = atoi(col);
i = atoi(Info_ValueForKey (player->userinfo, "*spectator"));
i = atoi(InfoBuf_ValueForKey (&player->userinfo, "*spectator"));
if (i == 2)
player->spectator = 2;
else if (i)
@ -5108,7 +5112,7 @@ static void CL_ProcessUserInfo (int slot, player_info_t *player)
#ifdef HEXEN2
/*if we're running hexen2, they have to be some class...*/
player->h2playerclass = atoi(Info_ValueForKey (player->userinfo, "cl_playerclass"));
player->h2playerclass = atoi(InfoBuf_ValueForKey (&player->userinfo, "cl_playerclass"));
if (player->h2playerclass > 5)
player->h2playerclass = 5;
if (player->h2playerclass < 1)
@ -5168,7 +5172,7 @@ static void CL_UpdateUserinfo (void)
player = &cl.players[slot];
player->userid = MSG_ReadLong ();
Q_strncpyz (player->userinfo, MSG_ReadString(), sizeof(player->userinfo));
InfoBuf_FromString(&player->userinfo, MSG_ReadString(), false);
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player);
@ -5178,7 +5182,7 @@ static void CL_UpdateUserinfo (void)
if (slot == cl.playerview[0].playernum && player->name[0])
{
char *qz;
qz = Info_ValueForKey(player->userinfo, "Qizmo");
qz = InfoBuf_ValueForKey(&player->userinfo, "Qizmo");
if (*qz)
TP_ExecTrigger("f_qizmoconnect", false);
}
@ -5193,27 +5197,55 @@ static void CL_ParseSetInfo (void)
{
int slot;
player_info_t *player;
char key[MAX_QWMSGLEN];
char value[MAX_QWMSGLEN];
char *temp;
char *key;
char *val;
unsigned int offset;
qboolean final;
size_t keysize;
size_t valsize;
slot = MSG_ReadByte ();
Q_strncpyz (key, MSG_ReadString(), sizeof(key));
Q_strncpyz (value, MSG_ReadString(), sizeof(value));
if (slot == 255)
{
slot = MSG_ReadByte();
offset = MSG_ReadLong();
final = !!(offset & 0x80000000);
offset &= ~0x80000000;
}
else
{
final = true;
offset = 0;
}
if (slot >= MAX_CLIENTS)
Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, value);
temp = MSG_ReadString();
key = InfoBuf_DecodeString(temp, temp+strlen(temp), &keysize);
temp = MSG_ReadString();
val = InfoBuf_DecodeString(temp, temp+strlen(temp), &valsize);
if (slot == 255)
InfoBuf_SyncReceive(&cl.serverinfo, key, keysize, val, valsize, offset, final);
else if (slot >= MAX_CLIENTS)
Con_Printf("INVALID SETINFO %i: %s=%s\n", slot, key, val);
else
{
player = &cl.players[slot];
Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
if (offset)
Con_DPrintf("SETINFO %s: %s+=%s\n", player->name, key, val);
else
Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, val);
Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo));
InfoBuf_SyncReceive(&player->userinfo, key, keysize, val, valsize, offset, final);
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player);
}
Z_Free(key);
Z_Free(val);
}
/*
@ -5233,7 +5265,7 @@ static void CL_ServerInfo (void)
Con_DPrintf("SERVERINFO: %s=%s\n", key, value);
Info_SetValueForStarKey (cl.serverinfo, key, value, MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&cl.serverinfo, key, value);
CL_CheckServerInfo();
}
@ -5286,11 +5318,11 @@ static void CL_SetStatMovevar(int pnum, int stat, int ivalue, float value)
{
case STAT_FRAGLIMIT:
if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
Info_SetValueForKey(cl.serverinfo, "fraglimit", va("%g", value), sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "fraglimit", va("%g", value));
break;
case STAT_TIMELIMIT:
if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
Info_SetValueForKey(cl.serverinfo, "timelimit", va("%g", value), sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "timelimit", va("%g", value));
break;
case STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR: //0
case STAT_MOVEVARS_AIRCONTROL_PENALTY: //0
@ -5714,7 +5746,7 @@ static int CL_PlayerColor(player_info_t *plr, qboolean *name_coloured)
// 0-6 is standard colors (red to white)
// 7-13 is using secondard charactermask
// 14 and afterwards repeats
t = Info_ValueForKey(plr->userinfo, "tc");
t = InfoBuf_ValueForKey(&plr->userinfo, "tc");
if (*t)
c = atoi(t);
else
@ -6194,20 +6226,20 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
if (Cmd_Argc() == 2)
{
cl.haveserverinfo = true;
Q_strncpyz (cl.serverinfo, Cmd_Argv(1), sizeof(cl.serverinfo));
InfoBuf_FromString(&cl.serverinfo, Cmd_Argv(1), false);
CL_CheckServerInfo();
}
#if _MSC_VER > 1200
if (cls.netchan.remote_address.type != NA_LOOPBACK)
Sys_RecentServer("+connect", cls.servername, va("%s (%s)", Info_ValueForKey(cl.serverinfo, "hostname"), cls.servername), "Join QW Server");
Sys_RecentServer("+connect", cls.servername, va("%s (%s)", InfoBuf_ValueForKey(&cl.serverinfo, "hostname"), cls.servername), "Join QW Server");
#endif
}
else if (!strncmp(stufftext, "//svi ", 6)) //for serverinfo over NQ protocols
{
Cmd_TokenizeString(stufftext+2, false, false);
Con_DPrintf("SERVERINFO: %s=%s\n", Cmd_Argv(1), Cmd_Argv(2));
Info_SetValueForStarKey (cl.serverinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&cl.serverinfo, Cmd_Argv(1), Cmd_Argv(2));
CL_CheckServerInfo();
}
@ -6241,8 +6273,8 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
{
if (!cl.haveserverinfo)
{
Info_SetValueForStarKey(cl.serverinfo, "maxpitch", (atoi(stufftext+13))? "90":"", sizeof(cl.serverinfo));
Info_SetValueForStarKey(cl.serverinfo, "minpitch", (atoi(stufftext+13))?"-90":"", sizeof(cl.serverinfo));
InfoBuf_SetKey(&cl.serverinfo, "maxpitch", (atoi(stufftext+13))? "90":"");
InfoBuf_SetKey(&cl.serverinfo, "minpitch", (atoi(stufftext+13))?"-90":"");
CL_CheckServerInfo();
}
}
@ -6363,12 +6395,12 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
{
player_info_t *player = &cl.players[slot];
Con_DPrintf("SETINFO %s: %s\n", player->name, value);
Q_strncpyz(player->userinfo, value, sizeof(player->userinfo));
InfoBuf_FromString(&player->userinfo, value, false);
player->userinfovalid = true;
CL_ProcessUserInfo (slot, player);
}
}
else if (!strncmp(stufftext, "//ui ", 5)) //ui <slot> <key> <value>. Full user info updates.
else if (!strncmp(stufftext, "//ui ", 5)) //ui <slot> <key> <value>. Partial user info updates.
{
unsigned int slot;
const char *key, *value;
@ -6380,7 +6412,7 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
{
player_info_t *player = &cl.players[slot];
Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
Info_SetValueForStarKey (player->userinfo, key, value, sizeof(player->userinfo));
InfoBuf_SetValueForStarKey (&player->userinfo, key, value);
CL_ProcessUserInfo (slot, player);
}
}
@ -7871,7 +7903,7 @@ void CLNQ_ParseServerMessage (void)
strcpy(cl.players[i].name, MSG_ReadString());
if (*cl.players[i].name)
cl.players[i].userid = i+1;
Info_SetValueForKey(cl.players[i].userinfo, "name", cl.players[i].name, sizeof(cl.players[i].userinfo));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "name", cl.players[i].name);
if (!cl.nqplayernamechanged)
cl.nqplayernamechanged = realtime+2;
@ -7901,9 +7933,9 @@ void CLNQ_ParseServerMessage (void)
// cl.players[i].rbottomcolor = (a&0xf0)>>4;
// sprintf(cl.players[i].team, "%2d", cl.players[i].rbottomcolor);
Info_SetValueForKey(cl.players[i].userinfo, "topcolor", va("%i", a&0x0f), sizeof(cl.players[i].userinfo));
Info_SetValueForKey(cl.players[i].userinfo, "bottomcolor", va("%i", (a&0xf0)>>4), sizeof(cl.players[i].userinfo));
Info_SetValueForKey(cl.players[i].userinfo, "team", va("%i", (a&0xf0)>>4), sizeof(cl.players[i].userinfo));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "topcolor", va("%i", a&0x0f));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "bottomcolor", va("%i", (a&0xf0)>>4));
InfoBuf_SetValueForKey(&cl.players[i].userinfo, "team", va("%i", (a&0xf0)>>4));
CL_ProcessUserInfo (i, &cl.players[i]);
// CLNQ_CheckPlayerIsSpectator(i);

View File

@ -544,7 +544,7 @@ static qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const q
out->activetime = realtime - cl.players[i].realentertime;
out->userid = cl.players[i].userid;
out->spectator = cl.players[i].spectator;
Q_strncpyz(out->userinfo, cl.players[i].userinfo, sizeof(out->userinfo));
InfoBuf_ToString(&cl.players[i].userinfo, out->userinfo, sizeof(out->userinfo), basicuserinfos, NULL, NULL, NULL, NULL);
Q_strncpyz(out->team, cl.players[i].team, sizeof(out->team));
}
@ -589,7 +589,7 @@ static qintptr_t VARGS Plug_GetServerInfo(void *offset, quintptr_t mask, const q
if (VM_OOB(arg[0], outlen))
return false;
Q_strncpyz(outptr, cl.serverinfo, outlen);
InfoBuf_ToString(&cl.serverinfo, outptr, outlen, NULL, NULL, NULL, NULL, NULL);
Q_strncatz(outptr, va("\\intermission\\%i", cl.intermissionmode), outlen);
switch(cls.demoplayback)
{

View File

@ -1769,7 +1769,7 @@ void SCR_DrawGameClock(void)
flags = (show_gameclock.value-1);
if (flags & 1)
timelimit = 60 * atof(Info_ValueForKey(cl.serverinfo, "timelimit"));
timelimit = 60 * atof(InfoBuf_ValueForKey(&cl.serverinfo, "timelimit"));
else
timelimit = 0;

View File

@ -664,7 +664,7 @@ void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font)
snprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
in.c = COM_LoadTempFile(name, &sz);
in.c = COM_LoadTempFile(name, 0, &sz);
if (sz == sizeof(fontInfo_t))
{
for(i=0; i<GLYPHS_PER_FONT; i++)

View File

@ -114,7 +114,7 @@ typedef struct
short gravity;
short delta_angles[3]; // add to command angles to get view direction
// changed by spawns, rotating objects, and teleporters
short pad;
// short pad;
} q2pmove_state_t;
typedef struct
@ -156,11 +156,11 @@ typedef struct colourised_s {
#define MAX_DISPLAYEDNAME 16
typedef struct player_info_s
{
int userid;
char userinfo[EXTENDED_INFO_STRING];
qboolean userinfovalid; //set if we actually know the userinfo (ie: false on vanilla nq servers)
char teamstatus[128];
float teamstatustime;
int userid;
infobuf_t userinfo;
qboolean userinfovalid; //set if we actually know the userinfo (ie: false on vanilla nq servers)
char teamstatus[128];
float teamstatustime;
// scoreboard information
int spectator;
@ -474,8 +474,6 @@ typedef struct
int protocol_q2;
qboolean resendinfo;
qboolean findtrack;
int framecount;
@ -487,8 +485,8 @@ typedef struct
netchan_t netchan;
float lastarbiatarypackettime; //used to mark when packets were sent to prevent mvdsv servers from causing us to disconnect.
// private userinfo for sending to masterless servers
char userinfo[MAX_SPLITS][EXTENDED_INFO_STRING];
infobuf_t userinfo[MAX_SPLITS];
infosync_t userinfosync;
char servername[MAX_OSPATH]; // name of server from original connect
@ -757,7 +755,7 @@ typedef struct
qboolean stillloading; // set when doing something slow, and the game is still loading.
qboolean haveserverinfo; //nq servers will usually be false. don't override stuff if we already know better.
char serverinfo[MAX_SERVERINFO_STRING];
infobuf_t serverinfo;
char serverpaknames[1024];
char serverpakcrcs[1024];
qboolean serverpakschanged;
@ -899,6 +897,7 @@ typedef struct
qboolean gamedirchanged;
#ifdef Q2CLIENT
char q2airaccel[16];
char q2statusbar[1024];
char q2layout[MAX_SPLITS][1024];
int parse_entities;
@ -1089,7 +1088,7 @@ void CL_Reconnect_f (void);
void CL_ConnectionlessPacket (void);
qboolean CL_DemoBehind(void);
void CL_SaveInfo(vfsfile_t *f);
void CL_SetInfo (int pnum, char *key, char *value);
void CL_SetInfo (int pnum, const char *key, const char *value);
void CL_BeginServerConnect(const char *host, int port, qboolean noproxy);
char *CL_TryingToConnect(void);
@ -1197,7 +1196,7 @@ void CL_BaseMove (usercmd_t *cmd, int pnum, float priortime, float extratime);
int Master_FindBestRoute(char *server, char *out, size_t outsize, int *directcost, int *chainedcost);
float CL_KeyState (kbutton_t *key, int pnum, qboolean noslowstart);
char *Key_KeynumToString (int keynum, int modifier);
const char *Key_KeynumToString (int keynum, int modifier);
int Key_StringToKeynum (const char *str, int *modifier);
char *Key_GetBinding(int keynum, int bindmap, int modifier);
void Key_GetBindMap(int *bindmaps);
@ -1688,7 +1687,7 @@ void Stats_NewMap(void);
void Stats_Clear(void);
void Stats_Init(void);
enum uploadfmt;
//enum uploadfmt;
/*struct mediacallbacks_s
{ //functions provided by the engine/renderer, for faster/off-thread updates
qboolean pbocanoffthread;

View File

@ -107,7 +107,7 @@ sfx_t *S_PrecacheSexedSound(int entnum, const char *soundname)
{ //a 'sexed' sound
if (entnum > 0 && entnum <= MAX_CLIENTS)
{
char *model = Info_ValueForKey(cl.players[entnum-1].userinfo, "skin");
char *model = InfoBuf_ValueForKey(&cl.players[entnum-1].userinfo, "skin");
char *skin;
skin = strchr(model, '/');
if (skin)
@ -2140,7 +2140,7 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.model=NULL;
player = &cl.players[(s1->skinnum&0xff)%MAX_CLIENTS];
modelname = Info_ValueForKey(player->userinfo, "skin");
modelname = InfoBuf_ValueForKey(&player->userinfo, "skin");
if (!modelname[0])
modelname = "male";
skin = strchr(modelname, '/');

View File

@ -513,7 +513,7 @@ qboolean CLQ3_SystemInfoChanged(char *str)
value = "baseq3";
COM_Gamedir(value, NULL);
#ifndef CLIENTONLY
Info_SetValueForStarKey (svs.info, "*gamedir", value, MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey (&svs.info, "*gamedir", value);
#endif
}
@ -899,12 +899,6 @@ void CLQ3_SendCmd(usercmd_t *cmd)
usercmd_t *to, *from;
extern int keycatcher;
if (cls.resendinfo)
{
cls.resendinfo = false;
CLQ3_SendClientCommand("userinfo \"%s\"", cls.userinfo[0]);
}
//reuse the q1 array
cmd->servertime = cl.servertime*1000;
cmd->weapon = ccs.selected_weapon;
@ -1044,19 +1038,23 @@ void CLQ3_SendAuthPacket(netadr_t *gameserver)
void CLQ3_SendConnectPacket(netadr_t *to, int challenge, int qport)
{
char infostr[1024];
char data[2048];
char adrbuf[MAX_ADR_SIZE];
sizebuf_t msg;
static const char *nonq3[] = {"challenge", "qport", "protocol", "ip", "chat", NULL};
memset(&ccs, 0, sizeof(ccs));
InfoBuf_ToString(&cls.userinfo[0], infostr, sizeof(infostr), basicuserinfos, nonq3, NULL, &cls.userinfosync, &cls.userinfo[0]);
cl.splitclients = 1;
msg.data = data;
msg.cursize = 0;
msg.overflowed = msg.allowoverflow = 0;
msg.maxsize = sizeof(data);
MSG_WriteLong(&msg, -1);
MSG_WriteString(&msg, va("connect \"\\challenge\\%i\\qport\\%i\\protocol\\%i\\ip\\%s%s\"", challenge, qport, PROTOCOL_VERSION_Q3, NET_AdrToString (adrbuf, sizeof(adrbuf), &net_local_cl_ipadr), cls.userinfo[0]));
MSG_WriteString(&msg, va("connect \"\\challenge\\%i\\qport\\%i\\protocol\\%i\\ip\\%s%s\"", challenge, qport, PROTOCOL_VERSION_Q3, NET_AdrToString (adrbuf, sizeof(adrbuf), &net_local_cl_ipadr), infostr));
#ifdef HUFFNETWORK
Huff_EncryptPacket(&msg, 12);
if (!Huff_CompressionCRC(HUFFCRC_QUAKE3))

View File

@ -1440,15 +1440,16 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
for (i = 0; i < c->num; i++)
{
int col = (con_commandmatch == i+1)?3:2;
s = (conchar_t*)(con->completionline+1);
//note: if cl_chatmode is 0, then we shouldn't show the leading /, however that is how the console link stuff recognises it as command text, so we always display it.
cmd = c->completions[i].text;
// desc = c->completions[i].desc;
// if (desc)
// end = COM_ParseFunString((COLOR_GREEN<<CON_FGSHIFT), va("^[^2/%s\\tip\\%s^]\t", cmd, desc), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true);
// end = COM_ParseFunString((COLOR_GREEN<<CON_FGSHIFT), va("^[^%i/%s\\tip\\%s^]\t", col, cmd, desc), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true);
// else
end = COM_ParseFunString((COLOR_GREEN<<CON_FGSHIFT), va("^[^2/%s^]\t", cmd), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true);
end = COM_ParseFunString((COLOR_GREEN<<CON_FGSHIFT), va("^[^%i/%s^]\t", col, cmd), s+con->completionline->length, (con->completionline->maxlength-con->completionline->length)*sizeof(maskedtext[0]), true);
con->completionline->length = end - s;
}
if (c->extra)
@ -2645,7 +2646,7 @@ void Con_DrawConsole (int lines, qboolean noback)
size_t fsize;
char *buf;
shader->defaulttextures->base = Image_CreateTexture(key, NULL, IF_NOREPLACE|IF_PREMULTIPLYALPHA);
if ((buf = COM_LoadFile (key, 5, &fsize)))
if ((buf = FS_LoadMallocFile (key, &fsize)))
Image_LoadTextureFromMemory(shader->defaulttextures->base, shader->defaulttextures->base->flags|IF_NOWORKER, key, key, buf, fsize);
}
shader->width = shader->defaulttextures->base->width;

View File

@ -618,7 +618,7 @@ static void Stats_LoadFragFile(char *name)
strcpy(filename, name);
COM_DefaultExtension(filename, ".dat", sizeof(filename));
file = COM_LoadTempFile(filename, NULL);
file = COM_LoadTempFile(filename, 0, NULL);
if (!file || !*file)
{
Con_DPrintf("Couldn't load %s\n", filename);

View File

@ -2801,7 +2801,7 @@ void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips)
VFS_CLOSE(file);
}
static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize)
static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
{
static const char magic[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};
ktxheader_t *header;
@ -3038,7 +3038,7 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, char *fn
#endif
#ifdef IMAGEFMT_PKM
static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize)
static struct pendingtextureinfo *Image_ReadPKMFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
{
struct pendingtextureinfo *mips;
unsigned int encoding, blockbytes;
@ -3157,7 +3157,7 @@ typedef struct {
unsigned int miscflags2;
} dds10header_t;
static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize)
static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
{
int nummips;
int mipnum;
@ -3362,7 +3362,7 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, char *fn
#endif
#ifdef IMAGEFMT_BLP
static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, char *fname, qbyte *filedata, size_t filesize)
static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize)
{
//FIXME: cba with endian.
int miplevel;
@ -6212,7 +6212,7 @@ static qboolean Image_LoadRawTexture(texid_t tex, unsigned int flags, void *rawd
#if 1
//always frees filedata, even on failure.
//also frees the textures fallback data, but only on success
static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname, char *fname, qbyte *filedata, int filesize)
static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname, const char *fname, qbyte *filedata, int filesize)
{
qboolean hasalpha;
qbyte *rgbadata;
@ -6267,7 +6267,7 @@ static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char
COM_FileExtension(fname, ext, sizeof(ext));
Q_strncatz(aname, "_alpha.", sizeof(aname));
Q_strncatz(aname, ext, sizeof(aname));
if (!strchr(aname, ':') && (alph = COM_LoadFile (aname, 5, &alphsize)))
if (!strchr(aname, ':') && (alph = FS_LoadMallocFile (aname, &alphsize)))
{
if ((alphadata = Read32BitImageFile(alph, alphsize, &alpha_width, &alpha_height, &hasalpha, aname)))
{
@ -6324,7 +6324,7 @@ static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char
//always frees filedata, even on failure.
//also frees the textures fallback data, but only on success
qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, char *fname, qbyte *filedata, int filesize)
qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, const char *fname, qbyte *filedata, int filesize)
{
struct pendingtextureinfo *mips = Image_LoadMipsFromMemory(flags, iname, fname, filedata, filesize);
if (mips)
@ -6406,7 +6406,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname,
COM_FileExtension(fname, ext, sizeof(ext));
Q_strncatz(aname, "_alpha.", sizeof(aname));
Q_strncatz(aname, ext, sizeof(aname));
if (!strchr(aname, ':') && (alph = COM_LoadFile (aname, 5, &alphsize)))
if (!strchr(aname, ':') && (alph = FS_LoadMallocFile (aname, &alphsize)))
{
if ((alphadata = Read32BitImageFile(alph, alphsize, &alpha_width, &alpha_height, &hasalpha, aname)))
{
@ -6465,7 +6465,7 @@ qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname,
}
#endif
struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, char *subpath, unsigned int texflags)
static struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, char *subpath, unsigned int texflags)
{
static struct
{
@ -6529,12 +6529,12 @@ struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicename, ch
for (j = 0; j < countof(cmscheme); j++)
{
Q_snprintfz(fname+prefixlen, sizeof(fname)-prefixlen, "%s_%s%s", nicename, cmscheme[j][i].suffix, tex_extensions[e].name);
buf = COM_LoadFile(fname, 5, &filesize);
buf = FS_LoadMallocFile(fname, &filesize);
if (buf)
break;
Q_snprintfz(fname+prefixlen, sizeof(fname)-prefixlen, "%s%s%s", nicename, cmscheme[j][i].suffix, tex_extensions[e].name);
buf = COM_LoadFile(fname, 5, &filesize);
buf = FS_LoadMallocFile(fname, &filesize);
if (buf)
break;
}
@ -6592,7 +6592,7 @@ nextface:;
return mips;
}
static qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *bestname, size_t bestnamesize, unsigned int *bestflags)
qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *bestname, size_t bestnamesize, unsigned int *bestflags)
{
char fname[MAX_QPATH], nicename[MAX_QPATH];
int i, e;
@ -6827,8 +6827,6 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
int imgheight;
qboolean alphaed;
// Sys_Sleep(0.3);
if ((tex->flags & IF_TEXTYPE) == IF_CUBEMAP)
{ //cubemaps require special handling because they are (normally) 6 files instead of 1.
//the exception is single-file dds cubemaps, but we don't support those.
@ -6963,7 +6961,7 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t
if (Image_LoadTextureFromMemory(tex, tex->flags, tex->ident, fname, buf, fsize))
{
BZ_Free(tex->fallbackdata);
tex->fallbackdata = NULL;
tex->fallbackdata = NULL;
return;
}
}
@ -7057,7 +7055,10 @@ static image_t *Image_CreateTexture_Internal (const char *identifier, const char
tex->next = imagelist;
imagelist = tex;
tex->flags = flags;
if ((vid.flags & VID_SRGBAWARE) && !(flags & IF_NOSRGB))
tex->flags = flags | IF_SRGB; //guess...
else
tex->flags = flags;
tex->width = 0;
tex->height = 0;
tex->regsequence = r_regsequence;
@ -7597,7 +7598,7 @@ texid_t R_LoadBumpmapTexture(const char *name, const char *subpath)
TRACE(("dbg: Mod_LoadBumpmapTexture: opening %s\n", fname));
if ((buf = COM_LoadFile (fname, 5, &fsize)))
if ((buf = FS_LoadMallocFile (fname, &fsize)))
{
if ((data = ReadTargaFile(buf, fsize, &image_width, &image_height, &hasalpha, 2))) //Only load a greyscale image.
{

View File

@ -455,7 +455,7 @@ void Key_UpdateCompletionDesc(void)
}
}
void CompleteCommand (qboolean force)
void CompleteCommand (qboolean force, int direction)
{
const char *cmd, *s;
const char *desc;
@ -535,7 +535,9 @@ void CompleteCommand (qboolean force)
}
}
con_commandmatch++;
con_commandmatch += direction;
if (con_commandmatch <= 0)
con_commandmatch += c->num;
Key_UpdateCompletionDesc();
}
@ -1695,14 +1697,15 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
Cbuf_AddText("\nvid_toggle\n", RESTRICT_LOCAL);
#endif
if (con_commandmatch)
if ((con_commandmatch && !strchr(key_lines[edit_line], ' ')) || shift)
{ //if that isn't actually a command, and we can actually complete it to something, then lets try to complete it.
char *txt = key_lines[edit_line];
if (*txt == '/')
txt++;
if (!Cmd_IsCommand(txt) && Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL))
if ((shift||!Cmd_IsCommand(txt)) && Cmd_CompleteCommand(txt, true, true, con_commandmatch, NULL))
{
CompleteCommand (true);
CompleteCommand (true, 1);
return true;
}
Con_Footerf(con, false, "");
@ -1723,6 +1726,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
key_lines[edit_line] = BZ_Malloc(1);
key_lines[edit_line][0] = '\0';
key_linepos = 0;
con_commandmatch = 0;
return true;
}
@ -1733,21 +1737,21 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
txt++;
if (Cmd_CompleteCommand(txt, true, true, con->commandcompletion, NULL))
{
CompleteCommand (true);
CompleteCommand (true, 1);
return true;
}
}
if (key == K_TAB)
{ // command completion
if (shift)
if (ctrl&&shift)
{
Con_CycleConsole();
return true;
}
if (con->commandcompletion)
CompleteCommand (ctrl);
CompleteCommand (ctrl, shift?-1:1);
return true;
}
@ -1802,9 +1806,29 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
if (rkey != '`' || key_linepos==0)
return false;
}
if (con_commandmatch)
con_commandmatch = 1;
Key_EntryLine(&key_lines[edit_line], 0, &key_linepos, key, unicode);
{ //if they're typing, try to retain the current completion guess.
cmd_completion_t *c;
char *txt = key_lines[edit_line];
char *guess = Cmd_CompleteCommand(*txt=='/'?txt+1:txt, true, true, con_commandmatch, NULL);
Key_EntryLine(&key_lines[edit_line], 0, &key_linepos, key, unicode);
if (guess)
{
guess = Z_StrDup(guess);
txt = key_lines[edit_line];
c = Cmd_Complete(*txt=='/'?txt+1:txt, true);
for (con_commandmatch = c->num; con_commandmatch > 1; con_commandmatch--)
{
if (!strcmp(guess, c->completions[con_commandmatch-1].text))
break;
}
Z_Free(guess);
}
}
else
Key_EntryLine(&key_lines[edit_line], 0, &key_linepos, key, unicode);
return true;
}
@ -1999,9 +2023,9 @@ static char *Key_KeynumToStringRaw (int keynum)
return "<UNKNOWN KEYNUM>";
}
char *Key_KeynumToString (int keynum, int modifier)
const char *Key_KeynumToString (int keynum, int modifier)
{
char *r = Key_KeynumToStringRaw(keynum);
const char *r = Key_KeynumToStringRaw(keynum);
if (r[0] == '<' && r[1])
modifier = 0; //would be too weird.
switch(modifier)

View File

@ -567,7 +567,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
int y = ypos+option->common.posy;
int keys[8], keymods[countof(keys)];
int keycount;
char *keyname;
const char *keyname;
int j;
Draw_FunStringWidth(x, y, option->bind.caption, option->bind.captionwidth, true, !menu->cursoritem && menu->selecteditem == option);

View File

@ -1390,7 +1390,7 @@ void Media_LoadTrackNames (char *listname)
char *trackname;
mediatrack_t *newtrack;
size_t fsize;
char *data = COM_LoadTempFile(listname, &fsize);
char *data = COM_LoadTempFile(listname, FSLF_IGNOREPURE, &fsize);
loadedtracknames=true;
@ -3210,13 +3210,16 @@ static void QDECL capture_avi_video(void *vctx, int frame, void *vdata, int stri
qbyte *data, *in, *out;
int x, y;
if (stride < 0) //if stride is negative, then its bottom-up, but the data pointer is at the start of the buffer (rather than 'first row')
vdata = (char*)vdata - stride*(height-1);
//we need to output a packed bottom-up bgr image.
//switch the input from logically top-down to bottom-up (regardless of the physical ordering of its rows)
//switch the input from logical-top-down to bottom-up (regardless of the physical ordering of its rows)
in = (qbyte*)vdata + stride*(height-1);
stride = -stride;
if (fmt == TF_BGR24 && stride == width*3)
if (fmt == TF_BGR24 && stride == width*-3)
{ //no work needed!
data = in;
}

View File

@ -76,7 +76,7 @@ static shader_t *MN_CachePic(const char *picname)
{
return R2D_SafeCachePic(picname);
}
static qboolean MN_DrawGetImageSize(void *pic, int *w, int *h)
static qboolean MN_DrawGetImageSize(struct shader_s *pic, int *w, int *h)
{
return R_GetShaderSizes(pic, w, h, true)>0;
}
@ -234,8 +234,8 @@ static void MN_RenderScene(menuscene_t *scene)
ent.keynum = i;
ent.model = scene->entlist[i].model;
VectorCopy(e->matrix[0], ent.axis[0]); ent.origin[0] = e->matrix[0][3];
VectorCopy(e->matrix[1], ent.axis[1]); ent.origin[1] = e->matrix[0][7];
VectorCopy(e->matrix[2], ent.axis[2]); ent.origin[2] = e->matrix[0][11];
VectorCopy(e->matrix[1], ent.axis[1]); ent.origin[1] = e->matrix[1][3];
VectorCopy(e->matrix[2], ent.axis[2]); ent.origin[2] = e->matrix[2][3];
ent.scale = 1;
ent.framestate.g[FS_REG].frame[0] = e->frame[0];
@ -263,8 +263,8 @@ static void MN_RenderScene(menuscene_t *scene)
}
VectorCopy(scene->viewmatrix[0], r_refdef.viewaxis[0]); r_refdef.vieworg[0] = scene->viewmatrix[0][3];
VectorCopy(scene->viewmatrix[1], r_refdef.viewaxis[1]); r_refdef.vieworg[1] = scene->viewmatrix[0][7];
VectorCopy(scene->viewmatrix[2], r_refdef.viewaxis[2]); r_refdef.vieworg[2] = scene->viewmatrix[0][11];
VectorCopy(scene->viewmatrix[1], r_refdef.viewaxis[1]); r_refdef.vieworg[1] = scene->viewmatrix[1][3];
VectorCopy(scene->viewmatrix[2], r_refdef.viewaxis[2]); r_refdef.vieworg[2] = scene->viewmatrix[2][3];
r_refdef.viewangles[0] = -(atan2(r_refdef.viewaxis[0][2], sqrt(r_refdef.viewaxis[0][1]*r_refdef.viewaxis[0][1]+r_refdef.viewaxis[0][0]*r_refdef.viewaxis[0][0])) * 180 / M_PI);
r_refdef.viewangles[1] = (atan2(r_refdef.viewaxis[0][1], r_refdef.viewaxis[0][0]) * 180 / M_PI);

View File

@ -763,7 +763,7 @@ const char *presetexec[] =
"seta gl_polyblend 0;"
"seta gl_flashblend 0;"
"seta gl_specular 0;"
"seta r_deluxmapping 0;"
"seta r_deluxemapping 0;"
"seta r_loadlit 0;"
"seta r_fastsky 1;"
"seta r_drawflame 0;"
@ -893,12 +893,12 @@ const char *presetexec[] =
"r_shadow_realtime_dlight 1;"
// "gl_detail 1;"
"r_lightstylesmooth 1;"
"r_deluxmapping 2;"
"r_deluxemapping 2;"
"gl_texture_anisotropic_filtering 4;"
, // realtime options
"r_bloom 1;"
"r_deluxmapping 0;" //won't be seen anyway
"r_deluxemapping 0;" //won't be seen anyway
"r_particledesc \"high tsshaft\";"
"r_waterstyle 3;"
"r_glsl_offsetmapping 1;"
@ -959,7 +959,7 @@ void M_Menu_Preset_f (void)
#else
bias = 1;
#endif
if (r_deluxmapping_cvar.ival)
if (r_deluxemapping_cvar.ival)
item = 2; //nice
else if (gl_load24bit.ival)
item = 3; //normal
@ -1571,7 +1571,7 @@ void M_Menu_Lighting_f (void)
#endif
MB_COMBOCVAR("Lightmap Format", r_lightmap_format, lightmapformatopts, lightmapformatvalues, "Selects which format to use for lightmaps."),
MB_COMBOCVAR("LIT Loading", r_loadlits, loadlitopts, loadlitvalues, "Determines if the engine should use external colored lighting for maps. The generated setting will cause the engine to generate colored lighting for maps that don't have the associated data."),
MB_COMBOCVAR("Deluxmapping", r_deluxmapping_cvar, loadlitopts, loadlitvalues, "Controls whether static lighting should respond to lighting directions."),
MB_COMBOCVAR("Deluxemapping", r_deluxemapping_cvar, loadlitopts, loadlitvalues, "Controls whether static lighting should respond to lighting directions."),
MB_CHECKBOXCVAR("Lightstyle Lerp", r_lightstylesmooth, 0),
MB_SPACING(4),
MB_COMBOCVAR("Flash Blend", r_flashblend, fbopts, fbvalues, "Disables or enables the spherical light effect for dynamic lights. Traced means the sphere effect will be line of sight checked before displaying the effect."),

View File

@ -385,7 +385,7 @@ typedef enum backendmode_e
typedef struct rendererinfo_s {
char *description;
char *name[4];
char *name[5];
r_qrenderer_t rtype;
//FIXME: all but the vid stuff really should be filled in by the video code, simplifying system-specific stuff.

View File

@ -1531,7 +1531,7 @@ void QCBUILTIN PF_R_PolygonBegin(pubprogfuncs_t *prinst, struct globalvars_s *pr
}
else
twod = qcflags & DRAWFLAG_2D;
if ((qcflags & 3) == DRAWFLAG_ADD)
beflags = BEF_NOSHADOWS|BEF_FORCEADDITIVE;
else
@ -2053,7 +2053,7 @@ nogameaccess:
break;
}
}
static uploadfmt_t PR_TranslateTextureFormat(int qcformat)
uploadfmt_t PR_TranslateTextureFormat(int qcformat)
{
switch(qcformat)
{
@ -2291,7 +2291,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
break;
case VF_ENVMAP:
Q_strncpyz(r_refdef.nearenvmap.texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_sourcecolour));
Q_strncpyz(r_refdef.nearenvmap.texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.nearenvmap.texname));
BE_RenderToTextureUpdate2d(false);
break;
@ -3694,13 +3694,13 @@ static const char *PF_cs_serverkey_internal(const char *keyname)
#ifndef CLIENTONLY
if (sv.state >= ss_loading)
{
ret = Info_ValueForKey(svs.info, keyname);
ret = InfoBuf_ValueForKey(&svs.info, keyname);
if (!*ret)
ret = Info_ValueForKey(localinfo, keyname);
ret = InfoBuf_ValueForKey(&svs.localinfo, keyname);
}
else
#endif
ret = Info_ValueForKey(cl.serverinfo, keyname);
ret = InfoBuf_ValueForKey(&cl.serverinfo, keyname);
}
return ret;
}
@ -3810,7 +3810,7 @@ static const char *PF_cs_getplayerkey_internal (unsigned int pnum, const char *k
#endif
else
{
ret = Info_ValueForKey(cl.players[pnum].userinfo, keyname);
ret = InfoBuf_ValueForKey(&cl.players[pnum].userinfo, keyname);
}
return ret;
}
@ -3834,6 +3834,34 @@ static void QCBUILTIN PF_cs_serverkeyfloat (pubprogfuncs_t *prinst, struct globa
else
G_FLOAT(OFS_RETURN) = (prinst->callargc >= 2)?G_FLOAT(OFS_PARM1):0;
}
static void QCBUILTIN PF_cs_serverkeyblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *keyname = PR_GetStringOfs(prinst, OFS_PARM0);
int qcptr = G_INT(OFS_PARM1);
int qcsize = G_INT(OFS_PARM2);
void *ptr;
size_t blobsize = 0;
const char *blob;
if (qcptr < 0 || qcptr+qcsize >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_cs_serverkeyblob: invalid pointer\n");
return;
}
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
blob = InfoBuf_BlobForKey(&cl.serverinfo, keyname, &blobsize);
if (qcptr)
{
blobsize = min(blobsize, qcsize);
memcpy(ptr, blob, blobsize);
G_INT(OFS_RETURN) = blobsize;
}
else
G_INT(OFS_RETURN) = blobsize;
}
//string(float pnum, string keyname)
static void QCBUILTIN PF_cs_getplayerkeystring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -3883,6 +3911,50 @@ static void QCBUILTIN PF_cs_getplayerkeyfloat (pubprogfuncs_t *prinst, struct gl
else
G_FLOAT(OFS_RETURN) = (prinst->callargc >= 3)?G_FLOAT(OFS_PARM2):0;
}
static void QCBUILTIN PF_cs_getplayerkeyblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int pnum = G_FLOAT(OFS_PARM0);
const char *keyname = PR_GetStringOfs(prinst, OFS_PARM1);
int qcptr = G_INT(OFS_PARM2);
int qcsize = G_INT(OFS_PARM3);
void *ptr;
if (pnum < 0)
{
if (csqc_resortfrags)
{
Sbar_SortFrags(true, false);
csqc_resortfrags = false;
}
if (pnum >= -scoreboardlines)
{//sort by
pnum = fragsort[-(pnum+1)];
}
}
if (qcptr < 0 || qcptr+qcsize >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_cs_getplayerkeyblob: invalid pointer\n");
return;
}
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
if ((unsigned int)pnum >= (unsigned int)cl.allocated_client_slots)
G_INT(OFS_RETURN) = 0;
else
{
size_t blobsize = 0;
const char *blob = InfoBuf_BlobForKey(&cl.players[pnum].userinfo, keyname, &blobsize);
if (qcptr)
{
blobsize = min(blobsize, qcsize);
memcpy(ptr, blob, blobsize);
G_INT(OFS_RETURN) = blobsize;
}
else
G_INT(OFS_RETURN) = blobsize;
}
}
static void QCBUILTIN PF_cs_infokey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -6092,6 +6164,7 @@ static struct {
{"abort", PF_Abort, 211}, //#211 void() abort (FTE_MULTITHREADED)
// {"sleep", PF_Fixme, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
{"forceinfokey", PF_NoCSQC, 213},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"forceinfokeyblob", PF_NoCSQC, 0},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"chat", PF_NoCSQC, 214},//{"chat", PF_chat, 0, 0, 0, 214},// #214 void(string filename, float starttag, entity edict) SV_Chat (FTE_NPCCHAT)
{"particle2", PF_cs_particle2, 215}, //215 (FTE_PEXT_HEXEN2)
@ -6296,7 +6369,8 @@ static struct {
{"runstandardplayerphysics",PF_cs_runplayerphysics, 347}, // #347 void() runstandardplayerphysics (EXT_CSQC)
{"getplayerkeyvalue", PF_cs_getplayerkeystring, 348}, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
{"getplayerkeyfloat", PF_cs_getplayerkeyfloat, 0}, // #348 string(float playernum, string keyname) getplayerkeyvalue
{"getplayerkeyfloat", PF_cs_getplayerkeyfloat, 0}, // #348 string(float playernum, string keyname) getplayerkeyvalue
{"getplayerkeyblob", PF_cs_getplayerkeyblob, 0}, // #0 int(float playernum, string keyname, optional void *outptr, int size) getplayerkeyblob
{"isdemo", PF_cl_playingdemo, 349}, // #349 float() isdemo (EXT_CSQC)
//350
@ -6309,6 +6383,7 @@ static struct {
{"serverkey", PF_cs_serverkey, 354}, // #354 string(string key) serverkey;
{"serverkeyfloat", PF_cs_serverkeyfloat, 0}, // #0 float(string key) serverkeyfloat;
{"serverkeyblob", PF_cs_serverkeyblob, 0},
{"getentitytoken", PF_cs_getentitytoken, 355}, // #355 string() getentitytoken;
{"findfont", PF_CL_findfont, 356},
{"loadfont", PF_CL_loadfont, 357},
@ -6618,6 +6693,7 @@ static struct {
{"setbindmaps", PF_cl_SetBindMap, 632},
{"digest_hex", PF_digest_hex, 639},
{"digest_ptr", PF_digest_ptr, 0},
{"V_CalcRefdef", PF_V_CalcRefdef, 640},
{NULL}
@ -6901,9 +6977,11 @@ void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(v
char newname[MAX_QPATH];
snprintf(newname, MAX_QPATH, "csprogsvers/%x.dat", csprogs_checksum);
//we can use FSLF_IGNOREPURE because we have our own hashes/size checks instead.
//this should make it slightly easier for server admins
if (csprogs_checksum)
{
file = COM_LoadTempFile (newname, sz);
file = COM_LoadTempFile (newname, FSLF_IGNOREPURE, sz);
if (file)
{
if (cls.protocol == CP_NETQUAKE && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
@ -6921,7 +6999,7 @@ void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(v
if (!file)
{
file = COM_LoadTempFile (path, sz);
file = COM_LoadTempFile (path, FSLF_IGNOREPURE, sz);
if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum
{
@ -6956,7 +7034,7 @@ void *PDECL CSQC_PRLoadFile (const char *path, unsigned char *(PDECL *buf_get)(v
}
}
else
file = COM_LoadTempFile (path, sz);
file = COM_LoadTempFile (path, 0, sz);
if (file)
{
@ -7137,7 +7215,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
csqc_mayread = false;
csqc_singlecheats = cls.demoplayback;
cheats = Info_ValueForKey(cl.serverinfo, "*cheats");
cheats = InfoBuf_ValueForKey(&cl.serverinfo, "*cheats");
if (!Q_strcasecmp(cheats, "ON") || atoi(cheats))
csqc_singlecheats = true;
#ifndef CLIENTONLY
@ -7353,7 +7431,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks
str = (string_t*)PR_FindGlobal(csqcprogs, "mapname", 0, NULL);
if (str)
{
char *s = Info_ValueForKey(cl.serverinfo, "map");
char *s = InfoBuf_ValueForKey(&cl.serverinfo, "map");
if (!*s)
s = cl.model_name[1];
if (!*s)

View File

@ -711,7 +711,8 @@ void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *p
int width = G_INT(OFS_PARM1);
int height = G_INT(OFS_PARM2);
int src = G_INT(OFS_PARM3); //ptr
int size = width * height * 4;
int size = (prinst->callargc > 4)?G_INT(OFS_PARM4):(width * height * 4);
uploadfmt_t format = (prinst->callargc > 5)?PR_TranslateTextureFormat(G_INT(OFS_PARM5)):TF_RGBA32;
void *imgptr;
texid_t tid;
@ -735,11 +736,30 @@ void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *p
if (!TEXVALID(tid))
tid = Image_CreateTexture(imagename, NULL, RT_IMAGEFLAGS);
Image_Upload(tid, TF_RGBA32, imgptr, NULL, width, height, RT_IMAGEFLAGS);
tid->width = width;
tid->height = height;
G_INT(OFS_RETURN) = 1;
if (!format)
{
void *data = BZ_Malloc(size);
memcpy(data, imgptr, size);
G_INT(OFS_RETURN) = Image_LoadTextureFromMemory(tid, tid->flags, tid->ident, imagename, data, size);
}
else
{
unsigned int blockbytes, blockwidth, blockheight;
//get format info
Image_BlockSizeForEncoding(format, &blockbytes, &blockwidth, &blockheight);
//round up as appropriate
blockwidth = ((width+blockwidth-1)/blockwidth)*blockwidth;
blockheight = ((height+blockheight-1)/blockheight)*blockheight;
if (size != blockwidth*blockheight*blockbytes)
G_INT(OFS_RETURN) = 0; //size isn't right. which means the pointer might be invalid too.
else
{
Image_Upload(tid, format, imgptr, NULL, width, height, RT_IMAGEFLAGS);
tid->width = width;
tid->height = height;
G_INT(OFS_RETURN) = 1;
}
}
}
//warning: not threadable. hopefully noone abuses it.
@ -2152,6 +2172,9 @@ static struct {
//unproject 310
//project 311
{"r_uploadimage", PF_CL_uploadimage, 0},
{"r_readimage", PF_CL_readimage, 0},
{"print_csqc", PF_print, 339},
{"keynumtostring_csqc", PF_cl_keynumtostring, 340},
@ -2317,6 +2340,7 @@ static struct {
{"crypto_getmykeyfp", PF_crypto_getmykeyfp, 636},
{"crypto_getmyidfp", PF_crypto_getmyidfp, 637},
{"digest_hex", PF_digest_hex, 639},
{"digest_ptr", PF_digest_ptr, 0},
{"crypto_getmyidstatus", PF_crypto_getmyidfp, 641},
{NULL}
};

View File

@ -4293,7 +4293,7 @@ TRACE(("dbg: Surf_NewMap: tp\n"));
void Surf_PreNewMap(void)
{
r_loadbumpmapping = r_deluxmapping || r_glsl_offsetmapping.ival;
r_loadbumpmapping = r_deluxemapping || r_glsl_offsetmapping.ival;
#ifdef RTLIGHTS
r_loadbumpmapping |= r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival;
#endif

View File

@ -447,7 +447,8 @@ image_t *Image_CreateTexture(const char *identifier, const char *subpath, unsign
image_t *QDECL Image_GetTexture (const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt);
qboolean Image_UnloadTexture(image_t *tex); //true if it did something.
void Image_DestroyTexture (image_t *tex);
qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, char *fname, qbyte *filedata, int filesize); //intended really for worker threads, but should be fine from the main thread too
qboolean Image_LoadTextureFromMemory(texid_t tex, int flags, const char *iname, const char *fname, qbyte *filedata, int filesize); //intended really for worker threads, but should be fine from the main thread too
qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *bestname, size_t bestnamesize, unsigned int *bestflags);
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags);
void Image_Purge(void); //purge any textures which are not needed any more (releases memory, but doesn't give null pointers).
void Image_Init(void);
@ -626,8 +627,8 @@ extern cvar_t r_telestyle;
extern cvar_t r_dynamic;
extern cvar_t r_novis;
extern cvar_t r_netgraph;
extern cvar_t r_deluxmapping_cvar;
extern qboolean r_deluxmapping;
extern cvar_t r_deluxemapping_cvar;
extern qboolean r_deluxemapping;
extern cvar_t r_softwarebanding_cvar;
extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar;

View File

@ -120,7 +120,7 @@ cvar_t r_wireframe = CVARFD ("r_wireframe", "0",
CVAR_CHEAT, "Developer feature where everything is drawn with wireframe over the top. Only active where cheats are permitted.");
cvar_t r_wireframe_smooth = CVAR ("r_wireframe_smooth", "0");
cvar_t r_refract_fbo = CVARD ("r_refract_fbo", "1", "Use an fbo for refraction. If 0, just renders as a portal and uses a copy of the current framebuffer.");
cvar_t r_refractreflect_scale = CVARD ("r_refractreflect_scale", "0.5", "Use a different scale for refraction and reflection. Because $reasons.");
cvar_t r_refractreflect_scale = CVARD ("r_refractreflect_scale", "0.5", "Use a different scale for refraction and reflection texturemaps. Because $reasons.");
cvar_t gl_miptexLevel = CVAR ("gl_miptexLevel", "0");
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0");
@ -344,9 +344,9 @@ cvar_t gl_ati_truform_type = CVAR ("gl_ati_truform_type", "1");
cvar_t r_tessellation_level = CVAR ("r_tessellation_level", "5");
cvar_t gl_blend2d = CVAR ("gl_blend2d", "1");
cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them");
cvar_t r_deluxmapping_cvar = CVARAFD ("r_deluxemapping", "0", "r_glsl_deluxemapping",
cvar_t r_deluxemapping_cvar = CVARAFD ("r_deluxemapping", "1", "r_glsl_deluxemapping",
CVAR_ARCHIVE|CVAR_RENDERERLATCH, "Enables bumpmapping based upon precomputed light directions.\n0=off\n1=use if available\n2=auto-generate (if possible)");
qboolean r_deluxmapping;
qboolean r_deluxemapping;
cvar_t r_shaderblobs = CVARD ("r_shaderblobs", "0", "If enabled, can massively accelerate vid restarts / loading (especially with the d3d renderer). Can cause issues when upgrading engine versions, so this is disabled by default.");
cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed.");
cvar_t gl_conback = CVARFCD ("gl_conback", "",
@ -529,7 +529,7 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES);
Cvar_Register (&r_deluxmapping_cvar, GRAPHICALNICETIES);
Cvar_Register (&r_deluxemapping_cvar, GRAPHICALNICETIES);
#ifdef R_XFLIP
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
@ -1464,7 +1464,7 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
if (host_basepal)
Z_Free(host_basepal);
host_basepal = BZ_Malloc(768);
pcx = COM_LoadTempFile("pics/colormap.pcx", &sz);
pcx = COM_LoadTempFile("pics/colormap.pcx", 0, &sz);
if (!pcx || !ReadPCXPalette(pcx, sz, host_basepal))
{
memcpy(host_basepal, default_quakepal, 768);
@ -1522,7 +1522,7 @@ TRACE(("dbg: R_ApplyRenderer: vid applied\n"));
R_GenPaletteLookup();
r_softwarebanding = false;
r_deluxmapping = false;
r_deluxemapping = false;
r_lightprepass = false;
W_LoadWadFile("gfx.wad");

View File

@ -346,7 +346,7 @@ char *Get_Q2ConfigString(int i)
if (i >= Q2CS_SOUNDS && i < Q2CS_SOUNDS + Q2MAX_SOUNDS)
return cl.sound_name [i-Q2CS_SOUNDS];
if (i == Q2CS_AIRACCEL)
return "4";
return cl.q2airaccel;
if (i >= Q2CS_PLAYERSKINS && i < Q2CS_GENERAL+Q2MAX_GENERAL)
return cl.configstring_general[i-Q2CS_PLAYERSKINS]?cl.configstring_general[i-Q2CS_PLAYERSKINS]:"";
//#define Q2CS_LIGHTS (Q2CS_IMAGES +Q2MAX_IMAGES)
@ -465,7 +465,7 @@ void Sbar_ExecuteLayoutString (char *s, int seat)
Draw_FunString (x+32, y+16, va("Ping: %i", ping));
Draw_FunString (x+32, y+24, va("Time: %i", time));
p = R2D_SafeCachePic(va("players/%s_i.pcx", Info_ValueForKey(cl.players[value].userinfo, "skin")));
p = R2D_SafeCachePic(va("players/%s_i.pcx", InfoBuf_ValueForKey(&cl.players[value].userinfo, "skin")));
if (!p || !R_GetShaderSizes(p, NULL, NULL, false)) //display a default if the icon couldn't be found.
p = R2D_SafeCachePic("players/male/grunt_i.pcx");
R2D_ScalePic (x, y, 32, 32, p);
@ -3289,7 +3289,7 @@ ping time frags name
#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},NOFILL)
#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},NOFILL)
#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},NOFILL)
#define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(Info_ValueForKey(s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL)
#define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(InfoBuf_ValueForKey(&s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL)
//columns are listed here in display order
@ -3519,7 +3519,7 @@ if (showcolumns & (1<<COLUMN##title)) \
{
int background_color;
// Electro's scoreboard eyecandy: red vs blue are common teams, force the colours
Q_strncpyz (team, Info_ValueForKey(s->userinfo, "team"), sizeof(team));
Q_strncpyz (team, InfoBuf_ValueForKey(&s->userinfo, "team"), sizeof(team));
if (S_Voip_Speaking(k))
background_color = 0x00ff00;

View File

@ -181,6 +181,7 @@ typedef enum uploadfmt
PTI_DEPTH32,
PTI_DEPTH24_8,
//non-native formats (generally requiring weird palettes that are not supported by hardware)
TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/
TF_MIP4_R8, /*8bit 4-mip greyscale image*/
TF_MIP4_SOLID8, /*8bit 4-mip image in default palette*/

View File

@ -49,7 +49,7 @@ char *Skin_FindName (player_info_t *sc)
}
else
{
s = Info_ValueForKey(sc->userinfo, "skin");
s = InfoBuf_ValueForKey(&sc->userinfo, "skin");
if (s && s[0])
Q_strncpyz(name, s, sizeof(name));
else
@ -212,7 +212,7 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
size_t pcxsize;
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", skin->name);
raw = COM_LoadTempFile (name, &pcxsize);
raw = COM_LoadTempFile (name, FSLF_IGNOREPURE, &pcxsize);
if (!raw)
{
//use 24bit skins even if gl_load24bit is failed
@ -223,7 +223,7 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
if (*baseskin.string)
{
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", baseskin.string);
raw = COM_LoadTempFile (name, &pcxsize);
raw = COM_LoadTempFile (name, FSLF_IGNOREPURE, &pcxsize);
}
}
if (!raw)
@ -463,7 +463,7 @@ void Skin_NextDownload (void)
sc = &cl.players[i];
if (!sc->name[0])
continue;
skinname = Info_ValueForKey(sc->userinfo, "skin");
skinname = InfoBuf_ValueForKey(&sc->userinfo, "skin");
slash = strchr(skinname, '/');
if (slash)
{

View File

@ -842,6 +842,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned
}
pitch = (float)chan->rate/(1<<PITCHSHIFT);
pitch = bound(0.5, pitch, 2.0); //openal documents a limit on the allowed range of pitches. clamp to avoid error spam. openal-soft doesn't enforce anything other than it >=0
palSourcef(src, AL_PITCH, pitch);
#ifdef USEEFX

View File

@ -907,7 +907,7 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
else
Q_snprintfz(namebuffer, sizeof(namebuffer), "%s%s", prefixes[pre], name);
data = COM_LoadFile(namebuffer, 5, &filesize);
data = FS_LoadMallocFile(namebuffer, &filesize);
if (data)
break;
COM_FileExtension(namebuffer, orig, sizeof(orig));
@ -917,7 +917,7 @@ static void S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
if (!strcmp(orig, extensions[ex]+1))
continue;
Q_snprintfz(namebuffer, sizeof(namebuffer), "%s%s", altname, extensions[ex]);
data = COM_LoadFile(namebuffer, 5, &filesize);
data = FS_LoadMallocFile(namebuffer, &filesize);
if (data)
{
Con_DPrintf("found a mangled name: %s\n", namebuffer);

View File

@ -2396,7 +2396,6 @@ int global_nCmdShow;
HWND hwnd_dialog;
static const IID qIID_IShellLinkW = {0x000214F9L, 0, 0, {0xc0,0,0,0,0,0,0,0x46}};
static const IID qIID_IPersistFile = {0x0000010BL, 0, 0, {0xc0,0,0,0,0,0,0,0x46}};
#include <shlobj.h>
#if defined(_MSC_VER) && _MSC_VER <= 1200
@ -2764,11 +2763,11 @@ void Win7_TaskListInit(void)
#define UPD_BUILDTYPE "test"
//WARNING: Security comes from the fact that the triptohell.info certificate is hardcoded in the tls code.
//this will correctly detect insecure tls proxies also.
#define UPDATE_URL_ROOT "https://triptohell.info/moodles/"
#define UPDATE_URL_TESTED UPDATE_URL_ROOT "autoup/"
#define UPDATE_URL_NIGHTLY UPDATE_URL_ROOT
#define UPDATE_URL_VERSION "%sversion.txt"
#ifdef NOLEGACY
// #define UPDATE_URL_ROOT "https://triptohell.info/moodles/"
// #define UPDATE_URL_TESTED UPDATE_URL_ROOT "autoup/"
// #define UPDATE_URL_NIGHTLY UPDATE_URL_ROOT
// #define UPDATE_URL_VERSION "%sversion.txt"
/* #ifdef NOLEGACY
#ifdef _WIN64
#define UPDATE_URL_BUILD "%snocompat64/fte" EXETYPE "64.exe"
#else
@ -2780,7 +2779,7 @@ void Win7_TaskListInit(void)
#else
#define UPDATE_URL_BUILD "%swin32/fte" EXETYPE ".exe"
#endif
#endif
#endif*/
#endif
#if defined(SERVERONLY)
@ -3150,6 +3149,7 @@ static BOOL microsoft_accessU(LPCSTR pszFolder, DWORD dwAccessDesired)
#define BFFM_SETOKTEXT (WM_USER + 105) //v6
#define BFFM_SETEXPANDED (WM_USER + 106) //v6
#endif
static const IID qIID_IPersistFile = {0x0000010BL, 0, 0, {0xc0,0,0,0,0,0,0,0x46}};
static WNDPROC omgwtfwhyohwhy;
static LRESULT CALLBACK stoopidstoopidstoopid(HWND w, UINT m, WPARAM wp, LPARAM lp)
@ -4297,6 +4297,8 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
}
}
// FIXME: CreateIconIndirect does NOT understand DPI scaling, and will show a tiny cursor in such cases.
// we should rescale scale by vid_conautoscale etc.
if (scale != 1)
{
int nw,nh;
@ -4363,8 +4365,8 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale
// Create the alpha cursor with the alpha DIB section.
hAlphaCursor = CreateIconIndirect(&ii);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
return hAlphaCursor;
}

View File

@ -393,6 +393,86 @@ void Con_EditorMoveCursor(console_t *con, conline_t *newline, int newoffset, qbo
con->userline = newline;
con->useroffset = newoffset;
}
static conchar_t *Con_Editor_Equals(conchar_t *start, conchar_t *end, const char *match)
{
conchar_t *n;
unsigned int ccode, flags;
for (; start < end; start = n)
{
n = Font_Decode(start, &flags, &ccode);
if (*match)
{
if (ccode != *(unsigned char*)match++)
return NULL;
}
else if (ccode == ' ' || ccode == '\t')
break; //found whitespace after the token, its complete.
else
return NULL;
}
if (*match)
return NULL; //truncated
//and skip any trailing whitespace, because we can.
for (; start < end; start = n)
{
n = Font_Decode(start, &flags, &ccode);
if (ccode == ' ' || ccode == '\t')
continue;
else
break;
}
return start;
}
static conchar_t *Con_Editor_SkipWhite(conchar_t *start, conchar_t *end)
{
conchar_t *n;
unsigned int ccode, flags;
for (; start < end; start = n)
{
n = Font_Decode(start, &flags, &ccode);
if (ccode == ' ' || ccode == '\t')
continue;
else
break;
}
return start;
}
static void Con_Editor_LineChanged_Shader(conline_t *line)
{
static const char *maplines[] = {"map", "clampmap"};
size_t i;
conchar_t *start = (conchar_t*)(line+1), *end = start + line->length, *n;
start = Con_Editor_SkipWhite(start, end);
line->flags &= ~(CONL_BREAKPOINT|CONL_EXECUTION);
for (i = 0; i < countof(maplines); i++)
{
n = Con_Editor_Equals(start, end, maplines[i]);
if (n)
{
char mapname[8192];
char fname[MAX_QPATH];
flocation_t loc;
unsigned int flags;
image_t img;
memset(&img, 0, sizeof(img));
img.ident = mapname;
COM_DeFunString(n, end, mapname, sizeof(mapname), true, true);
if (!Image_LocateHighResTexture(&img, &loc, fname, sizeof(fname), &flags))
line->flags |= CONL_BREAKPOINT;
return;
}
}
}
static void Con_Editor_LineChanged(console_t *con, conline_t *line)
{
if (!Q_strncasecmp(con->name, "scripts/", 8))
Con_Editor_LineChanged_Shader(line);
}
qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
{
extern qboolean keydown[K_MAX];
@ -430,6 +510,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
con->useroffset--;
memmove((conchar_t*)(con->userline+1)+con->useroffset, (conchar_t*)(con->userline+1)+con->useroffset+1, (con->userline->length - con->useroffset)*sizeof(conchar_t));
con->userline->length -= 1;
Con_Editor_LineChanged(con, con->userline);
}
return true;
case K_DEL:
@ -444,6 +525,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
{
memmove((conchar_t*)(con->userline+1)+con->useroffset, (conchar_t*)(con->userline+1)+con->useroffset+1, (con->userline->length - con->useroffset)*sizeof(conchar_t));
con->userline->length -= 1;
Con_Editor_LineChanged(con, con->userline);
}
break;
case K_ENTER: /*split the line into two, selecting the new line*/
@ -553,7 +635,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
// "F12: Go to definition\n"
);
Cbuf_AddText("toggleconsole\n", RESTRICT_LOCAL);
break;
return true;
case K_F2:
/*{
char file[1024];
@ -721,7 +803,10 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key)
if (con->flags & CONF_KEEPSELECTION)
Con_Editor_DeleteSelection(con);
if (Con_InsertConChars(con, con->userline, con->useroffset, c, l))
{
con->useroffset += l;
Con_Editor_LineChanged(con, con->userline);
}
break;
}
return false;
@ -782,6 +867,7 @@ console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
{
static int editorcascade;
console_t *con;
conline_t *l;
con = Con_FindConsole(fname);
if (con)
{
@ -820,7 +906,7 @@ console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
con->redirect = Con_Editor_Key;
con->mouseover = Con_Editor_MouseOver;
con->close = Con_Editor_Close;
con->maxlines = 0x7fffffff; //line limit is effectively unbounded.
con->maxlines = 0x7fffffff; //line limit is effectively unbounded, for a 31-bit process.
if (!newfile)
{
@ -835,6 +921,9 @@ console_t *Con_TextEditor(const char *fname, const char *line, qboolean newfile)
}
VFS_CLOSE(file);
}
for (l = con->oldest; l; l = l->newer)
Con_Editor_LineChanged(con, l);
}
con->display = con->oldest;

View File

@ -96,7 +96,7 @@ static void Validation_Version(void)
{
signed_buffer_t *resp;
resp = Security_Generate_Crc(cl.playerview[0].playernum, cl.players[cl.playerview[0].playernum].userinfo, cl.serverinfo);
resp = NULL;//Security_Generate_Crc(cl.playerview[0].playernum, cl.players[cl.playerview[0].playernum].userinfo, cl.serverinfo);
if (!resp || !resp->buf)
auth = "";
else
@ -186,7 +186,7 @@ void Validation_CheckIfResponse(char *text)
{
signed_buffer_t *resp;
resp = Security_Verify_Response(f_query_client, crc, cl.players[f_query_client].userinfo, cl.serverinfo);
resp = NULL;//Security_Verify_Response(f_query_client, crc, cl.players[f_query_client].userinfo, cl.serverinfo);
if (resp && resp->size && *resp->buf)
Con_Printf(CON_NOTICE "Authentication Successful.\n");

View File

@ -115,23 +115,3 @@ extern unsigned int d_8to24rgbtable[256];
extern unsigned int d_8to24srgbtable[256];
extern unsigned int d_8to24bgrtable[256];
extern unsigned int d_quaketo24srgbtable[256];
#ifdef GLQUAKE
//called when gamma ramps need to be reapplied
qboolean GLVID_ApplyGammaRamps (unsigned int size, unsigned short *ramps);
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette);
// Called at startup to set up translation tables, takes 256 8 bit RGB values
// the palette data will go away after the call, so it must be copied off if
// the video driver will need it again
void GLVID_Crashed(void);
void GLVID_Update (vrect_t *rects);
// flushes the given rectangles from the view buffer to the screen
void GLVID_SwapBuffers(void);
enum uploadfmt;
char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum uploadfmt *fmt);
void GLVID_SetCaption(const char *caption);
#endif

View File

@ -100,7 +100,7 @@ void W_LoadWadFile (char *filename)
if (wad_base)
Z_Free(wad_base);
wad_base = COM_LoadFile (filename, 0, NULL);
wad_base = COM_LoadFile (filename, 0, 0, NULL);
if (!wad_base)
{
wad_numlumps = 0;

View File

@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define WINQUAKE_H
#ifdef _WIN32
void GLVID_Crashed(void);
#if defined(_WIN32) && !defined(WIN32)
#define WIN32 _WIN32

View File

@ -727,7 +727,7 @@ static char *Skin_To_TFSkin (char *myskin)
static char *Macro_TF_Skin (void)
{
return Skin_To_TFSkin(Info_ValueForKey(cl.players[cl.playerview[SP].playernum].userinfo, "skin"));
return Skin_To_TFSkin(InfoBuf_ValueForKey(&cl.players[cl.playerview[SP].playernum].userinfo, "skin"));
}
//Spike: added these:
@ -1485,7 +1485,7 @@ static void TP_LoadLocFile (char *filename, qbool quiet)
Q_snprintfz (fullpath, sizeof(fullpath) - 4, "locs/%s", filename);
COM_DefaultExtension (fullpath, ".loc", sizeof(fullpath));
buf = (char *) COM_LoadTempFile (fullpath, NULL);
buf = (char *) COM_LoadTempFile (fullpath, 0, NULL);
if (!buf)
{
if (!quiet)
@ -3189,19 +3189,19 @@ char *Utils_TF_ColorToTeam(int color)
switch (color)
{
case 13:
if (*(s = Info_ValueForKey(cl.serverinfo, "team1")) || *(s = Info_ValueForKey(cl.serverinfo, "t1")))
if (*(s = InfoBuf_ValueForKey(&cl.serverinfo, "team1")) || *(s = InfoBuf_ValueForKey(&cl.serverinfo, "t1")))
return s;
break;
case 4:
if (*(s = Info_ValueForKey(cl.serverinfo, "team2")) || *(s = Info_ValueForKey(cl.serverinfo, "t2")))
if (*(s = InfoBuf_ValueForKey(&cl.serverinfo, "team2")) || *(s = InfoBuf_ValueForKey(&cl.serverinfo, "t2")))
return s;
break;
case 12:
if (*(s = Info_ValueForKey(cl.serverinfo, "team3")) || *(s = Info_ValueForKey(cl.serverinfo, "t3")))
if (*(s = InfoBuf_ValueForKey(&cl.serverinfo, "team3")) || *(s = InfoBuf_ValueForKey(&cl.serverinfo, "t3")))
return s;
break;
case 11:
if (*(s = Info_ValueForKey(cl.serverinfo, "team4")) || *(s = Info_ValueForKey(cl.serverinfo, "t4")))
if (*(s = InfoBuf_ValueForKey(&cl.serverinfo, "team4")) || *(s = InfoBuf_ValueForKey(&cl.serverinfo, "t4")))
return s;
break;
default:
@ -3343,7 +3343,7 @@ static void TP_FindPoint (void)
name = tp_name_enemy.string;
if (!eyes)
name = va("%s%s%s", name, name[0] ? " " : "", Skin_To_TFSkin(Info_ValueForKey(bestinfo->userinfo, "skin")));
name = va("%s%s%s", name, name[0] ? " " : "", Skin_To_TFSkin(InfoBuf_ValueForKey(&bestinfo->userinfo, "skin")));
}
else
{

View File

@ -725,7 +725,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#if (defined(CSQC_DAT) || !defined(CLIENTONLY)) && defined(PLUGINS) //use ode only if we have a constant world state, and the library is enbled in some form.
#if (defined(CSQC_DAT) || !defined(CLIENTONLY)) && (defined(PLUGINS)||defined(USE_INTERNAL_BULLET)||defined(USE_INTERNAL_ODE)) //use ode only if we have a constant world state, and the library is enbled in some form.
#define USERBE
#endif

View File

@ -2336,7 +2336,7 @@ void Cmd_Complete_End(cmd_completion_t *c)
int QDECL Cmd_Complete_Sort(const void *a, const void *b)
{ //FIXME: its possible that they're equal (eg: filesystem searches). we should strip one in that case, but gah.
const struct cmd_completion_opt_s *c1 = a, *c2 = b;
return strcmp(c1->text, c2->text);
return Q_strcasecmp(c1->text, c2->text);
}
cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens)
{
@ -2351,7 +2351,7 @@ cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens)
qboolean quoted = false;
static cmd_completion_t c;
if (!partial)
{
Cmd_Complete_End(&c);
@ -2725,7 +2725,7 @@ void Cmd_ExecuteString (const char *text, int level)
return; //let the csqc handle it if it wants.
#endif
#if defined(MENU_NATIVECODE)
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, cmd_argv))
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv))
return;
#endif
Cmd_ForwardToServer ();
@ -2890,7 +2890,7 @@ void Cmd_ExecuteString (const char *text, int level)
return; //let the csqc handle it if it wants.
#endif
#if defined(MENU_NATIVECODE)
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, cmd_argv))
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv))
return;
#endif

View File

@ -39,9 +39,9 @@ void Mod_UpdateCRC(void *ctx, void *data, size_t a, size_t b)
{
char st[40];
Q_snprintfz(st, sizeof(st), "%d", (int) a);
if (strcmp(st, Info_ValueForKey(cls.userinfo[0], ctx)))
if (strcmp(st, InfoBuf_ValueForKey(&cls.userinfo[0], ctx)))
{
Info_SetValueForKey (cls.userinfo[0], ctx, st, sizeof(cls.userinfo[0]));
InfoBuf_SetKey(&cls.userinfo[0], ctx, st);
if (cls.state >= ca_connected && (cls.protocol == CP_QUAKEWORLD || (cls.fteprotocolextensions2 & PEXT2_PREDINFO)))
CL_SendClientCommand(true, "setinfo %s %s", (char*)ctx, st);
}
@ -2571,7 +2571,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
size_t fsize;
com_tokentype_t ttype;
Q_snprintfz(fname, sizeof(fname), "%s.framegroups", modelname);
line = file = COM_LoadFile(fname, 5, &fsize);
line = file = FS_LoadMallocFile(fname, &fsize);
if (!file)
return NULL;
while(line && *line)
@ -2650,7 +2650,7 @@ static qboolean Mod_ParseModelEvents(model_t *mod, galiasanimation_t *anims, uns
size_t fsize;
char *line, *file, *eol;
Q_snprintfz(fname, sizeof(fname), "%s.events", modelname);
line = file = COM_LoadFile(fname, 5, &fsize);
line = file = FS_LoadMallocFile(fname, &fsize);
if (!file)
return false;
while(line && *line)
@ -3914,7 +3914,7 @@ int Mod_ReadFlagsFromMD1(char *name, int md3version)
return 0;
}
pinmodel = (dmdl_t *)COM_LoadFile(fname, 5, &fsize);
pinmodel = (dmdl_t *)FS_LoadMallocFile(fname, &fsize);
if (pinmodel)
{
if (fsize >= sizeof(dmdl_t) && LittleLong(pinmodel->ident) == IDPOLYHEADER)
@ -5812,7 +5812,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
COM_StripExtension(mod->name, psaname, sizeof(psaname));
Q_strncatz(psaname, ".psa", sizeof(psaname));
buffer = NULL;//test
psabuffer = COM_LoadFile(psaname, 5, &psasize);
psabuffer = FS_LoadMallocFile(psaname, &psasize);
if (psabuffer)
{
pos = 0;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -362,7 +362,7 @@ void deleetstring(char *result, const char *leet);
extern char com_token[65536];
typedef enum {TTP_UNKNOWN, TTP_STRING, TTP_LINEENDING, TTP_RAWTOKEN, TTP_EOF, TTP_PUNCTUATION} com_tokentype_t;
typedef enum com_tokentype_e {TTP_UNKNOWN, TTP_STRING, TTP_LINEENDING, TTP_RAWTOKEN, TTP_EOF, TTP_PUNCTUATION} com_tokentype_t;
extern com_tokentype_t com_tokentype;
//these cast away the const for the return value.
@ -616,7 +616,7 @@ vfsfile_t *CL_OpenFileInPackage(searchpathfuncs_t *search, char *name);
qboolean CL_ListFilesInPackage(searchpathfuncs_t *search, char *name, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, void *recursioninfo);
qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, size_t *fsize);
qbyte *COM_LoadTempFile (const char *path, size_t *fsize);
qbyte *COM_LoadTempFile (const char *path, unsigned int locateflags, size_t *fsize);
qbyte *COM_LoadTempMoreFile (const char *path, size_t *fsize); //allocates a little bit more without freeing old temp
//qbyte *COM_LoadHunkFile (const char *path);
@ -704,7 +704,7 @@ qbyte *FS_LoadMallocFile (const char *path, size_t *fsize);
qofs_t FS_LoadFile(const char *name, void **file);
void FS_FreeFile(void *file);
qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize);
qbyte *COM_LoadFile (const char *path, unsigned int locateflags, int usehunk, size_t *filesize);
qboolean COM_LoadMapPackFile(const char *name, qofs_t offset);
void COM_FlushTempoaryPacks(void);
@ -724,15 +724,79 @@ unsigned int COM_RemapMapChecksum(struct model_s *model, unsigned int checksum);
#define MAX_INFO_KEY 256
char *Info_ValueForKey (const char *s, const char *key);
void Info_RemoveKey (char *s, const char *key);
char *Info_KeyForNumber (const char *s, int num);
void Info_RemovePrefixedKeys (char *start, char prefix);
void Info_RemoveNonStarKeys (char *start);
void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize);
void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize);
void Info_RemovePrefixedKeys (char *start, char prefix);
void Info_RemoveKey (char *s, const char *key);
char *Info_KeyForNumber (const char *s, int num);
void Info_Print (const char *s, const char *lineprefix);
/*
void Info_RemoveNonStarKeys (char *start);
void Info_Enumerate (const char *s, void *ctx, void(*cb)(void *ctx, const char *key, const char *value));
void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags);
*/
/*
Info Buffers
Keynames are still length limited, and may not contain nulls, but neither restriction applies to values.
Using base64 encoding, we're able to encode problematic chars like quotes and newlines (and nulls).
This allows mods to store image files inside userinfo.
*/
typedef struct
{
struct infokey_s
{
qbyte partial:1; //partial values read as "".
qbyte large:1; //requires partial/encoded transmission
char *name;
size_t size;
size_t buffersize; //to avoid excessive reallocs
char *value;
} *keys;
size_t numkeys;
size_t totalsize; //so we can limit userinfo abuse.
void (*ChangeCB)(void *context, const char *key); //usually calls InfoSync_Add on all the interested parties.
void *ChangeCTX;
} infobuf_t;
typedef struct
{
struct
{
void *context;
char *name;
size_t syncpos; //reset to 0 when dirty.
} *keys;
size_t numkeys;
} infosync_t;
void InfoSync_Remove(infosync_t *sync, size_t k);
void InfoSync_Add(infosync_t *sync, void *context, const char *name);
void InfoSync_Clear(infosync_t *sync); //wipes all memory etc.
void InfoSync_Strip(infosync_t *sync, void *context); //Clears away all infos from that context.
extern const char *basicuserinfos[]; //note: has a leading *
extern const char *privateuserinfos[]; //key names that are not broadcast from the server
qboolean InfoBuf_FindKey (infobuf_t *info, const char *key, size_t *idx);
const char *InfoBuf_KeyForNumber (infobuf_t *info, int num);
const char *InfoBuf_BlobForKey (infobuf_t *info, const char *key, size_t *blobsize);
char *InfoBuf_ReadKey (infobuf_t *info, const char *key, char *outbuf, size_t outsize);
char *InfoBuf_ValueForKey (infobuf_t *info, const char *key);
qboolean InfoBuf_RemoveKey (infobuf_t *info, const char *key);
qboolean InfoBuf_SetKey (infobuf_t *info, const char *key, const char *val); //refuses to set *keys.
qboolean InfoBuf_SetStarKey (infobuf_t *info, const char *key, const char *val);
qboolean InfoBuf_SetStarBlobKey (infobuf_t *info, const char *key, const char *val, size_t valsize);
#define InfoBuf_SetValueForKey InfoBuf_SetKey
#define InfoBuf_SetValueForStarKey InfoBuf_SetStarKey
void InfoBuf_Clear(infobuf_t *info, qboolean all);
void InfoBuf_Clone(infobuf_t *dest, infobuf_t *src);
void InfoBuf_FromString(infobuf_t *info, const char *infostring, qboolean append);
char *InfoBuf_DecodeString(const char *instart, const char *inend, size_t *sz);
qboolean InfoBuf_EncodeString(const char *n, size_t s, char *out, size_t outsize);
size_t InfoBuf_ToString(infobuf_t *info, char *infostring, size_t maxsize, const char **priority, const char **ignore, const char **exclusive, infosync_t *sync, void *synccontext); //_ and * can be used to indicate ALL such keys.
qboolean InfoBuf_SyncReceive (infobuf_t *info, const char *key, size_t keysize, const char *val, size_t valsize, size_t offset, qboolean final);
void InfoBuf_Print(infobuf_t *info, const char *prefix);
void InfoBuf_WriteToFile(vfsfile_t *f, infobuf_t *info, const char *commandname, int cvarflags);
void InfoBuf_Enumerate (infobuf_t *info, void *ctx, void(*cb)(void *ctx, const char *key, const char *value));
void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf);
unsigned int Com_BlockChecksum (const void *buffer, int length);

View File

@ -156,7 +156,7 @@
// Outdated stuff
#define SVRANKING //legacy server-side ranking system.
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
#define SVCHAT //ancient lame builtin to support NPC-style chat...
//#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.

View File

@ -154,6 +154,8 @@
#undef HAVE_MEDIA_ENCODER //capture/capturedemo work.
#undef HAVE_SPEECHTOTEXT //windows speech-to-text thing
//#define USE_INTERNAL_BULLET
#ifdef COMPILE_OPTS
//things to configure qclib, which annoyingly doesn't include this file itself
-DOMIT_QCC //disable the built-in qcc
@ -162,6 +164,10 @@
-DNO_ZLIB //disable zlib
#endif
#ifdef USE_INTERNAL_BULLET //makefile will respond to this by trying to link bullet into the engine itself, instead of as a plugin.
-DLINK_INTERNAL_BULLET
#endif
-DNO_SPEEX //disable static speex
#ifndef BOTLIB_STATIC

View File

@ -784,13 +784,7 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
#ifndef CLIENTONLY
if (var->flags & CVAR_SERVERINFO)
{
// char *old = Info_ValueForKey(svs.info, var->name);
// if (strcmp(old, value)) //only spam the server if it actually changed
{
Info_SetValueForKey (svs.info, var->name, value, MAX_SERVERINFO_STRING);
SV_SendServerInfoChange(var->name, value);
// SV_BroadcastCommand ("fullserverinfo \"%s\"\n", svs.info);
}
InfoBuf_SetKey (&svs.info, var->name, value);
}
#endif
#ifndef SERVERONLY
@ -802,23 +796,10 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
}
if (var->flags & CVAR_USERINFO)
{
char *old = Info_ValueForKey(cls.userinfo[0], var->name);
char *old = InfoBuf_ValueForKey(&cls.userinfo[0], var->name);
if (strcmp(old, value)) //only spam the server if it actually changed
{ //this helps with config execs
Info_SetValueForKey (cls.userinfo[0], var->name, value, sizeof(cls.userinfo[0]));
if (cls.state >= ca_connected)
{
#if defined(Q2CLIENT) || defined(Q3CLIENT)
if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) //q2 just resends the lot. Kinda bad...
{
cls.resendinfo = true;
}
else
#endif
{
CL_SendClientCommand(true, "setinfo \"%s\" \"%s\"\n", var->name, value);
}
}
InfoBuf_SetKey (&cls.userinfo[0], var->name, value);
}
}
#endif

View File

@ -2138,14 +2138,16 @@ Filename are reletive to the quake directory.
Always appends a 0 qbyte to the loaded data.
============
*/
qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize)
qbyte *COM_LoadFile (const char *path, unsigned int locateflags, int usehunk, size_t *filesize)
{
vfsfile_t *f;
qbyte *buf;
qofs_t len;
flocation_t loc;
if (!FS_FLocateFile(path, FSLF_IFFOUND, &loc) || !loc.search)
locateflags &= ~FSLF_DEEPONFAILURE; //disable any flags that can't be supported here
if (!FS_FLocateFile(path, locateflags, &loc) || !loc.search)
return NULL; //wasn't found
if (loc.len > 0x7fffffff) //don't malloc 5000gb sparse files or anything crazy on a 32bit system...
@ -2198,7 +2200,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk, size_t *filesize)
qbyte *FS_LoadMallocFile (const char *path, size_t *fsize)
{
return COM_LoadFile (path, 5, fsize);
return COM_LoadFile (path, 0, 5, fsize);
}
void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize)
@ -2223,13 +2225,13 @@ void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize)
return mem;
}
qbyte *COM_LoadTempFile (const char *path, size_t *fsize)
qbyte *COM_LoadTempFile (const char *path, unsigned int locateflags, size_t *fsize)
{
return COM_LoadFile (path, 2, fsize);
return COM_LoadFile (path, locateflags, 2, fsize);
}
qbyte *COM_LoadTempMoreFile (const char *path, size_t *fsize)
{
return COM_LoadFile (path, 6, fsize);
return COM_LoadFile (path, 0, 6, fsize);
}
// uses temp hunk if larger than bufsize
@ -2241,7 +2243,7 @@ qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, siz
loadbuf = (qbyte *)buffer;
loadsize = bufsize;
buf = COM_LoadFile (path, 4, fsize);
buf = COM_LoadFile (path, 0, 4, fsize);
return buf;
}
@ -2251,7 +2253,7 @@ qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize, siz
qofs_t FS_LoadFile(const char *name, void **file)
{
size_t fsz;
*file = COM_LoadFile (name, 5, &fsz);
*file = FS_LoadMallocFile (name, &fsz);
if (!*file)
return (qofs_t)-1;
return fsz;
@ -3119,8 +3121,8 @@ const gamemode_info_t gamemode_info[] = {
#ifndef NOLEGACY
//cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name
//two quakes - one without extra game dirs which should avoid fuckups from nquake's configs (which screw over cvars that every nq progs.dat depends upon but which the ezquake id1-only less-compatible gamecode ignores).
{"-quake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-netquake", "nq", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-quake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-netquake", "nq", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1"}, "Quake", "https://triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
//quake's mission packs should not be favoured over the base game nor autodetected
//third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content.
//and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity

View File

@ -1,6 +1,44 @@
#include "quakedef.h"
#include "fs.h"
//#define AVAIL_BZLIB
//#define DYNAMIC_BZLIB
#ifdef AVAIL_BZLIB
# include <bzlib.h>
# ifdef DYNAMIC_BZLIB
# ifndef WINAPI
# define WINAPI
# endif
# define BZ2_bzDecompressInit pBZ2_bzDecompressInit
# define BZ2_bzDecompress pBZ2_bzDecompress
# define BZ2_bzDecompressEnd pBZ2_bzDecompressEnd
static int (WINAPI *BZ2_bzDecompressInit)(bz_stream *strm, int verbosity, int small);
static int (WINAPI *BZ2_bzDecompress)(bz_stream* strm);
static int (WINAPI *BZ2_bzDecompressEnd)(bz_stream *strm);
static qboolean BZLIB_LOADED(void)
{
static qboolean tried;
static void *handle;
if (!tried)
{
static dllfunction_t funcs[] =
{
{(void*)&BZ2_bzDecompressInit, "BZ2_bzDecompressInit"},
{(void*)&BZ2_bzDecompress, "BZ2_bzDecompress"},
{(void*)&BZ2_bzDecompressEnd, "BZ2_bzDecompressEnd"},
{NULL, NULL}
};
tried = true;
handle = Sys_LoadLibrary("libbz2", funcs);
}
return handle != NULL;
}
# else
# define BZLIB_LOADED() 1
# endif
#endif
#ifdef AVAIL_ZLIB
# define ZIPCRYPT
@ -504,9 +542,6 @@ vfsfile_t *FS_GZ_WriteFilter(vfsfile_t *outfile, qboolean autoclosefile, qboolea
#ifdef PACKAGE_PK3
typedef struct
@ -520,11 +555,12 @@ typedef struct
unsigned int crc;
unsigned int flags;
} zpackfile_t;
#define ZFL_DEFLATED 1 //need to use zlib
#define ZFL_STORED 2 //direct access is okay
#define ZFL_SYMLINK 4 //file is a symlink
#define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable (usually just means we don't support reading it rather than actually corrupt, but hey).
#define ZFL_WEAKENCRYPT 16 //traditional zip encryption
#define ZFL_DEFLATED (1u<<0) //need to use zlib
#define ZFL_BZIP2 (1u<<1) //bzip2 compression
#define ZFL_STORED (1u<<2) //direct access is okay
#define ZFL_SYMLINK (1u<<3) //file is a symlink
#define ZFL_CORRUPT (1u<<4) //file is corrupt or otherwise unreadable (usually just means we don't support reading it rather than actually corrupt, but hey).
#define ZFL_WEAKENCRYPT (1u<<5) //traditional zip encryption
typedef struct zipfile_s
@ -712,9 +748,12 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
return result;
}
#ifdef AVAIL_ZLIB
struct decompressstate
{
struct decompressstate *(*Reinit)(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc);
qofs_t (*Read)(struct decompressstate *st, qbyte *buffer, qofs_t bytes);
void (*Destroy)(struct decompressstate *st);
zipfile_t *source;
qofs_t cstart; //position of start of data
qofs_t cofs; //current read offset
@ -731,9 +770,16 @@ struct decompressstate
const z_crc_t * crctable;
#endif
#ifdef AVAIL_ZLIB
z_stream strm;
#endif
#ifdef AVAIL_BZLIB
bz_stream bstrm;
#endif
};
#if defined(AVAIL_ZLIB) || defined(AVAIL_BZLIB)
#ifdef ZIPCRYPT
#define CRC32(c, b) ((*(st->crctable+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
@ -791,47 +837,8 @@ static void FSZIP_DecryptBlock(struct decompressstate *st, char *block, size_t b
}
#endif
static struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc)
{
struct decompressstate *st;
if (!ZLIB_LOADED())
{
Con_Printf("zlib not available\n");
return NULL;
}
st = Z_Malloc(sizeof(*st));
st->source = source;
#ifdef ZIPCRYPT
if (password && csize >= 12)
{
char entropy[12];
if (Sys_LockMutex(source->mutex))
{
VFS_SEEK(source->raw, start);
VFS_READ(source->raw, entropy, sizeof(entropy));
Sys_UnlockMutex(source->mutex);
}
if (!FSZIP_SetupCrytoKeys(st, password, entropy, crc))
{
Con_Printf("Invalid password, cannot decrypt %s\n", filename);
Z_Free(st);
return NULL;
}
start += sizeof(entropy);
csize -= sizeof(entropy);
}
#endif
st->cstart = st->cofs = start;
st->cend = start + csize;
st->usize = usize;
st->strm.data_type = Z_UNKNOWN;
qinflateInit2(&st->strm, -MAX_WBITS);
return st;
}
static qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes)
#ifdef AVAIL_ZLIB
static qofs_t FSZIP_Deflate_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes)
{
qboolean eof = false;
int err;
@ -893,11 +900,171 @@ static qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, q
return read;
}
static void FSZIP_Decompress_Destroy(struct decompressstate *st)
static void FSZIP_Deflate_Destroy(struct decompressstate *st)
{
qinflateEnd(&st->strm);
Z_Free(st);
}
static struct decompressstate *FSZIP_Deflate_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc)
{
struct decompressstate *st;
if (!ZLIB_LOADED())
{
Con_Printf("zlib not available\n");
return NULL;
}
st = Z_Malloc(sizeof(*st));
st->Reinit = FSZIP_Deflate_Init;
st->Read = FSZIP_Deflate_Read;
st->Destroy = FSZIP_Deflate_Destroy;
st->source = source;
#ifdef ZIPCRYPT
if (password && csize >= 12)
{
char entropy[12];
if (Sys_LockMutex(source->mutex))
{
VFS_SEEK(source->raw, start);
VFS_READ(source->raw, entropy, sizeof(entropy));
Sys_UnlockMutex(source->mutex);
}
if (!FSZIP_SetupCrytoKeys(st, password, entropy, crc))
{
Con_Printf("Invalid password, cannot decrypt %s\n", filename);
Z_Free(st);
return NULL;
}
start += sizeof(entropy);
csize -= sizeof(entropy);
}
#endif
st->cstart = st->cofs = start;
st->cend = start + csize;
st->usize = usize;
st->strm.data_type = Z_UNKNOWN;
qinflateInit2(&st->strm, -MAX_WBITS);
return st;
}
#endif
#ifdef AVAIL_BZLIB
static qofs_t FSZIP_BZip2_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes)
{
qboolean eof = false;
int err;
qofs_t read = 0;
while(bytes)
{
if (st->readoffset < st->bstrm.total_out_lo32)
{
unsigned int consume = st->bstrm.total_out_lo32-st->readoffset;
if (consume > bytes)
consume = bytes;
memcpy(buffer, st->outbuffer+st->readoffset, consume);
buffer += consume;
bytes -= consume;
read += consume;
st->readoffset += consume;
continue;
}
else if (eof)
break; //no input available, and nothing in the buffers.
st->bstrm.total_out_lo32 = 0;
st->bstrm.total_out_hi32 = 0;
st->bstrm.avail_out = sizeof(st->outbuffer);
st->bstrm.next_out = st->outbuffer;
st->readoffset = 0;
if (!st->bstrm.avail_in)
{
qofs_t sz;
sz = st->cend - st->cofs;
if (sz > sizeof(st->inbuffer))
sz = sizeof(st->inbuffer);
if (sz)
{
//feed it.
if (Sys_LockMutex(st->source->mutex))
{
VFS_SEEK(st->source->raw, st->cofs);
st->bstrm.avail_in = VFS_READ(st->source->raw, st->inbuffer, sz);
Sys_UnlockMutex(st->source->mutex);
}
else
st->bstrm.avail_in = 0;
st->bstrm.next_in = st->inbuffer;
st->cofs += st->bstrm.avail_in;
#ifdef ZIPCRYPT
if (st->encrypted)
FSZIP_DecryptBlock(st, st->inbuffer, st->bstrm.avail_in);
#endif
}
if (!st->bstrm.avail_in)
eof = true;
}
err = BZ2_bzDecompress(&st->bstrm);
if (err == BZ_FINISH_OK)
eof = true;
else if (err < 0)
break;
}
return read;
}
static void FSZIP_BZip2_Destroy(struct decompressstate *st)
{
BZ2_bzDecompressEnd(&st->bstrm);
Z_Free(st);
}
static struct decompressstate *FSZIP_BZip2_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc)
{
struct decompressstate *st;
if (!BZLIB_LOADED())
{
Con_Printf("bzlib not available\n");
return NULL;
}
st = Z_Malloc(sizeof(*st));
st->Reinit = FSZIP_BZip2_Init;
st->Read = FSZIP_BZip2_Read;
st->Destroy = FSZIP_BZip2_Destroy;
st->source = source;
#ifdef ZIPCRYPT
if (password && csize >= 12)
{
char entropy[12];
if (Sys_LockMutex(source->mutex))
{
VFS_SEEK(source->raw, start);
VFS_READ(source->raw, entropy, sizeof(entropy));
Sys_UnlockMutex(source->mutex);
}
if (!FSZIP_SetupCrytoKeys(st, password, entropy, crc))
{
Con_Printf("Invalid password, cannot decrypt %s\n", filename);
Z_Free(st);
return NULL;
}
start += sizeof(entropy);
csize -= sizeof(entropy);
}
#endif
st->cstart = st->cofs = start;
st->cend = start + csize;
st->usize = usize;
BZ2_bzDecompressInit(&st->bstrm, 0, false);
return st;
}
#endif
static vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress)
{ //if they're going to seek on a file in a zip, let's just copy it out
qofs_t cstart = decompress->cstart, csize = decompress->cend - cstart;
@ -906,61 +1073,48 @@ static vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress
struct decompressstate *nc;
qbyte buffer[16384];
vfsfile_t *defer;
struct decompressstate *(*Reinit)(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc) = decompress->Reinit;
zipfile_t *source = decompress->source;
#ifdef ZIPCRYPT //we need to preserve any crypto stuff if we're restarting the stream
qboolean encrypted = decompress->encrypted;
unsigned int cryptkeys[3];
const z_crc_t *crctab = decompress->crctable;
memcpy(cryptkeys, decompress->initialkey, sizeof(cryptkeys));
#endif
defer = FS_OpenTemp();
if (defer)
{
FSZIP_Decompress_Destroy(decompress);
decompress->Destroy(decompress);
decompress = NULL;
nc = FSZIP_Decompress_Init(source, cstart, csize, usize, NULL, NULL, 0);
nc = Reinit(source, cstart, csize, usize, NULL, NULL, 0);
#ifdef ZIPCRYPT
nc->encrypted = encrypted;
nc->crctable = crctab;
memcpy(nc->initialkey, cryptkeys, sizeof(nc->initialkey));
memcpy(nc->cryptkey, cryptkeys, sizeof(nc->cryptkey));
#endif
while (upos < usize)
{
chunk = usize - upos;
if (chunk > sizeof(buffer))
chunk = sizeof(buffer);
if (!FSZIP_Decompress_Read(nc, buffer, chunk))
if (!nc->Read(nc, buffer, chunk))
break;
if (VFS_WRITE(defer, buffer, chunk) != chunk)
break;
upos += chunk;
}
FSZIP_Decompress_Destroy(nc);
nc->Destroy(nc);
return defer;
}
return NULL;
}
#else
struct decompressstate
{
int nothing;
};
struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize, char *filename, char *password, unsigned int crc)
{
return NULL;
}
qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes)
{
return 0;
}
void FSZIP_Decompress_Destroy(struct decompressstate *st)
{
}
vfsfile_t *FSZIP_Decompress_ToTempFile(struct decompressstate *decompress)
{
return NULL;
@ -992,7 +1146,7 @@ static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int byt
if (vfsz->decompress)
{
read = FSZIP_Decompress_Read(vfsz->decompress, buffer, bytestoread);
read = vfsz->decompress->Read(vfsz->decompress, buffer, bytestoread);
}
else if (Sys_LockMutex(vfsz->parent->mutex))
{
@ -1056,7 +1210,7 @@ static qboolean QDECL VFSZIP_Close (struct vfsfile_s *file)
VFS_CLOSE(vfsz->defer);
if (vfsz->decompress)
FSZIP_Decompress_Destroy(vfsz->decompress);
vfsz->decompress->Destroy(vfsz->decompress);
FSZIP_ClosePath(&vfsz->parent->pub);
Z_Free(vfsz);
@ -1131,6 +1285,7 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
return NULL;
}
#ifdef AVAIL_ZLIB
if (flags & ZFL_DEFLATED)
{
#ifdef ZIPCRYPT
@ -1139,7 +1294,7 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
#else
char *password = NULL;
#endif
vfsz->decompress = FSZIP_Decompress_Init(zip, vfsz->startpos, datasize, vfsz->length, pf->name, password, pf->crc);
vfsz->decompress = FSZIP_Deflate_Init(zip, vfsz->startpos, datasize, vfsz->length, pf->name, password, pf->crc);
if (!vfsz->decompress)
{
/*
@ -1150,6 +1305,28 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
return NULL;
}
}
#endif
#ifdef AVAIL_BZLIB
if (flags & ZFL_BZIP2)
{
#ifdef ZIPCRYPT
//FIXME: Cvar_Get is not threadsafe, and nor is accessing the cvar...
char *password = (flags & ZFL_WEAKENCRYPT)?Cvar_Get("fs_zip_password", "thisispublic", 0, "Filesystem")->string:NULL;
#else
char *password = NULL;
#endif
vfsz->decompress = FSZIP_BZip2_Init(zip, vfsz->startpos, datasize, vfsz->length, pf->name, password, pf->crc);
if (!vfsz->decompress)
{
/*
windows explorer tends to use deflate64 on large files, which zlib and thus we, do not support, thus this is a 'common' failure path
this might also trigger from other errors, of course.
*/
Z_Free(vfsz);
return NULL;
}
}
#endif
if (Sys_LockMutex(zip->mutex))
{
@ -1159,7 +1336,7 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
else
{
if (vfsz->decompress)
FSZIP_Decompress_Destroy(vfsz->decompress);
vfsz->decompress->Destroy(vfsz->decompress);
Z_Free(vfsz);
return NULL;
}
@ -1376,9 +1553,15 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo
return false; //FIXME: proper spanned zips fragment compressed data over multiple spans, but we don't support that
if (local.cmethod == 0)
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_STORED;
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_STORED;
#ifdef AVAIL_ZLIB
if (local.cmethod == 8)
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_DEFLATED;
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_DEFLATED;
#endif
#ifdef AVAIL_BZLIB
if (local.cmethod == 12)
return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_BZIP2;
#endif
return false; //some other method that we don't know.
}
@ -1539,13 +1722,12 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce
//2-5: reduce
//6: implode
//7: tokenize
else if (entry->cmethod == 8)
else if (entry->cmethod == 8) //8: deflate
entry->flags |= ZFL_DEFLATED;
//8: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements.
//9: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements.
//10: implode
//12: bzip2
// else if (entry->cmethod == 12)
// entry->flags |= ZFL_BZIP2;
else if (entry->cmethod == 12) //12: bzip2
entry->flags |= ZFL_BZIP2;
// else if (entry->cmethod == 14)
// entry->flags |= ZFL_LZMA;
//19: lz77

View File

@ -3558,18 +3558,20 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
out += (m%loadmodel->lightmaps.merge)*mapsize;
#if 1
//q3bsp has 4-fold overbrights, so if we're not using overbrights then we basically need to scale the values up by 4
//this will require clamping, which can result in oversaturation of channels, meaning discolouration
for(s = 0; s < mapsize; )
{
float scale = (1<<(2-gl_overbright.ival));
float i;
vec3_t l;
l[0] = *in++;
l[1] = *in++;
l[2] = *in++;
i = VectorNormalize(l);
i *= (1<<(2-gl_overbright.ival));
VectorScale(l, scale, l); //it should be noted that this maths is wrong if you're trying to use srgb lightmaps.
i = max(l[0], max(l[1], l[2]));
if (i > 255)
i = 255; //don't oversaturate (clamping results in discolouration, which looks weird)
VectorScale(l, i, l);
VectorScale(l, 255/i, l); //clamp the brightest channel, scaling the others down to retain chromiance.
out[s++] = l[0];
out[s++] = l[1];
out[s++] = l[2];

View File

@ -251,11 +251,13 @@ void SV_LogPlayer(client_t *cl, char *msg)
if (cl->protocol == SCP_BAD)
return; //don't log botclients
snprintf(line, sizeof(line),
"%s\\%s\\%i\\%s\\%s\\%i\\guid\\%s%s\n",
Q_snprintfz(line, sizeof(line)-1,
"%s\\%s\\%i\\%s\\%s\\%i\\guid\\%s",
msg, cl->name, cl->userid,
NET_BaseAdrToString(remote_adr, sizeof(remote_adr), &cl->netchan.remote_address), (cl->realip_status > 0 ? NET_BaseAdrToString(realip_adr, sizeof(realip_adr), &cl->realip) : "??"),
cl->netchan.remote_address.port, cl->guid, cl->userinfo);
cl->netchan.remote_address.port, cl->guid);
InfoBuf_ToString(&cl->userinfo, line+strlen(line), sizeof(line)-1-strlen(line), NULL, NULL, NULL, NULL, NULL);
Q_strncatz(line, "\n", sizeof(line));
Log_String(LOG_PLAYER, line);
}

View File

@ -199,6 +199,7 @@ unsigned int Net_PextMask(int maskset, qboolean fornq)
mask |= PEXT2_VOICECHAT;
#endif
mask |= PEXT2_SETANGLEDELTA;
// mask |= PEXT2_INFOBLOBS;
if (pext_replacementdeltas.ival)
mask |= PEXT2_REPLACEMENTDELTAS;

View File

@ -23,14 +23,15 @@ struct
qintptr_t (*initfunction)(qintptr_t *args);
} staticplugins[] =
{
#if defined(USERBE) && !defined(QUAKETC)
// {"Bullet_internal", Plug_Bullet_Init},
// {"ODE_internal", Plug_ODE_Init},
#if defined(USE_INTERNAL_BULLET)
{"Bullet_internal", Plug_Bullet_Init},
#endif
#if defined(USE_INTERNAL_ODE)
{"ODE_internal", Plug_ODE_Init},
#endif
{NULL}
};
#ifdef GLQUAKE
#include "glquake.h"
#endif

View File

@ -2780,7 +2780,7 @@ void QCBUILTIN PF_callfunction (pubprogfuncs_t *prinst, struct globalvars_s *pr_
void QCBUILTIN PF_loadfromfile (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *filename = PR_GetStringOfs(prinst, OFS_PARM0);
const char *file = COM_LoadTempFile(filename, NULL);
const char *file = COM_LoadTempFile(filename, 0, NULL);
size_t size;
@ -4439,14 +4439,11 @@ void QCBUILTIN PF_crc16 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
G_FLOAT(OFS_RETURN) = QCRC_Block(str, len);
}
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_digest_internal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, const char *hashtype, const void *str, size_t len)
{
const char *hashtype = PR_GetStringOfs(prinst, OFS_PARM0);
const char *str = PF_VarString(prinst, 1, pr_globals);
int digestsize, i;
unsigned char digest[64];
unsigned char hexdig[sizeof(digest)*2+1];
size_t len = strlen(str);
if (!strcmp(hashtype, "MD4"))
{
@ -4487,6 +4484,27 @@ void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
G_INT(OFS_RETURN) = 0;
}
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *hashtype = PR_GetStringOfs(prinst, OFS_PARM0);
const char *str = PF_VarString(prinst, 1, pr_globals);
PF_digest_internal(prinst, pr_globals, hashtype, str, strlen(str));
}
void QCBUILTIN PF_digest_ptr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *hashtype = PR_GetStringOfs(prinst, OFS_PARM0);
int qcptr = G_INT(OFS_PARM1);
int size = G_INT(OFS_PARM2);
if (qcptr < 0 || qcptr+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_digest_ptr: invalid dest\n");
G_INT(OFS_RETURN) = 0;
return;
}
PF_digest_internal(prinst, pr_globals, hashtype, prinst->stringtable + qcptr, size);
}
// #510 string(string in) uri_escape = #510;
void QCBUILTIN PF_uri_escape (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{

View File

@ -356,6 +356,7 @@ void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
void QCBUILTIN PF_strtrim (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_digest_ptr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_edict_for_num (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -501,12 +502,14 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored);
void PR_Common_SaveGame(vfsfile_t *f, pubprogfuncs_t *prinst, qboolean binary);
uploadfmt_t PR_TranslateTextureFormat(int qcformat);
//FIXME
pbool PR_RunWarning (pubprogfuncs_t *ppf, char *error, ...);
/*these are server ones, provided by pr_cmds.c, as required by pr_q1qvm.c*/
int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *value);
int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *value, size_t valsize);
#ifdef VM_Q1
void PR_SV_FillWorldGlobals(world_t *w);
model_t *QDECL SVPR_GetCModel(world_t *w, int modelindex);

View File

@ -73,6 +73,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues.
#define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks.
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding.
#define PEXT2_INFOBLOBS 0x00000080 //serverinfo+userinfo lengths can be MUCH higher (protocol is unbounded, but expect low sanity limits on userinfo), and contain nulls etc.
//EzQuake/Mvdsv extensions
#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding...

View File

@ -8,10 +8,7 @@
typedef struct {
char name[256];
char *data;
int bufferlen;
qofs_t len;
qofs_t ofs;
vfsfile_t *file;
int accessmode;
int owner;
} vm_fopen_files_t;
@ -20,7 +17,6 @@ vm_fopen_files_t vm_fopen_files[MAX_VM_FILES];
qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner)
{
int i;
size_t insize;
if (!handle)
return !!FS_FLocateFile(name, FSLF_IFFOUND, NULL);
@ -28,7 +24,7 @@ qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner)
*handle = 0;
for (i = 0; i < MAX_VM_FILES; i++)
if (!vm_fopen_files[i].data)
if (!vm_fopen_files[i].file)
break;
if (i == MAX_VM_FILES) //too many already open
@ -46,39 +42,27 @@ qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner)
switch (fmode)
{
case VM_FS_READ:
vm_fopen_files[i].data = FS_LoadMallocFile(name, &insize);
vm_fopen_files[i].bufferlen = vm_fopen_files[i].len = insize;
vm_fopen_files[i].ofs = 0;
if (vm_fopen_files[i].data)
break;
else
return -1;
vm_fopen_files[i].file = FS_OpenVFS(name, "rb", FS_GAME);
break;
/*
case VM_FS_APPEND:
case VM_FS_APPEND2:
vm_fopen_files[i].data = FS_LoadMallocFile(name);
vm_fopen_files[i].ofs = vm_fopen_files[i].bufferlen = vm_fopen_files[i].len = com_filesize;
if (vm_fopen_files[i].data)
break;
//fall through
case VM_FS_WRITE:
vm_fopen_files[i].bufferlen = 8192;
vm_fopen_files[i].data = BZ_Malloc(vm_fopen_files[i].bufferlen);
vm_fopen_files[i].len = 0;
vm_fopen_files[i].ofs = 0;
case VM_FS_APPEND_SYNC:
vm_fopen_files[i].file = FS_OpenVFS(name, "ab", FS_GAMEONLY);
break;
case VM_FS_WRITE:
vm_fopen_files[i].file = FS_OpenVFS(name, "wb", FS_GAMEONLY);
break;
*/
default: //bad
return -1;
}
if (!vm_fopen_files[i].file)
return -1;
Q_strncpyz(vm_fopen_files[i].name, name, sizeof(vm_fopen_files[i].name));
vm_fopen_files[i].accessmode = fmode;
vm_fopen_files[i].owner = owner;
*handle = i+1;
return vm_fopen_files[i].len;
return VFS_GETLEN(vm_fopen_files[i].file);
}
void VM_fclose (int fnum, int owner)
@ -91,22 +75,10 @@ void VM_fclose (int fnum, int owner)
if (vm_fopen_files[fnum].owner != owner)
return; //cgs?
if (!vm_fopen_files[fnum].data)
if (!vm_fopen_files[fnum].file)
return; //not open
switch(vm_fopen_files[fnum].accessmode)
{
case VM_FS_READ:
BZ_Free(vm_fopen_files[fnum].data);
break;
case VM_FS_WRITE:
case VM_FS_APPEND:
case VM_FS_APPEND2:
COM_WriteFile(vm_fopen_files[fnum].name, FS_GAMEONLY, vm_fopen_files[fnum].data, vm_fopen_files[fnum].len);
BZ_Free(vm_fopen_files[fnum].data);
break;
}
vm_fopen_files[fnum].data = NULL;
VFS_CLOSE(vm_fopen_files[fnum].file);
vm_fopen_files[fnum].file = NULL;
}
int VM_FRead (char *dest, int quantity, int fnum, int owner)
@ -118,76 +90,68 @@ int VM_FRead (char *dest, int quantity, int fnum, int owner)
if (vm_fopen_files[fnum].owner != owner)
return 0; //cgs?
if (!vm_fopen_files[fnum].data)
if (!vm_fopen_files[fnum].file)
return 0; //not open
if (quantity > vm_fopen_files[fnum].len - vm_fopen_files[fnum].ofs)
quantity = vm_fopen_files[fnum].len - vm_fopen_files[fnum].ofs;
memcpy(dest, vm_fopen_files[fnum].data + vm_fopen_files[fnum].ofs, quantity);
vm_fopen_files[fnum].ofs += quantity;
return quantity;
if (!vm_fopen_files[fnum].file->ReadBytes)
return 0;
return VFS_READ(vm_fopen_files[fnum].file, dest, quantity);
}
int VM_FWrite (const char *dest, int quantity, int fnum, int owner)
{
/*
int fnum = G_FLOAT(OFS_PARM0);
char *msg = PF_VarString(prinst, 1, pr_globals);
int len = strlen(msg);
if (fnum < 0 || fnum >= MAX_QC_FILES)
return; //out of range
fnum--;
if (fnum < 0 || fnum >= MAX_VM_FILES)
return 0; //out of range
if (!pf_fopen_files[fnum].data)
return; //not open
if (vm_fopen_files[fnum].owner != owner)
return 0; //cgs?
if (pf_fopen_files[fnum].prinst != prinst)
return; //this just isn't ours.
if (!vm_fopen_files[fnum].file)
return 0; //not open
if (!vm_fopen_files[fnum].file->WriteBytes)
return 0;
quantity = VFS_WRITE(vm_fopen_files[fnum].file, dest, quantity);
if (pf_fopen_files[fnum].bufferlen < pf_fopen_files[fnum].ofs + len)
{
char *newbuf;
pf_fopen_files[fnum].bufferlen = pf_fopen_files[fnum].bufferlen*2 + len;
newbuf = BZF_Malloc(pf_fopen_files[fnum].bufferlen);
memcpy(newbuf, pf_fopen_files[fnum].data, pf_fopen_files[fnum].len);
BZ_Free(pf_fopen_files[fnum].data);
pf_fopen_files[fnum].data = newbuf;
}
memcpy(pf_fopen_files[fnum].data + pf_fopen_files[fnum].ofs, msg, len);
if (pf_fopen_files[fnum].len < pf_fopen_files[fnum].ofs + len)
pf_fopen_files[fnum].len = pf_fopen_files[fnum].ofs + len;
pf_fopen_files[fnum].ofs+=len;
*/
return 0;
if (vm_fopen_files[fnum].accessmode == VM_FS_APPEND_SYNC)
VFS_FLUSH(vm_fopen_files[fnum].file);
return quantity;
}
qboolean VM_FSeek (int fnum, qofs_t offset, int seektype, int owner)
{
qofs_t fsize;
fnum--;
if (fnum < 0 || fnum >= MAX_VM_FILES)
return false; //out of range
if (vm_fopen_files[fnum].owner != owner)
return false; //cgs?
if (!vm_fopen_files[fnum].data)
if (!vm_fopen_files[fnum].file)
return false; //not open
switch(seektype)
switch(vm_fopen_files[fnum].file->seekstyle)
{
case 0:
offset = vm_fopen_files[fnum].ofs + offset;
case 1:
offset = vm_fopen_files[fnum].len + offset;
break;
default:
case 2:
//offset = 0 + offset;
break;
case SS_SEEKABLE:
case SS_SLOW:
fsize = VFS_GETLEN(vm_fopen_files[fnum].file); //can't cache it if we're writing
switch(seektype)
{
case 0:
offset += VFS_TELL(vm_fopen_files[fnum].file);
return 0;
case 1:
offset += fsize;
break;
default:
case 2:
offset += 0;
break;
}
if (offset > fsize)
return false;
VFS_SEEK(vm_fopen_files[fnum].file, offset);
return true;
case SS_PIPE:
case SS_UNSEEKABLE:
return false;
}
// if (offset < 0)
// offset = 0;
if (offset > vm_fopen_files[fnum].len)
offset = vm_fopen_files[fnum].len;
vm_fopen_files[fnum].ofs = offset;
return true;
return false; //should be unreachable.
}
qofs_t VM_FTell (int fnum, int owner)
{
@ -196,10 +160,10 @@ qofs_t VM_FTell (int fnum, int owner)
return 0; //out of range
if (vm_fopen_files[fnum].owner != owner)
return 0; //cgs?
if (!vm_fopen_files[fnum].data)
if (!vm_fopen_files[fnum].file)
return 0; //not open
return vm_fopen_files[fnum].ofs;
return VFS_TELL(vm_fopen_files[fnum].file);
}
void VM_fcloseall (int owner)
{
@ -370,16 +334,14 @@ int VMQ3_Cvar_Register(q3vmcvar_t *v, char *name, char *defval, int flags)
if ((flags & CVAR_USERINFO) && !(c->flags & CVAR_USERINFO))
{
c->flags |= CVAR_USERINFO;
Info_SetValueForKey(cls.userinfo[0], c->name, c->string, sizeof(cls.userinfo[0]));
cls.resendinfo = true;
InfoBuf_SetKey(&cls.userinfo[0], c->name, c->string);
}
#endif
#ifndef CLIENTONLY
if ((flags & CVAR_SERVERINFO) && !(c->flags & CVAR_SERVERINFO))
{
c->flags |= CVAR_SERVERINFO;
Info_SetValueForKey (svs.info, c->name, c->string, MAX_SERVERINFO_STRING);
SV_SendServerInfoChange(c->name, c->string);
InfoBuf_SetKey (&svs.info, c->name, c->string);
}
#endif
for (i = 0; i < MAX_VMQ3_CVARS; i++)

View File

@ -87,7 +87,7 @@ void Script_Get_File_And_Line(int handle, char *filename, int *line);
#define VM_FS_READ 0
#define VM_FS_WRITE 1
#define VM_FS_APPEND 2
#define VM_FS_APPEND2 3 //I don't know, don't ask me. look at q3 source
#define VM_FS_APPEND_SYNC 3 //I don't know, don't ask me. look at q3 source
qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner);
int VM_FRead (char *dest, int quantity, int fnum, int owner);
int VM_FWrite (const char *dest, int quantity, int fnum, int owner);

View File

@ -1524,7 +1524,7 @@ static qboolean BE_DrawMeshChain_SetupPass(shaderpass_t *pass, unsigned int vert
}
else
Vector4Set(map->colorsb, 255, 255, 255, 255);
VectorCopy(mesh->st_array[i], map->tc[0]);
Vector2Copy(mesh->st_array[i], map->tc[0]);
if (mesh->lmst_array[0])
Vector2Copy(mesh->lmst_array[0][i], map->tc[1]);
}

View File

@ -179,6 +179,7 @@ typedef struct
float m_model[16];
unsigned int lastpasscount;
vbo_t *batchvbo;
program_t *curprog;
shader_t *shader_rtlight;
IDirect3DTexture9 *curtex[MAX_TMUS];
@ -1070,6 +1071,8 @@ static void colourgenbyte(const shaderpass_t *pass, int cnt, byte_vec4_t *srcb,
break;
default:
identity:
case RGB_GEN_UNKNOWN:
case RGB_GEN_IDENTITY_OVERBRIGHT:
case RGB_GEN_IDENTITY:
block = D3DCOLOR_RGBA(255, 255, 255, 255);
while((cnt)--)
@ -1459,6 +1462,11 @@ static void tcmod(const tcmod_t *tcmod, int cnt, const float *src, float *dst, c
break;
default:
for (j = 0; j < cnt; j++, dst+=2,src+=2)
{
dst[0] = src[0];
dst[1] = src[1];
}
break;
}
}
@ -1862,109 +1870,6 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds
}
}
/*does not do the draw call, does not consider indicies (except for billboard generation) */
static qboolean BE_DrawMeshChain_SetupPass(shaderpass_t *pass, unsigned int vertcount)
{
int vdec;
void *map;
int i;
unsigned int passno = 0, tmu;
int lastpass = pass->numMergedPasses;
for (i = 0; i < lastpass; i++)
{
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
break;
}
if (i == lastpass)
return false;
/*all meshes in a chain must have the same features*/
vdec = 0;
/*we only use one colour, generated from the first pass*/
vdec |= BE_GenerateColourMods(vertcount, pass);
tmu = 0;
/*activate tmus*/
for (passno = 0; passno < lastpass; passno++)
{
if (pass[passno].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[passno].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[passno].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
SelectPassTexture(tmu, pass+passno);
vdec |= D3D_VDEC_ST0<<tmu;
if (shaderstate.batchvbo && pass[passno].tcgen == TC_GEN_BASE && !pass[passno].numtcmods)
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.batchvbo->texcoord.d3d.buff, shaderstate.batchvbo->texcoord.d3d.offs, sizeof(vbovdata_t)));
else if (shaderstate.batchvbo && pass[passno].tcgen == TC_GEN_LIGHTMAP && !pass[passno].numtcmods)
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.batchvbo->lmcoord[0].d3d.buff, shaderstate.batchvbo->lmcoord[0].d3d.offs, sizeof(vbovdata_t)));
else if (pass[passno].tcgen == TC_GEN_SKYBOX)
{
vdec |= D3D_VDEC_CM;
allocvertexbuffer(shaderstate.dynst_buff[tmu], shaderstate.dynst_size, &shaderstate.dynst_offs[tmu], &map, vertcount*sizeof(vec3_t));
GenerateTCMods3(pass+passno, map);
d3dcheck(IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[tmu]));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.dynst_buff[tmu], shaderstate.dynst_offs[tmu] - vertcount*sizeof(vec3_t), sizeof(vec3_t)));
}
else
{
allocvertexbuffer(shaderstate.dynst_buff[tmu], shaderstate.dynst_size, &shaderstate.dynst_offs[tmu], &map, vertcount*sizeof(vec2_t));
GenerateTCMods(pass+passno, map);
d3dcheck(IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[tmu]));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.dynst_buff[tmu], shaderstate.dynst_offs[tmu] - vertcount*sizeof(vec2_t), sizeof(vec2_t)));
}
tmu++;
}
/*deactivate any extras*/
for (; tmu < shaderstate.lastpasscount; )
{
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, NULL, 0, 0));
BindTexture(tmu, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_COLOROP, D3DTOP_DISABLE));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
tmu++;
}
shaderstate.lastpasscount = tmu;
// if (meshchain->normals_array &&
// meshchain->2 &&
// meshchain->tnormals_array)
// vdec |= D3D_VDEC_NORMS;
if (vdec != shaderstate.curvertdecl)
{
shaderstate.curvertdecl = vdec;
d3dcheck(IDirect3DDevice9_SetVertexDeclaration(pD3DDev9, vertexdecls[shaderstate.curvertdecl]));
}
BE_ApplyShaderBits(pass->shaderbits);
return true;
}
static void BE_SubmitMeshChain(unsigned int vertbase, unsigned int firstvert, unsigned int vertcount, unsigned int idxfirst, int unsigned idxcount)
{
if (shaderstate.flags & BEF_LINES)
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_LINELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/2);
else
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/3);
RQuantAdd(RQUANT_DRAWS, 1);
RQuantAdd(RQUANT_PRIMITIVEINDICIES, idxcount);
}
static void R_FetchPlayerColour(unsigned int cv, vec3_t rgb)
{
int i;
@ -1997,7 +1902,6 @@ static void R_FetchPlayerColour(unsigned int cv, vec3_t rgb)
*retblue = gammatable[*retblue];
}*/
}
static void BE_ApplyUniforms(program_t *prog, int permu)
{
struct programpermu_s *perm = &prog->permu[permu];
@ -2005,8 +1909,12 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
vec4_t param4;
int h;
int i;
IDirect3DDevice9_SetVertexShader(pD3DDev9, perm->h.hlsl.vert);
IDirect3DDevice9_SetPixelShader(pD3DDev9, perm->h.hlsl.frag);
if (shaderstate.curprog != prog)
{
shaderstate.curprog = prog;
IDirect3DDevice9_SetVertexShader(pD3DDev9, perm->h.hlsl.vert);
IDirect3DDevice9_SetPixelShader(pD3DDev9, perm->h.hlsl.frag);
}
for (i = 0, pp = perm->parm; i < perm->numparms; i++, pp++)
{
h = pp->handle;
@ -2169,6 +2077,208 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
}
}
static unsigned int BE_DrawMeshChain_SetupProgram(program_t *p)
{
unsigned int vdec = 0;
unsigned int perm = 0;
#ifdef SKELETALMODELS
if (shaderstate.batchvbo && shaderstate.batchvbo->numbones)
{
if (p->permu[perm|PERMUTATION_SKELETAL].h.loaded)
perm |= PERMUTATION_SKELETAL;
}
#endif
if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded)
perm |= PERMUTATION_BUMPMAP;
if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded)
perm |= PERMUTATION_FULLBRIGHT;
if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay)))
perm |= PERMUTATION_UPPERLOWER;
if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].h.loaded)
perm |= PERMUTATION_FOG;
#ifdef NONSKELETALMODELS
if (p->permu[perm|PERMUTATION_FRAMEBLEND].h.loaded && shaderstate.batchvbo && shaderstate.batchvbo->coord2.d3d.buff)
{
perm |= PERMUTATION_FRAMEBLEND;
vdec |= D3D_VDEC_POS2;
}
#endif
// if (p->permu[perm|PERMUTATION_DELUXE].h.loaded && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe)
// perm |= PERMUTATION_DELUXE;
#if MAXRLIGHTMAPS > 1
if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded)
perm |= PERMUTATION_LIGHTSTYLES;
#endif
vdec |= D3D_VDEC_COL4B;//BE_GenerateColourMods(vertcount, s->passes);
BE_ApplyUniforms(p, perm);
return vdec;
}
/*does not do the draw call, does not consider indicies (except for billboard generation) */
static qboolean BE_DrawMeshChain_SetupPass(shaderpass_t *pass, unsigned int vertcount)
{
int vdec;
void *map;
int i;
unsigned int passno = 0, tmu;
int lastpass = pass->numMergedPasses;
for (i = 0; i < lastpass; i++)
{
if (pass[i].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[i].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[i].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
break;
}
if (i == lastpass)
return false;
/*all meshes in a chain must have the same features*/
vdec = 0;
/*we only use one colour, generated from the first pass*/
vdec |= BE_GenerateColourMods(vertcount, pass);
if (pass->prog)
{
vdec |= BE_DrawMeshChain_SetupProgram(pass->prog);
tmu = 0;
/*activate tmus*/
for (passno = 0; passno < lastpass; passno++)
{
SelectPassTexture(tmu, pass+passno);
tmu++;
}
/*deactivate any extras*/
for (; tmu < shaderstate.lastpasscount; )
{
BindTexture(tmu, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_COLOROP, D3DTOP_DISABLE));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
tmu++;
}
if (1)
{
vdec |= D3D_VDEC_ST0|D3D_VDEC_ST1;
if (shaderstate.batchvbo)
{
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0, shaderstate.batchvbo->texcoord.d3d.buff, shaderstate.batchvbo->texcoord.d3d.offs, sizeof(vbovdata_t)));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC1, shaderstate.batchvbo->lmcoord[0].d3d.buff, shaderstate.batchvbo->lmcoord[0].d3d.offs, sizeof(vbovdata_t)));
}
else
{
mesh_t *mesh;
unsigned int mno;
float *outtc, *outlm;
allocvertexbuffer(shaderstate.dynst_buff[0], shaderstate.dynst_size, &shaderstate.dynst_offs[0], &map, vertcount*sizeof(vec4_t));
outtc = map;
outlm = outtc + vertcount*2;
for (mno = 0; mno < shaderstate.nummeshes; mno++)
{
mesh = shaderstate.meshlist[mno];
memcpy(outtc, mesh->st_array, sizeof(vec2_t)*mesh->numvertexes);
memcpy(outlm, mesh->lmst_array[0], sizeof(vec2_t)*mesh->numvertexes);
}
d3dcheck(IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[0]));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0, shaderstate.dynst_buff[0], shaderstate.dynst_offs[0] - vertcount*sizeof(vec4_t), sizeof(vec2_t)));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC1, shaderstate.dynst_buff[0], shaderstate.dynst_offs[0] - vertcount*sizeof(vec2_t), sizeof(vec2_t)));
}
shaderstate.lastpasscount = max(2, tmu);
}
}
else
{
if (shaderstate.curprog)
{
shaderstate.curprog = NULL;
IDirect3DDevice9_SetVertexShader(pD3DDev9, NULL);
IDirect3DDevice9_SetPixelShader(pD3DDev9, NULL);
}
tmu = 0;
/*activate tmus*/
for (passno = 0; passno < lastpass; passno++)
{
if (pass[passno].texgen == T_GEN_UPPEROVERLAY && !TEXLOADED(shaderstate.curtexnums->upperoverlay))
continue;
if (pass[passno].texgen == T_GEN_LOWEROVERLAY && !TEXLOADED(shaderstate.curtexnums->loweroverlay))
continue;
if (pass[passno].texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
SelectPassTexture(tmu, pass+passno);
vdec |= D3D_VDEC_ST0<<tmu;
if (shaderstate.batchvbo && pass[passno].tcgen == TC_GEN_BASE/* && !pass[passno].numtcmods*/)
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.batchvbo->texcoord.d3d.buff, shaderstate.batchvbo->texcoord.d3d.offs, sizeof(vbovdata_t)));
else if (shaderstate.batchvbo)// && pass[passno].tcgen == TC_GEN_LIGHTMAP/* && !pass[passno].numtcmods*/)
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.batchvbo->lmcoord[0].d3d.buff, shaderstate.batchvbo->lmcoord[0].d3d.offs, sizeof(vbovdata_t)));
else if (pass[passno].tcgen == TC_GEN_SKYBOX)
{
vdec |= D3D_VDEC_CM;
allocvertexbuffer(shaderstate.dynst_buff[tmu], shaderstate.dynst_size, &shaderstate.dynst_offs[tmu], &map, vertcount*sizeof(vec3_t));
GenerateTCMods3(pass+passno, map);
d3dcheck(IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[tmu]));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.dynst_buff[tmu], shaderstate.dynst_offs[tmu] - vertcount*sizeof(vec3_t), sizeof(vec3_t)));
}
else
{
allocvertexbuffer(shaderstate.dynst_buff[tmu], shaderstate.dynst_size, &shaderstate.dynst_offs[tmu], &map, vertcount*sizeof(vec2_t));
GenerateTCMods(pass+passno, map);
d3dcheck(IDirect3DVertexBuffer9_Unlock(shaderstate.dynst_buff[tmu]));
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, shaderstate.dynst_buff[tmu], shaderstate.dynst_offs[tmu] - vertcount*sizeof(vec2_t), sizeof(vec2_t)));
}
tmu++;
}
/*deactivate any extras*/
for (; tmu < shaderstate.lastpasscount; )
{
d3dcheck(IDirect3DDevice9_SetStreamSource(pD3DDev9, STRM_TC0+tmu, NULL, 0, 0));
BindTexture(tmu, NULL);
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_COLOROP, D3DTOP_DISABLE));
d3dcheck(IDirect3DDevice9_SetTextureStageState(pD3DDev9, tmu, D3DTSS_ALPHAOP, D3DTOP_DISABLE));
tmu++;
}
shaderstate.lastpasscount = tmu;
}
// if (meshchain->normals_array &&
// meshchain->2 &&
// meshchain->tnormals_array)
// vdec |= D3D_VDEC_NORMS;
if (vdec != shaderstate.curvertdecl)
{
shaderstate.curvertdecl = vdec;
d3dcheck(IDirect3DDevice9_SetVertexDeclaration(pD3DDev9, vertexdecls[shaderstate.curvertdecl]));
}
BE_ApplyShaderBits(pass->shaderbits);
return true;
}
static void BE_SubmitMeshChain(unsigned int vertbase, unsigned int firstvert, unsigned int vertcount, unsigned int idxfirst, int unsigned idxcount)
{
if (shaderstate.flags & BEF_LINES)
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_LINELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/2);
else
IDirect3DDevice9_DrawIndexedPrimitive(pD3DDev9, D3DPT_TRIANGLELIST, vertbase, firstvert, vertcount, idxfirst, idxcount/3);
RQuantAdd(RQUANT_DRAWS, 1);
RQuantAdd(RQUANT_PRIMITIVEINDICIES, idxcount);
}
static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned int vertfirst, unsigned int vertcount, unsigned int idxfirst, unsigned int idxcount)
{
int vdec = D3D_VDEC_ST0|D3D_VDEC_ST1|D3D_VDEC_NORM;
@ -2208,7 +2318,7 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in
perm |= PERMUTATION_LIGHTSTYLES;
#endif
vdec |= BE_GenerateColourMods(vertcount, s->passes);
vdec |= D3D_VDEC_COL4B;//BE_GenerateColourMods(vertcount, s->passes);
BE_ApplyUniforms(p, perm);

View File

@ -796,8 +796,6 @@ static qboolean D3D9_VID_Init(rendererstate_t *info, unsigned char *palette)
D3D9_Set2D();
// pD3DX->lpVtbl->GetBufferSize((void*)pD3DX, &width, &height);
vid.pixelwidth = width;
vid.pixelheight = height;
@ -1006,10 +1004,12 @@ static qboolean (D3D9_SCR_UpdateScreen) (void)
if (vid_srgb.modified)
{
vid_srgb.modified = false;
vid.flags &= VID_SRGB_FB;
if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival)
//VID_SRGBAWARE defines whether textures are meant to be srgb or not.
//as it requires a vid_reload, we don't mess with it here.
//that said, we can still change srgb freely otherwise.
vid.flags &= VID_SRGBAWARE;
if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival<0)
vid.flags |= (d3dpp.Windowed)?VID_SRGB_FB_FAKED:VID_SRGB_FB_LINEAR;
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, !!(vid.flags&VID_SRGB_FB_LINEAR));
}
@ -1182,8 +1182,13 @@ static void (D3D9_Draw_Init) (void)
{
{
vid_srgb.modified = false;
vid.flags &= VID_SRGB_FB;
if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival)
//VID_SRGBAWARE defines whether textures are meant to be srgb or not.
//we're doing a vid_reload here, so we can change it here easily enough
if (vid_srgb.ival > 0) //d3d9 does srgb using post-process stuff for us.
vid.flags |= VID_SRGBAWARE;
else
vid.flags = 0;
if ((vid.flags & VID_SRGBAWARE) || vid_srgb.ival<0)
vid.flags |= (d3dpp.Windowed)?VID_SRGB_FB_FAKED:VID_SRGB_FB_LINEAR;
IDirect3DDevice9_SetRenderState(pD3DDev9, D3DRS_SRGBWRITEENABLE, !!(vid.flags&VID_SRGB_FB_LINEAR));
@ -1351,6 +1356,7 @@ rendererinfo_t d3d9rendererinfo =
"D3D",
"Direct3d",
"DirectX",
"2" //this is evil, but worth a laugh.
},
QR_DIRECT3D9,

View File

@ -802,7 +802,7 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
scd.BufferCount = 1+info->triplebuffer; //back buffer count
if (info->srgb)
{
if (info->srgb >= 3) //fixme: detect properly.
if (info->srgb >= 2) //fixme: detect properly.
scd.BufferDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; //on nvidia, outputs linear rgb to srgb devices, which means info->srgb is effectively set
else
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
@ -956,7 +956,7 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
//non-linear formats.
break;
}
if ((vid.flags & VID_SRGB_FB) && info->srgb != 1)
if ((vid.flags & VID_SRGB_FB) && info->srgb >= 0)
vid.flags |= VID_SRGBAWARE;
vid.numpages = scd.BufferCount;

View File

@ -24,7 +24,6 @@ extern cvar_t gl_overbright;
extern cvar_t r_tessellation;
extern cvar_t r_wireframe;
extern cvar_t r_refract_fbo;
extern cvar_t r_refractreflect_scale;
extern texid_t missing_texture;
extern texid_t missing_texture_gloss;
@ -5132,7 +5131,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
if ((bs->flags & SHADER_HASREFLECT) && gl_config.ext_framebuffer_objects)
{
float renderscale = r_refractreflect_scale.value;
float renderscale = bs->portalfboscale;
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
if (!shaderstate.tex_reflection[r_refdef.recurse])
@ -5155,7 +5154,13 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
shaderstate.tex_reflection[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_reflection[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_reflection[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F])
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA8_SRGB])
qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shaderstate.tex_reflection[r_refdef.recurse]->width, shaderstate.tex_reflection[r_refdef.recurse]->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -5177,7 +5182,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
{
if (r_refract_fboival || (bs->flags&SHADER_HASPORTAL))
{
float renderscale = min(1, r_refractreflect_scale.value);
float renderscale = min(1, bs->portalfboscale);
vrect_t ovrect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
r_refdef.vrect.x = 0;
@ -5200,7 +5205,12 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
shaderstate.tex_refraction[r_refdef.recurse]->width = r_refdef.pxrect.width;
shaderstate.tex_refraction[r_refdef.recurse]->height = r_refdef.pxrect.height;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_refraction[r_refdef.recurse]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if ((vid.flags&VID_FP16) && sh_config.texfmt[PTI_RGBA16F])
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else if ((vid.flags&(VID_SRGBAWARE|VID_FP16)) && sh_config.texfmt[PTI_RGBA16F])
qglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8_EXT, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, r_refdef.pxrect.width, r_refdef.pxrect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -5252,7 +5262,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
}
if ((bs->flags & SHADER_HASRIPPLEMAP) && gl_config.ext_framebuffer_objects)
{
float renderscale = r_refractreflect_scale.value;
float renderscale = bs->portalfboscale;
vrect_t orect = r_refdef.vrect;
pxrect_t oprect = r_refdef.pxrect;
r_refdef.vrect.x = 0;

View File

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

View File

@ -1131,7 +1131,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b)
char *buf;
char dollname[MAX_QPATH];
Q_snprintfz(dollname, sizeof(dollname), "%s.doll", mod->name);
buf = COM_LoadFile(dollname, 5, &filesize);
buf = FS_LoadMallocFile(dollname, &filesize);
if (buf)
{
mod->dollinfo = rag_createdollfromstring(mod, dollname, numbones, buf);
@ -1273,7 +1273,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b)
char altname[MAX_QPATH];
Q_snprintfz(altname, sizeof(altname), "%s.%s", mdlbase, token);
TRACE(("Mod_LoadModel: Trying to load (replacement) model \"%s\"\n", altname));
buf = (unsigned *)COM_LoadFile (altname, 5, &filesize);
buf = (unsigned *)FS_LoadMallocFile (altname, &filesize);
if (buf)
Q_strncpyz(mod->name, altname, sizeof(mod->name));
@ -1281,7 +1281,7 @@ static void Mod_LoadModelWorker (void *ctx, void *data, size_t a, size_t b)
else
{
TRACE(("Mod_LoadModel: Trying to load model \"%s\"\n", mod->publicname));
buf = (unsigned *)COM_LoadFile (mod->publicname, 5, &filesize);
buf = (unsigned *)FS_LoadMallocFile (mod->publicname, &filesize);
if (buf)
Q_strncpyz(mod->name, mod->publicname, sizeof(mod->name));
else if (!buf)
@ -1837,7 +1837,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
samples = ql2->lmsize;
litdata = shifts+ql2->numsurfs;
if (r_deluxmapping)
if (r_deluxemapping)
luxdata = litdata+samples*3;
}
}
@ -1906,7 +1906,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
}
if (!luxdata && r_loadlits.ival && r_deluxmapping)
if (!luxdata && r_loadlits.ival && r_deluxemapping)
{ //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous.
char luxname[MAX_QPATH];
size_t luxsz = 0;
@ -1971,14 +1971,14 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
#endif
#ifdef RUNTIMELIGHTING
if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxmapping)))
if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxemapping)))
{
writelitfile = !litdata;
numlightdata = l->filelen;
lightmodel = loadmodel;
relitsurface = 0;
}
else if (!lightmodel && r_deluxmapping_cvar.value>1 && r_deluxmapping && !luxdata
else if (!lightmodel && r_deluxemapping_cvar.value>1 && r_deluxemapping && !luxdata
#ifdef RTLIGHTS
&& !(r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value<=0)
#endif
@ -2008,7 +2008,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
}
}
/*if we're relighting, make sure there's the proper lux data to be updated*/
if (lightmodel == loadmodel && r_deluxmapping && !luxdata)
if (lightmodel == loadmodel && r_deluxemapping && !luxdata)
{
int i;
luxdata = ZG_Malloc(&loadmodel->memgroup, samples*3);

View File

@ -1064,7 +1064,7 @@ qboolean R_LoadRTLights(void)
COM_StripExtension(cl.worldmodel->name, fname, sizeof(fname));
strncat(fname, ".rtlights", MAX_QPATH-1);
file = COM_LoadTempFile(fname, NULL);
file = COM_LoadTempFile(fname, 0, NULL);
if (file)
while(1)
{

View File

@ -1987,7 +1987,7 @@ void GLR_RenderView (void)
}
else if ((r_refdef.flags & (RDF_ALLPOSTPROC)) || forcedfb)
{
unsigned int rtflags = IF_NOMIPMAP|IF_CLAMP|IF_RENDERTARGET;
unsigned int rtflags = IF_NOMIPMAP|IF_CLAMP|IF_RENDERTARGET|IF_NOSRGB;
enum uploadfmt fmt;
r_refdef.flags |= RDF_RENDERSCALE;

View File

@ -321,7 +321,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
else if (!Q_stricmp(token, "lightmap"))
lhs = !r_fullbright.value;
else if (!Q_stricmp(token, "deluxmap") || !Q_stricmp(token, "deluxe"))
lhs = r_deluxmapping;
lhs = r_deluxemapping;
else if (!Q_stricmp(token, "softwarebanding"))
lhs = r_softwarebanding;
@ -374,7 +374,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
// else if (!Q_stricmp(token, "GLSL"))
// lhs = 1;
else if (!Q_stricmp(token, "deluxeMaps") || !Q_stricmp(token, "deluxe"))
lhs = r_deluxmapping;
lhs = r_deluxemapping;
else if (!Q_stricmp(token, "portalMaps"))
lhs = false;
//end qfusion
@ -1149,21 +1149,21 @@ const struct sh_defaultsamplers_s sh_defaultsamplers[] =
{"s_reflectcube", 1u<<9},
{"s_reflectmask", 1u<<10},
{"s_lightmap", 1u<<11},
{"s_deluxmap", 1u<<12},
{"s_deluxemap", 1u<<12},
#if MAXRLIGHTMAPS > 1
{"s_lightmap1", 1u<<13},
{"s_lightmap2", 1u<<14},
{"s_lightmap3", 1u<<15},
{"s_deluxmap1", 1u<<16},
{"s_deluxmap2", 1u<<17},
{"s_deluxmap3", 1u<<18},
{"s_deluxemap1", 1u<<16},
{"s_deluxemap2", 1u<<17},
{"s_deluxemap3", 1u<<18},
#else
{"s_lightmap1", 0},
{"s_lightmap2", 0},
{"s_lightmap3", 0},
{"s_deluxmap1", 0},
{"s_deluxmap2", 0},
{"s_deluxmap3", 0},
{"s_deluxemap1", 0},
{"s_deluxemap2", 0},
{"s_deluxemap3", 0},
#endif
{NULL}
};
@ -1258,6 +1258,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
script += 7;
while (*script != '\n' && *script != '\r')
{
size_t len;
int i;
char *start;
while (*script == ' ' || *script == '\t')
@ -1266,9 +1267,18 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
while (*script != ' ' && *script != '\t' && *script != '\r' && *script != '\n')
script++;
#ifndef NOLEGACY
if (script-start >= 8 && !strncmp(start, "deluxmap", 8))
{ //FIXME: remove this some time.
start = va("deluxemap%s",start+8);
len = strlen(start);
}
else
#endif
len = script-start;
for (i = 0; sh_defaultsamplers[i].name; i++)
{
if (!strncmp(start, sh_defaultsamplers[i].name+2, script-start) && sh_defaultsamplers[i].name[2+script-start] == 0)
if (!strncmp(start, sh_defaultsamplers[i].name+2, len) && sh_defaultsamplers[i].name[2+len] == 0)
{
prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits;
break;
@ -1656,7 +1666,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
permutationdefines[pn++] = "#define RELIEFMAPPING\n";
}
if (r_deluxmapping) //fixme: should be per-model really
if (r_deluxemapping) //fixme: should be per-model really
permutationdefines[pn++] = "#define DELUXE\n";
}
permutationdefines[pn++] = NULL;
@ -1832,7 +1842,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
if (file)
{
Con_DPrintf("Loaded %s from disk\n", sh_config.progpath?va(sh_config.progpath, basicname):basicname);
// Con_DPrintf("Loaded %s from disk\n", sh_config.progpath?va(sh_config.progpath, basicname):basicname);
g->failed = !Shader_LoadPermutations(g->name, &g->prog, file, qrtype, 0, blobname);
FS_FreeFile(file);
return;
@ -1860,6 +1870,18 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
}
}
}
const char *Shader_NameForGeneric(program_t *prog)
{
sgeneric_t *g;
for (g = sgenerics; g; g = g->next)
{
if (prog == &g->prog)
return g->name;
}
return "INLINE";
}
program_t *Shader_FindGeneric(char *name, int qrtype)
{
sgeneric_t *g;
@ -1982,51 +2004,55 @@ struct shader_field_names_s shader_attr_names[] =
struct shader_field_names_s shader_unif_names[] =
{
/**///tagged names are available to vulkan
/*matricies*/
{"m_model", SP_M_MODEL},
{"m_view", SP_M_VIEW},
{"m_modelview", SP_M_MODELVIEW},
{"m_projection", SP_M_PROJECTION},
{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},
{"m_bones", SP_M_ENTBONES},
{"m_invviewprojection", SP_M_INVVIEWPROJECTION},
{"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},
/**/{"m_model", SP_M_MODEL}, //the model matrix
{"m_view", SP_M_VIEW}, //the view matrix
{"m_modelview", SP_M_MODELVIEW},//the combined modelview matrix
{"m_projection", SP_M_PROJECTION},//projection matrix
/**/{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},//fancy mvp matrix. probably has degraded precision.
{"m_bones", SP_M_ENTBONES}, //bone matrix array. should normally be read via sys/skeletal.h
{"m_invviewprojection", SP_M_INVVIEWPROJECTION},//inverted vp matrix
{"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},//inverted mvp matrix.
/**///m_modelinv
/*viewer properties*/
{"v_eyepos", SP_V_EYEPOS},
{"w_fog", SP_W_FOG},
{"w_user", SP_W_USER},
{"v_eyepos", SP_V_EYEPOS}, //eye pos in worldspace
/**/{"w_fog", SP_W_FOG}, //read by sys/fog.h
{"w_user", SP_W_USER}, //set via VF_USERDATA
/*ent properties*/
{"e_vblend", SP_E_VBLEND},
{"e_lmscale", SP_E_LMSCALE}, /*overbright shifting*/
{"e_vlscale", SP_E_VLSCALE}, /*no lightmaps, no overbrights*/
{"e_origin", SP_E_ORIGIN},
{"e_time", SP_E_TIME},
{"e_eyepos", SP_E_EYEPOS},
{"e_colour", SP_E_COLOURS},
{"e_colourident", SP_E_COLOURSIDENT},
{"e_glowmod", SP_E_GLOWMOD},
{"e_uppercolour", SP_E_TOPCOLOURS},
{"e_lowercolour", SP_E_BOTTOMCOLOURS},
{"e_light_dir", SP_E_L_DIR},
{"e_light_mul", SP_E_L_MUL},
{"e_light_ambient", SP_E_L_AMBIENT},
{"e_vblend", SP_E_VBLEND}, //v_position1+v_position2 scalers
/**/{"e_lmscale", SP_E_LMSCALE}, /*overbright shifting*/
{"e_vlscale", SP_E_VLSCALE}, /*no lightmaps, no overbrights*/
{"e_origin", SP_E_ORIGIN}, //the ents origin in worldspace
/**/{"e_time", SP_E_TIME}, //r_refdef.time - entity->time
/**/{"e_eyepos", SP_E_EYEPOS}, //eye pos in modelspace
{"e_colour", SP_E_COLOURS}, //colormod/alpha, even if colormod isn't set
/**/{"e_colourident", SP_E_COLOURSIDENT}, //colormod,alpha or 1,1,1,alpha if colormod isn't set
/**/{"e_glowmod", SP_E_GLOWMOD}, //fullbright scalers (for hdr mostly)
/**/{"e_uppercolour", SP_E_TOPCOLOURS}, //q1 player colours
/**/{"e_lowercolour", SP_E_BOTTOMCOLOURS},//q1 player colours
/**/{"e_light_dir", SP_E_L_DIR}, //lightgrid light dir. dotproducts should be clamped to 0-1.
/**/{"e_light_mul", SP_E_L_MUL}, //lightgrid light scaler.
/**/{"e_light_ambient", SP_E_L_AMBIENT}, //lightgrid light value for the unlit side.
{"s_colour", SP_S_COLOUR},
{"s_colour", SP_S_COLOUR}, //the rgbgen/alphagen stuff. obviously doesn't work with per-vertex ones.
/*rtlight properties, use with caution*/
{"l_lightscreen", SP_LIGHTSCREEN},
{"l_lightradius", SP_LIGHTRADIUS},
{"l_lightcolour", SP_LIGHTCOLOUR},
{"l_lightposition", SP_LIGHTPOSITION},
{"l_lightcolourscale", SP_LIGHTCOLOURSCALE},
{"l_cubematrix", SP_LIGHTCUBEMATRIX},
{"l_shadowmapproj", SP_LIGHTSHADOWMAPPROJ},
{"l_shadowmapscale", SP_LIGHTSHADOWMAPSCALE},
{"l_lightscreen", SP_LIGHTSCREEN}, //screenspace position of the current rtlight
/**/{"l_lightradius", SP_LIGHTRADIUS}, //radius of the current rtlight
/**/{"l_lightcolour", SP_LIGHTCOLOUR}, //rgb values of the current rtlight
/**/{"l_lightposition", SP_LIGHTPOSITION}, //light position in modelspace
/**/{"l_lightcolourscale", SP_LIGHTCOLOURSCALE},//ambient/diffuse/specular scalers
/**/{"l_cubematrix", SP_LIGHTCUBEMATRIX},//matrix used to control the rtlight's cubemap projection
/**/{"l_shadowmapproj", SP_LIGHTSHADOWMAPPROJ}, //compacted projection matrix for shadowmaps
/**/{"l_shadowmapscale", SP_LIGHTSHADOWMAPSCALE},//should probably use a samplerRect instead...
{"e_sourcesize", SP_SOURCESIZE}, //size of VF_SOURCECOLOUR image
{"e_rendertexturescale", SP_RENDERTEXTURESCALE}, //scaler for $currentrender, when npot isn't supported.
{"e_sourcesize", SP_SOURCESIZE},
{"e_rendertexturescale", SP_RENDERTEXTURESCALE},
{NULL}
};
@ -2434,6 +2460,12 @@ static void Shader_Translucent(shader_t *shader, shaderpass_t *pass, char **ptr)
shader->flags |= SHADER_BLEND;
}
static void Shader_PortalFBOScale(shader_t *shader, shaderpass_t *pass, char **ptr)
{
shader->portalfboscale = Shader_ParseFloat(shader, ptr, 0);
shader->portalfboscale = max(shader->portalfboscale, 0);
}
static void Shader_DP_Camera(shader_t *shader, shaderpass_t *pass, char **ptr)
{
shader->sort = SHADER_SORT_PORTAL;
@ -2623,6 +2655,7 @@ static shaderkey_t shaderkeys[] =
{"uppermap", Shader_UpperMap, "fte"},
{"lowermap", Shader_LowerMap, "fte"},
{"reflectmask", Shader_ReflectMask, "fte"},
{"portalfboscale", Shader_PortalFBOScale, "fte"}, //portal/mirror/refraction/reflection FBOs are resized by this scale
/*program stuff at the material level is an outdated practise.*/
{"program", Shader_ProgramName, "fte"}, //usable with any renderer that has a usable shader language...
@ -4087,6 +4120,7 @@ char *Shader_Skip ( char *ptr )
void Shader_Reset(shader_t *s)
{
extern cvar_t r_refractreflect_scale;
char name[MAX_QPATH];
int id = s->id;
int uses = s->uses;
@ -4103,6 +4137,7 @@ void Shader_Reset(shader_t *s)
s->defaulttextures = NULL;
Shader_Free(s);
memset(s, 0, sizeof(*s));
s->portalfboscale = r_refractreflect_scale.value; //unless otherwise specified, this cvar specifies the value.
s->remapto = s;
s->id = id;
@ -6819,15 +6854,42 @@ static qboolean Shader_ParseShader(char *parsename, shader_t *s)
size_t offset = 0, length;
char *buf = NULL;
shadercachefile_t *sourcefile = NULL;
char *file;
const char *token;
//if the named shader is a .shader file then just directly load it.
token = COM_GetFileExtension(parsename, NULL);
if (!strcmp(token, ".shader") || !*token)
{
char shaderfile[MAX_QPATH];
if (!*token)
{
Q_snprintfz(shaderfile, sizeof(shaderfile), "%s.shader", parsename);
file = COM_LoadTempMoreFile(shaderfile, &length);
}
else
file = COM_LoadTempMoreFile(parsename, &length);
if (file)
{
Shader_Reset(s);
token = COM_ParseExt (&file, true, false); //we need to skip over the leading {.
if (*token != '{')
token = COM_ParseExt (&file, true, false); //try again, in case we found some legacy name.
if (*token == '{')
{
Shader_ReadShader(s, file, NULL);
return true;
}
else
Con_Printf("file %s.shader does not appear to contain a shader\n", shaderfile);
}
}
if (Shader_LocateSource(parsename, &buf, &length, &offset, &sourcefile))
{
// the shader is in the shader scripts
if (buf && offset < length )
{
char *file, *token;
file = buf + offset;
token = COM_ParseExt (&file, true, true);
if ( !file || token[0] != '{' )
@ -6974,8 +7036,9 @@ static shader_t *R_LoadShader (const char *name, unsigned int usageflags, shader
}
if (Shader_ParseShader(cleanname, s))
return s;
if (Shader_ParseShader(shortname, s))
return s;
if (strcmp(cleanname, shortname))
if (Shader_ParseShader(shortname, s))
return s;
}
// make a default shader
@ -7045,7 +7108,7 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple)
if (p->prog)
{
sprintf(o, "program\n");
sprintf(o, "program %s\n", Shader_NameForGeneric(p->prog));
o+=strlen(o);
}
@ -7277,7 +7340,7 @@ char *Shader_Decompose(shader_t *s)
if (s->prog)
{
sprintf(o, "program\n");
sprintf(o, "program %s\n", Shader_NameForGeneric(s->prog));
o+=strlen(o);
p = s->passes;
@ -7396,6 +7459,8 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize)
}
}
#endif
saveshaderbody = NULL;
return adr;
}
@ -7526,8 +7591,9 @@ void Shader_DoReload(void)
}
if (Shader_ParseShader(cleanname, s))
continue;
if (Shader_ParseShader(shortname, s))
continue;
if (strcmp(cleanname, shortname))
if (Shader_ParseShader(shortname, s))
continue;
}
if (s->generator)
{
@ -7666,7 +7732,7 @@ void Shader_RemapShader_f(void)
char *destname = Cmd_Argv(2);
float timeoffset = atof(Cmd_Argv(3));
if (!Cmd_FromGamecode() && strcmp(Info_ValueForKey(cl.serverinfo, "*cheats"), "ON"))
if (!Cmd_FromGamecode() && strcmp(InfoBuf_ValueForKey(&cl.serverinfo, "*cheats"), "ON"))
{
Con_Printf("%s may only be used from gamecode, or when cheats are enabled\n", Cmd_Argv(0));
return;

View File

@ -1353,16 +1353,23 @@ static const char *glsl_hdrs[] =
"uniform samplerCube s_reflectcube;"
"uniform sampler2D s_reflectmask;"
"uniform sampler2D s_lightmap;"
"uniform sampler2D s_deluxmap;"
"uniform sampler2D s_deluxemap;"
"\n#define s_lightmap0 s_lightmap\n"
"#define s_deluxmap0 s_deluxmap\n"
"#define s_deluxemap0 s_deluxemap\n"
#if MAXRLIGHTMAPS > 1
"uniform sampler2D s_lightmap1;"
"uniform sampler2D s_lightmap2;"
"uniform sampler2D s_lightmap3;"
"uniform sampler2D s_deluxmap1;"
"uniform sampler2D s_deluxmap2;"
"uniform sampler2D s_deluxmap3;\n"
"uniform sampler2D s_deluxemap1;"
"uniform sampler2D s_deluxemap2;"
"uniform sampler2D s_deluxemap3;\n"
//FIXME: remove these some time.
// "#define s_deluxmap s_deluxemap\n"
// "#define s_deluxmap0 s_deluxemap0\n"
// "#define s_deluxmap1 s_deluxemap1\n"
// "#define s_deluxmap2 s_deluxemap2\n"
// "#define s_deluxmap3 s_deluxemap3\n"
#endif
#endif
"#ifdef USEUBOS\n"
@ -2107,14 +2114,14 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
"uniform samplerCube s_reflectcube;\n",
"uniform sampler2D s_reflectmask;\n",
"uniform sampler2D s_lightmap;\n#define s_lightmap0 s_lightmap\n",
"uniform sampler2D s_deluxmap;\n#define s_deluxmap0 s_deluxmap\n",
"uniform sampler2D s_deluxemap;\n#define s_deluxemap0 s_deluxemap\n",
"uniform sampler2D s_lightmap1;\n",
"uniform sampler2D s_lightmap2;\n",
"uniform sampler2D s_lightmap3;\n",
"uniform sampler2D s_deluxmap1;\n",
"uniform sampler2D s_deluxmap2;\n",
"uniform sampler2D s_deluxmap3;\n",
"uniform sampler2D s_deluxemap1;\n",
"uniform sampler2D s_deluxemap2;\n",
"uniform sampler2D s_deluxemap3;\n",
};
for (i = 0; i < countof(defaultsamplernames); i++)
{

View File

@ -1506,6 +1506,19 @@ static int GLVID_SetMode (rendererstate_t *info, unsigned char *palette)
if (!GL_Init(info, getglfunc))
return false;
if (qwglGetPixelFormatAttribfvARB) //just for debugging info.
{
int iAttributeNames[] = {WGL_RED_BITS_ARB, WGL_GREEN_BITS_ARB, WGL_BLUE_BITS_ARB, WGL_ALPHA_BITS_ARB, WGL_PIXEL_TYPE_ARB, WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB};
float fAttributeValues[countof(iAttributeNames)] = {0};
if (qwglGetPixelFormatAttribfvARB(maindc, currentpixelformat, 0, countof(iAttributeNames), iAttributeNames, fAttributeValues))
{
Con_DPrintf("Colour buffer: GL_R%gG%gB%gA%g%s\n", fAttributeValues[0], fAttributeValues[1], fAttributeValues[2], fAttributeValues[3], fAttributeValues[5]==WGL_TYPE_RGBA_FLOAT_ARB?"F":((vid.flags & VID_SRGBAWARE)?"_SRGB":""));
Con_DPrintf("Depth buffer: GL_DEPTH%g_STENCIL%g\n", fAttributeValues[5], fAttributeValues[6]);
}
}
qSwapBuffers(maindc);
#ifdef VKQUAKE
@ -2299,7 +2312,7 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info)
iAttribute[iAttributes++] = WGL_SUPPORT_OPENGL_ARB; iAttribute[iAttributes++] = GL_TRUE;
iAttribute[iAttributes++] = WGL_ACCELERATION_ARB; iAttribute[iAttributes++] = WGL_FULL_ACCELERATION_ARB;
if (info->srgb>=3 && modestate != MS_WINDOWED)
if (info->srgb>=2 && modestate != MS_WINDOWED)
{ //half-float backbuffers!
//'as has been the case since Windows Vista, fp16 swap chains are expected to have linear color data'

File diff suppressed because it is too large Load Diff

View File

@ -592,6 +592,7 @@ struct shader_s
byte_vec4_t fog_color;
float fog_dist;
float portaldist;
float portalfboscale; //if we're using texturemaps for portal recursion, this is the scale of the texture relative to the screen.
int numdeforms;
deformv_t deforms[SHADER_DEFORM_MAX];
@ -714,6 +715,7 @@ void Shader_RemapShader_f(void);
void Shader_ShowShader_f(void);
program_t *Shader_FindGeneric(char *name, int qrtype);
const char *Shader_NameForGeneric(program_t *prog);
void Shader_ReleaseGeneric(program_t *prog);
mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org);
@ -838,7 +840,11 @@ qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo);
void GLBE_EndShadowMap(int restorefbo);
void GLBE_SetupForShadowMap(dlight_t *dl, int texwidth, int texheight, float shadowscale);
qboolean GLVID_ApplyGammaRamps (unsigned int size, unsigned short *ramps); //called when gamma ramps need to be reapplied
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette); //the platform-specific function to init gl state
void GLVID_SwapBuffers(void);
char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum uploadfmt *fmt);
void GLVID_SetCaption(const char *caption);
#endif
#ifdef D3D8QUAKE
void D3D8BE_Init(void);

View File

@ -525,7 +525,12 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize)
memcpy(&progs, buf, sizeof(progs));
if (progs.version == PROG_VERSION)
if (progs.version == PROG_QTESTVERSION)
{
defsz = -32; //ddefs_t is 32bit
stsz = -16; //statements is mostly 16bit. there's some line numbers in there too.
}
else if (progs.version == PROG_VERSION)
stsz = defsz = 16;
else if (progs.version == 7)
{
@ -559,8 +564,10 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize)
// if (numstatements > MAX_STATEMENTS)
// Sys_Error("Too many statements");
if (stsz == 16)
{
if (stsz == 32)
statements = (dstatement32_t*)(buf+progs.ofs_statements);
else if (stsz == 16)
{ //need to expand the statements to 32bit.
const dstatement16_t *statements6 = (const dstatement16_t*)(buf+progs.ofs_statements);
statements = malloc(numstatements * sizeof(*statements));
for (i = 0; i < numstatements; i++)
@ -582,8 +589,29 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize)
statements[i].c = (unsigned short)statements6[i].c;
}
}
else if (stsz == 32)
statements = (dstatement32_t*)(buf+progs.ofs_statements);
else if (stsz == -16)
{
const qtest_statement_t *statements3 = (const qtest_statement_t*)(buf+progs.ofs_statements);
statements = malloc(numstatements * sizeof(*statements));
for (i = 0; i < numstatements; i++)
{
statements[i].op = statements3[i].op;
if (statements[i].op == OP_GOTO)
statements[i].a = (signed short)statements3[i].a;
else
statements[i].a = (unsigned short)statements3[i].a;
if (statements[i].op == OP_IF_I || statements[i].op == OP_IFNOT_I ||
statements[i].op == OP_IF_F || statements[i].op == OP_IFNOT_F ||
statements[i].op == OP_IF_S || statements[i].op == OP_IFNOT_S)
statements[i].b = (signed short)statements3[i].b;
else
statements[i].b = (unsigned short)statements3[i].b;
statements[i].c = (unsigned short)statements3[i].c;
}
}
else
Sys_Error("Unrecognised progs version");
@ -615,6 +643,45 @@ int DecompileReadData(char *srcfilename, char *buf, size_t bufsize)
fields[i].type = gd16[i].type;
}
}
else if (defsz == -32)
{
const qtest_function_t *funcin = (const qtest_function_t*)(buf+progs.ofs_functions);
const qtest_def_t *gdqt = (const qtest_def_t*)(buf+progs.ofs_globaldefs);
globals = malloc(numglobaldefs * sizeof(*globals));
for (i = 0; i < numglobaldefs; i++)
{
globals[i].ofs = gdqt[i].ofs;
globals[i].s_name = gdqt[i].s_name;
globals[i].type = gdqt[i].type;
}
gdqt = (const qtest_def_t*)(buf+progs.ofs_fielddefs);
fields = malloc(numfielddefs * sizeof(*fields));
for (i = 0; i < numfielddefs; i++)
{
fields[i].ofs = gdqt[i].ofs;
fields[i].s_name = gdqt[i].s_name;
fields[i].type = gdqt[i].type;
}
functions = malloc(numfunctions * sizeof(*functions));
for (i = 0; i < numfunctions; i++)
{
functions[i].first_statement = funcin[i].first_statement; // negative numbers are builtins
functions[i].parm_start = funcin[i].parm_start;
functions[i].locals = funcin[i].locals; // total ints of parms + locals
functions[i].profile = funcin[i].profile; // runtime
functions[i].s_name = funcin[i].s_name;
functions[i].s_file = funcin[i].s_file; // source file defined in
functions[i].numparms = funcin[i].numparms;
for (j = 0; j < MAX_PARMS; j++)
functions[i].parm_size[j] = funcin[i].parm_size[j];
}
}
else
{
globals = (QCC_ddef32_t*)(buf+progs.ofs_globaldefs);
@ -2775,7 +2842,7 @@ void DecompileFunction(const char *name, int *lastglobal)
}
QCC_CatVFile(Decompileofile, "\n{\n");
startpos = Decompileofile->fsize;
startpos = Decompileofile->size;
/*
fprintf(Decompileprofile, "%s", DecompileProfiles[findex]);
@ -3014,7 +3081,7 @@ void DecompileProgsDat(char *name, void *buf, size_t bufsize)
DecompileReadData(name, buf, bufsize);
DecompileDecompileFunctions(c);
printf("Done.");
printf("Done.\n");
}
char *DecompileGlobalStringNoContents(gofs_t ofs)

View File

@ -1100,13 +1100,14 @@ int QCC_CopyStringLength (const char *str, size_t length);
typedef struct qcc_cachedsourcefile_s {
char filename[128];
size_t size;
size_t bufsize;
size_t zhdrofs;
int zcrc;
char *file;
enum{FT_CODE, FT_DATA} type; //quakec source file or not.
struct qcc_cachedsourcefile_s *next;
char filename[1];
} qcc_cachedsourcefile_t;
extern qcc_cachedsourcefile_t *qcc_sourcefile;
int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed);
@ -1164,18 +1165,26 @@ extern void *(*pHash_GetNext)(hashtable_t *table, const char *name, void *old);
extern void *(*pHash_Add)(hashtable_t *table, const char *name, void *data, bucket_t *);
extern void (*pHash_RemoveData)(hashtable_t *table, const char *name, void *data);
typedef struct vfile_s
{ //when originally running from a .dat, we load up all the functions and work from those rather than actual files.
//(these get re-written into the resulting .dat)
struct vfile_s *next;
void *fdata;
size_t fsize;
size_t msize;
char name[1];
} vfile_t;
//when originally running from a .dat, we load up all the functions and work from those rather than actual files.
//(these get re-written into the resulting .dat)
typedef struct qcc_cachedsourcefile_s vfile_t;
vfile_t *QCC_FindVFile(const char *name);
vfile_t *QCC_AddVFile(const char *name, void *data, size_t size);
void QCC_CatVFile(vfile_t *, const char *fmt, ...);
void QCC_InsertVFile(vfile_t *, size_t pos, const char *fmt, ...);
//void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size, pbool issourcefile);
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;

View File

@ -889,10 +889,17 @@ void ResizeBuf(int hand, int newsize)
}
void SafeWrite(int hand, const void *buf, long count)
{
if (qccfile[hand].ofs +count >= qccfile[hand].buffsize)
ResizeBuf(hand, qccfile[hand].ofs + count+(64*1024));
if (qccfile[hand].stdio)
{
fwrite(buf, 1, count, qccfile[hand].stdio);
}
else
{
if (qccfile[hand].ofs +count >= qccfile[hand].buffsize)
ResizeBuf(hand, qccfile[hand].ofs + count+(64*1024));
memcpy(&qccfile[hand].buff[qccfile[hand].ofs], buf, count);
memcpy(&qccfile[hand].buff[qccfile[hand].ofs], buf, count);
}
qccfile[hand].ofs+=count;
if (qccfile[hand].ofs > qccfile[hand].maxofs)
qccfile[hand].maxofs = qccfile[hand].ofs;
@ -903,7 +910,10 @@ int SafeSeek(int hand, int ofs, int mode)
return qccfile[hand].ofs;
else
{
ResizeBuf(hand, ofs+1024);
if (qccfile[hand].stdio)
fseek(qccfile[hand].stdio, ofs, SEEK_SET);
else
ResizeBuf(hand, ofs+1024);
qccfile[hand].ofs = ofs;
if (qccfile[hand].ofs > qccfile[hand].maxofs)
qccfile[hand].maxofs = qccfile[hand].ofs;
@ -1220,7 +1230,7 @@ char *QCC_SanitizeCharSet(char *mem, size_t *len, pbool *freeresult, int *origfm
static unsigned char *PDECL QCC_LoadFileHunk(void *ctx, size_t size)
{ //2 ensures we can always put a \n in there.
return (unsigned char*)qccHunkAlloc(sizeof(qcc_cachedsourcefile_t)+size+2) + sizeof(qcc_cachedsourcefile_t);
return (unsigned char*)qccHunkAlloc(sizeof(qcc_cachedsourcefile_t)+strlen(ctx)+size+2) + sizeof(qcc_cachedsourcefile_t) + strlen(ctx);
}
long QCC_LoadFile (char *filename, void **bufferptr)
@ -1234,13 +1244,13 @@ long QCC_LoadFile (char *filename, void **bufferptr)
int orig;
pbool warned = false;
mem = externs->ReadFile(filename, QCC_LoadFileHunk, NULL, &len, true);
mem = externs->ReadFile(filename, QCC_LoadFileHunk, filename, &len, true);
if (!mem)
{
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
return -1;
}
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t));
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t)-strlen(filename));
mem[len] = 0;
mem = QCC_SanitizeCharSet(mem, &len, NULL, &orig);
@ -1284,10 +1294,10 @@ void QCC_AddFile (char *filename)
char *mem;
size_t len;
mem = externs->ReadFile(filename, QCC_LoadFileHunk, NULL, &len, false);
mem = externs->ReadFile(filename, QCC_LoadFileHunk, filename, &len, false);
if (!mem)
externs->Abort("failed to find file %s", filename);
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t));
sfile = (qcc_cachedsourcefile_t*)(mem-sizeof(qcc_cachedsourcefile_t)-strlen(filename));
mem[len] = '\0';
sfile->size = len;

View File

@ -3657,11 +3657,10 @@ void QCC_PR_Lex (void)
QCC_PR_LexWhitespace (false);
if (currentchunk)
pr_token_line_last = currentchunk->currentlinenumber-1 + pr_token_line;
else
pr_token_line_last = pr_token_line;
pr_token_line_last = pr_token_line;
pr_token_line = pr_source_line;
if (currentchunk)
pr_token_line += currentchunk->currentlinenumber-1;
if (!pr_file_p)
{

View File

@ -350,31 +350,132 @@ static pbool QCC_RegSetValue(HKEY base, char *keyname, char *valuename, int type
}
*/
#undef printf
#undef Sys_Error
void Sys_Error(const char *text, ...);
pbool qcc_vfiles_changed;
static vfile_t *qcc_vfiles;
HWND mainwindow;
HINSTANCE ghInstance;
static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) ;
void QCC_SaveVFiles(void)
{
vfile_t *f;
if (qcc_vfiles_changed)
{
switch (MessageBox(mainwindow, "Save files as archive?", "FTEQCCGUI", MB_YESNOCANCEL))
{
case IDYES:
{
char filename[MAX_PATH];
char oldpath[MAX_PATH+10];
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = ghInstance;
ofn.lpstrFile = filename;
ofn.lpstrTitle = "Output archive";
ofn.nMaxFile = sizeof(filename)-1;
ofn.lpstrFilter = "QuakeC Projects\0*.zip\0All files\0*.*\0";
memset(filename, 0, sizeof(filename));
GetCurrentDirectory(sizeof(oldpath)-1, oldpath);
ofn.lpstrInitialDir = oldpath;
if (GetSaveFileName(&ofn))
{
int h = SafeOpenWrite(ofn.lpstrFile, -1);
progfuncs_t funcs;
progexterns_t ext;
memset(&funcs, 0, sizeof(funcs));
funcs.funcs.parms = &ext;
memset(&ext, 0, sizeof(ext));
ext.ReadFile = GUIReadFile;
ext.FileSize = GUIFileSize;
ext.WriteFile = QCC_WriteFile;
ext.Sys_Error = Sys_Error;
ext.Printf = GUIprintf;
qccprogfuncs = &funcs;
WriteSourceFiles(qcc_vfiles, h, true, false);
qccprogfuncs = NULL;
SafeClose(h);
qcc_vfiles_changed = false;
return;
}
}
break;
case IDNO:
{
char oldworkingdir[MAX_PATH], newdir[MAX_PATH+10], workingdir[MAX_PATH];
BROWSEINFO bi;
LPITEMIDLIST il;
memset(&bi, 0, sizeof(bi));
bi.hwndOwner = mainwindow;
bi.pidlRoot = NULL;
GetCurrentDirectory(sizeof(oldworkingdir)-1, oldworkingdir);
GetCurrentDirectory(sizeof(workingdir)-1, workingdir);
bi.pszDisplayName = workingdir;
bi.lpszTitle = "Where do you want the source?";
bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT;
bi.lpfn = StupidBrowseCallbackProc;
bi.lParam = 0;
bi.iImage = 0;
il = SHBrowseForFolder(&bi);
if (il)
{
SHGetPathFromIDList(il, newdir);
CoTaskMemFree(il);
for (f = qcc_vfiles; f; f = f->next)
{
char nname[MAX_PATH];
int h;
QC_snprintfz(nname, sizeof(nname), "%s\\%s", newdir, f->filename);
h = SafeOpenWrite(f->filename, -1);
if (h >= 0)
{
SafeWrite(h, f->file, f->size);
SafeClose(h);
}
}
}
SetCurrentDirectory(oldworkingdir); //revert microsoft stupidity.
}
break;
default:
return;
}
}
}
void QCC_CloseAllVFiles(void)
{
vfile_t *f;
while(qcc_vfiles)
{
f = qcc_vfiles;
qcc_vfiles = f->next;
free(f->fdata);
free(f->file);
free(f);
}
qcc_vfiles_changed = false;
}
vfile_t *QCC_FindVFile(const char *name)
{
vfile_t *f;
for (f = qcc_vfiles; f; f = f->next)
{
if (!strcmp(f->name, name))
if (!strcmp(f->filename, name))
return f;
}
//give it another go, for case
for (f = qcc_vfiles; f; f = f->next)
{
if (!QC_strcasecmp(f->name, name))
if (!QC_strcasecmp(f->filename, name))
return f;
}
return NULL;
@ -386,14 +487,17 @@ vfile_t *QCC_AddVFile(const char *name, void *data, size_t size)
{
f = malloc(sizeof(vfile_t) + strlen(name));
f->next = qcc_vfiles;
strcpy(f->name, name);
strcpy(f->filename, name);
qcc_vfiles = f;
}
else
free(f->fdata);
f->fdata = malloc(size);
memcpy(f->fdata, data, size);
f->fsize = f->msize = size;
free(f->file);
f->file = malloc(size);
f->type = FT_CODE;
memcpy(f->file, data, size);
f->size = f->bufsize = size;
qcc_vfiles_changed = true;
return f;
}
void QCC_CatVFile(vfile_t *f, const char *fmt, ...)
@ -407,14 +511,14 @@ void QCC_CatVFile(vfile_t *f, const char *fmt, ...)
va_end (argptr);
n = strlen(msg);
if (f->fsize+n > f->msize)
if (f->size+n > f->bufsize)
{
size_t msize = f->msize + n + 8192;
f->fdata = realloc(f->fdata, msize);
f->msize = msize;
size_t msize = f->bufsize + n + 8192;
f->file = realloc(f->file, msize);
f->bufsize = msize;
}
memcpy((char*)f->fdata+f->fsize, msg, n);
f->fsize += n;
memcpy((char*)f->file+f->size, msg, n);
f->size += n;
}
void QCC_InsertVFile(vfile_t *f, size_t pos, const char *fmt, ...)
{
@ -426,15 +530,15 @@ void QCC_InsertVFile(vfile_t *f, size_t pos, const char *fmt, ...)
va_end (argptr);
n = strlen(msg);
if (f->fsize+n > f->msize)
if (f->size+n > f->bufsize)
{
size_t msize = f->msize + n + 8192;
f->fdata = realloc(f->fdata, msize);
f->msize = msize;
size_t msize = f->bufsize + n + 8192;
f->file = realloc(f->file, msize);
f->bufsize = msize;
}
memmove((char*)f->fdata+pos+n, (char*)f->fdata+pos, f->fsize-pos);
f->fsize += n;
memcpy((char*)f->fdata+pos, msg, n);
memmove((char*)f->file+pos+n, (char*)f->file+pos, f->size-pos);
f->size += n;
memcpy((char*)f->file+pos, msg, n);
}
void QCC_EnumerateFilesResult(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)
@ -442,6 +546,7 @@ void QCC_EnumerateFilesResult(const char *name, const void *compdata, size_t com
void *buffer = malloc(plainsize);
if (QC_decode(NULL, compsize, plainsize, method, compdata, buffer))
QCC_AddVFile(name, buffer, plainsize);
free(buffer);
}
@ -459,7 +564,7 @@ static void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx
vfile_t *v = QCC_FindVFile(fname);
if (v)
{
len = v->fsize;
len = v->size;
if (buf_get)
buffer = buf_get(buf_ctx, len+1);
else
@ -467,9 +572,9 @@ static void *QCC_ReadFile(const char *fname, unsigned char *(*buf_get)(void *ctx
if (!buffer)
return NULL;
((char*)buffer)[len] = 0;
if (len > v->fsize)
len = v->fsize;
memcpy(buffer, v->fdata, len);
if (len > v->size)
len = v->size;
memcpy(buffer, v->file, len);
if (out_size)
*out_size = len;
return buffer;
@ -510,7 +615,7 @@ int PDECL QCC_RawFileSize (const char *fname)
vfile_t *v = QCC_FindVFile(fname);
if (v)
return v->fsize;
return v->size;
f = fopen(fname, "rb");
if (!f)
@ -3029,6 +3134,7 @@ static void EditorReload(editor_t *editor)
//2: draw extra focus to it
void EditFile(const char *name, int line, pbool setcontrol)
{
const char *ext;
char title[1024];
editor_t *neweditor;
WNDCLASS wndclass;
@ -3081,6 +3187,33 @@ void EditFile(const char *name, int line, pbool setcontrol)
return;
}
ext = strrchr(name, '.');
if (ext)
{
if (!QC_strcasecmp(ext, ".wav"))
{
size_t flensz;
char *rawfile = QCC_ReadFile(name, NULL, NULL, &flensz);
//fixme: thread this...
BOOL (WINAPI *pPlaySound)(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound);
HMODULE winmm = LoadLibrary("winmm.dll");
pPlaySound = (void*)GetProcAddress(winmm, "PlaySoundA");
if (pPlaySound)
pPlaySound(rawfile, NULL, SND_MEMORY|SND_SYNC|SND_NODEFAULT);
free(rawfile);
return;
}
else if (!QC_strcasecmp(ext, ".ogg") || !QC_strcasecmp(ext, ".mp3") || !QC_strcasecmp(ext, ".opus") ||
!QC_strcasecmp(ext, ".bsp") || !QC_strcasecmp(ext, ".mdl") || !QC_strcasecmp(ext, ".md2") || !QC_strcasecmp(ext, ".md3") || !QC_strcasecmp(ext, ".iqm") ||
!QC_strcasecmp(ext, ".wad") || !QC_strcasecmp(ext, ".lmp") || !QC_strcasecmp(ext, ".png") || !QC_strcasecmp(ext, ".tga") || !QC_strcasecmp(ext, ".jpeg") ||
!QC_strcasecmp(ext, ".jpg") || !QC_strcasecmp(ext, ".dds") || !QC_strcasecmp(ext, ".ktx") || !QC_strcasecmp(ext, ".bmp") || !QC_strcasecmp(ext, ".pcx") ||
!QC_strcasecmp(ext, ".bin") || !QC_strcasecmp(ext, ".dat") || !QC_strcasecmp(ext, ".pak") || !QC_strcasecmp(ext, ".pk3") || !QC_strcasecmp(ext, ".dem") || !QC_strcasecmp(ext, ".spr"))
{
if (IDOK != MessageBox(NULL, "The file extension implies that it is a binary file. Open as text anyway?", "FTEQCCGUI", MB_OKCANCEL))
return;
}
}
neweditor = malloc(sizeof(editor_t));
if (!neweditor)
{
@ -6985,6 +7118,26 @@ static void Packager_MessageCallback(void *ctx, const char *fmt, ...)
outlen = GUIEmitOutputText(outputbox, outlen, message, strlen(message), RGB(0, 0, 0));
}
void GUI_DoDecompile(void *buf, size_t size)
{
char *c = ReadProgsCopyright(buf, size);
if (!c || !*c)
c = "COPYRIGHT OWNER NOT KNOWN"; //all work is AUTOMATICALLY copyrighted under the terms of the Berne Convention in all major nations. It _IS_ copyrighted, even if there's no license etc included. Good luck guessing what rights you have.
if (MessageBox(mainwindow, qcva("The copyright message from this progs is\n%s\n\nPlease respect the wishes and legal rights of the person who created this.", c), "Copyright", MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP) == IDOK)
{
CreateOutputWindow(true);
compilecb();
DecompileProgsDat(progssrcname, buf, size);
if (SplitterGet(outputbox))
{
SendMessage(outputbox, WM_SETREDRAW, TRUE, 0);
RedrawWindow(outputbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
QCC_SaveVFiles();
}
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
pbool fl_acc;
@ -7176,7 +7329,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
//if the project is a .dat or .zip then decompile it now (so we can access the 'source')
{
char *ext = strrchr(progssrcname, '.');
if (ext && (!QC_strcasecmp(ext, ".dat") || !QC_strcasecmp(ext, ".zip") || !QC_strcasecmp(ext, ".pk3")))
if (ext && (!QC_strcasecmp(ext, ".dat") || !QC_strcasecmp(ext, ".pak") || !QC_strcasecmp(ext, ".zip") || !QC_strcasecmp(ext, ".pk3")))
{
FILE *f = fopen(progssrcname, "rb");
if (f)
@ -7192,21 +7345,24 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
fclose(f);
QCC_CloseAllVFiles();
if (!QC_EnumerateFilesFromBlob(buf, size, QCC_EnumerateFilesResult) && !QC_strcasecmp(ext, ".dat"))
{ //its a .dat and contains no .src files
GUI_DoDecompile(buf, size);
}
else if (!QCC_FindVFile("progs.src"))
{
char *c = ReadProgsCopyright(buf, size);
if (!c || !*c)
c = "COPYRIGHT OWNER NOT KNOWN"; //all work is AUTOMATICALLY copyrighted under the terms of the Berne Convention in all major nations. It _IS_ copyrighted, even if there's no license etc included. Good luck guessing what rights you have.
if (MessageBox(mainwindow, qcva("The copyright message from this progs is\n%s\n\nPlease respect the wishes and legal rights of the person who created this.", c), "Copyright", MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP) == IDOK)
{
CreateOutputWindow(true);
compilecb();
DecompileProgsDat(progssrcname, buf, size);
if (SplitterGet(outputbox))
{
SendMessage(outputbox, WM_SETREDRAW, TRUE, 0);
RedrawWindow(outputbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
}
vfile_t *f;
char *archivename = progssrcname;
while(strchr(archivename, '\\'))
archivename = strchr(archivename, '\\')+1;
AddSourceFile(NULL, archivename);
for (f = qcc_vfiles; f; f = f->next)
AddSourceFile(archivename, f->filename);
f = QCC_FindVFile("progs.dat");
if (f)
GUI_DoDecompile(f->file, f->size);
else
resetprogssrc = false;
}
free(buf);
strcpy(progssrcname, "progs.src");
@ -7227,8 +7383,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (fl_compileonstart)
{
CreateOutputWindow(false);
RunCompiler(lpCmdLine, false);
if (resetprogssrc)
{
CreateOutputWindow(false);
RunCompiler(lpCmdLine, false);
}
}
else
{
@ -7242,8 +7401,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
RunCompiler("-?", false);
}
}
if (resetprogssrc)
UpdateFileList();
resetprogssrc = false;
UpdateFileList();
}
EditorsRun();

View File

@ -769,7 +769,7 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell
if (zipembed)
{
size_t end;
char header[32+sizeof(f->filename)];
char header[32];
size_t fnamelen = strlen(f->filename);
f->zcrc = QC_encodecrc(f->size, f->file);
misint (header, 0, 0x04034b50);
@ -783,10 +783,10 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell
misint (header, 22, f->size);//uncompressed size
misshort(header, 26, fnamelen);//filename length
misshort(header, 28, 0);//extradata length
strcpy(header+30, f->filename);
f->zhdrofs = SafeSeek(h, 0, SEEK_CUR);
SafeWrite(h, header, 30+fnamelen);
SafeWrite(h, header, 30);
SafeWrite(h, f->filename, fnamelen);
strcpy(idf[num].filename, f->filename);
idf[num].size = f->size;
@ -803,13 +803,13 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell
end = SafeSeek(h, 0, SEEK_CUR);
SafeSeek(h, f->zhdrofs, SEEK_SET);
SafeWrite(h, header, 30+strlen(f->filename));
SafeWrite(h, header, 30);
SafeSeek(h, end, SEEK_SET);
}
}
else
{
if (f->type == FT_CODE && !sourceaswell)
if (strlen(f->filename) >= sizeof(idf[num].filename))
continue;
strcpy(idf[num].filename, f->filename);
@ -827,7 +827,7 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell
if (zipembed)
{
char centralheader[46+sizeof(f->filename)];
char centralheader[46];
int centraldirsize;
ofs = SafeSeek(h, 0, SEEK_CUR);
for (f = filelist,num=0; f ; f=f->next)
@ -853,8 +853,8 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell
misshort(centralheader, 36, 0);//internal file attribs
misint (centralheader, 38, 0);//external file attribs
misint (centralheader, 42, f->zhdrofs);//local header offset
strcpy(centralheader+46, f->filename);
SafeWrite(h, centralheader, 46 + fnamelen);
SafeWrite(h, centralheader, 46);
SafeWrite(h, f->filename, fnamelen);
num++;
}
@ -3614,19 +3614,6 @@ DIRECTORY COPYING / PACKFILE CREATION
==============================================================================
*/
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;
packfile_t pfiles[4096], *pf;
int packhandle;
int packbytes;

View File

@ -191,6 +191,18 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons
int ret = 0;
if (blobsize < 22)
return ret;
if (!strncmp(blob, "PACK", 4))
{
const packheader_t *head = blob;
const packfile_t *f = (packfile_t*)((char*)blob + head->dirofs);
for (ret = 0; ret < head->dirlen/sizeof(*f); ret++, f++)
{
cb(f->name, (const char*)blob+f->filepos, f->filelen, 0, f->filelen);
}
return ret;
}
//treat it as a zip
eocd = blob;
eocd += blobsize-22;
if (QC_ReadRawInt(eocd+0) != 0x06054b50)

View File

@ -647,11 +647,11 @@ void NPP_SetInfo(client_t *cl, char *key, char *value)
if (!strcmp(key, "colours"))
{
i = atoi(value);
Info_SetValueForKey (cl->userinfo, "bottomcolor", va("%i", i&15), sizeof(cl->userinfo));
Info_SetValueForKey (cl->userinfo, "topcolor", va("%i", i>>4), sizeof(cl->userinfo));
InfoBuf_SetKey (&cl->userinfo, "bottomcolor", va("%i", i&15));
InfoBuf_SetKey (&cl->userinfo, "topcolor", va("%i", i>>4));
}
Info_SetValueForKey (cl->userinfo, key, value, sizeof(cl->userinfo));
if (!*Info_ValueForKey (cl->userinfo, "name"))
InfoBuf_SetKey (&cl->userinfo, key, value);
if (!*InfoBuf_ValueForKey (&cl->userinfo, "name"))
cl->name[0] = '\0';
else // process any changed values
SV_ExtractFromUserinfo (cl, false);
@ -662,19 +662,19 @@ void NPP_SetInfo(client_t *cl, char *key, char *value)
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, i);
MSG_WriteString (&sv.reliable_datagram, "bottomcolor");
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(cl->userinfo, "bottomcolor"));
MSG_WriteString (&sv.reliable_datagram, InfoBuf_ValueForKey(&cl->userinfo, "bottomcolor"));
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, i);
MSG_WriteString (&sv.reliable_datagram, "topcolor");
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(cl->userinfo, "topcolor"));
MSG_WriteString (&sv.reliable_datagram, InfoBuf_ValueForKey(&cl->userinfo, "topcolor"));
}
else
{
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, i);
MSG_WriteString (&sv.reliable_datagram, key);
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(cl->userinfo, key));
MSG_WriteString (&sv.reliable_datagram, InfoBuf_ValueForKey(&cl->userinfo, key));
}
}
@ -1851,8 +1851,8 @@ void NPP_QWFlush(void)
unsigned int j = buffer[1];
if (j < sv.allocated_client_slots)
{
Q_strncpyz(svs.clients[j].userinfo, (buffer+6), sizeof(svs.clients[j].userinfo));
if (*Info_ValueForKey(svs.clients[j].userinfo, "name"))
InfoBuf_FromString(&svs.clients[j].userinfo, buffer+6, false);
if (*InfoBuf_ValueForKey(&svs.clients[j].userinfo, "name"))
SV_ExtractFromUserinfo(&svs.clients[j], false);
else
*svs.clients[j].name = '\0';
@ -1864,7 +1864,7 @@ void NPP_QWFlush(void)
if (j < sv.allocated_client_slots)
{
*svs.clients[j].name = '\0';
*svs.clients[j].userinfo = '\0';
InfoBuf_Clear(&svs.clients[j].userinfo, true);
}
}

View File

@ -206,6 +206,47 @@ static qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float re
return state;
}
void *PR_GetWriteQCPtr(pubprogfuncs_t *prinst, int qcptr, int qcsize)
{
// void *r;
if (qcsize < 0)
return NULL;
if (!qcptr)
return NULL;
if (qcptr >= 0 && qcptr <= prinst->stringtablemaxsize)
{
if (qcptr + qcsize <= prinst->stringtablemaxsize)
return prinst->stringtable+qcptr; //its in bounds
}
/*else
{
r = PR_GetString(prinst, qcptr);
if (qcsize < strlen(r))
return r;
}*/
return NULL;
}
const void *PR_GetReadQCPtr(pubprogfuncs_t *prinst, int qcptr, int qcsize)
{
const char *r;
if (qcsize < 0)
return NULL;
if (!qcptr)
return NULL;
if (qcptr >= 0 && qcptr <= prinst->stringtablemaxsize)
{
if (qcptr + qcsize <= prinst->stringtablemaxsize)
return prinst->stringtable+qcptr; //its in bounds
}
else
{
r = PR_GetString(prinst, qcptr);
if (qcsize < strlen(r))
return r;
}
return NULL;
}
void PDECL ED_Spawned (struct edict_s *ent, int loading)
{
#ifdef VM_Q1
@ -1778,7 +1819,7 @@ void Q_InitProgs(void)
int j, maps;
char *f;
f = COM_LoadTempFile("maplist.txt", NULL);
f = COM_LoadTempFile("maplist.txt", 0, NULL);
f = COM_Parse(f);
maps = atoi(com_token);
for (j = 0; j < maps; j++)
@ -3853,7 +3894,7 @@ void PF_stuffcmd_Internal(int entnum, const char *str, unsigned int flags)
case 13: tname = "blue"; break;
default: tname = va("t%i", team); break; //good job our va has multiple buffers
}
PF_ForceInfoKey_Internal(entnum, "team", tname);
PF_ForceInfoKey_Internal(entnum, "team", tname, strlen(tname));
ClientReliableWrite_Begin (cl, svc_stufftext, 2+strlen("color "));
ClientReliableWrite_String (cl, "color ");
@ -4721,14 +4762,14 @@ void QCBUILTIN PF_aim (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
i = NUM_FOR_EDICT(prinst, ent);
if (i>0 && i<sv.allocated_client_slots)
{
noaim = Info_ValueForKey (svs.clients[i-1].userinfo, "noaim");
noaim = InfoBuf_ValueForKey (&svs.clients[i-1].userinfo, "noaim");
if (atoi(noaim) > 0)
{
VectorCopy (P_VEC(v_forward), G_VECTOR(OFS_RETURN));
return;
}
noaim = Info_ValueForKey (svs.clients[i-1].userinfo, "aim");
noaim = InfoBuf_ValueForKey (&svs.clients[i-1].userinfo, "aim");
if (noaim)
{
dist = atof(noaim);
@ -5842,8 +5883,8 @@ char *PF_infokey_Internal (int entnum, const char *key)
value = "2.40";
else
{
if ((value = Info_ValueForKey (svs.info, key)) == NULL || !*value)
value = Info_ValueForKey(localinfo, key);
if ((value = InfoBuf_ValueForKey(&svs.info, key)) == NULL || !*value)
value = InfoBuf_ValueForKey(&svs.localinfo, key);
}
}
else if (entnum <= sv.allocated_client_slots)
@ -5950,7 +5991,7 @@ char *PF_infokey_Internal (int entnum, const char *key)
else if (!strcmp(key, "*islagged"))
value = (svs.clients[entnum-1].penalties & BAN_LAGGED)?"1":"";
else
value = Info_ValueForKey (svs.clients[entnum-1].userinfo, key);
value = InfoBuf_ValueForKey (&svs.clients[entnum-1].userinfo, key);
} else
value = "";
@ -5985,18 +6026,96 @@ static void QCBUILTIN PF_infokey_f (pubprogfuncs_t *prinst, struct globalvars_s
static void QCBUILTIN PF_sv_serverkeystring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *value = Info_ValueForKey (svs.info, key);
const char *value = InfoBuf_ValueForKey (&svs.info, key);
G_INT(OFS_RETURN) = *value?PR_TempString(prinst, value):0;
}
static void QCBUILTIN PF_sv_serverkeyfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *value = Info_ValueForKey (svs.info, key);
const char *value = InfoBuf_ValueForKey (&svs.info, key);
if (*value)
G_FLOAT(OFS_RETURN) = strtod(value, NULL);
else
G_FLOAT(OFS_RETURN) = (prinst->callargc>=2)?G_FLOAT(OFS_PARM1):0;
}
static void QCBUILTIN PF_sv_serverkeyblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
size_t blobsize = 0;
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *blobvalue = InfoBuf_BlobForKey(&svs.info, key, &blobsize);
if ((prinst->callargc<2) || G_INT(OFS_PARM1) == 0)
G_INT(OFS_RETURN) = blobsize; //no pointer to write to, just return the length.
else
{
size_t size = min(blobsize, G_INT(OFS_PARM2));
void *ptr = PR_GetWriteQCPtr(prinst, G_INT(OFS_PARM1), size);
if (!ptr)
PR_BIError(prinst, "PF_sv_serverkeyblob: invalid pointer/size\n");
G_INT(OFS_RETURN) = size;
memcpy(ptr, blobvalue, size);
}
}
static void QCBUILTIN PF_setserverkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *value;
size_t size;
if (prinst->callargc > 2)
{
size = G_INT(OFS_PARM2);
value = PR_GetReadQCPtr(prinst, G_INT(OFS_PARM1), size);
}
else
{
value = PR_GetStringOfs(prinst, OFS_PARM1);
size = strlen(value);
}
if (!value)
PR_BIError(prinst, "PF_setserverkey: invalid pointer/size\n");
InfoBuf_SetStarBlobKey(&svs.info, key, value, size);
}
static void QCBUILTIN PF_getlocalinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
size_t blobsize = 0;
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *blobvalue = InfoBuf_BlobForKey(&svs.localinfo, key, &blobsize);
if ((prinst->callargc<2) || G_INT(OFS_PARM1) == 0)
G_INT(OFS_RETURN) = blobsize; //no pointer to write to, just return the length.
else
{
size_t size = min(blobsize, G_INT(OFS_PARM2));
void *ptr = PR_GetWriteQCPtr(prinst, G_INT(OFS_PARM1), size);
if (!ptr)
PR_BIError(prinst, "PF_getlocalinfo: invalid pointer/size\n");
G_INT(OFS_RETURN) = size;
memcpy(ptr, blobvalue, size);
}
}
static void QCBUILTIN PF_setlocalinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
const char *value;
size_t size;
if (prinst->callargc > 2)
{
size = G_INT(OFS_PARM2);
value = PR_GetReadQCPtr(prinst, G_INT(OFS_PARM1), size);
}
else
{
value = PR_GetStringOfs(prinst, OFS_PARM1);
size = strlen(value);
}
if (!value)
PR_BIError(prinst, "PF_setlocalinfo: invalid pointer/size\n");
InfoBuf_SetStarBlobKey(&svs.localinfo, key, value, size);
}
/*
==============
@ -7384,7 +7503,7 @@ void PRH2_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc)
sprintf(temp,"%i",(int)classnum);
else
*temp = 0;
Info_SetValueForKey (cl->userinfo, "cl_playerclass", temp, sizeof(cl->userinfo));
InfoBuf_SetKey (&cl->userinfo, "cl_playerclass", temp);
if (cl->playerclass != classnum)
{
cl->edict->xv->playerclass = classnum;
@ -7427,7 +7546,7 @@ static void QCBUILTIN PF_h2setclass (pubprogfuncs_t *prinst, struct globalvars_s
client->playerclass = NewClass;
sprintf(temp,"%d",(int)NewClass);
Info_SetValueForKey (client->userinfo, "cl_playerclass", temp, sizeof(client->userinfo));
InfoBuf_SetValueForKey (&client->userinfo, "cl_playerclass", temp);
client->sendinfo = true;
}
@ -9091,29 +9210,25 @@ static void QCBUILTIN PF_te_plasmaburn(pubprogfuncs_t *prinst, struct globalvars
}
int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *value)
int PF_ForceInfoKey_Internal(unsigned int entnum, const char *key, const char *value, size_t valsize)
{
if (entnum == 0)
{ //localinfo
Info_SetValueForKey (localinfo, key, value, MAX_LOCALINFO_STRING);
{ //serverinfo
InfoBuf_SetStarBlobKey(&svs.info, key, value, valsize);
return 2;
}
else if (entnum <= sv.allocated_client_slots)
{ //woo. we found a client.
char *oldvalue;
if (svs.clients[entnum-1].state == cs_free)
{
Con_DPrintf("PF_ForceInfoKey: inactive client\n");
return 0;
}
oldvalue = Info_ValueForKey(svs.clients[entnum-1].userinfo, key);
if (strcmp(oldvalue, value))
if (InfoBuf_SetStarBlobKey(&svs.clients[entnum-1].userinfo, key, value, valsize))
{
Info_SetValueForStarKey(svs.clients[entnum-1].userinfo, key, value, sizeof(svs.clients[entnum-1].userinfo));
SV_ExtractFromUserinfo (&svs.clients[entnum-1], false);
value = Info_ValueForKey(svs.clients[entnum-1].userinfo, key);
value = InfoBuf_ValueForKey(&svs.clients[entnum-1].userinfo, key);
if (!strcmp(key, "*spectator"))
{
@ -9155,7 +9270,33 @@ static void QCBUILTIN PF_ForceInfoKey(pubprogfuncs_t *prinst, struct globalvars_
key = PR_GetStringOfs(prinst, OFS_PARM1);
value = PR_GetStringOfs(prinst, OFS_PARM2);
G_FLOAT(OFS_RETURN) = PF_ForceInfoKey_Internal(e->entnum, key, value);
G_FLOAT(OFS_RETURN) = PF_ForceInfoKey_Internal(e->entnum, key, value, strlen(value));
}
static void QCBUILTIN PF_ForceInfoKeyBlob(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *e;
const char *value;
const char *key;
int size;
e = G_EDICT(prinst, OFS_PARM0);
key = PR_GetStringOfs(prinst, OFS_PARM1);
value = PR_GetStringOfs(prinst, OFS_PARM2);
size = G_INT(OFS_PARM3);
if (size < 0)
size = 0;
if (G_INT(OFS_PARM2) >= 0 && G_INT(OFS_PARM2) < prinst->stringtablesize)
{
if (value+size > prinst->stringtable+prinst->stringtablesize)
return;
}
else
{
if (size > strlen(value)+1)
return;
}
G_FLOAT(OFS_RETURN) = PF_ForceInfoKey_Internal(e->entnum, key, value, size);
}
/*
@ -9189,16 +9330,16 @@ static void QCBUILTIN PF_setcolors (pubprogfuncs_t *prinst, struct globalvars_s
client->edict->v->team = (i & 15) + 1;
Q_snprintfz(number, sizeof(number), "%i", i>>4);
if (strcmp(number, Info_ValueForKey(client->userinfo, "topcolor")))
if (strcmp(number, InfoBuf_ValueForKey(&client->userinfo, "topcolor")))
{
Info_SetValueForKey(client->userinfo, "topcolor", number, sizeof(client->userinfo));
InfoBuf_SetValueForKey(&client->userinfo, "topcolor", number);
key = "topcolor";
}
Q_snprintfz(number, sizeof(number), "%i", i&15);
if (strcmp(number, Info_ValueForKey(client->userinfo, "bottomcolor")))
if (strcmp(number, InfoBuf_ValueForKey(&client->userinfo, "bottomcolor")))
{
Info_SetValueForKey(client->userinfo, "bottomcolor", number, sizeof(client->userinfo));
InfoBuf_SetValueForKey(&client->userinfo, "bottomcolor", number);
key = key?"*bothcolours":"bottomcolor";
}
@ -10282,6 +10423,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"abort", PF_Abort, 0, 0, 0, 211, D("void(optional __variant ret)", "QC execution is aborted. Parent QC functions on the stack will be skipped, effectively this forces all QC functions to 'return ret' until execution returns to the engine. If ret is ommited, it is assumed to be 0.")},
{"sleep", PF_Sleep, 0, 0, 0, 212, D("void(float sleeptime)", "Suspends the current QC execution thread for 'sleeptime' seconds.\nOther QC functions can and will be executed in the interim, including changing globals and field state (but not simultaneously).\nThe self and other globals will be restored when the thread wakes up (or set to world if they were removed since the thread started sleeping). Locals will be preserved, but will not be protected from remove calls.\nIf the engine is expecting the QC to return a value (even in the parent/root function), the value 0 shall be used instead of waiting for the qc to resume.")},
{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213, D("void(entity player, string key, string value)", "Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers.")},
{"forceinfokeyblob",PF_ForceInfoKeyBlob,0, 0, 0, 0, D("void(entity player, string key, void *data, int size)", "Directly changes a user's info without pinging off the client. Also allows explicitly setting * keys, including *spectator. Does not affect the user's config or other servers.")},
#ifdef SVCHAT
{"chat", PF_chat, 0, 0, 0, 214, "void(string filename, float starttag, entity edict)"}, //(FTE_NPCCHAT)
#endif
@ -10486,8 +10628,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"drawline", PF_Fixme, 0, 0, 0, 315, D("void(float width, vector pos1, vector pos2, vector rgb, float alpha, optional float drawflag)", "Draws a 2d line between the two 2d points.")},// (EXT_CSQC)
{"iscachedpic", PF_Fixme, 0, 0, 0, 316, D("float(string name)", "Checks to see if the image is currently loaded. Engines might lie, or cache between maps.")},// (EXT_CSQC)
{"precache_pic", PF_Fixme, 0, 0, 0, 317, D("string(string name, optional float trywad)", "Forces the engine to load the named image. If trywad is specified, the specified name must any lack path and extension.")},// (EXT_CSQC)
{"r_uploadimage", PF_Fixme, 0, 0, 0, 0, D("void(string imagename, int width, int height, int *pixeldata)", "Updates a texture with the specified rgba data. Will be created if needed.")},
{"r_readimage", PF_Fixme, 0, 0, 0, 0, D("int*(string filename, __out int width, __out int height)", "Reads and decodes an image from disk, providing raw pixel data. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it.")},
{"r_uploadimage", PF_Fixme, 0, 0, 0, 0, D("void(string imagename, int width, int height, void *pixeldata, optional int datasize, optional int format)", "Updates a texture with the specified rgba data. Will be created if needed. If blobsize is specified then the image is decoded (eg .ktx or .dds data) instead of being raw R8G8B8A data. You'll typically want shaderforname to also generate a shader to use the texture.")},
{"r_readimage", PF_Fixme, 0, 0, 0, 0, D("int*(string filename, __out int width, __out int height)", "Reads and decodes an image from disk, providing raw R8G8B8A pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it.")},
{"drawgetimagesize",PF_Fixme, 0, 0, 0, 318, D("#define draw_getimagesize drawgetimagesize\nvector(string picname)", "Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution.")},// (EXT_CSQC)
{"freepic", PF_Fixme, 0, 0, 0, 319, D("void(string name)", "Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed.")},// (EXT_CSQC)
//320
@ -10540,6 +10682,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"runstandardplayerphysics",PF_runclientphys,0,0,0, 347, D("void(entity ent)", "Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement.")},
{"getplayerkeyvalue", PF_Fixme,0, 0, 0, 348, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC)
{"getplayerkeyfloat", PF_Fixme,0, 0, 0, 0, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")},
{"getplayerkeyblob", PF_Fixme,0, 0, 0, 0, D("int(float playernum, string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"getlocalinfo", PF_getlocalinfo,0, 0, 0, 0, D("int(string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"setlocalinfo", PF_setlocalinfo,0, 0, 0, 0, D("void(string keyname, optional void *outptr, int size)", "Changes the server's localinfo. This data will be available for the following map, and will *usually* reload with saved games.")},
{"isdemo", PF_Fixme, 0, 0, 0, 349, D("float()", "Returns if the client is currently playing a demo or not")},// (EXT_CSQC)
{"isserver", PF_Fixme, 0, 0, 0, 350, D("float()", "Returns if the client is acting as the server (aka: listen server)")},//(EXT_CSQC)
@ -10549,6 +10695,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"wasfreed", PF_WasFreed,0, 0, 0, 353, D("float(entity ent)", "Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust.")},//(EXT_CSQC) (should be availabe on server too)
{"serverkey", PF_sv_serverkeystring,0,0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string")},//
{"serverkeyfloat", PF_sv_serverkeyfloat,0,0, 0, 0, D("float(string key, optional float assumevalue)", "Version of serverkey that returns the value as a float (which avoids tempstrings).")},//
{"serverkeyblob", PF_sv_serverkeyblob,0,0, 0, 0, D("int(int buf, string key, optional void *ptr, int size)", "Version of serverkey that can obtain entire serverinfo, localinfo, or (local)userinfo blobs. Returns blob size")},//
{"setserverkey", PF_setserverkey,0, 0, 0, 0, D("void(int buf, string key, void *ptr, optional int size)", "Changes the server's serverinfo.")},//
{"getentitytoken", PF_Fixme, 0, 0, 0, 355, D("string(optional string resetstring)", "Grab the next token in the map's entity lump.\nIf resetstring is not specified, the next token will be returned with no other sideeffects.\nIf empty, will reset from the map before returning the first token, probably {.\nIf not empty, will tokenize from that string instead.\nAlways returns tempstrings.")},//;
{"findfont", PF_Fixme, 0, 0, 0, 356, D("float(string s)", "Looks up a named font slot. Matches the actual font name as a last resort.")},//;
{"loadfont", PF_Fixme, 0, 0, 0, 357, D("float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset)", "too convoluted for me to even try to explain correct usage. Try drawfont = loadfont(\"\", \"cour\", \"16\", -1, 0, 0); to switch to the courier font (optimised for 16 virtual pixels high), if you have the freetype2 library in windows..")},
@ -10869,6 +11017,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"crypto_getmyidfp",PF_Fixme, 0, 0, 0, 637, "string(float addr)" STUB},
// {"VM_CL_RotateMoves",PF_Fixme, 0, 0, 0, 638, ""},
{"digest_hex", PF_digest_hex, 0, 0, 0, 639, "string(string digest, string data, ...)"},
{"digest_ptr", PF_digest_ptr, 0, 0, 0, 0, D("string(string digest, void *data, int length)", "Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function.")},
// {"V_CalcRefdef", PF_Fixme, 0, 0, 0, 640, "void(entity e)"},
{"crypto_getmyidstatus",PF_Fixme, 0, 0, 0, 641, "float(float i)" STUB},
@ -11075,7 +11224,7 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any
{
char *builtinmap;
int binum;
builtinmap = COM_LoadTempFile("fte_bimap.txt", NULL);
builtinmap = COM_LoadTempFile("fte_bimap.txt", 0, NULL);
while(1)
{
builtinmap = COM_Parse(builtinmap);

View File

@ -1100,7 +1100,7 @@ static int bi_lua_setinfokey(lua_State *L)
key = lua_tolstring(L, 2, NULL);
value = lua_tolstring(L, 3, NULL);
result = PF_ForceInfoKey_Internal(entnum, key, value);
result = PF_ForceInfoKey_Internal(entnum, key, value, strlen(value));
lua_pushinteger(L, result);
return 1;
}

View File

@ -1532,11 +1532,11 @@ static qintptr_t QVM_Add_Bot (void *offset, quintptr_t mask, const qintptr_t *ar
cl->edict = EDICT_NUM_PB(sv.world.progs, i+1);
Info_SetValueForKey(cl->userinfo, "name", name, sizeof(cl->userinfo));
Info_SetValueForKey(cl->userinfo, "topcolor", va("%i", top), sizeof(cl->userinfo));
Info_SetValueForKey(cl->userinfo, "bottomcolor", va("%i", bottom), sizeof(cl->userinfo));
Info_SetValueForKey(cl->userinfo, "skin", skin, sizeof(cl->userinfo));
Info_SetValueForStarKey(cl->userinfo, "*bot", "1", sizeof(cl->userinfo));
InfoBuf_SetKey(&cl->userinfo, "name", name);
InfoBuf_SetKey(&cl->userinfo, "topcolor", va("%i", top));
InfoBuf_SetKey(&cl->userinfo, "bottomcolor", va("%i", bottom));
InfoBuf_SetKey(&cl->userinfo, "skin", skin);
InfoBuf_SetStarKey(&cl->userinfo, "*bot", "1");
SV_ExtractFromUserinfo(cl, true);
SV_SetUpClientEdict (cl, cl->edict);
@ -1598,14 +1598,20 @@ static qintptr_t QVM_SetBotCMD (void *offset, quintptr_t mask, const qintptr_t *
}
static qintptr_t QVM_SetUserInfo (void *offset, quintptr_t mask, const qintptr_t *arg)
{
char *key = VM_POINTER(arg[1]);
int ent = VM_LONG(arg[0]);
const char *key = VM_POINTER(arg[1]);
const char *val = VM_POINTER(arg[2]);
if (*key == '*' && (VM_LONG(arg[3])&1))
return -1; //denied!
return PF_ForceInfoKey_Internal(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]));
return PF_ForceInfoKey_Internal(ent, key, val, strlen(val));
}
static qintptr_t QVM_SetBotUserInfo (void *offset, quintptr_t mask, const qintptr_t *arg)
{
return PF_ForceInfoKey_Internal(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]));
int ent = VM_LONG(arg[0]);
const char *key = VM_POINTER(arg[1]);
const char *val = VM_POINTER(arg[2]);
return PF_ForceInfoKey_Internal(ent, key, val, strlen(val));
}
static qintptr_t QVM_MoveToGoal (void *offset, quintptr_t mask, const qintptr_t *arg)
{
@ -2509,7 +2515,7 @@ qboolean Q1QVM_ClientSay(edict_t *player, qboolean team)
}
qboolean Q1QVM_UserInfoChanged(edict_t *player)
{
{ //mod will use G_CMD_ARGV to get argv1+argv2 to read the info that is changing.
if (!q1qvm)
return false;

View File

@ -1207,7 +1207,6 @@ void SV_Savegame (const char *savename, qboolean mapchange)
vfsfile_t *f;
int len;
levelcache_t *cache;
char str[MAX_LOCALINFO_STRING+1];
char *savefilename;
#ifndef QUAKETC
@ -1291,13 +1290,9 @@ void SV_Savegame (const char *savename, qboolean mapchange)
//write floats too so you can use it to debug.
}
Q_strncpyz(str, svs.info, sizeof(str));
Info_RemovePrefixedKeys(str, '*');
VFS_PRINTF (f, "%s\n", str);
Q_strncpyz(str, localinfo, sizeof(str));
Info_RemovePrefixedKeys(str, '*');
VFS_PUTS(f, str);
InfoBuf_WriteToFile(f, &svs.info, NULL, 0);
VFS_PUTS(f, "\n");
InfoBuf_WriteToFile(f, &svs.localinfo, NULL, 0);
VFS_PRINTF (f, "\n{\n"); //all game vars. FIXME: Should save the ones that have been retrieved/set by progs.
VFS_PRINTF (f, "skill \"%s\"\n", skill.string);
@ -1703,9 +1698,8 @@ void SV_Loadgame_f (void)
for (trim = str; *trim <= ' ' && *trim; trim++)
;
Info_RemovePrefixedKeys(str, '*'); //just in case
Info_RemoveNonStarKeys(svs.info);
len = strlen(svs.info);
Q_strncpyz(svs.info+len, str, sizeof(svs.info)-len);
InfoBuf_Clear(&svs.info, false);
InfoBuf_FromString(&svs.info, str, true);
VFS_GETS(f, str, sizeof(str)-1);
for (trim = str+strlen(str)-1; trim>=str && *trim <= ' '; trim--)
@ -1713,9 +1707,8 @@ void SV_Loadgame_f (void)
for (trim = str; *trim <= ' ' && *trim; trim++)
;
Info_RemovePrefixedKeys(str, '*'); //just in case
Info_RemoveNonStarKeys(localinfo);
len = strlen(localinfo);
Q_strncpyz(localinfo+len, str, sizeof(localinfo)-len);
InfoBuf_Clear(&svs.localinfo, false);
InfoBuf_FromString(&svs.localinfo, str, true);
VFS_GETS(f, str, sizeof(str)-1);
for (trim = str+strlen(str)-1; trim>=str && *trim <= ' '; trim--)

View File

@ -458,9 +458,10 @@ typedef struct client_s
qboolean drop; // lose this guy next opportunity
int lossage; // loss percentage
int challenge;
int userid; // identifying number
char userinfo[EXTENDED_INFO_STRING]; // infostring
int challenge;
int userid; // identifying number
infobuf_t userinfo; // all of the user's various settings
infosync_t infosync; // information about the infos that the client still doesn't know (server and multiple clients).
char *transfer;
usercmd_t lastcmd; // for filling in big drops and partial predictions
@ -908,7 +909,8 @@ typedef struct
int heartbeat_sequence;
svstats_t stats;
char info[MAX_SERVERINFO_STRING];
infobuf_t info;
infobuf_t localinfo;
// log messages are used so that fraglog processes can get stats
int logsequence; // the message currently being filled
@ -1069,8 +1071,6 @@ extern edict_t *sv_player;
//extern char localmodels[MAX_MODELS][5]; // inline model names for precache
extern char localinfo[MAX_LOCALINFO_STRING+1];
extern vfsfile_t *sv_fraglogfile;
//===========================================================
@ -1123,7 +1123,6 @@ void SV_ArgumentOverrides(void);
int SV_CalcPing (client_t *cl, qboolean forcecalc);
void SV_FullClientUpdate (client_t *client, client_t *to);
void SV_GeneratePublicUserInfo(int pext, client_t *cl, char *info, int infolength);
char *SV_PlayerPublicAddress(client_t *cl);
qboolean SVC_GetChallenge (qboolean respond_dp);
@ -1273,7 +1272,6 @@ void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...);
void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...) LIKEPRINTF(2);
void VARGS SV_BroadcastTPrintf (int level, translation_t fmt, ...);
void VARGS SV_BroadcastCommand (const char *fmt, ...) LIKEPRINTF(1);
void SV_SendServerInfoChange(const char *key, const char *value);
void SV_SendMessagesToAll (void);
void SV_FindModelNumbers (void);

View File

@ -579,7 +579,7 @@ void SV_Map_f (void)
if (!startspot)
{
//revert the startspot if its not overridden
Q_strncpyz(spot, Info_ValueForKey(svs.info, "*startspot"), sizeof(spot));
Q_strncpyz(spot, InfoBuf_ValueForKey(&svs.info, "*startspot"), sizeof(spot));
startspot = spot;
}
}
@ -664,7 +664,7 @@ void SV_Map_f (void)
if (!isDedicated) //otherwise, info used on map loading isn't present
{
cl.haveserverinfo = true;
Q_strncpyz (cl.serverinfo, svs.info, sizeof(cl.serverinfo));
InfoBuf_Clone(&cl.serverinfo, &svs.info);
CL_CheckServerInfo();
}
@ -1100,9 +1100,9 @@ void SV_EvaluatePenalties(client_t *cl)
}
if (delta & BAN_VIP)
Info_SetValueForStarKey(cl->userinfo, "*VIP", (cl->penalties & BAN_VIP)?"1":"", sizeof(cl->userinfo));
InfoBuf_SetStarKey(&cl->userinfo, "*VIP", (cl->penalties & BAN_VIP)?"1":"");
if (delta & BAN_MAPPER)
Info_SetValueForStarKey(cl->userinfo, "*mapper", (cl->penalties & BAN_MAPPER)?"1":"", sizeof(cl->userinfo));
InfoBuf_SetStarKey(&cl->userinfo, "*mapper", (cl->penalties & BAN_MAPPER)?"1":"");
}
static time_t reevaluatebantime;
@ -1623,7 +1623,7 @@ static void SV_ForceName_f (void)
while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum)))
{
Info_SetValueForKey(cl->userinfo, "name", Cmd_Argv(2), EXTENDED_INFO_STRING);
InfoBuf_SetKey(&cl->userinfo, "name", Cmd_Argv(2));
SV_LogPlayer(cl, "name forced");
SV_ExtractFromUserinfo(cl, true);
Q_strncpyz(cl->name, Cmd_Argv(2), sizeof(cl->namebuf));
@ -2192,51 +2192,6 @@ static void SV_Heartbeat_f (void)
SV_Master_ReResolve();
}
#define FOREACHCLIENT(i,cl) \
for (i = sv.mvdrecording?-1:0; i < sv.allocated_client_slots; i++) \
if ((cl = (i==-1?&demo.recorder:&svs.clients[i]))) \
if ((i == -1) || cl->state >= cs_connected)
void SV_SendServerInfoChange(const char *key, const char *value)
{
int i;
client_t *cl;
if (!sv.state)
return;
#ifdef Q2SERVER
if (svs.gametype == GT_QUAKE2)
return; //FIXME!!!
#endif
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3)
return; //FIXME!!!
#endif
FOREACHCLIENT(i, cl)
{
if (cl->controller)
continue;
if (ISQWCLIENT(cl))
{
ClientReliableWrite_Begin(cl, svc_serverinfo, strlen(key) + strlen(value)+3);
ClientReliableWrite_String(cl, key);
ClientReliableWrite_String(cl, value);
}
else if (ISNQCLIENT(cl) && (cl->fteprotocolextensions2 & PEXT2_PREDINFO))
{
ClientReliableWrite_Begin(cl, svc_stufftext, 1+6+strlen(key)+2+strlen(value)+3);
ClientReliableWrite_SZ(cl, "//svi ", 6);
ClientReliableWrite_SZ(cl, key, strlen(key));
ClientReliableWrite_SZ(cl, " \"", 2);
ClientReliableWrite_SZ(cl, value, strlen(value));
ClientReliableWrite_String(cl, "\"\n");
}
}
}
/*
===========
SV_Serverinfo_f
@ -2253,7 +2208,7 @@ void SV_Serverinfo_f (void)
if (Cmd_Argc() == 1)
{
Con_TPrintf ("Server info settings:\n");
Info_Print (svs.info, "");
InfoBuf_Print (&svs.info, "");
return;
}
@ -2268,18 +2223,18 @@ void SV_Serverinfo_f (void)
if (!strcmp(Cmd_Argv(1), "*"))
if (!strcmp(Cmd_Argv(2), ""))
{ //clear it out
char *k;
const char *k;
for(i=0;;)
{
k = Info_KeyForNumber(svs.info, i);
if (!*k)
k = InfoBuf_KeyForNumber(&svs.info, i);
if (!k)
break; //no more.
else if (*k == '*')
i++; //can't remove * keys
else if ((var = Cvar_FindVar(k)) && var->flags&CVAR_SERVERINFO)
i++; //this one is a cvar.
else
Info_RemoveKey(svs.info, k); //we can remove this one though, so yay.
InfoBuf_RemoveKey(&svs.info, k); //we can remove this one though, so yay.
}
return;
@ -2287,15 +2242,34 @@ void SV_Serverinfo_f (void)
Con_Printf ("Can't set * keys\n");
return;
}
Q_strncpyz(value, Cmd_Argv(2), sizeof(value));
value[sizeof(value)-1] = '\0';
for (i = 3; i < Cmd_Argc(); i++)
{
strncat(value, " ", sizeof(value)-1);
strncat(value, Cmd_Argv(i), sizeof(value)-1);
}
Info_SetValueForKey (svs.info, Cmd_Argv(1), value, MAX_SERVERINFO_STRING);
if (!strcmp(Cmd_Argv(0), "serverinfoblob"))
{
qofs_t fsize;
char *data = FS_MallocFile(Cmd_Argv(2), FS_GAME, &fsize);
if (!data)
{
Con_Printf ("Unable to read %s\n", Cmd_Argv(2));
return;
}
if (fsize > 64*1024*1024)
Con_Printf ("File is over 64mb\n");
else
InfoBuf_SetStarBlobKey(&svs.info, Cmd_Argv(1), data, fsize);
FS_FreeFile(data);
}
else
{
Q_strncpyz(value, Cmd_Argv(2), sizeof(value));
value[sizeof(value)-1] = '\0';
for (i = 3; i < Cmd_Argc(); i++)
{
strncat(value, " ", sizeof(value)-1);
strncat(value, Cmd_Argv(i), sizeof(value)-1);
}
InfoBuf_SetValueForKey (&svs.info, Cmd_Argv(1), value);
}
// if this is a cvar, change it too
var = Cvar_FindVar (Cmd_Argv(1));
@ -2306,8 +2280,6 @@ void SV_Serverinfo_f (void)
var->string = Z_StrDup (value);
var->value = Q_atof (var->string);
*/ }
SV_SendServerInfoChange(Cmd_Argv(1), value);
}
@ -2325,7 +2297,7 @@ static void SV_Localinfo_f (void)
if (Cmd_Argc() == 1)
{
Con_TPrintf ("Local info settings:\n");
Info_Print (localinfo, "");
InfoBuf_Print (&svs.localinfo, "");
return;
}
@ -2340,14 +2312,14 @@ static void SV_Localinfo_f (void)
if (!strcmp(Cmd_Argv(1), "*"))
if (!strcmp(Cmd_Argv(2), ""))
{ //clear it out
Info_RemoveNonStarKeys(localinfo);
InfoBuf_Clear(&svs.localinfo, false);
return;
}
Con_Printf ("Can't set * keys\n");
return;
}
old = Info_ValueForKey(localinfo, Cmd_Argv(1));
Info_SetValueForKey (localinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_LOCALINFO_STRING);
old = InfoBuf_ValueForKey(&svs.localinfo, Cmd_Argv(1));
InfoBuf_SetValueForKey (&svs.localinfo, Cmd_Argv(1), Cmd_Argv(2));
PR_LocalInfoChanged(Cmd_Argv(1), old, Cmd_Argv(2));
@ -2358,10 +2330,10 @@ void SV_SaveInfos(vfsfile_t *f)
{
VFS_WRITE(f, "\n", 1);
VFS_WRITE(f, "serverinfo * \"\"\n", 16);
Info_WriteToFile(f, svs.info, "serverinfo", CVAR_SERVERINFO);
InfoBuf_WriteToFile(f, &svs.info, "serverinfo", CVAR_SERVERINFO);
VFS_WRITE(f, "\n", 1);
VFS_WRITE(f, "localinfo * \"\"\n", 15);
Info_WriteToFile(f, localinfo, "localinfo", 0);
InfoBuf_WriteToFile(f, &svs.localinfo, "localinfo", 0);
}
/*
@ -2390,7 +2362,7 @@ void SV_User_f (void)
"fatness", "hlbsp", "bullet", "hullsize", "modeldbl", "entitydbl", "entitydbl2", "floatcoords",
"OLD vweap", "q2bsp", "q3bsp", "colormod", "splitscreen", "hexen2", "spawnstatic2", "customtempeffects",
"packents", "UNKNOWN", "showpic", "setattachment","UNKNOWN", "chunkeddls", "csqc", "dpflags"};
static const char *pext2names[32] = { "prydoncursor", "voip", "setangledelta", "rplcdeltas", "maxplayers", "predinfo", "sizeenc", "UNKNOWN",
static const char *pext2names[32] = { "prydoncursor", "voip", "setangledelta", "rplcdeltas", "maxplayers", "predinfo", "sizeenc", "infoblobs",
"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"};
@ -2405,14 +2377,17 @@ void SV_User_f (void)
Con_Printf("Userinfo:\n");
while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum)))
{
Info_Print (cl->userinfo, " ");
InfoBuf_Print (&cl->userinfo, " ");
switch(cl->protocol)
{
case SCP_BAD:
Con_Printf("protocol: bot/invalid\n");
break;
case SCP_QUAKEWORLD:
Con_Printf("protocol: quakeworld\n");
case SCP_QUAKEWORLD: //branding is everything...
if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
Con_Printf("protocol: fteqw-nack\n");
else
Con_Printf("protocol: quakeworld\n");
break;
case SCP_QUAKE2:
Con_Printf("protocol: quake2\n");
@ -2421,13 +2396,19 @@ void SV_User_f (void)
Con_Printf("protocol: quake3\n");
break;
case SCP_NETQUAKE:
Con_Printf("protocol: (net)quake\n");
if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
Con_Printf("protocol: ftenq-nack\n");
else
Con_Printf("protocol: (net)quake\n");
break;
case SCP_BJP3:
Con_Printf("protocol: bjp3\n");
break;
case SCP_FITZ666:
Con_Printf("protocol: fitzquake 666\n");
if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
Con_Printf("protocol: fte666-nack\n");
else
Con_Printf("protocol: fitzquake 666\n");
break;
case SCP_DARKPLACES6:
Con_Printf("protocol: dpp6\n");
@ -2442,9 +2423,12 @@ void SV_User_f (void)
if (cl->fteprotocolextensions)
{
unsigned int effective = cl->fteprotocolextensions;
if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) //these flags were made obsolete. don't list them.
effective &= ~(PEXT_SCALE|PEXT_TRANS|PEXT_ACCURATETIMINGS|PEXT_FATNESS|PEXT_HULLSIZE|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_COLOURMOD|PEXT_SPAWNSTATIC2|PEXT_SETATTACHMENT|PEXT_DPFLAGS);
Con_Printf("pext1:");
for (u = 0; u < 32; u++)
if (cl->fteprotocolextensions & (1u<<u))
if (effective & (1u<<u))
Con_Printf(" %s", pext1names[u]);
Con_Printf("\n");
}
@ -2520,7 +2504,7 @@ static void SV_Gamedir (void)
if (Cmd_Argc() == 1)
{
Con_TPrintf ("Current gamedir: %s\n", Info_ValueForKey (svs.info, "*gamedir"));
Con_TPrintf ("Current gamedir: %s\n", InfoBuf_ValueForKey (&svs.info, "*gamedir"));
return;
}
@ -2539,7 +2523,7 @@ static void SV_Gamedir (void)
return;
}
Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey (&svs.info, "*gamedir", dir);
}
static int QDECL CompleteGamedirPath (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
@ -2630,7 +2614,7 @@ static void SV_Gamedir_f (void)
else
{
COM_Gamedir (dir, NULL);
Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey (&svs.info, "*gamedir", dir);
}
Z_Free(dir);
}
@ -3004,6 +2988,7 @@ void SV_InitOperatorCommands (void)
Cmd_AddCommand ("sayone", SV_ConSayOne_f);
Cmd_AddCommand ("tell", SV_ConSayOne_f);
Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); //commands that conflict with client commands.
Cmd_AddCommand ("serverinfoblob", SV_Serverinfo_f); //commands that conflict with client commands.
Cmd_AddCommand ("user", SV_User_f);
Cmd_AddCommand ("god", SV_God_f);

View File

@ -585,7 +585,7 @@ unsigned SV_CheckModel(char *mdl)
unsigned short crc;
// int len;
buf = (qbyte *)COM_LoadFile (mdl, 5, &fsize);
buf = (qbyte *)FS_LoadMallocFile (mdl, &fsize);
if (!buf)
return 0;
crc = QCRC_Block(buf, fsize);
@ -645,6 +645,7 @@ void SV_UnspawnServer (void) //terminate the running server.
svs.clients[i].state = 0;
*svs.clients[i].namebuf = '\0';
svs.clients[i].name = NULL;
InfoBuf_Clear(&svs.clients[i].userinfo, true);
}
free(svs.clients);
svs.clients = NULL;
@ -693,6 +694,13 @@ void SV_UpdateMaxPlayers(int newmax)
svs.clients[i].controller = svs.clients + (svs.clients[i].controller - old);
}
svs.allocated_client_slots = sv.allocated_client_slots = newmax;
for (i = 0; i < svs.allocated_client_slots; i++)
{
InfoSync_Clear(&svs.clients[i].infosync);
svs.clients[i].userinfo.ChangeCB = svs.info.ChangeCB;
svs.clients[i].userinfo.ChangeCTX = &svs.clients[i].userinfo;
}
}
sv.allocated_client_slots = svs.allocated_client_slots;
}
@ -874,7 +882,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
{
svs.clients[i].nextservertimeupdate = 0;
if (!svs.clients[i].state) //bots with the net_preparse module.
svs.clients[i].userinfo[0] = '\0'; //clear the userinfo to clear the name
InfoBuf_Clear(&svs.clients[i].userinfo, true); //clear the userinfo to clear the name
if (svs.clients[i].netchan.remote_address.type == NA_LOOPBACK)
{ //forget this client's message buffers, so that any shared client/server network state persists (eg: float coords)
@ -943,17 +951,17 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
if (sv_cheats.ival)
{
sv_allow_cheats = true;
Info_SetValueForStarKey(svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*cheats", "ON");
}
else
{
sv_allow_cheats = 2;
Info_SetValueForStarKey(svs.info, "*cheats", "", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*cheats", "");
}
#ifndef SERVERONLY
//This fixes a bug where the server advertises cheats, the internal client connects, and doesn't think cheats are allowed.
//this applies to anything that can affect the content that is loaded by the server, but cheats is the only special one (because of the *)
Q_strncpyz(cl.serverinfo, svs.info, sizeof(cl.serverinfo));
InfoBuf_Clone(&cl.serverinfo, &svs.info);
if (!isDedicated)
CL_CheckServerInfo();
#endif
@ -1029,16 +1037,16 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
#endif
if (sv.world.worldmodel->fromgame == fg_doom)
Info_SetValueForStarKey(svs.info, "*bspversion", "1", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*bspversion", "1");
else if (sv.world.worldmodel->fromgame == fg_halflife)
Info_SetValueForStarKey(svs.info, "*bspversion", "30", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*bspversion", "30");
else if (sv.world.worldmodel->fromgame == fg_quake2)
Info_SetValueForStarKey(svs.info, "*bspversion", "38", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*bspversion", "38");
else if (sv.world.worldmodel->fromgame == fg_quake3)
Info_SetValueForStarKey(svs.info, "*bspversion", "46", MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*bspversion", "46");
else
Info_SetValueForStarKey(svs.info, "*bspversion", "", MAX_SERVERINFO_STRING);
Info_SetValueForStarKey(svs.info, "*startspot", (startspot?startspot:""), MAX_SERVERINFO_STRING);
InfoBuf_SetStarKey(&svs.info, "*bspversion", "");
InfoBuf_SetStarKey(&svs.info, "*startspot", (startspot?startspot:""));
//
// init physics interaction links
@ -1049,7 +1057,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
#ifdef PEXT_CSQC
fsz = 0;
if (*sv_csqc_progname.string)
file = COM_LoadTempFile(sv_csqc_progname.string, &fsz);
file = COM_LoadTempFile(sv_csqc_progname.string, 0, &fsz);
else
file = NULL;
if (file)
@ -1057,27 +1065,27 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
char text[64];
sv.csqcchecksum = Com_BlockChecksum(file, fsz);
sprintf(text, "0x%x", sv.csqcchecksum);
Info_SetValueForStarKey(svs.info, "*csprogs", text, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csprogs", text);
sprintf(text, "0x%x", (unsigned int)fsz);
Info_SetValueForStarKey(svs.info, "*csprogssize", text, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csprogssize", text);
if (strcmp(sv_csqc_progname.string, "csprogs.dat"))
Info_SetValueForStarKey(svs.info, "*csprogsname", sv_csqc_progname.string, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csprogsname", sv_csqc_progname.string);
else
Info_SetValueForStarKey(svs.info, "*csprogsname", "", MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csprogsname", "");
}
else
{
sv.csqcchecksum = 0;
Info_SetValueForStarKey(svs.info, "*csprogs", "", MAX_SERVERINFO_STRING);
Info_SetValueForStarKey(svs.info, "*csprogssize", "", MAX_SERVERINFO_STRING);
Info_SetValueForStarKey(svs.info, "*csprogsname", "", MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csprogs", "");
InfoBuf_SetValueForStarKey(&svs.info, "*csprogssize", "");
InfoBuf_SetValueForStarKey(&svs.info, "*csprogsname", "");
}
sv.csqcdebug = sv_csqcdebug.value;
if (sv.csqcdebug)
Info_SetValueForStarKey(svs.info, "*csqcdebug", "1", MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*csqcdebug", "1");
else
Info_RemoveKey(svs.info, "*csqcdebug");
InfoBuf_RemoveKey(&svs.info, "*csqcdebug");
#endif
if (svs.gametype == GT_PROGS)
@ -1272,6 +1280,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
svs.clients[i].edict = NULL;
svs.clients[i].name = svs.clients[i].namebuf;
svs.clients[i].team = svs.clients[i].teambuf;
InfoSync_Clear(&svs.clients[i].infosync); //we'll mark all the info as dirty at some point while connecting.
}
switch (svs.gametype)
@ -1368,8 +1377,8 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
for (i=0 ; i<sv.allocated_client_slots ; i++)
{
Q_strncpyz(svs.clients[i].name, Info_ValueForKey(svs.clients[i].userinfo, "name"), sizeof(svs.clients[i].namebuf));
Q_strncpyz(svs.clients[i].team, Info_ValueForKey(svs.clients[i].userinfo, "team"), sizeof(svs.clients[i].teambuf));
Q_strncpyz(svs.clients[i].name, InfoBuf_ValueForKey(&svs.clients[i].userinfo, "name"), sizeof(svs.clients[i].namebuf));
Q_strncpyz(svs.clients[i].team, InfoBuf_ValueForKey(&svs.clients[i].userinfo, "team"), sizeof(svs.clients[i].teambuf));
}
#ifndef SERVERONLY
@ -1484,10 +1493,10 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
{
char crc[12];
sprintf(crc, "%i", sv.world.worldmodel->entitiescrc);
Info_SetValueForStarKey(svs.info, "*entfile", crc, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*entfile", crc);
}
else
Info_SetValueForStarKey(svs.info, "*entfile", "", MAX_SERVERINFO_STRING);
InfoBuf_SetValueForStarKey(&svs.info, "*entfile", "");
file = Mod_GetEntitiesString(sv.world.worldmodel);
if (!file)
@ -1599,7 +1608,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents,
SV_GibFilterInit();
SV_FilterImpulseInit();
Info_SetValueForKey (svs.info, "map", svs.name, MAX_SERVERINFO_STRING);
InfoBuf_SetValueForKey (&svs.info, "map", svs.name);
if (sv.allocated_client_slots != 1)
Con_TPrintf ("Server spawned.\n"); //misc filenotfounds can be misleading.

View File

@ -271,6 +271,10 @@ void SV_Shutdown (void)
Cmd_Shutdown();
PM_Shutdown();
InfoBuf_Clear(&svs.info, true);
InfoBuf_Clear(&svs.localinfo, true);
#ifdef WEBSERVER
IWebShutdown();
#endif
@ -643,7 +647,8 @@ void SV_DropClient (client_t *drop)
#endif
drop->namebuf[0] = 0;
drop->name = drop->namebuf;
memset (drop->userinfo, 0, sizeof(drop->userinfo));
InfoBuf_Clear(&drop->userinfo, true);
InfoSync_Clear(&drop->infosync);
while ((lp = drop->laggedpacket))
{
@ -943,39 +948,6 @@ int SV_CalcPing (client_t *cl, qboolean forcecalc)
return 0;
}
//generate whatever public userinfo is supported by the client.
//private keys like _ prefixes and the password key are stripped out here.
//password needs to be stripped in case the password key doesn't actually relate to this server.
void SV_GeneratePublicUserInfo(int pext, client_t *cl, char *info, int infolength)
{
char *key, *s;
int i;
//FIXME: we should probably use some sort of priority system instead if I'm honest about it
if (pext & PEXT_BIGUSERINFOS)
Q_strncpyz (info, cl->userinfo, infolength);
else
{
if (infolength >= BASIC_INFO_STRING)
infolength = BASIC_INFO_STRING;
*info = 0;
for (i = 0; (key = Info_KeyForNumber(cl->userinfo, i)); i++)
{
if (!*key)
break;
if (!SV_UserInfoIsBasic(key))
continue;
s = Info_ValueForKey(cl->userinfo, key);
Info_SetValueForStarKey (info, key, s, infolength);
}
}
Info_RemovePrefixedKeys (info, '_'); // server passwords, etc
Info_RemoveKey(info, "password");
Info_RemoveKey(info, "*ip");
}
/*
===================
SV_FullClientUpdate
@ -1011,6 +983,7 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
if (ISQWCLIENT(to))
{
unsigned int pext = to->fteprotocolextensions;
int ping = SV_CalcPing (client, false);
if (ping > 0xffff)
ping = 0xffff;
@ -1031,8 +1004,7 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
ClientReliableWrite_Byte (to, i);
ClientReliableWrite_Float (to, realtime - client->connection_started);
SV_GeneratePublicUserInfo(to->fteprotocolextensions, client, info, sizeof(info));
InfoBuf_ToString(&client->userinfo, info, (pext&PEXT_BIGUSERINFOS)?BASIC_INFO_STRING:sizeof(info), basicuserinfos, privateuserinfos, (pext&PEXT_BIGUSERINFOS)?NULL:basicuserinfos, NULL, NULL);
ClientReliableWrite_Begin(to, svc_updateuserinfo, 7 + strlen(info));
ClientReliableWrite_Byte (to, i);
ClientReliableWrite_Long (to, client->userid);
@ -1041,7 +1013,7 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
else if (ISNQCLIENT(to))
{
int top, bottom, playercolor;
char *nam = Info_ValueForKey(client->userinfo, "name");
char *nam = InfoBuf_ValueForKey(&client->userinfo, "name");
ClientReliableWrite_Begin(to, svc_updatefrags, 4);
ClientReliableWrite_Byte (to, i);
@ -1051,8 +1023,8 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
ClientReliableWrite_Byte (to, i);
ClientReliableWrite_String(to, nam);
top = atoi(Info_ValueForKey(client->userinfo, "topcolor"));
bottom = atoi(Info_ValueForKey(client->userinfo, "bottomcolor"));
top = atoi(InfoBuf_ValueForKey(&client->userinfo, "topcolor"));
bottom = atoi(InfoBuf_ValueForKey(&client->userinfo, "bottomcolor"));
top &= 15;
if (top > 13)
top = 13;
@ -1067,8 +1039,9 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
if (to->fteprotocolextensions2 & PEXT2_PREDINFO)
{
char quotedval[8192];
char *s = va("//fui %i %s\n", i, COM_QuotedString(client->userinfo, quotedval, sizeof(quotedval), false));
char *s;
InfoBuf_ToString(&client->userinfo, info, sizeof(info), basicuserinfos, privateuserinfos, NULL, NULL, NULL);
s = va("//fui %i \"%s\"\n", i, info);
ClientReliableWrite_Begin(to, svc_stufftext, 2+strlen(s));
ClientReliableWrite_String(to, s);
}
@ -1124,21 +1097,27 @@ static void SVC_Status (void)
Cmd_TokenizeString ("status", false, false);
SV_BeginRedirect (RD_PACKET, TL_FindLanguage(""));
if (displayflags&STATUS_SERVERINFO)
Con_Printf ("%s\n", svs.info);
{
char infostr[1024]; //FIXME: vanilla limit is 512. we should probably have a list of known cvars for lower priority sending.
const char *ignorekeys[] = {"mapname", "*z_ext", NULL}; //ignore some pointless stuff
const char *prioritykeys[] = {"hostname", "admin", "*gamedir", "*version", "deathmatch", "timelimit", "fraglimit", "maxclients", "maxspectators", "status", NULL}; //make sure we include these before we start overflowing
InfoBuf_ToString(&svs.info, infostr, sizeof(infostr), prioritykeys, ignorekeys, NULL, NULL, NULL);
Con_Printf ("%s\n", infostr);
}
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
cl = &svs.clients[i];
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && ((cl->spectator && displayflags&STATUS_SPECTATORS) || (!cl->spectator && displayflags&STATUS_PLAYERS)))
{
top = atoi(Info_ValueForKey (cl->userinfo, "topcolor"));
bottom = atoi(Info_ValueForKey (cl->userinfo, "bottomcolor"));
top = atoi(InfoBuf_ValueForKey (&cl->userinfo, "topcolor"));
bottom = atoi(InfoBuf_ValueForKey (&cl->userinfo, "bottomcolor"));
top = (top < 0) ? 0 : ((top > 13) ? 13 : top);
bottom = (bottom < 0) ? 0 : ((bottom > 13) ? 13 : bottom);
ping = SV_CalcPing (cl, false);
name = cl->name;
skin = Info_ValueForKey (cl->userinfo, "skin");
team = Info_ValueForKey (cl->userinfo, "team");
skin = InfoBuf_ValueForKey (&cl->userinfo, "skin");
team = InfoBuf_ValueForKey (&cl->userinfo, "team");
if (!cl->state || cl->protocol == SCP_BAD) //show bots differently. Just to be courteous.
botpre = "BOT:";
@ -1235,26 +1214,31 @@ static void SVC_GetInfo (char *challenge, int fullstatus)
resp += strlen(resp);
*resp++ = '\n';
//first line is the serverinfo
Q_strncpyz(resp, svs.info, sizeof(response) - (resp-response));
//this is a DP protocol query, so some QW fields are not needed
Info_RemoveKey(resp, "maxclients"); //replaced with sv_maxclients
Info_RemoveKey(resp, "map"); //replaced with mapname
Info_RemoveKey(resp, "*gamedir"); //replaced with modname
Info_RemoveKey(resp, "*z_ext"); //uninteresting and spammy.
Info_SetValueForKey(resp, "gamename", protocolname, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response));
// Info_SetValueForKey(resp, "gamedir", FS_GetGamedir(true), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "protocol", va("%d", com_protocolversion.ival), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "mapname", Info_ValueForKey(svs.info, "map"), sizeof(response) - (resp-response));
if (*gamestatus)
Info_SetValueForKey(resp, "qcstatus", gamestatus, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "challenge", challenge, sizeof(response) - (resp-response));
resp += strlen(resp);
//first line contains the serverinfo, or some form of it
{
const char *ignorekeys[] = {
"maxclients", "map", "*gamedir", "*z_ext", //this is a DP protocol query, so some QW fields are not needed
"gamename", "modname", "protocol", "clients", "sv_maxclients", "mapname", "qcstatus", "challenge", NULL}; //and we need to add some
const char *prioritykeys[] = {"hostname", NULL}; //make sure we include these before we start overflowing
*resp++ = 0; //there's already a null, but hey
*resp = 0;
Info_SetValueForKey(resp, "challenge", challenge, sizeof(response) - (resp-response)); //the challenge can be important for the master protocol to prevent poisoning
Info_SetValueForKey(resp, "gamename", protocolname, sizeof(response) - (resp-response));//distinguishes it from other types of games
Info_SetValueForKey(resp, "protocol", com_protocolversion.string, sizeof(response) - (resp-response)); //should be an int.
Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "mapname", InfoBuf_ValueForKey(&svs.info, "map"), sizeof(response) - (resp-response));
resp += strlen(resp);
//now include the full/regular serverinfo
resp += InfoBuf_ToString(&svs.info, resp, sizeof(response) - (resp-response), prioritykeys, ignorekeys, NULL, NULL, NULL);
*resp = 0;
//and any possibly-long qc status string
if (*gamestatus)
Info_SetValueForKey(resp, "qcstatus", gamestatus, sizeof(response) - (resp-response));
resp += strlen(resp);
}
*resp++ = 0;
if (fullstatus)
{
@ -2225,21 +2209,18 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id)
case GT_QUAKE2:
cl->q2edict = Q2EDICT_NUM(i+1);
if (!ge->ClientConnect(cl->q2edict, cl->userinfo))
if (!ge->ClientConnect(cl->q2edict, info))
{
const char *reject = Info_ValueForKey(cl->userinfo, "rejmsg");
const char *reject = Info_ValueForKey(info, "rejmsg");
if (*reject)
SV_ClientPrintf(controller, PRINT_HIGH, "Splitscreen Refused: %s\n", reject);
else
SV_ClientPrintf(controller, PRINT_HIGH, "Splitscreen Refused\n");
Con_DPrintf ("Game rejected a connection.\n");
*cl->userinfo = 0;
cl->namebuf[0] = 0;
return NULL;
}
ge->ClientUserinfoChanged(cl->q2edict, cl->userinfo);
ge->ClientUserinfoChanged(cl->q2edict, info);
break;
#endif
default:
@ -2252,13 +2233,11 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id)
cl->controller = controller;
cl->controlled = NULL;
Q_strncpyS (cl->userinfo, info, sizeof(cl->userinfo)-1);
cl->userinfo[sizeof(cl->userinfo)-1] = '\0';
Info_RemoveKey (cl->userinfo, "spectator");
InfoBuf_FromString(&cl->userinfo, info, false);
InfoBuf_RemoveKey (&cl->userinfo, "spectator");
//this is a hint rather than a game breaker should it fail.
if (cl->spectator)
Info_SetValueForStarKey (cl->userinfo, "*spectator", va("%i", cl->spectator), sizeof(cl->userinfo));
InfoBuf_SetValueForStarKey (&cl->userinfo, "*spectator", va("%i", cl->spectator));
cl->state = controller->state;
// host_client = NULL;
@ -2759,20 +2738,6 @@ client_t *SVC_DirectConnect(void)
if (sv.msgfromdemo)
newcl->wasrecorded = true;
// works properly
if (!sv_highchars.value)
{
qbyte *p, *q;
for (p = (qbyte *)newcl->userinfo, q = (qbyte *)userinfo;
*q && p < (qbyte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++)
if (*q > 31 && *q <= 127)
*p++ = *q;
}
else
Q_strncpyS (newcl->userinfo, userinfo[0], sizeof(newcl->userinfo)-1);
newcl->userinfo[sizeof(newcl->userinfo)-1] = '\0';
// Con_TPrintf("%s:%s:connect\n", sv.name, NET_AdrToString (adrbuf, sizeof(adrbuf), &adr));
// if there is already a slot for this ip, drop it
@ -2814,13 +2779,13 @@ client_t *SVC_DirectConnect(void)
}
}
name = Info_ValueForKey (temp.userinfo, "name");
name = Info_ValueForKey (userinfo[0], "name");
if (sv.world.worldmodel && protocol == SCP_QUAKEWORLD &&!atoi(Info_ValueForKey (temp.userinfo, "iknow")))
if (sv.world.worldmodel && protocol == SCP_QUAKEWORLD &&!atoi(Info_ValueForKey (userinfo[0], "iknow")))
{
if (sv.world.worldmodel->fromgame == fg_halflife && !(newcl->fteprotocolextensions & PEXT_HLBSP))
{
if (atof(Info_ValueForKey (temp.userinfo, "*FuhQuake")) < 0.3)
if (atof(Info_ValueForKey (userinfo[0], "*FuhQuake")) < 0.3)
{
SV_RejectMessage (protocol, "The server is using a halflife level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n");
// Con_Printf("player %s was dropped due to incompatible client\n", name);
@ -3045,9 +3010,9 @@ client_t *SVC_DirectConnect(void)
temp.edict = NULL;
temp.q2edict = q2ent;
if (!ge->ClientConnect(q2ent, temp.userinfo))
if (!ge->ClientConnect(q2ent, userinfo[0]))
{
const char *reject = Info_ValueForKey(temp.userinfo, "rejmsg");
const char *reject = Info_ValueForKey(userinfo[0], "rejmsg");
if (*reject)
SV_RejectMessage(protocol, "%s\nConnection Refused.", reject);
else
@ -3056,7 +3021,7 @@ client_t *SVC_DirectConnect(void)
return NULL;
}
ge->ClientUserinfoChanged(q2ent, temp.userinfo);
ge->ClientUserinfoChanged(q2ent, userinfo[0]);
break;
@ -3074,13 +3039,18 @@ client_t *SVC_DirectConnect(void)
temp.name = newcl->name;
temp.team = newcl->team;
InfoSync_Clear(&newcl->infosync);
*newcl = temp;
newcl->userinfo.ChangeCB = svs.info.ChangeCB;
newcl->userinfo.ChangeCTX = &svs.clients[i].userinfo;
InfoBuf_FromString(&newcl->userinfo, userinfo[0], false);
// NET_AdrToStringResolve(&adr, SV_UserDNSResolved, NULL, newcl-svs.clients, newcl->userid);
newcl->challenge = challenge;
newcl->zquake_extensions = atoi(Info_ValueForKey(newcl->userinfo, "*z_ext"));
if (*Info_ValueForKey(newcl->userinfo, "*fuhquake")) //fuhquake doesn't claim to support z_ext but does look at our z_ext serverinfo key.
newcl->zquake_extensions = atoi(InfoBuf_ValueForKey(&newcl->userinfo, "*z_ext"));
if (*InfoBuf_ValueForKey(&newcl->userinfo, "*fuhquake")) //fuhquake doesn't claim to support z_ext but does look at our z_ext serverinfo key.
{ //so switch on the bits that it should be sending.
newcl->zquake_extensions |= Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW;
}
@ -3089,7 +3059,7 @@ client_t *SVC_DirectConnect(void)
//ezquake's download mechanism is so smegging buggy.
//its causing far far far too many connectivity issues. seriously. its beyond a joke. I cannot stress that enough.
//as the client needs to listen for the serverinfo to know which extensions will actually be used (yay demos), we can just forget that it supports svc-level extensions, at least for anything that isn't spammed via clc_move etc before the serverinfo.
s = Info_ValueForKey(newcl->userinfo, "*client");
s = InfoBuf_ValueForKey(&newcl->userinfo, "*client");
if (!strncmp(s, "ezQuake", 7) && (newcl->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS))
{
if (pext_ezquake_nochunks.ival)
@ -3184,7 +3154,7 @@ client_t *SVC_DirectConnect(void)
SV_RejectMessage (protocol, "Rankings/Account system failed\n");
Con_TPrintf("banned player %s is trying to connect\n", newcl->name);
newcl->name[0] = 0;
memset (newcl->userinfo, 0, sizeof(newcl->userinfo));
InfoBuf_Clear(&newcl->userinfo, true);
newcl->state = cs_free;
return NULL;
}
@ -3312,7 +3282,7 @@ client_t *SVC_DirectConnect(void)
if (spectators >= maxspectators.ival)
newcl->drop = true; //oops.
newcl->spectator = spectator = true;
Info_SetValueForStarKey (cl->userinfo, "*spectator", "1", sizeof(cl->userinfo));
InfoBuf_SetValueForStarKey (&cl->userinfo, "*spectator", "1");
}
//only advertise PEXT_SPLITSCREEN when splitscreen is allowed, to avoid spam. this might mean people need to reconnect after its enabled. oh well.
@ -4076,18 +4046,18 @@ qboolean SVNQ_ConnectionlessPacket(void)
SZ_Clear (&sb);
MSG_WriteLong (&sb, 0);
{
char *rname, *rval, *kname;
const char *rname, *rval, *kname;
rname = MSG_ReadString();
if (!*rname)
rname = Info_KeyForNumber(svs.info, 0);
rname = InfoBuf_KeyForNumber(&svs.info, 0);
else
{
int i = 0;
for(;;)
{
kname = Info_KeyForNumber(svs.info, i);
if (!*kname)
kname = InfoBuf_KeyForNumber(&svs.info, i);
if (!kname)
{
rname = NULL;
break;
@ -4095,12 +4065,15 @@ qboolean SVNQ_ConnectionlessPacket(void)
i++;
if (!strcmp(kname, rname))
{
rname = Info_KeyForNumber(svs.info, i);
rname = InfoBuf_KeyForNumber(&svs.info, i);
break;
}
}
}
rval = Info_ValueForKey(svs.info, rname);
if (rname)
rval = InfoBuf_ValueForKey(&svs.info, rname);
else
rval = rname = "";
MSG_WriteByte (&sb, CCREP_RULE_INFO);
MSG_WriteString (&sb, rname);
MSG_WriteString (&sb, rval);
@ -4627,9 +4600,9 @@ void SV_CheckVars (void)
Con_DPrintf ("Updated needpass.\n");
if (!v)
Info_SetValueForKey (svs.info, "needpass", "", MAX_SERVERINFO_STRING);
InfoBuf_SetValueForKey (&svs.info, "needpass", "");
else
Info_SetValueForKey (svs.info, "needpass", va("%i",v), MAX_SERVERINFO_STRING);
InfoBuf_SetValueForKey (&svs.info, "needpass", va("%i",v));
}
#ifdef Q2SERVER
@ -4815,8 +4788,7 @@ float SV_Frame (void)
newspeed = "";
else
newspeed = va("%g", sv.gamespeed*100);
Info_SetValueForStarKey(svs.info, "*gamespeed", newspeed, MAX_SERVERINFO_STRING);
SV_SendServerInfoChange("*gamespeed", newspeed);
InfoBuf_SetValueForStarKey(&svs.info, "*gamespeed", newspeed);
//correct sv.starttime
sv.starttime = Sys_DoubleTime() - (sv.time/sv.gamespeed);
@ -5048,6 +5020,23 @@ float SV_Frame (void)
return delay;
}
static void SV_InfoChanged(void *context, const char *key)
{
size_t i;
if (context != &svs.info && *key == '_')
return; //these keys are considered private to originating client/server, and are not broadcast to anyone else
if (svs.demorecording)
InfoSync_Add(&demo.recorder.infosync, context, key); //make sure it gets written into mvds too.
for (i = 0; i < svs.allocated_client_slots; i++)
{
if (svs.clients[i].state >= cs_connected)
{
InfoSync_Add(&svs.clients[i].infosync, context, key);
}
}
}
/*
===============
SV_InitLocal
@ -5232,9 +5221,10 @@ void SV_InitLocal (void)
SV_MVDInit();
Info_SetValueForStarKey (svs.info, "*version", version_string(), MAX_SERVERINFO_STRING);
Info_SetValueForStarKey (svs.info, "*z_ext", va("%i", SUPPORTED_Z_EXTENSIONS), MAX_SERVERINFO_STRING);
svs.info.ChangeCB = SV_InfoChanged;
svs.info.ChangeCTX = &svs.info;
InfoBuf_SetValueForStarKey (&svs.info, "*version", version_string());
InfoBuf_SetValueForStarKey (&svs.info, "*z_ext", va("%i", SUPPORTED_Z_EXTENSIONS));
// init fraglog stuff
svs.logsequence = 1;
@ -5251,17 +5241,18 @@ void SV_InitLocal (void)
}
#define iswhite(c) ((c) == ' ' || (unsigned char)(c) == (unsigned char)INVIS_CHAR1 || (unsigned char)(c) == (unsigned char)INVIS_CHAR2 || (unsigned char)(c) == (unsigned char)INVIS_CHAR3)
#define isinvalid(c) ((c) == ':' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff || (c) == '\"')
#define isinvalid(c) ((c) == ':' || (c) == '\\' || (c) == '\r' || (c) == '\n' || (unsigned char)(c) == (unsigned char)0xff || (c) == '\"')
//colon is so clients can't get confused while parsing chats
//255 is so fuhquake/ezquake don't end up with nameless players
//" is so mods that use player names in tokenizing/frik_files don't mess up. mods are still expected to be able to cope with space.
//\ is blocked because it messes up our ^[NAME\player\NUM^] links, and because vanilla would hate it.
//is allowed to shorten, out must be as long as in and min of "unnamed"+1
void SV_FixupName(const char *in, char *out, unsigned int outlen)
{
char *s, *p;
unsigned int len;
conchar_t testbuf[1024], *t, *e;
unsigned int len, codepoint, codeflags;
conchar_t testbuf[1024], *t, *n, *e;
if (outlen == 0)
return;
@ -5274,7 +5265,7 @@ void SV_FixupName(const char *in, char *out, unsigned int outlen)
while(*in && len > 1)
{
if (isinvalid(*in))
{
{ //chars that cause a problem.
in++;
continue;
}
@ -5285,16 +5276,21 @@ void SV_FixupName(const char *in, char *out, unsigned int outlen)
/*note: clients are not guarenteed to parse things the same as the server. utf-8 surrogates may be awkward here*/
e = COM_ParseFunString(CON_WHITEMASK, out, testbuf, sizeof(testbuf), false);
for (t = testbuf; t < e; t++)
for (t = testbuf; t < e; t = n)
{
n = Font_Decode(t, &codeflags, &codepoint);
/*reject anything hidden in names*/
if (*t & CON_HIDDEN)
if ((codeflags & CON_HIDDEN) || (codeflags&(CON_LINKSPECIAL|CON_RICHFORECOLOUR))==CON_LINKSPECIAL)
break;
/*reject pictograms*/
if ((*t & CON_CHARMASK) >= 0xe100 && (*t & CON_CHARMASK) < 0xe200)
if (codepoint >= 0xe100 && codepoint < 0xe200)
break;
if (!sv_highchars.ival && (codeflags & CON_2NDCHARSETTEXT))
break;
/*FIXME: should we try to ensure that the chars are in most fonts? that might annoy speakers of more exotic languages I suppose. cvar it?*/
}
//and spit it out again, which makes sure there's no weird markup that might screw up other strings.
COM_DeFunString(testbuf, t, out, outlen, false, false);
if (!*out || (t < e) || e == testbuf)
{ //reached end and it was all whitespace
@ -5316,9 +5312,9 @@ qboolean ReloadRanking(client_t *cl, const char *newname)
int newid;
int j;
rankstats_t rs;
newid = Rank_GetPlayerID(cl->guid, newname, atoi(Info_ValueForKey (cl->userinfo, "_pwd")), true, false); //'_' keys are always stripped. On any server. So try and use that so persistant data won't give out the password when connecting to a different server
newid = Rank_GetPlayerID(cl->guid, newname, atoi(InfoBuf_ValueForKey (&cl->userinfo, "_pwd")), true, false); //'_' keys are always stripped. On any server. So try and use that so persistant data won't give out the password when connecting to a different server
if (!newid)
newid = Rank_GetPlayerID(cl->guid, newname, atoi(Info_ValueForKey (cl->userinfo, "password")), true, false);
newid = Rank_GetPlayerID(cl->guid, newname, atoi(InfoBuf_ValueForKey (&cl->userinfo, "password")), true, false);
if (newid)
{
if (cl->rankid && cl->state >= cs_spawned)//apply current stats
@ -5383,23 +5379,23 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
extern cvar_t rank_filename;
#endif
int bottom = atoi(Info_ValueForKey(cl->userinfo, "bottomcolor"));
int bottom = atoi(InfoBuf_ValueForKey(&cl->userinfo, "bottomcolor"));
if (progstype == PROG_NQ)
p = va("t%u", bottom);
else
p = Info_ValueForKey(localinfo, va("team%u", bottom));
val = Info_ValueForKey (cl->userinfo, "team");
p = InfoBuf_ValueForKey(&svs.localinfo, va("team%u", bottom));
val = InfoBuf_ValueForKey (&cl->userinfo, "team");
if (*p && strcmp(p, val))
{
Info_SetValueForKey(cl->userinfo, "team", p, sizeof(cl->userinfo));
InfoBuf_SetValueForKey(&cl->userinfo, "team", p);
if (verbose)
SV_BroadcastUserinfoChange(cl, true, "team", p);
}
Q_strncpyz (cl->team, val, sizeof(cl->teambuf));
// name for C code
val = Info_ValueForKey (cl->userinfo, "name");
val = InfoBuf_ValueForKey (&cl->userinfo, "name");
if (cl->protocol != SCP_BAD || *val)
{
@ -5473,18 +5469,6 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
}
}
//try and actually set that new name, if it differs from what they asked for.
if (strcmp(val, newname))
{
Info_SetValueForKey (cl->userinfo, "name", newname, sizeof(cl->userinfo));
val = Info_ValueForKey (cl->userinfo, "name");
if (!*val)
{
SV_BroadcastTPrintf (PRINT_HIGH, "corrupt userinfo for player %s\n", cl->name);
cl->drop = true;
}
}
if (!cl->drop && strncmp(val, cl->name, sizeof(cl->namebuf)-1) && cl->state > cs_zombie)
{
if (*cl->name && cl->state >= cs_spawned && !cl->spectator && verbose)
@ -5506,30 +5490,41 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
}
}
val = Info_ValueForKey (cl->userinfo, "lang");
//make CERTAIN that the name we think they're using is actually the name everyone else sees too.
{
InfoBuf_SetValueForKey (&cl->userinfo, "name", newname);
val = InfoBuf_ValueForKey (&cl->userinfo, "name");
if (!*val)
{
SV_BroadcastTPrintf (PRINT_HIGH, "corrupt userinfo for player %s\n", cl->name);
cl->drop = true;
}
}
val = InfoBuf_ValueForKey (&cl->userinfo, "lang");
cl->language = *val?TL_FindLanguage(val):svs.language;
val = Info_ValueForKey (cl->userinfo, "nogib");
val = InfoBuf_ValueForKey (&cl->userinfo, "nogib");
cl->gibfilter = !!atoi(val);
// rate command
val = Info_ValueForKey (cl->userinfo, "rate");
val = InfoBuf_ValueForKey (&cl->userinfo, "rate");
if (strlen(val))
cl->rate = atoi(val);
else
cl->rate = 0;//0 means no specific limit, limited only by sv_maxrate.
val = Info_ValueForKey (cl->userinfo, "dupe");
val = InfoBuf_ValueForKey (&cl->userinfo, "dupe");
cl->netchan.dupe = bound(0, atoi(val), 5);
val = Info_ValueForKey (cl->userinfo, "drate");
val = InfoBuf_ValueForKey (&cl->userinfo, "drate");
if (strlen(val))
cl->drate = atoi(val);
else
cl->drate = 0; //0 disables rate limiting while downloading
#ifdef HEXEN2
val = Info_ValueForKey (cl->userinfo, "cl_playerclass");
val = InfoBuf_ValueForKey (&cl->userinfo, "cl_playerclass");
if (val)
{
PRH2_SetPlayerClass(cl, atoi(val), false);
@ -5537,13 +5532,13 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
#endif
// msg command
val = Info_ValueForKey (cl->userinfo, "msg");
val = InfoBuf_ValueForKey (&cl->userinfo, "msg");
if (strlen(val))
{
cl->messagelevel = atoi(val);
}
val = Info_ValueForKey (cl->userinfo, "sp"); //naming for compat with mvdsv
val = InfoBuf_ValueForKey (&cl->userinfo, "sp"); //naming for compat with mvdsv
if (*val)
cl->spec_print = atoi(val);
else
@ -5551,7 +5546,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
#ifdef NQPROT
{
int top = atoi(Info_ValueForKey(cl->userinfo, "topcolor"));
int top = atoi(InfoBuf_ValueForKey(&cl->userinfo, "topcolor"));
top &= 15;
if (top > 13)
top = 13;

View File

@ -823,7 +823,7 @@ void SV_MVD_FullClientUpdate(sizebuf_t *msg, client_t *player)
MSG_WriteByte (msg, player - svs.clients);
MSG_WriteFloat (msg, realtime - player->connection_started);
SV_GeneratePublicUserInfo(demo.recorder.fteprotocolextensions, player, info, sizeof(info));
InfoBuf_ToString(&player->userinfo, info, sizeof(info), basicuserinfos, privateuserinfos, NULL, &demo.recorder.infosync, player);
if (dosizes)
msg = MVDWrite_Begin (dem_all, 0, 7 + strlen(info));
@ -1205,12 +1205,12 @@ static char *SV_PrintTeams(void)
clients[numcl++] = &svs.clients[i];
for (j = 0; j < numt; j++)
if (!strcmp(Info_ValueForKey(svs.clients[i].userinfo, "team"), teams[j]))
if (!strcmp(InfoBuf_ValueForKey(&svs.clients[i].userinfo, "team"), teams[j]))
break;
if (j != numt)
continue;
teams[numt++] = Info_ValueForKey(svs.clients[i].userinfo, "team");
teams[numt++] = InfoBuf_ValueForKey(&svs.clients[i].userinfo, "team");
}
// create output
@ -1231,7 +1231,7 @@ static char *SV_PrintTeams(void)
{
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "team %s:\n", teams[j]);
for (i = 0; i < numcl; i++)
if (!strcmp(Info_ValueForKey(clients[i]->userinfo, "team"), teams[j]))
if (!strcmp(InfoBuf_ValueForKey(&clients[i]->userinfo, "team"), teams[j]))
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %s\n", clients[i]->name);
}
}
@ -1668,7 +1668,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
// send the serverdata
gamedir = Info_ValueForKey (svs.info, "*gamedir");
gamedir = InfoBuf_ValueForKey (&svs.info, "*gamedir");
if (!gamedir[0])
gamedir = FS_GetGamedir(true);
@ -2088,11 +2088,11 @@ char *Dem_Team(int num)
if (!client->name[0] || client->spectator)
continue;
if (first || strcmp(lastteam[index], Info_ValueForKey(client->userinfo, "team")))
if (first || strcmp(lastteam[index], InfoBuf_ValueForKey(&client->userinfo, "team")))
{
first = false;
num--;
lastteam[index] = Info_ValueForKey(client->userinfo, "team");
lastteam[index] = InfoBuf_ValueForKey(&client->userinfo, "team");
}
}
@ -2136,7 +2136,7 @@ char *Dem_PlayerNameTeam(char *t)
if (!client->name[0] || client->spectator)
continue;
if (strcmp(t, Info_ValueForKey(client->userinfo, "team"))==0)
if (strcmp(t, InfoBuf_ValueForKey(&client->userinfo, "team"))==0)
{
if (sep >= 1)
Q_strncatz (n, "_", sizeof(n));
@ -2158,7 +2158,7 @@ int Dem_CountTeamPlayers (char *t)
for (i = 0; i < sv.allocated_client_slots ; i++)
{
if (svs.clients[i].name[0] && !svs.clients[i].spectator)
if (strcmp(Info_ValueForKey(svs.clients[i].userinfo, "team"), t)==0)
if (strcmp(InfoBuf_ValueForKey(&svs.clients[i].userinfo, "team"), t)==0)
count++;
}

View File

@ -2683,7 +2683,7 @@ qboolean SV_CanTrack(client_t *client, int entity)
return false;
if (svs.clients[entity-1].spectator)
return false;
if (svs.clients[entity-1].state == cs_spawned || (svs.clients[entity-1].state == cs_free && *svs.clients[entity-1].userinfo))
if (svs.clients[entity-1].state == cs_spawned || (svs.clients[entity-1].state == cs_free && svs.clients[entity-1].userinfo.numkeys))
return true;
return false;
}
@ -2924,6 +2924,100 @@ void SV_FlushBroadcasts (void)
#endif
}
static qboolean SV_SyncInfoBuf(client_t *client)
{
const char *key = client->infosync.keys[0].name;
infobuf_t *info = client->infosync.keys[0].context;
size_t bloboffset = client->infosync.keys[0].syncpos;
//unsigned int seat = info - cls.userinfo;
size_t blobsize;
const char *blobdata = InfoBuf_BlobForKey(info, key, &blobsize);
size_t sendsize;
size_t bufferspace;
qboolean final;
char enckey[2048];
char encval[2048];
if (client->protocol == SCP_QUAKE2)
{ //q2 gamecode is fully responsible for networking this via configstrings.
InfoSync_Clear(&client->infosync);
return false;
}
if (host_client->num_backbuf)
return false;
if (client->netchan.message.cursize >= MAX_BACKBUFLEN/2)
return false; //don't bother trying to send anything.
if (!InfoBuf_EncodeString(key, strlen(key), enckey, sizeof(enckey)))
{
InfoSync_Remove(&client->infosync, 0);
return false;
}
sendsize = blobsize - bloboffset;
bufferspace = MAX_BACKBUFLEN - client->netchan.message.cursize;
bufferspace -= 7 - strlen(enckey) - 2; //extra overhead
bufferspace = (bufferspace/4)*3; //encoding overhead
sendsize = min(bufferspace, sendsize);
final = (bloboffset+sendsize >= blobsize);
if (!InfoBuf_EncodeString(blobdata+bloboffset, sendsize, encval, sizeof(encval)))
{
InfoSync_Remove(&client->infosync, 0);
return false;
}
if (final && !bloboffset && *enckey != '\xff' && *encval != '\xff')
{ //vanilla-compatible info.
if (ISNQCLIENT(client))
{ //except that nq never had any userinfo
const char *s = va("//ui %i \"%s\" \"%s\"\n", (client_t*)info-svs.clients, enckey, encval);
ClientReliableWrite_Begin(client, svc_stufftext, strlen(s)+2);
ClientReliableWrite_String(client, s);
}
else
{
if (info == &svs.info)
ClientReliableWrite_Begin(client, svc_serverinfo, 1+strlen(enckey)+1+strlen(encval)+1);
else
{
ClientReliableWrite_Begin(client, svc_setinfo, 2+strlen(enckey)+1+strlen(encval)+1);
ClientReliableWrite_Byte(client, (client_t*)info-svs.clients);
}
ClientReliableWrite_String(client, enckey);
ClientReliableWrite_String(client, encval);
}
}
else if (client->fteprotocolextensions2 & PEXT2_INFOBLOBS)
{
int pl;
if (info == &svs.info)
pl = 255; //colourmaps being 1-based with these being 0-based means that only 0-254 are valid players, and 255 is unused, so lets use it for serverinfo blobs.
else
pl = (client_t*)info-svs.clients;
ClientReliableWrite_Begin(client, svc_setinfo, 7+strlen(enckey)+1+strlen(encval)+1);
ClientReliableWrite_Byte(client, 255); //special meaning to say that this is a partial update
ClientReliableWrite_Byte(client, pl);
ClientReliableWrite_Long(client, (final?0x80000000:0)|bloboffset);
ClientReliableWrite_String(client, enckey);
ClientReliableWrite_String(client, encval);
}
else
{ //client can't receive this info, stop trying to send it.
InfoSync_Remove(&client->infosync, 0);
return true;
}
if (bloboffset+sendsize == blobsize)
InfoSync_Remove(&client->infosync, 0);
else
client->infosync.keys[0].syncpos += sendsize;
return true;
}
/*
=======================
SV_UpdateToReliableMessages
@ -2949,8 +3043,8 @@ void SV_UpdateToReliableMessages (void)
//DP_SV_CLIENTCOLORS
if (host_client->edict->xv->clientcolors != host_client->playercolor)
{
Info_SetValueForKey(host_client->userinfo, "topcolor", va("%i", (int)host_client->edict->xv->clientcolors/16), sizeof(host_client->userinfo));
Info_SetValueForKey(host_client->userinfo, "bottomcolor", va("%i", (int)host_client->edict->xv->clientcolors&15), sizeof(host_client->userinfo));
InfoBuf_SetValueForKey(&host_client->userinfo, "topcolor", va("%i", (int)host_client->edict->xv->clientcolors/16));
InfoBuf_SetValueForKey(&host_client->userinfo, "bottomcolor", va("%i", (int)host_client->edict->xv->clientcolors&15));
{
SV_ExtractFromUserinfo (host_client, true); //this will take care of nq for us anyway.
SV_BroadcastUserinfoChange(host_client, true, "*bothcolours", NULL);
@ -2974,7 +3068,7 @@ void SV_UpdateToReliableMessages (void)
Q_strncpyz(oname, host_client->name, sizeof(oname));
Con_DPrintf("Client %s programatically renamed to %s\n", host_client->name, name);
Info_SetValueForKey(host_client->userinfo, "name", name, sizeof(host_client->userinfo));
InfoBuf_SetValueForKey(&host_client->userinfo, "name", name);
SV_ExtractFromUserinfo (host_client, true);
if (strcmp(oname, host_client->name))
@ -3135,6 +3229,12 @@ void SV_UpdateToReliableMessages (void)
}
}
}
while (host_client->infosync.numkeys)
{
if (!SV_SyncInfoBuf(host_client))
break;
}
}
if (sv.reliable_datagram.overflowed)
@ -3173,7 +3273,7 @@ static void SV_SendUserinfoChange(client_t *to, client_t *about, qboolean isbasi
return;
if (!newval)
newval = Info_ValueForKey(about->userinfo, key);
newval = InfoBuf_ValueForKey(&about->userinfo, key);
if (ISQWCLIENT(to))
{
@ -3181,13 +3281,13 @@ static void SV_SendUserinfoChange(client_t *to, client_t *about, qboolean isbasi
{
if (ISQWCLIENT(to) && !strcmp(key, "*bothcolours"))
{
newval = Info_ValueForKey(about->userinfo, "topcolor");
newval = InfoBuf_ValueForKey(&about->userinfo, "topcolor");
ClientReliableWrite_Begin(to, svc_setinfo, 4+strlen(key)+strlen(newval));
ClientReliableWrite_Byte(to, playernum);
ClientReliableWrite_String(to, "topcolor");
ClientReliableWrite_String(to, Info_ValueForKey(about->userinfo, "topcolor"));
ClientReliableWrite_String(to, InfoBuf_ValueForKey(&about->userinfo, "topcolor"));
newval = Info_ValueForKey(about->userinfo, "bottomcolor");
newval = InfoBuf_ValueForKey(&about->userinfo, "bottomcolor");
ClientReliableWrite_Begin(to, svc_setinfo, 4+strlen(key)+strlen(newval));
ClientReliableWrite_Byte(to, playernum);
ClientReliableWrite_String(to, "bottomcolor");
@ -3223,8 +3323,8 @@ static void SV_SendUserinfoChange(client_t *to, client_t *about, qboolean isbasi
}
else if (!strcmp(key, "topcolor") || !strcmp(key, "bottomcolor") || !strcmp(key, "*bothcolours"))
{ //due to these being combined, nq players get double colour change notifications...
int tc = atoi(Info_ValueForKey(about->userinfo, "topcolor"));
int bc = atoi(Info_ValueForKey(about->userinfo, "bottomcolor"));
int tc = atoi(InfoBuf_ValueForKey(&about->userinfo, "topcolor"));
int bc = atoi(InfoBuf_ValueForKey(&about->userinfo, "bottomcolor"));
if (tc < 0 || tc > 13)
tc = 0;
if (bc < 0 || bc > 13)
@ -3250,7 +3350,7 @@ void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *k
client_t *client;
int j;
if (!newval)
newval = Info_ValueForKey(about->userinfo, key);
newval = InfoBuf_ValueForKey(&about->userinfo, key);
for (j = 0; j < svs.allocated_client_slots; j++)
{
client = svs.clients+j;

View File

@ -121,6 +121,9 @@ cvar_t sv_realiphostname_ipv4 = CVARD("sv_realiphostname_ipv4", "", "This is the
cvar_t sv_realiphostname_ipv6 = CVARD("sv_realiphostname_ipv6", "", "This is the server's public ip:port. This is needed for realip to work when the autodetected/local ip is not globally routable");
cvar_t sv_realip_timeout = CVAR("sv_realip_timeout", "10");
cvar_t sv_userinfo_keylimit = CVARD("sv_userinfo_keylimit", "128", "This is the maximum number of userinfo keys each user may create.");
cvar_t sv_userinfo_bytelimit = CVARD("sv_userinfo_bytelimit", "8192", "This is the maximum number of bytes that may be stored into each user's userinfo. Note that this includes key names too.");
#ifdef VOICECHAT
cvar_t sv_voip = CVARD("sv_voip", "1", "Enable reception of voice packets.");
cvar_t sv_voip_record = CVARD("sv_voip_record", "0", "Record voicechat into mvds. Requires player support. 0=noone, 1=everyone, 2=spectators only");
@ -255,7 +258,7 @@ void SV_New_f (void)
}
else
{
char *srv = Info_ValueForKey(host_client->userinfo, "*redirect");
const char *srv = InfoBuf_ValueForKey(&host_client->userinfo, "*redirect");
if (*srv)
{
char *msg = va("connect \"%s\"\n", srv);
@ -284,7 +287,7 @@ void SV_New_f (void)
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
gamedir = Info_ValueForKey (svs.info, "*gamedir");
gamedir = InfoBuf_ValueForKey (&svs.info, "*gamedir");
if (!gamedir[0])
{
if (ISQWCLIENT(host_client) || ISQ2CLIENT(host_client))
@ -650,7 +653,7 @@ void SVNQ_New_f (void)
Q_snprintfz(build, sizeof(build), "%s", __DATE__);
#endif
gamedir = Info_ValueForKey (svs.info, "*gamedir");
gamedir = InfoBuf_ValueForKey (&svs.info, "*gamedir");
if (!gamedir[0])
{
gamedir = FS_GetGamedir(true);
@ -694,7 +697,7 @@ void SVNQ_New_f (void)
MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
MSG_WriteString (&host_client->netchan.message, "cl_serverextension_download 1\n");
f = COM_LoadTempFile("csprogs.dat", &sz);
f = COM_LoadTempFile("csprogs.dat", 0, &sz);
if (f)
{
MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
@ -1009,13 +1012,15 @@ void SV_SendClientPrespawnInfo(client_t *client)
{
if (!ISNQCLIENT(client) || (client->fteprotocolextensions2 & PEXT2_PREDINFO))
{ //nq does not normally get serverinfo sent to it.
ClientReliableWrite_Begin(client, svc_stufftext, 20 + strlen(svs.info));
ClientReliableWrite_String (client, va("fullserverinfo \"%s\"\n", svs.info) );
i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, NULL, NULL, &client->infosync, &svs.info);
ClientReliableWrite_Begin(client, svc_stufftext, 20 + i);
ClientReliableWrite_String (client, va("fullserverinfo \"%s\"\n", buffer) );
}
else if (sv.csqcdebug)
{
ClientReliableWrite_Begin(client, svc_stufftext, 22 + strlen(svs.info));
ClientReliableWrite_String (client, va("//fullserverinfo \"%s\"\n", svs.info) );
i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, NULL, NULL, &client->infosync, &svs.info);
ClientReliableWrite_Begin(client, svc_stufftext, 22 + i);
ClientReliableWrite_String (client, va("//fullserverinfo \"%s\"\n", buffer) );
}
}
else if (client->prespawn_idx == 1)
@ -1946,7 +1951,9 @@ void SV_Begin_Core(client_t *split)
#ifdef Q2SERVER
if (ge)
{
ge->ClientUserinfoChanged (split->q2edict, split->userinfo); //tell the gamecode
char userinfo[8192];
InfoBuf_ToString(&split->userinfo, userinfo, sizeof(userinfo), NULL, NULL, NULL, NULL, NULL);
ge->ClientUserinfoChanged (split->q2edict, userinfo); //tell the gamecode
SV_ExtractFromUserinfo(split, true); //let the server routines know
ge->ClientBegin(split->q2edict);
@ -1980,11 +1987,11 @@ void SV_Begin_Core(client_t *split)
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "playermodel", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, Info_ValueForKey(split->userinfo, "model"), false);
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, InfoBuf_ValueForKey(&split->userinfo, "model"), false);
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "playerskin", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, Info_ValueForKey(split->userinfo, "skin"), false);
svprogfuncs->SetStringField(svprogfuncs, ent, &eval->string, InfoBuf_ValueForKey(&split->userinfo, "skin"), false);
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, "netaddress", ev_string, NULL);
if (eval)
@ -2176,8 +2183,8 @@ void SV_Begin_f (void)
//check he's not cheating
if (progstype == PROG_QW)
{
pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
pmodel = atoi(InfoBuf_ValueForKey (&host_client->userinfo, "pmodel"));
emodel = atoi(InfoBuf_ValueForKey (&host_client->userinfo, "emodel"));
if (pmodel != sv.model_player_checksum ||
emodel != sv.eyes_player_checksum)
@ -3694,7 +3701,7 @@ void SV_Say (qboolean team)
if (team)
{
Q_strncpyz (t1, Info_ValueForKey (host_client->userinfo, "team"), sizeof(t1));
Q_strncpyz (t1, InfoBuf_ValueForKey(&host_client->userinfo, "team"), sizeof(t1));
}
if (host_client->spectator && (!sv_spectalk.value || team))
@ -3790,7 +3797,7 @@ void SV_Say (qboolean team)
if (!client->spectator)
continue;
} else {
t2 = Info_ValueForKey (client->userinfo, "team");
t2 = InfoBuf_ValueForKey (&client->userinfo, "team");
if (strcmp(t1, t2) || client->spectator)
continue; // on different teams
}
@ -4222,7 +4229,7 @@ void SV_Rate_f (void)
return;
}
Info_SetValueForKey (host_client->userinfo, "rate", Cmd_Argv(1), sizeof(host_client->userinfo));
InfoBuf_SetKey (&host_client->userinfo, "rate", Cmd_Argv(1));
SV_ExtractFromUserinfo (host_client, true);
if (host_client->state > cs_connected)
@ -4254,20 +4261,9 @@ void SV_Msg_f (void)
qboolean SV_UserInfoIsBasic(const char *infoname)
{
int i;
char *basicinfos[] = {
"name",
"team",
"skin",
"topcolor",
"bottomcolor",
"chat", //ezquake's afk indicators
NULL};
for (i = 0; basicinfos[i]; i++)
for (i = 1; basicuserinfos[i]; i++)
{
if (*infoname == '*' || !strcmp(infoname, basicinfos[i]))
if (*infoname == '*' || !strcmp(infoname, basicuserinfos[i]))
return true;
}
return false;
@ -4277,6 +4273,8 @@ qboolean SV_UserInfoIsBasic(const char *infoname)
static void SV_SetInfo_PrintCB (void *ctx, const char *key, const char *value)
{
client_t *cl = ctx;
if (cl->num_backbuf > MAX_BACK_BUFFERS/2)
return; //stop printing if there's too many...
SV_ClientPrintf(cl, PRINT_HIGH, "\t%-20s%s\n", key, value);
}
@ -4290,89 +4288,102 @@ Allow clients to change userinfo
void SV_SetInfo_f (void)
{
char oldval[MAX_INFO_KEY];
char *key, *val;
char *key, *val, *t;
size_t offset, keysize, valsize, k;
qboolean final;
if (Cmd_Argc() == 1)
{
SV_ClientPrintf(host_client, PRINT_HIGH, "User info settings:\n");
Info_Enumerate(host_client->userinfo, (void*)host_client, SV_SetInfo_PrintCB);
InfoBuf_Enumerate(&host_client->userinfo, (void*)host_client, SV_SetInfo_PrintCB);
SV_ClientPrintf(host_client, PRINT_HIGH, "[%u/%i, %u/%i]\n", (unsigned int)host_client->userinfo.numkeys, sv_userinfo_keylimit.ival, (unsigned int)host_client->userinfo.totalsize, sv_userinfo_bytelimit.ival);
return;
}
if (Cmd_Argc() != 3)
if (Cmd_Argc() == 4)
{
offset = strtoul(Cmd_Argv(3), &t, 0);
final = (*t != '+');
}
else if (Cmd_Argc() == 3)
{
offset = 0;
final = true;
}
else
{
SV_ClientPrintf(host_client, PRINT_HIGH, "usage: setinfo [ <key> <value> ]\n");
return;
}
key = Cmd_Argv(1);
if (key[0] == '*')
return; // don't set priveledged values
if (strstr(key, "\\") || strstr(Cmd_Argv(2), "\\"))
return; // illegal char
Q_strncpyz(oldval, Info_ValueForKey(host_client->userinfo, key), sizeof(oldval));
#ifdef VM_Q1
if (Q1QVM_UserInfoChanged(sv_player))
return;
#endif
Info_SetValueForKey (host_client->userinfo, key, Cmd_Argv(2), sizeof(host_client->userinfo));
// name is extracted below in ExtractFromUserInfo
// strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
// , sizeof(host_client->name)-1);
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
if (!strcmp(Info_ValueForKey(host_client->userinfo, key), oldval))
return; // key hasn't changed
key = Cmd_Argv(1);
val = Cmd_Argv(2);
if (strstr(key, "\\") || strstr(val, "\\"))
return; // illegal char, at least at this point.
key = InfoBuf_DecodeString(key, key+strlen(key), &keysize);
val = InfoBuf_DecodeString(val, val+strlen(val), &valsize);
if (key[0] == '*')
SV_ClientPrintf(host_client, PRINT_HIGH, "setinfo: %s may not be changed mid-game\n", key);
else if (sv_userinfo_keylimit.ival >= 0 && host_client->userinfo.numkeys >= sv_userinfo_keylimit.ival && !offset && *val && !InfoBuf_FindKey(&host_client->userinfo, key, &k)) //when the limit is hit, allow people to freely change existing keys, but not new ones. they can also silently remove any that don't exist yet, too.
SV_ClientPrintf(host_client, PRINT_MEDIUM, "setinfo: userinfo is limited to %i keys. Ignoring setting %s\n", sv_userinfo_keylimit.ival, key);
else if (sv_userinfo_bytelimit.ival >= 0 && host_client->userinfo.totalsize >= sv_userinfo_bytelimit.ival && *val)
{
SV_ClientPrintf(host_client, PRINT_MEDIUM, "setinfo: userinfo is limited to %i bytes. Ignoring setting %s\n", sv_userinfo_bytelimit.ival, key);
if (offset) //kill it if they're part way through sending one, so that they're not penalised by the presence of partials that will never complete.
InfoBuf_RemoveKey(&host_client->userinfo, key);
}
else if (InfoBuf_SyncReceive(&host_client->userinfo, key, keysize, val, valsize, offset, final))
{
#ifdef Q2SERVER
if (svs.gametype == GT_QUAKE2)
{
ge->ClientUserinfoChanged (host_client->q2edict, host_client->userinfo); //tell the gamecode
SV_ExtractFromUserinfo(host_client, true); //let the server routines know
return;
}
if (svs.gametype == GT_QUAKE2)
{
char tempbuffer[32768];
InfoBuf_ToString(&host_client->userinfo, tempbuffer, sizeof(tempbuffer), NULL, NULL, NULL, NULL, NULL);
ge->ClientUserinfoChanged (host_client->q2edict, tempbuffer); //tell the gamecode
SV_ExtractFromUserinfo(host_client, true); //let the server routines know
}
else
#endif
{
if (progstype != PROG_QW && !strcmp(key, "bottomcolor"))
{ //team fortress has a nasty habit of booting people without this
sv_player->v->team = atoi(Cmd_Argv(2))+1;
}
if (progstype != PROG_QW && !strcmp(key, "bottomcolor"))
{ //team fortress has a nasty habit of booting people without this
sv_player->v->team = atoi(Cmd_Argv(2))+1;
}
#ifndef NOLEGACY
if (progstype != PROG_QW && !strcmp(key, "model"))
{
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playermodel", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
}
if (progstype != PROG_QW && !strcmp(key, "skin"))
{
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playerskin", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
}
if (progstype != PROG_QW && !strcmp(key, "model"))
{
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playermodel", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
}
if (progstype != PROG_QW && !strcmp(key, "skin"))
{
eval_t *eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, sv_player, "playerskin", ev_string, NULL);
if (eval)
svprogfuncs->SetStringField(svprogfuncs, sv_player, &eval->string, Cmd_Argv(2), false);
}
#endif
// process any changed values
SV_ExtractFromUserinfo (host_client, true);
// process any changed values
// chat happens far too often and makes debugging annoying, as well as making logs spammy
if (strcmp(key, "chat"))
{
SV_ExtractFromUserinfo (host_client, true);
SV_LogPlayer(host_client, "userinfo changed");
}
if (*key != '_')
{
val = Info_ValueForKey(host_client->userinfo, key);
SV_BroadcastUserinfoChange(host_client, SV_UserInfoIsBasic(key), key, val);
PR_ClientUserInfoChanged(key, oldval, InfoBuf_ValueForKey(&host_client->userinfo, key));
}
}
//doh't spam chat changes. they're not interesting, and just spammy.
if (strcmp(key, "chat"))
SV_LogPlayer(host_client, "userinfo changed");
PR_ClientUserInfoChanged(key, oldval, Info_ValueForKey(host_client->userinfo, key));
Z_Free(key);
Z_Free(val);
}
/*
@ -4385,7 +4396,7 @@ Dumps the serverinfo info string
void SV_ShowServerinfo_f (void)
{
SV_BeginRedirect(RD_CLIENT, host_client->language);
Info_Print (svs.info, "");
InfoBuf_Print (&svs.info, "");
SV_EndRedirect();
}
@ -4950,8 +4961,8 @@ void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
}
{
int tc = atoi(Info_ValueForKey(cl->userinfo, "topcolor"));
int bc = atoi(Info_ValueForKey(cl->userinfo, "bottomcolor"));
int tc = atoi(InfoBuf_ValueForKey(&cl->userinfo, "topcolor"));
int bc = atoi(InfoBuf_ValueForKey(&cl->userinfo, "bottomcolor"));
if (tc < 0 || tc > 13)
tc = 0;
if (bc < 0 || bc > 13)
@ -5152,7 +5163,7 @@ void Cmd_Join_f (void)
// turn the spectator into a player
host_client->spectator = false;
Info_RemoveKey (host_client->userinfo, "*spectator");
InfoBuf_RemoveKey (&host_client->userinfo, "*spectator");
// FIXME, bump the client's userid?
@ -5287,7 +5298,7 @@ void Cmd_Observe_f (void)
// turn the player into a spectator
host_client->spectator = true;
Info_SetValueForStarKey (host_client->userinfo, "*spectator", "1", sizeof(host_client->userinfo));
InfoBuf_SetValueForStarKey (&host_client->userinfo, "*spectator", "1");
// FIXME, bump the client's userid?
@ -5555,8 +5566,8 @@ static void SVNQ_Begin_f (void)
if (sv_playermodelchecks.value)
{
pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
pmodel = atoi(InfoBuf_ValueForKey (&host_client->userinfo, "pmodel"));
emodel = atoi(InfoBuf_ValueForKey (&host_client->userinfo, "emodel"));
if (pmodel != sv.model_player_checksum ||
emodel != sv.eyes_player_checksum)
@ -5672,18 +5683,12 @@ static void SVNQ_NQColour_f (void)
host_client->edict->v->team = bottom + 1;
val = va("%i", top);
if (strcmp(val, Info_ValueForKey(host_client->userinfo, "topcolor")))
{
Info_SetValueForKey(host_client->userinfo, "topcolor", val, sizeof(host_client->userinfo));
if (InfoBuf_SetValueForKey(&host_client->userinfo, "topcolor", val))
SV_BroadcastUserinfoChange(host_client, true, "topcolor", NULL);
}
val = va("%i", bottom);
if (strcmp(val, Info_ValueForKey(host_client->userinfo, "bottomcolor")))
{
Info_SetValueForKey(host_client->userinfo, "bottomcolor", val, sizeof(host_client->userinfo));
if (InfoBuf_SetValueForKey(&host_client->userinfo, "bottomcolor", val))
SV_BroadcastUserinfoChange(host_client, true, "bottomcolor", NULL);
}
switch(bottom)
{
@ -5697,9 +5702,9 @@ static void SVNQ_NQColour_f (void)
val = va("t%i", bottom+1);
break;
}
if (strcmp(val, Info_ValueForKey(host_client->userinfo, "team")))
if (strcmp(val, InfoBuf_ValueForKey(&host_client->userinfo, "team")))
{
Info_SetValueForKey(host_client->userinfo, "team", val, sizeof(host_client->userinfo));
InfoBuf_SetValueForKey(&host_client->userinfo, "team", val);
SV_BroadcastUserinfoChange(host_client, true, "team", NULL);
}
@ -6066,6 +6071,7 @@ ucmd_t nqucmds[] =
{"download", SV_BeginDownload_f},
{"sv_startdownload", SVDP_StartDownload_f},
{"serverinfo", SV_ShowServerinfo_f},
/*userinfo stuff*/
{"setinfo", SV_SetInfo_f},
{"name", SVNQ_NQInfo_f},
@ -8067,9 +8073,11 @@ void SVQ2_ExecuteClientMessage (client_t *cl)
break;
case clcq2_userinfo:
strncpy (cl->userinfo, MSG_ReadString (), sizeof(cl->userinfo)-1);
ge->ClientUserinfoChanged (cl->q2edict, cl->userinfo); //tell the gamecode
//FIXME: allows the client to set * keys mid-game.
s = MSG_ReadString();
InfoBuf_FromString(&cl->userinfo, s, false);
SV_ExtractFromUserinfo(cl, true); //let the server routines know
ge->ClientUserinfoChanged (cl->q2edict, s); //tell the gamecode
break;
case clcq2_stringcmd:
@ -8459,6 +8467,9 @@ void SV_UserInit (void)
Cvar_Register (&sv_realiphostname_ipv6, cvargroup_servercontrol);
Cvar_Register (&sv_realip_timeout, cvargroup_servercontrol);
Cvar_Register (&sv_userinfo_keylimit, cvargroup_servercontrol);
Cvar_Register (&sv_userinfo_bytelimit, cvargroup_servercontrol);
Cvar_Register (&sv_pushplayers, cvargroup_servercontrol);
Cvar_Register (&sv_protocol_nq, cvargroup_servercontrol);

View File

@ -1013,7 +1013,9 @@ static qintptr_t Q3G_SystemCalls(void *offset, unsigned int mask, qintptr_t fn,
{
char *dest = VM_POINTER(arg[0]);
int length = VM_LONG(arg[1]);
Q_strncpyz(dest, svs.info, length);
if (VM_OOB(arg[1], arg[2]))
return 0;
InfoBuf_ToString(&svs.info, dest, length, NULL, NULL, NULL, NULL, NULL);
}
return true;
case G_GET_USERINFO://int num, char *buffer, int bufferSize 20
@ -1021,11 +1023,13 @@ static qintptr_t Q3G_SystemCalls(void *offset, unsigned int mask, qintptr_t fn,
return 0;
if ((unsigned)VM_LONG(arg[0]) >= sv.allocated_client_slots)
return 0;
Q_strncpyz(VM_POINTER(arg[1]), svs.clients[VM_LONG(arg[0])].userinfo, VM_LONG(arg[2]));
InfoBuf_ToString(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), VM_LONG(arg[2]), NULL, NULL, NULL, NULL, NULL);
break;
case G_SET_USERINFO://int num, char *buffer 20
Q_strncpyz(svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), sizeof(svs.clients[0].userinfo));
if (VM_OOB(arg[1], 1))
return 0;
InfoBuf_FromString(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), false);
SV_ExtractFromUserinfo(&svs.clients[VM_LONG(arg[0])], false);
break;
@ -1894,13 +1898,13 @@ qboolean SVQ3_InitGame(void)
q3_sentities = Z_Malloc(sizeof(q3serverEntity_t)*MAX_GENTITIES);
/*qw serverinfo settings are not normally visible in the q3 serverinfo*/
strcpy(buffer, svs.info);
Info_SetValueForKey(buffer, "map", "", sizeof(buffer));
Info_SetValueForKey(buffer, "maxclients", "", sizeof(buffer));
Info_SetValueForKey(buffer, "mapname", svs.name, sizeof(buffer));
Info_SetValueForKey(buffer, "sv_maxclients", "32", sizeof(buffer));
Info_SetValueForKey(buffer, "sv_pure", "", sizeof(buffer));
{ /*qw serverinfo settings are not normally visible in the q3 serverinfo, so strip them from the configstring*/
static const char *ignores[] = {"maxclients", "map", "sv_maxclients", "*z_ext", "*bspversion", "*gamedir", NULL};
extern cvar_t maxclients;
InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, ignores, NULL, NULL, NULL);
//add in maxclients.. the q3 version
Q_strncatz(buffer, va("\\sv_maxclients\\%s", maxclients.string), sizeof(buffer));
}
SVQ3_SetConfigString(0, buffer);
Cvar_Set(Cvar_Get("sv_running", "0", 0, "Q3 compatability"), "1");
@ -3069,8 +3073,7 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta)
void SVQ3_UpdateUserinfo_f(client_t *cl)
{
Q_strncpyz(cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo));
InfoBuf_FromString(&cl->userinfo, Cmd_Argv(1), false);
SV_ExtractFromUserinfo (cl, true);
if (svs.gametype == GT_QUAKE3)
@ -3386,9 +3389,9 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and
reason = "Invalid challenge";
else
{
Q_strncpyz(cl->userinfo, userinfo, sizeof(cl->userinfo));
InfoBuf_FromString(&cl->userinfo, userinfo, false);
reason = NET_AdrToString(adr, sizeof(adr), &net_from);
Info_SetValueForStarKey(cl->userinfo, "ip", reason, sizeof(cl->userinfo));
InfoBuf_SetKey(&cl->userinfo, "ip", reason);
ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, (int)(cl-svs.clients), false, false);
if (!ret)

View File

@ -5,6 +5,7 @@
char shaders[][64] =
{
"fixedemu",
"q3terrain",
"altwater",
"bloom_blur",
"bloom_filter",
@ -129,7 +130,7 @@ int main(void)
if (!c)
{
printf("unable to open a file\n");
return;
return 0;
}
fprintf(c, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n");
@ -166,4 +167,6 @@ int main(void)
}
fclose(c);
return 0;
}

View File

@ -9,7 +9,7 @@
!!permu REFLECTCUBEMASK
!!cvarf r_glsl_offsetmapping_scale
!!cvardf r_tessellation_level=5
!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3
!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3
#include "sys/defs.h"
@ -271,16 +271,16 @@ void main ()
#else
vec3 lightmaps = vc.rgb;
#endif
#define delux vec3(0.0,0.0,1.0)
#define deluxe vec3(0.0,0.0,1.0)
#else
#ifdef LIGHTSTYLED
#define delux vec3(0.0,0.0,1.0)
#define deluxe vec3(0.0,0.0,1.0)
vec3 lightmaps;
#ifdef DELUXE
lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxmap0, lm0).rgb-0.5);
lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_deluxmap1, lm1).rgb-0.5);
lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_deluxmap2, lm2).rgb-0.5);
lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_deluxmap3, lm3).rgb-0.5);
lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_deluxemap0, lm0).rgb-0.5);
lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_deluxemap1, lm1).rgb-0.5);
lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_deluxemap2, lm2).rgb-0.5);
lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_deluxemap3, lm3).rgb-0.5);
#else
lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb;
lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb;
@ -291,15 +291,15 @@ void main ()
vec3 lightmaps = (texture2D(s_lightmap, lm0) * e_lmscale).rgb;
//modulate by the bumpmap dot light
#ifdef DELUXE
vec3 delux = (texture2D(s_deluxmap, lm0).rgb-0.5);
vec3 deluxe = (texture2D(s_deluxemap, lm0).rgb-0.5);
#ifdef BUMPMODELSPACE
delux = normalize(delux*invsurface);
deluxe = normalize(deluxe*invsurface);
#else
lightmaps *= 2.0 / max(0.25, delux.z); //counter the darkening from deluxmaps
lightmaps *= 2.0 / max(0.25, deluxe.z); //counter the darkening from deluxemaps
#endif
lightmaps *= dot(norm, delux);
lightmaps *= dot(norm, deluxe);
#else
#define delux vec3(0.0,0.0,1.0)
#define deluxe vec3(0.0,0.0,1.0)
#endif
#endif
#endif
@ -307,7 +307,7 @@ void main ()
//add in specular, if applicable.
#ifdef SPECULAR
vec4 specs = texture2D(s_specular, tc);
vec3 halfdir = normalize(normalize(eyevector) + delux); //this norm should be the deluxemap info instead
vec3 halfdir = normalize(normalize(eyevector) + deluxe); //this norm should be the deluxemap info instead
float spec = pow(max(dot(halfdir, norm), 0.0), FTE_SPECULAR_EXPONENT * specs.a);
spec *= FTE_SPECULAR_MULTIPLIER;
//NOTE: rtlights tend to have a *4 scaler here to over-emphasise the effect because it looks cool.

View File

@ -5069,7 +5069,6 @@ void VKBE_RT_End(struct vk_rendertarg *targ)
static qboolean BE_GenerateRefraction(batch_t *batch, shader_t *bs)
{
extern cvar_t r_refractreflect_scale;
float oldil;
int oldbem;
// struct vk_rendertarg *targ;
@ -5093,8 +5092,8 @@ static qboolean BE_GenerateRefraction(batch_t *batch, shader_t *bs)
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = max(1, vid.fbvwidth*r_refractreflect_scale.value);
r_refdef.vrect.height = max(1, vid.fbvheight*r_refractreflect_scale.value);
r_refdef.vrect.width = max(1, vid.fbvwidth*bs->portalfboscale);
r_refdef.vrect.height = max(1, vid.fbvheight*bs->portalfboscale);
VKBE_RT_Gen(&shaderstate.rt_reflection, r_refdef.vrect.width, r_refdef.vrect.height, false, RT_IMAGEFLAGS);
VKBE_RT_Begin(&shaderstate.rt_reflection);
R_DrawPortal(batch, cl.worldmodel->batches, NULL, 1);

View File

@ -3746,7 +3746,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
VkResult err;
VkApplicationInfo app;
VkInstanceCreateInfo inst_info;
int gpuidx;
int gpuidx = 0;
const char *extensions[8];
uint32_t extensions_count = 0;