27 Aug 2010

This commit is contained in:
g-cont 2010-08-27 00:00:00 +04:00 committed by Alibek Omarov
parent 08114a7f78
commit 1010c2c5c1
12 changed files with 329 additions and 297 deletions

View File

@ -39,13 +39,6 @@ typedef enum
force_model_specifybounds, // for model files only, the geometry must fit in the specified bbox
} FORCE_TYPE;
typedef enum
{
AREA_SOLID, // find any solid edicts
AREA_TRIGGERS, // find all SOLID_TRIGGER edicts
AREA_CUSTOM, // find all edicts with custom contents - water, lava, fog, laders etc
} AREA_TYPE;
typedef struct
{
int fAllSolid; // if true, plane is not valid
@ -100,7 +93,7 @@ typedef struct enginefuncs_s
void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr );
void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr );
const char *(*pfnTraceTexture)( edict_t *pTextureEntity, const float *v1, const float *v2 );
int (*pfnAreaEdicts)( const float *mins, const float *maxs, edict_t **list, int maxcount, AREA_TYPE areatype ); // a part of CustomPhysics implementation
void (*pfnTraceSphere)( const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr );
void (*pfnGetAimVector)( edict_t* ent, float speed, float *rgflReturn );
void (*pfnServerCommand)( const char* str );
void (*pfnServerExecute)( void );

View File

@ -694,7 +694,15 @@ void StartFrame( void )
if ( g_fGameOver )
return;
#if 0
for( int i = 0; i < g_engfuncs.pfnNumberOfEntities(); i++ )
{
edict_t *ed = INDEXENT( i );
if( !ed ) continue;
ALERT( at_console, "Entity #%i, %s, headnode %i, num_leafs %i\n", i, STRING( ed->v.classname ), ed->headnode, ed->num_leafs );
}
#endif
gpGlobals->teamplay = teamplay->value;
g_ulFrameCount++;
}

View File

@ -880,6 +880,7 @@ class CMomentaryDoor : public CBaseToggle
public:
void Spawn( void );
void Precache( void );
void EXPORT MomentaryMoveDone( void );
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
@ -1021,6 +1022,13 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM);
LinearMove( move, speed );
SetMoveDone( MomentaryMoveDone );
}
}
void CMomentaryDoor::MomentaryMoveDone( void )
{
STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving));
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM);
}

View File

@ -97,7 +97,7 @@ void CItem::Spawn( void )
if (DROP_TO_FLOOR(ENT(pev)) == 0)
{
ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z);
ALERT(at_error, "Item %s fell out of level at %f,%f,%f\n", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z);
UTIL_Remove( this );
return;
}

View File

@ -137,6 +137,7 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
{
// Msg( "Entity %s was removed from delta-message\n", ent->curstate.classname );
ent->curstate.effects |= EF_NODRAW; // don't rendering
clgame.dllFuncs.pfnUpdateOnRemove( ent );
}
// entity was delta removed

View File

@ -24,6 +24,13 @@ ENTITY AREA CHECKING
#define AREA_NODES 32
#define AREA_DEPTH 4
typedef enum
{
AREA_SOLID, // find any solid edicts
AREA_TRIGGERS, // find all SOLID_TRIGGER edicts
AREA_CUSTOM, // find all edicts with custom contents - water, lava, fog, laders etc
} AREA_TYPE;
typedef struct areanode_s
{
int axis; // -1 = leaf node

View File

@ -452,7 +452,7 @@ void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
void SV_InitStudioHull( void );
bool SV_StudioExtractBbox( model_t *mod, int sequence, float *mins, float *maxs );
void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang );
bool SV_StudioTrace( edict_t *ent, const vec3_t p1, vec3_t mins, vec3_t maxs, const vec3_t p2, trace_t *ptr );
trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end );
void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang );
//============================================================
@ -472,14 +472,6 @@ void SV_UnlinkEdict (edict_t *ent);
// sets ent->leafnums[] for pvs determination even if the entity
// is not solid
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype );
// fills in a table of edict pointers with edicts that have bounding boxes
// that intersect the given area. It is possible for a non-axial bmodel
// to be returned that doesn't actually intersect the area on an exact
// test.
// returns the number of pointers filled in
// ??? does this always return the world?
//
// sv_pmove.c
//
@ -494,12 +486,12 @@ extern areanode_t sv_areanodes[];
void SV_ClearWorld( void );
bool SV_HeadnodeVisible( mnode_t *node, byte *visbits );
int SV_HullPointContents( hull_t *hull, int num, const vec3_t p );
trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end );
trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int type, edict_t *e );
trace_t SV_ClipMove( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int flags );
trace_t SV_MoveHull( const vec3_t start, int hullNumber, const vec3_t end, int type, edict_t *e );
trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore );
void SV_LinkEdict( edict_t *ent, bool touch_triggers );
void SV_TouchLinks( edict_t *ent, areanode_t *node );
edict_t *SV_TestPlayerPosition( const vec3_t origin, edict_t *pass, TraceResult *trace );
int SV_TruePointContents( const vec3_t p );
int SV_PointContents( const vec3_t p );

View File

@ -1356,7 +1356,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
// can't track this entity on the client.
// write static sound
if( !ent->headnode ) flags |= SND_FIXED_ORIGIN;
if( !ent->v.modelindex ) flags |= SND_FIXED_ORIGIN;
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
@ -1399,7 +1399,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
sound_idx = SV_SoundIndex( sample );
}
if( !ent->headnode )
if( !ent->v.modelindex )
entityIndex = 0;
else if( SV_IsValidEdict( ent->v.aiment ))
entityIndex = ent->v.aiment->serialnumber;
@ -1512,16 +1512,13 @@ pfnTraceLine
*/
static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
{
trace_t result;
if( !ptr ) return;
if( svgame.globals->trace_flags & 1 )
fNoMonsters |= FMOVE_SIMPLEBOX;
svgame.globals->trace_flags = 0;
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
Host_Error( "TraceLine: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
result = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip );
if( ptr ) *ptr = result;
*ptr = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip );
}
/*
@ -1532,7 +1529,7 @@ pfnTraceToss
*/
static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr )
{
trace_t result;
if( !ptr ) return;
if( !SV_IsValidEdict( pent ))
{
@ -1540,8 +1537,7 @@ static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr
return;
}
result = SV_MoveToss( pent, pentToIgnore );
if( ptr ) *ptr = result;
*ptr = SV_MoveToss( pent, pentToIgnore );
}
/*
@ -1552,21 +1548,13 @@ pfnTraceHull
*/
static void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr )
{
trace_t result;
float *mins, *maxs;
hullNumber = bound( 0, hullNumber, 3 );
mins = GI->client_mins[hullNumber];
maxs = GI->client_maxs[hullNumber];
if( !ptr ) return;
if( svgame.globals->trace_flags & 1 )
fNoMonsters |= FMOVE_SIMPLEBOX;
svgame.globals->trace_flags = 0;
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
Host_Error( "TraceHull: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
result = SV_Move( v1, mins, maxs, v2, fNoMonsters, pentToSkip );
if( ptr ) Mem_Copy( ptr, &result, sizeof( *ptr ));
*ptr = SV_MoveHull( v1, hullNumber, v2, fNoMonsters, pentToSkip );
}
/*
@ -1611,6 +1599,8 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi
{
float *mins, *maxs;
if( !ptr ) return;
if( !SV_IsValidEdict( pent ))
{
MsgDev( D_WARN, "TraceModel: invalid entity %s\n", SV_ClassName( pent ));
@ -1618,12 +1608,10 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi
}
hullNumber = bound( 0, hullNumber, 3 );
mins = svgame.player_mins[hullNumber];
maxs = svgame.player_maxs[hullNumber];
mins = sv.worldmodel->hulls[hullNumber].clip_mins;
maxs = sv.worldmodel->hulls[hullNumber].clip_maxs;
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
Host_Error( "TraceModel: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
if( ptr ) *ptr = SV_ClipMove( pent, v1, mins, maxs, v2, 0 );
*ptr = SV_TraceHull( pent, hullNumber, v1, mins, maxs, v2 );
}
/*
@ -1649,32 +1637,13 @@ static const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, co
/*
=============
pfnAreaEdicts
pfnTraceSphere
returns true if the entity is in solid currently
FIXME: implement
=============
*/
static int pfnAreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
static void pfnTraceSphere( const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr )
{
if( !mins || !maxs )
{
MsgDev( D_ERROR, "SV_AreaEdicts: invalid area bounds\n" );
return 0;
}
if( VectorIsNAN( mins ) || VectorIsNAN( maxs ))
Host_Error( "SV_AreaEdicts: NAN errors detected '%f %f %f', '%f %f %f'\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2] );
if( !list || maxcount <= 0 )
return 0;
if( areatype < AREA_SOLID || areatype > AREA_CUSTOM )
{
MsgDev( D_WARN, "SV_AreaEdicts: bad area type %i. Defaulting to AREA_SOLID\n", areatype );
areatype = AREA_SOLID;
}
return SV_AreaEdicts( mins, maxs, list, maxcount, areatype );
}
/*
@ -3277,9 +3246,6 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
// vis not set - fullvis enabled
if( !pset ) return 1;
if( !ent->headnode )
return 0; // not a linked in ?
if( ent->headnode == -1 )
{
int i;
@ -3298,11 +3264,15 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
{
mnode_t *node;
if( ent->headnode < 0 )
node = (mnode_t *)(sv.worldmodel->leafs + (-1 - ent->headnode));
else node = sv.worldmodel->nodes + ent->headnode;
// too many leafs for individual check, go by headnode
node = sv.worldmodel->nodes + ent->headnode;
if( !SV_HeadnodeVisible( node, pset ))
return 0;
}
#if 0
// NOTE: uncommenat this if you want to get more accuracy culling on large brushes
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
@ -3555,7 +3525,7 @@ static enginefuncs_t gEngfuncs =
pfnTraceHull,
pfnTraceModel,
pfnTraceTexture,
pfnAreaEdicts,
pfnTraceSphere,
pfnGetAimVector,
pfnServerCommand,
pfnServerExecute,

View File

@ -60,7 +60,7 @@ realcheck:
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent );
if( trace.flFraction == 1.0f )
return false;
@ -76,7 +76,7 @@ realcheck:
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent );
if( trace.flFraction != 1.0f && trace.vecEndPos[2] > bottom )
bottom = trace.vecEndPos[2];
@ -138,7 +138,7 @@ bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode )
{
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_WORLDONLY, ent );
else trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent );
if( trace.flFraction == 1.0f )
{
@ -162,7 +162,7 @@ bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode )
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid )
return false;
@ -173,7 +173,7 @@ bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode )
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid || trace.fStartSolid )
return false;
@ -202,7 +202,7 @@ bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode )
// check our pos
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_WORLDONLY, ent );
else trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
else trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent );
if( trace.fStartSolid )
{

View File

@ -159,6 +159,51 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t
SV_AddLinksToPmove( node->children[1], pmove_mins, pmove_maxs );
}
/*
====================
SV_AddLaddersToPmove
====================
*/
void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t pmove_maxs )
{
link_t *l, *next;
edict_t *check;
physent_t *pe;
// get water edicts
for( l = node->water_edicts.next; l != &node->water_edicts; l = next )
{
next = l->next;
check = EDICT_FROM_AREA( l );
if( check->v.solid != SOLID_NOT ) // disabled ?
continue;
// only brushes can have special contents
if( CM_GetModelType( check->v.modelindex ) != mod_brush )
continue;
if( !BoundsIntersect( pmove_mins, pmove_maxs, check->v.absmin, check->v.absmax ))
continue;
if( svgame.pmove->nummoveent == MAX_MOVEENTS )
return;
pe = &svgame.pmove->moveents[svgame.pmove->nummoveent];
if( SV_CopyEdictToPhysEnt( pe, check, true ))
svgame.pmove->nummoveent++;
}
// recurse down both sides
if( node->axis == -1 ) return;
if( pmove_maxs[node->axis] > node->dist )
SV_AddLaddersToPmove( node->children[0], pmove_mins, pmove_maxs );
if( pmove_mins[node->axis] < node->dist )
SV_AddLaddersToPmove( node->children[1], pmove_mins, pmove_maxs );
}
static void pfnParticle( float *origin, int color, float life, int zpos, int zvel )
{
int v;
@ -244,7 +289,7 @@ static pmtrace_t pfnPlayerTrace( float *start, float *end, int traceFlags, int i
mins = svgame.pmove->player_mins[svgame.pmove->usehull];
maxs = svgame.pmove->player_maxs[svgame.pmove->usehull];
result = SV_Move( start, mins, maxs, end, FMOVE_SIMPLEBOX, clent );
result = SV_Move( start, mins, maxs, end, MOVE_NORMAL, clent );
VectorCopy( result.vecEndPos, out.endpos );
VectorCopy( result.vecPlaneNormal, out.plane.normal );
@ -315,13 +360,13 @@ static float pfnTraceModel( physent_t *pEnt, float *start, float *end, pmtrace_t
static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
{
physent_t *pe;
edict_t *ent;
if( ground < 0 || ground >= svgame.pmove->numphysent )
return NULL; // bad ground
pe = &svgame.pmove->physents[ground];
return PM_TraceTexture( pe, vstart, vend );
ent = EDICT_NUM( svgame.pmove->physents[ground].info );
return CM_TraceTexture( ent, vstart, vend );
}
static int pfnCOM_FileSize( const char *filename )
@ -459,10 +504,8 @@ static void PM_CheckMovingGround( edict_t *ent, float frametime )
static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd, const char *physinfo )
{
physent_t *pe;
edict_t *touch[MAX_EDICTS];
vec3_t absmin, absmax;
int i, count;
int i;
pmove->player_index = NUM_FOR_EDICT( clent ) - 1;
pmove->multiplayer = (sv_maxclients->integer > 1) ? true : false;
@ -530,23 +573,7 @@ static void PM_SetupMove( playermove_t *pmove, edict_t *clent, usercmd_t *ucmd,
svgame.pmove->numphysent = 1; // always have world
SV_AddLinksToPmove( sv_areanodes, absmin, absmax );
count = SV_AreaEdicts( absmin, absmax, touch, MAX_EDICTS, AREA_CUSTOM );
// build list of ladders around player
for( i = 0; i < count; i++ )
{
if( pmove->nummoveent >= MAX_MOVEENTS )
{
MsgDev( D_ERROR, "PM_PlayerMove: too many ladders in PVS\n" );
break;
}
if( touch[i] == clent ) continue;
pe = &svgame.pmove->moveents[svgame.pmove->nummoveent];
if( SV_CopyEdictToPhysEnt( pe, touch[i], true ))
svgame.pmove->nummoveent++;
}
SV_AddLaddersToPmove( sv_areanodes, absmin, absmax );
}
static void PM_FinishMove( playermove_t *pmove, edict_t *clent )

View File

@ -3,7 +3,7 @@
// sv_studio.c - server studio utilities
//=======================================================================
// FIXME: these code needs be some cleanup from lerping code
// FIXME: these code needs to be some cleanup from lerping code
#include "common.h"
#include "server.h"
@ -14,10 +14,10 @@ static mplane_t sv_hitboxplanes[6]; // there a temp hitbox
static matrix4x4 sv_studiomatrix;
static matrix4x4 sv_studiobones[MAXSTUDIOBONES];
typedef bool (*pfnHitboxTrace)( trace_t *trace );
static float trace_realfraction;
static vec3_t trace_startmins, trace_endmins;
static vec3_t trace_startmaxs, trace_endmaxs;
static vec3_t trace_absmins, trace_absmaxs;
static float trace_realfraction;
/*
====================
@ -871,23 +871,24 @@ static bool SV_StudioIntersect( edict_t *ent, const vec3_t start, vec3_t mins, v
return BoundsIntersect( trace_mins, trace_maxs, anim_mins, anim_maxs );
}
bool SV_StudioTrace( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *ptr )
trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end )
{
vec3_t start_l, end_l;
int i, outBone = -1;
pfnHitboxTrace TraceHitbox = NULL;
trace_t trace;
// assume we didn't hit anything
Mem_Set( ptr, 0, sizeof( pmtrace_t ));
VectorCopy( end, ptr->vecEndPos );
ptr->flFraction = trace_realfraction = 1.0f;
ptr->iHitgroup = -1;
Mem_Set( &trace, 0, sizeof( trace_t ));
VectorCopy( end, trace.vecEndPos );
trace.flFraction = trace_realfraction = 1.0f;
trace.iHitgroup = -1;
if( !SV_StudioIntersect( ent, start, mins, maxs, end ))
return false;
return trace;
if( !SV_StudioSetupModel( ent ))
return false;
return trace;
if( VectorCompare( start, end ))
TraceHitbox = SV_StudioTestToHitbox; // special case for test position
@ -911,13 +912,13 @@ bool SV_StudioTrace( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs,
VectorAdd( end_l, mins, trace_endmins );
VectorAdd( end_l, maxs, trace_endmaxs );
if( TraceHitbox( ptr ))
if( TraceHitbox( &trace ))
{
outBone = phitbox->bone;
ptr->iHitgroup = phitbox->group;
trace.iHitgroup = phitbox->group;
}
if( ptr->fAllSolid )
if( trace.fAllSolid )
break;
}
@ -926,14 +927,13 @@ bool SV_StudioTrace( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs,
{
vec3_t temp;
ptr->pHit = ent;
VectorCopy( ptr->vecPlaneNormal, temp );
ptr->flFraction = bound( 0, ptr->flFraction, 1.0f );
VectorLerp( start, ptr->flFraction, end, ptr->vecEndPos );
Matrix4x4_TransformPositivePlane( sv_studiobones[outBone], temp, ptr->flPlaneDist, ptr->vecPlaneNormal, &ptr->flPlaneDist );
return true;
trace.pHit = ent;
VectorCopy( trace.vecPlaneNormal, temp );
trace.flFraction = bound( 0, trace.flFraction, 1.0f );
VectorLerp( start, trace.flFraction, end, trace.vecEndPos );
Matrix4x4_TransformPositivePlane( sv_studiobones[outBone], temp, trace.flPlaneDist, trace.vecPlaneNormal, &trace.flPlaneDist );
}
return false;
return trace;
}
void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang )
@ -963,5 +963,4 @@ void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang )
Matrix3x3_FromMatrix4x4( axis, sv_studiobones[iBone] );
if( org ) Matrix4x4_OriginFromMatrix( sv_studiobones[iBone], org );
if( ang ) Matrix3x3_ToAngles( axis, ang, true );
}

View File

@ -7,6 +7,7 @@
#include "server.h"
#include "const.h"
#include "pm_local.h"
#include "matrix_lib.h"
typedef struct moveclip_s
{
@ -18,7 +19,7 @@ typedef struct moveclip_s
edict_t *passedict;
int type; // move type
int flags; // trace flags
int trace_hull; // -1 to let entity select hull
int hull; // -1 to let entity select hull
} moveclip_t;
/*
@ -119,7 +120,7 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs
if( hullNumber == -1 )
{
// FIXME: these constanst doesn't works with user-defined hulls
// FIXME: these constant doesn't works with user-defined hulls
// revisit this
if( size[0] < 3 )
hull = &model->hulls[0]; // point hull
@ -143,12 +144,28 @@ hull_t *SV_HullForEntity( edict_t *ent, int hullNumber, vec3_t mins, vec3_t maxs
}
else
{
// create a temp hull from bounding box sizes
VectorSubtract( ent->v.mins, maxs, hullmins );
VectorSubtract( ent->v.maxs, mins, hullmaxs );
hull = SV_HullForBox( hullmins, hullmaxs );
// hullNumber is force to use hull from brushmodel (even if solid == SOLID_NOT)
if( hullNumber != -1 && CM_GetModelType( ent->v.modelindex ) == mod_brush )
{
model = CM_ClipHandleToModel( ent->v.modelindex );
if( !model ) Host_Error( "SV_HullForEntity: using custom hull on bad bsp model\n" );
// TraceHull stuff
hull = &model->hulls[hullNumber];
// calculate an offset value to center the origin
VectorSubtract( hull->clip_mins, mins, offset );
VectorAdd( offset, ent->v.origin, offset );
}
else
{
// create a temp hull from bounding box sizes
VectorSubtract( ent->v.mins, maxs, hullmins );
VectorSubtract( ent->v.maxs, mins, hullmaxs );
hull = SV_HullForBox( hullmins, hullmaxs );
VectorCopy( ent->v.origin, offset );
VectorCopy( ent->v.origin, offset );
}
}
return hull;
}
@ -217,8 +234,8 @@ SV_ClearWorld
*/
void SV_ClearWorld( void )
{
SV_InitBoxHull(); // for box testing
SV_InitStudioHull();// for hitbox testing
SV_InitBoxHull(); // for box testing
SV_InitStudioHull(); // for hitbox testing
Mem_Set( sv_areanodes, 0, sizeof( sv_areanodes ));
sv_numareanodes = 0;
@ -265,7 +282,7 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
continue;
// check triggers accuracy
// check brush triggers accuracy
if( CM_GetModelType( touch->v.modelindex ) == mod_brush )
{
hull = SV_HullForEntity( touch, -1, ent->v.mins, ent->v.maxs, test );
@ -346,8 +363,13 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node )
if( ent->headnode == -1 )
ent->headnode = node - worldmodel->nodes;
if( ent->num_leafs == MAX_ENT_LEAFS )
if( ent->num_leafs >= MAX_ENT_LEAFS )
{
// continue counting leafs,
// so we know how many it's overrun
ent->num_leafs++;
return;
}
leaf = (mleaf_t *)node;
leafnum = leaf - sv.worldmodel->leafs - 1;
@ -434,7 +456,7 @@ void SV_LinkEdict( edict_t *ent, bool touch_triggers )
return;
}
if( ent->num_leafs == MAX_ENT_LEAFS )
if( ent->num_leafs > MAX_ENT_LEAFS )
ent->num_leafs = 0; // so we use headnode instead
else ent->headnode = -1; // use normal leafs check
}
@ -721,49 +743,87 @@ bool SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t
/*
==================
SV_ClipMove
SV_TraceHull
Handles selection or creation of a clipping hull, and offseting (and
eventually rotation) of the end points
==================
*/
trace_t SV_ClipMove( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int flags )
trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end )
{
trace_t trace;
pmtrace_t pmtrace;
int pm_flags = 0;
physent_t pe;
matrix4x4 matrix;
vec3_t offset, temp;
vec3_t start_l, end_l;
hull_t *hull;
// fill in a default trace
Mem_Set( &trace, 0, sizeof( trace_t ));
VectorCopy( end, trace.vecEndPos );
trace.flFraction = 1.0f;
trace.fAllSolid = true;
trace.iHitgroup = -1;
// setup physentity
if( !SV_CopyEdictToPhysEnt( &pe, ent, false ))
return trace;
// get the clipping hull
hull = SV_HullForEntity( ent, hullNum, mins, maxs, offset );
// setup pm_flags
if( flags & FMOVE_SIMPLEBOX )
pm_flags |= PM_STUDIO_BOX;
if( flags & FMOVE_IGNORE_GLASS )
pm_flags |= PM_GLASS_IGNORE;
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
if( !PM_TraceModel( &pe, start, mins, maxs, end, &pmtrace, pm_flags ))
return trace; // didn't hit anything
// rotate start and end into the models frame of reference
if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles ))
{
matrix4x4 imatrix;
const float *org, *ang;
// copy the trace results
trace.fAllSolid = pmtrace.allsolid;
trace.fStartSolid = pmtrace.startsolid;
trace.fInOpen = pmtrace.inopen;
trace.fInWater = pmtrace.inwater;
trace.flFraction = pmtrace.fraction;
VectorCopy( pmtrace.endpos, trace.vecEndPos );
trace.flPlaneDist = pmtrace.plane.dist;
VectorCopy( pmtrace.plane.normal, trace.vecPlaneNormal );
trace.iHitgroup = pmtrace.hitgroup;
trace.pHit = ent;
org = ent->v.origin;
ang = ent->v.angles;
Matrix4x4_CreateFromEntity( matrix, org[0], org[1], org[2], ang[0], ang[1], ang[2], 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );
Matrix4x4_VectorTransform( imatrix, end, end_l );
// calc hull offsets (monsters use this)
VectorCopy( start_l, temp );
VectorMAMAM( 1, temp, 1, mins, -1, hull->clip_mins, start_l );
VectorCopy( end_l, temp );
VectorMAMAM( 1, temp, 1, mins, -1, hull->clip_mins, end_l );
}
// trace a line through the apropriate clipping hull
SV_RecursiveHullCheck( hull, hull->firstclipnode, 0.0f, 1.0f, start_l, end_l, &trace );
// rotate endpos back to world frame of reference
if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles ))
{
if( trace.flFraction != 1.0f )
{
// compute endpos
trace.vecEndPos[0] = start[0] + trace.flFraction * ( end[0] - start[0] );
trace.vecEndPos[1] = start[1] + trace.flFraction * ( end[1] - start[1] );
trace.vecEndPos[2] = start[2] + trace.flFraction * ( end[2] - start[2] );
VectorCopy( trace.vecPlaneNormal, temp );
Matrix4x4_TransformPositivePlane( matrix, temp, trace.flPlaneDist,
trace.vecPlaneNormal, &trace.flPlaneDist );
}
}
else
{
// special case for non-rotated bmodels
// fix trace up by the offset
if( trace.flFraction != 1.0f )
VectorAdd( trace.vecEndPos, offset, trace.vecEndPos );
trace.flPlaneDist = DotProduct( trace.vecEndPos, trace.vecPlaneNormal );
}
// did we clip the move?
if( trace.flFraction < 1.0f || trace.fStartSolid )
trace.pHit = ent;
return trace;
}
@ -780,6 +840,8 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
link_t *l, *next;
edict_t *touch;
trace_t trace;
bool traceHitbox;
float *mins, *maxs;
// touch linked edicts
for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
@ -788,34 +850,38 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
touch = EDICT_FROM_AREA( l );
if( touch->v.solid == SOLID_NOT )
continue;
if( touch == clip->passedict )
if( touch == clip->passedict || touch->v.solid == SOLID_NOT )
continue;
if( touch->v.solid == SOLID_TRIGGER )
Host_Error( "trigger in clipping list\n" );
// completely ignore all edicts but brushes
if( clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP )
continue;
// don't clip points against points (they can't collide)
if( VectorCompare( touch->v.mins, touch->v.maxs ) && (clip->type != MOVE_MISSILE || !( touch->v.flags & FL_MONSTER )))
continue;
// can't tracehull at dead monsters, only traceline
if( touch->v.deadflag == DEAD_DEAD && !VectorCompare( touch->v.mins, touch->v.maxs ))
continue;
if( clip->type == MOVE_WORLDONLY )
{
if( CM_GetModelType( touch->v.modelindex ) != mod_brush )
continue;
// accept only real bsp models with FL_WORLDBRUSH set
if( CM_GetModelType( touch->v.modelindex ) == mod_brush && touch->v.flags & FL_WORLDBRUSH );
else continue;
if(!( touch->v.flags & FL_WORLDBRUSH ));
continue;
}
if( !BoundsIntersect( clip->boxmins, clip->boxmaxs, touch->v.absmin, touch->v.absmax ))
continue;
if( clip->passedict && clip->passedict->v.solid == SOLID_TRIGGER )
{
// never collide items and player (because call "give" always stuck item in player
// and total trace returns fail (old half-life bug)
// items touch should be done in SV_TouchLinks not here
if( touch->v.flags & ( FL_CLIENT|FL_FAKECLIENT|FL_MONSTER ))
continue;
}
if( clip->passedict && !VectorIsNull( clip->passedict->v.size ) && VectorIsNull( touch->v.size ))
continue; // points never interact
@ -826,32 +892,16 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
else continue;
}
// custom user filter
if( svgame.dllFuncs2.pfnShouldCollide )
{
if( !svgame.dllFuncs2.pfnShouldCollide( touch, clip->passedict ))
continue;
}
if( clip->flags & FMOVE_IGNORE_GLASS && CM_GetModelType( touch->v.modelindex ) == mod_brush )
{
vec3_t point;
// we ignore brushes with rendermode != kRenderNormal
switch( touch->v.rendermode )
{
case kRenderTransTexture:
case kRenderTransAlpha:
case kRenderTransAdd:
if( touch->v.renderamt < 200 )
continue;
// check for translucent contents
if( VectorIsNull( touch->v.origin ))
VectorAverage( touch->v.absmin, touch->v.absmax, point );
else VectorCopy( touch->v.origin, point );
if( SV_PointContents( point ) == CONTENTS_TRANSLUCENT )
continue; // grate detected
default: break;
case kRenderTransAlpha:
case kRenderTransTexture:
continue; // passed through glass
default: break;
}
}
@ -866,9 +916,38 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
continue; // don't clip against owner
}
traceHitbox = false;
// select a properly trace method
if( CM_GetModelType( touch->v.modelindex ) == mod_studio && !( clip->flags & FMOVE_SIMPLEBOX ))
{
// always do hitbox trace for bbox solidity
if( touch->v.solid == SOLID_BBOX )
traceHitbox = true;
// do tracing hitbox only for pointtrace (bullets)
if( touch->v.solid == SOLID_SLIDEBOX && VectorCompare( clip->mins2, clip->maxs2 ))
traceHitbox = true;
}
if( touch->v.flags & FL_MONSTER )
trace = SV_ClipMove( touch, clip->start, clip->mins2, clip->maxs2, clip->end, clip->flags );
else trace = SV_ClipMove( touch, clip->start, clip->mins, clip->maxs, clip->end, clip->flags );
{
mins = clip->mins2;
maxs = clip->maxs2;
}
else
{
mins = clip->mins;
maxs = clip->maxs;
}
// can't trace dead bodies as hull, only traceline (for damage)
if( touch->v.deadflag == DEAD_DEAD && !VectorCompare( mins, maxs ))
continue;
if( traceHitbox )
trace = SV_TraceHitbox( touch, clip->start, mins, maxs, clip->end );
else trace = SV_TraceHull( touch, clip->hull, clip->start, mins, maxs, clip->end );
clip->trace = World_CombineTraces( &clip->trace, &trace, touch );
}
@ -901,9 +980,10 @@ trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end,
clip.type = (type & 0xFF);
clip.flags = (type & 0xFF00);
clip.passedict = e;
clip.hull = -1;
// clip to world
clip.trace = SV_ClipMove( EDICT_NUM( 0 ), start, mins, maxs, end, 0 );
clip.trace = SV_TraceHull( EDICT_NUM( 0 ), clip.hull, start, mins, maxs, end );
if( type == MOVE_MISSILE )
{
@ -928,6 +1008,54 @@ trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end,
return clip.trace;
}
/*
==================
SV_Move
==================
*/
trace_t SV_MoveHull( const vec3_t start, int hullNumber, const vec3_t end, int type, edict_t *e )
{
moveclip_t clip;
int i;
Mem_Set( &clip, 0, sizeof( moveclip_t ));
clip.start = start;
clip.end = end;
clip.type = (type & 0xFF);
clip.flags = (type & 0xFF00);
clip.passedict = e;
clip.hull = hullNumber = bound( 0, hullNumber, 3 );
clip.mins = sv.worldmodel->hulls[clip.hull].clip_mins;
clip.maxs = sv.worldmodel->hulls[clip.hull].clip_maxs;
clip.flags |= FMOVE_SIMPLEBOX; // completely ignore hitboxes, trace hulls only
// clip to world
clip.trace = SV_TraceHull( EDICT_NUM( 0 ), clip.hull, start, clip.mins, clip.maxs, end );
if( type == MOVE_MISSILE )
{
for( i = 0; i < 3; i++ )
{
clip.mins2[i] = -15;
clip.maxs2[i] = 15;
}
}
else
{
VectorCopy( clip.mins, clip.mins2 );
VectorCopy( clip.maxs, clip.maxs2 );
}
// create the bounding box of the entire move
World_MoveBounds( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
// clip to entities
SV_ClipToLinks( sv_areanodes, &clip );
return clip.trace;
}
/*
==================
SV_MoveToss
@ -968,105 +1096,4 @@ trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore )
VectorCopy( original_avelocity, tossent->v.avelocity );
return trace;
}
/*
============================================================================
AREA QUERY
Fills in a list of all entities who's absmin / absmax intersects the given
bounds. This does NOT mean that they actually touch in the case of bmodels.
============================================================================
*/
/*
====================
SV_AreaEdicts_r
====================
*/
void SV_AreaEdicts_r( areanode_t *node, area_t *ap )
{
link_t *l, *next, *start;
edict_t *check;
int count = 0;
// touch linked edicts
if( ap->type == AREA_SOLID )
start = &node->solid_edicts;
else if( ap->type == AREA_TRIGGERS )
start = &node->trigger_edicts;
else start = &node->water_edicts;
for( l = start->next; l != start; l = next )
{
next = l->next;
check = EDICT_FROM_AREA( l );
if( check->v.solid == SOLID_NOT && check->v.skin == CONTENTS_NONE )
continue; // deactivated
if( !BoundsIntersect( check->v.absmin, check->v.absmax, ap->mins, ap->maxs ))
continue; // not touching
if( ap->count == ap->maxcount )
{
MsgDev( D_WARN, "SV_AreaEdicts: maxcount hit\n" );
return;
}
ap->list[ap->count] = check;
ap->count++;
}
if( node->axis == -1 ) return; // terminal node
// recurse down both sides
if( ap->maxs[node->axis] > node->dist ) SV_AreaEdicts_r( node->children[0], ap );
if( ap->mins[node->axis] < node->dist ) SV_AreaEdicts_r( node->children[1], ap );
}
/*
================
SV_AreaEdicts
================
*/
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
{
area_t ap;
ap.mins = mins;
ap.maxs = maxs;
ap.list = list;
ap.count = 0;
ap.maxcount = maxcount;
ap.type = areatype;
SV_AreaEdicts_r( sv_areanodes, &ap );
return ap.count;
}
/*
============
SV_TestPlayerPosition
============
*/
edict_t *SV_TestPlayerPosition( const vec3_t origin, edict_t *pass, TraceResult *tr )
{
float *mins, *maxs;
trace_t result;
svgame.pmove->usehull = bound( 0, svgame.pmove->usehull, 3 );
mins = svgame.pmove->player_mins[svgame.pmove->usehull];
maxs = svgame.pmove->player_maxs[svgame.pmove->usehull];
if( pass ) SV_SetMinMaxSize( pass, mins, maxs );
result = SV_Move( origin, mins, maxs, origin, MOVE_NORMAL, pass );
if( tr ) *tr = result;
if( result.pHit )
return result.pHit;
return NULL;
}