mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 07:21:58 +00:00
Implement csqc validation, we can start on giving more capabilities now that we can distinguish between modified and unmodified csprogs.
This commit is contained in:
parent
e04c097eb8
commit
929dd85164
13 changed files with 278 additions and 100 deletions
|
@ -108,6 +108,14 @@ CL_ClearState
|
|||
*/
|
||||
void CL_ClearState (void)
|
||||
{
|
||||
if (cl.qcvm.extfuncs.CSQC_Shutdown)
|
||||
{
|
||||
PR_SwitchQCVM(&cl.qcvm);
|
||||
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Shutdown);
|
||||
qcvm->extfuncs.CSQC_Shutdown = 0;
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
|
||||
if (!sv.active)
|
||||
Host_ClearMemory ();
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ typedef struct
|
|||
// information that is static for the entire time connected to a server
|
||||
//
|
||||
struct qmodel_s *model_precache[MAX_MODELS];
|
||||
struct qmodel_s *model_precache_csqc[MAX_MODELS];
|
||||
struct sfx_s *sound_precache[MAX_SOUNDS];
|
||||
|
||||
char mapname[128];
|
||||
|
@ -291,6 +292,7 @@ typedef struct
|
|||
int model_count;
|
||||
int model_download;
|
||||
char model_name[MAX_MODELS][MAX_QPATH];
|
||||
char model_name_csqc[MAX_MODELS][MAX_QPATH]; //negative indexes in the csqc are csqc ones.
|
||||
int sound_count;
|
||||
int sound_download;
|
||||
char sound_name[MAX_SOUNDS][MAX_QPATH];
|
||||
|
|
|
@ -402,6 +402,7 @@ void R_DrawSpriteModel (entity_t *e);
|
|||
void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain);
|
||||
|
||||
void R_RenderDlights (void);
|
||||
void GL_BuildModel (qmodel_t *m);
|
||||
void GL_BuildLightmaps (void);
|
||||
void GL_DeleteBModelVertexBuffer (void);
|
||||
void GL_BuildBModelVertexBuffer (void);
|
||||
|
|
153
Quake/host.c
153
Quake/host.c
|
@ -489,7 +489,7 @@ void SV_DropClient (qboolean crash)
|
|||
{
|
||||
if (!client->knowntoqc)
|
||||
continue;
|
||||
if (host_client->protocol_pext2 & PEXT2_REPLACEMENTDELTAS)
|
||||
if ((host_client->protocol_pext1 & PEXT1_CSQC) || (host_client->protocol_pext2 & PEXT2_REPLACEMENTDELTAS))
|
||||
{
|
||||
MSG_WriteByte (&client->message, svc_stufftext);
|
||||
MSG_WriteString (&client->message, va("//fui %u \"\"\n", (unsigned)(host_client - svs.clients)));
|
||||
|
@ -594,6 +594,14 @@ not reinitialize anything.
|
|||
*/
|
||||
void Host_ClearMemory (void)
|
||||
{
|
||||
if (cl.qcvm.extfuncs.CSQC_Shutdown)
|
||||
{
|
||||
PR_SwitchQCVM(&cl.qcvm);
|
||||
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Shutdown);
|
||||
qcvm->extfuncs.CSQC_Shutdown = 0;
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
|
||||
Con_DPrintf ("Clearing memory\n");
|
||||
D_FlushCaches ();
|
||||
Mod_ClearAll ();
|
||||
|
@ -727,6 +735,104 @@ qmodel_t *CL_ModelForIndex(int index)
|
|||
return cl.model_precache[index];
|
||||
}
|
||||
|
||||
|
||||
static void CL_LoadCSProgs(void)
|
||||
{
|
||||
qboolean fullcsqc = false;
|
||||
PR_ClearProgs(&cl.qcvm);
|
||||
if (pr_checkextension.value && !cl_nocsqc.value)
|
||||
{ //only try to use csqc if qc extensions are enabled.
|
||||
char versionedname[MAX_QPATH];
|
||||
unsigned int csqchash;
|
||||
size_t csqcsize;
|
||||
PR_SwitchQCVM(&cl.qcvm);
|
||||
csqchash = strtoul(Info_GetKey(cl.serverinfo, "*csprogs", versionedname, sizeof(versionedname)), NULL, 0);
|
||||
csqcsize = strtoul(Info_GetKey(cl.serverinfo, "*csprogssize", versionedname, sizeof(versionedname)), NULL, 0);
|
||||
|
||||
snprintf(versionedname, MAX_QPATH, "csprogsvers/%x.dat", csqchash);
|
||||
|
||||
//try csprogs.dat first, then fall back on progs.dat in case someone tried merging the two.
|
||||
//we only care about it if it actually contains a CSQC_DrawHud, otherwise its either just a (misnamed) ssqc progs or a full csqc progs that would just crash us on 3d stuff.
|
||||
if ((PR_LoadProgs(versionedname, false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && (qcvm->extfuncs.CSQC_DrawHud||cl.qcvm.extfuncs.CSQC_UpdateView))||
|
||||
(PR_LoadProgs("csprogs.dat", false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && (qcvm->extfuncs.CSQC_DrawHud||cl.qcvm.extfuncs.CSQC_UpdateView))||
|
||||
(PR_LoadProgs("progs.dat", false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && (qcvm->extfuncs.CSQC_DrawHud||cl.qcvm.extfuncs.CSQC_UpdateView)))
|
||||
{
|
||||
qcvm->max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
|
||||
qcvm->edicts = (edict_t *) malloc (qcvm->max_edicts*qcvm->edict_size);
|
||||
qcvm->num_edicts = qcvm->reserved_edicts = 1;
|
||||
memset(qcvm->edicts, 0, qcvm->num_edicts*qcvm->edict_size);
|
||||
|
||||
//in terms of exploit protection this is kinda pointless as someone can just strip out this check and compile themselves. oh well.
|
||||
if ((qcvm->progshash == csqchash && qcvm->progssize == csqcsize) || cls.demoplayback)
|
||||
fullcsqc = true;
|
||||
else
|
||||
{ //okay, it doesn't match. full csqc is disallowed to prevent cheats, but we still allow simplecsqc...
|
||||
if (!qcvm->extfuncs.CSQC_DrawHud)
|
||||
{ //no simplecsqc entry points... abort entirely!
|
||||
PR_ClearProgs(qcvm);
|
||||
PR_SwitchQCVM(NULL);
|
||||
return;
|
||||
}
|
||||
fullcsqc = false;
|
||||
qcvm->nogameaccess = true;
|
||||
|
||||
qcvm->extfuncs.CSQC_Input_Frame = 0; //prevent reading/writing input frames (no wallhacks please).
|
||||
qcvm->extfuncs.CSQC_UpdateView = 0; //will probably bug out. block it.
|
||||
qcvm->extfuncs.CSQC_Ent_Update = 0; //don't let the qc know where ents are... the server should prevent this, but make sure the user didn't cheese a 'cmd enablecsqc'
|
||||
qcvm->extfuncs.CSQC_Ent_Remove = 0;
|
||||
qcvm->extfuncs.CSQC_Parse_StuffCmd = 0; //don't allow blocking stuffcmds... though we can't prevent cvar queries+sets, so this is probably futile...
|
||||
|
||||
qcvm->extglobals.clientcommandframe = NULL; //input frames are blocked, so don't bother to connect these either.
|
||||
qcvm->extglobals.servercommandframe = NULL;
|
||||
}
|
||||
|
||||
qcvm->GetModel = PR_CSQC_GetModel;
|
||||
//set a few globals, if they exist
|
||||
if (qcvm->extglobals.maxclients)
|
||||
*qcvm->extglobals.maxclients = cl.maxclients;
|
||||
pr_global_struct->time = cl.time;
|
||||
pr_global_struct->mapname = PR_SetEngineString(cl.mapname);
|
||||
pr_global_struct->total_monsters = cl.statsf[STAT_TOTALMONSTERS];
|
||||
pr_global_struct->total_secrets = cl.statsf[STAT_TOTALSECRETS];
|
||||
pr_global_struct->deathmatch = cl.gametype;
|
||||
pr_global_struct->coop = (cl.gametype == GAME_COOP) && cl.maxclients != 1;
|
||||
if (qcvm->extglobals.player_localnum)
|
||||
*qcvm->extglobals.player_localnum = cl.viewentity-1; //this is a guess, but is important for scoreboards.
|
||||
|
||||
//set a few worldspawn fields too
|
||||
qcvm->edicts->v.solid = SOLID_BSP;
|
||||
qcvm->edicts->v.modelindex = 1;
|
||||
qcvm->edicts->v.model = PR_SetEngineString(cl.worldmodel->name);
|
||||
VectorCopy(cl.worldmodel->mins, qcvm->edicts->v.mins);
|
||||
VectorCopy(cl.worldmodel->maxs, qcvm->edicts->v.maxs);
|
||||
qcvm->edicts->v.message = PR_SetEngineString(cl.levelname);
|
||||
|
||||
//and call the init function... if it exists.
|
||||
qcvm->worldmodel = cl.worldmodel;
|
||||
SV_ClearWorld();
|
||||
if (qcvm->extfuncs.CSQC_Init)
|
||||
{
|
||||
int maj = (int)QUAKESPASM_VERSION;
|
||||
int min = (QUAKESPASM_VERSION-maj) * 100;
|
||||
G_FLOAT(OFS_PARM0) = fullcsqc;
|
||||
G_INT(OFS_PARM1) = PR_SetEngineString("QuakeSpasm-Spiked");
|
||||
G_FLOAT(OFS_PARM2) = 10000*maj + 100*(min) + QUAKESPASM_VER_PATCH;
|
||||
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Init);
|
||||
}
|
||||
|
||||
if (fullcsqc)
|
||||
{
|
||||
//let the server know.
|
||||
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||
MSG_WriteString (&cls.message, "enablecsqc");
|
||||
}
|
||||
}
|
||||
else
|
||||
PR_ClearProgs(qcvm);
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Host_Frame
|
||||
|
@ -773,50 +879,7 @@ void _Host_Frame (double time)
|
|||
{
|
||||
if (CL_CheckDownloads())
|
||||
{
|
||||
PR_ClearProgs(&cl.qcvm);
|
||||
if (pr_checkextension.value && !cl_nocsqc.value)
|
||||
{ //only try to use csqc if qc extensions are enabled.
|
||||
PR_SwitchQCVM(&cl.qcvm);
|
||||
//try csprogs.dat first, then fall back on progs.dat in case someone tried merging the two.
|
||||
//we only care about it if it actually contains a CSQC_DrawHud, otherwise its either just a (misnamed) ssqc progs or a full csqc progs that would just crash us on 3d stuff.
|
||||
if ((PR_LoadProgs("csprogs.dat", false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && qcvm->extfuncs.CSQC_DrawHud)||
|
||||
(PR_LoadProgs("progs.dat", false, PROGHEADER_CRC, pr_csqcbuiltins, pr_csqcnumbuiltins) && qcvm->extfuncs.CSQC_DrawHud))
|
||||
{
|
||||
qcvm->max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS);
|
||||
qcvm->edicts = (edict_t *) malloc (qcvm->max_edicts*qcvm->edict_size);
|
||||
qcvm->num_edicts = qcvm->reserved_edicts = 1;
|
||||
memset(qcvm->edicts, 0, qcvm->num_edicts*qcvm->edict_size);
|
||||
|
||||
//set a few globals, if they exist
|
||||
if (qcvm->extglobals.maxclients)
|
||||
*qcvm->extglobals.maxclients = cl.maxclients;
|
||||
pr_global_struct->time = cl.time;
|
||||
pr_global_struct->mapname = PR_SetEngineString(cl.mapname);
|
||||
pr_global_struct->total_monsters = cl.statsf[STAT_TOTALMONSTERS];
|
||||
pr_global_struct->total_secrets = cl.statsf[STAT_TOTALSECRETS];
|
||||
pr_global_struct->deathmatch = cl.gametype;
|
||||
pr_global_struct->coop = (cl.gametype == GAME_COOP) && cl.maxclients != 1;
|
||||
if (qcvm->extglobals.player_localnum)
|
||||
*qcvm->extglobals.player_localnum = cl.viewentity-1; //this is a guess, but is important for scoreboards.
|
||||
|
||||
//set a few worldspawn fields too
|
||||
qcvm->edicts->v.message = PR_SetEngineString(cl.levelname);
|
||||
|
||||
//and call the init function... if it exists.
|
||||
qcvm->worldmodel = cl.worldmodel;
|
||||
SV_ClearWorld();
|
||||
if (qcvm->extfuncs.CSQC_Init)
|
||||
{
|
||||
G_FLOAT(OFS_PARM0) = 0;
|
||||
G_INT(OFS_PARM1) = PR_SetEngineString("QuakeSpasm-Spiked");
|
||||
G_FLOAT(OFS_PARM2) = QUAKESPASM_VERSION;
|
||||
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Init);
|
||||
}
|
||||
}
|
||||
else
|
||||
PR_ClearProgs(qcvm);
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
CL_LoadCSProgs();
|
||||
|
||||
cl.sendprespawn = false;
|
||||
MSG_WriteByte (&cls.message, clc_stringcmd);
|
||||
|
|
|
@ -1878,6 +1878,21 @@ static void PF_cl_precache_sound (void)
|
|||
S_PrecacheSound(s);
|
||||
}
|
||||
|
||||
qmodel_t *PR_CSQC_GetModel(int idx)
|
||||
{
|
||||
if (idx < 0)
|
||||
{
|
||||
idx = -idx;
|
||||
if (idx < MAX_MODELS)
|
||||
return cl.model_precache_csqc[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx < MAX_MODELS)
|
||||
return cl.model_precache[idx];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
int CL_Precache_Model(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
@ -1892,37 +1907,43 @@ int CL_Precache_Model(const char *name)
|
|||
if (!strcmp(cl.model_name[i], name))
|
||||
return i;
|
||||
}
|
||||
|
||||
//check if the client precached one, and if not then do it.
|
||||
for (i = 1; i < MAX_MODELS; i++)
|
||||
{
|
||||
if (!*cl.model_name_csqc[i])
|
||||
break; //no more
|
||||
if (!strcmp(cl.model_name_csqc[i], name))
|
||||
return -i;
|
||||
}
|
||||
|
||||
if (i < MAX_MODELS && strlen(name) < sizeof(cl.model_name_csqc[i]))
|
||||
{
|
||||
strcpy(cl.model_name_csqc[i], name);
|
||||
cl.model_precache_csqc[i] = Mod_ForName (name, false);
|
||||
if (cl.model_precache_csqc[i])
|
||||
GL_BuildModel(cl.model_precache_csqc[i]);
|
||||
return -i;
|
||||
}
|
||||
|
||||
PR_RunError ("CL_Precache_Model: implementme");
|
||||
return 0;
|
||||
}
|
||||
static void PF_cl_precache_model (void)
|
||||
{
|
||||
const char *s;
|
||||
int i;
|
||||
|
||||
s = G_STRING(OFS_PARM0);
|
||||
const char *s = G_STRING(OFS_PARM0);
|
||||
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||
PR_CheckEmptyString (s);
|
||||
|
||||
//if the server precached the model then we don't need to do anything.
|
||||
for (i = 1; i < MAX_MODELS; i++)
|
||||
{
|
||||
if (!*cl.model_name[i])
|
||||
break; //no more
|
||||
if (!strcmp(cl.model_name[i], s))
|
||||
return;
|
||||
}
|
||||
PR_RunError ("PF_cl_precache_model: implementme");
|
||||
CL_Precache_Model(s);
|
||||
}
|
||||
static void PF_cl_setmodel (void)
|
||||
{
|
||||
int i;
|
||||
const char *m;
|
||||
qmodel_t *mod;
|
||||
edict_t *e;
|
||||
edict_t *e = G_EDICT(OFS_PARM0);
|
||||
const char *m = G_STRING(OFS_PARM1);
|
||||
|
||||
e = G_EDICT(OFS_PARM0);
|
||||
m = G_STRING(OFS_PARM1);
|
||||
int i;
|
||||
qmodel_t *mod;
|
||||
eval_t *modelflags = GetEdictFieldValue(e, qcvm->extfields.modelflags);
|
||||
|
||||
i = CL_Precache_Model(m);
|
||||
|
||||
|
@ -1966,10 +1987,26 @@ static void PF_cl_setmodel (void)
|
|||
SetMinMaxSize (e, mod->clipmins, mod->clipmaxs, true);
|
||||
else
|
||||
SetMinMaxSize (e, mod->mins, mod->maxs, true);
|
||||
|
||||
if (modelflags)
|
||||
modelflags->_float= (mod?mod->flags:0) & (0xff|MF_HOLEY);
|
||||
}
|
||||
//johnfitz
|
||||
else
|
||||
{
|
||||
SetMinMaxSize (e, vec3_origin, vec3_origin, true);
|
||||
if (modelflags)
|
||||
modelflags->_float = 0;
|
||||
}
|
||||
|
||||
if (e == qcvm->edicts)
|
||||
{
|
||||
if (mod && cl.worldmodel != mod)
|
||||
{
|
||||
qcvm->worldmodel = cl.worldmodel = mod;
|
||||
R_NewMap ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PF_NoCSQC PF_Fixme
|
||||
|
|
|
@ -935,10 +935,13 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
|
|||
if (keyname[0] == '_')
|
||||
{
|
||||
//spike -- hacks to support func_illusionary with all sorts of mdls, and various particle effects
|
||||
if (!strcmp(keyname, "_precache_model") && sv.state == ss_loading)
|
||||
SV_Precache_Model(PR_GetString(ED_NewString(com_token)));
|
||||
else if (!strcmp(keyname, "_precache_sound") && sv.state == ss_loading)
|
||||
SV_Precache_Sound(PR_GetString(ED_NewString(com_token)));
|
||||
if (qcvm == &sv.qcvm)
|
||||
{
|
||||
if (!strcmp(keyname, "_precache_model") && sv.state == ss_loading)
|
||||
SV_Precache_Model(PR_GetString(ED_NewString(com_token)));
|
||||
else if (!strcmp(keyname, "_precache_sound") && sv.state == ss_loading)
|
||||
SV_Precache_Sound(PR_GetString(ED_NewString(com_token)));
|
||||
}
|
||||
//spike
|
||||
continue;
|
||||
}
|
||||
|
@ -949,7 +952,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
|
|||
//johnfitz
|
||||
|
||||
//spike -- hacks to support func_illusionary/info_notnull with all sorts of mdls, and various particle effects
|
||||
if (!strcmp(keyname, "modelindex") && sv.state == ss_loading)
|
||||
if (!strcmp(keyname, "modelindex") && qcvm == &sv.qcvm && sv.state == ss_loading)
|
||||
{
|
||||
//"model" "progs/foobar.mdl"
|
||||
//"modelindex" "progs/foobar.mdl"
|
||||
|
@ -967,12 +970,12 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
|
|||
{
|
||||
#ifdef PSET_SCRIPT
|
||||
eval_t *val;
|
||||
if (!strcmp(keyname, "traileffect") && sv.state == ss_loading)
|
||||
if (!strcmp(keyname, "traileffect") && qcvm == &sv.qcvm && sv.state == ss_loading)
|
||||
{
|
||||
if ((val = GetEdictFieldValue(ent, qcvm->extfields.traileffectnum)))
|
||||
val->_float = PF_SV_ForceParticlePrecache(com_token);
|
||||
}
|
||||
else if (!strcmp(keyname, "emiteffect") && sv.state == ss_loading)
|
||||
else if (!strcmp(keyname, "emiteffect") && qcvm == &sv.qcvm && sv.state == ss_loading)
|
||||
{
|
||||
if ((val = GetEdictFieldValue(ent, qcvm->extfields.emiteffectnum)))
|
||||
val->_float = PF_SV_ForceParticlePrecache(com_token);
|
||||
|
@ -992,7 +995,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
|
|||
sprintf (com_token, "0 %s 0", temp);
|
||||
}
|
||||
|
||||
if (!ED_ParseEpair ((void *)&ent->v, key, com_token, false))
|
||||
if (!ED_ParseEpair ((void *)&ent->v, key, com_token, qcvm != &sv.qcvm))
|
||||
Host_Error ("ED_ParseEdict: parse error");
|
||||
}
|
||||
|
||||
|
@ -1156,9 +1159,11 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcr
|
|||
if (!qcvm->progs)
|
||||
return false;
|
||||
|
||||
CRC_Init (&qcvm->crc);
|
||||
qcvm->progssize = com_filesize;
|
||||
CRC_Init (&qcvm->progscrc);
|
||||
for (i = 0; i < com_filesize; i++)
|
||||
CRC_ProcessByte (&qcvm->crc, ((byte *)qcvm->progs)[i]);
|
||||
CRC_ProcessByte (&qcvm->progscrc, ((byte *)qcvm->progs)[i]);
|
||||
qcvm->progshash = Com_BlockChecksum(qcvm->progs, com_filesize);
|
||||
|
||||
// byte swap the header
|
||||
for (i = 0; i < (int) sizeof(*qcvm->progs) / 4; i++)
|
||||
|
|
|
@ -6010,8 +6010,8 @@ static struct
|
|||
#define PF_FullCSQCOnly NULL
|
||||
#define PF_NoMenu NULL,0
|
||||
{
|
||||
{"setmodel", PF_NoSSQC, PF_FullCSQCOnly, 3, PF_m_setmodel, 90, "void(entity ent, string modelname)", ""},
|
||||
{"precache_model", PF_NoSSQC, PF_FullCSQCOnly, 20, PF_m_precache_model,91, "string(string modelname)", ""},
|
||||
{"setmodel", PF_NoSSQC, PF_NoCSQC, 3, PF_m_setmodel, 90, "void(entity ent, string modelname)", ""},
|
||||
{"precache_model", PF_NoSSQC, PF_NoCSQC, 20, PF_m_precache_model,91, "string(string modelname)", ""},
|
||||
|
||||
{"vectoangles2", PF_ext_vectoangles, PF_ext_vectoangles, 51, PF_NoMenu, D("vector(vector fwd, optional vector up)", "Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning.")},
|
||||
{"sin", PF_Sin, PF_Sin, 60, PF_Sin,38, "float(float angle)"}, //60
|
||||
|
|
|
@ -351,7 +351,9 @@ struct qcvm_s
|
|||
dfunction_t *xfunction;
|
||||
int xstatement;
|
||||
|
||||
unsigned short crc;
|
||||
unsigned short progscrc; //crc16 of the entire file
|
||||
unsigned int progshash; //folded file md4
|
||||
unsigned int progssize; //file size (bytes)
|
||||
|
||||
struct pr_extglobals_s extglobals;
|
||||
struct pr_extfuncs_s extfuncs;
|
||||
|
@ -359,6 +361,7 @@ struct qcvm_s
|
|||
|
||||
qboolean cursorforced;
|
||||
void *cursorhandle; //video code.
|
||||
qboolean nogameaccess; //simplecsqc isn't allowed to poke properties of the actual game (to prevent cheats when there's no restrictions on what it can access)
|
||||
|
||||
//was static inside pr_edict
|
||||
char *strings;
|
||||
|
|
|
@ -60,9 +60,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
//#define PEXT1_SHOWPIC 0x04000000
|
||||
//#define PEXT1_CHUNKEDDOWNLOADS 0x20000000
|
||||
#define PEXT1_CSQC 0x40000000 //(full)csqc additions, required for csqc ents+events.
|
||||
#define PEXT1_ACCEPTED_CLIENT (/*PEXT1_SUPPORTED_CLIENT|*/PEXT1_CSQC|PEXT1_Q3BSP|PEXT1_Q2BSP|PEXT1_HLBSP) //pext1 flags that we can accept from a server (aka: partial support)
|
||||
#define PEXT1_SUPPORTED_CLIENT (0) //pext1 flags that we advertise to servers (aka: full support)
|
||||
#define PEXT1_SUPPORTED_SERVER (0) //pext1 flags that we accept from clients.
|
||||
#define PEXT1_ACCEPTED_CLIENT (PEXT1_SUPPORTED_CLIENT|PEXT1_Q3BSP|PEXT1_Q2BSP|PEXT1_HLBSP) //pext1 flags that we can accept from a server (aka: partial support)
|
||||
#define PEXT1_SUPPORTED_CLIENT (PEXT1_CSQC) //pext1 flags that we advertise to servers (aka: full support)
|
||||
#define PEXT1_SUPPORTED_SERVER (PEXT1_CSQC) //pext1 flags that we accept from clients.
|
||||
|
||||
// PROTOCOL_FTE_PEXT2 flags
|
||||
#define PEXT2_PRYDONCURSOR 0x00000001 //a mouse cursor exposed to ssqc
|
||||
|
|
|
@ -867,6 +867,29 @@ void BuildSurfaceDisplayList (msurface_t *fa)
|
|||
poly->numverts = lnumverts;
|
||||
}
|
||||
|
||||
/*
|
||||
Makes sure the model is good to go.
|
||||
*/
|
||||
void GL_BuildModel (qmodel_t *m)
|
||||
{
|
||||
int i;
|
||||
if (m->name[0] == '*')
|
||||
return;
|
||||
r_pcurrentvertbase = m->vertexes;
|
||||
currentmodel = m;
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
|
||||
if (m->surfaces[i].flags & SURF_DRAWTILED)
|
||||
continue;
|
||||
GL_CreateSurfaceLightmap (m, m->surfaces + i);
|
||||
BuildSurfaceDisplayList (m->surfaces + i);
|
||||
//johnfitz
|
||||
}
|
||||
|
||||
// GL_BuildBModelVertexBuffer();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
GL_BuildLightmaps -- called at level load time
|
||||
|
@ -911,19 +934,14 @@ void GL_BuildLightmaps (void)
|
|||
m = cl.model_precache[j];
|
||||
if (!m)
|
||||
break;
|
||||
if (m->name[0] == '*')
|
||||
continue;
|
||||
r_pcurrentvertbase = m->vertexes;
|
||||
currentmodel = m;
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
|
||||
if (m->surfaces[i].flags & SURF_DRAWTILED)
|
||||
continue;
|
||||
GL_CreateSurfaceLightmap (m, m->surfaces + i);
|
||||
BuildSurfaceDisplayList (m->surfaces + i);
|
||||
//johnfitz
|
||||
}
|
||||
GL_BuildModel(m);
|
||||
}
|
||||
for (j=1 ; j<MAX_MODELS ; j++)
|
||||
{
|
||||
m = cl.model_precache_csqc[j];
|
||||
if (!m)
|
||||
break;
|
||||
GL_BuildModel(m);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1010,6 +1028,17 @@ void GL_BuildBModelVertexBuffer (void)
|
|||
numverts += m->surfaces[i].numedges;
|
||||
}
|
||||
}
|
||||
for (j=1 ; j<MAX_MODELS ; j++)
|
||||
{
|
||||
m = cl.model_precache_csqc[j];
|
||||
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
numverts += m->surfaces[i].numedges;
|
||||
}
|
||||
}
|
||||
|
||||
// build vertex array
|
||||
varray_bytes = VERTEXSIZE * sizeof(float) * numverts;
|
||||
|
@ -1030,6 +1059,20 @@ void GL_BuildBModelVertexBuffer (void)
|
|||
varray_index += s->numedges;
|
||||
}
|
||||
}
|
||||
for (j=1 ; j<MAX_MODELS ; j++)
|
||||
{
|
||||
m = cl.model_precache_csqc[j];
|
||||
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
||||
continue;
|
||||
|
||||
for (i=0 ; i<m->numsurfaces ; i++)
|
||||
{
|
||||
msurface_t *s = &m->surfaces[i];
|
||||
s->vbo_firstvert = varray_index;
|
||||
memcpy (&varray[VERTEXSIZE * varray_index], s->polys->verts, VERTEXSIZE * sizeof(float) * s->numedges);
|
||||
varray_index += s->numedges;
|
||||
}
|
||||
}
|
||||
|
||||
// upload to GPU
|
||||
GL_BindBufferFunc (GL_ARRAY_BUFFER, gl_bmodel_vbo);
|
||||
|
|
|
@ -1628,7 +1628,7 @@ void SV_SendServerinfo (client_t *client)
|
|||
retry:
|
||||
MSG_WriteByte (&client->message, svc_print);
|
||||
// sprintf (message, "%c\nFITZQUAKE %1.2f SERVER (%i CRC)\n", 2, FITZQUAKE_VERSION, pr_crc); //johnfitz -- include fitzquake version
|
||||
sprintf (message, "%c\n"ENGINE_NAME_AND_VER" Server (%i CRC)\n", 2, qcvm->crc); //spike -- quakespasm has moved on, and has its own server capabilities now. Advertising = good, right?
|
||||
sprintf (message, "%c\n"ENGINE_NAME_AND_VER" Server (%i CRC)\n", 2, qcvm->progscrc); //spike -- quakespasm has moved on, and has its own server capabilities now. Advertising = good, right?
|
||||
MSG_WriteString (&client->message,message);
|
||||
|
||||
// lack of serverinfo means any csqc info might as well be sent the lame dp way
|
||||
|
@ -3040,6 +3040,7 @@ void SV_SpawnServer (const char *server)
|
|||
static char dummy[8] = { 0,0,0,0,0,0,0,0 };
|
||||
edict_t *ent;
|
||||
int i;
|
||||
qcvm_t *vm = qcvm;
|
||||
|
||||
// let's not have any servers with no name
|
||||
if (hostname.string[0] == 0)
|
||||
|
@ -3049,15 +3050,13 @@ void SV_SpawnServer (const char *server)
|
|||
Con_DPrintf ("SpawnServer: %s\n",server);
|
||||
svs.changelevel_issued = false; // now safe to issue another
|
||||
|
||||
PR_SwitchQCVM(NULL);
|
||||
|
||||
//
|
||||
// tell all connected clients that we are going to a new level
|
||||
//
|
||||
if (sv.active)
|
||||
{
|
||||
PR_SwitchQCVM(NULL);
|
||||
SV_SendReconnect ();
|
||||
PR_SwitchQCVM(&sv.qcvm);
|
||||
}
|
||||
|
||||
//
|
||||
// make cvars consistant
|
||||
|
@ -3093,6 +3092,22 @@ void SV_SpawnServer (const char *server)
|
|||
}
|
||||
else sv.protocolflags = 0;
|
||||
|
||||
{ //update the serverinfo so that clients can know which csprogs they're allowed to use.
|
||||
void *csprogs = (void *)COM_LoadMallocFile("csprogs.dat", NULL);
|
||||
if (csprogs)
|
||||
{
|
||||
Info_SetKey(svs.serverinfo, sizeof(svs.serverinfo), "*csprogs", va("%#x", Com_BlockChecksum(csprogs, com_filesize)));
|
||||
Info_SetKey(svs.serverinfo, sizeof(svs.serverinfo), "*csprogssize", va("%#x", com_filesize));
|
||||
free(csprogs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Info_SetKey(svs.serverinfo, sizeof(svs.serverinfo), "*csprogs", "");
|
||||
Info_SetKey(svs.serverinfo, sizeof(svs.serverinfo), "*csprogssize", "");
|
||||
}
|
||||
}
|
||||
|
||||
PR_SwitchQCVM(vm);
|
||||
// load progs to get entity field count
|
||||
PR_LoadProgs ("progs.dat", true, PROGHEADER_CRC, pr_ssqcbuiltins, pr_ssqcnumbuiltins);
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
|
|||
Con_Warning ("SOLID_BSP without MOVETYPE_PUSH (%s at %f %f %f)\n",
|
||||
PR_GetString(ent->v.classname), ent->v.origin[0], ent->v.origin[1], ent->v.origin[2]);
|
||||
|
||||
model = sv.models[ (int)ent->v.modelindex ];
|
||||
model = qcvm->GetModel(ent->v.modelindex);
|
||||
|
||||
if (!model || model->type != mod_brush)
|
||||
{
|
||||
|
|
|
@ -89,5 +89,6 @@ trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, e
|
|||
|
||||
qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace);
|
||||
|
||||
qmodel_t *PR_CSQC_GetModel(int idx);
|
||||
#endif /* _QUAKE_WORLD_H */
|
||||
|
||||
|
|
Loading…
Reference in a new issue