Add r_meshroll, like r_meshpitch (hexen2 requires it set to -1 - they made the bug worse).
HTTP client code now tracks the reason for failure better (so we can distinguish between dns, no response, disconnects, and tls cert issues). Downloads menu shows reasons for failure for its various sources. make hexen2's +infoplaque button work even when tab isn't held! Yes! usability! who'd a thought it? Try to clean up some client-only build issues. Added 'librequake' as a recognised game name (mostly so that we can reuse the quake-specific engine compat settings. .map support now supports patches enough to query+create(+network)+select them. Collisions are basically defective though. qcc: Remove char as default keyword. qcc: Fix some recent regressions. sv: Add 'sv_protocol csqc' setting to force csqc protocols on clients that disabled handshakes, for mods that NEED csqc support. other options include 'fte1' and 'fte2', if you want to force extra stuff. Engines that don't support the selected protocols will crash out so only set these if your mod/map always requires it. sv: default to qw physics whenever a mod defines the SV_RunClientCommand, even if its an nq mod. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5775 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
524fdb3dfd
commit
432bc96456
39 changed files with 1100 additions and 298 deletions
|
@ -2013,11 +2013,7 @@ void CL_RotateAroundTag(entity_t *ent, int entnum, int parenttagent, int parentt
|
||||||
else
|
else
|
||||||
model = NULL;
|
model = NULL;
|
||||||
if (model && model->type == mod_alias)
|
if (model && model->type == mod_alias)
|
||||||
{
|
AngleVectorsMesh(ang, axis[0], axis[1], axis[2]);
|
||||||
ang[0]*=r_meshpitch.value;
|
|
||||||
AngleVectors(ang, axis[0], axis[1], axis[2]);
|
|
||||||
ang[0]*=r_meshpitch.value;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
AngleVectors(ang, axis[0], axis[1], axis[2]);
|
AngleVectors(ang, axis[0], axis[1], axis[2]);
|
||||||
VectorInverse(axis[1]);
|
VectorInverse(axis[1]);
|
||||||
|
@ -2160,10 +2156,8 @@ entity_t *V_AddEntity(entity_t *in)
|
||||||
|
|
||||||
*ent = *in;
|
*ent = *in;
|
||||||
|
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
|
||||||
|
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
@ -2190,10 +2184,8 @@ void VQ2_AddLerpEntity(entity_t *in) //a convienience function
|
||||||
|
|
||||||
ent->framestate.g[FS_REG].lerpfrac = back;
|
ent->framestate.g[FS_REG].lerpfrac = back;
|
||||||
|
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
int V_AddLight (int entsource, vec3_t org, float quant, float r, float g, float b)
|
int V_AddLight (int entsource, vec3_t org, float quant, float r, float g, float b)
|
||||||
|
@ -3333,10 +3325,8 @@ void CL_LinkStaticEntities(void *pvs, int *areas)
|
||||||
|
|
||||||
//figure out the correct axis for the model
|
//figure out the correct axis for the model
|
||||||
if (clmodel && clmodel->type == mod_alias && (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE))
|
if (clmodel && clmodel->type == mod_alias && (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE))
|
||||||
{ //q2 is fixed, but q1 pitches the wrong way
|
{ //q2 is fixed, but q1 pitches the wrong way, and hexen2 rolls the wrong way too.
|
||||||
stat->state.angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(stat->state.angles, stat->ent.axis[0], stat->ent.axis[1], stat->ent.axis[2]);
|
||||||
AngleVectors(stat->state.angles, stat->ent.axis[0], stat->ent.axis[1], stat->ent.axis[2]);
|
|
||||||
stat->state.angles[0]*=r_meshpitch.value;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
AngleVectors(stat->state.angles, stat->ent.axis[0], stat->ent.axis[1], stat->ent.axis[2]);
|
AngleVectors(stat->state.angles, stat->ent.axis[0], stat->ent.axis[1], stat->ent.axis[2]);
|
||||||
|
@ -4072,8 +4062,9 @@ void CL_LinkPacketEntities (void)
|
||||||
{
|
{
|
||||||
VectorCopy(le->angles, angles);
|
VectorCopy(le->angles, angles);
|
||||||
//if (model && model->type == mod_alias)
|
//if (model && model->type == mod_alias)
|
||||||
angles[0]*=r_meshpitch.value; //pflags matches alias models.
|
AngleVectorsMesh(angles, dl->axis[0], dl->axis[1], dl->axis[2]); //pflags matches alias models.
|
||||||
AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
|
//else
|
||||||
|
// AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]);
|
||||||
VectorInverse(dl->axis[1]);
|
VectorInverse(dl->axis[1]);
|
||||||
R_LoadNumberedLightTexture(dl, state->skinnum);
|
R_LoadNumberedLightTexture(dl, state->skinnum);
|
||||||
}
|
}
|
||||||
|
@ -4333,10 +4324,8 @@ void CL_LinkPacketEntities (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model && model->type == mod_alias)
|
|
||||||
angles[0]*=r_meshpitch.value; //carmack screwed up when he added alias models - they pitch the wrong way.
|
|
||||||
VectorCopy(angles, ent->angles);
|
VectorCopy(angles, ent->angles);
|
||||||
AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
AngleVectorsMesh(angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
|
|
||||||
/*if this entity is in a player's slot...*/
|
/*if this entity is in a player's slot...*/
|
||||||
|
@ -4578,10 +4567,8 @@ void CL_LinkProjectiles (void)
|
||||||
VectorCopy (pr->origin, ent->origin);
|
VectorCopy (pr->origin, ent->origin);
|
||||||
VectorCopy (pr->angles, ent->angles);
|
VectorCopy (pr->angles, ent->angles);
|
||||||
|
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5110,8 +5097,7 @@ void CL_AddFlagModels (entity_t *ent, int team)
|
||||||
newent->angles[2] -= 45;
|
newent->angles[2] -= 45;
|
||||||
|
|
||||||
VectorCopy(newent->angles, angles);
|
VectorCopy(newent->angles, angles);
|
||||||
angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(angles, newent->axis[0], newent->axis[1], newent->axis[2]);
|
||||||
AngleVectors(angles, newent->axis[0], newent->axis[1], newent->axis[2]);
|
|
||||||
VectorInverse(newent->axis[1]);
|
VectorInverse(newent->axis[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5369,7 +5355,10 @@ void CL_LinkPlayers (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model && model->type == mod_alias)
|
if (model && model->type == mod_alias)
|
||||||
|
{
|
||||||
angles[0]*=r_meshpitch.value; //carmack screwed up when he added alias models - they pitch the wrong way.
|
angles[0]*=r_meshpitch.value; //carmack screwed up when he added alias models - they pitch the wrong way.
|
||||||
|
angles[2]*=r_meshroll.value; //hexen2 screwed it up even more - they roll the wrong way.
|
||||||
|
}
|
||||||
VectorCopy(angles, ent->angles);
|
VectorCopy(angles, ent->angles);
|
||||||
AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
AngleVectors(angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
|
@ -5707,6 +5696,7 @@ void CL_SetSolidEntities (void)
|
||||||
pent->model = mod;
|
pent->model = mod;
|
||||||
VectorCopy (state->angles, pent->angles);
|
VectorCopy (state->angles, pent->angles);
|
||||||
pent->angles[0]*=r_meshpitch.value;
|
pent->angles[0]*=r_meshpitch.value;
|
||||||
|
pent->angles[2]*=r_meshroll.value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -4679,7 +4679,7 @@ void CL_Status_f(void)
|
||||||
for (i = 0; i < csqc_world.num_edicts; i++)
|
for (i = 0; i < csqc_world.num_edicts; i++)
|
||||||
{
|
{
|
||||||
e = EDICT_NUM_PB(csqc_world.progs, i);
|
e = EDICT_NUM_PB(csqc_world.progs, i);
|
||||||
if (e && e->ereftype == ER_FREE && sv.time - e->freetime > 0.5)
|
if (e && e->ereftype == ER_FREE && Sys_DoubleTime() - e->freetime > 0.5)
|
||||||
continue; //free, and older than the zombie time
|
continue; //free, and older than the zombie time
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -5972,6 +5972,7 @@ void CL_UpdateHeadAngles(void)
|
||||||
R_ConcatRotations(headchange, tmp, tmp2);
|
R_ConcatRotations(headchange, tmp, tmp2);
|
||||||
VectorAngles(tmp2[0], tmp2[2], pv->viewangles);
|
VectorAngles(tmp2[0], tmp2[2], pv->viewangles);
|
||||||
pv->viewangles[0] *= r_meshpitch.value;
|
pv->viewangles[0] *= r_meshpitch.value;
|
||||||
|
pv->viewangles[2] *= r_meshroll.value;
|
||||||
|
|
||||||
//fall through
|
//fall through
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -4803,11 +4803,7 @@ static void CL_ParseStaticProt (int baselinetype)
|
||||||
VectorCopy (es.origin, ent->origin);
|
VectorCopy (es.origin, ent->origin);
|
||||||
VectorCopy (es.angles, ent->angles);
|
VectorCopy (es.angles, ent->angles);
|
||||||
if (ent->model && ent->model->type == mod_alias)
|
if (ent->model && ent->model->type == mod_alias)
|
||||||
{
|
AngleVectorsMesh(es.angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
es.angles[0]*=r_meshpitch.value;
|
|
||||||
AngleVectors(es.angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
|
||||||
es.angles[0]*=r_meshpitch.value;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
AngleVectors(es.angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
AngleVectors(es.angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
|
|
|
@ -1425,6 +1425,7 @@ void CL_PredictMovePNum (int seat)
|
||||||
if (pv->pmovetype != PM_6DOF)
|
if (pv->pmovetype != PM_6DOF)
|
||||||
le->angles[0] *= 0.333;
|
le->angles[0] *= 0.333;
|
||||||
le->angles[0] *= r_meshpitch.value;
|
le->angles[0] *= r_meshpitch.value;
|
||||||
|
le->angles[2] *= r_meshroll.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2496,6 +2496,7 @@ void CL_SpawnSpriteEffect(vec3_t org, vec3_t dir, vec3_t orientationup, model_t
|
||||||
else
|
else
|
||||||
ex->angles[1] = 0;
|
ex->angles[1] = 0;
|
||||||
ex->angles[0]*=r_meshpitch.value;
|
ex->angles[0]*=r_meshpitch.value;
|
||||||
|
ex->angles[2]*=r_meshroll.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3205,6 +3206,7 @@ void CL_UpdateExplosions (void)
|
||||||
VectorCopy (ex->angles, ent->angles);
|
VectorCopy (ex->angles, ent->angles);
|
||||||
ent->skinnum = ex->skinnum;
|
ent->skinnum = ex->skinnum;
|
||||||
ent->angles[0]*=r_meshpitch.value;
|
ent->angles[0]*=r_meshpitch.value;
|
||||||
|
ent->angles[2]*=r_meshroll.value;
|
||||||
AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
AngleVectors(ent->angles, ent->axis[0], ent->axis[1], ent->axis[2]);
|
||||||
VectorInverse(ent->axis[1]);
|
VectorInverse(ent->axis[1]);
|
||||||
ent->model = ex->model;
|
ent->model = ex->model;
|
||||||
|
|
|
@ -1998,7 +1998,8 @@ static void CLQ2_AddPacketEntities (q2frame_t *frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ent.angles[0]*=r_meshpitch.value; //q2 has it fixed.
|
ent.angles[0]*=r_meshpitch.value; //q2 has it fixed. consistency...
|
||||||
|
ent.angles[2]*=r_meshroll.value; //h2 doesn't. consistency...
|
||||||
|
|
||||||
if (s1->number == cl.playerview[0].playernum+1) //woo! this is us!
|
if (s1->number == cl.playerview[0].playernum+1) //woo! this is us!
|
||||||
{
|
{
|
||||||
|
|
|
@ -2680,9 +2680,7 @@ static void Con_DrawModelPreview(model_t *model, float x, float y, float w, floa
|
||||||
ent.scale = 1;
|
ent.scale = 1;
|
||||||
ent.angles[1] = realtime*90;//mods->yaw;
|
ent.angles[1] = realtime*90;//mods->yaw;
|
||||||
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
|
||||||
VectorInverse(ent.axis[1]);
|
VectorInverse(ent.axis[1]);
|
||||||
|
|
||||||
//ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
|
//ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5 + ent.model->mins[2];
|
||||||
|
@ -2725,9 +2723,7 @@ static void Con_DrawModelPreview(model_t *model, float x, float y, float w, floa
|
||||||
if (ent.model->camerabone>0 && Mod_GetTag(ent.model, ent.model->camerabone, &ent.framestate, transforms))
|
if (ent.model->camerabone>0 && Mod_GetTag(ent.model, ent.model->camerabone, &ent.framestate, transforms))
|
||||||
{
|
{
|
||||||
VectorClear(ent.origin);
|
VectorClear(ent.origin);
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
|
||||||
VectorInverse(ent.axis[1]);
|
VectorInverse(ent.axis[1]);
|
||||||
scale = 1;
|
scale = 1;
|
||||||
{
|
{
|
||||||
|
@ -2749,9 +2745,7 @@ static void Con_DrawModelPreview(model_t *model, float x, float y, float w, floa
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ent.angles[1] = realtime*90;//mods->yaw;
|
ent.angles[1] = realtime*90;//mods->yaw;
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
|
||||||
VectorScale(ent.axis[0], scale, ent.axis[0]);
|
VectorScale(ent.axis[0], scale, ent.axis[0]);
|
||||||
VectorScale(ent.axis[1], -scale, ent.axis[1]);
|
VectorScale(ent.axis[1], -scale, ent.axis[1]);
|
||||||
VectorScale(ent.axis[2], scale, ent.axis[2]);
|
VectorScale(ent.axis[2], scale, ent.axis[2]);
|
||||||
|
|
|
@ -223,7 +223,11 @@ static struct
|
||||||
{
|
{
|
||||||
SRCSTAT_UNKNOWN, //we don't know whether the user wants to allow or block this source.
|
SRCSTAT_UNKNOWN, //we don't know whether the user wants to allow or block this source.
|
||||||
SRCSTAT_DISABLED, //do NOT query this source
|
SRCSTAT_DISABLED, //do NOT query this source
|
||||||
SRCSTAT_FAILED, //tried but failed. FIXME: add some reasons.
|
SRCSTAT_FAILED_DNS, //tried but failed, unresolvable
|
||||||
|
SRCSTAT_FAILED_NORESP, //tried but failed, no response.
|
||||||
|
SRCSTAT_FAILED_EOF, //tried but failed, abrupt termination.
|
||||||
|
SRCSTAT_FAILED_MITM, //tried but failed. misc cert problems.
|
||||||
|
SRCSTAT_FAILED_HTTP, //tried but failed, misc http failure
|
||||||
SRCSTAT_PENDING, //waiting for response (or queued). don't show package list yet.
|
SRCSTAT_PENDING, //waiting for response (or queued). don't show package list yet.
|
||||||
SRCSTAT_OBTAINED, //we got a response.
|
SRCSTAT_OBTAINED, //we got a response.
|
||||||
} status;
|
} status;
|
||||||
|
@ -2081,7 +2085,7 @@ static void PM_ListDownloaded(struct dl_download *dl)
|
||||||
size_t listidx = dl->user_num;
|
size_t listidx = dl->user_num;
|
||||||
size_t sz = 0;
|
size_t sz = 0;
|
||||||
char *f = NULL;
|
char *f = NULL;
|
||||||
if (dl->file)
|
if (dl->file && dl->status != DL_FAILED)
|
||||||
{
|
{
|
||||||
sz = VFS_GETLEN(dl->file);
|
sz = VFS_GETLEN(dl->file);
|
||||||
f = BZ_Malloc(sz+1);
|
f = BZ_Malloc(sz+1);
|
||||||
|
@ -2115,10 +2119,20 @@ static void PM_ListDownloaded(struct dl_download *dl)
|
||||||
{
|
{
|
||||||
downloadablelist[listidx].status = SRCSTAT_OBTAINED;
|
downloadablelist[listidx].status = SRCSTAT_OBTAINED;
|
||||||
PM_ParsePackageList(f, 0, dl->url, downloadablelist[listidx].prefix);
|
PM_ParsePackageList(f, 0, dl->url, downloadablelist[listidx].prefix);
|
||||||
BZ_Free(f);
|
|
||||||
}
|
}
|
||||||
|
else if (dl->replycode == HTTP_DNSFAILURE)
|
||||||
|
downloadablelist[listidx].status = SRCSTAT_FAILED_DNS;
|
||||||
|
else if (dl->replycode == HTTP_NORESPONSE)
|
||||||
|
downloadablelist[listidx].status = SRCSTAT_FAILED_NORESP;
|
||||||
|
else if (dl->replycode == HTTP_EOF)
|
||||||
|
downloadablelist[listidx].status = SRCSTAT_FAILED_EOF;
|
||||||
|
else if (dl->replycode == HTTP_MITM || dl->replycode == HTTP_UNTRUSTED)
|
||||||
|
downloadablelist[listidx].status = SRCSTAT_FAILED_MITM;
|
||||||
|
else if (dl->replycode && dl->replycode < 900)
|
||||||
|
downloadablelist[listidx].status = SRCSTAT_FAILED_HTTP;
|
||||||
else
|
else
|
||||||
downloadablelist[listidx].status = SRCSTAT_FAILED;
|
downloadablelist[listidx].status = SRCSTAT_FAILED_EOF;
|
||||||
|
BZ_Free(f);
|
||||||
|
|
||||||
if (!doautoupdate && !domanifestinstall)
|
if (!doautoupdate && !domanifestinstall)
|
||||||
return; //don't spam this.
|
return; //don't spam this.
|
||||||
|
@ -2252,7 +2266,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
||||||
|
|
||||||
if (allowphonehome<=0)
|
if (allowphonehome<=0)
|
||||||
{
|
{
|
||||||
downloadablelist[i].status = SRCSTAT_FAILED;
|
downloadablelist[i].status = SRCSTAT_FAILED_DNS;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded);
|
downloadablelist[i].curdl = HTTP_CL_Get(va("%s%s"DOWNLOADABLESARGS, downloadablelist[i].url, strchr(downloadablelist[i].url,'?')?"&":"?"), NULL, PM_ListDownloaded);
|
||||||
|
@ -2267,7 +2281,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_Printf("Could not contact updates server - %s\n", downloadablelist[i].url);
|
Con_Printf("Could not contact updates server - %s\n", downloadablelist[i].url);
|
||||||
downloadablelist[i].status = SRCSTAT_FAILED;
|
downloadablelist[i].status = SRCSTAT_FAILED_DNS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3030,7 +3044,7 @@ int PM_IsApplying(qboolean listsonly)
|
||||||
int count = 0;
|
int count = 0;
|
||||||
#ifdef WEBCLIENT
|
#ifdef WEBCLIENT
|
||||||
package_t *p;
|
package_t *p;
|
||||||
int i;
|
// int i;
|
||||||
if (!listsonly)
|
if (!listsonly)
|
||||||
{
|
{
|
||||||
for (p = availablepackages; p ; p=p->next)
|
for (p = availablepackages; p ; p=p->next)
|
||||||
|
@ -3039,11 +3053,11 @@ int PM_IsApplying(qboolean listsonly)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < numdownloadablelists; i++)
|
/*for (i = 0; i < numdownloadablelists; i++)
|
||||||
{
|
{
|
||||||
if (downloadablelist[i].curdl)
|
if (downloadablelist[i].curdl)
|
||||||
count++;
|
count++;
|
||||||
}
|
}*/
|
||||||
#endif
|
#endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -4541,10 +4555,33 @@ static void MD_Source_Draw (int x, int y, struct menucustom_s *c, struct emenu_s
|
||||||
switch(downloadablelist[c->dint].status)
|
switch(downloadablelist[c->dint].status)
|
||||||
{
|
{
|
||||||
case SRCSTAT_OBTAINED:
|
case SRCSTAT_OBTAINED:
|
||||||
case SRCSTAT_PENDING:
|
|
||||||
Draw_FunStringWidth (x, y, "^&02 ", 48, 2, false); //green
|
Draw_FunStringWidth (x, y, "^&02 ", 48, 2, false); //green
|
||||||
break;
|
break;
|
||||||
case SRCSTAT_FAILED:
|
case SRCSTAT_PENDING:
|
||||||
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
|
Draw_FunStringWidth (x, y, "??", 48, 2, false); //this should be fast... so if they get a chance to see the ?? then there's something bad happening, and the ?? is appropriate.
|
||||||
|
break;
|
||||||
|
case SRCSTAT_FAILED_DNS:
|
||||||
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
|
Draw_FunStringWidth (x, y, "DNS", 48, 2, false);
|
||||||
|
break;
|
||||||
|
case SRCSTAT_FAILED_NORESP:
|
||||||
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
|
Draw_FunStringWidth (x, y, "NR", 48, 2, false);
|
||||||
|
break;
|
||||||
|
case SRCSTAT_FAILED_EOF:
|
||||||
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
|
Draw_FunStringWidth (x, y, "EOF", 48, 2, false);
|
||||||
|
break;
|
||||||
|
case SRCSTAT_FAILED_MITM:
|
||||||
|
Draw_FunStringWidth (x, y, "^&04 ", 48, 2, false); //red
|
||||||
|
Draw_FunStringWidth (x, y, "^bMITM", 48, 2, false);
|
||||||
|
break;
|
||||||
|
case SRCSTAT_FAILED_HTTP:
|
||||||
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
|
Draw_FunStringWidth (x, y, "404", 48, 2, false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
case SRCSTAT_UNKNOWN:
|
case SRCSTAT_UNKNOWN:
|
||||||
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
Draw_FunStringWidth (x, y, "^&0E ", 48, 2, false); //yellow
|
||||||
break;
|
break;
|
||||||
|
@ -4564,7 +4601,7 @@ static qboolean MD_Source_Key (struct menucustom_s *c, struct emenu_s *m, int ke
|
||||||
{
|
{
|
||||||
case SRCSTAT_OBTAINED:
|
case SRCSTAT_OBTAINED:
|
||||||
case SRCSTAT_PENDING:
|
case SRCSTAT_PENDING:
|
||||||
case SRCSTAT_FAILED:
|
default: //various failures
|
||||||
case SRCSTAT_UNKNOWN:
|
case SRCSTAT_UNKNOWN:
|
||||||
downloadablelist[c->dint].status = SRCSTAT_DISABLED;
|
downloadablelist[c->dint].status = SRCSTAT_DISABLED;
|
||||||
break;
|
break;
|
||||||
|
@ -4865,18 +4902,18 @@ static void MD_Download_UpdateStatus(struct emenu_s *m)
|
||||||
|
|
||||||
if (!info->populated)
|
if (!info->populated)
|
||||||
{
|
{
|
||||||
for (i = 0; i < numdownloadablelists; i++)
|
y = 48;
|
||||||
|
/*for (i = 0; i < numdownloadablelists; i++)
|
||||||
{
|
{
|
||||||
if (downloadablelist[i].status == SRCSTAT_PENDING)
|
if (downloadablelist[i].status == SRCSTAT_PENDING)
|
||||||
{
|
{
|
||||||
Draw_FunStringWidth(0, vid.height - 8, "Querying for package list", vid.width, 2, false);
|
Draw_FunStringWidth(0, y, "Querying for package list", vid.width, 2, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
info->populated = true;
|
info->populated = true;
|
||||||
MC_AddFrameStart(m, 48);
|
MC_AddFrameStart(m, 48);
|
||||||
y = 48;
|
|
||||||
#ifdef WEBCLIENT
|
#ifdef WEBCLIENT
|
||||||
for (i = 0; i < numdownloadablelists; i++)
|
for (i = 0; i < numdownloadablelists; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2338,6 +2338,7 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k
|
||||||
if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_START && key != K_MOUSE1)
|
if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_START && key != K_MOUSE1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef HAVE_SERVER
|
||||||
switch(info->skillcombo->selectedoption)
|
switch(info->skillcombo->selectedoption)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -2356,6 +2357,7 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k
|
||||||
|
|
||||||
if ((unsigned)info->mapcombo->selectedoption < countof(maplist_h2))
|
if ((unsigned)info->mapcombo->selectedoption < countof(maplist_h2))
|
||||||
Cbuf_AddText(va("map %s\n", maplist_h2[info->mapcombo->selectedoption]), RESTRICT_LOCAL);
|
Cbuf_AddText(va("map %s\n", maplist_h2[info->mapcombo->selectedoption]), RESTRICT_LOCAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
M_RemoveMenu(menu);
|
M_RemoveMenu(menu);
|
||||||
Cbuf_AddText("menu_spcheats\n", RESTRICT_LOCAL);
|
Cbuf_AddText("menu_spcheats\n", RESTRICT_LOCAL);
|
||||||
|
@ -2404,8 +2406,8 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void)
|
||||||
y+=8;
|
y+=8;
|
||||||
#ifdef HAVE_SERVER
|
#ifdef HAVE_SERVER
|
||||||
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
|
info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8;
|
||||||
#endif
|
|
||||||
info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_h2, currentmap); y+=8;
|
info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_h2, currentmap); y+=8;
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SERVER
|
#ifdef HAVE_SERVER
|
||||||
MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8;
|
MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8;
|
||||||
#endif
|
#endif
|
||||||
|
@ -3264,14 +3266,16 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
||||||
// ent.angles[1] = realtime*45;//mods->yaw;
|
// ent.angles[1] = realtime*45;//mods->yaw;
|
||||||
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
// ent.angles[0] = realtime*23.4;//mods->pitch;
|
||||||
|
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
|
||||||
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
|
||||||
ent.angles[0]*=r_meshpitch.value;
|
|
||||||
VectorInverse(ent.axis[1]);
|
|
||||||
|
|
||||||
ent.model = Mod_ForName(mods->modelname, MLV_WARN);
|
ent.model = Mod_ForName(mods->modelname, MLV_WARN);
|
||||||
if (!ent.model)
|
if (!ent.model)
|
||||||
return; //panic!
|
return; //panic!
|
||||||
|
|
||||||
|
if (ent.model->type == mod_alias) //should we even bother with this here?
|
||||||
|
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||||
|
else
|
||||||
|
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
|
||||||
|
VectorInverse(ent.axis[1]);
|
||||||
|
|
||||||
ent.scale = max(max(fabs(ent.model->maxs[0]-ent.model->mins[0]), fabs(ent.model->maxs[1]-ent.model->mins[1])), fabs(ent.model->maxs[2]-ent.model->mins[2]));
|
ent.scale = max(max(fabs(ent.model->maxs[0]-ent.model->mins[0]), fabs(ent.model->maxs[1]-ent.model->mins[1])), fabs(ent.model->maxs[2]-ent.model->mins[2]));
|
||||||
ent.scale = ent.scale?64.0/ent.scale:1;
|
ent.scale = ent.scale?64.0/ent.scale:1;
|
||||||
// ent.scale = 1;
|
// ent.scale = 1;
|
||||||
|
|
|
@ -6827,6 +6827,11 @@ static struct {
|
||||||
{"brush_getfacepoints", PF_brush_getfacepoints, 0},
|
{"brush_getfacepoints", PF_brush_getfacepoints, 0},
|
||||||
{"brush_calcfacepoints", PF_brush_calcfacepoints,0},
|
{"brush_calcfacepoints", PF_brush_calcfacepoints,0},
|
||||||
{"brush_findinvolume", PF_brush_findinvolume, 0},
|
{"brush_findinvolume", PF_brush_findinvolume, 0},
|
||||||
|
|
||||||
|
{"patch_getcp", PF_patch_getcp, 0},
|
||||||
|
{"patch_getmesh", PF_patch_getmesh, 0},
|
||||||
|
{"patch_create", PF_patch_create, 0},
|
||||||
|
// {"patch_calculate", PF_patch_calculate, 0},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENGINE_ROUTING
|
#ifdef ENGINE_ROUTING
|
||||||
|
|
|
@ -223,7 +223,10 @@ static void bonemat_fromentity(world_t *w, wedict_t *ed, float *trans)
|
||||||
a[1] = ed->v->angles[1];
|
a[1] = ed->v->angles[1];
|
||||||
a[2] = ed->v->angles[2];
|
a[2] = ed->v->angles[2];
|
||||||
if (!mod || mod->type == mod_alias)
|
if (!mod || mod->type == mod_alias)
|
||||||
|
{
|
||||||
a[0] *= r_meshpitch.value;
|
a[0] *= r_meshpitch.value;
|
||||||
|
a[2] *= r_meshroll.value;
|
||||||
|
}
|
||||||
AngleVectors(a, d[0], d[1], d[2]);
|
AngleVectors(a, d[0], d[1], d[2]);
|
||||||
bonemat_fromqcvectors(trans, d[0], d[1], d[2], ed->v->origin);
|
bonemat_fromqcvectors(trans, d[0], d[1], d[2], ed->v->origin);
|
||||||
}
|
}
|
||||||
|
@ -1684,7 +1687,7 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
||||||
//fixme: respond to renderflags&USEAXIS? scale?
|
//fixme: respond to renderflags&USEAXIS? scale?
|
||||||
a[0] = wed->v->angles[0] * r_meshpitch.value; /*mod_alias bug*/
|
a[0] = wed->v->angles[0] * r_meshpitch.value; /*mod_alias bug*/
|
||||||
a[1] = wed->v->angles[1];
|
a[1] = wed->v->angles[1];
|
||||||
a[2] = wed->v->angles[2];
|
a[2] = wed->v->angles[2] * r_meshroll.value; /*hexen2 bug*/
|
||||||
AngleVectors(a, d[0], d[1], d[2]);
|
AngleVectors(a, d[0], d[1], d[2]);
|
||||||
bonemat_fromqcvectors(emat, d[0], d[1], d[2], wed->v->origin);
|
bonemat_fromqcvectors(emat, d[0], d[1], d[2], wed->v->origin);
|
||||||
skelidx = wed->xv->skeletonindex;
|
skelidx = wed->xv->skeletonindex;
|
||||||
|
|
|
@ -716,6 +716,7 @@ extern cvar_t gl_playermip;
|
||||||
extern cvar_t r_lightmap_saturation;
|
extern cvar_t r_lightmap_saturation;
|
||||||
|
|
||||||
extern cvar_t r_meshpitch;
|
extern cvar_t r_meshpitch;
|
||||||
|
extern cvar_t r_meshroll; //gah!
|
||||||
extern cvar_t vid_hardwaregamma;
|
extern cvar_t vid_hardwaregamma;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -2397,18 +2397,6 @@ static void Sbar_Hexen2DrawExtra (playerview_t *pv)
|
||||||
"Demoness"
|
"Demoness"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pv->sb_hexen2_infoplaque)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Con_Printf("Objectives:\n");
|
|
||||||
for (i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
if (pv->stats[STAT_H2_OBJECTIVE1 + i/32] & (1<<(i&31)))
|
|
||||||
Con_Printf("%s\n", T_GetInfoString(i));
|
|
||||||
}
|
|
||||||
pv->sb_hexen2_infoplaque = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pv->sb_hexen2_extra_info)
|
if (!pv->sb_hexen2_extra_info)
|
||||||
{
|
{
|
||||||
sbar_rect.y -= 46-SBAR_HEIGHT;
|
sbar_rect.y -= 46-SBAR_HEIGHT;
|
||||||
|
@ -2877,6 +2865,19 @@ void Sbar_Draw (playerview_t *pv)
|
||||||
if (sbar_hexen2)
|
if (sbar_hexen2)
|
||||||
{
|
{
|
||||||
//hexen2 hud
|
//hexen2 hud
|
||||||
|
|
||||||
|
if (pv->sb_hexen2_infoplaque)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Con_Printf("Objectives:\n");
|
||||||
|
for (i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (pv->stats[STAT_H2_OBJECTIVE1 + i/32] & (1<<(i&31)))
|
||||||
|
Con_Printf("%s\n", T_GetInfoString(i));
|
||||||
|
}
|
||||||
|
pv->sb_hexen2_infoplaque = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sb_lines > 24 || pv->sb_hexen2_extra_info)
|
if (sb_lines > 24 || pv->sb_hexen2_extra_info)
|
||||||
{
|
{
|
||||||
Sbar_Hexen2DrawExtra(pv);
|
Sbar_Hexen2DrawExtra(pv);
|
||||||
|
|
|
@ -1310,6 +1310,7 @@ int main (int c, const char **v)
|
||||||
newtime = Sys_DoubleTime ();
|
newtime = Sys_DoubleTime ();
|
||||||
time = newtime - oldtime;
|
time = newtime - oldtime;
|
||||||
|
|
||||||
|
#ifdef HAVE_SERVER
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
{
|
{
|
||||||
sleeptime = SV_Frame();
|
sleeptime = SV_Frame();
|
||||||
|
@ -1317,6 +1318,7 @@ int main (int c, const char **v)
|
||||||
NET_Sleep(sleeptime, noconinput?false:true);
|
NET_Sleep(sleeptime, noconinput?false:true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
sleeptime = Host_Frame(time);
|
sleeptime = Host_Frame(time);
|
||||||
oldtime = newtime;
|
oldtime = newtime;
|
||||||
|
|
|
@ -366,6 +366,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#undef AVAIL_WASAPI //wasapi is available in the vista sdk, while that's compatible with earlier versions, its not really expected until 2008
|
#undef AVAIL_WASAPI //wasapi is available in the vista sdk, while that's compatible with earlier versions, its not really expected until 2008
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(HAVE_SERVER) && !defined(SV_MASTER)
|
||||||
|
#undef HAVE_HTTPSV
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef NO_MULTITHREAD
|
#ifdef NO_MULTITHREAD
|
||||||
#undef MULTITHREAD
|
#undef MULTITHREAD
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,6 +38,7 @@ cvar_t r_meshpitch = CVARCD ("r_meshpitch", "1", r_meshpitch_callback, "Sp
|
||||||
#else
|
#else
|
||||||
cvar_t r_meshpitch = CVARCD ("r_meshpitch", "-1", r_meshpitch_callback, "Specifies the direction of the pitch angle on mesh models formats, Quake compatibility requires -1.");
|
cvar_t r_meshpitch = CVARCD ("r_meshpitch", "-1", r_meshpitch_callback, "Specifies the direction of the pitch angle on mesh models formats, Quake compatibility requires -1.");
|
||||||
#endif
|
#endif
|
||||||
|
cvar_t r_meshroll = CVARCD ("r_meshroll", "1", r_meshpitch_callback, "Specifies the direction of the roll angle on mesh models formats, also affects gamecode, so do not change from its default.");
|
||||||
cvar_t dpcompat_skinfiles = CVARD ("dpcompat_skinfiles", "0", "When set, uses a nodraw shader for any unmentioned surfaces.");
|
cvar_t dpcompat_skinfiles = CVARD ("dpcompat_skinfiles", "0", "When set, uses a nodraw shader for any unmentioned surfaces.");
|
||||||
|
|
||||||
#ifdef HAVE_CLIENT
|
#ifdef HAVE_CLIENT
|
||||||
|
|
|
@ -64,6 +64,7 @@ static int VectorCompare (const vec3_t v1, const vec3_t v2)
|
||||||
|
|
||||||
static rbeplugfuncs_t *rbefuncs;
|
static rbeplugfuncs_t *rbefuncs;
|
||||||
cvar_t r_meshpitch;
|
cvar_t r_meshpitch;
|
||||||
|
cvar_t r_meshroll;
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// physics engine support
|
// physics engine support
|
||||||
|
@ -2738,6 +2739,7 @@ static void QDECL World_ODE_Start(world_t *world)
|
||||||
world->rbe = &ctx->pub;
|
world->rbe = &ctx->pub;
|
||||||
|
|
||||||
r_meshpitch.value = cvarfuncs->GetFloat("r_meshpitch");
|
r_meshpitch.value = cvarfuncs->GetFloat("r_meshpitch");
|
||||||
|
r_meshroll.value = cvarfuncs->GetFloat("r_meshroll");
|
||||||
|
|
||||||
VectorAvg(world->worldmodel->mins, world->worldmodel->maxs, center);
|
VectorAvg(world->worldmodel->mins, world->worldmodel->maxs, center);
|
||||||
VectorSubtract(world->worldmodel->maxs, center, extents);
|
VectorSubtract(world->worldmodel->maxs, center, extents);
|
||||||
|
|
|
@ -580,6 +580,14 @@ typedef struct vfsfile_s
|
||||||
#endif
|
#endif
|
||||||
} vfsfile_t;
|
} vfsfile_t;
|
||||||
|
|
||||||
|
#define VFS_ERROR_TRYLATER 0 //nothing to write/read yet.
|
||||||
|
#define VFS_ERROR_UNSPECIFIED -1 //no reason given
|
||||||
|
#define VFS_ERROR_NORESPONSE -2 //no reason given
|
||||||
|
#define VFS_ERROR_EOF -3 //no reason given
|
||||||
|
#define VFS_ERROR_DNSFAILURE -4 //weird one, but oh well
|
||||||
|
#define VFS_ERROR_WRONGCERT -5 //server gave a certificate with the wrong name
|
||||||
|
#define VFS_ERROR_UNTRUSTED -6 //server gave a certificate with the right name, but we don't have a full chain of trust
|
||||||
|
|
||||||
#define VFS_CLOSE(vf) ((vf)->Close(vf))
|
#define VFS_CLOSE(vf) ((vf)->Close(vf))
|
||||||
#define VFS_TELL(vf) ((vf)->Tell(vf))
|
#define VFS_TELL(vf) ((vf)->Tell(vf))
|
||||||
#define VFS_GETLEN(vf) ((vf)->GetLen(vf))
|
#define VFS_GETLEN(vf) ((vf)->GetLen(vf))
|
||||||
|
|
|
@ -369,18 +369,21 @@ showhelp:
|
||||||
|
|
||||||
// print cvar list header
|
// print cvar list header
|
||||||
if (!(listflags & CLF_RAW) && !num)
|
if (!(listflags & CLF_RAW) && !num)
|
||||||
Con_TPrintf("CVar list:\n");
|
Con_TPrintf("^aCVar list:\n");
|
||||||
|
|
||||||
// print group header
|
// print group header
|
||||||
if (!(listflags & CLF_RAW) && !gnum)
|
if (!(listflags & CLF_RAW) && !gnum)
|
||||||
Con_Printf("%s --\n", grp->name);
|
Con_Printf("^a%s --\n", grp->name);
|
||||||
|
|
||||||
// print restriction level
|
// print restriction level
|
||||||
if (listflags & CLF_LEVEL)
|
if (listflags & CLF_LEVEL)
|
||||||
Con_Printf("(%i) ", cmd->restriction);
|
Con_Printf("(%i) ", cmd->restriction);
|
||||||
|
|
||||||
// print cvar name
|
// print cvar name
|
||||||
Con_Printf("%s", cmd->name);
|
if (!cmd->defaultstr || !strcmp(cmd->string, cmd->defaultstr))
|
||||||
|
Con_Printf(S_COLOR_GREEN "%s", cmd->name);
|
||||||
|
else
|
||||||
|
Con_Printf(S_COLOR_RED "%s", cmd->name);
|
||||||
total++;
|
total++;
|
||||||
|
|
||||||
// print current value
|
// print current value
|
||||||
|
|
|
@ -3650,7 +3650,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
|
||||||
/*quake requires a few settings for compatibility*/
|
/*quake requires a few settings for compatibility*/
|
||||||
#define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8\n"
|
#define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8\n"
|
||||||
#define QUAKESPASMSUCKS "set mod_h2holey_bugged 1\n"
|
#define QUAKESPASMSUCKS "set mod_h2holey_bugged 1\n"
|
||||||
#define QCFG "set v_gammainverted 1\nset con_stayhidden 0\nset com_parseutf8 0\nset allow_download_pakcontents 1\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT QUAKESPASMSUCKS
|
#define QCFG "set v_gammainverted 1\nset con_stayhidden 0\nset com_parseutf8 0\nset allow_download_pakcontents 1\nset allow_download_refpackages 0\nset r_meshpitch -1\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT QUAKESPASMSUCKS
|
||||||
/*NetQuake reconfiguration, to make certain people feel more at home...*/
|
/*NetQuake reconfiguration, to make certain people feel more at home...*/
|
||||||
#define NQCFG "//disablehomedir 1\n//mainconfig ftenq\ncfg_save_auto 1\n" QCFG "set sv_nqplayerphysics 1\nset cl_loopbackprotocol auto\ncl_sbar 1\nset plug_sbar 0\nset sv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\nset m_preset_chosen 1\nset vid_wait 1\nset cl_demoreel 1\n"
|
#define NQCFG "//disablehomedir 1\n//mainconfig ftenq\ncfg_save_auto 1\n" QCFG "set sv_nqplayerphysics 1\nset cl_loopbackprotocol auto\ncl_sbar 1\nset plug_sbar 0\nset sv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\nset m_preset_chosen 1\nset vid_wait 1\nset cl_demoreel 1\n"
|
||||||
#define SPASMCFG NQCFG "fps_preset builtin_spasm\nset cl_demoreel 0\ncl_sbar 2\nset gl_load24bit 1\n"
|
#define SPASMCFG NQCFG "fps_preset builtin_spasm\nset cl_demoreel 0\ncl_sbar 2\nset gl_load24bit 1\n"
|
||||||
|
@ -3666,7 +3666,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
|
||||||
/*some modern non-compat settings*/
|
/*some modern non-compat settings*/
|
||||||
#define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
|
#define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
|
||||||
/*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/
|
/*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/
|
||||||
#define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset cl_forwardspeed 200\nset cl_backspeed 200\ncl_sidespeed 225\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc/hith2o.wav\"\nsv_sound_land \"fx/thngland.wav\"\nset sv_walkpitch 0\n"
|
#define HEX2CFG "set v_gammainverted 1\nset com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset cl_forwardspeed 200\nset cl_backspeed 200\ncl_sidespeed 225\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset r_meshpitch -1\nset r_meshroll -1\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc/hith2o.wav\"\nsv_sound_land \"fx/thngland.wav\"\nset sv_walkpitch 0\n"
|
||||||
/*yay q2!*/
|
/*yay q2!*/
|
||||||
#define Q2CFG "set v_gammainverted 1\nset com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)"\n"
|
#define Q2CFG "set v_gammainverted 1\nset com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)"\n"
|
||||||
/*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/
|
/*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/
|
||||||
|
@ -3750,6 +3750,7 @@ const gamemode_info_t gamemode_info[] = {
|
||||||
{"-quoth", "quoth", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "quoth", "*fte"}, "Quake: Quoth", UPDATEURL(Q1)},
|
{"-quoth", "quoth", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},QCFG, {"id1", "qw", "quoth", "*fte"}, "Quake: Quoth", UPDATEURL(Q1)},
|
||||||
{"-nehahra", "nehahra", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},NEHCFG, {"id1", "qw", "nehahra", "*fte"}, "Quake: Seal Of Nehahra", UPDATEURL(Q1)},
|
{"-nehahra", "nehahra", "FTE-Quake", {"id1/pak0.pak","id1/quake.rc"},NEHCFG, {"id1", "qw", "nehahra", "*fte"}, "Quake: Seal Of Nehahra", UPDATEURL(Q1)},
|
||||||
//various quake-based standalone mods.
|
//various quake-based standalone mods.
|
||||||
|
{"-librequake", "librequake","LibreQuake", {"lq1/pak0.pak","lq1/gfx.pk3","lq1/quake.rc"},QCFG, {"lq1"}, "LibreQuake", UPDATEURL(LQ)},
|
||||||
// {"-nexuiz", "nexuiz", "Nexuiz", {"nexuiz.exe"}, NEXCFG, {"data", "*ftedata"},"Nexuiz"},
|
// {"-nexuiz", "nexuiz", "Nexuiz", {"nexuiz.exe"}, NEXCFG, {"data", "*ftedata"},"Nexuiz"},
|
||||||
// {"-xonotic", "xonotic", "Xonotic", {"data/xonotic-data.pk3dir",
|
// {"-xonotic", "xonotic", "Xonotic", {"data/xonotic-data.pk3dir",
|
||||||
// "data/xonotic-*data*.pk3"}, XONCFG, {"data", "*ftedata"},"Xonotic", UPDATEURL(Xonotic)},
|
// "data/xonotic-*data*.pk3"}, XONCFG, {"data", "*ftedata"},"Xonotic", UPDATEURL(Xonotic)},
|
||||||
|
|
|
@ -335,7 +335,10 @@ void QDECL VectorAngles(const float *forward, const float *up, float *result, qb
|
||||||
yaw *= 180 / M_PI;
|
yaw *= 180 / M_PI;
|
||||||
roll *= 180 / M_PI;
|
roll *= 180 / M_PI;
|
||||||
if (meshpitch)
|
if (meshpitch)
|
||||||
|
{
|
||||||
pitch *= r_meshpitch.value;
|
pitch *= r_meshpitch.value;
|
||||||
|
roll *= r_meshroll.value;
|
||||||
|
}
|
||||||
if (pitch < 0)
|
if (pitch < 0)
|
||||||
pitch += 360;
|
pitch += 360;
|
||||||
if (yaw < 0)
|
if (yaw < 0)
|
||||||
|
@ -382,6 +385,14 @@ void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3
|
||||||
up[2] = cr*cp;
|
up[2] = cr*cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void AngleVectorsMesh (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
|
||||||
|
{
|
||||||
|
vec3_t ang;
|
||||||
|
ang[0] = angles[0] * r_meshpitch.value;
|
||||||
|
ang[1] = angles[1];
|
||||||
|
ang[2] = angles[2] * r_meshroll.value;
|
||||||
|
AngleVectors (ang, forward, right, up);
|
||||||
|
}
|
||||||
|
|
||||||
int VectorCompare (const vec3_t v1, const vec3_t v2)
|
int VectorCompare (const vec3_t v1, const vec3_t v2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -129,6 +129,7 @@ typedef struct {
|
||||||
void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs);
|
void AddPointToBounds (const vec3_t v, vec3_t mins, vec3_t maxs);
|
||||||
float anglemod (float a);
|
float anglemod (float a);
|
||||||
void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
|
void QDECL AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
|
||||||
|
void QDECL AngleVectorsMesh (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
|
||||||
void QDECL VectorAngles (const float *forward, const float *up, float *angles, qboolean meshpitch); //up may be NULL
|
void QDECL VectorAngles (const float *forward, const float *up, float *angles, qboolean meshpitch); //up may be NULL
|
||||||
void VARGS BOPS_Error (void);
|
void VARGS BOPS_Error (void);
|
||||||
int VARGS BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const struct mplane_s *plane);
|
int VARGS BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const struct mplane_s *plane);
|
||||||
|
|
|
@ -430,6 +430,9 @@ typedef struct
|
||||||
qboolean handshaking;
|
qboolean handshaking;
|
||||||
qboolean datagram;
|
qboolean datagram;
|
||||||
|
|
||||||
|
int pullerror; //adding these two because actual networking errors are not getting represented properly, at least with regard to timeouts.
|
||||||
|
int pusherror;
|
||||||
|
|
||||||
qboolean challenging; //not sure this is actually needed, but hey.
|
qboolean challenging; //not sure this is actually needed, but hey.
|
||||||
void *cbctx;
|
void *cbctx;
|
||||||
neterr_t(*cbpush)(void *cbctx, const qbyte *data, size_t datasize);
|
neterr_t(*cbpush)(void *cbctx, const qbyte *data, size_t datasize);
|
||||||
|
@ -658,7 +661,7 @@ static int SSL_DoHandshake(gnutlsfile_t *file)
|
||||||
if (!file->session)
|
if (!file->session)
|
||||||
{
|
{
|
||||||
//Sys_Printf("null session\n");
|
//Sys_Printf("null session\n");
|
||||||
return -1;
|
return VFS_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = qgnutls_handshake (file->session);
|
err = qgnutls_handshake (file->session);
|
||||||
|
@ -676,9 +679,18 @@ static int SSL_DoHandshake(gnutlsfile_t *file)
|
||||||
qgnutls_perror (err);
|
qgnutls_perror (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
SSL_Close(&file->funcs);
|
|
||||||
// Con_Printf("%s: abort\n", file->certname);
|
// Con_Printf("%s: abort\n", file->certname);
|
||||||
return -1;
|
|
||||||
|
switch(err)
|
||||||
|
{
|
||||||
|
case GNUTLS_E_CERTIFICATE_ERROR: err = VFS_ERROR_UNTRUSTED; break;
|
||||||
|
case GNUTLS_E_PREMATURE_TERMINATION: err = VFS_ERROR_EOF; break;
|
||||||
|
case GNUTLS_E_PUSH_ERROR: err = file->pusherror; break;
|
||||||
|
case GNUTLS_E_PULL_ERROR: err = file->pullerror; break;
|
||||||
|
default: err = VFS_ERROR_UNSPECIFIED; break;
|
||||||
|
}
|
||||||
|
SSL_Close(&file->funcs);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
file->handshaking = false;
|
file->handshaking = false;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -697,7 +709,7 @@ static int QDECL SSL_Read(struct vfsfile_s *f, void *buffer, int bytestoread)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bytestoread) //gnutls doesn't like this.
|
if (!bytestoread) //gnutls doesn't like this.
|
||||||
return -1;
|
return VFS_ERROR_UNSPECIFIED; //caller is expecting data that we can never return, or something.
|
||||||
|
|
||||||
read = qgnutls_record_recv(file->session, buffer, bytestoread);
|
read = qgnutls_record_recv(file->session, buffer, bytestoread);
|
||||||
if (read < 0)
|
if (read < 0)
|
||||||
|
@ -705,7 +717,7 @@ static int QDECL SSL_Read(struct vfsfile_s *f, void *buffer, int bytestoread)
|
||||||
if (read == GNUTLS_E_PREMATURE_TERMINATION)
|
if (read == GNUTLS_E_PREMATURE_TERMINATION)
|
||||||
{
|
{
|
||||||
Con_Printf("TLS Premature Termination from %s\n", file->certname);
|
Con_Printf("TLS Premature Termination from %s\n", file->certname);
|
||||||
return -1;
|
return VFS_ERROR_EOF;
|
||||||
}
|
}
|
||||||
else if (read == GNUTLS_E_REHANDSHAKE)
|
else if (read == GNUTLS_E_REHANDSHAKE)
|
||||||
{
|
{
|
||||||
|
@ -721,7 +733,7 @@ static int QDECL SSL_Read(struct vfsfile_s *f, void *buffer, int bytestoread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (read == 0)
|
else if (read == 0)
|
||||||
return -1; //closed by remote connection.
|
return VFS_ERROR_EOF; //closed by remote connection.
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
static int QDECL SSL_Write(struct vfsfile_s *f, const void *buffer, int bytestowrite)
|
static int QDECL SSL_Write(struct vfsfile_s *f, const void *buffer, int bytestowrite)
|
||||||
|
@ -744,11 +756,11 @@ static int QDECL SSL_Write(struct vfsfile_s *f, const void *buffer, int bytestow
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_DPrintf("TLS Send Error %i (%i bytes)\n", written, bytestowrite);
|
Con_DPrintf("TLS Send Error %i (%i bytes)\n", written, bytestowrite);
|
||||||
return -1;
|
return VFS_ERROR_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (written == 0)
|
else if (written == 0)
|
||||||
return -1; //closed by remote connection.
|
return VFS_ERROR_EOF; //closed by remote connection.
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
static qboolean QDECL SSL_Seek (struct vfsfile_s *file, qofs_t pos)
|
static qboolean QDECL SSL_Seek (struct vfsfile_s *file, qofs_t pos)
|
||||||
|
@ -775,7 +787,17 @@ static ssize_t SSL_Push(gnutls_transport_ptr_t p, const void *data, size_t size)
|
||||||
int done = VFS_WRITE(file->stream, data, size);
|
int done = VFS_WRITE(file->stream, data, size);
|
||||||
if (done <= 0)
|
if (done <= 0)
|
||||||
{
|
{
|
||||||
qgnutls_transport_set_errno(file->session, (done==0)?EAGAIN:ECONNRESET);
|
int eno;
|
||||||
|
file->pusherror = done;
|
||||||
|
switch(done)
|
||||||
|
{
|
||||||
|
case VFS_ERROR_EOF: return 0;
|
||||||
|
case VFS_ERROR_DNSFAILURE:
|
||||||
|
case VFS_ERROR_NORESPONSE: eno = ECONNRESET; break;
|
||||||
|
case VFS_ERROR_TRYLATER: eno = EAGAIN; break;
|
||||||
|
default: eno = ECONNRESET; break;
|
||||||
|
}
|
||||||
|
qgnutls_transport_set_errno(file->session, eno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return done;
|
return done;
|
||||||
|
@ -787,8 +809,17 @@ static ssize_t SSL_Pull(gnutls_transport_ptr_t p, void *data, size_t size)
|
||||||
int done = VFS_READ(file->stream, data, size);
|
int done = VFS_READ(file->stream, data, size);
|
||||||
if (done <= 0)
|
if (done <= 0)
|
||||||
{
|
{
|
||||||
//use ECONNRESET instead of returning eof.
|
int eno;
|
||||||
qgnutls_transport_set_errno(file->session, (done==0)?EAGAIN:ECONNRESET);
|
file->pullerror = done;
|
||||||
|
switch(done)
|
||||||
|
{
|
||||||
|
case VFS_ERROR_EOF: return 0;
|
||||||
|
case VFS_ERROR_DNSFAILURE:
|
||||||
|
case VFS_ERROR_NORESPONSE: eno = ECONNRESET; break;
|
||||||
|
case VFS_ERROR_TRYLATER: eno = EAGAIN; break;
|
||||||
|
default: eno = ECONNRESET; break;
|
||||||
|
}
|
||||||
|
qgnutls_transport_set_errno(file->session, eno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return done;
|
return done;
|
||||||
|
|
|
@ -229,7 +229,7 @@ static int SSPI_CheckNewInCrypt(sslfile_t *f)
|
||||||
{
|
{
|
||||||
int newd;
|
int newd;
|
||||||
if (!f->stream)
|
if (!f->stream)
|
||||||
return -1;
|
return VFS_ERROR_EOF;
|
||||||
newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, f->incrypt.datasize - f->incrypt.avail);
|
newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, f->incrypt.datasize - f->incrypt.avail);
|
||||||
if (newd < 0)
|
if (newd < 0)
|
||||||
return newd;
|
return newd;
|
||||||
|
|
|
@ -3986,9 +3986,7 @@ typedef struct ftenet_tcp_stream_s {
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
#if defined(HAVE_SERVER) || defined(SV_MASTER)
|
|
||||||
TCPC_UNKNOWN, //waiting to see what they send us.
|
TCPC_UNKNOWN, //waiting to see what they send us.
|
||||||
#endif
|
|
||||||
//TCPC_QTV, //included for completeness. qtv handles the sockets itself, we just parse initial handshake and then pass it over (as either a tcp or tls vfsfile_t)
|
//TCPC_QTV, //included for completeness. qtv handles the sockets itself, we just parse initial handshake and then pass it over (as either a tcp or tls vfsfile_t)
|
||||||
TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length.
|
TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length.
|
||||||
#ifdef HAVE_HTTPSV
|
#ifdef HAVE_HTTPSV
|
||||||
|
@ -3996,8 +3994,8 @@ typedef struct ftenet_tcp_stream_s {
|
||||||
TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary')
|
TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary')
|
||||||
TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake
|
TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake
|
||||||
TCPC_HTTPCLIENT, //we're sending a file to this victim.
|
TCPC_HTTPCLIENT, //we're sending a file to this victim.
|
||||||
|
TCPC_WEBRTC_HOST, //for brokering webrtc connections, doesn't carry any actual game data itself.
|
||||||
TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself.
|
TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself.
|
||||||
TCPC_WEBRTC_HOST //for brokering webrtc connections, doesn't carry any actual game data itself.
|
|
||||||
#endif
|
#endif
|
||||||
} clienttype;
|
} clienttype;
|
||||||
qbyte inbuffer[MAX_OVERALLMSGLEN];
|
qbyte inbuffer[MAX_OVERALLMSGLEN];
|
||||||
|
@ -5129,6 +5127,7 @@ static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_s
|
||||||
if (st->dlfile)
|
if (st->dlfile)
|
||||||
VFS_CLOSE(st->dlfile);
|
VFS_CLOSE(st->dlfile);
|
||||||
|
|
||||||
|
#ifdef HAVE_HTTPSV
|
||||||
if (st->clienttype == TCPC_WEBRTC_CLIENT)
|
if (st->clienttype == TCPC_WEBRTC_CLIENT)
|
||||||
{ //notify its server
|
{ //notify its server
|
||||||
ftenet_tcp_stream_t *o;
|
ftenet_tcp_stream_t *o;
|
||||||
|
@ -5165,6 +5164,7 @@ static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_s
|
||||||
SVM_RemoveBrokerGame(st->webrtc.resource);
|
SVM_RemoveBrokerGame(st->webrtc.resource);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -8823,8 +8823,8 @@ typedef struct {
|
||||||
|
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
qboolean conpending;
|
qboolean conpending;
|
||||||
qboolean readaborted; //some kind of error. don't spam
|
int readaborted; //some kind of error. don't spam
|
||||||
qboolean writeaborted; //some kind of error. don't spam
|
int writeaborted; //some kind of error. don't spam
|
||||||
|
|
||||||
char readbuffer[65536];
|
char readbuffer[65536];
|
||||||
int readbuffered;
|
int readbuffered;
|
||||||
|
@ -8871,19 +8871,24 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
||||||
int e = neterrno();
|
int e = neterrno();
|
||||||
if (e != NET_EWOULDBLOCK && e != NET_EINTR)
|
if (e != NET_EWOULDBLOCK && e != NET_EINTR)
|
||||||
{
|
{
|
||||||
|
tf->readaborted = VFS_ERROR_UNSPECIFIED;
|
||||||
switch(e)
|
switch(e)
|
||||||
{
|
{
|
||||||
case NET_ENOTCONN:
|
case NET_ENOTCONN:
|
||||||
Con_Printf("connection to \"%s\" failed\n", tf->peer);
|
Con_Printf("connection to \"%s\" failed\n", tf->peer);
|
||||||
|
tf->readaborted = VFS_ERROR_NORESPONSE;
|
||||||
break;
|
break;
|
||||||
case NET_ECONNABORTED:
|
case NET_ECONNABORTED:
|
||||||
Con_DPrintf("connection to \"%s\" aborted\n", tf->peer);
|
Con_DPrintf("connection to \"%s\" aborted\n", tf->peer);
|
||||||
|
tf->readaborted = VFS_ERROR_NORESPONSE;
|
||||||
break;
|
break;
|
||||||
case NET_ETIMEDOUT:
|
case NET_ETIMEDOUT:
|
||||||
Con_Printf("connection to \"%s\" timed out\n", tf->peer);
|
Con_Printf("connection to \"%s\" timed out\n", tf->peer);
|
||||||
|
tf->readaborted = VFS_ERROR_NORESPONSE;
|
||||||
break;
|
break;
|
||||||
case NET_ECONNREFUSED:
|
case NET_ECONNREFUSED:
|
||||||
Con_DPrintf("connection to \"%s\" refused\n", tf->peer);
|
Con_DPrintf("connection to \"%s\" refused\n", tf->peer);
|
||||||
|
tf->readaborted = VFS_ERROR_NORESPONSE;
|
||||||
break;
|
break;
|
||||||
case NET_ECONNRESET:
|
case NET_ECONNRESET:
|
||||||
Con_DPrintf("connection to \"%s\" reset\n", tf->peer);
|
Con_DPrintf("connection to \"%s\" reset\n", tf->peer);
|
||||||
|
@ -8891,14 +8896,13 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
||||||
default:
|
default:
|
||||||
Con_Printf("tcp socket error %i (%s)\n", e, tf->peer);
|
Con_Printf("tcp socket error %i (%s)\n", e, tf->peer);
|
||||||
}
|
}
|
||||||
tf->readaborted = true;
|
|
||||||
}
|
}
|
||||||
//fixme: figure out wouldblock or error
|
//fixme: figure out wouldblock or error
|
||||||
}
|
}
|
||||||
else if (len == 0 && trying != 0)
|
else if (len == 0 && trying != 0)
|
||||||
{
|
{
|
||||||
//peer disconnected
|
//peer disconnected
|
||||||
tf->readaborted = true;
|
tf->readaborted = VFS_ERROR_EOF;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -8910,7 +8914,7 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
||||||
if (bytestoread > tf->readbuffered)
|
if (bytestoread > tf->readbuffered)
|
||||||
bytestoread = tf->readbuffered;
|
bytestoread = tf->readbuffered;
|
||||||
if (bytestoread < 0)
|
if (bytestoread < 0)
|
||||||
return -1; //caller error...
|
return VFS_ERROR_UNSPECIFIED; //caller error...
|
||||||
|
|
||||||
if (bytestoread > 0)
|
if (bytestoread > 0)
|
||||||
{
|
{
|
||||||
|
@ -8919,14 +8923,7 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
|
||||||
memmove(tf->readbuffer, tf->readbuffer+bytestoread, tf->readbuffered);
|
memmove(tf->readbuffer, tf->readbuffer+bytestoread, tf->readbuffered);
|
||||||
return bytestoread;
|
return bytestoread;
|
||||||
}
|
}
|
||||||
else
|
else return tf->readaborted;
|
||||||
{
|
|
||||||
if (tf->readaborted)
|
|
||||||
{
|
|
||||||
return -1; //signal an error
|
|
||||||
}
|
|
||||||
return 0; //signal nothing available
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestoread)
|
int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestoread)
|
||||||
{
|
{
|
||||||
|
@ -8934,7 +8931,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (tf->writeaborted)
|
if (tf->writeaborted)
|
||||||
return -1;
|
return VFS_ERROR_UNSPECIFIED; //a previous write failed.
|
||||||
|
|
||||||
if (tf->conpending)
|
if (tf->conpending)
|
||||||
{
|
{
|
||||||
|
@ -8955,6 +8952,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
||||||
len = send(tf->sock, buffer, bytestoread, 0);
|
len = send(tf->sock, buffer, bytestoread, 0);
|
||||||
if (len == -1 || len == 0)
|
if (len == -1 || len == 0)
|
||||||
{
|
{
|
||||||
|
int reason = VFS_ERROR_UNSPECIFIED;
|
||||||
int e = (len==0)?NET_ECONNABORTED:neterrno();
|
int e = (len==0)?NET_ECONNABORTED:neterrno();
|
||||||
switch(e)
|
switch(e)
|
||||||
{
|
{
|
||||||
|
@ -8963,16 +8961,17 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
||||||
return 0; //nothing available yet.
|
return 0; //nothing available yet.
|
||||||
case NET_ETIMEDOUT:
|
case NET_ETIMEDOUT:
|
||||||
Con_Printf("connection to \"%s\" timed out\n", tf->peer);
|
Con_Printf("connection to \"%s\" timed out\n", tf->peer);
|
||||||
return -1; //don't bother trying to read if we never connected.
|
return VFS_ERROR_NORESPONSE; //don't bother trying to read if we never connected.
|
||||||
case NET_ECONNABORTED:
|
case NET_ECONNABORTED:
|
||||||
Con_Printf("connection to \"%s\" aborted\n", tf->peer);
|
Con_Printf("connection to \"%s\" aborted\n", tf->peer);
|
||||||
|
reason = len?VFS_ERROR_NORESPONSE:VFS_ERROR_EOF;
|
||||||
break;
|
break;
|
||||||
case NET_ENOTCONN:
|
case NET_ENOTCONN:
|
||||||
#ifdef __unix__
|
#ifdef __unix__
|
||||||
case EPIPE:
|
case EPIPE:
|
||||||
#endif
|
#endif
|
||||||
Con_Printf("connection to \"%s\" failed\n", tf->peer);
|
Con_Printf("connection to \"%s\" failed\n", tf->peer);
|
||||||
return -1; //don't bother trying to read if we never connected.
|
return VFS_ERROR_NORESPONSE; //don't bother trying to read if we never connected.
|
||||||
default:
|
default:
|
||||||
Sys_Printf("tcp socket error %i (%s)\n", e, tf->peer);
|
Sys_Printf("tcp socket error %i (%s)\n", e, tf->peer);
|
||||||
break;
|
break;
|
||||||
|
@ -8981,7 +8980,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
|
||||||
// instead let the read handling kill it if there's nothing new to be read
|
// instead let the read handling kill it if there's nothing new to be read
|
||||||
VFSTCP_ReadBytes(file, NULL, 0);
|
VFSTCP_ReadBytes(file, NULL, 0);
|
||||||
tf->writeaborted = true;
|
tf->writeaborted = true;
|
||||||
return -1;
|
return reason;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6334,9 +6334,7 @@ void QCBUILTIN PF_rotatevectorsbyangles (pubprogfuncs_t *prinst, struct globalva
|
||||||
|
|
||||||
float *ang = G_VECTOR(OFS_PARM0);
|
float *ang = G_VECTOR(OFS_PARM0);
|
||||||
vec3_t src[3], trans[3], res[3];
|
vec3_t src[3], trans[3], res[3];
|
||||||
ang[0]*=r_meshpitch.value;
|
AngleVectorsMesh(ang, trans[0], trans[1], trans[2]);
|
||||||
AngleVectors(ang, trans[0], trans[1], trans[2]);
|
|
||||||
ang[0]*=r_meshpitch.value;
|
|
||||||
VectorInverse(trans[1]);
|
VectorInverse(trans[1]);
|
||||||
|
|
||||||
VectorCopy(w->g.v_forward, src[0]);
|
VectorCopy(w->g.v_forward, src[0]);
|
||||||
|
|
|
@ -341,6 +341,9 @@ void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr
|
||||||
void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
|
void QCBUILTIN PF_patch_getcp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
|
void QCBUILTIN PF_patch_getmesh(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
|
void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||||
|
|
|
@ -7,18 +7,19 @@ See gl_terrain.h for terminology, networking notes, etc.
|
||||||
#ifdef TERRAIN
|
#ifdef TERRAIN
|
||||||
#include "glquake.h"
|
#include "glquake.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "com_mesh.h"
|
||||||
|
|
||||||
#include "pr_common.h"
|
#include "pr_common.h"
|
||||||
|
|
||||||
#include "gl_terrain.h"
|
#include "gl_terrain.h"
|
||||||
|
|
||||||
static plugterrainfuncs_t terrainfuncs;
|
static plugterrainfuncs_t terrainfuncs;
|
||||||
struct patchvert_s
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3_t v;
|
vec3_t v;
|
||||||
vec2_t tc;
|
vec2_t tc;
|
||||||
vec4_t rgba;
|
vec4_t rgba;
|
||||||
};
|
} qcpatchvert_t;
|
||||||
|
|
||||||
|
|
||||||
cvar_t mod_terrain_networked = CVARD("mod_terrain_networked", "0", "Terrain edits are networked. Clients will download sections on demand, and servers will notify clients of changes.");
|
cvar_t mod_terrain_networked = CVARD("mod_terrain_networked", "0", "Terrain edits are networked. Clients will download sections on demand, and servers will notify clients of changes.");
|
||||||
|
@ -33,10 +34,11 @@ cvar_t mod_terrain_brushtexscale = CVARD("mod_map_texscale", "1", "Defines the s
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
hmcmd_brush_delete,
|
hmcmd_brush_delete, //brush OR patch destruction
|
||||||
hmcmd_brush_insert,
|
hmcmd_brush_insert, //brush creation
|
||||||
hmcmd_prespawning, //sent before initial inserts
|
hmcmd_prespawning, //sent before initial inserts
|
||||||
hmcmd_prespawned, //sent just after initial inserts
|
hmcmd_prespawned, //sent just after initial inserts
|
||||||
|
hmcmd_patch_insert, //patch creation
|
||||||
|
|
||||||
hmcmd_ent_edit = 0x40,
|
hmcmd_ent_edit = 0x40,
|
||||||
hmcmd_ent_remove
|
hmcmd_ent_remove
|
||||||
|
@ -3726,6 +3728,72 @@ static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes, b
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean Heightmap_Trace_Quad(hmtrace_t *tr, const float *v0, const float *v1, const float *v2, const float *v3)
|
||||||
|
{
|
||||||
|
//super lame shite. be lazy and just use a bbox
|
||||||
|
static vec4_t n[6] = {
|
||||||
|
{-1, 0, 0, 0},
|
||||||
|
{ 0,-1, 0, 0},
|
||||||
|
{ 0, 0,-1, 0},
|
||||||
|
{ 1, 0, 0, 0},
|
||||||
|
{ 0, 1, 0, 0},
|
||||||
|
{ 0, 0, 1, 0},
|
||||||
|
};
|
||||||
|
vec3_t d[2];
|
||||||
|
const float epsilon = 1.0/64;
|
||||||
|
VectorCopy(v0, d[0]);
|
||||||
|
VectorCopy(v0, d[1]);
|
||||||
|
AddPointToBounds(v1, d[0], d[1]);
|
||||||
|
AddPointToBounds(v2, d[0], d[1]);
|
||||||
|
AddPointToBounds(v3, d[0], d[1]);
|
||||||
|
|
||||||
|
//I'm implementing this primarily for selecting patches.
|
||||||
|
//decals are often infinitely thin things.
|
||||||
|
//so expand them by a tiny amount in the hopes that traces will hit patches before the wall they're coplanar with.
|
||||||
|
n[0][3] =-d[0][0]+epsilon;
|
||||||
|
n[1][3] =-d[0][1]+epsilon;
|
||||||
|
n[2][3] =-d[0][2]+epsilon;
|
||||||
|
n[3][3] = d[1][0]+epsilon;
|
||||||
|
n[4][3] = d[1][1]+epsilon;
|
||||||
|
n[5][3] = d[1][2]+epsilon;
|
||||||
|
|
||||||
|
return Heightmap_Trace_Brush(tr, n, 6, NULL) != 0;
|
||||||
|
}
|
||||||
|
static qboolean Heightmap_Trace_Patch(hmtrace_t *tr, brushes_t *brushinfo)
|
||||||
|
{
|
||||||
|
const struct patchdata_s *patch = brushinfo->patch;
|
||||||
|
unsigned int w, h, x, y;
|
||||||
|
qboolean ret = false;
|
||||||
|
|
||||||
|
if (!patch->tessvert)
|
||||||
|
{
|
||||||
|
const struct patchcpvert_s *r1 = patch->cp, *r2;
|
||||||
|
w = patch->numcp[0];
|
||||||
|
h = patch->numcp[1];
|
||||||
|
|
||||||
|
for (y = 0, r2 = r1 + w; y < h-1; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < w-1; x++, r1++, r2++)
|
||||||
|
ret |= Heightmap_Trace_Quad(tr, r1[0].v, r1[1].v, r2[0].v, r1[1].v);
|
||||||
|
r1++; r2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const struct patchtessvert_s *r1 = patch->tessvert, *r2;
|
||||||
|
w = patch->tesssize[0];
|
||||||
|
h = patch->tesssize[1];
|
||||||
|
|
||||||
|
for (y = 0, r2 = r1 + w; y < h-1; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < w-1; x++, r1++, r2++)
|
||||||
|
ret |= Heightmap_Trace_Quad(tr, r1[0].v, r1[1].v, r2[0].v, r1[1].v);
|
||||||
|
r1++; r2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
//sx,sy are the tile coord
|
//sx,sy are the tile coord
|
||||||
//note that tile SECTHEIGHTSIZE-1 does not exist, as the last sample overlaps the first sample of the next section
|
//note that tile SECTHEIGHTSIZE-1 does not exist, as the last sample overlaps the first sample of the next section
|
||||||
static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
|
static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty)
|
||||||
|
@ -4249,6 +4317,14 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, const framesta
|
||||||
hmtrace.absmins[1] > brushes->maxs[1] ||
|
hmtrace.absmins[1] > brushes->maxs[1] ||
|
||||||
hmtrace.absmins[2] > brushes->maxs[2])
|
hmtrace.absmins[2] > brushes->maxs[2])
|
||||||
continue;
|
continue;
|
||||||
|
if (brushes->patch)
|
||||||
|
{
|
||||||
|
if (Heightmap_Trace_Patch(&hmtrace, brushes))
|
||||||
|
face = -1;
|
||||||
|
else
|
||||||
|
face = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
face = Heightmap_Trace_Brush(&hmtrace, brushes->planes, brushes->numplanes, brushes);
|
face = Heightmap_Trace_Brush(&hmtrace, brushes->planes, brushes->numplanes, brushes);
|
||||||
if (face)
|
if (face)
|
||||||
{
|
{
|
||||||
|
@ -5898,32 +5974,38 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
|
||||||
{
|
{
|
||||||
for (numverts = 0, numindicies = 0; i < hm->numbrushes; i++, br++)
|
for (numverts = 0, numindicies = 0; i < hm->numbrushes; i++, br++)
|
||||||
{
|
{
|
||||||
//if a single batch has too many verts, cut it off before it overflows our maximum batch size, and hope we don't get a really really complex brush.
|
if (br->selected)
|
||||||
if (numverts >= 0xf000 || numindicies >= 0xf000)
|
continue;
|
||||||
break;
|
if (br->patch)
|
||||||
|
{ //this one's a patch
|
||||||
if (br->patch && br->patch->tex == bt && lmnum == -1)
|
if (br->patch->tex == bt && lmnum == -1)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
index_t r1, r2;
|
index_t r1, r2;
|
||||||
|
|
||||||
for (y = 0, r1 = numverts, r2 = 0; y < br->patch->ypoints; y++)
|
if (br->patch->tessvert && !br->selected)
|
||||||
{
|
{ //tessellated version of the patch.
|
||||||
for (x = 0; x < br->patch->xpoints; x++, r1++, r2++)
|
|
||||||
{
|
|
||||||
VectorCopy(br->patch->verts[r2].v, arrays->coord[r1]);
|
|
||||||
Vector2Copy(br->patch->verts[r2].tc, arrays->texcoord[r1]);
|
|
||||||
VectorCopy(br->patch->verts[r2].norm, arrays->normal[r1]);
|
|
||||||
VectorCopy(br->patch->verts[r2].sdir, arrays->svector[r1]);
|
|
||||||
VectorCopy(br->patch->verts[r2].tdir, arrays->tvector[r1]);
|
|
||||||
Vector4Copy(br->patch->verts[r2].rgba, arrays->rgba[r1]);
|
|
||||||
|
|
||||||
Vector2Copy(br->patch->verts[r2].tc, arrays->lmcoord[r1]);
|
//make sure we don't overflow anything.
|
||||||
}
|
size_t newverts = br->patch->tesssize[0]*br->patch->tesssize[1], newindexes = (br->patch->tesssize[0]-1)*(br->patch->tesssize[1]-1)*6;
|
||||||
}
|
if (numverts+newverts >= 0xffff || numindicies+newindexes >= 0xffff)
|
||||||
for (y = 0, r1 = numverts, r2 = r1 + br->patch->xpoints; y < br->patch->ypoints-1; y++)
|
break;
|
||||||
|
|
||||||
|
for (y = 0, r1 = numverts, r2 = 0; y < br->patch->tesssize[1]; y++)
|
||||||
{
|
{
|
||||||
for (x = 0; x < br->patch->xpoints-1; x++, r1++, r2++)
|
for (x = 0; x < br->patch->tesssize[0]; x++, r1++, r2++)
|
||||||
|
{
|
||||||
|
VectorCopy(br->patch->tessvert[r2].v, arrays->coord[r1]);
|
||||||
|
Vector2Copy(br->patch->tessvert[r2].tc, arrays->texcoord[r1]);
|
||||||
|
Vector4Copy(br->patch->tessvert[r2].rgba, arrays->rgba[r1]);
|
||||||
|
|
||||||
|
//lame
|
||||||
|
Vector2Copy(br->patch->tessvert[r2].tc, arrays->lmcoord[r1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (y = 0, r1 = numverts, r2 = r1 + br->patch->tesssize[0]; y < br->patch->tesssize[1]-1; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < br->patch->tesssize[0]-1; x++, r1++, r2++)
|
||||||
{
|
{
|
||||||
arrays->index[numindicies++] = r1;
|
arrays->index[numindicies++] = r1;
|
||||||
arrays->index[numindicies++] = r1+1;
|
arrays->index[numindicies++] = r1+1;
|
||||||
|
@ -5935,8 +6017,61 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
|
||||||
}
|
}
|
||||||
r1++; r2++;
|
r1++; r2++;
|
||||||
}
|
}
|
||||||
numverts += br->patch->ypoints*br->patch->xpoints;
|
Mod_AccumulateTextureVectors(arrays->coord, arrays->texcoord, arrays->normal, arrays->svector, arrays->tvector, arrays->index+numindicies-newindexes, newindexes, true);
|
||||||
|
Mod_NormaliseTextureVectors(arrays->normal+numverts, arrays->svector+numverts, arrays->tvector+numverts, newverts, true);
|
||||||
|
numverts += newverts;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{ //control-point representation.
|
||||||
|
|
||||||
|
//make sure we don't overflow anything.
|
||||||
|
size_t newverts = br->patch->numcp[0]*br->patch->numcp[1], newindexes = (br->patch->numcp[0]-1)*(br->patch->numcp[1]-1)*6;
|
||||||
|
if (numverts+newverts >= 0xffff || numindicies+newindexes >= 0xffff)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (y = 0, r1 = numverts, r2 = 0; y < br->patch->numcp[1]; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < br->patch->numcp[0]; x++, r1++, r2++)
|
||||||
|
{
|
||||||
|
VectorCopy(br->patch->cp[r2].v, arrays->coord[r1]);
|
||||||
|
Vector2Copy(br->patch->cp[r2].tc, arrays->texcoord[r1]);
|
||||||
|
Vector4Copy(br->patch->cp[r2].rgba, arrays->rgba[r1]);
|
||||||
|
|
||||||
|
//lame
|
||||||
|
Vector2Copy(br->patch->cp[r2].tc, arrays->lmcoord[r1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (y = 0, r1 = numverts, r2 = r1 + br->patch->numcp[0]; y < br->patch->numcp[1]-1; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < br->patch->numcp[0]-1; x++, r1++, r2++)
|
||||||
|
{
|
||||||
|
arrays->index[numindicies++] = r1;
|
||||||
|
arrays->index[numindicies++] = r1+1;
|
||||||
|
arrays->index[numindicies++] = r2;
|
||||||
|
|
||||||
|
arrays->index[numindicies++] = r1+1;
|
||||||
|
arrays->index[numindicies++] = r2+1;
|
||||||
|
arrays->index[numindicies++] = r2;
|
||||||
|
}
|
||||||
|
r1++; r2++;
|
||||||
|
}
|
||||||
|
Mod_AccumulateTextureVectors(arrays->coord, arrays->texcoord, arrays->normal, arrays->svector, arrays->tvector, arrays->index+numindicies-newindexes, newindexes, true);
|
||||||
|
Mod_NormaliseTextureVectors(arrays->normal+numverts, arrays->svector+numverts, arrays->tvector+numverts, newverts, true);
|
||||||
|
numverts += newverts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //regular brush
|
||||||
|
|
||||||
|
//make sure we don't overflow anything.
|
||||||
|
size_t newverts = 0, newindexes = 0;
|
||||||
|
for (j = 0; j < br->numplanes; j++)
|
||||||
|
if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
|
||||||
|
newverts += br->faces[j].numpoints, newindexes += (br->faces[j].numpoints-2)*3;
|
||||||
|
if (numverts+newverts >= 0xffff || numindicies+newindexes >= 0xffff)
|
||||||
|
break;
|
||||||
|
|
||||||
for (j = 0; j < br->numplanes; j++)
|
for (j = 0; j < br->numplanes; j++)
|
||||||
{
|
{
|
||||||
if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
|
if (br->faces[j].tex == bt && !br->selected && br->faces[j].lightmap == lmnum)
|
||||||
|
@ -5972,6 +6107,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (numverts || numindicies)
|
if (numverts || numindicies)
|
||||||
{
|
{
|
||||||
|
@ -6101,11 +6237,11 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
|
||||||
out->planes = NULL;
|
out->planes = NULL;
|
||||||
out->faces = NULL;
|
out->faces = NULL;
|
||||||
out->numplanes = 0;
|
out->numplanes = 0;
|
||||||
|
ClearBounds(out->mins, out->maxs);
|
||||||
if (brush->numplanes)
|
if (brush->numplanes)
|
||||||
{
|
{
|
||||||
out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * brush->numplanes);
|
out->planes = BZ_Malloc((sizeof(*out->planes)+sizeof(*out->faces)) * brush->numplanes);
|
||||||
out->faces = (void*)(out->planes+brush->numplanes);
|
out->faces = (void*)(out->planes+brush->numplanes);
|
||||||
ClearBounds(out->mins, out->maxs);
|
|
||||||
for (iface = 0, oface = 0; iface < brush->numplanes; iface++)
|
for (iface = 0, oface = 0; iface < brush->numplanes; iface++)
|
||||||
{
|
{
|
||||||
for (j = 0; j < oface; j++)
|
for (j = 0; j < oface; j++)
|
||||||
|
@ -6215,13 +6351,14 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
|
||||||
|
|
||||||
if (brush->patch)
|
if (brush->patch)
|
||||||
{
|
{
|
||||||
out->patch = BZ_Malloc(sizeof(*out->patch)-sizeof(out->patch->verts) + sizeof(*out->patch->verts)*brush->patch->xpoints*brush->patch->ypoints);
|
out->patch = BZ_Malloc(sizeof(*out->patch)-sizeof(out->patch->cp) + sizeof(*out->patch->cp)*brush->patch->numcp[0]*brush->patch->numcp[1]);
|
||||||
memcpy(out->patch, brush->patch, sizeof(*out->patch)-sizeof(out->patch->verts) + sizeof(*out->patch->verts)*brush->patch->xpoints*brush->patch->ypoints);
|
memcpy(out->patch, brush->patch, sizeof(*out->patch)-sizeof(out->patch->cp) + sizeof(*out->patch->cp)*brush->patch->numcp[0]*brush->patch->numcp[1]);
|
||||||
|
|
||||||
numpoints = out->patch->xpoints*out->patch->ypoints;
|
numpoints = out->patch->numcp[0]*out->patch->numcp[1];
|
||||||
//FIXME: lightmap...
|
//FIXME: lightmap...
|
||||||
for (j = 0; j < numpoints; j++)
|
for (j = 0; j < numpoints; j++)
|
||||||
AddPointToBounds(out->patch->verts[j].v, out->mins, out->maxs);
|
AddPointToBounds(out->patch->cp[j].v, out->mins, out->maxs);
|
||||||
|
|
||||||
|
|
||||||
out->patch->tex->rebuild = true;
|
out->patch->tex->rebuild = true;
|
||||||
}
|
}
|
||||||
|
@ -6275,29 +6412,32 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static brushes_t *Terr_Patch_Insert(model_t *model, heightmap_t *hm, brushtex_t *patch_tex, int patch_w, int patch_h, struct patchvert_s *patch_v, int stride)
|
static brushes_t *Terr_Patch_Insert(model_t *model, heightmap_t *hm, brushtex_t *patch_tex, unsigned patch_w, unsigned patch_h, unsigned subdiv_w, unsigned subdiv_h, qcpatchvert_t *patch_v, int stride)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
brushes_t brush;
|
brushes_t brush;
|
||||||
//finish the brush
|
//finish the brush
|
||||||
brush.contents = 0;
|
brush.contents = FTECONTENTS_SOLID;
|
||||||
brush.numplanes = 0;
|
brush.numplanes = 0;
|
||||||
brush.planes = NULL;
|
brush.planes = NULL;
|
||||||
brush.faces = NULL;
|
brush.faces = NULL;
|
||||||
brush.id = 0;
|
brush.id = 0;
|
||||||
brush.patch = alloca(sizeof(*brush.patch)-sizeof(brush.patch->verts) + sizeof(*brush.patch->verts)*patch_w*patch_h);
|
brush.patch = alloca(sizeof(*brush.patch)-sizeof(brush.patch->cp) + sizeof(*brush.patch->cp)*patch_w*patch_h);
|
||||||
|
|
||||||
brush.patch->tex = patch_tex;
|
brush.patch->tex = patch_tex;
|
||||||
brush.patch->xpoints = patch_w;
|
brush.patch->numcp[0] = patch_w;
|
||||||
brush.patch->ypoints = patch_h;
|
brush.patch->numcp[1] = patch_h;
|
||||||
|
brush.patch->subdiv[0] = subdiv_w;
|
||||||
|
brush.patch->subdiv[1] = subdiv_h;
|
||||||
|
brush.patch->tessvert = NULL;
|
||||||
|
|
||||||
for (y = 0; y < patch_h; y++)
|
for (y = 0; y < patch_h; y++)
|
||||||
{
|
{
|
||||||
for (x = 0; x < patch_w; x++)
|
for (x = 0; x < patch_w; x++)
|
||||||
{
|
{
|
||||||
VectorCopy(patch_v[x].v, brush.patch->verts[x + y*patch_w].v);
|
VectorCopy(patch_v[x].v, brush.patch->cp[x + y*patch_w].v);
|
||||||
Vector2Copy(patch_v[x].tc, brush.patch->verts[x + y*patch_w].tc);
|
Vector2Copy(patch_v[x].tc, brush.patch->cp[x + y*patch_w].tc);
|
||||||
Vector4Copy(patch_v[x].rgba, brush.patch->verts[x + y*patch_w].rgba);
|
Vector4Copy(patch_v[x].rgba, brush.patch->cp[x + y*patch_w].rgba);
|
||||||
//brush.patch->verts[x + y*patch_w].norm
|
//brush.patch->verts[x + y*patch_w].norm
|
||||||
//brush.patch->verts[x + y*patch_w].sdir
|
//brush.patch->verts[x + y*patch_w].sdir
|
||||||
//brush.patch->verts[x + y*patch_w].tdir
|
//brush.patch->verts[x + y*patch_w].tdir
|
||||||
|
@ -6396,6 +6536,7 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br)
|
||||||
br->planes[i][2] = MSG_ReadFloat();
|
br->planes[i][2] = MSG_ReadFloat();
|
||||||
br->planes[i][3] = MSG_ReadFloat();
|
br->planes[i][3] = MSG_ReadFloat();
|
||||||
|
|
||||||
|
//FIXME: can we optimise this part? a flag to say whether its needed?
|
||||||
br->faces[i].stdir[0][0] = MSG_ReadFloat();
|
br->faces[i].stdir[0][0] = MSG_ReadFloat();
|
||||||
br->faces[i].stdir[0][1] = MSG_ReadFloat();
|
br->faces[i].stdir[0][1] = MSG_ReadFloat();
|
||||||
br->faces[i].stdir[0][2] = MSG_ReadFloat();
|
br->faces[i].stdir[0][2] = MSG_ReadFloat();
|
||||||
|
@ -6409,6 +6550,89 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Patch_Serialise(sizebuf_t *sb, brushes_t *br)
|
||||||
|
{
|
||||||
|
qbyte flags = 0;
|
||||||
|
unsigned int i, m = br->patch->numcp[0]*br->patch->numcp[1];
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++)
|
||||||
|
{
|
||||||
|
if (br->patch->cp[i].rgba[0] != 1)
|
||||||
|
flags |= 1;
|
||||||
|
if (br->patch->cp[i].rgba[1] != 1)
|
||||||
|
flags |= 2;
|
||||||
|
if (br->patch->cp[i].rgba[2] != 1)
|
||||||
|
flags |= 4;
|
||||||
|
if (br->patch->cp[i].rgba[3] != 1)
|
||||||
|
flags |= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG_WriteLong(sb, br->id);
|
||||||
|
MSG_WriteByte(sb, flags);
|
||||||
|
|
||||||
|
MSG_WriteLong(sb, br->contents);
|
||||||
|
MSG_WriteString(sb, br->patch->tex->shadername);
|
||||||
|
MSG_WriteShort(sb, br->patch->numcp[0]);
|
||||||
|
MSG_WriteShort(sb, br->patch->numcp[1]);
|
||||||
|
MSG_WriteShort(sb, br->patch->subdiv[0]);
|
||||||
|
MSG_WriteShort(sb, br->patch->subdiv[1]);
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++)
|
||||||
|
{
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].v[0]);
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].v[1]);
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].v[2]);
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].tc[0]);
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].tc[1]);
|
||||||
|
|
||||||
|
if (flags&1)
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].rgba[0]);
|
||||||
|
if (flags&2)
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].rgba[1]);
|
||||||
|
if (flags&4)
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].rgba[2]);
|
||||||
|
if (flags&8)
|
||||||
|
MSG_WriteFloat(sb, br->patch->cp[i].rgba[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static qboolean Patch_Deserialise(heightmap_t *hm, brushes_t *br)
|
||||||
|
{
|
||||||
|
struct patchcpvert_s vert;
|
||||||
|
qboolean flags;
|
||||||
|
unsigned int i, maxverts = br->patch->numcp[0]*br->patch->numcp[1];
|
||||||
|
br->id = MSG_ReadLong();
|
||||||
|
flags = MSG_ReadByte();
|
||||||
|
|
||||||
|
br->contents = MSG_ReadLong();
|
||||||
|
|
||||||
|
//FIXME: as a server, we probably want to reject the brush if we exceed some texnum/memory limitation, so clients can't just spam new textures endlessly.
|
||||||
|
br->patch->tex = Terr_Brush_FindTexture(hm, MSG_ReadString());
|
||||||
|
|
||||||
|
br->patch->numcp[0] = MSG_ReadShort();
|
||||||
|
br->patch->numcp[1] = MSG_ReadShort();
|
||||||
|
br->patch->subdiv[0] = MSG_ReadShort();
|
||||||
|
br->patch->subdiv[1] = MSG_ReadShort();
|
||||||
|
|
||||||
|
for (i = 0; i < br->patch->numcp[0]*br->patch->numcp[1]; i++)
|
||||||
|
{
|
||||||
|
vert.v[0] = MSG_ReadFloat();
|
||||||
|
vert.v[1] = MSG_ReadFloat();
|
||||||
|
vert.v[2] = MSG_ReadFloat();
|
||||||
|
vert.tc[0] = MSG_ReadFloat();
|
||||||
|
vert.tc[1] = MSG_ReadFloat();
|
||||||
|
|
||||||
|
vert.rgba[0] = (flags&1)?MSG_ReadFloat():1;
|
||||||
|
vert.rgba[1] = (flags&2)?MSG_ReadFloat():1;
|
||||||
|
vert.rgba[2] = (flags&4)?MSG_ReadFloat():1;
|
||||||
|
vert.rgba[3] = (flags&8)?MSG_ReadFloat():1;
|
||||||
|
|
||||||
|
if (i < maxverts)
|
||||||
|
br->patch->cp[i] = vert;
|
||||||
|
}
|
||||||
|
return i <= maxverts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef SERVERONLY
|
#ifndef SERVERONLY
|
||||||
heightmap_t *CL_BrushEdit_ForceContext(model_t *mod)
|
heightmap_t *CL_BrushEdit_ForceContext(model_t *mod)
|
||||||
{
|
{
|
||||||
|
@ -6454,18 +6678,30 @@ void CL_Parse_BrushEdit(void)
|
||||||
return; //ignore if we're the server, we should already have it anyway.
|
return; //ignore if we're the server, we should already have it anyway.
|
||||||
Terr_Brush_DeleteId(hm, id);
|
Terr_Brush_DeleteId(hm, id);
|
||||||
}
|
}
|
||||||
else if (cmd == hmcmd_brush_insert) //1=create/replace
|
else if (cmd == hmcmd_brush_insert || cmd == hmcmd_patch_insert) //1=create/replace
|
||||||
{
|
{
|
||||||
brushes_t brush;
|
brushes_t brush;
|
||||||
|
|
||||||
hm = CL_BrushEdit_ForceContext(mod); //do this early, to ensure that the textures are correct
|
hm = CL_BrushEdit_ForceContext(mod); //do this early, to ensure that the textures are correct
|
||||||
|
|
||||||
memset(&brush, 0, sizeof(brush));
|
memset(&brush, 0, sizeof(brush));
|
||||||
|
if (cmd == hmcmd_patch_insert)
|
||||||
|
{
|
||||||
|
const unsigned int maxpoints = 64*64;
|
||||||
|
brush.patch = alloca(sizeof(*brush.patch) + sizeof(*brush.patch->cp)*(maxpoints-countof(brush.patch->cp)));
|
||||||
|
brush.patch->numcp[0] = 1;
|
||||||
|
brush.patch->numcp[1] = maxpoints;
|
||||||
|
if (!Patch_Deserialise(hm, &brush))
|
||||||
|
Host_EndGame("CL_Parse_BrushEdit: unparsable patch\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
brush.numplanes = 128;
|
brush.numplanes = 128;
|
||||||
brush.planes = alloca(sizeof(*brush.planes) * brush.numplanes);
|
brush.planes = alloca(sizeof(*brush.planes) * brush.numplanes);
|
||||||
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
|
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
|
||||||
if (!Brush_Deserialise(hm, &brush))
|
if (!Brush_Deserialise(hm, &brush))
|
||||||
Host_EndGame("CL_Parse_BrushEdit: unparsable brush\n");
|
Host_EndGame("CL_Parse_BrushEdit: unparsable brush\n");
|
||||||
|
}
|
||||||
if (ignore)
|
if (ignore)
|
||||||
return; //ignore if we're the server, we should already have it anyway (but might need it for demos, hence why its still sent).
|
return; //ignore if we're the server, we should already have it anyway (but might need it for demos, hence why its still sent).
|
||||||
if (brush.id)
|
if (brush.id)
|
||||||
|
@ -6600,8 +6836,16 @@ qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned
|
||||||
{
|
{
|
||||||
MSG_WriteByte(msg, svcfte_brushedit);
|
MSG_WriteByte(msg, svcfte_brushedit);
|
||||||
MSG_WriteShort(msg, *modelindex);
|
MSG_WriteShort(msg, *modelindex);
|
||||||
|
if (best->patch)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(msg, hmcmd_patch_insert);
|
||||||
|
Patch_Serialise(msg, best);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
MSG_WriteByte(msg, hmcmd_brush_insert);
|
MSG_WriteByte(msg, hmcmd_brush_insert);
|
||||||
Brush_Serialise(msg, best);
|
Brush_Serialise(msg, best);
|
||||||
|
}
|
||||||
*lastid = bestid;
|
*lastid = bestid;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6634,10 +6878,25 @@ qboolean SV_Parse_BrushEdit(void)
|
||||||
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd == hmcmd_brush_insert)
|
else if (cmd == hmcmd_brush_insert || cmd == hmcmd_patch_insert)
|
||||||
{
|
{
|
||||||
brushes_t brush;
|
brushes_t brush;
|
||||||
memset(&brush, 0, sizeof(brush));
|
memset(&brush, 0, sizeof(brush));
|
||||||
|
if (cmd == hmcmd_patch_insert)
|
||||||
|
{
|
||||||
|
const unsigned int maxpoints = 64*64;
|
||||||
|
brush.patch = alloca(sizeof(*brush.patch) + sizeof(*brush.patch->cp)*(maxpoints-countof(brush.patch->cp)));
|
||||||
|
memset(brush.patch, 0, sizeof(*brush.patch));
|
||||||
|
brush.patch->numcp[0] = maxpoints;
|
||||||
|
brush.patch->numcp[1] = 1;
|
||||||
|
if (!Patch_Deserialise(hm, &brush))
|
||||||
|
{
|
||||||
|
Con_Printf("SV_Parse_BrushEdit: %s sent an unparsable patch\n", host_client->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
brush.numplanes = 128;
|
brush.numplanes = 128;
|
||||||
brush.planes = alloca(sizeof(*brush.planes) * brush.numplanes);
|
brush.planes = alloca(sizeof(*brush.planes) * brush.numplanes);
|
||||||
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
|
brush.faces = alloca(sizeof(*brush.faces) * brush.numplanes);
|
||||||
|
@ -6646,6 +6905,7 @@ qboolean SV_Parse_BrushEdit(void)
|
||||||
Con_Printf("SV_Parse_BrushEdit: %s sent an unparsable brush\n", host_client->name);
|
Con_Printf("SV_Parse_BrushEdit: %s sent an unparsable brush\n", host_client->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!authorise)
|
if (!authorise)
|
||||||
{
|
{
|
||||||
SV_PrintToClient(host_client, PRINT_MEDIUM, "Brush editing ignored: you are not a mapper\n");
|
SV_PrintToClient(host_client, PRINT_MEDIUM, "Brush editing ignored: you are not a mapper\n");
|
||||||
|
@ -6660,7 +6920,10 @@ qboolean SV_Parse_BrushEdit(void)
|
||||||
|
|
||||||
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
|
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
|
||||||
MSG_WriteShort(&sv.multicast, modelindex);
|
MSG_WriteShort(&sv.multicast, modelindex);
|
||||||
MSG_WriteByte(&sv.multicast, hmcmd_brush_insert);
|
MSG_WriteByte(&sv.multicast, cmd);
|
||||||
|
if (cmd == hmcmd_patch_insert)
|
||||||
|
Patch_Serialise(&sv.multicast, &brush);
|
||||||
|
else
|
||||||
Brush_Serialise(&sv.multicast, &brush);
|
Brush_Serialise(&sv.multicast, &brush);
|
||||||
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
||||||
return true;
|
return true;
|
||||||
|
@ -6701,7 +6964,7 @@ qboolean SV_Parse_BrushEdit(void)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int shadername;
|
string_t shadername;
|
||||||
vec3_t planenormal;
|
vec3_t planenormal;
|
||||||
float planedist;
|
float planedist;
|
||||||
vec3_t sdir;
|
vec3_t sdir;
|
||||||
|
@ -6710,6 +6973,17 @@ typedef struct
|
||||||
float tbias;
|
float tbias;
|
||||||
} qcbrushface_t;
|
} qcbrushface_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
string_t shadername;
|
||||||
|
unsigned int contents;
|
||||||
|
unsigned int cp_width;
|
||||||
|
unsigned int cp_height;
|
||||||
|
unsigned int subdiv_x;
|
||||||
|
unsigned int subdiv_y;
|
||||||
|
vec3_t texinfo;
|
||||||
|
} qcpatchinfo_t;
|
||||||
|
|
||||||
static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elementsize, size_t elementcount, qboolean allownull)
|
static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elementsize, size_t elementcount, qboolean allownull)
|
||||||
{
|
{
|
||||||
//make sure that the sizes can't overflow
|
//make sure that the sizes can't overflow
|
||||||
|
@ -6731,6 +7005,124 @@ static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elem
|
||||||
}
|
}
|
||||||
return prinst->stringtable + qcptr;
|
return prinst->stringtable + qcptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {"patch_getcp", PF_patch_getcp, 0, 0, 0, 0, D(qcpatchvert "int(float modelidx, int patchid, patchvert_t *out_controlverts, int maxcp, __out patchinfo_t out_info)", "Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error.")},
|
||||||
|
void QCBUILTIN PF_patch_getcp(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
{
|
||||||
|
world_t *vmw = prinst->parms->user;
|
||||||
|
model_t *mod = vmw->Get_CModel(vmw, G_FLOAT(OFS_PARM0));
|
||||||
|
heightmap_t *hm = mod?mod->terrain:NULL;
|
||||||
|
unsigned int patchid = G_INT(OFS_PARM1);
|
||||||
|
unsigned int maxverts = G_INT(OFS_PARM3);
|
||||||
|
qcpatchvert_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*out_verts), maxverts, true);
|
||||||
|
qcpatchinfo_t *out_info = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_info), 1, true);
|
||||||
|
unsigned int i, j;
|
||||||
|
brushes_t *br;
|
||||||
|
|
||||||
|
//assume the worst.
|
||||||
|
G_INT(OFS_RETURN) = 0;
|
||||||
|
if (out_info)
|
||||||
|
memset(out_info, 0, sizeof(*out_info));
|
||||||
|
|
||||||
|
if (!hm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < hm->numbrushes; i++)
|
||||||
|
{
|
||||||
|
br = &hm->wbrushes[i];
|
||||||
|
if (br->id == patchid)
|
||||||
|
{
|
||||||
|
if (!br->patch)
|
||||||
|
return;
|
||||||
|
if (out_info)
|
||||||
|
{
|
||||||
|
out_info->contents = br->contents;
|
||||||
|
out_info->cp_width = br->patch->numcp[0];
|
||||||
|
out_info->cp_height = br->patch->numcp[1];
|
||||||
|
out_info->subdiv_x = br->patch->subdiv[0];
|
||||||
|
out_info->subdiv_y = br->patch->subdiv[1];
|
||||||
|
out_info->shadername = PR_TempString(prinst, br->patch->tex->shadername);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out_verts)
|
||||||
|
G_INT(OFS_RETURN) = br->patch->numcp[0]*br->patch->numcp[1];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxverts = min(br->numplanes, maxverts);
|
||||||
|
|
||||||
|
for (j = 0; j < br->patch->numcp[0]*br->patch->numcp[1]; j++)
|
||||||
|
{
|
||||||
|
VectorCopy(br->patch->cp[j].v, out_verts->v);
|
||||||
|
Vector2Copy(br->patch->cp[j].tc, out_verts->tc);
|
||||||
|
Vector4Copy(br->patch->cp[j].rgba, out_verts->rgba);
|
||||||
|
|
||||||
|
out_verts++;
|
||||||
|
}
|
||||||
|
G_INT(OFS_RETURN) = j;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// {"patch_getmesh", PF_patch_getmesh, 0, 0, 0, 0, D("int(float modelidx, int patchid, patchvert_t *out_verts, int maxverts, __out patchinfo_t out_info)", "Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error.")},
|
||||||
|
void QCBUILTIN PF_patch_getmesh(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
{
|
||||||
|
world_t *vmw = prinst->parms->user;
|
||||||
|
model_t *mod = vmw->Get_CModel(vmw, G_FLOAT(OFS_PARM0));
|
||||||
|
heightmap_t *hm = mod?mod->terrain:NULL;
|
||||||
|
unsigned int patchid = G_INT(OFS_PARM1);
|
||||||
|
unsigned int maxverts = G_INT(OFS_PARM3);
|
||||||
|
qcpatchvert_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*out_verts), maxverts, true);
|
||||||
|
qcpatchinfo_t *out_info = validateqcpointer(prinst, G_INT(OFS_PARM4), sizeof(*out_info), 1, true);
|
||||||
|
unsigned int i, j;
|
||||||
|
brushes_t *br;
|
||||||
|
|
||||||
|
//assume the worst.
|
||||||
|
G_INT(OFS_RETURN) = 0;
|
||||||
|
if (out_info)
|
||||||
|
memset(out_info, 0, sizeof(*out_info));
|
||||||
|
|
||||||
|
if (!hm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < hm->numbrushes; i++)
|
||||||
|
{
|
||||||
|
br = &hm->wbrushes[i];
|
||||||
|
if (br->id == patchid)
|
||||||
|
{
|
||||||
|
if (!br->patch)
|
||||||
|
return;
|
||||||
|
if (out_info)
|
||||||
|
{
|
||||||
|
out_info->contents = br->contents;
|
||||||
|
out_info->cp_width = br->patch->numcp[0];
|
||||||
|
out_info->cp_height = br->patch->numcp[1];
|
||||||
|
out_info->subdiv_x = br->patch->subdiv[0];
|
||||||
|
out_info->subdiv_y = br->patch->subdiv[1];
|
||||||
|
out_info->shadername = PR_TempString(prinst, br->patch->tex->shadername);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out_verts)
|
||||||
|
G_INT(OFS_RETURN) = br->patch->tesssize[0]*br->patch->tesssize[1];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxverts = min(br->numplanes, maxverts);
|
||||||
|
|
||||||
|
for (j = 0; j < br->patch->tesssize[0]*br->patch->tesssize[1]; j++)
|
||||||
|
{
|
||||||
|
VectorCopy(br->patch->tessvert[j].v, out_verts->v);
|
||||||
|
Vector2Copy(br->patch->tessvert[j].tc, out_verts->tc);
|
||||||
|
Vector4Copy(br->patch->tessvert[j].rgba, out_verts->rgba);
|
||||||
|
|
||||||
|
out_verts++;
|
||||||
|
}
|
||||||
|
G_INT(OFS_RETURN) = j;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// {"brush_get", PF_brush_get, 0, 0, 0, 0, D(qcbrushface "int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents)", "Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error.")},
|
// {"brush_get", PF_brush_get, 0, 0, 0, 0, D(qcbrushface "int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents)", "Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error.")},
|
||||||
void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
|
@ -6757,6 +7149,8 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
||||||
br = &hm->wbrushes[i];
|
br = &hm->wbrushes[i];
|
||||||
if (br->id == brushid)
|
if (br->id == brushid)
|
||||||
{
|
{
|
||||||
|
if (br->patch)
|
||||||
|
return;
|
||||||
if (out_contents)
|
if (out_contents)
|
||||||
*out_contents = br->contents;
|
*out_contents = br->contents;
|
||||||
if (!out_faces)
|
if (!out_faces)
|
||||||
|
@ -6784,7 +7178,7 @@ void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// {"brush_create", PF_brush_create, 0, 0, 0, 0, D("int(float modelidx, brushface_t *in_faces, int numfaces, int contents)", "Inserts a new brush into the model. Return value is the new brush's id.")},
|
// {"brush_create", PF_brush_create, 0, 0, 0, 0, D("int(float modelidx, brushface_t *in_faces, int numfaces, int contents, optional int prevbrushid=0)", "Inserts a new brush into the model. Return value is the new brush's id.")},
|
||||||
void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
world_t *vmw = prinst->parms->user;
|
world_t *vmw = prinst->parms->user;
|
||||||
|
@ -6901,6 +7295,120 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//{"patch_create", PF_patch_create, 0, 0, 0, 0, D("int(float modelidx, int oldpatchid, patchvert_t *in_controlverts, patchinfo_t in_info)", "Inserts a new patch into the model. Return value is the new patch's id.")},
|
||||||
|
void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
|
{
|
||||||
|
world_t *vmw = prinst->parms->user;
|
||||||
|
int modelindex = G_FLOAT(OFS_PARM0);
|
||||||
|
model_t *mod = vmw->Get_CModel(vmw, modelindex);
|
||||||
|
heightmap_t *hm = mod?mod->terrain:NULL;
|
||||||
|
unsigned int brushid = G_INT(OFS_PARM1); //to simplify edits
|
||||||
|
qcpatchinfo_t *info = (qcpatchinfo_t*)&G_INT(OFS_PARM3);
|
||||||
|
unsigned int totalcp = info->cp_width*info->cp_width;
|
||||||
|
qcpatchvert_t *in_cverts = validateqcpointer(prinst, G_INT(OFS_PARM2), sizeof(*in_cverts), totalcp, false);
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
brushes_t brush, *nb;
|
||||||
|
|
||||||
|
G_INT(OFS_RETURN) = 0;
|
||||||
|
|
||||||
|
if (!hm)
|
||||||
|
{
|
||||||
|
if (mod && mod->loadstate == MLS_LOADING)
|
||||||
|
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
|
||||||
|
if (mod && mod->loadstate == MLS_LOADED)
|
||||||
|
{
|
||||||
|
char basename[MAX_QPATH];
|
||||||
|
COM_FileBase(mod->name, basename, sizeof(basename));
|
||||||
|
mod->terrain = Mod_LoadTerrainInfo(mod, basename, true);
|
||||||
|
hm = mod->terrain;
|
||||||
|
if (!hm)
|
||||||
|
return;
|
||||||
|
Terr_FinishTerrain(mod);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we're creating one that already exists, then assume that its a move.
|
||||||
|
if (brushid && Terr_Brush_DeleteId(hm, brushid))
|
||||||
|
{
|
||||||
|
#ifndef CLIENTONLY
|
||||||
|
if (sv.state && modelindex > 0)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
|
||||||
|
MSG_WriteShort(&sv.multicast, modelindex);
|
||||||
|
MSG_WriteByte(&sv.multicast, hmcmd_brush_delete);
|
||||||
|
MSG_WriteLong(&sv.multicast, brushid);
|
||||||
|
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifndef SERVERONLY
|
||||||
|
if (cls.state && modelindex > 0)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
|
||||||
|
MSG_WriteShort(&cls.netchan.message, modelindex);
|
||||||
|
MSG_WriteByte(&cls.netchan.message, hmcmd_brush_delete);
|
||||||
|
MSG_WriteLong(&cls.netchan.message, brushid);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
brush.patch = alloca(sizeof(*brush.patch) + sizeof(brush.patch->cp[0])*(totalcp-countof(brush.patch->cp)));
|
||||||
|
memset (brush.patch, 0, sizeof(*brush.patch) - sizeof(brush.patch->cp));
|
||||||
|
brush.patch->numcp[0] = info->cp_width;
|
||||||
|
brush.patch->numcp[1] = info->cp_height;
|
||||||
|
brush.patch->subdiv[0] = info->subdiv_x;
|
||||||
|
brush.patch->subdiv[1] = info->subdiv_y;
|
||||||
|
|
||||||
|
brush.patch->tex = Terr_Brush_FindTexture(hm, PR_GetString(prinst, info->shadername));
|
||||||
|
|
||||||
|
for (i = 0; i < totalcp; i++)
|
||||||
|
{
|
||||||
|
VectorCopy(in_cverts[i].v, brush.patch->cp[i].v);
|
||||||
|
Vector2Copy(in_cverts[i].tc, brush.patch->cp[i].tc);
|
||||||
|
Vector4Copy(in_cverts[i].rgba, brush.patch->cp[i].rgba);
|
||||||
|
}
|
||||||
|
|
||||||
|
//now emit it
|
||||||
|
brush.id = 0;
|
||||||
|
brush.contents = info->contents;
|
||||||
|
brush.numplanes = 0;
|
||||||
|
brush.planes = NULL;
|
||||||
|
if (info->cp_width > 1 && info->cp_width > 1)
|
||||||
|
{
|
||||||
|
nb = Terr_Brush_Insert(mod, hm, &brush);
|
||||||
|
if (nb)
|
||||||
|
{
|
||||||
|
G_INT(OFS_RETURN) = nb->id;
|
||||||
|
#ifndef CLIENTONLY
|
||||||
|
if (sv.state && modelindex > 0)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
|
||||||
|
MSG_WriteShort(&sv.multicast, modelindex);
|
||||||
|
MSG_WriteByte(&sv.multicast, hmcmd_brush_insert);
|
||||||
|
Brush_Serialise(&sv.multicast, nb);
|
||||||
|
SV_MulticastProtExt(vec3_origin, MULTICAST_ALL_R, ~0, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef SERVERONLY
|
||||||
|
if (cls.state && modelindex > 0)
|
||||||
|
{
|
||||||
|
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
|
||||||
|
MSG_WriteShort(&cls.netchan.message, modelindex);
|
||||||
|
MSG_WriteByte(&cls.netchan.message, hmcmd_brush_insert);
|
||||||
|
Brush_Serialise(&cls.netchan.message, nb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// {"brush_delete", PF_brush_delete, 0, 0, 0, 0, D("void(float modelidx, int brushid)", "Destroys the specified brush.")},
|
// {"brush_delete", PF_brush_delete, 0, 0, 0, 0, D("void(float modelidx, int brushid)", "Destroys the specified brush.")},
|
||||||
void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||||
{
|
{
|
||||||
|
@ -6965,12 +7473,20 @@ void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr
|
||||||
if (state >= 0)
|
if (state >= 0)
|
||||||
{
|
{
|
||||||
if (br->selected != state)
|
if (br->selected != state)
|
||||||
|
{
|
||||||
|
if (br->patch)
|
||||||
|
{
|
||||||
|
br->patch->tex->rebuild = true;
|
||||||
|
// br->patch->relight = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < br->numplanes; i++)
|
for (i = 0; i < br->numplanes; i++)
|
||||||
{
|
{
|
||||||
br->faces[i].tex->rebuild = true;
|
br->faces[i].tex->rebuild = true;
|
||||||
br->faces[i].relight = true;
|
br->faces[i].relight = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
br->selected = state;
|
br->selected = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7073,11 +7589,32 @@ void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
faceid--;
|
faceid--;
|
||||||
|
if (br->patch)
|
||||||
|
{
|
||||||
|
int w = br->patch->numcp[0];
|
||||||
|
int h = br->patch->numcp[1];
|
||||||
|
int x = faceid % (w-1);
|
||||||
|
int y = faceid / (w-1);
|
||||||
|
if (x >= w-1 || y >= h-1)
|
||||||
|
break;
|
||||||
|
if (maxpoints >= 1)
|
||||||
|
VectorCopy(br->patch->cp[(x+0)+(y+0)*w].v, out_verts[0]);
|
||||||
|
if (maxpoints >= 2)
|
||||||
|
VectorCopy(br->patch->cp[(x+1)+(y+0)*w].v, out_verts[1]);
|
||||||
|
if (maxpoints >= 3)
|
||||||
|
VectorCopy(br->patch->cp[(x+1)+(y+1)*w].v, out_verts[2]);
|
||||||
|
if (maxpoints >= 3)
|
||||||
|
VectorCopy(br->patch->cp[(x+0)+(y+1)*w].v, out_verts[3]);
|
||||||
|
p = min(4, maxpoints);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (faceid >= br->numplanes)
|
if (faceid >= br->numplanes)
|
||||||
break;
|
break;
|
||||||
maxpoints = min(maxpoints, br->faces[faceid].numpoints);
|
maxpoints = min(maxpoints, br->faces[faceid].numpoints);
|
||||||
for (p = 0; p < maxpoints; p++)
|
for (p = 0; p < maxpoints; p++)
|
||||||
VectorCopy(br->faces[faceid].points[p], out_verts[p]);
|
VectorCopy(br->faces[faceid].points[p], out_verts[p]);
|
||||||
|
}
|
||||||
G_INT(OFS_RETURN) = p;
|
G_INT(OFS_RETURN) = p;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -7147,40 +7684,56 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br)
|
||||||
if (br->patch)
|
if (br->patch)
|
||||||
{
|
{
|
||||||
qboolean hasrgba = false;
|
qboolean hasrgba = false;
|
||||||
for (y = 0; y < br->patch->ypoints*br->patch->xpoints; y++)
|
for (y = 0; y < br->patch->numcp[1]*br->patch->numcp[0]; y++)
|
||||||
{
|
{
|
||||||
if (br->patch->verts[y].rgba[0] != 1.0 || br->patch->verts[y].rgba[1] != 1.0 || br->patch->verts[y].rgba[2] != 1.0 || br->patch->verts[y].rgba[3] != 1.0)
|
if (br->patch->cp[y].rgba[0] != 1.0 || br->patch->cp[y].rgba[1] != 1.0 || br->patch->cp[y].rgba[2] != 1.0 || br->patch->cp[y].rgba[3] != 1.0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hasrgba = (y < br->patch->ypoints*br->patch->xpoints);
|
hasrgba = (y < br->patch->numcp[1]*br->patch->numcp[0]);
|
||||||
|
|
||||||
VFS_PRINTF(file, "\n\tpatchDef%s\n\t{\n\t\t\"%s\"\n\t\t( %u %u %.9g %.9g %.9g )\n\t\t(\n",
|
if (br->patch->subdiv[0]>=0 && br->patch->subdiv[1]>=0)
|
||||||
hasrgba?"WS":"2",
|
{
|
||||||
|
VFS_PRINTF(file, "\n\tpatchDef3%s\n\t{\n\t\t\"%s\"\n\t\t( %u %u %u %u %.9g %.9g %.9g )\n\t\t(\n",
|
||||||
|
hasrgba?"WS":"",
|
||||||
br->patch->tex?br->patch->tex->shadername:"",
|
br->patch->tex?br->patch->tex->shadername:"",
|
||||||
br->patch->xpoints/*width*/,
|
br->patch->numcp[0]/*width*/,
|
||||||
br->patch->ypoints/*height*/,
|
br->patch->numcp[1]/*height*/,
|
||||||
|
br->patch->subdiv[0]/*width*/,
|
||||||
|
br->patch->subdiv[1]/*height*/,
|
||||||
0.0/*rotation*/,
|
0.0/*rotation*/,
|
||||||
1.0/*xscale*/,
|
1.0/*xscale*/,
|
||||||
1.0/*yscale*/);
|
1.0/*yscale*/);
|
||||||
for (y = 0; y < br->patch->ypoints; y++)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VFS_PRINTF(file, "\n\tpatchDef2%s\n\t{\n\t\t\"%s\"\n\t\t( %u %u %.9g %.9g %.9g )\n\t\t(\n",
|
||||||
|
hasrgba?"WS":"",
|
||||||
|
br->patch->tex?br->patch->tex->shadername:"",
|
||||||
|
br->patch->numcp[0]/*width*/,
|
||||||
|
br->patch->numcp[1]/*height*/,
|
||||||
|
0.0/*rotation*/,
|
||||||
|
1.0/*xscale*/,
|
||||||
|
1.0/*yscale*/);
|
||||||
|
}
|
||||||
|
for (y = 0; y < br->patch->numcp[1]; y++)
|
||||||
{
|
{
|
||||||
VFS_PRINTF(file, "\t\t\t(\n");
|
VFS_PRINTF(file, "\t\t\t(\n");
|
||||||
for (x = 0; x < br->patch->xpoints; x++)
|
for (x = 0; x < br->patch->numcp[0]; x++)
|
||||||
{
|
{
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
if (hasrgba)
|
if (hasrgba)
|
||||||
fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g )\n";
|
fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g %.9g )\n";
|
||||||
else
|
else
|
||||||
fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g )\n"; //q3 compat.
|
fmt = "\t\t\t\t( %.9g %.9g %.9g %.9g %.9g )\n"; //q3 compat.
|
||||||
VFS_PRINTF(file, fmt, br->patch->verts[x + y*br->patch->xpoints].v[0],
|
VFS_PRINTF(file, fmt, br->patch->cp[x + y*br->patch->numcp[0]].v[0],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].v[1],
|
br->patch->cp[x + y*br->patch->numcp[0]].v[1],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].v[2],
|
br->patch->cp[x + y*br->patch->numcp[0]].v[2],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].tc[0],
|
br->patch->cp[x + y*br->patch->numcp[0]].tc[0],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].tc[1],
|
br->patch->cp[x + y*br->patch->numcp[0]].tc[1],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].rgba[0],
|
br->patch->cp[x + y*br->patch->numcp[0]].rgba[0],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].rgba[1],
|
br->patch->cp[x + y*br->patch->numcp[0]].rgba[1],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].rgba[2],
|
br->patch->cp[x + y*br->patch->numcp[0]].rgba[2],
|
||||||
br->patch->verts[x + y*br->patch->xpoints].rgba[3]);
|
br->patch->cp[x + y*br->patch->numcp[0]].rgba[3]);
|
||||||
}
|
}
|
||||||
VFS_PRINTF(file, "\t\t\t)\n");
|
VFS_PRINTF(file, "\t\t\t)\n");
|
||||||
}
|
}
|
||||||
|
@ -7209,7 +7762,7 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br)
|
||||||
);
|
);
|
||||||
|
|
||||||
//write the name - if it contains markup or control chars, or other weird glyphs then be sure to quote it.
|
//write the name - if it contains markup or control chars, or other weird glyphs then be sure to quote it.
|
||||||
//we could always quote it, but that can and will screw up some editor somewhere...
|
//we could unconditionally quote it, but that can and will screw up some editor somewhere (like trenchbroom...)
|
||||||
for (s = texname = br->faces[i].tex?br->faces[i].tex->shadername:""; *s; s++)
|
for (s = texname = br->faces[i].tex?br->faces[i].tex->shadername:""; *s; s++)
|
||||||
{
|
{
|
||||||
if (*s <= 32 || *s >= 127 || *s == '\\' || *s == '(' || *s == '[' || *s == '{' || *s == ')' || *s == ']' || *s == '}')
|
if (*s <= 32 || *s >= 127 || *s == '\\' || *s == '(' || *s == '[' || *s == '{' || *s == ')' || *s == ']' || *s == '}')
|
||||||
|
@ -7409,8 +7962,8 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
|
|
||||||
//patch info
|
//patch info
|
||||||
brushtex_t *patch_tex=NULL;
|
brushtex_t *patch_tex=NULL;
|
||||||
int patch_w=0, patch_h=0;
|
int patchsz[2], patchsubdiv[2];
|
||||||
struct patchvert_s patch_v[64][64];
|
qcpatchvert_t patch_v[64][64];
|
||||||
|
|
||||||
#ifdef RUNTIMELIGHTING
|
#ifdef RUNTIMELIGHTING
|
||||||
hm->entsdirty = true;
|
hm->entsdirty = true;
|
||||||
|
@ -7447,7 +8000,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
Terr_Brush_Insert(submod, subhm, &brush);
|
Terr_Brush_Insert(submod, subhm, &brush);
|
||||||
}
|
}
|
||||||
else if (patch_tex)
|
else if (patch_tex)
|
||||||
Terr_Patch_Insert(submod, subhm, patch_tex, patch_w, patch_h, patch_v[0], countof(patch_v[0]));
|
Terr_Patch_Insert(submod, subhm, patch_tex, patchsz[0], patchsz[1], patchsubdiv[0], patchsubdiv[1], patch_v[0], countof(patch_v[0]));
|
||||||
subhm->brushesedited = oe;
|
subhm->brushesedited = oe;
|
||||||
}
|
}
|
||||||
numplanes = 0;
|
numplanes = 0;
|
||||||
|
@ -7532,11 +8085,14 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") || !strcmp(token, "patchDefWS")))
|
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") ||
|
||||||
|
!strcmp(token, "patchDef2WS") || !strcmp(token, "patchDef3WS")))
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
qboolean patchdef3 = !strcmp(token, "patchDef3"); //fancy alternative with rgba colours per control point
|
qboolean patchdef3 = !!strchr(token, '3'); //explict tessellation info (doom3-like)
|
||||||
qboolean parsergba = !strcmp(token, "patchDefWS"); //fancy alternative with rgba colours per control point
|
qboolean parsergba = !!strstr(token, "WS"); //fancy alternative with rgba colours per control point
|
||||||
|
patchsz[0] = patchsz[1] = 0;
|
||||||
|
patchsubdiv[0] = patchsubdiv[1] = -1;
|
||||||
if (numplanes || patch_tex)
|
if (numplanes || patch_tex)
|
||||||
{
|
{
|
||||||
Con_Printf(CON_ERROR "%s: mixed patch+planes\n", mod->name);
|
Con_Printf(CON_ERROR "%s: mixed patch+planes\n", mod->name);
|
||||||
|
@ -7554,14 +8110,14 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
/*patch_w = atof(token);*/
|
/*patch_w = atof(token);*/
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
/*patch_h = atof(token);*/
|
/*patch_h = atof(token);*/
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
|
||||||
if (patchdef3)
|
if (patchdef3)
|
||||||
{
|
{
|
||||||
/*xsubdiv = atof(token);*/
|
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
/*ysubdiv = atof(token);*/
|
patchsubdiv[0] = atof(token);
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
|
patchsubdiv[1] = atof(token);
|
||||||
}
|
}
|
||||||
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
/*rotation = atof(token);*/
|
/*rotation = atof(token);*/
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
/*xscale = atof(token);*/
|
/*xscale = atof(token);*/
|
||||||
|
@ -7573,7 +8129,6 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
y = 0;
|
y = 0;
|
||||||
patch_w = patch_h = 0;
|
|
||||||
while (!strcmp(token, "("))
|
while (!strcmp(token, "("))
|
||||||
{
|
{
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
|
@ -7622,14 +8177,14 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
|
||||||
if (x < countof(patch_v[y])-1)
|
if (x < countof(patch_v[y])-1)
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
if (patch_w < x)
|
if (patchsz[0] < x)
|
||||||
patch_w = x;
|
patchsz[0] = x;
|
||||||
if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
if (y < countof(patch_v)-1)
|
if (y < countof(patch_v)-1)
|
||||||
y++;
|
y++;
|
||||||
}
|
}
|
||||||
patch_h = y;
|
patchsz[1] = y;
|
||||||
if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
||||||
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
|
||||||
if (strcmp(token, "}")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
if (strcmp(token, "}")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
|
||||||
|
|
|
@ -618,6 +618,7 @@ void Mod_Init (qboolean initial)
|
||||||
Cvar_Register(&mod_loadentfiles_dir, NULL);
|
Cvar_Register(&mod_loadentfiles_dir, NULL);
|
||||||
Cvar_Register(&temp_lit2support, NULL);
|
Cvar_Register(&temp_lit2support, NULL);
|
||||||
Cvar_Register (&r_meshpitch, "Gamecode");
|
Cvar_Register (&r_meshpitch, "Gamecode");
|
||||||
|
Cvar_Register (&r_meshroll, "Gamecode");
|
||||||
Cmd_AddCommandD("sv_saveentfile", Mod_SaveEntFile_f, "Dumps a copy of the map's entities to disk, so that it can be edited and used as a replacement for slightly customised maps.");
|
Cmd_AddCommandD("sv_saveentfile", Mod_SaveEntFile_f, "Dumps a copy of the map's entities to disk, so that it can be edited and used as a replacement for slightly customised maps.");
|
||||||
Cmd_AddCommandD("mod_showent", Mod_ShowEnt_f, "Allows you to quickly search through a map's entities.");
|
Cmd_AddCommandD("mod_showent", Mod_ShowEnt_f, "Allows you to quickly search through a map's entities.");
|
||||||
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);
|
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);
|
||||||
|
|
|
@ -271,18 +271,27 @@ typedef struct
|
||||||
struct patchdata_s
|
struct patchdata_s
|
||||||
{ //unlit, always...
|
{ //unlit, always...
|
||||||
brushtex_t *tex;
|
brushtex_t *tex;
|
||||||
unsigned short xpoints;
|
unsigned short numcp[2];
|
||||||
unsigned short ypoints;
|
short subdiv[2]; //<0=regular q3 patch, 0=cp-only, >0=fixed-tessellation.
|
||||||
struct
|
|
||||||
|
unsigned short tesssize[2];
|
||||||
|
struct patchtessvert_s
|
||||||
{
|
{
|
||||||
vec3_t v;
|
vec3_t v;
|
||||||
vec2_t tc;
|
vec2_t tc;
|
||||||
vec4_t rgba;
|
vec4_t rgba;
|
||||||
|
// vec3_t norm;
|
||||||
|
// vec3_t sdir;
|
||||||
|
// vec3_t tdir;
|
||||||
|
} *tessvert; //x+(y*tesssize[0])
|
||||||
|
|
||||||
vec3_t norm;
|
//control points
|
||||||
vec3_t sdir;
|
struct patchcpvert_s
|
||||||
vec3_t tdir;
|
{
|
||||||
} verts[1]; //x+(y*xpoints)
|
vec3_t v;
|
||||||
|
vec2_t tc;
|
||||||
|
vec4_t rgba;
|
||||||
|
} cp[1]; //x+(y*numcp[0]) extends past end of patchdata_s
|
||||||
} *patch; //if this is NULL, then its a regular brush. otherwise its a patch.
|
} *patch; //if this is NULL, then its a regular brush. otherwise its a patch.
|
||||||
struct brushface_s
|
struct brushface_s
|
||||||
{
|
{
|
||||||
|
|
|
@ -510,6 +510,26 @@ static void ExpandBuffer(struct http_dl_ctx_s *con, int quant)
|
||||||
con->bufferlen = newlen;
|
con->bufferlen = newlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int VFSError_To_HTTP(int vfserr)
|
||||||
|
{
|
||||||
|
switch(vfserr)
|
||||||
|
{
|
||||||
|
case VFS_ERROR_TRYLATER:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
case VFS_ERROR_UNSPECIFIED:
|
||||||
|
return 0; //don't know, no reason given.
|
||||||
|
case VFS_ERROR_EOF:
|
||||||
|
return HTTP_EOF;
|
||||||
|
case VFS_ERROR_DNSFAILURE:
|
||||||
|
return HTTP_DNSFAILURE;
|
||||||
|
case VFS_ERROR_WRONGCERT:
|
||||||
|
return HTTP_MITM;
|
||||||
|
case VFS_ERROR_UNTRUSTED:
|
||||||
|
return HTTP_UNTRUSTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static qboolean HTTP_DL_Work(struct dl_download *dl)
|
static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
{
|
{
|
||||||
struct http_dl_ctx_s *con = dl->ctx;
|
struct http_dl_ctx_s *con = dl->ctx;
|
||||||
|
@ -549,7 +569,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
if (!ammount)
|
if (!ammount)
|
||||||
return true;
|
return true;
|
||||||
if (ammount < 0)
|
if (ammount < 0)
|
||||||
|
{
|
||||||
|
dl->status = DL_FAILED;
|
||||||
|
dl->replycode = VFSError_To_HTTP(ammount);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ammount = send(con->sock, con->buffer, con->bufferused, 0);
|
ammount = send(con->sock, con->buffer, con->bufferused, 0);
|
||||||
|
|
||||||
|
@ -579,7 +603,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||||
if (!ammount)
|
if (!ammount)
|
||||||
return true;
|
return true;
|
||||||
if (ammount < 0)
|
if (ammount < 0)
|
||||||
|
{
|
||||||
|
dl->status = DL_FAILED;
|
||||||
|
dl->replycode = VFSError_To_HTTP(ammount);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ammount = recv(con->sock, con->buffer+con->bufferused, con->bufferlen-con->bufferused-15, 0);
|
ammount = recv(con->sock, con->buffer+con->bufferused, con->bufferlen-con->bufferused-15, 0);
|
||||||
if (!ammount)
|
if (!ammount)
|
||||||
|
|
|
@ -148,6 +148,14 @@ struct dl_download *DL_Create(const char *url);
|
||||||
qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl));
|
qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl));
|
||||||
void DL_Close(struct dl_download *dl);
|
void DL_Close(struct dl_download *dl);
|
||||||
void DL_DeThread(void);
|
void DL_DeThread(void);
|
||||||
|
|
||||||
|
//internal 'http' error codes.
|
||||||
|
#define HTTP_DNSFAILURE 900 //no ip known
|
||||||
|
#define HTTP_NORESPONSE 901 //tcp failure
|
||||||
|
#define HTTP_EOF 902 //unexpected eof
|
||||||
|
#define HTTP_MITM 903 //wrong cert
|
||||||
|
#define HTTP_UNTRUSTED 904 //unverifiable cert
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1904,6 +1904,9 @@ Emits a primitive statement, returning the var it places it's value in
|
||||||
*/
|
*/
|
||||||
static int QCC_ShouldConvert(QCC_type_t *from, etype_t wanted)
|
static int QCC_ShouldConvert(QCC_type_t *from, etype_t wanted)
|
||||||
{
|
{
|
||||||
|
if (from->type == ev_boolean)
|
||||||
|
from = from->parentclass;
|
||||||
|
|
||||||
/*no conversion needed*/
|
/*no conversion needed*/
|
||||||
if (from->type == wanted)
|
if (from->type == wanted)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2007,7 +2010,7 @@ static QCC_sref_t QCC_SupplyConversion(QCC_sref_t var, etype_t wanted, pbool fa
|
||||||
QCC_PR_ParsePrintSRef(WARN_LAXCAST, var);
|
QCC_PR_ParsePrintSRef(WARN_LAXCAST, var);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
QCC_PR_ParseErrorPrintSRef(ERR_TYPEMISMATCH, var, "Implicit type mismatch. Needed %s, got %s.", basictypenames[wanted], basictypenames[var.cast->type]);
|
QCC_PR_ParseErrorPrintSRef(ERR_TYPEMISMATCH, var, "Implicit type mismatch. Needed %s%s%s, got %s%s%s.", col_type,basictypenames[wanted],col_none, col_type,basictypenames[var.cast->type],col_none);
|
||||||
}
|
}
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
@ -7070,11 +7073,11 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func,
|
||||||
QCC_ForceUnFreeDef(fparm.sym);
|
QCC_ForceUnFreeDef(fparm.sym);
|
||||||
}
|
}
|
||||||
fparm.ofs = ofs;
|
fparm.ofs = ofs;
|
||||||
if (!fparm.ofs)
|
// if (!fparm.ofs)
|
||||||
{
|
// {
|
||||||
args[parm].firststatement = numstatements;
|
args[parm].firststatement = numstatements;
|
||||||
args[parm].ref = fparm;
|
args[parm].ref = fparm;
|
||||||
}
|
// }
|
||||||
parm++;
|
parm++;
|
||||||
|
|
||||||
if (ofs+asz == arglist[i]->cast->size)
|
if (ofs+asz == arglist[i]->cast->size)
|
||||||
|
@ -9187,7 +9190,7 @@ fieldarrayindex:
|
||||||
|
|
||||||
if (arraysize && makearraypointers)
|
if (arraysize && makearraypointers)
|
||||||
{
|
{
|
||||||
QCC_PR_ParseWarning(0, "Is this still needed?");
|
// QCC_PR_ParseWarning(0, "Is this still needed?"); //yes, when passing the head of an array to a function that takes a pointer
|
||||||
r = QCC_PR_GenerateAddressOf(retbuf, r);
|
r = QCC_PR_GenerateAddressOf(retbuf, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9200,6 +9203,13 @@ QCC_sref_t QCC_PR_GenerateVector(QCC_sref_t x, QCC_sref_t y, QCC_sref_t z)
|
||||||
{
|
{
|
||||||
QCC_sref_t d;
|
QCC_sref_t d;
|
||||||
|
|
||||||
|
if (x.cast->type != ev_float && x.cast->type != ev_integer)
|
||||||
|
x = QCC_EvaluateCast(x, type_float, true);
|
||||||
|
if (y.cast->type != ev_float && y.cast->type != ev_integer)
|
||||||
|
y = QCC_EvaluateCast(y, type_float, true);
|
||||||
|
if (z.cast->type != ev_float && z.cast->type != ev_integer)
|
||||||
|
z = QCC_EvaluateCast(z, type_float, true);
|
||||||
|
|
||||||
if ((x.cast->type != ev_float && x.cast->type != ev_integer) ||
|
if ((x.cast->type != ev_float && x.cast->type != ev_integer) ||
|
||||||
(y.cast->type != ev_float && y.cast->type != ev_integer) ||
|
(y.cast->type != ev_float && y.cast->type != ev_integer) ||
|
||||||
(z.cast->type != ev_float && z.cast->type != ev_integer))
|
(z.cast->type != ev_float && z.cast->type != ev_integer))
|
||||||
|
@ -14800,7 +14810,7 @@ static pbool QCC_CheckUninitialised(int firststatement, int laststatement)
|
||||||
err = QCC_CheckOneUninitialised(firststatement, laststatement, local, local->ofs, local->ofs + local->type->size * (local->arraysize?local->arraysize:1));
|
err = QCC_CheckOneUninitialised(firststatement, laststatement, local, local->ofs, local->ofs + local->type->size * (local->arraysize?local->arraysize:1));
|
||||||
if (err > 0)
|
if (err > 0)
|
||||||
{
|
{
|
||||||
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s", local->name);
|
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s%s%s", col_symbol,local->name,col_none);
|
||||||
result = true;
|
result = true;
|
||||||
// break;
|
// break;
|
||||||
}
|
}
|
||||||
|
@ -17271,10 +17281,16 @@ QCC_sref_t QCC_PR_ParseInitializerType_Internal(int arraysize, QCC_def_t *basede
|
||||||
QCC_sref_t QCC_PR_ParseInitializerTemp(QCC_type_t *type)
|
QCC_sref_t QCC_PR_ParseInitializerTemp(QCC_type_t *type)
|
||||||
{
|
{
|
||||||
QCC_sref_t def = QCC_GetTemp(type);
|
QCC_sref_t def = QCC_GetTemp(type);
|
||||||
def = QCC_PR_ParseInitializerType_Internal(0, NULL, def, 0);
|
QCC_sref_t imm;
|
||||||
if (def.cast != type)
|
imm = QCC_PR_ParseInitializerType_Internal(0, NULL, def, 0);
|
||||||
|
if (imm.cast)
|
||||||
|
{
|
||||||
|
if (imm.cast != type)
|
||||||
QCC_PR_ParseError(ERR_INTERNAL, "QCC_PR_ParseInitializerTemp changed type\n");
|
QCC_PR_ParseError(ERR_INTERNAL, "QCC_PR_ParseInitializerTemp changed type\n");
|
||||||
return def;
|
QCC_FreeTemp(def);
|
||||||
|
return imm; //just use the immediate.
|
||||||
|
}
|
||||||
|
return def; //use our silly temp.
|
||||||
}
|
}
|
||||||
//returns true where its a const/static initialiser. false if non-const/final initialiser
|
//returns true where its a const/static initialiser. false if non-const/final initialiser
|
||||||
pbool QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def, unsigned int flags)
|
pbool QCC_PR_ParseInitializerType(int arraysize, QCC_def_t *basedef, QCC_sref_t def, unsigned int flags)
|
||||||
|
|
|
@ -343,11 +343,11 @@ compiler_flag_t compiler_flag[] = {
|
||||||
{&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."},
|
{&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."},
|
||||||
{&keyword_int, typekeyword, "int", "Keyword: int", "Disables the 'int' keyword."},
|
{&keyword_int, typekeyword, "int", "Keyword: int", "Disables the 'int' keyword."},
|
||||||
{&keyword_integer, typekeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."},
|
{&keyword_integer, typekeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."},
|
||||||
{&keyword_double, defaultkeyword, "double", "Keyword: double", "Disables the 'double' keyword."},
|
{&keyword_double, nondefaultkeyword, "double", "Keyword: double", "Disables the 'double' keyword."},
|
||||||
{&keyword_long, defaultkeyword, "long", "Keyword: long", "Disables the 'long' keyword."},
|
{&keyword_long, nondefaultkeyword, "long", "Keyword: long", "Disables the 'long' keyword."},
|
||||||
{&keyword_short, defaultkeyword, "short", "Keyword: short", "Disables the 'short' keyword."},
|
{&keyword_short, nondefaultkeyword, "short", "Keyword: short", "Disables the 'short' keyword."},
|
||||||
{&keyword_char, defaultkeyword, "char", "Keyword: char", "Disables the 'char' keyword."},
|
{&keyword_char, nondefaultkeyword, "char", "Keyword: char", "Disables the 'char' keyword."},
|
||||||
{&keyword_signed, defaultkeyword, "signed", "Keyword: signed", "Disables the 'signed' keyword."},
|
{&keyword_signed, nondefaultkeyword, "signed", "Keyword: signed", "Disables the 'signed' keyword."},
|
||||||
{&keyword_unsigned, defaultkeyword, "unsigned", "Keyword: unsigned", "Disables the 'unsigned' keyword."},
|
{&keyword_unsigned, defaultkeyword, "unsigned", "Keyword: unsigned", "Disables the 'unsigned' keyword."},
|
||||||
{&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't warn about it.
|
{&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't warn about it.
|
||||||
{&keyword_unused, nondefaultkeyword, "unused", "Keyword: unused", "Disables the 'unused' keyword. 'unused' means that the variable is unused, you're aware that its unused, and you'd rather not know about all the warnings this results in."},
|
{&keyword_unused, nondefaultkeyword, "unused", "Keyword: unused", "Disables the 'unused' keyword. 'unused' means that the variable is unused, you're aware that its unused, and you'd rather not know about all the warnings this results in."},
|
||||||
|
@ -4335,6 +4335,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
|
||||||
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
|
keyword_vector = keyword_entity = keyword_float = keyword_string = false; //not to be confused with actual types, but rather the absence of the keyword local.
|
||||||
keyword_integer = keyword_enumflags = false;
|
keyword_integer = keyword_enumflags = false;
|
||||||
keyword_float = keyword_int = keyword_typedef = keyword_struct = keyword_union = keyword_enum = true;
|
keyword_float = keyword_int = keyword_typedef = keyword_struct = keyword_union = keyword_enum = true;
|
||||||
|
keyword_double = keyword_long = keyword_short = keyword_char = keyword_signed = keyword_unsigned = true;
|
||||||
keyword_thinktime = keyword_until = keyword_loop = false;
|
keyword_thinktime = keyword_until = keyword_loop = false;
|
||||||
|
|
||||||
keyword_integer = true;
|
keyword_integer = true;
|
||||||
|
|
|
@ -3006,7 +3006,8 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m)
|
||||||
// if it is an inline model, get the size information for it
|
// if it is an inline model, get the size information for it
|
||||||
if (m && (m[0] == '*' || (*m&&progstype == PROG_H2)))
|
if (m && (m[0] == '*' || (*m&&progstype == PROG_H2)))
|
||||||
{
|
{
|
||||||
mod = Mod_ForName (Mod_FixName(m, sv.modelname), MLV_WARN);
|
mod = SVPR_GetCModel(&sv.world, i);
|
||||||
|
// mod = Mod_ForName (Mod_FixName(m, sv.modelname), MLV_WARN);
|
||||||
if (mod)
|
if (mod)
|
||||||
{
|
{
|
||||||
while(mod->loadstate == MLS_LOADING)
|
while(mod->loadstate == MLS_LOADING)
|
||||||
|
@ -3014,7 +3015,15 @@ void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m)
|
||||||
|
|
||||||
VectorCopy (mod->mins, e->v->mins);
|
VectorCopy (mod->mins, e->v->mins);
|
||||||
VectorCopy (mod->maxs, e->v->maxs);
|
VectorCopy (mod->maxs, e->v->maxs);
|
||||||
VectorSubtract (mod->maxs, mod->mins, e->v->size);
|
#ifdef HEXEN2
|
||||||
|
if (progstype == PROG_H2 && mod->type == mod_alias && !sv_gameplayfix_setmodelrealbox.ival)
|
||||||
|
{ //hexen2 expands its mdls by 10
|
||||||
|
vec3_t hexen2expansion = {10,10,10};
|
||||||
|
VectorSubtract (mod->mins, hexen2expansion, e->v->mins);
|
||||||
|
VectorAdd (mod->maxs, hexen2expansion, e->v->maxs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
VectorSubtract (e->v->maxs, e->v->mins, e->v->size);
|
||||||
World_LinkEdict (&sv.world, (wedict_t*)e, false);
|
World_LinkEdict (&sv.world, (wedict_t*)e, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10985,7 +10994,7 @@ static 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(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.")},
|
{"infoadd", PF_infoadd, 0, 0, 0, 226, D("infostring(infostring old, string key, string value)", "Returns a new tempstring infostring with the named value changed (or added if it was previously unspecified). Key and value may not contain the \\ character.")},
|
||||||
{"infoget", PF_infoget, 0, 0, 0, 227, D("string(infostring info, string key)", "Reads a named value from an infostring. The returned value is a tempstring")},
|
{"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.")},
|
||||||
|
@ -11105,6 +11114,27 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
|
||||||
{"brush_findinvolume",PF_brush_findinvolume,0, 0, 0, 0, D("int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults)", "Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice.")},
|
{"brush_findinvolume",PF_brush_findinvolume,0, 0, 0, 0, D("int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults)", "Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice.")},
|
||||||
// {"brush_editplane", PF_brush_editplane, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, in brushface *face)", "Changes a surface's texture info.")},
|
// {"brush_editplane", PF_brush_editplane, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, in brushface *face)", "Changes a surface's texture info.")},
|
||||||
// {"brush_transformselected",PF_brush_transformselected,0,0,0, 0, D("int(float modelid, int brushid, float *matrix)", "Transforms selected brushes by the given transform")},
|
// {"brush_transformselected",PF_brush_transformselected,0,0,0, 0, D("int(float modelid, int brushid, float *matrix)", "Transforms selected brushes by the given transform")},
|
||||||
|
|
||||||
|
#define qcpatchvert \
|
||||||
|
"typedef struct\n{\n" \
|
||||||
|
"\tstring shadername;\n" \
|
||||||
|
"\tint contents;\n" \
|
||||||
|
"\tint cpwidth;\n" \
|
||||||
|
"\tint cpheight;\n" \
|
||||||
|
"\tint tesswidth;\n" \
|
||||||
|
"\tint tessheight;\n" \
|
||||||
|
"\tvector texinfo;/*scalex,y,rot*/\n" \
|
||||||
|
"} patchinfo_t;\n" \
|
||||||
|
"typedef struct\n{\n" \
|
||||||
|
"\tvector xyz;\n" \
|
||||||
|
"\tvector rgb; float a;\n" \
|
||||||
|
"\tfloat s, t;\n" \
|
||||||
|
"} patchvert_t;\n" \
|
||||||
|
"#define patch_delete(modelidx,patchidx) brush_delete(modelidx,patchidx)\n"
|
||||||
|
{"patch_getcp", PF_patch_getcp, 0, 0, 0, 0, D(qcpatchvert "int(float modelidx, int patchid, patchvert_t *out_controlverts, int maxcp, patchinfo_t *out_info)", "Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error.")},
|
||||||
|
{"patch_getmesh", PF_patch_getmesh, 0, 0, 0, 0, D("int(float modelidx, int patchid, patchvert_t *out_verts, int maxverts, __out patchinfo_t out_info)", "Queries a patch's information. You must pre-allocate the face array for the builtin to write to. Return value is the total number of control verts that were retrieved, 0 on error.")},
|
||||||
|
{"patch_create", PF_patch_create, 0, 0, 0, 0, D("int(float modelidx, int oldpatchid, patchvert_t *in_controlverts, patchinfo_t in_info)", "Inserts a new patch into the model. Return value is the new patch's id.")},
|
||||||
|
// {"patch_calculate", PF_patch_calculate, 0, 0, 0, 0, D("int(patchvert_t *in_controlverts, patchvert_t *out_renderverts, int maxout, __inout patchinfo_t inout_info)", "Calculates the geometry of a hyperthetical patch.")},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENGINE_ROUTING
|
#ifdef ENGINE_ROUTING
|
||||||
|
|
|
@ -163,7 +163,7 @@ cvar_t sv_csqc_progname = CVARAF("sv_csqc_progname", "csprogs.dat", /*dp*/"csqc_
|
||||||
cvar_t pausable = CVAR("pausable", "");
|
cvar_t pausable = CVAR("pausable", "");
|
||||||
cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies.");
|
cvar_t sv_banproxies = CVARD("sv_banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies.");
|
||||||
cvar_t sv_specprint = CVARD("sv_specprint", "3", "Bitfield that controls which player events spectators see when tracking that player.\n&1: spectators will see centerprints.\n&2: spectators will see sprints (pickup messages etc).\n&4: spectators will receive console commands, this is potentially risky.\nIndividual spectators can use 'setinfo sp foo' to limit this setting.");
|
cvar_t sv_specprint = CVARD("sv_specprint", "3", "Bitfield that controls which player events spectators see when tracking that player.\n&1: spectators will see centerprints.\n&2: spectators will see sprints (pickup messages etc).\n&4: spectators will receive console commands, this is potentially risky.\nIndividual spectators can use 'setinfo sp foo' to limit this setting.");
|
||||||
|
cvar_t sv_protocol = CVARD("sv_protocol", "", "Specifies which protocol extensions to force. recognised values: csqc");
|
||||||
|
|
||||||
//
|
//
|
||||||
// game rules mirrored in svs.info
|
// game rules mirrored in svs.info
|
||||||
|
@ -1945,6 +1945,56 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
|
||||||
extern cvar_t pr_maxedicts;
|
extern cvar_t pr_maxedicts;
|
||||||
client_t *seat;
|
client_t *seat;
|
||||||
|
|
||||||
|
extern cvar_t sv_protocol;
|
||||||
|
char *s = sv_protocol.string;
|
||||||
|
while ((s = COM_Parse(s)))
|
||||||
|
{
|
||||||
|
if (!strcasecmp(com_token, "fte2"))
|
||||||
|
{ //fancy stuff
|
||||||
|
client->fteprotocolextensions
|
||||||
|
|= PEXT_CSQC /*mods break without*/
|
||||||
|
| PEXT_CHUNKEDDOWNLOADS /*much faster downloads+redirects*/
|
||||||
|
;
|
||||||
|
client->fteprotocolextensions2
|
||||||
|
|= PEXT2_PRYDONCURSOR /*mods might break without*/
|
||||||
|
// | PEXT2_VOICECHAT /*entirely optional*/
|
||||||
|
| PEXT2_SETANGLEDELTA /*mostly just nice to have*/
|
||||||
|
| PEXT2_REPLACEMENTDELTAS /*carries quite a bit of extra info*/
|
||||||
|
| PEXT2_MAXPLAYERS /*not supporting the extra players is bad*/
|
||||||
|
| PEXT2_PREDINFO /*fixes some repdelta issues (especially for nq)*/
|
||||||
|
| PEXT2_NEWSIZEENCODING /*more accurate sizes, for awkward mods*/
|
||||||
|
| PEXT2_INFOBLOBS /*allows mods to send infoblobs to csqc (for avatar images or whatever)*/
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(com_token, "fte1"))
|
||||||
|
{ //older stuff. most of this was replaced by replacementdeltas.
|
||||||
|
client->fteprotocolextensions
|
||||||
|
|= PEXT_SETVIEW
|
||||||
|
| PEXT_SCALE
|
||||||
|
| PEXT_TRANS
|
||||||
|
| PEXT_ACCURATETIMINGS
|
||||||
|
| PEXT_SOUNDDBL
|
||||||
|
| PEXT_MODELDBL
|
||||||
|
| PEXT_ENTITYDBL
|
||||||
|
| PEXT_ENTITYDBL2
|
||||||
|
| PEXT_FLOATCOORDS
|
||||||
|
| PEXT_COLOURMOD
|
||||||
|
| PEXT_SPAWNSTATIC2
|
||||||
|
| PEXT_256PACKETENTITIES
|
||||||
|
| PEXT_SETATTACHMENT
|
||||||
|
| PEXT_CHUNKEDDOWNLOADS
|
||||||
|
| PEXT_CSQC
|
||||||
|
| PEXT_DPFLAGS
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if (!strcasecmp(com_token, "csqc"))
|
||||||
|
{ //JUST csqc.
|
||||||
|
client->fteprotocolextensions
|
||||||
|
|= PEXT_CSQC
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
client->fteprotocolextensions &= Net_PextMask(PROTOCOL_VERSION_FTE1, ISNQCLIENT(client));
|
client->fteprotocolextensions &= Net_PextMask(PROTOCOL_VERSION_FTE1, ISNQCLIENT(client));
|
||||||
client->fteprotocolextensions2 &= Net_PextMask(PROTOCOL_VERSION_FTE2, ISNQCLIENT(client));
|
client->fteprotocolextensions2 &= Net_PextMask(PROTOCOL_VERSION_FTE2, ISNQCLIENT(client));
|
||||||
client->ezprotocolextensions1 &= Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE;
|
client->ezprotocolextensions1 &= Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE;
|
||||||
|
@ -5408,6 +5458,7 @@ void SV_InitLocal (void)
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
sv_public.enginevalue = "1";
|
sv_public.enginevalue = "1";
|
||||||
|
|
||||||
|
Cvar_Register (&sv_protocol, cvargroup_servercontrol);
|
||||||
Cvar_Register (&sv_guidhash, cvargroup_servercontrol);
|
Cvar_Register (&sv_guidhash, cvargroup_servercontrol);
|
||||||
Cvar_Register (&sv_serverip, cvargroup_servercontrol);
|
Cvar_Register (&sv_serverip, cvargroup_servercontrol);
|
||||||
Cvar_Register (&sv_public, cvargroup_servercontrol);
|
Cvar_Register (&sv_public, cvargroup_servercontrol);
|
||||||
|
|
|
@ -323,8 +323,7 @@ float World_changeyaw (wedict_t *ent)
|
||||||
vec3_t vang;
|
vec3_t vang;
|
||||||
|
|
||||||
/*calc current view matrix relative to the surface*/
|
/*calc current view matrix relative to the surface*/
|
||||||
ent->v->angles[PITCH] *= r_meshpitch.value;
|
AngleVectorsMesh(ent->v->angles, view[0], view[1], view[2]);
|
||||||
AngleVectors(ent->v->angles, view[0], view[1], view[2]);
|
|
||||||
VectorNegate(view[1], view[1]);
|
VectorNegate(view[1], view[1]);
|
||||||
|
|
||||||
World_GetEntGravityAxis(ent, surf);
|
World_GetEntGravityAxis(ent, surf);
|
||||||
|
|
|
@ -151,6 +151,7 @@ SV_CheckVelocity
|
||||||
void WPhys_CheckVelocity (world_t *w, wedict_t *ent)
|
void WPhys_CheckVelocity (world_t *w, wedict_t *ent)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
#ifdef HAVE_SERVER
|
||||||
extern cvar_t sv_nqplayerphysics;
|
extern cvar_t sv_nqplayerphysics;
|
||||||
|
|
||||||
if (sv_nqplayerphysics.ival)
|
if (sv_nqplayerphysics.ival)
|
||||||
|
@ -175,6 +176,7 @@ void WPhys_CheckVelocity (world_t *w, wedict_t *ent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{ //bound radially (for sanity)
|
{ //bound radially (for sanity)
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,9 @@ void QDECL SV_NQPhysicsUpdate(cvar_t *var, char *oldvalue)
|
||||||
{
|
{
|
||||||
if (!strcmp(var->string, "auto") || !strcmp(var->string, ""))
|
if (!strcmp(var->string, "auto") || !strcmp(var->string, ""))
|
||||||
{ //prediction requires nq physics, so use it by default in multiplayer.
|
{ //prediction requires nq physics, so use it by default in multiplayer.
|
||||||
if (progstype <= PROG_QW || (!isDedicated && sv.allocated_client_slots > 1))
|
if ( progstype <= PROG_QW || //none or qw use qw physics by default
|
||||||
|
(!isDedicated && sv.allocated_client_slots > 1) || //multiplayer dedicated servers use qw physics for nq mods too. server admins are expected to be able to spend a little more time to configure things properly.
|
||||||
|
(svprogfuncs&&PR_FindFunction(svprogfuncs, "SV_RunClientCommand", PR_ANY))) //mods that use explicit custom player physics/pred ALWAYS want qw physics (just hope noone forces it off)
|
||||||
var->ival = 0;
|
var->ival = 0;
|
||||||
else
|
else
|
||||||
var->ival = 1;
|
var->ival = 1;
|
||||||
|
@ -1224,7 +1226,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
|
||||||
if (client->fteprotocolextensions & PEXT_SOUNDDBL)
|
if (client->fteprotocolextensions & PEXT_SOUNDDBL)
|
||||||
maxclientsupportedsounds = MAX_PRECACHE_SOUNDS;
|
maxclientsupportedsounds = MAX_PRECACHE_SOUNDS;
|
||||||
#endif
|
#endif
|
||||||
#ifdef PEXT_SOUNDDBL
|
#ifdef PEXT2_REPLACEMENTDELTAS
|
||||||
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
|
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
|
||||||
maxclientsupportedsounds = MAX_PRECACHE_SOUNDS;
|
maxclientsupportedsounds = MAX_PRECACHE_SOUNDS;
|
||||||
#endif
|
#endif
|
||||||
|
@ -6154,13 +6156,13 @@ void SV_Pext_f(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SV_ClientProtocolExtensionsChanged(host_client);
|
||||||
|
|
||||||
if (!host_client->supportedprotocols && Cmd_Argc() == 1)
|
if (!host_client->supportedprotocols && Cmd_Argc() == 1)
|
||||||
Con_DPrintf("%s reports no extended capabilities.\n", host_client->name);
|
Con_DPrintf("%s reports no extended capabilities.\n", host_client->name);
|
||||||
else
|
else
|
||||||
Con_DPrintf("%s now using pext: %x, %x, %x\n", host_client->name, host_client->fteprotocolextensions, host_client->fteprotocolextensions2, host_client->ezprotocolextensions1);
|
Con_DPrintf("%s now using pext: %x, %x, %x\n", host_client->name, host_client->fteprotocolextensions, host_client->fteprotocolextensions2, host_client->ezprotocolextensions1);
|
||||||
|
|
||||||
SV_ClientProtocolExtensionsChanged(host_client);
|
|
||||||
|
|
||||||
#ifdef NQPROT
|
#ifdef NQPROT
|
||||||
if (ISNQCLIENT(host_client))
|
if (ISNQCLIENT(host_client))
|
||||||
SVNQ_New_f();
|
SVNQ_New_f();
|
||||||
|
|
Loading…
Reference in a new issue