1
0
Fork 0
forked from fte/fteqw

fix typo with menus.

fix a couple of obscure bugs.
rework qw/q2 skins. qwskin command now exists in .skin support.
add support for mod_external_vis, to load vis patches.
made the included http server a little more verbose with peer addresses.
preliminary support for using accessors in fteextensions.qc, will wait a while until fteqcc's support is robust before its enabled by default.
preliminary webgl drag+drop. still lots of work to do before giving it a pak1.pak is trivial.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4748 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-09-08 23:47:19 +00:00
parent 0fb5e2bc25
commit b328df6936
40 changed files with 956 additions and 475 deletions

View file

@ -1802,7 +1802,7 @@ void CL_QTVPoll (void)
int len;
qboolean streamavailable = false;
qboolean saidheader = false;
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
menu_t *sourcesmenu = NULL;
#endif
int sourcenum = 0;
@ -1971,7 +1971,7 @@ void CL_QTVPoll (void)
{
streamid = atoi(colon);
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
//now put it on a menu
if (!sourcesmenu)
{

View file

@ -3908,6 +3908,8 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "text/x-quaketvident"))
f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "application/x-fteplugin"))
f->flags |= HRF_MANIFEST;
else if (!strcmp(mimetype, "application/x-ftemanifest"))
f->flags |= HRF_MANIFEST;
else if (!strcmp(mimetype, "application/x-multiviewdemo"))
@ -3916,6 +3918,9 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
// f->flags |= HRF_BSP;
// else if (!strcmp(mimetype, "application/x-ftepackage"))
// f->flags |= HRF_PACKAGE;
if (f->flags & HRF_MANIFEST)
waitingformanifest++;
}
if (!(f->flags & HRF_FILETYPES))
@ -4001,7 +4006,7 @@ static qboolean isurl(char *url)
#ifdef FTE_TARGET_WEB
return true; //assume EVERYTHING is a url, because the local filesystem is pointless.
#endif
return !strncmp(url, "http://", 7) || !strncmp(url, "https://", 8);
return /*!strncmp(url, "data:", 5) || */!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8);
}
void Host_DoRunFile(hrf_t *f)
@ -4041,13 +4046,17 @@ void Host_DoRunFile(hrf_t *f)
if (!(f->flags & HRF_OPENED))
{
struct dl_download *dl;
f->flags |= HRF_OPENED|HRF_DOWNLOADED|HRF_WAITING;
f->flags |= HRF_OPENED;
dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
if (dl)
{
f->flags |= HRF_WAITING|HRF_DOWNLOADED;
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
waitingformanifest++;
return;
waitingformanifest++;
return;
}
}
}
#endif
@ -4169,9 +4178,12 @@ void Host_DoRunFile(hrf_t *f)
if (isurl(f->fname))
{
struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
return;
if (dl)
{
dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f;
return;
}
}
#endif
f->srcfile = VFSOS_Open(f->fname, "rb"); //input file is a system path, or something.
@ -4733,7 +4745,7 @@ void CL_StartCinematicOrMenu(void)
{
if (qrenderer > QR_NONE && !m_state)
{
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
if (!cls.state && !m_state && !*FS_GetGamedir(false))
M_Menu_Mods_f();
#endif

View file

@ -4341,7 +4341,7 @@ CL_NewTranslation
void CL_NewTranslation (int slot)
{
int top, bottom;
int local;
int local;
char *s;
player_info_t *player;
@ -4351,10 +4351,33 @@ void CL_NewTranslation (int slot)
player = &cl.players[slot];
if (cls.protocol == CP_QUAKE2)
{
char *mod, *skin;
player->qwskin = NULL;
player->skinid = 0;
player->model = NULL;
player->ttopcolor = TOP_DEFAULT;
player->tbottomcolor = BOTTOM_DEFAULT;
mod = Info_ValueForKey(player->userinfo, "skin");
skin = strchr(mod, '/');
if (skin)
*skin++ = 0;
player->model = Mod_ForName(va("players/%s/tris.md2", mod), 0);
player->skinid = Mod_RegisterSkinFile(va("players/%s/%s.skin", mod,skin));
if (!player->skinid)
player->skinid = Mod_ReadSkinFile(va("players/%s/%s.skin", mod,skin), va("replace \"\" \"players/%s/%s.pcx\"", mod,skin));
return;
}
s = Skin_FindName (player);
COM_StripExtension(s, s, MAX_QPATH);
if (player->skin && !stricmp(s, player->skin->name))
player->skin = NULL;
if (player->qwskin && !stricmp(s, player->qwskin->name))
player->qwskin = NULL;
player->skinid = 0;
player->model = NULL;

View file

@ -226,7 +226,7 @@ void SCR_ScreenShot_f (void);
void SCR_RSShot_f (void);
void SCR_CPrint_f(void);
cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works");
cvar_t con_stayhidden = CVARFD("con_stayhidden", "0", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works");
cvar_t show_fps = SCVARF("show_fps", "0", CVAR_ARCHIVE);
cvar_t show_fps_x = SCVAR("show_fps_x", "-1");
cvar_t show_fps_y = SCVAR("show_fps_y", "-1");

View file

@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "particles.h"
typedef struct
typedef struct qwskin_s
{
char name[64];
int width;
@ -32,7 +32,7 @@ typedef struct
qboolean failedload; // the name isn't a valid skin
void *skindata;
} skin_t;
} qwskin_t;
// player_state_t is the information needed by a player entity
// to do move prediction and to generate a drawable entity
@ -168,8 +168,9 @@ typedef struct player_info_s
unsigned int ttopcolor; //team, according to colour forcing
unsigned int tbottomcolor;
int spectator;
skin_t *skin;
int spectator;
qwskin_t *qwskin;
skinid_t skinid;
struct model_s *model;
@ -1314,10 +1315,10 @@ typedef struct
qbyte *ReadPCXData(qbyte *buf, int length, int width, int height, qbyte *result);
qwskin_t *Skin_Lookup (char *fullname);
char *Skin_FindName (player_info_t *sc);
void Skin_Find (player_info_t *sc);
qbyte *Skin_Cache8 (skin_t *skin);
qbyte *Skin_Cache32 (skin_t *skin);
qbyte *Skin_Cache8 (qwskin_t *skin);
void Skin_Skins_f (void);
void Skin_FlushSkin(char *name);
void Skin_AllSkins_f (void);

View file

@ -1228,6 +1228,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.bottomcolour = 1;
ent.h2playerclass = 0;
ent.playerindex = -1;
ent.customskin = 0;
// set frame
if (effects & Q2EF_ANIM01)
@ -1315,11 +1316,14 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.model = player->model;
if (!ent.model || ent.model->needload) //we need to do better than this
{
if (!ent.model || ent.model->needload)
ent.model = Mod_ForName("players/male/tris.md2", MLV_SILENT);
ent.model = Mod_ForName("players/male/tris.md2", MLV_SILENT);
ent.customskin = Mod_RegisterSkinFile("players/male/grunt.skin");
if (!ent.customskin)
ent.customskin = Mod_ReadSkinFile("players/male/grunt.skin", "replace \"\" \"players/male/grunt.pcx\"");
}
else
ent.customskin = player->skinid;
ent.playerindex = (s1->skinnum&0xff)%cl.allocated_client_slots;
player->model = ent.model;
/* ci = &cl.clientinfo[s1->skinnum & 0xff];
// ent.skin = ci->skin;
ent.model = ci->model;
@ -1813,6 +1817,8 @@ void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops)
else
gun.framestate.g[FS_REG].frame[1] = ops->gunframe;
gun.playerindex = -1;
gun.flags = Q2RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
gun.framestate.g[FS_REG].lerpfrac = 1-cl.lerpfrac;
VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
@ -1926,6 +1932,7 @@ Emits all entities, particles, and lights to the refresh
*/
void CLQ2_AddEntities (void)
{
extern cvar_t chase_active, chase_back, chase_up;
if (cls.state != ca_active)
return;
@ -1952,6 +1959,22 @@ void CLQ2_AddEntities (void)
CLQ2_AddProjectiles ();
#endif
CL_UpdateTEnts ();
if (chase_active.ival)
{
playerview_t *pv = &cl.playerview[0];
vec3_t axis[3];
vec3_t camorg;
trace_t tr;
AngleVectors(r_refdef.viewangles, axis[0], axis[1], axis[2]);
VectorMA(r_refdef.vieworg, -chase_back.value, axis[0], camorg);
VectorMA(camorg, -chase_up.value, pv->gravitydir, camorg);
// if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, r_refdef.vieworg, camorg, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr))
VectorCopy(camorg, r_refdef.vieworg);
CL_EditExternalModels(0, NULL, 0);
}
}
void CL_GetNumberedEntityInfo (int num, float *org, float *ang)

View file

@ -1,6 +1,6 @@
#include "quakedef.h"
#if defined(WEBCLIENT) && !defined(NOBUITINMENUS)
#if defined(WEBCLIENT) && !defined(NOBUILTINMENUS)
#define DOWNLOADMENU
#endif

View file

@ -76,7 +76,7 @@ void Draw_TextBox (int x, int y, int width, int lines)
R2D_ScalePic (cx, cy+8, 8, 8, p);
}
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
int omousex;
int omousey;

View file

@ -1,6 +1,6 @@
#include "quakedef.h"
#if defined(CL_MASTER) && !defined(NOBUITINMENUS)
#if defined(CL_MASTER) && !defined(NOBUILTINMENUS)
#include "cl_master.h"
//filtering

View file

@ -743,7 +743,7 @@ void M_Media_Key (int key)
int dir;
if (key == K_ESCAPE)
{
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
M_Menu_Main_f();
#else
m_state = m_none;

View file

@ -4,7 +4,7 @@
#include "winquake.h"
#include "shader.h"
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
extern cvar_t maxclients;

View file

@ -93,7 +93,7 @@ qboolean M_Vid_GetMode(int num, int *w, int *h)
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
extern qboolean forcesaveprompt;
extern cvar_t pr_debugger;
@ -712,6 +712,7 @@ const char *presetexec[] =
"gl_texturemode2d n;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby!
"r_part_classic_expgrav 1;" //vanillaery
"r_particlesystem script;" //q2 or hexen2 particle effects need to be loadable
"cl_sbar 1;" //its a style thing
"sv_nqplayerphysics 1;" //gb wanted this
"cl_demoreel 1;" //yup, arcadey

View file

@ -3,7 +3,7 @@
#include "quakedef.h"
#include "shader.h"
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
int selectitem;
menu_t *menu_script;

View file

@ -154,7 +154,7 @@ void M_FindKeysForCommand (int pnum, const char *command, int *twokeys)
M_FindKeysForBind(va("%s%s", prefix, command), twokeys, 2);
}
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
void M_Menu_Audio_f (void);
void M_Menu_Demos_f (void);
@ -1270,7 +1270,7 @@ void M_Draw (int uimenu)
#endif
}
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
if (m_state != m_complex)
{
M_RemoveAllMenus();
@ -1286,7 +1286,7 @@ void M_Draw (int uimenu)
if (m_state == m_none || m_state == m_menu_dat)
return;
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
if ((!menu_script || scr_con_current) && !m_recursiveDraw)
{
extern menu_t *firstmenu;
@ -1308,7 +1308,7 @@ void M_Draw (int uimenu)
case m_none:
break;
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
case m_help:
M_Help_Draw ();
break;
@ -1345,7 +1345,7 @@ void M_Keydown (int key, int unicode)
case m_none:
Key_Dest_Remove(kdm_menu);
return;
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
case m_help:
M_Help_Key (key);
return;
@ -1380,7 +1380,7 @@ void M_Keyup (int key, int unicode)
{
switch (m_state)
{
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
case m_complex:
if (key == K_MOUSE1)
M_Complex_Key (key, unicode);

View file

@ -102,7 +102,7 @@ void M_DrawTextBox (int x, int y, int width, int lines);
#define NOMEDIAMENU
#ifndef NOBUITINMENUS
#ifndef NOBUILTINMENUS
//
// menus

View file

@ -148,6 +148,8 @@ typedef struct
int nummappings;
int maxmappings;
qbyte geomset[MAX_GEOMSETS]; //allows selecting a single set of geometry from alternatives. this might be a can of worms.
char qwskinname[MAX_QPATH];
struct qwskin_s *qwskin;
struct
{
char surface[MAX_QPATH];
@ -266,7 +268,7 @@ extern entity_t r_worldentity;
void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode); //if dl, filters based upon the dlight.
//gl_alias.c
void GL_GAliasFlushSkinCache(void);
void R_GAliasFlushSkinCache(qboolean final);
void R_GAlias_DrawBatch(struct batch_s *batch);
void R_GAlias_GenerateBatches(entity_t *e, struct batch_s **batches);
void R_LightArraysByte_BGR(const entity_t *entity, vecV_t *coords, byte_vec4_t *colours, int vertcount, vec3_t *normals);

View file

@ -411,7 +411,7 @@ void Sbar_ExecuteLayoutString (char *s)
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", cl.players[value].skin->name));
p = R2D_SafeCachePic(va("players/%s_i.pcx", cl.players[value].qwskin->name));
if (!p) //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);

View file

@ -30,8 +30,8 @@ extern cvar_t cl_enemyskin;
extern cvar_t r_fb_models;
char allskins[128];
#define MAX_CACHED_SKINS 128
skin_t skins[MAX_CACHED_SKINS];
#define MAX_CACHED_SKINS 256 //max_clients is 255. hopefully this will not be reached, but hey.
qwskin_t skins[MAX_CACHED_SKINS];
int numskins;
//returns the name
@ -108,6 +108,37 @@ char *Skin_FindName (player_info_t *sc)
return name;
}
qwskin_t *Skin_Lookup (char *fullname)
{
int i;
qwskin_t *skin;
char cleanname[sizeof(skin->name)];
COM_StripExtension (fullname, cleanname, sizeof(cleanname));
for (i=0 ; i<numskins ; i++)
{
if (!strcmp (cleanname, skins[i].name))
{
skin = &skins[i];
Skin_Cache8 (skin);
return skin;
}
}
//FIXME: this is stupid.
if (numskins == MAX_CACHED_SKINS)
{ // ran out of spots, so flush everything
Skin_Skins_f ();
}
skin = &skins[numskins];
numskins++;
memset (skin, 0, sizeof(*skin));
Q_strncpyz(skin->name, cleanname, sizeof(skin->name));
Skin_Cache8 (skin);
return skin;
}
/*
================
Skin_Find
@ -119,52 +150,35 @@ Skin_Find
*/
void Skin_Find (player_info_t *sc)
{
skin_t *skin;
qwskin_t *skin;
int i;
char name[128], *s;
model_t *model;
if (allskins[0])
s = allskins;
else
s = Info_ValueForKey (sc->userinfo, "skin");
sc->model = NULL;
sc->skinid = 0;
sc->qwskin = NULL;
if (!*s)
s = baseskin.string;
if (!*s)
s = "default";
return;
// s = "default";
s = Skin_FindName(sc);
COM_StripExtension (s, name, sizeof(name));
s = strchr(name, '/');
if (s)
{
*s = '\0';
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
model = Mod_ForName(va("players/%s/tris.md2", name), MLV_SILENT);
else
#endif
model = NULL;//Mod_ForName(va("models/players/%s.mdl", name), false);
if (model && model->type == mod_dummy)
model = NULL;
*s = '/';
}
else
model = NULL;
sc->model = model;
for (i=0 ; i<numskins ; i++)
{
if (!strcmp (name, skins[i].name))
{
sc->skin = &skins[i];
if (cls.protocol == CP_QUAKE2)
Skin_Cache32 (sc->skin);
else
Skin_Cache8 (sc->skin);
sc->qwskin = &skins[i];
Skin_Cache8 (sc->qwskin);
return;
}
}
@ -176,7 +190,7 @@ void Skin_Find (player_info_t *sc)
}
skin = &skins[numskins];
sc->skin = skin;
sc->qwskin = skin;
numskins++;
memset (skin, 0, sizeof(*skin));
@ -191,7 +205,7 @@ Skin_Cache
Returns a pointer to the skin bitmap, or NULL to use the default
==========
*/
qbyte *Skin_Cache8 (skin_t *skin)
qbyte *Skin_Cache8 (qwskin_t *skin)
{
char name[1024];
qbyte *raw;
@ -251,12 +265,7 @@ qbyte *Skin_Cache8 (skin_t *skin)
return out;
}
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
skinpath = "players";
else
#endif
skinpath = "skins";
skinpath = "skins";
//favour 24bit+recoloured skins if gl_load24bit is enabled.
Q_snprintfz (name, sizeof(name), "%s_shirt", skin->name);
@ -431,106 +440,6 @@ qbyte *Skin_Cache8 (skin_t *skin)
return out;
}
qbyte *Skin_Cache32 (skin_t *skin)
{
char name[1024];
qbyte *raw;
qbyte *out, *pix;
char *path;
qboolean hasalpha;
if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
return NULL; // not download new ones.
if (skin->failedload)
return NULL;
out = skin->skindata;
if (out)
return out;
if (cls.protocol == CP_QUAKE2)
path = "players/";
else
path = "skins/";
//
// load the pic from disk
//
Q_snprintfz (name, sizeof(name), "%s%s.tga", path, skin->name);
raw = COM_LoadTempFile (name);
if (raw)
{
pix = ReadTargaFile(raw, com_filesize, &skin->width, &skin->height, &hasalpha, false);
if (pix)
{
skin->skindata = out = BZ_Malloc(skin->width*skin->height*4);
memcpy(out, pix, skin->width*skin->height*4);
BZ_Free(pix);
return out;
}
}
Q_snprintfz (name, sizeof(name), "%s%s.pcx", path, skin->name);
raw = COM_LoadTempFile (name);
if (raw)
{
pix = ReadPCXFile(raw, com_filesize, &skin->width, &skin->height);
if (pix)
{
skin->skindata = out = BZ_Malloc(skin->width*skin->height*4);
memcpy(out, pix, skin->width*skin->height*4);
BZ_Free(pix);
return out;
}
}
#ifdef AVAIL_PNGLIB
Q_snprintfz (name, sizeof(name), "%s%s.png", path, skin->name);
raw = COM_LoadTempFile (name);
if (raw)
{
pix = ReadPNGFile(raw, com_filesize, &skin->width, &skin->height, name);
if (pix)
{
skin->skindata = out = BZ_Malloc(skin->width*skin->height*4);
memcpy(out, pix, skin->width*skin->height*4);
BZ_Free(pix);
return out;
}
}
#endif
#ifdef AVAIL_JPEGLIB
Q_snprintfz (name, sizeof(name), "%s%s.jpeg", path, skin->name);
raw = COM_LoadTempFile (name);
if (raw)
{
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
if (pix)
{
skin->skindata = out = BZ_Malloc(skin->width*skin->height*4);
memcpy(out, pix, skin->width*skin->height*4);
BZ_Free(pix);
return out;
}
}
Q_snprintfz (name, sizeof(name), "%s%s.jpg", path, skin->name); //jpegs are gready with 2 extensions...
raw = COM_LoadTempFile (name);
if (raw)
{
pix = ReadJPEGFile(raw, com_filesize, &skin->width, &skin->height);
if (pix)
{
skin->skindata = out = BZ_Malloc(skin->width*skin->height*4);
memcpy(out, pix, skin->width*skin->height*4);
BZ_Free(pix);
return out;
}
}
#endif
skin->failedload = true;
return NULL;
}
/*
=================
Skin_NextDownload
@ -542,62 +451,61 @@ void Skin_NextDownload (void)
int i;
//Con_Printf ("Checking skins...\n");
if (cls.protocol == CP_QUAKE2)
{
int j;
char *slash;
char *skinname;
for (i = 0; i != MAX_CLIENTS; i++)
{
sc = &cl.players[i];
if (!sc->name[0])
continue;
skinname = Info_ValueForKey(sc->userinfo, "skin");
slash = strchr(skinname, '/');
if (slash)
{
*slash = 0;
CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", skinname), NULL, 0);
for (j = 0; j < MAX_MODELS; j++)
{
if (cl.model_name[j][0] == '#')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.model_name[j]+1), NULL, 0);
}
for (j = 0; j < MAX_SOUNDS; j++)
{
if (cl.sound_name[j][0] == '*')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.sound_name[j]+1), NULL, 0);
}
*slash = '/';
CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", skinname), NULL, 0);
}
}
return;
}
for (i = 0; i != MAX_CLIENTS; i++)
{
sc = &cl.players[i];
if (!sc->name[0])
continue;
Skin_Find (sc);
if (noskins.ival)
if (noskins.ival || !sc->qwskin)
continue;
if (strchr(sc->skin->name, ' ')) //skip over skins using a space
if (strchr(sc->qwskin->name, ' ')) //skip over skins using a space
continue;
if (!*sc->skin->name)
if (!*sc->qwskin->name)
continue;
if (cls.protocol == CP_QUAKE2)
{
int j;
char *slash;
slash = strchr(sc->skin->name, '/');
if (slash)
{
*slash = 0;
CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", sc->skin->name), NULL, 0);
for (j = 0; j < MAX_MODELS; j++)
{
if (cl.model_name[j][0] == '#')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", sc->skin->name, cl.model_name[j]+1), NULL, 0);
}
for (j = 0; j < MAX_SOUNDS; j++)
{
if (cl.sound_name[j][0] == '*')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", sc->skin->name, cl.sound_name[j]+1), NULL, 0);
}
*slash = '/';
CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", sc->skin->name), NULL, 0);
}
}
else
CL_CheckOrEnqueDownloadFile(va("skins/%s.pcx", sc->skin->name), NULL, 0);
CL_CheckOrEnqueDownloadFile(va("skins/%s.pcx", sc->qwskin->name), NULL, 0);
}
// now load them in for real
for (i=0 ; i<MAX_CLIENTS ; i++)
{
sc = &cl.players[i];
if (!sc->name[0])
if (!sc->name[0] || !sc->qwskin)
continue;
if (cls.protocol == CP_QUAKE2)
Skin_Cache32(sc->skin);
else
Skin_Cache8 (sc->skin);
#ifdef GLQUAKE
sc->skin = NULL;
#endif
Skin_Cache8 (sc->qwskin);
//sc->qwskin = NULL;
}
}
@ -607,7 +515,7 @@ void Skin_FlushPlayers(void)
{ //wipe the skin info
int i;
for (i = 0; i < cl.allocated_client_slots; i++)
cl.players[i].skin = NULL;
cl.players[i].qwskin = NULL;
for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i);
@ -643,7 +551,7 @@ void Skin_Skins_f (void)
return;
}
GL_GAliasFlushSkinCache();
R_GAliasFlushSkinCache(false);
for (i=0 ; i<numskins ; i++)
{
if (skins[i].skindata)

View file

@ -95,6 +95,10 @@ cvar_t v_projectionmode = SCVAR("v_projectionmode", "0");
cvar_t scr_autoid = SCVAR("scr_autoid", "1");
cvar_t chase_active = CVAR("chase_active", "0");
cvar_t chase_back = CVAR("chase_back", "48");
cvar_t chase_up = CVAR("chase_up", "24");
extern cvar_t cl_chasecam;
@ -1295,13 +1299,24 @@ void V_CalcRefdef (playerview_t *pv)
r_refdef.time = cl.servertime;
// smooth out stair step ups
{
extern model_t *loadmodel;
loadmodel = cl.worldmodel;
}
if (chase_active.ival)
{
vec3_t axis[3];
vec3_t camorg;
trace_t tr;
AngleVectors(r_refdef.viewangles, axis[0], axis[1], axis[2]);
VectorMA(r_refdef.vieworg, -chase_back.value, axis[0], camorg);
VectorMA(camorg, -chase_up.value, pv->gravitydir, camorg);
// if (cl.worldmodel && cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, 0, NULL, r_refdef.vieworg, camorg, vec3_origin, vec3_origin, MASK_WORLDSOLID, &tr))
VectorCopy(camorg, r_refdef.vieworg);
CL_EditExternalModels(0, NULL, 0);
}
}
/*
@ -1471,6 +1486,11 @@ void V_RenderPlayerViews(playerview_t *pv)
DropPunchAngle (pv);
Cam_SelfTrack(pv);
oldnuments = cl_numvisedicts;
oldstris = cl_numstris;
CL_LinkViewModel ();
if (cl.intermission)
{ // intermission / finale rendering
V_CalcIntermissionRefdef (pv);
@ -1482,10 +1502,6 @@ void V_RenderPlayerViews(playerview_t *pv)
}
V_ApplyRefdef();
oldnuments = cl_numvisedicts;
oldstris = cl_numstris;
CL_LinkViewModel ();
R_RenderView ();
R2D_PolyBlend ();
R_DrawNameTags();
@ -1758,4 +1774,8 @@ void V_Init (void)
Cvar_Register (&v_gamma, VIEWVARS);
Cvar_Register (&v_contrast, VIEWVARS);
Cvar_Register (&v_brightness, VIEWVARS);
// Cvar_Register (&chase_active, VIEWVARS);
// Cvar_Register (&chase_back, VIEWVARS);
// Cvar_Register (&chase_up, VIEWVARS);
}

View file

@ -270,7 +270,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#ifdef QUAKETC
#define NOBUITINMENUS //kill engine menus (should be replaced with ewither csqc or menuqc)
#define NOBUILTINMENUS //kill engine menus (should be replaced with ewither csqc or menuqc)
#undef Q2CLIENT //not useful
#undef Q2SERVER //not useful
#undef Q3CLIENT //not useful

View file

@ -1281,7 +1281,17 @@ pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, fo
static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
{
if (!idx)
{
if (!pf_peristanthashtab.tab.numbuckets)
{
int numbuckets = 256;
pf_peristanthashtab.defaulttype = ev_string;
pf_peristanthashtab.prinst = NULL;
pf_peristanthashtab.bucketmem = Z_Malloc(Hash_BytesForBuckets(numbuckets));
Hash_InitTable(&pf_peristanthashtab.tab, numbuckets, pf_peristanthashtab.bucketmem);
}
return &pf_peristanthashtab;
}
idx -= 1;
if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst)
return &pf_hashtab[idx];
@ -1331,7 +1341,7 @@ void QCBUILTIN PF_hash_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{
pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
const char *name = PR_GetStringOfs(prinst, OFS_PARM1);
void *dflt = G_VECTOR(OFS_PARM2);
void *dflt = (prinst->callargc>2)?G_VECTOR(OFS_PARM2):vec3_origin;
int type = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):0;
int index = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0;
pf_hashentry_t *ent = NULL;
@ -1386,19 +1396,26 @@ void QCBUILTIN PF_hash_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
const char *name = PR_GetStringOfs(prinst, OFS_PARM1);
void *data = G_VECTOR(OFS_PARM2);
int flags = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):0;
int type = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0;
int type = flags & 0xff;
pf_hashentry_t *ent = NULL;
if (tab)
{
if (!type)
type = tab->defaulttype;
if (flags & 1)
Hash_Remove(&tab->tab, name);
if (flags & 256)
{
ent = Hash_Get(&tab->tab, name);
if (ent)
{
Hash_RemoveData(&tab->tab, name, ent);
BZ_Free(ent);
}
}
if (type == ev_string)
{ //strings copy their value out.
const char *value = PR_GetStringOfs(prinst, OFS_PARM2);
int nlen = strlen(name);
int vlen = strlen(data);
int vlen = strlen(value);
ent = BZ_Malloc(sizeof(*ent) + nlen+1 + vlen+1);
ent->name = (char*)(ent+1);
ent->type = ev_string;
@ -4452,7 +4469,7 @@ void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
prinst->pr_trace++; //continue debugging
PR_ExecuteProgram(prinst, f);
}
else if (!f)
else
{
f = PR_FindFunction(prinst, "MissingFunc", progsnum);
if (!f)

View file

@ -1380,7 +1380,9 @@
AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include,../d3d,../d3d9,../libs/dxsdk9/include"
PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;SERVERONLY;MULTITHREAD"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="quakedef.h"
@ -27238,13 +27240,6 @@
<File
RelativePath="..\common\net_ssl_winsspi.c"
>
<FileConfiguration
Name="MinGLRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\net_wins.c"

View file

@ -69,6 +69,17 @@ struct cctx_s
int width;
int height;
};
void Mod_FlushSkin(skinid_t id)
{
skinfile_t *sk;
id--;
if (id >= numregisteredskins)
return; //invalid!
sk = registeredskins[id];
if (!sk)
return;
sk->qwskin = NULL;
}
void Mod_WipeSkin(skinid_t id)
{
skinfile_t *sk;
@ -89,14 +100,22 @@ void Mod_WipeSkin(skinid_t id)
Z_Free(registeredskins[id]);
registeredskins[id] = NULL;
}
static void Mod_WipeAllSkins(void)
static void Mod_WipeAllSkins(qboolean final)
{
skinid_t id;
for (id = 0; id < numregisteredskins; )
Mod_WipeSkin(++id);
Z_Free(registeredskins);
registeredskins = NULL;
numregisteredskins = 0;
if (final)
{
for (id = 0; id < numregisteredskins; )
Mod_WipeSkin(++id);
Z_Free(registeredskins);
registeredskins = NULL;
numregisteredskins = 0;
}
else
{
for (id = 0; id < numregisteredskins; )
Mod_FlushSkin(++id);
}
}
skinfile_t *Mod_LookupSkin(skinid_t id)
{
@ -295,6 +314,11 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext)
{
//ignore it. matches q3.
}
else if (!strcmp(com_token, "qwskin"))
{
skintext = COM_ParseToken(skintext, NULL);
Q_strncpyz(skin->qwskinname, com_token, sizeof(skin->qwskinname));
}
else
{
while(*skintext == ' ' || *skintext == '\t')
@ -467,7 +491,10 @@ void GL_GAliasFlushOneSkin(char *skinname)
}
}
}*/
void GL_GAliasFlushSkinCache(void)
//final is set when the renderer is going down.
//if not set, this is mid-map, and everything should be regeneratable.
void R_GAliasFlushSkinCache(qboolean final)
{
int i;
bucket_t *b;
@ -494,14 +521,14 @@ void GL_GAliasFlushSkinCache(void)
numFacing = 0;
#endif
Mod_WipeAllSkins();
Mod_WipeAllSkins(final);
}
static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, entity_t *e, texnums_t **forcedtex)
{
galiasskin_t *skins;
shader_t *shader;
skin_t *plskin;
qwskin_t *plskin = NULL;
int frame;
unsigned int subframe;
extern int cl_playerindex; //so I don't have to strcmp
@ -528,6 +555,9 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
return sk->mappings[i].shader;
}
}
if (!sk->qwskin && *sk->qwskinname)
sk->qwskin = Skin_Lookup(sk->qwskinname);
plskin = sk->qwskin;
}
}
@ -552,14 +582,23 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (!gl_nocolors.ival || forced)
{
if (e->playerindex >= 0 && e->playerindex <= MAX_CLIENTS)
if (!plskin || plskin->failedload)
{
if (!cl.players[e->playerindex].skin)
Skin_Find(&cl.players[e->playerindex]);
plskin = cl.players[e->playerindex].skin;
if (e->playerindex >= 0 && e->playerindex <= MAX_CLIENTS)
{
//heads don't get skinned, only players (and weaponless players), they do still get recoloured.
if (model==cl.model_precache[cl_playerindex] || model==cl.model_precache_vwep[0])
{
if (!cl.players[e->playerindex].qwskin)
Skin_Find(&cl.players[e->playerindex]);
plskin = cl.players[e->playerindex].qwskin;
}
else
plskin = NULL;
}
else
plskin = NULL;
}
else
plskin = NULL;
tc = e->topcolour;
bc = e->bottomcolour;
pc = e->h2playerclass;
@ -667,27 +706,13 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (plskin)
{
if (cls.protocol == CP_QUAKE2)
original = Skin_Cache8(plskin);
if (original)
{
original = Skin_Cache32(plskin);
if (original)
{
inwidth = plskin->width;
inheight = plskin->height;
cm->texnum.base = R_LoadTexture32(plskin->name, inwidth, inheight, (unsigned int*)original, IF_NOALPHA|IF_NOGAMMA);
return shader;
}
}
else
{
original = Skin_Cache8(plskin);
if (original)
{
inwidth = plskin->width;
inheight = plskin->height;
cm->texnum.base = R_LoadTexture8(plskin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
return shader;
}
inwidth = plskin->width;
inheight = plskin->height;
cm->texnum.base = R_LoadTexture8(plskin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
return shader;
}
if (TEXVALID(plskin->textures.base))
@ -707,7 +732,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
}
cm->texnum.bump = shader->defaulttextures.bump; //can't colour bumpmapping
if (cls.protocol != CP_QUAKE2 && ((model==cl.model_precache[cl_playerindex] || model==cl.model_precache_vwep[0]) && plskin))
if (plskin)
{
/*q1 only reskins the player model, not gibbed heads (which have the same colourmap)*/
original = Skin_Cache8(plskin);

View file

@ -543,7 +543,7 @@ void GLDraw_DeInit (void)
R2D_Shutdown();
GL_GAliasFlushSkinCache();
R_GAliasFlushSkinCache(true);
draw_disc = NULL;
GL_ShutdownPostProcessing();

View file

@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern cvar_t r_shadow_bumpscale_basetexture;
extern cvar_t r_replacemodels;
extern cvar_t gl_lightmap_average;
cvar_t mod_external_vis = CVARD("mod_external_vis", "1", "Attempt to load .vis patches for quake maps, allowing transparent water to work properly.");
#ifdef SERVERONLY
cvar_t gl_overbright, gl_specular, gl_load24bit, r_replacemodels, gl_miptexLevel, r_fb_bmodels; //all of these can/should default to 0
cvar_t r_noframegrouplerp = CVARF ("r_noframegrouplerp", "0", CVAR_ARCHIVE);
@ -529,6 +529,8 @@ void Mod_Init (qboolean initial)
Cmd_AddCommand("mod_usetexture", Mod_BlockTextureColour_f);
#endif
}
else
Cvar_Register(&mod_external_vis, "Graphical Nicaties");
if (initial)
{
@ -2065,15 +2067,20 @@ void Mod_LoadLighting (lump_t *l)
Mod_LoadVisibility
=================
*/
void Mod_LoadVisibility (lump_t *l)
void Mod_LoadVisibility (lump_t *l, qbyte *ptr, size_t len)
{
if (!l->filelen)
if (!ptr)
{
ptr = mod_base + l->fileofs;
len = l->filelen;
}
if (!len)
{
loadmodel->visdata = NULL;
return;
}
loadmodel->visdata = ZG_Malloc(&loadmodel->memgroup, l->filelen);
memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
loadmodel->visdata = ZG_Malloc(&loadmodel->memgroup, len);
memcpy (loadmodel->visdata, ptr, len);
}
@ -3321,21 +3328,27 @@ qboolean Mod_LoadNodes (lump_t *l, int lm)
Mod_LoadLeafs
=================
*/
qboolean Mod_LoadLeafs (lump_t *l, int lm)
qboolean Mod_LoadLeafs (lump_t *l, int lm, qbyte *ptr, size_t len)
{
mleaf_t *out;
int i, j, count, p;
if (!ptr)
{
ptr = mod_base + l->fileofs;
len = l->filelen;
}
if (lm==2)
{
dl2leaf_t *in;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
in = (void *)ptr;
if (len % sizeof(*in))
{
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false;
}
count = l->filelen / sizeof(*in);
count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS)
{
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS);
@ -3392,13 +3405,13 @@ qboolean Mod_LoadLeafs (lump_t *l, int lm)
else if (lm)
{
dl1leaf_t *in;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
in = (void *)(ptr);
if (len % sizeof(*in))
{
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false;
}
count = l->filelen / sizeof(*in);
count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS)
{
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS);
@ -3455,13 +3468,13 @@ qboolean Mod_LoadLeafs (lump_t *l, int lm)
else
{
dsleaf_t *in;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
in = (void *)(ptr);
if (len % sizeof(*in))
{
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false;
}
count = l->filelen / sizeof(*in);
count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS)
{
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS);
@ -4195,6 +4208,79 @@ static void Mod_FixupMinsMaxs(void)
Mod_FixupNodeMinsMaxs (loadmodel->nodes, NULL); // sets nodes and leafs
}
struct vispatch_s
{
void *fileptr;
size_t filelen;
void *visptr;
int vislen;
void *leafptr;
int leaflen;
};
void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaflumpsize)
{
char patchname[MAX_QPATH];
int *lenptr, len;
int ofs;
qbyte *file;
memset(patch, 0, sizeof(*patch));
if (!mod_external_vis.ival)
return;
COM_StripExtension(mod->name, patchname, sizeof(patchname));
Q_strncatz(patchname, ".vis", sizeof(patchname));
//ignore the patch file if its in a different gamedir.
//this file format sucks too much for other verification.
if (FS_FLocateFile(mod->name,FSLFRT_DEPTH_OSONLY, NULL) != FS_FLocateFile(patchname,FSLFRT_DEPTH_OSONLY, NULL))
return;
patch->filelen = FS_LoadFile(patchname, &patch->fileptr);
if (!patch->fileptr)
return;
ofs = 0;
while (ofs+36 <= patch->filelen)
{
file = patch->fileptr;
file += ofs;
memcpy(patchname, file, 32);
patchname[32] = 0;
file += 32;
lenptr = (int*)file;
file += sizeof(int);
len = LittleLong(*lenptr);
if (ofs+36+len > patch->filelen)
break;
// if (!Q_strcasecmp(patchname, "foo"))
{
lenptr = (int*)file;
patch->vislen = LittleLong(*lenptr);
file += sizeof(int);
patch->visptr = file;
file += patch->vislen;
lenptr = (int*)file;
patch->leaflen = LittleLong(*lenptr);
file += sizeof(int);
patch->leafptr = file;
file += patch->leaflen;
if (sizeof(int)*2 + patch->vislen + patch->leaflen != len || patch->leaflen != leaflumpsize)
{
Con_Printf("Vis patch is unsuitable\n");
patch->visptr = NULL;
patch->leafptr = NULL;
}
}
ofs += 36+len;
}
}
/*
=================
Mod_LoadBrushModel
@ -4202,6 +4288,7 @@ Mod_LoadBrushModel
*/
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
{
struct vispatch_s vispatch;
int i, j;
dheader_t *header;
mmodel_t *bm;
@ -4306,6 +4393,8 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
crouchhullfile = NULL;
Mod_FindVisPatch(&vispatch, loadmodel, header->lumps[LUMP_LEAFS].filelen);
TRACE(("Loading info\n"));
#ifndef SERVERONLY
if (!isnotmap)
@ -4354,9 +4443,9 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
if (noerrors)
{
TRACE(("Loading Vis\n"));
Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY], vispatch.visptr, vispatch.vislen);
}
noerrors = noerrors && Mod_LoadLeafs (&header->lumps[LUMP_LEAFS], longm);
noerrors = noerrors && Mod_LoadLeafs (&header->lumps[LUMP_LEAFS], longm, vispatch.leafptr, vispatch.leaflen);
TRACE(("Loading Nodes\n"));
noerrors = noerrors && Mod_LoadNodes (&header->lumps[LUMP_NODES], longm);
TRACE(("Loading Clipnodes\n"));
@ -4379,6 +4468,8 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
crouchhullfile=NULL;
}
BZ_Free(vispatch.fileptr);
if (!noerrors)
{
return false;

View file

@ -9,7 +9,7 @@ model meshes are interpolated multiple times per frame
//#define DBG_COLOURNOTDEPTH
#ifdef RTLIGHTS
#if defined(RTLIGHTS) && !defined(SERVERONLY)
#include "glquake.h"
#include "shader.h"
@ -3506,7 +3506,7 @@ void Sh_DrawLights(qbyte *vis)
//so this little function is used to check if its needed or not.
qboolean Sh_StencilShadowsActive(void)
{
#ifdef RTLIGHTS
#if defined(RTLIGHTS) && !defined(SERVERONLY)
//if shadowmapping is forced on all lights then we don't need special depth stuff
// if (r_shadow_shadowmapping.ival)
// return false;
@ -3521,7 +3521,7 @@ qboolean Sh_StencilShadowsActive(void)
void Sh_RegisterCvars(void)
{
#ifdef RTLIGHTS
#if defined(RTLIGHTS) && !defined(SERVERONLY)
#define REALTIMELIGHTING "Realtime Lighting"
Cvar_Register (&r_shadow_scissor, REALTIMELIGHTING);
Cvar_Register (&r_shadow_realtime_world, REALTIMELIGHTING);

View file

@ -134,9 +134,6 @@ void GL_InitFogTexture(void);
#define GL_BeginRendering()
#define GL_EndRendering()
void GL_FlushSkinCache(void);
void GL_GAliasFlushSkinCache(void);
// Function prototypes for the Texture Object Extension routines
typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,
const GLboolean *);

View file

@ -814,12 +814,190 @@ qboolean HTTPDL_Poll(struct dl_download *dl)
return true;
}
/*
//decode a base64 byte to a 0-63 value. Cannot cope with =.
static unsigned int Base64_DecodeByte(char byt)
{
if (byt >= 'A' && byt <= 'Z')
return (byt-'A') + 0;
if (byt >= 'a' && byt <= 'z')
return (byt-'a') + 26;
if (byt >= '0' && byt <= '9')
return (byt-'0') + 52;
if (byt == '+')
return 62;
if (byt == '/')
return 63;
return -1;
}
//FIXME: we should be able to skip whitespace.
static int Base64_Decode(char *out, int outlen, char **srcout, int *srclenout)
{
int len = 0;
unsigned int result;
char *src = *srcout;
int srclen = *srclenout;
//4 input chars give 3 output chars
while(srclen >= 4)
{
if (len+3 > outlen)
{
//ran out of space in the output buffer
*srcout = src;
*srclenout = srclen;
return len;
}
result = Base64_DecodeByte(src[0])<<18;
result |= Base64_DecodeByte(src[1])<<12;
out[len++] = (result>>16)&0xff;
if (src[2] != '=')
{
result |= Base64_DecodeByte(src[2])<<6;
out[len++] = (result>>8)&0xff;
if (src[3] != '=')
{
result |= Base64_DecodeByte(src[3])<<0;
out[len++] = (result>>0)&0xff;
}
}
if (result & 0xff000000)
return 0; //some kind of invalid char
src += 4;
srclen -= 4;
}
//end of string
*srcout = src;
*srclenout = srclen;
//some kind of error
if (srclen)
{
if (srclen != 1 || *src)
return 0;
}
return len;
}
qboolean DataScheme_Decode(struct dl_download *dl)
{
char block[8192];
int remaining, blocksize;
char mimetype[256];
char baseval[256];
char charsetval[256];
char *url;
char *data;
char *charset;
char *base;
//failed previously
if (dl->status == DL_FAILED)
return false;
//data:[<MIME-type>][;charset=<encoding>][;base64],<data>
*mimetype = 0;
*baseval = 0;
*charsetval = 0;
url = dl->url;
if (!strncmp(url, "data:", 5))
url+=5; //should always match
data = strchr(url, ',');
if (!data)
return false;
charset = memchr(url, ';', data-url);
if (charset)
{
base = memchr(charset+1, ';', data-charset);
if (base)
{
if (data-(base+1) >= sizeof(baseval))
return false;
memcpy(baseval, base+1, data-(base+1));
baseval[data-(base+1)] = 0;
}
else
base = data;
if (base-(charset+1) >= sizeof(charsetval))
return false;
memcpy(charsetval, charset+1, base-(charset+1));
charsetval[base-(charset+1)] = 0;
if (!strchr(charsetval, '='))
{
strcpy(baseval, charsetval);
*charsetval = 0;
}
}
else
charset = data;
if (charset-(url) >= sizeof(charsetval))
return false;
memcpy(mimetype, url, charset-(url));
mimetype[charset-(url)] = 0;
if (!*mimetype)
Q_strncpyz(mimetype, "text/plain", sizeof(mimetype));
if (!*charsetval)
Q_strncpyz(charsetval, "charset=US-ASCII", sizeof(charsetval));
if (dl->notifystarted)
dl->notifystarted(dl, *mimetype?mimetype:NULL);
if (!dl->file)
{
#ifndef NPFTE
if (*dl->localname)
{
FS_CreatePath(dl->localname, FS_GAME);
dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAME);
}
else
dl->file = FS_OpenTemp();
#endif
if (!dl->file)
{
if (*dl->localname)
Con_Printf("HTTP: Couldn't open file \"%s\"\n", dl->localname);
else
Con_Printf("HTTP: Couldn't open temporary file\n");
dl->status = DL_FAILED;
return false;
}
}
data++;
remaining = strlen(data);
while(remaining > 0)
{
blocksize = Base64_Decode(block, sizeof(block), &data, &remaining);
if (!blocksize)
{
dl->status = DL_FAILED;
return false;
}
VFS_WRITE(dl->file, block, blocksize);
}
dl->status = DL_FINISHED;
return false;
}
*/
qboolean DL_Decide(struct dl_download *dl)
{
const char *url = dl->redir;
if (!*url)
url = dl->url;
/*if (!strnicmp(url, "data:", 5))
dl->poll = DataScheme_Decode;
else*/
if (!strnicmp(url, "http://", 7))
dl->poll = HTTPDL_Poll;
else
@ -883,11 +1061,12 @@ qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyF
struct dl_download *DL_Create(const char *url)
{
struct dl_download *newdl;
newdl = malloc(sizeof(*newdl));
newdl = malloc(sizeof(*newdl) + strlen(url)+1);
if (!newdl)
return NULL;
memset(newdl, 0, sizeof(*newdl));
Q_strncpyz(newdl->url, url, sizeof(newdl->url));
newdl->url = (char*)(newdl+1);
strcpy(newdl->url, url);
newdl->poll = DL_Decide;
if (!newdl->poll(newdl))
@ -995,10 +1174,10 @@ void HTTP_CL_Think(void)
cls.download = &dl->qdownload;
dl->qdownload.method = DL_HTTP;
if (*dl->localname)
strcpy(dl->qdownload.localname, dl->localname);
Q_strncpyz(dl->qdownload.localname, dl->localname, sizeof(dl->qdownload.localname));
else
strcpy(dl->qdownload.localname, dl->url);
strcpy(dl->qdownload.remotename, dl->url);
Q_strncpyz(dl->qdownload.localname, dl->url, sizeof(dl->qdownload.localname));
Q_strncpyz(dl->qdownload.remotename, dl->url, sizeof(dl->qdownload.remotename));
dl->qdownload.starttime = Sys_DoubleTime();
}

View file

@ -189,6 +189,7 @@ void HTTP_ServerShutdown(void)
typedef struct HTTP_active_connections_s {
SOCKET datasock;
char peername[256];
vfsfile_t *file;
struct HTTP_active_connections_s *next;
@ -242,6 +243,7 @@ void HTTP_RunExisting (void)
char *msg, *nl;
char buf2[2560]; //short lived temp buffer.
char resource[2560];
char host[256];
char mode[80];
qboolean hostspecified;
unsigned int contentlen;
@ -260,7 +262,7 @@ void HTTP_RunExisting (void)
if (cl->closereason)
{
IWebPrintf("Closing connection: %s\n", cl->closereason);
IWebPrintf("%s: Closing connection: %s\n", cl->peername, cl->closereason);
*link = cl->next;
closesocket(cl->datasock);
@ -342,6 +344,9 @@ cont:
continue;
}
host[0] = '?';
host[1] = 0;
hostspecified = false;
if (!strnicmp(resource, "http://", 7))
{ //groan... 1.1 compliance requires parsing this correctly, without the client ever specifiying it.
@ -351,7 +356,14 @@ cont:
if (!slash)
strcpy(resource, "/");
else
{
int hlen = slash-(resource+7);
if (hlen > sizeof(host)-1)
hlen = sizeof(host)-1;
memcpy(host, resource+7, hlen);
host[hlen] = 0;
memmove(resource, slash, strlen(slash+1)); //just get rid of the http:// stuff.
}
}
if (!strcmp(resource, "/"))
@ -397,7 +409,16 @@ cont:
msg++;
if (!strnicmp(msg, "Host: ", 6)) //parse needed header fields
{
int l = 0;
msg += 6;
while (*msg == ' ' || *msg == '\t')
msg++;
while (*msg != '\r' && *msg != '\n' && l < sizeof(host)-1)
host[l++] = *msg++;
host[l] = 0;
hostspecified = true;
}
else if (!strnicmp(msg, "Content-Length: ", 16)) //parse needed header fields
contentlen = strtoul(msg+16, NULL, 0);
else if (!strnicmp(msg, "Accept-Encoding:", 16)) //parse needed header fields
@ -491,7 +512,7 @@ cont:
resource[0] = '/';
resource[1] = 0; //I'm lazy, they need to comply
}
IWebPrintf("Download request for \"%s\"\n", resource+1);
IWebPrintf("%s: Download request for \"http://%s/%s\"\n", cl->peername, host, resource+1);
if (!strnicmp(mode, "P", 1)) //when stuff is posted, data is provided. Give an error message if we couldn't do anything with that data.
cl->file = IWebGenerateFile(resource+1, content, contentlen);
@ -519,7 +540,7 @@ cont:
}
if (!cl->file)
{
IWebPrintf("Download rejected\n");
IWebPrintf("%s: Download rejected\n", cl->peername);
if (HTTPmarkup >= 3)
msg = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/plain\r\n" "Content-Length: 15\r\n" "Server: "FULLENGINENAME"/0\r\n" "\r\n" "404 Bad address";
@ -611,7 +632,7 @@ notimplemented:
VFS_CLOSE(cl->file);
cl->file = NULL;
IWebPrintf("Download complete\n");
IWebPrintf("%s: Download complete\n", cl->peername);
}
else
cl->outbufferused+=ammount;
@ -663,14 +684,24 @@ notimplemented:
}
}
#ifdef WEBSVONLY
void VARGS Q_snprintfz (char *dest, size_t size, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vsnprintf (dest, size-1, fmt, args);
va_end (args);
//make sure its terminated.
dest[size-1] = 0;
}
#endif
qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while true
{
struct sockaddr_qstorage from;
int fromlen;
int clientsock;
int _true = true;
char buf[128];
netadr_t na;
HTTP_active_connections_t *cl;
@ -712,7 +743,7 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr
}
Con_Printf ("NET_GetPacket: %s\n", strerror(e));
IWebPrintf ("NET_GetPacket: %s\n", strerror(e));
return false;
}
@ -723,15 +754,19 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr
return false;
}
#ifndef WEBSVONLY
SockadrToNetadr(&from, &na);
IWebPrintf("New http connection from %s\n", NET_AdrToString(buf, sizeof(buf), &na));
#else
IWebPrintf("New http connection from %s\n", inet_ntoa(((struct sockaddr_in*)&from)->sin_addr));
#endif
cl = IWebMalloc(sizeof(HTTP_active_connections_t));
#ifndef WEBSVONLY
{
netadr_t na;
SockadrToNetadr(&from, &na);
NET_AdrToString(cl->peername, sizeof(cl->peername), &na);
}
#else
Q_snprintfz(cl->peername, sizeof(cl->peername), "%s:%i", inet_ntoa(((struct sockaddr_in*)&from)->sin_addr), ntohs(((struct sockaddr_in*)&from)->sin_port));
#endif
IWebPrintf("%s: New http connection\n", cl->peername);
cl->datasock = clientsock;
cl->next = HTTP_ServerConnections;

View file

@ -106,7 +106,7 @@ struct dl_download
qdownload_t qdownload;
/*stream config*/
char url[MAX_OSPATH]; /*original url*/
char *url; /*original url*/
char redir[MAX_OSPATH]; /*current redirected url*/
char localname[MAX_OSPATH]; /*leave empty for a temp file*/
struct vfsfile_s *file; /*downloaded to, if not already set when starting will open localname or a temp file*/

View file

@ -10,7 +10,7 @@ qboolean SV_AllowDownload (const char *name)
{
return true;
}
char com_token[1024];
char com_token[sizeof(com_token)];
com_tokentype_t com_tokentype;
int com_argc;
const char **com_argv;
@ -103,7 +103,7 @@ int main(int argc, char **argv)
}
void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *f), void *parm)
void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *f), void *parm)
{
HANDLE r;
WIN32_FIND_DATA fd;

View file

@ -1017,6 +1017,7 @@ void PR_Decompile_f(void)
}
void PR_Compile_f(void)
{
qboolean killondone = false;
int argc=3;
double time = Sys_DoubleTime();
char *argv[64] = {"", "-src", pr_sourcedir.string, "-srcfile", "progs.src"};
@ -1054,10 +1055,16 @@ void PR_Compile_f(void)
}
if (!svprogfuncs)
{
Q_SetProgsParms(true);
killondone = true;
}
if (PR_StartCompile(svprogfuncs, argc, argv))
while(PR_ContinueCompile(svprogfuncs));
if (killondone)
PR_Deinit();
time = Sys_DoubleTime() - time;
Con_TPrintf("Compile took %f secs\n", time);
@ -8904,7 +8911,7 @@ static void QCBUILTIN PF_clusterevent(pubprogfuncs_t *prinst, struct globalvars_
const char *dest = PR_GetStringOfs(prinst, OFS_PARM0);
const char *src = PR_GetStringOfs(prinst, OFS_PARM1);
const char *cmd = PR_GetStringOfs(prinst, OFS_PARM2);
const char *info = PF_VarString(prinst, 13, pr_globals);
const char *info = PF_VarString(prinst, 3, pr_globals);
SSV_Send(dest, src, cmd, info);
#endif
}
@ -8973,10 +8980,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"bound", PF_Fixme, 0, 0, 0, 45, "float(float min,float value,float max)"},
{"pow", PF_Fixme, 0, 0, 0, 46, "float(float,float)"},
{"copyentity", PF_Fixme, 0, 0, 0, 47, "void(entity src, entity dst)"},
{"fopen", PF_Fixme, 0, 0, 0, 48, "float(string filename, float mode)"},
{"fclose", PF_Fixme, 0, 0, 0, 49, "void(float fhandle)"},
{"fgets", PF_Fixme, 0, 0, 0, 50, "string(float fhandle)"},
{"fputs", PF_Fixme, 0, 0, 0, 51, "void(float fhandle, string s)"},
{"fopen", PF_Fixme, 0, 0, 0, 48, "filestream(string filename, float mode)"},
{"fclose", PF_Fixme, 0, 0, 0, 49, "void(filestream fhandle)"},
{"fgets", PF_Fixme, 0, 0, 0, 50, "string(filestream fhandle)"},
{"fputs", PF_Fixme, 0, 0, 0, 51, "void(filestream fhandle, string s)"},
{"strlen", PF_Fixme, 0, 0, 0, 52, "float(string)"},
{"strcat", PF_Fixme, 0, 0, 0, 53, "string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string)"},
{"substring", PF_Fixme, 0, 0, 0, 54, "string(string s, float start, float length)"},
@ -8999,10 +9006,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"cvar_string", PF_Fixme, 0, 0, 0, 71, "string(string name)"},
{"crash", PF_Fixme, 0, 0, 0, 72, "void()"},
{"stackdump", PF_Fixme, 0, 0, 0, 73, "void()"},
{"search_begin", PF_Fixme, 0, 0, 0, 74, "float(string pattern, float caseinsensitive, float quiet)"},
{"search_end", PF_Fixme, 0, 0, 0, 75, "void(float handle)"},
{"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(float handle)"},
{"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(float handle, float num)"},
{"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, float caseinsensitive, float quiet)"},
{"search_end", PF_Fixme, 0, 0, 0, 75, "void(searchhandle handle)"},
{"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(searchhandle handle)"},
{"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(searchhandle handle, float num)"},
{"etof", PF_Fixme, 0, 0, 0, 79, "float(entity)"},
{"ftoe", PF_Fixme, 0, 0, 0, 80, "entity(float)"},
{"validstring", PF_Fixme, 0, 0, 0, 81, "float(string)"},
@ -9161,10 +9168,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// Tomaz - QuakeC String Manipulation End
// Tomaz - QuakeC File System Begin (new mods use frik_file instead)
{"tq_fopen", PF_fopen, 0, 0, 0, 86, D("float(string filename, float mode)",NULL), true},// (QSG_FILE)
{"tq_fclose", PF_fclose, 0, 0, 0, 87, D("void(float fhandle)",NULL), true},// (QSG_FILE)
{"tq_fgets", PF_fgets, 0, 0, 0, 88, D("string(float fhandle)",NULL), true},// (QSG_FILE)
{"tq_fputs", PF_fputs, 0, 0, 0, 89, D("void(float fhandle, string s)",NULL), true},// (QSG_FILE)
{"tq_fopen", PF_fopen, 0, 0, 0, 86, D("filestream(string filename, float mode)",NULL), true},// (QSG_FILE)
{"tq_fclose", PF_fclose, 0, 0, 0, 87, D("void(filestream fhandle)",NULL), true},// (QSG_FILE)
{"tq_fgets", PF_fgets, 0, 0, 0, 88, D("string(filestream fhandle)",NULL), true},// (QSG_FILE)
{"tq_fputs", PF_fputs, 0, 0, 0, 89, D("void(filestream fhandle, string s)",NULL), true},// (QSG_FILE)
// Tomaz - QuakeC File System End
{"rain_go", PF_h2rain_go, 0, 0, 80, 0}, //80
@ -9260,10 +9267,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//End TEU_SHOWLMP2
//frik file
{"fopen", PF_fopen, 0, 0, 0, 110, "float(string filename, float mode, optional float mmapminsize)"}, // (FRIK_FILE)
{"fclose", PF_fclose, 0, 0, 0, 111, "void(float fhandle)"}, // (FRIK_FILE)
{"fgets", PF_fgets, 0, 0, 0, 112, "string(float fhandle)"}, // (FRIK_FILE)
{"fputs", PF_fputs, 0, 0, 0, 113, "void(float fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)"}, // (FRIK_FILE)
{"fopen", PF_fopen, 0, 0, 0, 110, "filestream(string filename, float mode, optional float mmapminsize)"}, // (FRIK_FILE)
{"fclose", PF_fclose, 0, 0, 0, 111, "void(filestream fhandle)"}, // (FRIK_FILE)
{"fgets", PF_fgets, 0, 0, 0, 112, "string(filestream fhandle)"}, // (FRIK_FILE)
{"fputs", PF_fputs, 0, 0, 0, 113, "void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)"}, // (FRIK_FILE)
{"strlen", PF_strlen, 0, 0, 0, 114, "float(string s)"}, // (FRIK_FILE)
{"strcat", PF_strcat, 0, 0, 0, 115, "string(string s1, optional string s2, ...)"}, // (FRIK_FILE)
{"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE)
@ -9284,7 +9291,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"externvalue", PF_externvalue, 0, 0, 0, 203, D("__variant(float prnum, string varname)", "Reads a global in the named progs by the name of that global.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")},
{"externset", PF_externset, 0, 0, 0, 204, D("void(float prnum, __variant newval, string varname)", "Sets a global in the named progs by name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")},
{"externrefcall", PF_externrefcall, 0, 0, 0, 205, D("__variant(float prnum, void() func, ...)","Calls a function between progs by its reference. No longer needed as direct function calls now switch progs context automatically, and have done for a long time. There is no remaining merit for this function."), true},
{"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpot(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos.")},
{"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos.")},
#if defined(Q2BSPS) || defined(Q3BSPS)
{"openportal", PF_OpenPortal, 0, 0, 0, 207, D("void(entity portal, float state)", "Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call.")},
#endif
@ -9317,8 +9324,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"chr2str", PF_chr2str, 0, 0, 0, 223, D("string(float chr, ...)", "The input floats are considered character values, and are concatenated.")},
{"strconv", PF_strconv, 0, 0, 0, 224, D("string(float ccase, float redalpha, float redchars, string str, ...)", "Converts quake chars in the input string amongst different representations.\nccase specifies the new case for letters.\n 0: not changed.\n 1: forced to lower case.\n 2: forced to upper case.\nredalpha and redchars switch between colour ranges.\n 0: no change.\n 1: Forced white.\n 2: Forced red.\n 3: Forced gold(low) (numbers only).\n 4: Forced gold (high) (numbers only).\n 5+6: Forced to white and red alternately.\nYou should not use this builtin in combination with UTF-8.")},
{"strpad", PF_strpad, 0, 0, 0, 225, D("string(float pad, string str1, ...)", "Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right.")}, //will be moved
{"infoadd", PF_infoadd, 0, 0, 0, 226, D("string(string old, string key, string value)", "Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \\ character.")},
{"infoget", PF_infoget, 0, 0, 0, 227, D("string(string info, string key)", "Reads a named value from an infostring. The returned value is a tempstring")},
{"infoadd", PF_infoadd, 0, 0, 0, 226, D("string(infostring old, string key, string value)", "Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \\ character.")},
{"infoget", PF_infoget, 0, 0, 0, 227, D("string(infostring info, string key)", "Reads a named value from an infostring. The returned value is a tempstring")},
// {"strcmp", PF_strncmp, 0, 0, 0, 228, D("float(string s1, string s2)", "Compares the two strings exactly. s1ofs allows you to treat s2 as a substring to compare against, or should be 0.\nReturns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher.")},
{"strncmp", PF_strncmp, 0, 0, 0, 228, D("#define strcmp strncmp\nfloat(string s1, string s2, optional float len, optional float s1ofs, optional float s2ofs)", "Compares up to 'len' chars in the two strings. s1ofs allows you to treat s2 as a substring to compare against, or should be 0.\nReturns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher.")},
{"strcasecmp", PF_strncasecmp, 0, 0, 0, 229, D("float(string s1, string s2)", "Compares the two strings without case sensitivity.\nReturns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon.")},
@ -9393,13 +9400,13 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"frametoname", PF_frametoname, 0, 0, 0, 284, "string(float modidx, float framenum)"},
{"skintoname", PF_skintoname, 0, 0, 0, 285, "string(float modidx, float skin)"},
// {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, 286, "void(string cvarname, optional string value)"},
{"hash_createtab", PF_hash_createtab, 0, 0, 0, 287, D("float(float tabsize, optional float defaulttype)", "Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return).")},
{"hash_destroytab", PF_hash_destroytab, 0, 0, 0, 288, D("void(float table)", "Destroys a hash table object.")},
{"hash_add", PF_hash_add, 0, 0, 0, 289, D("void(float table, string name, __variant value, optional float flags, optional float type)", "Adds the given key with the given value to the table.\nIf flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite.\nThe type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games.")},
{"hash_get", PF_hash_get, 0, 0, 0, 290, D("__variant(float table, string name, __variant deflt, optional float requiretype, optional float index)", "looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name.")},
{"hash_delete", PF_hash_delete, 0, 0, 0, 291, D("__variant(float table, string name)", "removes the named key. returns the value of the object that was destroyed, or 0 on error.")},
{"hash_getkey", PF_hash_getkey, 0, 0, 0, 292, D("string(float table, float idx)", "gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all.")},
{"hash_getcb", PF_hash_getcb, 0, 0, 0, 293, D("void(float table, void(string keyname, __variant val) callback, optional string name)", "For each item in the table that matches the name, call the callback. if name is omitted, will enumerate ALL keys."), true},
{"hash_createtab", PF_hash_createtab, 0, 0, 0, 287, D("hashtable(float tabsize, optional float defaulttype)", "Creates a hash table object with at least 'tabsize' slots. hash table with index 0 is a game-persistant table and will NEVER be returned by this builtin (except as an error return).")},
{"hash_destroytab", PF_hash_destroytab, 0, 0, 0, 288, D("void(hashtable table)", "Destroys a hash table object.")},
{"hash_add", PF_hash_add, 0, 0, 0, 289, D("void(hashtable table, string name, __variant value, optional float typeandflags)", "Adds the given key with the given value to the table.\nIf flags&HASH_REPLACE, the old value will be removed, if not set then multiple values may be added for a single key, they won't overwrite.\nThe type argument describes how the value should be stored and saved to files. While you can claim that all variables are just vectors, being more precise can result in less issues with tempstrings or saved games.")},
{"hash_get", PF_hash_get, 0, 0, 0, 290, D("__variant(hashtable table, string name, optional __variant deflt, optional float requiretype, optional float index)", "looks up the specified key name in the hash table. returns deflt if key was not found. If stringsonly=1, the return value will be in the form of a tempstring, otherwise it'll be the original value argument exactly as it was. If requiretype is specified, then values not of the specified type will be ignored. Hurrah for multiple types with the same name.")},
{"hash_delete", PF_hash_delete, 0, 0, 0, 291, D("__variant(hashtable table, string name)", "removes the named key. returns the value of the object that was destroyed, or 0 on error.")},
{"hash_getkey", PF_hash_getkey, 0, 0, 0, 292, D("string(hashtable table, float idx)", "gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all.")},
{"hash_getcb", PF_hash_getcb, 0, 0, 0, 293, D("void(hashtable table, void(string keyname, __variant val) callback, optional string name)", "For each item in the table that matches the name, call the callback. if name is omitted, will enumerate ALL keys."), true},
{"checkcommand", PF_checkcommand, 0, 0, 0, 294, D("float(string name)", "Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist.")},
{"argescape", PF_argescape, 0, 0, 0, 295, D("string(string s)", "Marks up a string so that it can be reliably tokenized as a single argument later.")},
{"clusterevent", PF_clusterevent, 0, 0, 0, 296, D("void(string dest, string from, string cmd, string info)", "Only functions in mapcluster mode. Sends an event to whichever server the named player is on. The destination server can then dispatch the event to the client or handle it itself via the SV_ParseClusterEvent entrypoint. If dest is empty, the event is broadcast to ALL servers. If the named player can't be found, the event will be returned to this server with the cmd prefixed with 'error:'.")},
@ -9586,16 +9593,16 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
#ifndef SERVERONLY
//begin menu-only
{"buf_create", PF_Fixme, 0, 0, 0, 440, "float()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_Fixme, 0, 0, 0, 441, "void(float bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_getsize", PF_Fixme, 0, 0, 0, 442, "float(float bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_copy", PF_Fixme, 0, 0, 0, 443, "void(float bufhandle_from, float bufhandle_to)"},//DP_QC_STRINGBUFFERS
{"buf_sort", PF_Fixme, 0, 0, 0, 444, "void(float bufhandle, float sortprefixlen, float backward)"},//DP_QC_STRINGBUFFERS
{"buf_implode", PF_Fixme, 0, 0, 0, 445, "string(float bufhandle, string glue)"},//DP_QC_STRINGBUFFERS
{"bufstr_get", PF_Fixme, 0, 0, 0, 446, "string(float bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"bufstr_set", PF_Fixme, 0, 0, 0, 447, "void(float bufhandle, float string_index, string str)"},//DP_QC_STRINGBUFFERS
{"bufstr_add", PF_Fixme, 0, 0, 0, 448, "float(float bufhandle, string str, float order)"},//DP_QC_STRINGBUFFERS
{"bufstr_free", PF_Fixme, 0, 0, 0, 449, "void(float bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"buf_create", PF_Fixme, 0, 0, 0, 440, "strbuf()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_Fixme, 0, 0, 0, 441, "void(strbuf bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_getsize", PF_Fixme, 0, 0, 0, 442, "float(strbuf bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_copy", PF_Fixme, 0, 0, 0, 443, "void(strbuf bufhandle_from, float bufhandle_to)"},//DP_QC_STRINGBUFFERS
{"buf_sort", PF_Fixme, 0, 0, 0, 444, "void(strbuf bufhandle, float sortprefixlen, float backward)"},//DP_QC_STRINGBUFFERS
{"buf_implode", PF_Fixme, 0, 0, 0, 445, "string(strbuf bufhandle, string glue)"},//DP_QC_STRINGBUFFERS
{"bufstr_get", PF_Fixme, 0, 0, 0, 446, "string(strbuf bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"bufstr_set", PF_Fixme, 0, 0, 0, 447, "void(strbuf bufhandle, float string_index, string str)"},//DP_QC_STRINGBUFFERS
{"bufstr_add", PF_Fixme, 0, 0, 0, 448, "float(strbuf bufhandle, string str, float order)"},//DP_QC_STRINGBUFFERS
{"bufstr_free", PF_Fixme, 0, 0, 0, 449, "void(strbuf bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"iscachedpic", PF_Fixme, 0, 0, 0, 451, "float(string name)"},// (EXT_CSQC)
{"precache_pic", PF_Fixme, 0, 0, 0, 452, "string(string name, optional float trywad)"},// (EXT_CSQC)
{"freepic", PF_Fixme, 0, 0, 0, 453, "void(string name)"},// (EXT_CSQC)
@ -9622,10 +9629,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"tokenize", PF_Tokenize, 0, 0, 0, 441, "float(string s)"},// (KRIMZON_SV_PARSECLIENTCOMMAND)
{"argv", PF_ArgV, 0, 0, 0, 442, "string(float n)"},// (KRIMZON_SV_PARSECLIENTCOMMAND
{"setattachment", PF_setattachment, 0, 0, 0, 443, "void(entity e, entity tagentity, string tagname)"},// (DP_GFX_QUAKE3MODELTAGS)
{"search_begin", PF_search_begin, 0, 0, 0, 444, D("float(string pattern, float caseinsensitive, float quiet)", "initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle.")},
{"search_end", PF_search_end, 0, 0, 0, 445, "void(float handle)"},
{"search_getsize", PF_search_getsize, 0, 0, 0, 446, D("float(float handle)", "Retrieves the number of files that were found.")},
{"search_getfilename", PF_search_getfilename,0, 0, 0, 447, D("string(float handle, float num)", "Retrieves name of one of the files that was found by the initial search.")},
{"search_begin", PF_search_begin, 0, 0, 0, 444, D("searchhandle(string pattern, float caseinsensitive, float quiet)", "initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle.")},
{"search_end", PF_search_end, 0, 0, 0, 445, "void(searchhandle handle)"},
{"search_getsize", PF_search_getsize, 0, 0, 0, 446, D("float(searchhandle handle)", "Retrieves the number of files that were found.")},
{"search_getfilename", PF_search_getfilename,0, 0, 0, 447, D("string(searchhandle handle, float num)", "Retrieves name of one of the files that was found by the initial search.")},
{"cvar_string", PF_cvar_string, 0, 0, 0, 448, "string(string cvarname)"},//DP_QC_CVAR_STRING
{"findflags", PF_FindFlags, 0, 0, 0, 449, "entity(entity start, .float fld, float match)"},//DP_QC_FINDFLAGS
{"findchainflags", PF_sv_findchainflags,0, 0, 0, 450, "entity(.float fld, float match)"},//DP_QC_FINDCHAINFLAGS
@ -9638,16 +9645,16 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// {"te_flamejet", PF_te_flamejet, 0, 0, 0, 457, "void(vector org, vector vel, float howmany)"},//DP_TE_FLAMEJET
// {"undefined", PF_Fixme, 0, 0, 0, 458, ""},
{"edict_num", PF_edict_for_num, 0, 0, 0, 459, "entity(float entnum)"},//DP_QC_EDICT_NUM
{"buf_create", PF_buf_create, 0, 0, 0, 460, "float()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_buf_del, 0, 0, 0, 461, "void(float bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_getsize", PF_buf_getsize, 0, 0, 0, 462, "float(float bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_copy", PF_buf_copy, 0, 0, 0, 463, "void(float bufhandle_from, float bufhandle_to)"},//DP_QC_STRINGBUFFERS
{"buf_sort", PF_buf_sort, 0, 0, 0, 464, "void(float bufhandle, float sortprefixlen, float backward)"},//DP_QC_STRINGBUFFERS
{"buf_implode", PF_buf_implode, 0, 0, 0, 465, "string(float bufhandle, string glue)"},//DP_QC_STRINGBUFFERS
{"bufstr_get", PF_bufstr_get, 0, 0, 0, 466, "string(float bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"bufstr_set", PF_bufstr_set, 0, 0, 0, 467, "void(float bufhandle, float string_index, string str)"},//DP_QC_STRINGBUFFERS
{"bufstr_add", PF_bufstr_add, 0, 0, 0, 468, "float(float bufhandle, string str, float order)"},//DP_QC_STRINGBUFFERS
{"bufstr_free", PF_bufstr_free, 0, 0, 0, 469, "void(float bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"buf_create", PF_buf_create, 0, 0, 0, 460, "strbuf()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_buf_del, 0, 0, 0, 461, "void(strbuf bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_getsize", PF_buf_getsize, 0, 0, 0, 462, "float(strbuf bufhandle)"},//DP_QC_STRINGBUFFERS
{"buf_copy", PF_buf_copy, 0, 0, 0, 463, "void(strbuf bufhandle_from, strbuf bufhandle_to)"},//DP_QC_STRINGBUFFERS
{"buf_sort", PF_buf_sort, 0, 0, 0, 464, "void(strbuf bufhandle, float sortprefixlen, float backward)"},//DP_QC_STRINGBUFFERS
{"buf_implode", PF_buf_implode, 0, 0, 0, 465, "string(strbuf bufhandle, string glue)"},//DP_QC_STRINGBUFFERS
{"bufstr_get", PF_bufstr_get, 0, 0, 0, 466, "string(strbuf bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
{"bufstr_set", PF_bufstr_set, 0, 0, 0, 467, "void(strbuf bufhandle, float string_index, string str)"},//DP_QC_STRINGBUFFERS
{"bufstr_add", PF_bufstr_add, 0, 0, 0, 468, "float(strbuf bufhandle, string str, float order)"},//DP_QC_STRINGBUFFERS
{"bufstr_free", PF_bufstr_free, 0, 0, 0, 469, "void(strbuf bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
//end non-menu
// {"undefined", PF_Fixme, 0, 0, 0, 470, ""},
@ -9699,7 +9706,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"tokenize_console",PF_tokenize_console,0, 0, 0, 514, "float(string str)"},
{"argv_start_index",PF_argv_start_index,0, 0, 0, 515, "float(float idx)"},
{"argv_end_index", PF_argv_end_index, 0, 0, 0, 516, "float(float idx)"},
{"buf_cvarlist", PF_buf_cvarlist, 0, 0, 0, 517, "void(float strbuf)"},
{"buf_cvarlist", PF_buf_cvarlist, 0, 0, 0, 517, "void(strbuf strbuf)"},
{"cvar_description",PF_cvar_description,0, 0, 0, 518, "string(string cvarname)"},
{"gettime", PF_gettime, 0, 0, 0, 519, "float(optional float timetype)"},
{"keynumtostring_omgwtf",PF_Fixme, 0, 0, 0, 520, "string(float keynum)"}, //excessive third version in dp's csqc.
@ -9722,8 +9729,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// {"log", PF_Fixme, 0, 0, 0, 532, "float(string mname)", true},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, "float(entity e, float channel)"},
{"soundlength", PF_Ignore, 0, 0, 0, 534, "float(string sample)"},
{"buf_loadfile", PF_buf_loadfile, 0, 0, 0, 535, "float(string filename, float bufhandle)"},
{"buf_writefile", PF_buf_writefile, 0, 0, 0, 536, "float(float filehandle, float bufhandle, optional float startpos, optional float numstrings)"},
{"buf_loadfile", PF_buf_loadfile, 0, 0, 0, 535, "float(string filename, strbuf bufhandle)"},
{"buf_writefile", PF_buf_writefile, 0, 0, 0, 536, "float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings)"},
// {"bufstr_find", PF_Fixme, 0, 0, 0, 537, "float(float bufhandle, string match, float matchrule, float startpos)"},
// {"matchpattern", PF_Fixme, 0, 0, 0, 538, "float(string s, string pattern, float matchrule)"},
// {"undefined", PF_Fixme, 0, 0, 0, 539, ""},
@ -9739,7 +9746,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"setmousetarget", PF_Fixme, 0, 0, 0, 603, "void(float trg)"},
{"getmousetarget", PF_Fixme, 0, 0, 0, 604, "float()"},
{"callfunction", PF_callfunction, 0, 0, 0, 605, D("void(.../*, string funcname*/)", "Invokes the named function. The function name is always passed as the last parameter and must always be present. The others are passed to the named function as-is")},
{"writetofile", PF_writetofile, 0, 0, 0, 606, D("void(float fh, entity e)", "Writes an entity's fields to the named frik_file file handle.")},
{"writetofile", PF_writetofile, 0, 0, 0, 606, D("void(filestream fh, entity e)", "Writes an entity's fields to the named frik_file file handle.")},
{"isfunction", PF_isfunction, 0, 0, 0, 607, "float(string s)"},
{"getresolution", PF_Fixme, 0, 0, 0, 608, "vector(float vidmode, optional float forfullscreen)"},
{"keynumtostring_menu",PF_Fixme, 0, 0, 0, 609, "string(float keynum)"}, //third copy of this builtin in dp's csqc.
@ -10133,6 +10140,7 @@ void PR_DumpPlatform_f(void)
char dbgfname[MAX_OSPATH];
unsigned int targ = 0;
qboolean defines = false;
qboolean accessors = false;
char *comment;
/*this list is here to ensure that the file can be used as a valid initial qc file (ignoring precompiler options)*/
@ -10369,7 +10377,7 @@ void PR_DumpPlatform_f(void)
{"TRUE", "const float", ALL, NULL, 1},
{"FALSE", "const float", ALL, "File not found...", 0},
{"M_PI", "const float", ALL, "File not found...", M_PI},
{"M_PI", "const float", ALL, NULL, M_PI},
{"MOVETYPE_NONE", "const float", QW|NQ|CS, NULL, MOVETYPE_NONE},
{"MOVETYPE_WALK", "const float", QW|NQ|CS, NULL, MOVETYPE_WALK},
@ -10585,16 +10593,15 @@ void PR_DumpPlatform_f(void)
{"EV_VECTOR", "const float", QW|NQ, NULL, ev_vector},
{"EV_ENTITY", "const float", QW|NQ, NULL, ev_entity},
// {"EV_FIELD", "const float", QW|NQ, NULL, ev_field},
// {"EV_FUNCTION", "const float", QW|NQ, NULL, ev_function},
// {"EV_POINTER", "const float", QW|NQ, NULL, ev_pointer},
{"EV_FUNCTION", "const float", QW|NQ, NULL, ev_function},
{"EV_POINTER", "const float", QW|NQ, NULL, ev_pointer},
{"EV_INTEGER", "const float", QW|NQ, NULL, ev_integer},
// {"EV_VARIANT", "const float", QW|NQ, NULL, ev_variant},
{"EV_VARIANT", "const float", QW|NQ, NULL, ev_variant},
// {"EV_STRUCT", "const float", QW|NQ, NULL, ev_struct},
// {"EV_UNION", "const float", QW|NQ, NULL, ev_union},
{"HASHT_PERSISTANT", "const float", ALL, "Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted).", 0},
{"HASH_REPLACE", "const float", ALL, "Used with hash_add. Attempts to remove the old value instead of adding two values for a single key.", 1},
{"HASH_STRING", "const float", ALL, "Used with hash_add. Specifies that the contents of the string argument should be internally zoned.", 2},
{"gamestate", "hashtable", ALL, "Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted).", 0},
{"HASH_REPLACE", "const float", ALL, "Used with hash_add. Attempts to remove the old value instead of adding two values for a single key.", 256},
{"STAT_HEALTH", "const float", CS, NULL, STAT_HEALTH},
{"STAT_WEAPON", "const float", CS, NULL, STAT_WEAPON},
@ -10779,6 +10786,10 @@ void PR_DumpPlatform_f(void)
defines = true;
if (!stricmp(Cmd_Argv(i), "-Fnodefines"))
defines = false;
if (!stricmp(Cmd_Argv(i), "-Faccessors"))
accessors = true;
if (!stricmp(Cmd_Argv(i), "-Fnoaccessors"))
accessors = false;
if (!stricmp(Cmd_Argv(i), "-O"))
fname = Cmd_Argv(++i);
}
@ -10808,6 +10819,7 @@ void PR_DumpPlatform_f(void)
"-Tcs - dump specifically CSQC fields\n"
"-Tmenu - dump specifically menuqc fields\n"
"-Fdefines - generate #defines instead of constants\n"
"-Faccessors - use accessors instead of basic types via defines\n"
"-O - write to a different qc file\n"
"*/\n"
, FULLENGINENAME, FTE_VER_MAJOR, FTE_VER_MINOR, Cmd_Argv(0), Cmd_Args());
@ -10877,6 +10889,25 @@ void PR_DumpPlatform_f(void)
"#endif\n"
);
if (accessors)
{
VFS_PRINTF(f, "accessor strbuf : float;\n");
VFS_PRINTF(f, "accessor searchhandle : float;\n");
VFS_PRINTF(f, "accessor hashtable : float;\n");
VFS_PRINTF(f, "accessor infostring : string;\n");
VFS_PRINTF(f, "accessor filestream : float;\n");
}
else
{
VFS_PRINTF(f, "#define strbuf float\n");
VFS_PRINTF(f, "#define searchhandle float\n");
VFS_PRINTF(f, "#define hashtable float\n");
VFS_PRINTF(f, "#define infostring string\n");
VFS_PRINTF(f, "#define filestream float\n");
}
for (i = 0; knowndefs[i].name; i++)
{
for (j = 0; j < i; j++)
@ -10963,10 +10994,20 @@ void PR_DumpPlatform_f(void)
comment = "";
if (!strcmp(knowndefs[i].type, "const float"))
{
if (defines)
VFS_PRINTF(f, "#define %s %g%s\n", knowndefs[i].name, knowndefs[i].value, comment);
if (knowndefs[i].value >= (1<<23))
{
if (defines)
VFS_PRINTF(f, "#define %s %i%s\n", knowndefs[i].name, (int)knowndefs[i].value, comment);
else
VFS_PRINTF(f, "%s %s = %i;%s\n", knowndefs[i].type, knowndefs[i].name, (int)knowndefs[i].value, comment);
}
else
VFS_PRINTF(f, "%s %s = %g;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
{
if (defines)
VFS_PRINTF(f, "#define %s %g%s\n", knowndefs[i].name, knowndefs[i].value, comment);
else
VFS_PRINTF(f, "%s %s = %g;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment);
}
}
else if (!strcmp(knowndefs[i].type, "const string"))
{
@ -11198,6 +11239,42 @@ void PR_DumpPlatform_f(void)
VFS_PRINTF(f, "#endif\n");
}
if (accessors)
{
VFS_PRINTF(f,
"accessor strbuf : float\n{\n"
"\tget float asfloat[float idx] = {return stof(bufstr_get(this, idx));};\n"
"\tset float asfloat[float idx] = {bufstr_set(this, idx, ftos(value));};\n"
"\tget string[float] = bufstr_get;\n"
"\tset string[float] = bufstr_set;\n"
"\tget float length = buf_getsize;\n"
"};\n");
VFS_PRINTF(f,
"accessor searchhandle : float\n{\n"
"\tget string[float] = search_getfilename;\n"
"\tget float length = search_getsize;\n"
"};\n");
VFS_PRINTF(f,
"accessor hashtable : float\n{\n"
"\tget vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);};\n"
"\tset vector v[string key] = {hash_add(this, key, value, 1, EV_VECTOR);};\n"
"\tget string s[string key] = {return hash_get(this, key, \"\", EV_STRING);};\n"
"\tset string s[string key] = {hash_add(this, key, value, 1, EV_STRING);};\n"
"\tget string f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);};\n"
"\tset string f[string key] = {hash_add(this, key, value, 1, EV_FLOAT);};\n"
"\tget __variant[string key] = {return hash_get(this, key, __NULL__);};\n"
"\tset __variant[string key] = {hash_add(this, key, value, 1);};\n"
"};\n");
VFS_PRINTF(f,
"accessor infostring : string\n{\n"
"\tget string[string] = infoget;\n"
"};\n");
VFS_PRINTF(f,
"accessor filestream : float\n{\n"
"\tget string = fgets;\n"
"\tset string = {fputs(this,value);};\n"
"};\n");
}
VFS_PRINTF(f, "#pragma noref 0\n");

View file

@ -1022,6 +1022,7 @@ void SSV_InstructMaster(sizebuf_t *cmd);
void SSV_PrintToMaster(char *s);
void SSV_ReadFromControlServer(void);
void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part
void SSV_RequestShutdown(void); //asks the cluster to not send us new players
void Sys_InstructSlave(pubsubserver_t *s, sizebuf_t *cmd);
int Sys_SubServerRead(pubsubserver_t *s); //1: yes. 0: no. -1: error

View file

@ -569,6 +569,9 @@ void SV_Map_f (void)
#ifndef SERVERONLY
SCR_SetLoadingStage(LS_NONE);
#endif
if (SSV_IsSubServer())
Cbuf_AddText("\nquit\n", RESTRICT_LOCAL);
return;
}
}

View file

@ -14,12 +14,6 @@ void VARGS SV_RejectMessage(int protocol, char *format, ...);
void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int numstats, float *stats);
static char *knownmaps[] =
{
"",
"start"
};
typedef struct {
//fixme: hash tables
unsigned int playerid;
@ -93,11 +87,7 @@ pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname)
if (s)
{
if (!id)
{
if (nextserverid < sizeof(knownmaps)/sizeof(knownmaps[0]))
nextserverid = sizeof(knownmaps)/sizeof(knownmaps[0]);
id = nextserverid++;
}
id = ++nextserverid;
s->id = id;
s->next = subservers;
subservers = s;
@ -125,33 +115,54 @@ pubsubserver_t *MSV_FindSubServer(unsigned int id)
return s;
}
if (!s && id >= 1 && id < sizeof(knownmaps)/sizeof(knownmaps[0]))
s = MSV_StartSubServer(id, knownmaps[id]);
return s;
return NULL;
}
pubsubserver_t *MSV_FindSubServerName(const char *mapname)
//"5" finds server 5 only
//"5:dm4" finds server 5, and will start it if not known (even if a different node is running the same map)
//"0:dm4" starts a new server running dm4, even if its already running
//":dm4" finds any server running dm4. starts a new one if needed.
pubsubserver_t *MSV_FindSubServerName(const char *servername)
{
pubsubserver_t *s;
unsigned int to;
for (to = 1; to < sizeof(knownmaps)/sizeof(knownmaps[0]); to++)
{
if (!strcmp(knownmaps[to], mapname))
return MSV_FindSubServer(to);
}
unsigned int id;
qboolean forcenew = false;
char *mapname;
for (s = subservers; s; s = s->next)
id = strtoul(servername, &mapname, 0);
if (*mapname == ':')
{
if (!strcmp(s->name, mapname))
if (!id && servername != mapname)
forcenew = true;
mapname++;
}
else
mapname = "";
if (id)
{
s = MSV_FindSubServer(id);
if (s)
return s;
}
return MSV_StartSubServer(0, mapname);
}
qboolean MSV_AddressForMap(netadr_t *ret, int natype, int serverid)
{
pubsubserver_t *s = MSV_FindSubServer(serverid);
if (*mapname)
{
if (!forcenew)
{
for (s = subservers; s; s = s->next)
{
if (!strcmp(s->name, mapname))
return s;
}
}
return MSV_StartSubServer(id, mapname);
}
return NULL;
}
qboolean MSV_AddressForServer(netadr_t *ret, int natype, pubsubserver_t *s)
{
if (s)
{
if (natype == s->addrv6.type)
@ -458,7 +469,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
send.cursize = 2;
NET_StringToAdr(claddr, 0, &cladr);
MSV_AddressForMap(&svadr, cladr.type, s->id);
MSV_AddressForServer(&svadr, cladr.type, s);
if (!to)
{
if (svadr.type != NA_INVALID)
@ -525,6 +536,13 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
for (s = subservers; s; s = s->next)
Sys_InstructSlave(s, &send);
}
else if (*dest == '\\')
{
//send to a specific server (backslashes should not be valid in infostrings, and thus not in names.
//FIXME: broadcasting for now.
for (s = subservers; s; s = s->next)
Sys_InstructSlave(s, &send);
}
else
{
//send it to the server that the player is currently on.
@ -940,15 +958,15 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
{
char tmpbuf[256];
netadr_t serveraddr;
pubsubserver_t *s = NULL;
if (!serverid)
serverid = 1;
if (!s)
s = MSV_FindSubServerName(":start");
if (!MSV_AddressForMap(&serveraddr, clientaddr->type, serverid) && !MSV_AddressForMap(&serveraddr, clientaddr->type, serverid=1))
if (!s || !MSV_AddressForServer(&serveraddr, clientaddr->type, s))
SV_RejectMessage(SCP_QUAKEWORLD, "Unable to find lobby.\n");
else
{
pubsubserver_t *s;
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN];
clusterplayer_t *pl;
@ -963,7 +981,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
NET_AdrToString(pl->address, sizeof(pl->address), clientaddr);
pl->playerid = playerid;
InsertLinkBefore(&pl->allplayers, &clusterplayers);
pl->server = s = MSV_FindSubServer(serverid);
pl->server = s;
MSG_WriteByte(&send, ccmd_takeplayer);
MSG_WriteLong(&send, playerid);

View file

@ -3764,41 +3764,42 @@ void SV_SetInfo_f (void)
return;
}
if (Cmd_Argv(1)[0] == '*')
key = Cmd_Argv(1);
if (key[0] == '*')
return; // don't set priveledged values
if (strstr(Cmd_Argv(1), "\\") || strstr(Cmd_Argv(2), "\\"))
if (strstr(key, "\\") || strstr(Cmd_Argv(2), "\\"))
return; // illegal char
Q_strncpyz(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), sizeof(oldval));
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, Cmd_Argv(1), Cmd_Argv(2), sizeof(host_client->userinfo));
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, Cmd_Argv(1)), oldval))
if (!strcmp(Info_ValueForKey(host_client->userinfo, key), oldval))
return; // key hasn't changed
// process any changed values
SV_ExtractFromUserinfo (host_client, true);
if (progstype != PROG_QW && !strcmp(Cmd_Argv(1), "bottomcolor"))
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 (*Cmd_Argv(1) != '_')
if (*key != '_')
{
i = host_client - svs.clients;
key = Cmd_Argv(1);
val = Info_ValueForKey(host_client->userinfo, key);
basic = SV_UserInfoIsBasic(key);
@ -3845,9 +3846,11 @@ void SV_SetInfo_f (void)
}
}
SV_LogPlayer(host_client, "userinfo changed");
//doh't spam chat changes. they're not interesting, and just spammy.
if (strcmp(key, "chat"))
SV_LogPlayer(host_client, "userinfo changed");
PR_ClientUserInfoChanged(Cmd_Argv(1), oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
PR_ClientUserInfoChanged(key, oldval, Info_ValueForKey(host_client->userinfo, key));
}
/*

View file

@ -74,12 +74,10 @@ static qboolean QDECL VFSWEB_ClosePersist(vfsfile_t *file)
return VFSWEB_Close(file);
}
vfsfile_t *FSWEB_OpenTemp(void)
vfsfile_t *FSWEB_OpenTempHandle(int f)
{
int f;
vfswebfile_t *file;
f = emscriptenfte_buf_create();
if (f == -1)
{
Con_Printf("FSWEB_OpenTemp failed\n");
@ -102,6 +100,11 @@ vfsfile_t *FSWEB_OpenTemp(void)
return &file->funcs;
}
vfsfile_t *FSWEB_OpenTemp(void)
{
return FSWEB_OpenTempHandle(emscriptenfte_buf_create());
}
vfsfile_t *VFSWEB_Open(const char *osname, const char *mode, qboolean *needsflush)
{
int f;

View file

@ -36,6 +36,6 @@ int emscriptenfte_setupcanvas(
void(*Mouse)(int devid,int abs,float x,float y,float z,float size),
void(*Button)(int devid, int down, int mbutton),
int(*Keyboard)(int devid, int down, int keycode, int unicode),
void(*Hash)(char *newhash)
void(*LoadFile)(char *newhash, int filehandle)
);

View file

@ -29,6 +29,33 @@ mergeInto(LibraryManager.library,
alert(msg);
},
emscriptenfte_handle_alloc__deps : ['$FTEH'],
emscriptenfte_handle_alloc : function(h)
{
for (var i = 0; FTEH.h.length; i+=1)
{
if (FTEH.h[i] == null)
{
FTEH.h[i] = h;
return i;
}
}
i = FTEH.h.length;
FTEH.h[i] = h;
return i;
},
//temp files
emscriptenfte_buf_createfromarraybuf__deps : ['emscriptenfte_handle_alloc'],
emscriptenfte_buf_createfromarraybuf : function(buf)
{
var len = buf.length;
var b = {h:-1, r:1, l:len,m:len,d:new Uint8Array(buf), n:null};
b.h = _emscriptenfte_handle_alloc(b);
return b.h;
},
$FTEC__deps : ['emscriptenfte_buf_createfromarraybuf'],
$FTEC:
{
ctxwarned:0,
@ -42,6 +69,20 @@ mergeInto(LibraryManager.library,
key:0
},
loadurl : function(url, arraybuf)
{
if (FTEC.evcb.loadfile != 0)
{
var handle = -1;
if (arraybuf !== undefined)
handle = _emscriptenfte_buf_createfromarraybuf(arraybuf);
var ptr = _malloc(url.length);
writeStringToMemory(url, ptr);
Runtime.dynCall('vii', FTEC.evcb.loadfile, [ptr, handle]);
_free(ptr);
}
},
handleevent : function(event)
{
switch(event.type)
@ -138,28 +179,49 @@ mergeInto(LibraryManager.library,
}
event.preventDefault();
break;
case 'dragenter':
case 'dragover':
event.stopPropagation();
event.preventDefault();
break;
case 'drop':
event.stopPropagation();
event.preventDefault();
var files = event.dataTransfer.files;
for (var i = 0; i < files.length; i++)
{
var file = files[i];
var reader = new FileReader();
reader.onload = function(evt)
{
FTEC.loadurl(file.name, evt.target.result);
};
reader.readAsArrayBuffer(file);
}
break;
default:
console.log(event);
break;
}
}
},
emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser'],
emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evh)
emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser', 'emscriptenfte_buf_createfromarraybuf'],
emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evf)
{
FTEC.evcb.resize = evresz;
FTEC.evcb.mouse = evm;
FTEC.evcb.button = evb;
FTEC.evcb.key = evk;
FTEC.evcb.hashchange = evh;
FTEC.evcb.loadfile = evf;
if (!FTEC.donecb)
{
FTEC.donecb = 1;
['mousedown', 'mouseup', 'mousemove', 'wheel', 'mousewheel', 'mouseout', 'keypress', 'keydown', 'keyup', 'touchstart', 'touchend', 'touchcancel', 'touchleave', 'touchmove'].forEach(function(event)
var events = ['mousedown', 'mouseup', 'mousemove', 'wheel', 'mousewheel', 'mouseout', 'keypress', 'keydown', 'keyup', 'touchstart', 'touchend', 'touchcancel', 'touchleave', 'touchmove', 'dragenter', 'dragover', 'drop'];
events.forEach(function(event)
{
Module['canvas'].addEventListener(event, FTEC.handleevent, true);
});
['keydown', 'keyup', 'keypress'].forEach(function(event)
events.forEach(function(event)
{
document.addEventListener(event, FTEC.handleevent, true);
});
@ -172,7 +234,7 @@ mergeInto(LibraryManager.library,
}
if (Module.print === undefined)
Module.print = function(msg){console.log(msg);};
var ctx = Browser.createContext(Module['canvas'], true, true);
var ctx = Browser.createContext(Module['canvas'], true, true);
if (ctx == null)
{
var msg = "Unable to set up webgl context.\n\nPlease use a browser that supports it and has it enabled\nYour graphics drivers may also be blacklisted, so try updating those too. woo, might as well update your entire operating system while you're at it.\nIt'll be expensive, but hey, its YOUR money, not mine.\nYou can probably just disable the blacklist, but please don't moan at me when your computer blows up, seriously, make sure those drivers are not too buggy.\nI knew a guy once. True story. Boring, but true.\nYou're probably missing out on something right now. Don't you just hate it when that happens?\nMeh, its probably just tinkertoys, right?\n\nYou know, you could always try Internet Explorer, you never know, hell might have frozen over.\nDon't worry, I wasn't serious.\n\nTum te tum. Did you get it working yet?\nDude, fix it already.\n\nThis message was brought to you by Sleep Deprivation, sponsoring quake since I don't know when";
@ -202,17 +264,12 @@ mergeInto(LibraryManager.library,
window.onresize();
if (FTEC.evcb.hashchange)
window.onhashchange = function()
{
if (FTEC.evcb.hashchange != 0)
window.onhashchange = function()
{
var val = location.hash;
var ptr = _malloc(val.length);
writeStringToMemory(val, ptr);
Runtime.dynCall('vi', FTEC.evcb.hashchange, [ptr]);
_free(ptr);
}
};
FTEC.loadurl(location.hash.substring(1));
};
}
return 1;
},
@ -228,23 +285,6 @@ mergeInto(LibraryManager.library,
return Date.now();
},
emscriptenfte_handle_alloc__deps : ['$FTEH'],
emscriptenfte_handle_alloc : function(h)
{
for (var i = 0; FTEH.h.length; i+=1)
{
if (FTEH.h[i] == null)
{
FTEH.h[i] = h;
return i;
}
}
i = FTEH.h.length;
FTEH.h[i] = h;
return i;
},
//temp files
emscriptenfte_buf_create__deps : ['emscriptenfte_handle_alloc'],
emscriptenfte_buf_create : function()
{
@ -481,7 +521,7 @@ mergeInto(LibraryManager.library,
http.onload = function(e)
{
// console.log("onload: " + _url + " status " + http.status);
console.log("onload: " + _url + " status " + http.status);
if (http.status == 200)
{
var bar = new Uint8Array(http.response);
@ -499,7 +539,7 @@ mergeInto(LibraryManager.library,
http.onerror = function(e)
{
// console.log("onerror: " + _url + " status " + http.status);
console.log("onerror: " + _url + " status " + http.status);
if (onerror)
Runtime.dynCall('vii', onerror, [ctx, http.status]);
};

View file

@ -151,15 +151,22 @@ static void DOM_ButtonEvent(int devid, int down, int button)
IN_KeyEvent(devid, down, K_MOUSE1+button, 0);
}
}
void DOM_HashChanged(char *loc)
vfsfile_t *FSWEB_OpenTempHandle(int f);
void DOM_LoadFile(char *loc, int handle)
{
vfsfile_t *file = NULL;
Con_Printf("DOM_LoadFile: %s %i\n", loc, handle);
if (handle != -1)
file = FSWEB_OpenTempHandle(handle);
//try and open it. generally downloading it from the server.
Host_RunFile(loc+1, strlen(loc+1), NULL);
if (!Host_RunFile(loc, strlen(loc), file))
{
if (file)
VFS_CLOSE(file);
}
}
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
{
int flags;
vid_isfullscreen = true;
if (!emscriptenfte_setupcanvas(
@ -169,7 +176,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
IN_MouseMove,
DOM_ButtonEvent,
DOM_KeyEvent,
DOM_HashChanged
DOM_LoadFile
))
{
Con_Printf("Couldn't set up canvas\n");