📄 sv_world.pas
字号:
unit sv_world;
// world.c -- world query functions
interface
uses
SysUtils,
Common,
GameUnit,
q_shared,
Server;
type
areanode_p = ^areanode_s;
areanode_s = record
axis: Integer; // -1 = leaf node
dist: Single;
children: array[0..2] of areanode_p; // to areanode_t;
trigger_edicts: link_t;
solid_edicts: link_t;
end;
areanode_t = areanode_s;
function SV_HullForEntity(ent: edict_p): Integer; cdecl;
procedure SV_ClearWorld; cdecl;
procedure SV_LinkEdict(ent: edict_p); cdecl;
procedure SV_UnlinkEdict(ent: edict_p); cdecl;
function SV_AreaEdicts (mins, maxs: vec3_t; list: PParea_list;
maxcount, areatype: Integer): Integer; cdecl;
function SV_Trace(start, mins, maxs, end_: vec3_p; passedict: edict_p; contentmask: Integer): trace_t; cdecl;
function SV_PointContents(p: vec3_t): Integer; cdecl;
const
AREA_DEPTH = 4;
AREA_NODES = 32;
type
{$IFNDEF COMPILER6_UP}
TSingleArray = array [0..MaxInt div SizeOf(Single)-1] of Single;
PSingleArray = ^TSingleArray;
{$ENDIF}
var
sv_areanodes: array[0..AREA_NODES-1] of areanode_t;
sv_numareanodes: Integer;
area_mins, area_maxs: PSingleArray;
area_list: PParea_list;
area_count, area_maxcount: Integer;
area_type: Integer;
implementation
uses
CModel,
g_local,
sv_game,
sv_init;
// !!!! Juha: Phew... !!!
(*
#define STRUCT_FROM_LINK(l,t,m) ((t * )((byte * )l - (int)&(((t * )0)->m)))
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
*)
function EDICT_FROM_AREA(l: pointer): edict_p;
begin
Result := edict_p(@edict_p(l).area);
end;
// ClearLink is used for new headnodes
procedure ClearLink(l: link_p);
begin
l^.next := l;
l^.prev := l^.next;
end;
procedure RemoveLink(l: link_p);
begin
l^.next^.prev := l^.prev;
l^.prev^.next := l^.next;
end;
procedure InsertLinkBefore(l: link_p; before: link_p);
begin
l^.next := before;
l^.prev := before^.prev;
l^.prev^.next := l;
l^.next^.prev := l;
end;
(*
===============
SV_CreateAreaNode
Builds a uniformly subdivided tree for the given world size
===============
*)
function SV_CreateAreaNode(depth: Integer; mins, maxs: vec3_t): areanode_p;
var
anode: areanode_p;
size, mins1, maxs1, mins2, maxs2: vec3_t;
begin
anode := @sv_areanodes[sv_numareanodes];
Inc(sv_numareanodes);
ClearLink(@anode^.trigger_edicts);
ClearLink(@anode^.solid_edicts);
if (depth = AREA_DEPTH) then
begin
anode^.axis := -1;
anode^.children[1] := Nil;
anode^.children[0] := anode^.children[1];
Result := anode;
Exit;
end;
VectorSubtract(maxs, mins, size);
if (size[0] > size[1]) then
anode^.axis := 0
else
anode^.axis := 1;
anode^.dist := 0.5 * (maxs[anode^.axis] + mins[anode^.axis]);
VectorCopy(mins, mins1);
VectorCopy(mins, mins2);
VectorCopy(maxs, maxs1);
VectorCopy(maxs, maxs2);
mins2[anode^.axis] := anode^.dist;
maxs1[anode^.axis] := mins2[anode^.axis];
anode^.children[0] := SV_CreateAreaNode(depth + 1, mins2, maxs2);
anode^.children[1] := SV_CreateAreaNode(depth + 1, mins1, maxs1);
Result := anode;
end;
(*
===============
SV_ClearWorld
===============
*)
procedure SV_ClearWorld;
begin
FillChar(sv_areanodes, SizeOf(sv_areanodes), 0);
sv_numareanodes := 0;
SV_CreateAreaNode(0, sv.models[1].mins, sv.models[1].maxs);
end;
(*
===============
SV_UnlinkEdict
===============
*)
procedure SV_UnlinkEdict(ent: edict_p); cdecl;
begin
if (ent.area.prev = nil) then
Exit; // not linked in anywhere
RemoveLink(@ent^.area);
ent^.area.next := nil;
ent^.area.prev := ent^.area.next;
end;
(*
===============
SV_LinkEdict
===============
*)
const
MAX_TOTAL_ENT_LEAFS = 128;
type
TMaxLeafsArray = array[0..MAX_TOTAL_ENT_LEAFS-1] of Integer;
procedure SV_LinkEdict(ent: edict_p);
var
node: areanode_p;
leafs: TMaxLeafsArray;
clusters: TMaxLeafsArray;
num_leafs: Integer;
i, j, k: Integer;
area: Integer;
topnode: Integer;
max, v: Single;
begin
if (ent.area.prev <> nil) then
SV_UnlinkEdict(ent); // unlink from old position
if (ent = ge^.edicts) then
Exit; // don't add the world
if (not ent^.inuse) then
Exit;
// set the size
VectorSubtract(ent^.maxs, ent^.mins, ent^.size);
// encode the size into the entity_state for client prediction
if (ent^.solid = SOLID_BBOX) AND ((ent^.svflags AND SVF_DEADMONSTER) = 0) then
begin
// assume that x/y are equal and symetric
i := Trunc(ent^.maxs[0] / 8);
if (i < 1) then
i := 1;
if (i > 31) then
i := 31;
// z is not symetric
j := Trunc((-ent^.mins[2]) / 8);
if (j < 1) then
j := 1;
if (j > 31) then
j := 31;
// and z maxs can be negative...
k := Trunc((ent^.maxs[2] + 32) / 8);
if (k < 1) then
k := 1;
if (k > 63) then
k := 63;
ent^.s.solid := (k shl 10) OR (j shl 5) OR i;
end
else if (ent^.solid = SOLID_BSP) then
begin
ent^.s.solid := 31; // a solid_bbox will never create this value
end
else
ent^.s.solid := 0;
// set the abs box
if ((ent^.solid = SOLID_BSP) AND
((ent^.s.angles[0] <> 0) OR (ent^.s.angles[1] <> 0) OR (ent^.s.angles[2] <> 0))) then
begin
// expand for rotation
max := 0;
for i := 0 to 2 do
begin
v := fabs(ent^.mins[i]);
if (v > max) then
max := v;
v := fabs(ent^.maxs[i]);
if (v > max) then
max := v;
end;
for i := 0 to 2 do
begin
ent^.absmin[i] := ent^.s.origin[i] - max;
ent^.absmax[i] := ent^.s.origin[i] + max;
end;
end
else
begin
// normal
VectorAdd(ent^.s.origin, ent^.mins, ent^.absmin);
VectorAdd(ent^.s.origin, ent^.maxs, ent^.absmax);
end;
// because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
ent^.absmin[0] := ent^.absmin[0] - 1;
ent^.absmin[1] := ent^.absmin[1] - 1;
ent^.absmin[2] := ent^.absmin[2] - 1;
ent^.absmax[0] := ent^.absmax[0] + 1;
ent^.absmax[1] := ent^.absmax[1] + 1;
ent^.absmax[2] := ent^.absmax[2] + 1;
// link to PVS leafs
ent^.num_clusters := 0;
ent^.areanum := 0;
ent^.areanum2 := 0;
//get all leafs, including solids
num_leafs := CM_BoxLeafnums(ent^.absmin, ent^.absmax, @leafs,
MAX_TOTAL_ENT_LEAFS, @topnode);
// set areas
for i := 0 to (num_leafs - 1) do
begin
clusters[i] := CM_LeafCluster(leafs[i]);
area := CM_LeafArea(leafs[i]);
if (area <> 0) then
begin
// doors may legally straggle two areas,
// but nothing should evern need more than that
if (ent^.areanum <> 0) AND (ent^.areanum <> area) then
begin
if (ent^.areanum2 <> 0) AND (ent^.areanum2 <> area) AND (sv.state = ss_loading) then
Com_DPrintf('Object touching 3 areas at %f %f %f'#10, [
ent^.absmin[0], ent^.absmin[1], ent^.absmin[2]]);
ent^.areanum2 := area;
end
else
ent^.areanum := area;
end;
end;
if (num_leafs >= MAX_TOTAL_ENT_LEAFS) then
begin
// assume we missed some leafs, and mark by headnode
ent^.num_clusters := -1;
ent^.headnode := topnode;
end
else
begin
ent^.num_clusters := 0;
for i := 0 to (num_leafs - 1) do
begin
if (clusters[i] = -1) then
Continue; // not a visible leaf
j := 0;
while j < i do
begin
if (clusters[j] = clusters[i]) then
Break;
Inc(j);
end;
if (j = i) then
begin
if (ent^.num_clusters = MAX_ENT_CLUSTERS) then
begin
// assume we missed some leafs, and mark by headnode
ent^.num_clusters := -1;
ent^.headnode := topnode;
Break;
end;
ent^.clusternums[ent^.num_clusters] := clusters[i];
Inc(ent^.num_clusters);
end;
end;
end;
// if first time, make sure old_origin is valid
if (ent^.linkcount = 0) then
begin
VectorCopy(ent^.s.origin, ent^.s.old_origin);
end;
Inc(ent^.linkcount);
if (ent^.solid = SOLID_NOT) then
Exit;
// find the first node that the ent's box crosses
node := @sv_areanodes;
while (True) do
begin
if (node^.axis = -1) then
Break;
if (ent^.absmin[node^.axis] > node^.dist) then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -