@@ -27,7 +27,7 @@ LeafNavMesh* LeafNavMeshGenerator::generate(Bsp* map) {
27
27
28
28
linkNavLeaves (map, navmesh);
29
29
setLeafOrigins (map, navmesh);
30
- linkLadderLeaves (map, navmesh);
30
+ linkEntityLeaves (map, navmesh);
31
31
calcPathCosts (map, navmesh);
32
32
33
33
int totalSz = 0 ;
@@ -278,56 +278,133 @@ void LeafNavMeshGenerator::linkNavLeaves(Bsp* map, LeafNavMesh* mesh) {
278
278
logf (" Added %d nav leaf links in %.2fs\n " , numLinks, (float )glfwGetTime () - linkStart);
279
279
}
280
280
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
+
282
288
for (int i = 0 ; i < map->ents .size (); i++) {
283
289
Entity* ent = map->ents [i];
284
290
285
291
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);
287
301
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;
292
305
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 ;
296
309
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 ;
300
312
}
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
+ }
313
323
}
324
+ }
314
325
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
+ }
320
329
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 );
323
337
}
324
338
}
339
+ else if (pentTarget != -1 ) {
340
+ LeafNode& entNode = addPointEntityNode (map, mesh, pentTarget, pointMins, pointMaxs);
341
+ linkEntityLeaves (map, mesh, entNode, regionLeaves);
325
342
326
- mesh->nodes .push_back (ladderNode);
343
+ teleNode.addLink (entNode.id , teleNode.origin );
344
+ }
327
345
}
328
346
}
329
347
}
330
348
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
+
331
408
int LeafNavMeshGenerator::tryFaceLinkLeaves (Bsp* map, LeafNavMesh* mesh, int srcLeafIdx, int dstLeafIdx) {
332
409
LeafNode& srcLeaf = mesh->nodes [srcLeafIdx];
333
410
LeafNode& dstLeaf = mesh->nodes [dstLeafIdx];
0 commit comments