Generates a PLY collision mesh and a .gset file from Apex Legends BSP map files, for use with Recast navigation mesh generation.
The PLY contains the combined collision geometry:
- BVH worldspawn collision (the map's static world geometry)
- Static prop collision from STL files (physics meshes exported from RPAKs)
- Entity/dynamic prop geometry from cast files (visual mesh LODs exported from RPAKs)
The .gset contains metadata for Recast:
- Zipline off-mesh connections
- Door trigger volumes
- Trigger exclusion zones (out-of-bounds, slip, hurt)
- Python 3.10+
- Python packages:
numpy,scipy bsp_tool— install viapip install bsp_tool, or point to a local copy with--bsp-tool-path- RSX (for exporting model assets from RPAKs)
- HarmonyVPKTool (for extracting map files from VPKs)
Map VPKs are located in <game_folder>\vpk. Open any of the map's VPK files in HarmonyVPKTool:
client_mp_rr_<mapname>.bsp.pak000_000.vpkenglishclient_mp_rr_<mapname>.bsp.pak000_dir.vpkenglishserver_mp_rr_<mapname>.bsp.pak000_dir.vpk
They all reference the same underlying data. Extract the entire VPK. You need the .bsp, .bsp_lump files, and .ent files.
RPAKs are also located in <game_folder>\paks\Win64. You need to load the following RPAKs (can be loaded all together or separately):
common_early.rpakcommon.rpakcommon_mp.rpaklobby.rpak(not present in all builds)mp_lobby.rpak(not present in all builds)- The map's own
.rpakfile
Go to Edit > Settings and configure:
- MDL export format:
CAST - Physics contents filter:
46E30203— this filters exports to only include models that have collision data, skipping things like vegetation and leaf particles that have no physics relevance. - Physics contents filter exclusive: OFF
- Physics contents filter require all: OFF
Note: RSX may crash and reset your settings. Always double-check the physics filter is set before exporting.
Important: Do not export props without the physics filter. Extra models without collision data will be included in the PLY and can produce incorrect navigation meshes.
Verify the physics filter is set (see above), then export the model data. Cast files provide the visual mesh geometry used for entity and dynamic props (e.g. prop_dynamic, player_vehicle). The script uses the lowest available LOD.
Change the MDL export format to STL (Respawn Physics). Verify the physics filter is still set — RSX may have reset it. Export again with the same RPAKs loaded. STL files provide the physics collision meshes used for static props. These represent what players actually collide with in-game, which is more accurate than visual geometry for navigation.
Both exports go to RSX's configured output directory. Point -m at that directory when running the script.
py gen-ply.py <path_to_extracted.bsp> -m <path_to_rsx_output_mdl_folder>
This produces <map_name>.ply and <map_name>.gset in the current directory.
Load the .gset file in Recast. The .gset references the PLY mesh and includes all off-mesh connections, door volumes, and trigger zones needed for navmesh generation.
py gen-ply.py [-h] [-o OUTPUT] -m MDL_FOLDER [--bsp-tool-path BSP_TOOL_PATH]
[-c CONFIG] [--info INFO] bsp_path
| Argument | Description |
|---|---|
bsp_path |
Path to the .bsp file |
-o |
Output .ply path (default: <map_name>.ply in current directory) |
-m |
Path to exported MDL folder containing .stl and .cast files (required) |
--bsp-tool-path |
Path to bsp_tool package directory, if not pip-installed |
-c |
Path to config JSON (default: config.json next to the script) |
--info |
Write a summary report to the given file path |
Model filter lists are stored in config.json (next to the script by default, or override with --config):
walkthrough_models: Models that have collision flagged as solid but players walk through in-game (vegetation, traffic cones, etc.). These are excluded from the PLY.scripted_door_models:prop_dynamicmodels that are actually scripted doors. These are excluded from prop geometry and instead written as trigger volumes in the.gset.