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

View file

@ -3908,6 +3908,8 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
f->flags |= HRF_QTVINFO; f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "text/x-quaketvident")) else if (!strcmp(mimetype, "text/x-quaketvident"))
f->flags |= HRF_QTVINFO; f->flags |= HRF_QTVINFO;
else if (!strcmp(mimetype, "application/x-fteplugin"))
f->flags |= HRF_MANIFEST;
else if (!strcmp(mimetype, "application/x-ftemanifest")) else if (!strcmp(mimetype, "application/x-ftemanifest"))
f->flags |= HRF_MANIFEST; f->flags |= HRF_MANIFEST;
else if (!strcmp(mimetype, "application/x-multiviewdemo")) else if (!strcmp(mimetype, "application/x-multiviewdemo"))
@ -3916,6 +3918,9 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
// f->flags |= HRF_BSP; // f->flags |= HRF_BSP;
// else if (!strcmp(mimetype, "application/x-ftepackage")) // else if (!strcmp(mimetype, "application/x-ftepackage"))
// f->flags |= HRF_PACKAGE; // f->flags |= HRF_PACKAGE;
if (f->flags & HRF_MANIFEST)
waitingformanifest++;
} }
if (!(f->flags & HRF_FILETYPES)) if (!(f->flags & HRF_FILETYPES))
@ -4001,7 +4006,7 @@ static qboolean isurl(char *url)
#ifdef FTE_TARGET_WEB #ifdef FTE_TARGET_WEB
return true; //assume EVERYTHING is a url, because the local filesystem is pointless. return true; //assume EVERYTHING is a url, because the local filesystem is pointless.
#endif #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) void Host_DoRunFile(hrf_t *f)
@ -4041,8 +4046,11 @@ void Host_DoRunFile(hrf_t *f)
if (!(f->flags & HRF_OPENED)) if (!(f->flags & HRF_OPENED))
{ {
struct dl_download *dl; 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 = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
if (dl)
{
f->flags |= HRF_WAITING|HRF_DOWNLOADED;
dl->notifystarted = Host_BeginFileDownload; dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f; dl->user_ctx = f;
@ -4050,6 +4058,7 @@ void Host_DoRunFile(hrf_t *f)
return; return;
} }
} }
}
#endif #endif
//if we get here, we have no mime type to give us any clues. //if we get here, we have no mime type to give us any clues.
@ -4169,10 +4178,13 @@ void Host_DoRunFile(hrf_t *f)
if (isurl(f->fname)) if (isurl(f->fname))
{ {
struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded); struct dl_download *dl = HTTP_CL_Get(f->fname, NULL, Host_RunFileDownloaded);
if (dl)
{
dl->notifystarted = Host_BeginFileDownload; dl->notifystarted = Host_BeginFileDownload;
dl->user_ctx = f; dl->user_ctx = f;
return; return;
} }
}
#endif #endif
f->srcfile = VFSOS_Open(f->fname, "rb"); //input file is a system path, or something. 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) if (qrenderer > QR_NONE && !m_state)
{ {
#ifndef NOBUITINMENUS #ifndef NOBUILTINMENUS
if (!cls.state && !m_state && !*FS_GetGamedir(false)) if (!cls.state && !m_state && !*FS_GetGamedir(false))
M_Menu_Mods_f(); M_Menu_Mods_f();
#endif #endif

View file

@ -4351,10 +4351,33 @@ void CL_NewTranslation (int slot)
player = &cl.players[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); s = Skin_FindName (player);
COM_StripExtension(s, s, MAX_QPATH); COM_StripExtension(s, s, MAX_QPATH);
if (player->skin && !stricmp(s, player->skin->name)) if (player->qwskin && !stricmp(s, player->qwskin->name))
player->skin = NULL; 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_RSShot_f (void);
void SCR_CPrint_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 = SCVARF("show_fps", "0", CVAR_ARCHIVE);
cvar_t show_fps_x = SCVAR("show_fps_x", "-1"); cvar_t show_fps_x = SCVAR("show_fps_x", "-1");
cvar_t show_fps_y = SCVAR("show_fps_y", "-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" #include "particles.h"
typedef struct typedef struct qwskin_s
{ {
char name[64]; char name[64];
int width; int width;
@ -32,7 +32,7 @@ typedef struct
qboolean failedload; // the name isn't a valid skin qboolean failedload; // the name isn't a valid skin
void *skindata; void *skindata;
} skin_t; } qwskin_t;
// player_state_t is the information needed by a player entity // player_state_t is the information needed by a player entity
// to do move prediction and to generate a drawable entity // to do move prediction and to generate a drawable entity
@ -169,7 +169,8 @@ typedef struct player_info_s
unsigned int tbottomcolor; unsigned int tbottomcolor;
int spectator; int spectator;
skin_t *skin; qwskin_t *qwskin;
skinid_t skinid;
struct model_s *model; struct model_s *model;
@ -1314,10 +1315,10 @@ typedef struct
qbyte *ReadPCXData(qbyte *buf, int length, int width, int height, qbyte *result); 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); char *Skin_FindName (player_info_t *sc);
void Skin_Find (player_info_t *sc); void Skin_Find (player_info_t *sc);
qbyte *Skin_Cache8 (skin_t *skin); qbyte *Skin_Cache8 (qwskin_t *skin);
qbyte *Skin_Cache32 (skin_t *skin);
void Skin_Skins_f (void); void Skin_Skins_f (void);
void Skin_FlushSkin(char *name); void Skin_FlushSkin(char *name);
void Skin_AllSkins_f (void); void Skin_AllSkins_f (void);

View file

@ -1228,6 +1228,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.bottomcolour = 1; ent.bottomcolour = 1;
ent.h2playerclass = 0; ent.h2playerclass = 0;
ent.playerindex = -1; ent.playerindex = -1;
ent.customskin = 0;
// set frame // set frame
if (effects & Q2EF_ANIM01) if (effects & Q2EF_ANIM01)
@ -1315,11 +1316,14 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.model = player->model; ent.model = player->model;
if (!ent.model || ent.model->needload) //we need to do better than this 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; ent.playerindex = (s1->skinnum&0xff)%cl.allocated_client_slots;
player->model = ent.model;
/* ci = &cl.clientinfo[s1->skinnum & 0xff]; /* ci = &cl.clientinfo[s1->skinnum & 0xff];
// ent.skin = ci->skin; // ent.skin = ci->skin;
ent.model = ci->model; ent.model = ci->model;
@ -1813,6 +1817,8 @@ void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops)
else else
gun.framestate.g[FS_REG].frame[1] = ops->gunframe; gun.framestate.g[FS_REG].frame[1] = ops->gunframe;
gun.playerindex = -1;
gun.flags = Q2RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL; gun.flags = Q2RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
gun.framestate.g[FS_REG].lerpfrac = 1-cl.lerpfrac; gun.framestate.g[FS_REG].lerpfrac = 1-cl.lerpfrac;
VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all 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) void CLQ2_AddEntities (void)
{ {
extern cvar_t chase_active, chase_back, chase_up;
if (cls.state != ca_active) if (cls.state != ca_active)
return; return;
@ -1952,6 +1959,22 @@ void CLQ2_AddEntities (void)
CLQ2_AddProjectiles (); CLQ2_AddProjectiles ();
#endif #endif
CL_UpdateTEnts (); 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) void CL_GetNumberedEntityInfo (int num, float *org, float *ang)

View file

@ -1,6 +1,6 @@
#include "quakedef.h" #include "quakedef.h"
#if defined(WEBCLIENT) && !defined(NOBUITINMENUS) #if defined(WEBCLIENT) && !defined(NOBUILTINMENUS)
#define DOWNLOADMENU #define DOWNLOADMENU
#endif #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); R2D_ScalePic (cx, cy+8, 8, 8, p);
} }
#ifndef NOBUITINMENUS #ifndef NOBUILTINMENUS
int omousex; int omousex;
int omousey; int omousey;

View file

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

View file

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

View file

@ -4,7 +4,7 @@
#include "winquake.h" #include "winquake.h"
#include "shader.h" #include "shader.h"
#ifndef NOBUITINMENUS #ifndef NOBUILTINMENUS
extern cvar_t maxclients; 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 qboolean forcesaveprompt;
extern cvar_t pr_debugger; extern cvar_t pr_debugger;
@ -712,6 +712,7 @@ const char *presetexec[] =
"gl_texturemode2d n;" //yeah, 2d too. "gl_texturemode2d n;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby! "r_part_classic_square 1;" //blocky baby!
"r_part_classic_expgrav 1;" //vanillaery "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 "cl_sbar 1;" //its a style thing
"sv_nqplayerphysics 1;" //gb wanted this "sv_nqplayerphysics 1;" //gb wanted this
"cl_demoreel 1;" //yup, arcadey "cl_demoreel 1;" //yup, arcadey

View file

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

View file

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

View file

@ -148,6 +148,8 @@ typedef struct
int nummappings; int nummappings;
int maxmappings; int maxmappings;
qbyte geomset[MAX_GEOMSETS]; //allows selecting a single set of geometry from alternatives. this might be a can of worms. 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 struct
{ {
char surface[MAX_QPATH]; 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. 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 //gl_alias.c
void GL_GAliasFlushSkinCache(void); void R_GAliasFlushSkinCache(qboolean final);
void R_GAlias_DrawBatch(struct batch_s *batch); void R_GAlias_DrawBatch(struct batch_s *batch);
void R_GAlias_GenerateBatches(entity_t *e, struct batch_s **batches); 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); 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+16, va("Ping: %i", ping));
Draw_FunString (x+32, y+24, va("Time: %i", time)); 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. if (!p) //display a default if the icon couldn't be found.
p = R2D_SafeCachePic("players/male/grunt_i.pcx"); p = R2D_SafeCachePic("players/male/grunt_i.pcx");
R2D_ScalePic (x, y, 32, 32, p); R2D_ScalePic (x, y, 32, 32, p);

View file

@ -30,8 +30,8 @@ extern cvar_t cl_enemyskin;
extern cvar_t r_fb_models; extern cvar_t r_fb_models;
char allskins[128]; char allskins[128];
#define MAX_CACHED_SKINS 128 #define MAX_CACHED_SKINS 256 //max_clients is 255. hopefully this will not be reached, but hey.
skin_t skins[MAX_CACHED_SKINS]; qwskin_t skins[MAX_CACHED_SKINS];
int numskins; int numskins;
//returns the name //returns the name
@ -108,6 +108,37 @@ char *Skin_FindName (player_info_t *sc)
return name; 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 Skin_Find
@ -119,52 +150,35 @@ Skin_Find
*/ */
void Skin_Find (player_info_t *sc) void Skin_Find (player_info_t *sc)
{ {
skin_t *skin; qwskin_t *skin;
int i; int i;
char name[128], *s; char name[128], *s;
model_t *model;
if (allskins[0]) if (allskins[0])
s = allskins; s = allskins;
else else
s = Info_ValueForKey (sc->userinfo, "skin"); s = Info_ValueForKey (sc->userinfo, "skin");
sc->model = NULL;
sc->skinid = 0;
sc->qwskin = NULL;
if (!*s) if (!*s)
s = baseskin.string; s = baseskin.string;
if (!*s) if (!*s)
s = "default"; return;
// s = "default";
s = Skin_FindName(sc); s = Skin_FindName(sc);
COM_StripExtension (s, name, sizeof(name)); 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++) for (i=0 ; i<numskins ; i++)
{ {
if (!strcmp (name, skins[i].name)) if (!strcmp (name, skins[i].name))
{ {
sc->skin = &skins[i]; sc->qwskin = &skins[i];
if (cls.protocol == CP_QUAKE2) Skin_Cache8 (sc->qwskin);
Skin_Cache32 (sc->skin);
else
Skin_Cache8 (sc->skin);
return; return;
} }
} }
@ -176,7 +190,7 @@ void Skin_Find (player_info_t *sc)
} }
skin = &skins[numskins]; skin = &skins[numskins];
sc->skin = skin; sc->qwskin = skin;
numskins++; numskins++;
memset (skin, 0, sizeof(*skin)); memset (skin, 0, sizeof(*skin));
@ -191,7 +205,7 @@ Skin_Cache
Returns a pointer to the skin bitmap, or NULL to use the default 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]; char name[1024];
qbyte *raw; qbyte *raw;
@ -251,11 +265,6 @@ qbyte *Skin_Cache8 (skin_t *skin)
return out; 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. //favour 24bit+recoloured skins if gl_load24bit is enabled.
@ -431,106 +440,6 @@ qbyte *Skin_Cache8 (skin_t *skin)
return out; 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 Skin_NextDownload
@ -542,62 +451,61 @@ void Skin_NextDownload (void)
int i; int i;
//Con_Printf ("Checking skins...\n"); //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++) for (i = 0; i != MAX_CLIENTS; i++)
{ {
sc = &cl.players[i]; sc = &cl.players[i];
if (!sc->name[0]) if (!sc->name[0])
continue; continue;
Skin_Find (sc); Skin_Find (sc);
if (noskins.ival) if (noskins.ival || !sc->qwskin)
continue; continue;
if (strchr(sc->qwskin->name, ' ')) //skip over skins using a space
if (strchr(sc->skin->name, ' ')) //skip over skins using a space
continue; continue;
if (!*sc->qwskin->name)
if (!*sc->skin->name)
continue; continue;
CL_CheckOrEnqueDownloadFile(va("skins/%s.pcx", sc->qwskin->name), NULL, 0);
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);
} }
// now load them in for real // now load them in for real
for (i=0 ; i<MAX_CLIENTS ; i++) for (i=0 ; i<MAX_CLIENTS ; i++)
{ {
sc = &cl.players[i]; sc = &cl.players[i];
if (!sc->name[0]) if (!sc->name[0] || !sc->qwskin)
continue; continue;
if (cls.protocol == CP_QUAKE2) Skin_Cache8 (sc->qwskin);
Skin_Cache32(sc->skin); //sc->qwskin = NULL;
else
Skin_Cache8 (sc->skin);
#ifdef GLQUAKE
sc->skin = NULL;
#endif
} }
} }
@ -607,7 +515,7 @@ void Skin_FlushPlayers(void)
{ //wipe the skin info { //wipe the skin info
int i; int i;
for (i = 0; i < cl.allocated_client_slots; 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++) for (i = 0; i < cl.allocated_client_slots; i++)
CL_NewTranslation(i); CL_NewTranslation(i);
@ -643,7 +551,7 @@ void Skin_Skins_f (void)
return; return;
} }
GL_GAliasFlushSkinCache(); R_GAliasFlushSkinCache(false);
for (i=0 ; i<numskins ; i++) for (i=0 ; i<numskins ; i++)
{ {
if (skins[i].skindata) 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 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; extern cvar_t cl_chasecam;
@ -1295,13 +1299,24 @@ void V_CalcRefdef (playerview_t *pv)
r_refdef.time = cl.servertime; r_refdef.time = cl.servertime;
// smooth out stair step ups
{ {
extern model_t *loadmodel; extern model_t *loadmodel;
loadmodel = cl.worldmodel; 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); DropPunchAngle (pv);
Cam_SelfTrack(pv); Cam_SelfTrack(pv);
oldnuments = cl_numvisedicts;
oldstris = cl_numstris;
CL_LinkViewModel ();
if (cl.intermission) if (cl.intermission)
{ // intermission / finale rendering { // intermission / finale rendering
V_CalcIntermissionRefdef (pv); V_CalcIntermissionRefdef (pv);
@ -1482,10 +1502,6 @@ void V_RenderPlayerViews(playerview_t *pv)
} }
V_ApplyRefdef(); V_ApplyRefdef();
oldnuments = cl_numvisedicts;
oldstris = cl_numstris;
CL_LinkViewModel ();
R_RenderView (); R_RenderView ();
R2D_PolyBlend (); R2D_PolyBlend ();
R_DrawNameTags(); R_DrawNameTags();
@ -1758,4 +1774,8 @@ void V_Init (void)
Cvar_Register (&v_gamma, VIEWVARS); Cvar_Register (&v_gamma, VIEWVARS);
Cvar_Register (&v_contrast, VIEWVARS); Cvar_Register (&v_contrast, VIEWVARS);
Cvar_Register (&v_brightness, 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 #endif
#ifdef QUAKETC #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 Q2CLIENT //not useful
#undef Q2SERVER //not useful #undef Q2SERVER //not useful
#undef Q3CLIENT //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) static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
{ {
if (!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; return &pf_peristanthashtab;
}
idx -= 1; idx -= 1;
if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst) if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst)
return &pf_hashtab[idx]; 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)); pf_hashtab_t *tab = PF_hash_findtab(prinst, G_FLOAT(OFS_PARM0));
const char *name = PR_GetStringOfs(prinst, OFS_PARM1); 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 type = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):0;
int index = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0; int index = (prinst->callargc>4)?G_FLOAT(OFS_PARM4):0;
pf_hashentry_t *ent = NULL; 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); const char *name = PR_GetStringOfs(prinst, OFS_PARM1);
void *data = G_VECTOR(OFS_PARM2); void *data = G_VECTOR(OFS_PARM2);
int flags = (prinst->callargc>3)?G_FLOAT(OFS_PARM3):0; 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; pf_hashentry_t *ent = NULL;
if (tab) if (tab)
{ {
if (!type) if (!type)
type = tab->defaulttype; type = tab->defaulttype;
if (flags & 1) if (flags & 256)
Hash_Remove(&tab->tab, name); {
ent = Hash_Get(&tab->tab, name);
if (ent)
{
Hash_RemoveData(&tab->tab, name, ent);
BZ_Free(ent);
}
}
if (type == ev_string) if (type == ev_string)
{ //strings copy their value out. { //strings copy their value out.
const char *value = PR_GetStringOfs(prinst, OFS_PARM2); const char *value = PR_GetStringOfs(prinst, OFS_PARM2);
int nlen = strlen(name); int nlen = strlen(name);
int vlen = strlen(data); int vlen = strlen(value);
ent = BZ_Malloc(sizeof(*ent) + nlen+1 + vlen+1); ent = BZ_Malloc(sizeof(*ent) + nlen+1 + vlen+1);
ent->name = (char*)(ent+1); ent->name = (char*)(ent+1);
ent->type = ev_string; 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 prinst->pr_trace++; //continue debugging
PR_ExecuteProgram(prinst, f); PR_ExecuteProgram(prinst, f);
} }
else if (!f) else
{ {
f = PR_FindFunction(prinst, "MissingFunc", progsnum); f = PR_FindFunction(prinst, "MissingFunc", progsnum);
if (!f) 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" 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" PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;SERVERONLY;MULTITHREAD"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="0" RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2" FloatingPointModel="2"
UsePrecompiledHeader="2" UsePrecompiledHeader="2"
PrecompiledHeaderThrough="quakedef.h" PrecompiledHeaderThrough="quakedef.h"
@ -27238,13 +27240,6 @@
<File <File
RelativePath="..\common\net_ssl_winsspi.c" RelativePath="..\common\net_ssl_winsspi.c"
> >
<FileConfiguration
Name="MinGLRelease|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File> </File>
<File <File
RelativePath="..\common\net_wins.c" RelativePath="..\common\net_wins.c"

View file

@ -69,6 +69,17 @@ struct cctx_s
int width; int width;
int height; 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) void Mod_WipeSkin(skinid_t id)
{ {
skinfile_t *sk; skinfile_t *sk;
@ -89,14 +100,22 @@ void Mod_WipeSkin(skinid_t id)
Z_Free(registeredskins[id]); Z_Free(registeredskins[id]);
registeredskins[id] = NULL; registeredskins[id] = NULL;
} }
static void Mod_WipeAllSkins(void) static void Mod_WipeAllSkins(qboolean final)
{ {
skinid_t id; skinid_t id;
if (final)
{
for (id = 0; id < numregisteredskins; ) for (id = 0; id < numregisteredskins; )
Mod_WipeSkin(++id); Mod_WipeSkin(++id);
Z_Free(registeredskins); Z_Free(registeredskins);
registeredskins = NULL; registeredskins = NULL;
numregisteredskins = 0; numregisteredskins = 0;
}
else
{
for (id = 0; id < numregisteredskins; )
Mod_FlushSkin(++id);
}
} }
skinfile_t *Mod_LookupSkin(skinid_t 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. //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 else
{ {
while(*skintext == ' ' || *skintext == '\t') 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; int i;
bucket_t *b; bucket_t *b;
@ -494,14 +521,14 @@ void GL_GAliasFlushSkinCache(void)
numFacing = 0; numFacing = 0;
#endif #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) static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, entity_t *e, texnums_t **forcedtex)
{ {
galiasskin_t *skins; galiasskin_t *skins;
shader_t *shader; shader_t *shader;
skin_t *plskin; qwskin_t *plskin = NULL;
int frame; int frame;
unsigned int subframe; unsigned int subframe;
extern int cl_playerindex; //so I don't have to strcmp 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; return sk->mappings[i].shader;
} }
} }
if (!sk->qwskin && *sk->qwskinname)
sk->qwskin = Skin_Lookup(sk->qwskinname);
plskin = sk->qwskin;
} }
} }
@ -551,15 +581,24 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
forced = false; forced = false;
if (!gl_nocolors.ival || forced) if (!gl_nocolors.ival || forced)
{
if (!plskin || plskin->failedload)
{ {
if (e->playerindex >= 0 && e->playerindex <= MAX_CLIENTS) if (e->playerindex >= 0 && e->playerindex <= MAX_CLIENTS)
{ {
if (!cl.players[e->playerindex].skin) //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]); Skin_Find(&cl.players[e->playerindex]);
plskin = cl.players[e->playerindex].skin; plskin = cl.players[e->playerindex].qwskin;
} }
else else
plskin = NULL; plskin = NULL;
}
else
plskin = NULL;
}
tc = e->topcolour; tc = e->topcolour;
bc = e->bottomcolour; bc = e->bottomcolour;
pc = e->h2playerclass; pc = e->h2playerclass;
@ -666,19 +705,6 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
shader = R_RegisterSkin(skinname, NULL); shader = R_RegisterSkin(skinname, NULL);
if (plskin) if (plskin)
{
if (cls.protocol == CP_QUAKE2)
{
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); original = Skin_Cache8(plskin);
if (original) if (original)
@ -688,7 +714,6 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
cm->texnum.base = R_LoadTexture8(plskin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1); cm->texnum.base = R_LoadTexture8(plskin->name, inwidth, inheight, original, IF_NOALPHA|IF_NOGAMMA, 1);
return shader; return shader;
} }
}
if (TEXVALID(plskin->textures.base)) 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 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)*/ /*q1 only reskins the player model, not gibbed heads (which have the same colourmap)*/
original = Skin_Cache8(plskin); original = Skin_Cache8(plskin);

View file

@ -543,7 +543,7 @@ void GLDraw_DeInit (void)
R2D_Shutdown(); R2D_Shutdown();
GL_GAliasFlushSkinCache(); R_GAliasFlushSkinCache(true);
draw_disc = NULL; draw_disc = NULL;
GL_ShutdownPostProcessing(); 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_shadow_bumpscale_basetexture;
extern cvar_t r_replacemodels; extern cvar_t r_replacemodels;
extern cvar_t gl_lightmap_average; 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 #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 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); 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); Cmd_AddCommand("mod_usetexture", Mod_BlockTextureColour_f);
#endif #endif
} }
else
Cvar_Register(&mod_external_vis, "Graphical Nicaties");
if (initial) if (initial)
{ {
@ -2065,15 +2067,20 @@ void Mod_LoadLighting (lump_t *l)
Mod_LoadVisibility 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; loadmodel->visdata = NULL;
return; return;
} }
loadmodel->visdata = ZG_Malloc(&loadmodel->memgroup, l->filelen); loadmodel->visdata = ZG_Malloc(&loadmodel->memgroup, len);
memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen); memcpy (loadmodel->visdata, ptr, len);
} }
@ -3321,21 +3328,27 @@ qboolean Mod_LoadNodes (lump_t *l, int lm)
Mod_LoadLeafs 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; mleaf_t *out;
int i, j, count, p; int i, j, count, p;
if (!ptr)
{
ptr = mod_base + l->fileofs;
len = l->filelen;
}
if (lm==2) if (lm==2)
{ {
dl2leaf_t *in; dl2leaf_t *in;
in = (void *)(mod_base + l->fileofs); in = (void *)ptr;
if (l->filelen % sizeof(*in)) if (len % sizeof(*in))
{ {
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name); Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false; return false;
} }
count = l->filelen / sizeof(*in); count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS) if (count > MAX_MAP_LEAFS)
{ {
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, 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) else if (lm)
{ {
dl1leaf_t *in; dl1leaf_t *in;
in = (void *)(mod_base + l->fileofs); in = (void *)(ptr);
if (l->filelen % sizeof(*in)) if (len % sizeof(*in))
{ {
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name); Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false; return false;
} }
count = l->filelen / sizeof(*in); count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS) if (count > MAX_MAP_LEAFS)
{ {
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, 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 else
{ {
dsleaf_t *in; dsleaf_t *in;
in = (void *)(mod_base + l->fileofs); in = (void *)(ptr);
if (l->filelen % sizeof(*in)) if (len % sizeof(*in))
{ {
Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name); Con_Printf (CON_ERROR "MOD_LoadBmodel: funny lump size in %s\n",loadmodel->name);
return false; return false;
} }
count = l->filelen / sizeof(*in); count = len / sizeof(*in);
if (count > MAX_MAP_LEAFS) if (count > MAX_MAP_LEAFS)
{ {
Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, 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 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 Mod_LoadBrushModel
@ -4202,6 +4288,7 @@ Mod_LoadBrushModel
*/ */
qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize) qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
{ {
struct vispatch_s vispatch;
int i, j; int i, j;
dheader_t *header; dheader_t *header;
mmodel_t *bm; mmodel_t *bm;
@ -4306,6 +4393,8 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
crouchhullfile = NULL; crouchhullfile = NULL;
Mod_FindVisPatch(&vispatch, loadmodel, header->lumps[LUMP_LEAFS].filelen);
TRACE(("Loading info\n")); TRACE(("Loading info\n"));
#ifndef SERVERONLY #ifndef SERVERONLY
if (!isnotmap) if (!isnotmap)
@ -4354,9 +4443,9 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
if (noerrors) if (noerrors)
{ {
TRACE(("Loading Vis\n")); 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")); TRACE(("Loading Nodes\n"));
noerrors = noerrors && Mod_LoadNodes (&header->lumps[LUMP_NODES], longm); noerrors = noerrors && Mod_LoadNodes (&header->lumps[LUMP_NODES], longm);
TRACE(("Loading Clipnodes\n")); TRACE(("Loading Clipnodes\n"));
@ -4379,6 +4468,8 @@ qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsize)
crouchhullfile=NULL; crouchhullfile=NULL;
} }
BZ_Free(vispatch.fileptr);
if (!noerrors) if (!noerrors)
{ {
return false; return false;

View file

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

View file

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

View file

@ -814,12 +814,190 @@ qboolean HTTPDL_Poll(struct dl_download *dl)
return true; 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) qboolean DL_Decide(struct dl_download *dl)
{ {
const char *url = dl->redir; const char *url = dl->redir;
if (!*url) if (!*url)
url = dl->url; url = dl->url;
/*if (!strnicmp(url, "data:", 5))
dl->poll = DataScheme_Decode;
else*/
if (!strnicmp(url, "http://", 7)) if (!strnicmp(url, "http://", 7))
dl->poll = HTTPDL_Poll; dl->poll = HTTPDL_Poll;
else 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 *DL_Create(const char *url)
{ {
struct dl_download *newdl; struct dl_download *newdl;
newdl = malloc(sizeof(*newdl)); newdl = malloc(sizeof(*newdl) + strlen(url)+1);
if (!newdl) if (!newdl)
return NULL; return NULL;
memset(newdl, 0, sizeof(*newdl)); 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; newdl->poll = DL_Decide;
if (!newdl->poll(newdl)) if (!newdl->poll(newdl))
@ -995,10 +1174,10 @@ void HTTP_CL_Think(void)
cls.download = &dl->qdownload; cls.download = &dl->qdownload;
dl->qdownload.method = DL_HTTP; dl->qdownload.method = DL_HTTP;
if (*dl->localname) if (*dl->localname)
strcpy(dl->qdownload.localname, dl->localname); Q_strncpyz(dl->qdownload.localname, dl->localname, sizeof(dl->qdownload.localname));
else else
strcpy(dl->qdownload.localname, dl->url); Q_strncpyz(dl->qdownload.localname, dl->url, sizeof(dl->qdownload.localname));
strcpy(dl->qdownload.remotename, dl->url); Q_strncpyz(dl->qdownload.remotename, dl->url, sizeof(dl->qdownload.remotename));
dl->qdownload.starttime = Sys_DoubleTime(); dl->qdownload.starttime = Sys_DoubleTime();
} }

View file

@ -189,6 +189,7 @@ void HTTP_ServerShutdown(void)
typedef struct HTTP_active_connections_s { typedef struct HTTP_active_connections_s {
SOCKET datasock; SOCKET datasock;
char peername[256];
vfsfile_t *file; vfsfile_t *file;
struct HTTP_active_connections_s *next; struct HTTP_active_connections_s *next;
@ -242,6 +243,7 @@ void HTTP_RunExisting (void)
char *msg, *nl; char *msg, *nl;
char buf2[2560]; //short lived temp buffer. char buf2[2560]; //short lived temp buffer.
char resource[2560]; char resource[2560];
char host[256];
char mode[80]; char mode[80];
qboolean hostspecified; qboolean hostspecified;
unsigned int contentlen; unsigned int contentlen;
@ -260,7 +262,7 @@ void HTTP_RunExisting (void)
if (cl->closereason) if (cl->closereason)
{ {
IWebPrintf("Closing connection: %s\n", cl->closereason); IWebPrintf("%s: Closing connection: %s\n", cl->peername, cl->closereason);
*link = cl->next; *link = cl->next;
closesocket(cl->datasock); closesocket(cl->datasock);
@ -342,6 +344,9 @@ cont:
continue; continue;
} }
host[0] = '?';
host[1] = 0;
hostspecified = false; hostspecified = false;
if (!strnicmp(resource, "http://", 7)) if (!strnicmp(resource, "http://", 7))
{ //groan... 1.1 compliance requires parsing this correctly, without the client ever specifiying it. { //groan... 1.1 compliance requires parsing this correctly, without the client ever specifiying it.
@ -351,8 +356,15 @@ cont:
if (!slash) if (!slash)
strcpy(resource, "/"); strcpy(resource, "/");
else 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. memmove(resource, slash, strlen(slash+1)); //just get rid of the http:// stuff.
} }
}
if (!strcmp(resource, "/")) if (!strcmp(resource, "/"))
strcpy(resource, "/index.html"); strcpy(resource, "/index.html");
@ -397,7 +409,16 @@ cont:
msg++; msg++;
if (!strnicmp(msg, "Host: ", 6)) //parse needed header fields 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; hostspecified = true;
}
else if (!strnicmp(msg, "Content-Length: ", 16)) //parse needed header fields else if (!strnicmp(msg, "Content-Length: ", 16)) //parse needed header fields
contentlen = strtoul(msg+16, NULL, 0); contentlen = strtoul(msg+16, NULL, 0);
else if (!strnicmp(msg, "Accept-Encoding:", 16)) //parse needed header fields else if (!strnicmp(msg, "Accept-Encoding:", 16)) //parse needed header fields
@ -491,7 +512,7 @@ cont:
resource[0] = '/'; resource[0] = '/';
resource[1] = 0; //I'm lazy, they need to comply 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. 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); cl->file = IWebGenerateFile(resource+1, content, contentlen);
@ -519,7 +540,7 @@ cont:
} }
if (!cl->file) if (!cl->file)
{ {
IWebPrintf("Download rejected\n"); IWebPrintf("%s: Download rejected\n", cl->peername);
if (HTTPmarkup >= 3) 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"; 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); VFS_CLOSE(cl->file);
cl->file = NULL; cl->file = NULL;
IWebPrintf("Download complete\n"); IWebPrintf("%s: Download complete\n", cl->peername);
} }
else else
cl->outbufferused+=ammount; 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 qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while true
{ {
struct sockaddr_qstorage from; struct sockaddr_qstorage from;
int fromlen; int fromlen;
int clientsock; int clientsock;
int _true = true; int _true = true;
char buf[128];
netadr_t na;
HTTP_active_connections_t *cl; 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; return false;
} }
@ -723,15 +754,19 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr
return false; 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)); 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->datasock = clientsock;
cl->next = HTTP_ServerConnections; cl->next = HTTP_ServerConnections;

View file

@ -106,7 +106,7 @@ struct dl_download
qdownload_t qdownload; qdownload_t qdownload;
/*stream config*/ /*stream config*/
char url[MAX_OSPATH]; /*original url*/ char *url; /*original url*/
char redir[MAX_OSPATH]; /*current redirected url*/ char redir[MAX_OSPATH]; /*current redirected url*/
char localname[MAX_OSPATH]; /*leave empty for a temp file*/ 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*/ 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; return true;
} }
char com_token[1024]; char com_token[sizeof(com_token)];
com_tokentype_t com_tokentype; com_tokentype_t com_tokentype;
int com_argc; int com_argc;
const char **com_argv; 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; HANDLE r;
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;

View file

@ -1017,6 +1017,7 @@ void PR_Decompile_f(void)
} }
void PR_Compile_f(void) void PR_Compile_f(void)
{ {
qboolean killondone = false;
int argc=3; int argc=3;
double time = Sys_DoubleTime(); double time = Sys_DoubleTime();
char *argv[64] = {"", "-src", pr_sourcedir.string, "-srcfile", "progs.src"}; char *argv[64] = {"", "-src", pr_sourcedir.string, "-srcfile", "progs.src"};
@ -1054,10 +1055,16 @@ void PR_Compile_f(void)
} }
if (!svprogfuncs) if (!svprogfuncs)
{
Q_SetProgsParms(true); Q_SetProgsParms(true);
killondone = true;
}
if (PR_StartCompile(svprogfuncs, argc, argv)) if (PR_StartCompile(svprogfuncs, argc, argv))
while(PR_ContinueCompile(svprogfuncs)); while(PR_ContinueCompile(svprogfuncs));
if (killondone)
PR_Deinit();
time = Sys_DoubleTime() - time; time = Sys_DoubleTime() - time;
Con_TPrintf("Compile took %f secs\n", 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 *dest = PR_GetStringOfs(prinst, OFS_PARM0);
const char *src = PR_GetStringOfs(prinst, OFS_PARM1); const char *src = PR_GetStringOfs(prinst, OFS_PARM1);
const char *cmd = PR_GetStringOfs(prinst, OFS_PARM2); 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); SSV_Send(dest, src, cmd, info);
#endif #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)"}, {"bound", PF_Fixme, 0, 0, 0, 45, "float(float min,float value,float max)"},
{"pow", PF_Fixme, 0, 0, 0, 46, "float(float,float)"}, {"pow", PF_Fixme, 0, 0, 0, 46, "float(float,float)"},
{"copyentity", PF_Fixme, 0, 0, 0, 47, "void(entity src, entity dst)"}, {"copyentity", PF_Fixme, 0, 0, 0, 47, "void(entity src, entity dst)"},
{"fopen", PF_Fixme, 0, 0, 0, 48, "float(string filename, float mode)"}, {"fopen", PF_Fixme, 0, 0, 0, 48, "filestream(string filename, float mode)"},
{"fclose", PF_Fixme, 0, 0, 0, 49, "void(float fhandle)"}, {"fclose", PF_Fixme, 0, 0, 0, 49, "void(filestream fhandle)"},
{"fgets", PF_Fixme, 0, 0, 0, 50, "string(float fhandle)"}, {"fgets", PF_Fixme, 0, 0, 0, 50, "string(filestream fhandle)"},
{"fputs", PF_Fixme, 0, 0, 0, 51, "void(float fhandle, string s)"}, {"fputs", PF_Fixme, 0, 0, 0, 51, "void(filestream fhandle, string s)"},
{"strlen", PF_Fixme, 0, 0, 0, 52, "float(string)"}, {"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)"}, {"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)"}, {"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)"}, {"cvar_string", PF_Fixme, 0, 0, 0, 71, "string(string name)"},
{"crash", PF_Fixme, 0, 0, 0, 72, "void()"}, {"crash", PF_Fixme, 0, 0, 0, 72, "void()"},
{"stackdump", PF_Fixme, 0, 0, 0, 73, "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_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, float caseinsensitive, float quiet)"},
{"search_end", PF_Fixme, 0, 0, 0, 75, "void(float handle)"}, {"search_end", PF_Fixme, 0, 0, 0, 75, "void(searchhandle handle)"},
{"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(float handle)"}, {"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(searchhandle handle)"},
{"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(float handle, float num)"}, {"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(searchhandle handle, float num)"},
{"etof", PF_Fixme, 0, 0, 0, 79, "float(entity)"}, {"etof", PF_Fixme, 0, 0, 0, 79, "float(entity)"},
{"ftoe", PF_Fixme, 0, 0, 0, 80, "entity(float)"}, {"ftoe", PF_Fixme, 0, 0, 0, 80, "entity(float)"},
{"validstring", PF_Fixme, 0, 0, 0, 81, "float(string)"}, {"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 String Manipulation End
// Tomaz - QuakeC File System Begin (new mods use frik_file instead) // 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_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(float fhandle)",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(float 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(float fhandle, string s)",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 // Tomaz - QuakeC File System End
{"rain_go", PF_h2rain_go, 0, 0, 80, 0}, //80 {"rain_go", PF_h2rain_go, 0, 0, 80, 0}, //80
@ -9260,10 +9267,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//End TEU_SHOWLMP2 //End TEU_SHOWLMP2
//frik file //frik file
{"fopen", PF_fopen, 0, 0, 0, 110, "float(string filename, float mode, optional float mmapminsize)"}, // (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(float fhandle)"}, // (FRIK_FILE) {"fclose", PF_fclose, 0, 0, 0, 111, "void(filestream fhandle)"}, // (FRIK_FILE)
{"fgets", PF_fgets, 0, 0, 0, 112, "string(float fhandle)"}, // (FRIK_FILE) {"fgets", PF_fgets, 0, 0, 0, 112, "string(filestream 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) {"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) {"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) {"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) {"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.")}, {"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.")}, {"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}, {"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) #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.")}, {"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 #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.")}, {"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.")}, {"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 {"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.")}, {"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(string info, string key)", "Reads a named value from an infostring. The returned value is a tempstring")}, {"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.")}, // {"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.")}, {"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.")}, {"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)"}, {"frametoname", PF_frametoname, 0, 0, 0, 284, "string(float modidx, float framenum)"},
{"skintoname", PF_skintoname, 0, 0, 0, 285, "string(float modidx, float skin)"}, {"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)"}, // {"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_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(float table)", "Destroys a hash table object.")}, {"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(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_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(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_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(float table, string name)", "removes the named key. returns the value of the object that was destroyed, or 0 on error.")}, {"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(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_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(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_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.")}, {"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.")}, {"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:'.")}, {"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 #ifndef SERVERONLY
//begin menu-only //begin menu-only
{"buf_create", PF_Fixme, 0, 0, 0, 440, "float()"},//DP_QC_STRINGBUFFERS {"buf_create", PF_Fixme, 0, 0, 0, 440, "strbuf()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_Fixme, 0, 0, 0, 441, "void(float bufhandle)"},//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(float 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(float bufhandle_from, float bufhandle_to)"},//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(float bufhandle, float sortprefixlen, float backward)"},//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(float bufhandle, string glue)"},//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(float bufhandle, float string_index)"},//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(float bufhandle, float string_index, string str)"},//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(float bufhandle, string str, float order)"},//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(float bufhandle, float string_index)"},//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) {"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) {"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) {"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) {"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 {"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) {"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_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(float handle)"}, {"search_end", PF_search_end, 0, 0, 0, 445, "void(searchhandle handle)"},
{"search_getsize", PF_search_getsize, 0, 0, 0, 446, D("float(float handle)", "Retrieves the number of files that were found.")}, {"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(float handle, float num)", "Retrieves name of one of the files that was found by the initial search.")}, {"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 {"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 {"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 {"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 // {"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, ""}, // {"undefined", PF_Fixme, 0, 0, 0, 458, ""},
{"edict_num", PF_edict_for_num, 0, 0, 0, 459, "entity(float entnum)"},//DP_QC_EDICT_NUM {"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_create", PF_buf_create, 0, 0, 0, 460, "strbuf()"},//DP_QC_STRINGBUFFERS
{"buf_del", PF_buf_del, 0, 0, 0, 461, "void(float bufhandle)"},//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(float 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(float bufhandle_from, float bufhandle_to)"},//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(float bufhandle, float sortprefixlen, float backward)"},//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(float bufhandle, string glue)"},//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(float bufhandle, float string_index)"},//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(float bufhandle, float string_index, string str)"},//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(float bufhandle, string str, float order)"},//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(float bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS {"bufstr_free", PF_bufstr_free, 0, 0, 0, 469, "void(strbuf bufhandle, float string_index)"},//DP_QC_STRINGBUFFERS
//end non-menu //end non-menu
// {"undefined", PF_Fixme, 0, 0, 0, 470, ""}, // {"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)"}, {"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_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)"}, {"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)"}, {"cvar_description",PF_cvar_description,0, 0, 0, 518, "string(string cvarname)"},
{"gettime", PF_gettime, 0, 0, 0, 519, "float(optional float timetype)"}, {"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. {"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}, // {"log", PF_Fixme, 0, 0, 0, 532, "float(string mname)", true},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, "float(entity e, float channel)"}, {"getsoundtime", PF_Ignore, 0, 0, 0, 533, "float(entity e, float channel)"},
{"soundlength", PF_Ignore, 0, 0, 0, 534, "float(string sample)"}, {"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_loadfile", PF_buf_loadfile, 0, 0, 0, 535, "float(string filename, strbuf bufhandle)"},
{"buf_writefile", PF_buf_writefile, 0, 0, 0, 536, "float(float filehandle, float bufhandle, optional float startpos, optional float numstrings)"}, {"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)"}, // {"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)"}, // {"matchpattern", PF_Fixme, 0, 0, 0, 538, "float(string s, string pattern, float matchrule)"},
// {"undefined", PF_Fixme, 0, 0, 0, 539, ""}, // {"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)"}, {"setmousetarget", PF_Fixme, 0, 0, 0, 603, "void(float trg)"},
{"getmousetarget", PF_Fixme, 0, 0, 0, 604, "float()"}, {"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")}, {"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)"}, {"isfunction", PF_isfunction, 0, 0, 0, 607, "float(string s)"},
{"getresolution", PF_Fixme, 0, 0, 0, 608, "vector(float vidmode, optional float forfullscreen)"}, {"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. {"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]; char dbgfname[MAX_OSPATH];
unsigned int targ = 0; unsigned int targ = 0;
qboolean defines = false; qboolean defines = false;
qboolean accessors = false;
char *comment; char *comment;
/*this list is here to ensure that the file can be used as a valid initial qc file (ignoring precompiler options)*/ /*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}, {"TRUE", "const float", ALL, NULL, 1},
{"FALSE", "const float", ALL, "File not found...", 0}, {"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_NONE", "const float", QW|NQ|CS, NULL, MOVETYPE_NONE},
{"MOVETYPE_WALK", "const float", QW|NQ|CS, NULL, MOVETYPE_WALK}, {"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_VECTOR", "const float", QW|NQ, NULL, ev_vector},
{"EV_ENTITY", "const float", QW|NQ, NULL, ev_entity}, {"EV_ENTITY", "const float", QW|NQ, NULL, ev_entity},
// {"EV_FIELD", "const float", QW|NQ, NULL, ev_field}, // {"EV_FIELD", "const float", QW|NQ, NULL, ev_field},
// {"EV_FUNCTION", "const float", QW|NQ, NULL, ev_function}, {"EV_FUNCTION", "const float", QW|NQ, NULL, ev_function},
// {"EV_POINTER", "const float", QW|NQ, NULL, ev_pointer}, {"EV_POINTER", "const float", QW|NQ, NULL, ev_pointer},
{"EV_INTEGER", "const float", QW|NQ, NULL, ev_integer}, {"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_STRUCT", "const float", QW|NQ, NULL, ev_struct},
// {"EV_UNION", "const float", QW|NQ, NULL, ev_union}, // {"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}, {"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.", 1}, {"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},
{"HASH_STRING", "const float", ALL, "Used with hash_add. Specifies that the contents of the string argument should be internally zoned.", 2},
{"STAT_HEALTH", "const float", CS, NULL, STAT_HEALTH}, {"STAT_HEALTH", "const float", CS, NULL, STAT_HEALTH},
{"STAT_WEAPON", "const float", CS, NULL, STAT_WEAPON}, {"STAT_WEAPON", "const float", CS, NULL, STAT_WEAPON},
@ -10779,6 +10786,10 @@ void PR_DumpPlatform_f(void)
defines = true; defines = true;
if (!stricmp(Cmd_Argv(i), "-Fnodefines")) if (!stricmp(Cmd_Argv(i), "-Fnodefines"))
defines = false; defines = false;
if (!stricmp(Cmd_Argv(i), "-Faccessors"))
accessors = true;
if (!stricmp(Cmd_Argv(i), "-Fnoaccessors"))
accessors = false;
if (!stricmp(Cmd_Argv(i), "-O")) if (!stricmp(Cmd_Argv(i), "-O"))
fname = Cmd_Argv(++i); fname = Cmd_Argv(++i);
} }
@ -10808,6 +10819,7 @@ void PR_DumpPlatform_f(void)
"-Tcs - dump specifically CSQC fields\n" "-Tcs - dump specifically CSQC fields\n"
"-Tmenu - dump specifically menuqc fields\n" "-Tmenu - dump specifically menuqc fields\n"
"-Fdefines - generate #defines instead of constants\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" "-O - write to a different qc file\n"
"*/\n" "*/\n"
, FULLENGINENAME, FTE_VER_MAJOR, FTE_VER_MINOR, Cmd_Argv(0), Cmd_Args()); , FULLENGINENAME, FTE_VER_MAJOR, FTE_VER_MINOR, Cmd_Argv(0), Cmd_Args());
@ -10877,6 +10889,25 @@ void PR_DumpPlatform_f(void)
"#endif\n" "#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 (i = 0; knowndefs[i].name; i++)
{ {
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
@ -10962,12 +10993,22 @@ void PR_DumpPlatform_f(void)
else else
comment = ""; comment = "";
if (!strcmp(knowndefs[i].type, "const float")) if (!strcmp(knowndefs[i].type, "const float"))
{
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
{ {
if (defines) if (defines)
VFS_PRINTF(f, "#define %s %g%s\n", knowndefs[i].name, knowndefs[i].value, comment); VFS_PRINTF(f, "#define %s %g%s\n", knowndefs[i].name, knowndefs[i].value, comment);
else else
VFS_PRINTF(f, "%s %s = %g;%s\n", knowndefs[i].type, knowndefs[i].name, knowndefs[i].value, comment); 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")) else if (!strcmp(knowndefs[i].type, "const string"))
{ {
if (defines) if (defines)
@ -11198,6 +11239,42 @@ void PR_DumpPlatform_f(void)
VFS_PRINTF(f, "#endif\n"); 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"); 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_PrintToMaster(char *s);
void SSV_ReadFromControlServer(void); void SSV_ReadFromControlServer(void);
void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part 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); void Sys_InstructSlave(pubsubserver_t *s, sizebuf_t *cmd);
int Sys_SubServerRead(pubsubserver_t *s); //1: yes. 0: no. -1: error 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 #ifndef SERVERONLY
SCR_SetLoadingStage(LS_NONE); SCR_SetLoadingStage(LS_NONE);
#endif #endif
if (SSV_IsSubServer())
Cbuf_AddText("\nquit\n", RESTRICT_LOCAL);
return; 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); void MSV_UpdatePlayerStats(unsigned int playerid, unsigned int serverid, int numstats, float *stats);
static char *knownmaps[] =
{
"",
"start"
};
typedef struct { typedef struct {
//fixme: hash tables //fixme: hash tables
unsigned int playerid; unsigned int playerid;
@ -93,11 +87,7 @@ pubsubserver_t *MSV_StartSubServer(unsigned int id, const char *mapname)
if (s) if (s)
{ {
if (!id) if (!id)
{ id = ++nextserverid;
if (nextserverid < sizeof(knownmaps)/sizeof(knownmaps[0]))
nextserverid = sizeof(knownmaps)/sizeof(knownmaps[0]);
id = nextserverid++;
}
s->id = id; s->id = id;
s->next = subservers; s->next = subservers;
subservers = s; subservers = s;
@ -125,33 +115,54 @@ pubsubserver_t *MSV_FindSubServer(unsigned int id)
return s; return s;
} }
if (!s && id >= 1 && id < sizeof(knownmaps)/sizeof(knownmaps[0])) return NULL;
s = MSV_StartSubServer(id, knownmaps[id]);
return s;
} }
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; pubsubserver_t *s;
unsigned int to; unsigned int id;
for (to = 1; to < sizeof(knownmaps)/sizeof(knownmaps[0]); to++) qboolean forcenew = false;
char *mapname;
id = strtoul(servername, &mapname, 0);
if (*mapname == ':')
{ {
if (!strcmp(knownmaps[to], mapname)) if (!id && servername != mapname)
return MSV_FindSubServer(to); forcenew = true;
mapname++;
}
else
mapname = "";
if (id)
{
s = MSV_FindSubServer(id);
if (s)
return s;
} }
if (*mapname)
{
if (!forcenew)
{
for (s = subservers; s; s = s->next) for (s = subservers; s; s = s->next)
{ {
if (!strcmp(s->name, mapname)) if (!strcmp(s->name, mapname))
return s; return s;
} }
}
return MSV_StartSubServer(0, mapname); return MSV_StartSubServer(id, mapname);
}
return NULL;
} }
qboolean MSV_AddressForMap(netadr_t *ret, int natype, int serverid) qboolean MSV_AddressForServer(netadr_t *ret, int natype, pubsubserver_t *s)
{ {
pubsubserver_t *s = MSV_FindSubServer(serverid);
if (s) if (s)
{ {
if (natype == s->addrv6.type) if (natype == s->addrv6.type)
@ -458,7 +469,7 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
send.cursize = 2; send.cursize = 2;
NET_StringToAdr(claddr, 0, &cladr); NET_StringToAdr(claddr, 0, &cladr);
MSV_AddressForMap(&svadr, cladr.type, s->id); MSV_AddressForServer(&svadr, cladr.type, s);
if (!to) if (!to)
{ {
if (svadr.type != NA_INVALID) if (svadr.type != NA_INVALID)
@ -525,6 +536,13 @@ void MSV_ReadFromSubServer(pubsubserver_t *s)
for (s = subservers; s; s = s->next) for (s = subservers; s; s = s->next)
Sys_InstructSlave(s, &send); 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 else
{ {
//send it to the server that the player is currently on. //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]; char tmpbuf[256];
netadr_t serveraddr; netadr_t serveraddr;
pubsubserver_t *s = NULL;
if (!serverid) if (!s)
serverid = 1; 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"); SV_RejectMessage(SCP_QUAKEWORLD, "Unable to find lobby.\n");
else else
{ {
pubsubserver_t *s;
sizebuf_t send; sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN]; qbyte send_buf[MAX_QWMSGLEN];
clusterplayer_t *pl; clusterplayer_t *pl;
@ -963,7 +981,7 @@ qboolean MSV_ClusterLoginReply(netadr_t *legacyclientredirect, unsigned int serv
NET_AdrToString(pl->address, sizeof(pl->address), clientaddr); NET_AdrToString(pl->address, sizeof(pl->address), clientaddr);
pl->playerid = playerid; pl->playerid = playerid;
InsertLinkBefore(&pl->allplayers, &clusterplayers); InsertLinkBefore(&pl->allplayers, &clusterplayers);
pl->server = s = MSV_FindSubServer(serverid); pl->server = s;
MSG_WriteByte(&send, ccmd_takeplayer); MSG_WriteByte(&send, ccmd_takeplayer);
MSG_WriteLong(&send, playerid); MSG_WriteLong(&send, playerid);

View file

@ -3764,41 +3764,42 @@ void SV_SetInfo_f (void)
return; return;
} }
if (Cmd_Argv(1)[0] == '*') key = Cmd_Argv(1);
if (key[0] == '*')
return; // don't set priveledged values 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 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 #ifdef VM_Q1
if (Q1QVM_UserInfoChanged(sv_player)) if (Q1QVM_UserInfoChanged(sv_player))
return; return;
#endif #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 // name is extracted below in ExtractFromUserInfo
// strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name") // strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
// , sizeof(host_client->name)-1); // , sizeof(host_client->name)-1);
// SV_FullClientUpdate (host_client, &sv.reliable_datagram); // SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true; // 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 return; // key hasn't changed
// process any changed values // process any changed values
SV_ExtractFromUserinfo (host_client, true); 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 { //team fortress has a nasty habit of booting people without this
sv_player->v->team = atoi(Cmd_Argv(2))+1; sv_player->v->team = atoi(Cmd_Argv(2))+1;
} }
if (*Cmd_Argv(1) != '_') if (*key != '_')
{ {
i = host_client - svs.clients; i = host_client - svs.clients;
key = Cmd_Argv(1);
val = Info_ValueForKey(host_client->userinfo, key); val = Info_ValueForKey(host_client->userinfo, key);
basic = SV_UserInfoIsBasic(key); basic = SV_UserInfoIsBasic(key);
@ -3845,9 +3846,11 @@ void SV_SetInfo_f (void)
} }
} }
//doh't spam chat changes. they're not interesting, and just spammy.
if (strcmp(key, "chat"))
SV_LogPlayer(host_client, "userinfo changed"); 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); return VFSWEB_Close(file);
} }
vfsfile_t *FSWEB_OpenTemp(void) vfsfile_t *FSWEB_OpenTempHandle(int f)
{ {
int f;
vfswebfile_t *file; vfswebfile_t *file;
f = emscriptenfte_buf_create();
if (f == -1) if (f == -1)
{ {
Con_Printf("FSWEB_OpenTemp failed\n"); Con_Printf("FSWEB_OpenTemp failed\n");
@ -102,6 +100,11 @@ vfsfile_t *FSWEB_OpenTemp(void)
return &file->funcs; 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) vfsfile_t *VFSWEB_Open(const char *osname, const char *mode, qboolean *needsflush)
{ {
int f; 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(*Mouse)(int devid,int abs,float x,float y,float z,float size),
void(*Button)(int devid, int down, int mbutton), void(*Button)(int devid, int down, int mbutton),
int(*Keyboard)(int devid, int down, int keycode, int unicode), 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); 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: $FTEC:
{ {
ctxwarned:0, ctxwarned:0,
@ -42,6 +69,20 @@ mergeInto(LibraryManager.library,
key:0 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) handleevent : function(event)
{ {
switch(event.type) switch(event.type)
@ -138,28 +179,49 @@ mergeInto(LibraryManager.library,
} }
event.preventDefault(); event.preventDefault();
break; 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: default:
console.log(event); console.log(event);
break; break;
} }
} }
}, },
emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser'], emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser', 'emscriptenfte_buf_createfromarraybuf'],
emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evh) emscriptenfte_setupcanvas : function(nw,nh,evresz,evm,evb,evk,evf)
{ {
FTEC.evcb.resize = evresz; FTEC.evcb.resize = evresz;
FTEC.evcb.mouse = evm; FTEC.evcb.mouse = evm;
FTEC.evcb.button = evb; FTEC.evcb.button = evb;
FTEC.evcb.key = evk; FTEC.evcb.key = evk;
FTEC.evcb.hashchange = evh; FTEC.evcb.loadfile = evf;
if (!FTEC.donecb) if (!FTEC.donecb)
{ {
FTEC.donecb = 1; 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); Module['canvas'].addEventListener(event, FTEC.handleevent, true);
}); });
['keydown', 'keyup', 'keypress'].forEach(function(event) events.forEach(function(event)
{ {
document.addEventListener(event, FTEC.handleevent, true); document.addEventListener(event, FTEC.handleevent, true);
}); });
@ -202,17 +264,12 @@ mergeInto(LibraryManager.library,
window.onresize(); window.onresize();
if (FTEC.evcb.hashchange) if (FTEC.evcb.hashchange)
{
window.onhashchange = function() window.onhashchange = function()
{ {
if (FTEC.evcb.hashchange != 0) FTEC.loadurl(location.hash.substring(1));
{
var val = location.hash;
var ptr = _malloc(val.length);
writeStringToMemory(val, ptr);
Runtime.dynCall('vi', FTEC.evcb.hashchange, [ptr]);
_free(ptr);
}
}; };
}
return 1; return 1;
}, },
@ -228,23 +285,6 @@ mergeInto(LibraryManager.library,
return Date.now(); 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__deps : ['emscriptenfte_handle_alloc'],
emscriptenfte_buf_create : function() emscriptenfte_buf_create : function()
{ {
@ -481,7 +521,7 @@ mergeInto(LibraryManager.library,
http.onload = function(e) http.onload = function(e)
{ {
// console.log("onload: " + _url + " status " + http.status); console.log("onload: " + _url + " status " + http.status);
if (http.status == 200) if (http.status == 200)
{ {
var bar = new Uint8Array(http.response); var bar = new Uint8Array(http.response);
@ -499,7 +539,7 @@ mergeInto(LibraryManager.library,
http.onerror = function(e) http.onerror = function(e)
{ {
// console.log("onerror: " + _url + " status " + http.status); console.log("onerror: " + _url + " status " + http.status);
if (onerror) if (onerror)
Runtime.dynCall('vii', onerror, [ctx, http.status]); 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); 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. //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) qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
{ {
int flags;
vid_isfullscreen = true; vid_isfullscreen = true;
if (!emscriptenfte_setupcanvas( if (!emscriptenfte_setupcanvas(
@ -169,7 +176,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
IN_MouseMove, IN_MouseMove,
DOM_ButtonEvent, DOM_ButtonEvent,
DOM_KeyEvent, DOM_KeyEvent,
DOM_HashChanged DOM_LoadFile
)) ))
{ {
Con_Printf("Couldn't set up canvas\n"); Con_Printf("Couldn't set up canvas\n");