Mapping a Map with Lua

Wizard coders, I need yall’s help.

I’m making a gamemode in which objects will be spawned in random parts of the map for players to find. I’m trying to make a code solution that will work on most every map. I started with this:



choose a random position vector within 50,000 units of center
if that point passes a util.IsInWorld() check and a util.PointContents (testfogvolume or empty) check, spawn here


But this ran into problems with a lot of maps having random huge technically playable, but not actually accessible un-spaces (really weird shit, Flatgrass is a good example) that the code would spawn things in. Like huge pockets of physically exist-able space leagues outside of the main area of the map. In some maps, the ground was non-solid only several meters below, where you’d be walking around in this freaky limbo type area. Problem is that the code sees this as playable space and sticks shit in it.

I tried to create another solution that would perform a one-time function that recursively mapped-out a single contiguous volume by using multiple steps and a shitload of spatial traces starting at a player’s spawnpoint (“into_player_start”). While the function worked very well in generating for me a table of world-vectors that represented good spawn points, it had two problems.

  1. in order to get enough granularity to both be able to map out large outdoor spaces as well as zoom around all in buildings with winding corridors, I had to do a fuckton of calculations, which was just too much calculation.
  2. not all maps have info_player_starts. What the fuck.

I’ve resorted to just having players run around before the game starts spawning little nodes from the spawnmenu in places, which I then use as anchors for spatial calculations when spawning things (line-of-sight etc). But it’s tedious to spawn these things at every hallway intersection like in cs_office.

Is there some kind of existing info_ entity or ai_ or some other type of invisible whatever that exists on hammer maps in order to mark the normal playable player-space? Or even the boundaries? Either would solve my problem. Howabout some existing info_ or hint_ whatever nodes that I can just rely on to be anchor points for spatial spawning calculations?

Or am I doomed to just have to use manually-spawned nodes to combat bullshit maps that have huge un-reachable spaces in the ether… does anyone have any ideas?

TL;DR: how do i reliably find the contiguous player-space on a map

ALSO!

Is there a way for lua to detect if a map has ai nodes? (nav nodes)? Is there a class of object that I can search for?

it sounds like you’re finding the 3d skyboxes of the maps you’re using, and if you are, they all have sky_camera entities inside of them, but I’m not sure if those get baked in or not

The inefficient solution would be a file with spawn positions for each map…
Easier yet iniefficient

NAV files corresponding to the BSP should have the information you need (particularly navigation areas). They can be automatically generated if not present, though that’s not always 100% reliable.

Thanks guys, I’ll take a look at these possible solutions.

@PortalGod

Sounds like I’ll be able to eliminate the skybox issue by simply checking to ensure I’m not near any sky_camera entities.

After investigating the nav meshes, it seems they actually do everything I want, which is pretty cool. Is there any way to actually get information from them with Lua? For instance, I generated a nav mesh manually for cs_office and saved it as a .nav file… but what about Lua? The wiki shows me a library of nav mesh functions, is that the same system?

Also, shouldn’t the existence of a nav mesh for a map enable AI to navigate it? I made a mesh for cs_office and saved it, then restarted and it’s still there, but zombies still can’t follow me beyond a mere 15 meters.

I actually already came up with a solution for this; it includes building a list of player positions as the game progresses, and using that to spawn items from. It starts out a bit slow, but it guaranteed to only spawn items in player-accessible areas, purely under the logic that a player has at one point accessed the area. I uploaded it to the Untitled repository, you can see the code there; https://github.com/Maurdekye/Untitled/blob/master/gamemode/modules/Maurdekye/sv_random_drops.lua

If you like, you can save the array of positions and modify the code slightly so that it just loads them back in.

You’re looking out too far… The map dimensions are 32k in width, height and depth… -16k to +16k ( 16384 )…

You could use player movement ( as the previous example uses ) to detect locations, but that could be too much… I’d recommend using math.random( 1, #player.GetAll( ) ) inside of Player( ) to get a random player, then spawn something near them at each spawn cycle, even going as far as using up to x percent of the player-base, if you go that route…

Another route would be, on InitPostEntity, would be to process possible spawn locations at the start of the map. Every map has entities, some of which shouldn’t be used such as lua_run, env_soundscape, etc… but some that can be used such as prop_physics / prop_physicsmultiplayer, player spawn locations, etc…

You could store those locations then branch off from there creating a different spawn group each time the map is located ( they’d be in the area of the original, but you could distance them out as far as you want so they could be randomized that way )… use a few trace-hulls to ensure they’re proper spawn locations and build the final position list ( optionally saving it so it only needs to be generated once; add a console command for rcon in case the current spawn list is bad so it’ll force a new one to be generated )…

Edit: A quick note about the unaccessible locations… Log how many times something was spawned and how many times those objects have been picked up and how many times the map has loaded… These would be a simple addition to the table or to the spawn-point. If no body has picked up the object ( ever ) in x number of loads, then that spawn point is marked inaccessible and stored as a bad spot in another table which is checked prior to creating a new spawn ( if you want x number of spawns per map it’d be good to create them first then if bad, on remove create a new one )…