This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/server/sv_world.c

410 lines
9.2 KiB
C
Raw Normal View History

2008-11-14 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2008 <20>
// sv_world.c - world query functions
//=======================================================================
2007-06-21 22:00:00 +02:00
2008-06-09 22:00:00 +02:00
#include "common.h"
2007-06-21 22:00:00 +02:00
#include "server.h"
2008-09-09 22:00:00 +02:00
#include "const.h"
2007-06-21 22:00:00 +02:00
/*
===============================================================================
2008-11-14 22:00:00 +01:00
ENTITY AREA CHECKING
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
FIXME: this use of "area" is different from the bsp file use
2007-06-21 22:00:00 +02:00
===============================================================================
*/
2008-12-15 22:00:00 +01:00
#define EDICT_FROM_AREA( l ) EDICT_NUM( l->entnum )
2008-11-14 22:00:00 +01:00
#define MAX_TOTAL_ENT_LEAFS 128
2009-07-12 22:00:00 +02:00
#define AREA_NODES 64
#define AREA_DEPTH 5
2008-11-14 22:00:00 +01:00
typedef struct areanode_s
{
int axis; // -1 = leaf node
float dist;
struct areanode_s *children[2];
link_t trigger_edicts;
link_t solid_edicts;
} areanode_t;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
typedef struct area_s
2007-06-21 22:00:00 +02:00
{
2008-01-17 22:00:00 +01:00
const float *mins;
const float *maxs;
edict_t **list;
int count;
int maxcount;
int type;
} area_t;
2007-06-21 22:00:00 +02:00
2009-01-04 22:00:00 +01:00
const char *ed_name[] =
{
"unknown",
"world",
"static",
"ambient",
"normal",
"brush",
"player",
"monster",
"tempent",
"beam",
"mover",
"viewmodel",
"item",
"ragdoll",
"physbody",
"trigger",
"portal",
"missile",
"decal",
"vehicle",
"error",
};
2008-11-14 22:00:00 +01:00
areanode_t sv_areanodes[AREA_NODES];
int sv_numareanodes;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
/*
===============
2008-11-14 22:00:00 +01:00
SV_ClearLink
SV_ClearLink is used for new headnodes
2008-01-17 22:00:00 +01:00
===============
*/
2008-11-14 22:00:00 +01:00
void SV_ClearLink( link_t *l )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
l->prev = l->next = l;
}
2008-01-17 22:00:00 +01:00
2008-11-14 22:00:00 +01:00
/*
===============
SV_RemoveLink
remove link from chain
===============
*/
void SV_RemoveLink( link_t *l )
{
l->next->prev = l->prev;
l->prev->next = l->next;
2007-06-21 22:00:00 +02:00
}
/*
===============
2008-11-14 22:00:00 +01:00
SV_InsertLinkBefore
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
kept trigger and solid entities seperate
2007-06-21 22:00:00 +02:00
===============
*/
2008-11-14 22:00:00 +01:00
void SV_InsertLinkBefore( link_t *l, link_t *before, edict_t *ent )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
2008-12-15 22:00:00 +01:00
l->entnum = NUM_FOR_EDICT( ent );
2008-11-14 22:00:00 +01:00
}
/*
===============
SV_CreateAreaNode
builds a uniformly subdivided tree for the given world size
===============
*/
areanode_t *SV_CreateAreaNode( int depth, vec3_t mins, vec3_t maxs )
{
areanode_t *anode;
2007-06-21 22:00:00 +02:00
vec3_t size;
2008-11-14 22:00:00 +01:00
vec3_t mins1, maxs1;
vec3_t mins2, maxs2;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
anode = &sv_areanodes[sv_numareanodes++];
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
SV_ClearLink( &anode->trigger_edicts );
SV_ClearLink( &anode->solid_edicts );
2008-01-17 22:00:00 +01:00
if( depth == AREA_DEPTH )
2007-06-21 22:00:00 +02:00
{
anode->axis = -1;
anode->children[0] = anode->children[1] = NULL;
return anode;
}
2008-01-17 22:00:00 +01:00
VectorSubtract( maxs, mins, size );
2008-11-14 22:00:00 +01:00
if( size[0] > size[1] )
anode->axis = 0;
2007-09-16 22:00:00 +02:00
else anode->axis = 1;
2008-11-14 22:00:00 +01:00
2008-01-17 22:00:00 +01:00
anode->dist = 0.5f * (maxs[anode->axis] + mins[anode->axis]);
2008-11-14 22:00:00 +01:00
VectorCopy( mins, mins1 );
VectorCopy( mins, mins2 );
VectorCopy( maxs, maxs1 );
VectorCopy( maxs, maxs2 );
2007-06-21 22:00:00 +02:00
maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
2008-11-14 22:00:00 +01:00
anode->children[0] = SV_CreateAreaNode( depth+1, mins2, maxs2 );
anode->children[1] = SV_CreateAreaNode( depth+1, mins1, maxs1 );
2007-06-21 22:00:00 +02:00
return anode;
}
/*
===============
SV_ClearWorld
===============
*/
2008-09-09 22:00:00 +02:00
void SV_ClearWorld( void )
2007-06-21 22:00:00 +02:00
{
2008-01-17 22:00:00 +01:00
cmodel_t *world = sv.models[1];
2008-11-14 22:00:00 +01:00
sv_numareanodes = 0;
Mem_Set( sv_areanodes, 0, sizeof( sv_areanodes ));
SV_CreateAreaNode( 0, world->mins, world->maxs );
2007-06-21 22:00:00 +02:00
}
2009-01-04 22:00:00 +01:00
/*
=================
SV_ClassifyEdict
sorting edict by type
=================
*/
void SV_ClassifyEdict( edict_t *ent )
{
sv_priv_t *sv_ent;
sv_ent = ent->pvServerData;
if( !sv_ent || sv_ent->s.ed_type != ED_SPAWNED )
return;
// update baseline for new entity
if( !sv_ent->s.number )
{
// take current state as baseline
2009-01-14 22:00:00 +01:00
SV_UpdateEntityState( ent, true );
2009-01-04 22:00:00 +01:00
svs.baselines[ent->serialnumber] = ent->pvServerData->s;
}
2009-01-14 22:00:00 +01:00
sv_ent->s.ed_type = svgame.dllFuncs.pfnClassifyEdict( ent );
2009-01-04 22:00:00 +01:00
2009-01-14 22:00:00 +01:00
if( sv_ent->s.ed_type != ED_SPAWNED )
2009-01-04 22:00:00 +01:00
{
2009-01-14 22:00:00 +01:00
// or leave unclassified, wait for next SV_LinkEdict...
2009-09-25 22:00:00 +02:00
// Msg( "%s: <%s>\n", STRING( ent->v.classname ), ed_name[sv_ent->s.ed_type] );
2009-01-04 22:00:00 +01:00
}
}
2007-06-21 22:00:00 +02:00
/*
===============
SV_UnlinkEdict
===============
*/
2008-01-17 22:00:00 +01:00
void SV_UnlinkEdict( edict_t *ent )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
// not linked in anywhere
2008-12-26 22:00:00 +01:00
if( !ent->pvServerData->area.prev ) return;
2008-01-17 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
SV_RemoveLink( &ent->pvServerData->area );
ent->pvServerData->area.prev = ent->pvServerData->area.next = NULL;
2008-01-17 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
/*
===============
2008-01-17 22:00:00 +01:00
SV_LinkEntity
2007-06-21 22:00:00 +02:00
===============
*/
2008-01-17 22:00:00 +01:00
void SV_LinkEdict( edict_t *ent )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
areanode_t *node;
2007-09-16 22:00:00 +02:00
int leafs[MAX_TOTAL_ENT_LEAFS];
2008-11-14 22:00:00 +01:00
int clusters[MAX_TOTAL_ENT_LEAFS];
2007-09-16 22:00:00 +02:00
int num_leafs;
2009-01-05 22:00:00 +01:00
int i, j;
2007-09-16 22:00:00 +02:00
int area;
2009-07-12 22:00:00 +02:00
int lastleaf;
2008-12-26 22:00:00 +01:00
sv_priv_t *sv_ent;
2008-01-17 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
sv_ent = ent->pvServerData;
2007-09-06 22:00:00 +02:00
2009-01-04 22:00:00 +01:00
if( !sv_ent ) return;
2008-11-14 22:00:00 +01:00
if( sv_ent->area.prev ) SV_UnlinkEdict( ent ); // unlink from old position
2008-12-17 22:00:00 +01:00
if( ent == EDICT_NUM( 0 )) return; // don't add the world
2008-12-15 22:00:00 +01:00
if( ent->free ) return;
2007-06-21 22:00:00 +02:00
2009-01-04 22:00:00 +01:00
// trying to classify unclassified edicts
if( sv.state == ss_active && sv_ent->s.ed_type == ED_SPAWNED )
SV_ClassifyEdict( ent );
2007-06-21 22:00:00 +02:00
// set the size
2008-12-15 22:00:00 +01:00
VectorSubtract( ent->v.maxs, ent->v.mins, ent->v.size );
2008-01-17 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
// set the abs box
2009-01-02 22:00:00 +01:00
svgame.dllFuncs.pfnSetAbsBox( ent );
2007-06-21 22:00:00 +02:00
2007-08-17 22:00:00 +02:00
// link to PVS leafs
2008-01-17 22:00:00 +01:00
sv_ent->num_clusters = 0;
2008-11-14 22:00:00 +01:00
sv_ent->areanum = 0;
sv_ent->areanum2 = 0;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
// get all leafs, including solids
2009-07-12 22:00:00 +02:00
num_leafs = pe->BoxLeafnums( ent->v.absmin, ent->v.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastleaf );
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
// if none of the leafs were inside the map, the
// entity is outside the world and can be considered unlinked
if( !num_leafs ) return;
// set areas, even from clusters that don't fit in the entity array
for( i = 0; i < num_leafs; i++ )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
clusters[i] = pe->LeafCluster( leafs[i] );
2008-01-17 22:00:00 +01:00
area = pe->LeafArea( leafs[i] );
2008-11-14 22:00:00 +01:00
if( area )
2008-01-17 22:00:00 +01:00
{
// doors may legally straggle two areas,
2007-06-21 22:00:00 +02:00
// but nothing should evern need more than that
2008-11-14 22:00:00 +01:00
if( sv_ent->areanum && sv_ent->areanum != area )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
if( sv_ent->areanum2 && sv_ent->areanum2 != area && sv.state == ss_loading )
2008-01-17 22:00:00 +01:00
{
2008-12-15 22:00:00 +01:00
float *v = ent->v.absmin;
2008-11-14 22:00:00 +01:00
MsgDev( D_WARN, "SV_LinkEdict: object touching 3 areas at %f %f %f\n", v[0], v[1], v[2] );
2008-01-17 22:00:00 +01:00
}
2008-11-14 22:00:00 +01:00
sv_ent->areanum2 = area;
2007-06-21 22:00:00 +02:00
}
2008-11-14 22:00:00 +01:00
else sv_ent->areanum = area;
2007-06-21 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
sv_ent->lastcluster = -1;
sv_ent->num_clusters = 0;
for( i = 0; i < num_leafs; i++ )
2007-06-21 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
if( clusters[i] == -1 )
continue; // not a visible leaf
for( j = 0; j < i; j++ )
2007-06-21 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
if( clusters[j] == clusters[i] )
break;
}
if( j == i )
{
if( sv_ent->num_clusters == MAX_ENT_CLUSTERS )
{
// we missed some leafs, so store the last visible cluster
sv_ent->lastcluster = pe->LeafCluster( lastleaf );
break;
2008-11-14 22:00:00 +01:00
}
2009-07-12 22:00:00 +02:00
sv_ent->clusternums[sv_ent->num_clusters++] = clusters[i];
2007-06-21 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
// if first time, make sure old_origin is valid
2009-07-15 22:00:00 +02:00
if( !sv_ent->linkcount && sv_ent->s.ed_type != ED_PORTAL )
VectorCopy( ent->v.origin, ent->v.oldorigin );
2009-07-12 22:00:00 +02:00
2008-12-26 22:00:00 +01:00
ent->pvServerData->linkcount++;
2009-01-14 22:00:00 +01:00
ent->pvServerData->s.ed_flags |= ESF_LINKEDICT; // change edict state on a client too...
2008-11-25 22:00:00 +01:00
2008-01-17 22:00:00 +01:00
// don't link not solid or rigid bodies
2008-12-15 22:00:00 +01:00
if( ent->v.solid == SOLID_NOT || ent->v.solid >= SOLID_BOX )
2008-09-09 22:00:00 +02:00
{
sv_ent->linked = true;
2007-11-27 22:00:00 +01:00
return;
2008-09-09 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
// find the first node that the ent's box crosses
node = sv_areanodes;
2008-01-17 22:00:00 +01:00
while( 1 )
2007-06-21 22:00:00 +02:00
{
2008-07-30 22:00:00 +02:00
if( node->axis == -1 ) break;
2008-12-15 22:00:00 +01:00
if( ent->v.absmin[node->axis] > node->dist )
2007-06-21 22:00:00 +02:00
node = node->children[0];
2008-12-15 22:00:00 +01:00
else if( ent->v.absmax[node->axis] < node->dist )
2007-06-21 22:00:00 +02:00
node = node->children[1];
2007-08-17 22:00:00 +02:00
else break; // crosses the node
2007-06-21 22:00:00 +02:00
}
2008-11-14 22:00:00 +01:00
// link it in
2008-12-15 22:00:00 +01:00
if( ent->v.solid == SOLID_TRIGGER )
2008-11-14 22:00:00 +01:00
SV_InsertLinkBefore( &sv_ent->area, &node->trigger_edicts, ent );
else SV_InsertLinkBefore (&sv_ent->area, &node->solid_edicts, ent );
2008-09-09 22:00:00 +02:00
sv_ent->linked = true;
2007-06-21 22:00:00 +02:00
}
2008-01-17 22:00:00 +01:00
/*
============================================================================
AREA QUERY
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
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.
============================================================================
*/
2007-06-21 22:00:00 +02:00
/*
====================
SV_AreaEdicts_r
====================
*/
2008-11-14 22:00:00 +01:00
void SV_AreaEdicts_r( areanode_t *node, area_t *ap )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
link_t *l, *next, *start;
edict_t *check;
int count = 0;
// touch linked edicts
if( ap->type == AREA_SOLID )
start = &node->solid_edicts;
else start = &node->trigger_edicts;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
for( l = start->next; l != start; l = next )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
next = l->next;
check = EDICT_FROM_AREA( l );
2007-06-21 22:00:00 +02:00
2008-12-15 22:00:00 +01:00
if( check->v.solid == SOLID_NOT ) continue; // deactivated
2009-07-12 22:00:00 +02:00
if( !BoundsIntersect( check->v.absmin, check->v.absmax, ap->mins, ap->maxs ))
2007-08-17 22:00:00 +02:00
continue; // not touching
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
if( ap->count == ap->maxcount )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
MsgDev( D_WARN, "SV_AreaEdicts: maxcount hit\n" );
2007-06-21 22:00:00 +02:00
return;
}
2008-11-14 22:00:00 +01:00
ap->list[ap->count] = check;
2008-01-17 22:00:00 +01:00
ap->count++;
2007-06-21 22:00:00 +02:00
}
2008-01-17 22:00:00 +01:00
if( node->axis == -1 ) return; // terminal node
2007-06-21 22:00:00 +02:00
// recurse down both sides
2008-11-14 22:00:00 +01:00
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 );
2007-06-21 22:00:00 +02:00
}
/*
================
SV_AreaEdicts
================
*/
2008-11-14 22:00:00 +01:00
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
2007-06-21 22:00:00 +02:00
{
2008-01-17 22:00:00 +01:00
area_t ap;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
ap.mins = mins;
ap.maxs = maxs;
ap.list = list;
ap.count = 0;
ap.maxcount = maxcount;
2008-11-14 22:00:00 +01:00
ap.type = areatype;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
SV_AreaEdicts_r( sv_areanodes, &ap );
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
return ap.count;
2007-09-17 22:00:00 +02:00
}