Skip to content

Commit 47d3d66

Browse files
committed
link leaves connected by teleports
plugins will have to do additional checks for disabled teleports
1 parent 508cb90 commit 47d3d66

File tree

2 files changed

+120
-35
lines changed

2 files changed

+120
-35
lines changed

Diff for: src/nav/LeafNavMeshGenerator.cpp

+110-33
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ LeafNavMesh* LeafNavMeshGenerator::generate(Bsp* map) {
2727

2828
linkNavLeaves(map, navmesh);
2929
setLeafOrigins(map, navmesh);
30-
linkLadderLeaves(map, navmesh);
30+
linkEntityLeaves(map, navmesh);
3131
calcPathCosts(map, navmesh);
3232

3333
int totalSz = 0;
@@ -278,56 +278,133 @@ void LeafNavMeshGenerator::linkNavLeaves(Bsp* map, LeafNavMesh* mesh) {
278278
logf("Added %d nav leaf links in %.2fs\n", numLinks, (float)glfwGetTime() - linkStart);
279279
}
280280

281-
void LeafNavMeshGenerator::linkLadderLeaves(Bsp* map, LeafNavMesh* mesh) {
281+
void LeafNavMeshGenerator::linkEntityLeaves(Bsp* map, LeafNavMesh* mesh) {
282+
vector<bool> regionLeaves;
283+
regionLeaves.resize(mesh->nodes.size());
284+
285+
const vec3 pointMins = vec3(-16, -16, -36);
286+
const vec3 pointMaxs = vec3(16, 16, 36);
287+
282288
for (int i = 0; i < map->ents.size(); i++) {
283289
Entity* ent = map->ents[i];
284290

285291
if (ent->keyvalues["classname"] == "func_ladder") {
286-
vector<LeafNode> leaves = getHullLeaves(map, ent->getBspModelIdx(), CONTENTS_SOLID);
292+
LeafNode& entNode = addSolidEntityNode(map, mesh, i);
293+
entNode.maxs.z += NAV_CROUCHJUMP_HEIGHT; // players can stand on top of the ladder for more height
294+
entNode.origin = (entNode.mins + entNode.maxs) * 0.5f;
295+
296+
linkEntityLeaves(map, mesh, entNode, regionLeaves);
297+
}
298+
else if (ent->keyvalues["classname"] == "trigger_teleport") {
299+
LeafNode& teleNode = addSolidEntityNode(map, mesh, i);
300+
linkEntityLeaves(map, mesh, teleNode, regionLeaves);
287301

288-
// create a special ladder node which is a combination of all its leaves
289-
LeafNode ladderNode = LeafNode();
290-
ladderNode.mins = vec3(FLT_MAX, FLT_MAX, FLT_MAX);
291-
ladderNode.maxs = vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
302+
// link teleport destination(s) to touched nodes
303+
int pentTarget = -1;
304+
vector<int> targets;
292305

293-
for (LeafNode& node : leaves) {
294-
expandBoundingBox(node.mins, ladderNode.mins, ladderNode.maxs);
295-
expandBoundingBox(node.maxs, ladderNode.mins, ladderNode.maxs);
306+
const int SF_TELE_RANDOM_DESTINATION = 64;
307+
string target = ent->keyvalues["target"];
308+
bool randomDestinations = atoi(ent->keyvalues["spawnflags"].c_str()) & SF_TELE_RANDOM_DESTINATION;
296309

297-
for (int i = 0; i < node.leafFaces.size(); i++) {
298-
ladderNode.leafFaces.push_back(node.leafFaces[i]);
299-
}
310+
if (!target.length()) {
311+
continue;
300312
}
301-
ladderNode.maxs.z += NAV_CROUCHJUMP_HEIGHT; // players can stand on top of the ladder for more height
302-
ladderNode.origin = (ladderNode.mins + ladderNode.maxs) * 0.5f;
303-
ladderNode.id = mesh->nodes.size();
304-
ladderNode.entidx = i;
305-
306-
vector<bool> regionLeaves;
307-
regionLeaves.resize(mesh->nodes.size());
308-
mesh->octree->getLeavesInRegion(&ladderNode, regionLeaves);
309-
310-
for (int i = 0; i < mesh->nodes.size(); i++) {
311-
if (!regionLeaves[i]) {
312-
continue;
313+
314+
for (int k = 0; k < map->ents.size(); k++) {
315+
Entity* tar = map->ents[k];
316+
if (tar->keyvalues["targetname"] == target) {
317+
if (tar->keyvalues["classname"] == "info_teleport_destination") {
318+
targets.push_back(k);
319+
}
320+
else if (pentTarget == -1) {
321+
pentTarget = k;
322+
}
313323
}
324+
}
314325

315-
LeafNode& node = mesh->nodes[i];
316-
if (boxesIntersect(node.mins, node.maxs, ladderNode.mins, ladderNode.maxs)) {
317-
// ladder can connect these leaves
318-
vec3 linkPos = ladderNode.origin;
319-
linkPos.z = node.origin.z;
326+
if (!randomDestinations && targets.size()) {
327+
pentTarget = targets[0]; // prefer teleport destinations
328+
}
320329

321-
ladderNode.addLink(i, linkPos);
322-
node.addLink(ladderNode.id, linkPos);
330+
if (randomDestinations && !targets.empty()) {
331+
// link all possible targets
332+
for (int k = 0; k < targets.size(); k++) {
333+
LeafNode& entNode = addPointEntityNode(map, mesh, targets[k], pointMins, pointMaxs);
334+
linkEntityLeaves(map, mesh, entNode, regionLeaves);
335+
336+
teleNode.addLink(entNode.id, teleNode.origin);
323337
}
324338
}
339+
else if (pentTarget != -1) {
340+
LeafNode& entNode = addPointEntityNode(map, mesh, pentTarget, pointMins, pointMaxs);
341+
linkEntityLeaves(map, mesh, entNode, regionLeaves);
325342

326-
mesh->nodes.push_back(ladderNode);
343+
teleNode.addLink(entNode.id, teleNode.origin);
344+
}
327345
}
328346
}
329347
}
330348

349+
void LeafNavMeshGenerator::linkEntityLeaves(Bsp* map, LeafNavMesh* mesh, LeafNode& entNode, vector<bool>& regionLeaves) {
350+
mesh->octree->getLeavesInRegion(&entNode, regionLeaves);
351+
352+
// link teleport destinations to touched nodes
353+
for (int i = 0; i < mesh->nodes.size(); i++) {
354+
if (!regionLeaves[i]) {
355+
continue;
356+
}
357+
358+
LeafNode& node = mesh->nodes[i];
359+
if (boxesIntersect(node.mins, node.maxs, entNode.mins, entNode.maxs)) {
360+
vec3 linkPos = entNode.origin;
361+
linkPos.z = node.origin.z;
362+
363+
entNode.addLink(i, linkPos);
364+
node.addLink(entNode.id, linkPos);
365+
}
366+
}
367+
}
368+
369+
LeafNode& LeafNavMeshGenerator::addSolidEntityNode(Bsp* map, LeafNavMesh* mesh, int entidx) {
370+
Entity* ent = map->ents[entidx];
371+
vector<LeafNode> leaves = getHullLeaves(map, ent->getBspModelIdx(), CONTENTS_SOLID);
372+
373+
// create a special ladder node which is a combination of all its leaves
374+
LeafNode ladderNode = LeafNode();
375+
ladderNode.mins = vec3(FLT_MAX, FLT_MAX, FLT_MAX);
376+
ladderNode.maxs = vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
377+
378+
for (LeafNode& node : leaves) {
379+
expandBoundingBox(node.mins, ladderNode.mins, ladderNode.maxs);
380+
expandBoundingBox(node.maxs, ladderNode.mins, ladderNode.maxs);
381+
382+
for (int i = 0; i < node.leafFaces.size(); i++) {
383+
ladderNode.leafFaces.push_back(node.leafFaces[i]);
384+
}
385+
}
386+
ladderNode.origin = (ladderNode.mins + ladderNode.maxs) * 0.5f;
387+
ladderNode.id = mesh->nodes.size();
388+
ladderNode.entidx = entidx;
389+
390+
mesh->nodes.push_back(ladderNode);
391+
return mesh->nodes[mesh->nodes.size() - 1];
392+
}
393+
394+
LeafNode& LeafNavMeshGenerator::addPointEntityNode(Bsp* map, LeafNavMesh* mesh, int entidx, vec3 mins, vec3 maxs) {
395+
Entity* ent = map->ents[entidx];
396+
397+
LeafNode node = LeafNode();
398+
node.origin = node.center = ent->getOrigin();
399+
node.mins = node.origin + mins;
400+
node.maxs = node.origin + maxs;
401+
node.id = mesh->nodes.size();
402+
node.entidx = entidx;
403+
404+
mesh->nodes.push_back(node);
405+
return mesh->nodes[mesh->nodes.size() - 1];
406+
}
407+
331408
int LeafNavMeshGenerator::tryFaceLinkLeaves(Bsp* map, LeafNavMesh* mesh, int srcLeafIdx, int dstLeafIdx) {
332409
LeafNode& srcLeaf = mesh->nodes[srcLeafIdx];
333410
LeafNode& dstLeaf = mesh->nodes[dstLeafIdx];

Diff for: src/nav/LeafNavMeshGenerator.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,16 @@ class LeafNavMeshGenerator {
3535
// links nav leaves which have faces touching each other
3636
void linkNavLeaves(Bsp* map, LeafNavMesh* mesh);
3737

38-
// use ladder entities to create cheaper paths between leaves
39-
void linkLadderLeaves(Bsp* map, LeafNavMesh* mesh);
38+
// use entities to create cheaper paths between leaves
39+
void linkEntityLeaves(Bsp* map, LeafNavMesh* mesh);
40+
41+
void linkEntityLeaves(Bsp* map, LeafNavMesh* mesh, LeafNode& entNode, vector<bool>& regionLeaves);
42+
43+
// returns a combined node for an entity, which is the bounding box of all its model leaves
44+
LeafNode& addSolidEntityNode(Bsp* map, LeafNavMesh* mesh, int entidx);
45+
46+
// returns a node for an entity, which is its bounding box
47+
LeafNode& addPointEntityNode(Bsp* map, LeafNavMesh* mesh, int entidx, vec3 mins, vec3 maxs);
4048

4149
int tryFaceLinkLeaves(Bsp* map, LeafNavMesh* mesh, int srcLeafIdx, int dstLeafIdx);
4250

0 commit comments

Comments
 (0)