├── addons └── sourcemod │ ├── plugins │ └── navmesh-test.smx │ └── scripting │ ├── navmesh-test.sp │ ├── include │ └── navmesh.inc │ └── navmesh.sp └── README.md /addons/sourcemod/plugins/navmesh-test.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kenzzer/sourcepawn-navmesh/HEAD/addons/sourcemod/plugins/navmesh-test.smx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #SourcePawn NavMesh 2 | 3 | This is basically a SourceMod plugin that can parse .NAV files and make data out of it that 4 | SourceMod plugins can read from. This plugin by itself doesn't do anything other than read 5 | data from the .NAV file. Other plugins have to utilize this plugin's features in order for 6 | this to have any purpose. 7 | 8 | Special thanks goes to Anthony Iacano (pimpinjuice) for the parser code, which can be found here: 9 | https://github.com/AnthonyIacono/War3SourceV2/tree/master/Nav 10 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/navmesh-test.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #pragma newdecls required 6 | #include 7 | 8 | #define PLUGIN_VERSION "1.0.2" 9 | 10 | int g_iPathLaserModelIndex = -1; 11 | 12 | public Plugin myinfo = 13 | { 14 | name = "SP-Readable Navigation Mesh Test", 15 | author = "KitRifty, Benoist3012", 16 | description = "Testing plugin of the SP-Readable Navigation Mesh plugin.", 17 | version = PLUGIN_VERSION, 18 | url = "" 19 | } 20 | 21 | public void OnPluginStart() 22 | { 23 | RegConsoleCmd("sm_navmesh_collectsurroundingareas", Command_NavMeshCollectSurroundingAreas); 24 | RegConsoleCmd("sm_navmesh_buildpath", Command_NavMeshBuildPath); 25 | RegConsoleCmd("sm_navmesh_worldtogridx", Command_NavMeshWorldToGridX); 26 | RegConsoleCmd("sm_navmesh_worldtogridy", Command_NavMeshWorldToGridY); 27 | RegConsoleCmd("sm_navmesh_getareasongrid", Command_GetNavAreasOnGrid); 28 | RegConsoleCmd("sm_navmesh_getareanavindex", Command_GetArea); 29 | RegConsoleCmd("sm_navmesh_getnearestarea", Command_GetNearestArea); 30 | RegConsoleCmd("sm_navmesh_getadjacentareas", Command_GetAdjacentNavAreas); 31 | } 32 | 33 | public void OnMapStart() 34 | { 35 | g_iPathLaserModelIndex = PrecacheModel("materials/sprites/laserbeam.vmt"); 36 | } 37 | 38 | public Action Command_GetArea(int client,int args) 39 | { 40 | if (!NavMesh_Exists()) return Plugin_Handled; 41 | 42 | float flEyePos[3], flEyeDir[3], flEndPos[3]; 43 | GetClientEyePosition(client, flEyePos); 44 | GetClientEyeAngles(client, flEyeDir); 45 | GetAngleVectors(flEyeDir, flEyeDir, NULL_VECTOR, NULL_VECTOR); 46 | NormalizeVector(flEyeDir, flEyeDir); 47 | ScaleVector(flEyeDir, 1000.0); 48 | AddVectors(flEyePos, flEyeDir, flEndPos); 49 | 50 | Handle hTrace = TR_TraceRayFilterEx(flEyePos, 51 | flEndPos, 52 | MASK_PLAYERSOLID_BRUSHONLY, 53 | RayType_EndPoint, 54 | TraceRayDontHitEntity, 55 | client); 56 | 57 | TR_GetEndPosition(flEndPos, hTrace); 58 | CloseHandle(hTrace); 59 | 60 | int iAreaID = NavMesh_GetNearestArea(flEndPos); 61 | 62 | PrintToChat(client, "Nearest area ID: %d", iAreaID); 63 | 64 | return Plugin_Handled; 65 | } 66 | 67 | public Action Command_GetNearestArea(int client,int args) 68 | { 69 | if (!NavMesh_Exists()) return Plugin_Handled; 70 | float flEyePos[3], flEyeDir[3], flEndPos[3]; 71 | GetClientEyePosition(client, flEyePos); 72 | GetClientEyeAngles(client, flEyeDir); 73 | GetAngleVectors(flEyeDir, flEyeDir, NULL_VECTOR, NULL_VECTOR); 74 | NormalizeVector(flEyeDir, flEyeDir); 75 | ScaleVector(flEyeDir, 1000.0); 76 | AddVectors(flEyePos, flEyeDir, flEndPos); 77 | 78 | Handle hTrace = TR_TraceRayFilterEx(flEyePos, 79 | flEndPos, 80 | MASK_PLAYERSOLID_BRUSHONLY, 81 | RayType_EndPoint, 82 | TraceRayDontHitEntity, 83 | client); 84 | 85 | TR_GetEndPosition(flEndPos, hTrace); 86 | CloseHandle(hTrace); 87 | 88 | int x = NavMesh_WorldToGridX(flEndPos[0]); 89 | int y = NavMesh_WorldToGridY(flEndPos[1]); 90 | int iGridIndex = x + y * NavMesh_GetGridSizeX(); 91 | 92 | int iAreaIndex = NavMesh_GetNearestArea(flEndPos); 93 | if (iAreaIndex != -1) 94 | { 95 | Handle hAreas = NavMesh_GetAreas(); 96 | int iAreaID = GetArrayCell(hAreas, iAreaIndex, NavMeshArea_ID); 97 | 98 | PrintToChat(client, "Nearest area ID found from spiral out of %d: %d", iGridIndex, iAreaID); 99 | } 100 | else 101 | { 102 | PrintToChat(client, "Could not find nearest area in spiral out of %d!", iGridIndex); 103 | } 104 | 105 | return Plugin_Handled; 106 | } 107 | 108 | public Action Command_GetAdjacentNavAreas(int client,int args) 109 | { 110 | if (!NavMesh_Exists()) return Plugin_Handled; 111 | 112 | if (args < 2) 113 | { 114 | ReplyToCommand(client, "Usage: sm_navmesh_getadjacentareas "); 115 | return Plugin_Handled; 116 | } 117 | 118 | Handle hAreas = NavMesh_GetAreas(); 119 | if (hAreas == INVALID_HANDLE) return Plugin_Handled; 120 | 121 | char sAreaID[64]; 122 | GetCmdArg(1, sAreaID, sizeof(sAreaID)); 123 | 124 | int iAreaID = StringToInt(sAreaID); 125 | 126 | int iStartAreaIndex = FindValueInArray(hAreas, iAreaID); 127 | if (iStartAreaIndex == -1) return Plugin_Handled; 128 | 129 | char sNavDirection[64]; 130 | GetCmdArg(2, sNavDirection, sizeof(sNavDirection)); 131 | 132 | int iNavDirection = StringToInt(sNavDirection); 133 | if (iNavDirection >= NAV_DIR_COUNT) 134 | { 135 | ReplyToCommand(client, "Invalid direction! Direction cannot reach %d!", NAV_DIR_COUNT); 136 | return Plugin_Handled; 137 | } 138 | 139 | Handle hAdjacentAreas = CreateStack(); 140 | NavMeshArea_GetAdjacentList(hAdjacentAreas, iStartAreaIndex, iNavDirection); 141 | 142 | if (!IsStackEmpty(hAdjacentAreas)) 143 | { 144 | while (!IsStackEmpty(hAdjacentAreas)) 145 | { 146 | int iAreaIndex = -1; 147 | PopStackCell(hAdjacentAreas, iAreaIndex); 148 | PrintToChat(client, "Found adjacent area (ID: %d) for area ID %d", GetArrayCell(hAreas, iAreaIndex), iAreaID); 149 | } 150 | 151 | CloseHandle(hAdjacentAreas); 152 | } 153 | else 154 | { 155 | PrintToChat(client, "Found no adjacent areas for area ID %d", iAreaID); 156 | } 157 | 158 | CloseHandle(hAdjacentAreas); 159 | 160 | return Plugin_Handled; 161 | } 162 | 163 | public Action Command_NavMeshCollectSurroundingAreas(int client,int args) 164 | { 165 | if (args < 2) 166 | { 167 | ReplyToCommand(client, "Usage: sm_navmesh_collectsurroundingareas "); 168 | return Plugin_Handled; 169 | } 170 | 171 | if (!NavMesh_Exists()) return Plugin_Handled; 172 | 173 | Handle hAreas = NavMesh_GetAreas(); 174 | if (hAreas == INVALID_HANDLE) return Plugin_Handled; 175 | 176 | char sAreaID[64]; 177 | GetCmdArg(1, sAreaID, sizeof(sAreaID)); 178 | 179 | int iAreaIndex = FindValueInArray(hAreas, StringToInt(sAreaID)); 180 | 181 | if (iAreaIndex == -1 || iAreaIndex == -1) return Plugin_Handled; 182 | 183 | char sMaxDist[64]; 184 | GetCmdArg(2, sMaxDist, sizeof(sMaxDist)); 185 | 186 | float flMaxDist = StringToFloat(sMaxDist); 187 | 188 | Handle hProfiler = CreateProfiler(); 189 | StartProfiling(hProfiler); 190 | 191 | Handle hNearAreas = CreateStack(); 192 | NavMesh_CollectSurroundingAreas(hNearAreas, iAreaIndex, flMaxDist); 193 | 194 | StopProfiling(hProfiler); 195 | 196 | float flProfileTime = GetProfilerTime(hProfiler); 197 | 198 | CloseHandle(hProfiler); 199 | 200 | if (!IsStackEmpty(hNearAreas)) 201 | { 202 | int iAreaCount; 203 | while (!IsStackEmpty(hNearAreas)) 204 | { 205 | int iSomething; 206 | PopStackCell(hNearAreas, iSomething); 207 | iAreaCount++; 208 | } 209 | 210 | if (client > 0) 211 | { 212 | PrintToChat(client, "Collected %d areas in %f seconds.", iAreaCount, flProfileTime); 213 | } 214 | else 215 | { 216 | PrintToServer("Collected %d areas in %f seconds.", iAreaCount, flProfileTime); 217 | } 218 | } 219 | 220 | CloseHandle(hNearAreas); 221 | 222 | return Plugin_Handled; 223 | } 224 | 225 | public Action Command_NavMeshWorldToGridX(int client,int args) 226 | { 227 | if (args < 1) return Plugin_Handled; 228 | 229 | char arg1[32]; 230 | GetCmdArg(1, arg1, sizeof(arg1)); 231 | 232 | float flpl = StringToFloat(arg1); 233 | 234 | ReplyToCommand(client, "Grid x: %d", NavMesh_WorldToGridX(flpl)); 235 | 236 | return Plugin_Handled; 237 | } 238 | 239 | public Action Command_NavMeshWorldToGridY(int client,int args) 240 | { 241 | if (args < 1) return Plugin_Handled; 242 | 243 | char arg1[32]; 244 | GetCmdArg(1, arg1, sizeof(arg1)); 245 | 246 | float flpl = StringToFloat(arg1); 247 | 248 | ReplyToCommand(client, "Grid y: %d", NavMesh_WorldToGridY(flpl)); 249 | 250 | return Plugin_Handled; 251 | } 252 | 253 | public Action Command_GetNavAreasOnGrid(int client,int args) 254 | { 255 | if (args < 2) return Plugin_Handled; 256 | 257 | char arg1[32]; 258 | GetCmdArg(1, arg1, sizeof(arg1)); 259 | 260 | int x = StringToInt(arg1); 261 | 262 | char arg2[32]; 263 | GetCmdArg(2, arg2, sizeof(arg2)); 264 | 265 | int y = StringToInt(arg2); 266 | 267 | Handle hAreas = CreateStack(); 268 | NavMesh_GetAreasOnGrid(hAreas, x, y); 269 | 270 | if (!IsStackEmpty(hAreas)) 271 | { 272 | while (!IsStackEmpty(hAreas)) 273 | { 274 | int iAreaIndex = -1; 275 | PopStackCell(hAreas, iAreaIndex); 276 | 277 | ReplyToCommand(client, "%d", iAreaIndex); 278 | } 279 | } 280 | 281 | CloseHandle(hAreas); 282 | 283 | return Plugin_Handled; 284 | } 285 | 286 | public Action Command_NavMeshBuildPath(int client,int args) 287 | { 288 | if (args < 2) 289 | { 290 | ReplyToCommand(client, "Usage: sm_navmesh_buildpath "); 291 | return Plugin_Handled; 292 | } 293 | 294 | if (!NavMesh_Exists()) return Plugin_Handled; 295 | 296 | Handle hAreas = NavMesh_GetAreas(); 297 | if (hAreas == INVALID_HANDLE) return Plugin_Handled; 298 | 299 | char sStartAreaID[64], sGoalAreaID[64]; 300 | GetCmdArg(1, sStartAreaID, sizeof(sStartAreaID)); 301 | GetCmdArg(2, sGoalAreaID, sizeof(sGoalAreaID)); 302 | 303 | int iStartAreaIndex = FindValueInArray(hAreas, StringToInt(sStartAreaID)); 304 | int iGoalAreaIndex = FindValueInArray(hAreas, StringToInt(sGoalAreaID)); 305 | 306 | if (iStartAreaIndex == -1 || iGoalAreaIndex == -1) return Plugin_Handled; 307 | 308 | float flGoalPos[3]; 309 | NavMeshArea_GetCenter(iGoalAreaIndex, flGoalPos); 310 | 311 | int iColor[4] = { 0, 255, 0, 255 }; 312 | 313 | float flMaxPathLength = 0.0; 314 | if (args > 2) 315 | { 316 | char sMaxPathLength[64]; 317 | GetCmdArg(3, sMaxPathLength, sizeof(sMaxPathLength)); 318 | flMaxPathLength = StringToFloat(sMaxPathLength); 319 | 320 | if (flMaxPathLength < 0.0) return Plugin_Handled; 321 | } 322 | 323 | float flMaxStepSize = 0.0; 324 | char sMaxStepSize[64]; 325 | GetCmdArg(4, sMaxStepSize, sizeof(sMaxStepSize)); 326 | flMaxStepSize = StringToFloat(sMaxStepSize); 327 | 328 | int iClosestAreaIndex = 0; 329 | 330 | Handle hProfiler = CreateProfiler(); 331 | StartProfiling(hProfiler); 332 | 333 | bool bBuiltPath = NavMesh_BuildPath(iStartAreaIndex, 334 | iGoalAreaIndex, 335 | flGoalPos, 336 | NavMeshShortestPathCost, 337 | _, 338 | iClosestAreaIndex, 339 | flMaxPathLength, 340 | flMaxStepSize); 341 | 342 | StopProfiling(hProfiler); 343 | 344 | float flProfileTime = GetProfilerTime(hProfiler); 345 | 346 | CloseHandle(hProfiler); 347 | 348 | if (client > 0) 349 | { 350 | PrintToChat(client, "Path built!\nBuild path time: %f\nReached goal: %d", flProfileTime, bBuiltPath); 351 | 352 | int iTempAreaIndex = iClosestAreaIndex; 353 | int iParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex); 354 | int iNavDirection; 355 | float flHalfWidth; 356 | 357 | float flCenterPortal[3], flClosestPoint[3]; 358 | 359 | Handle hPositions = CreateArray(3); 360 | 361 | PushArrayArray(hPositions, flGoalPos, 3); 362 | 363 | while (iParentAreaIndex != -1) 364 | { 365 | float flTempAreaCenter[3], flParentAreaCenter[3]; 366 | NavMeshArea_GetCenter(iTempAreaIndex, flTempAreaCenter); 367 | NavMeshArea_GetCenter(iParentAreaIndex, flParentAreaCenter); 368 | 369 | iNavDirection = NavMeshArea_ComputeDirection(iTempAreaIndex, flParentAreaCenter); 370 | NavMeshArea_ComputePortal(iTempAreaIndex, iParentAreaIndex, iNavDirection, flCenterPortal, flHalfWidth); 371 | NavMeshArea_ComputeClosestPointInPortal(iTempAreaIndex, iParentAreaIndex, iNavDirection, flCenterPortal, flClosestPoint); 372 | 373 | flClosestPoint[2] = NavMeshArea_GetZ(iTempAreaIndex, flClosestPoint); 374 | 375 | PushArrayArray(hPositions, flClosestPoint, 3); 376 | 377 | iTempAreaIndex = iParentAreaIndex; 378 | iParentAreaIndex = NavMeshArea_GetParent(iTempAreaIndex); 379 | } 380 | 381 | float flStartPos[3]; 382 | NavMeshArea_GetCenter(iStartAreaIndex, flStartPos); 383 | PushArrayArray(hPositions, flStartPos, 3); 384 | 385 | for (int i = GetArraySize(hPositions) - 1; i > 0; i--) 386 | { 387 | float flFromPos[3], flToPos[3]; 388 | GetArrayArray(hPositions, i, flFromPos, 3); 389 | GetArrayArray(hPositions, i - 1, flToPos, 3); 390 | 391 | TE_SetupBeamPoints(flFromPos, 392 | flToPos, 393 | g_iPathLaserModelIndex, 394 | g_iPathLaserModelIndex, 395 | 0, 396 | 30, 397 | 5.0, 398 | 5.0, 399 | 5.0, 400 | 5, 401 | 0.0, 402 | iColor, 403 | 30); 404 | 405 | TE_SendToClient(client); 406 | } 407 | } 408 | else 409 | { 410 | PrintToServer("Path built!\nBuild path time: %f\nReached goal: %d", flProfileTime, bBuiltPath); 411 | } 412 | 413 | return Plugin_Handled; 414 | } 415 | 416 | public bool TraceRayDontHitEntity(int entity,int mask, any data) 417 | { 418 | if (entity == data) return false; 419 | return true; 420 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/include/navmesh.inc: -------------------------------------------------------------------------------- 1 | #if defined _navmesh_included 2 | #endinput 3 | #endif 4 | #define _navmesh_included 5 | 6 | #define HalfHumanHeight 35.5 7 | #define StepHeight 18.0 8 | 9 | #define NAV_MAGIC_NUMBER 0xFEEDFACE 10 | 11 | #define WALK_THRU_PROP_DOORS 0x01 12 | #define WALK_THRU_FUNC_DOORS 0x02 13 | #define WALK_THRU_DOORS (WALK_THRU_PROP_DOORS | WALK_THRU_FUNC_DOORS) 14 | #define WALK_THRU_BREAKABLES 0x04 15 | #define WALK_THRU_TOGGLE_BRUSHES 0x08 16 | #define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES | WALK_THRU_TOGGLE_BRUSHES) 17 | 18 | enum 19 | { 20 | NAV_DIR_NORTH = 0, 21 | NAV_DIR_EAST, 22 | NAV_DIR_SOUTH, 23 | NAV_DIR_WEST, 24 | NAV_DIR_COUNT 25 | }; 26 | 27 | enum 28 | { 29 | NAV_LADDER_DIR_UP = 0, 30 | NAV_LADDER_DIR_DOWN, 31 | NAV_LADDER_DIR_COUNT 32 | }; 33 | 34 | enum 35 | { 36 | NAV_MESH_CROUCH = 0x0001, 37 | NAV_MESH_JUMP = 0x0002, 38 | NAV_MESH_PRECISE = 0x0004, 39 | NAV_MESH_NO_JUMP = 0x0008, 40 | NAV_MESH_STOP = 0x0010, 41 | NAV_MESH_RUN = 0x0020, 42 | NAV_MESH_WALK = 0x0040, 43 | NAV_MESH_AVOID = 0x0080, 44 | NAV_MESH_TRANSIENT = 0x0100, 45 | NAV_MESH_DONT_HIDE = 0x0200, 46 | NAV_MESH_STAND = 0x0400, 47 | NAV_MESH_NO_HOSTAGES = 0x0800 48 | }; 49 | 50 | enum 51 | { 52 | GO_NORTH = 0, 53 | GO_EAST, 54 | GO_SOUTH, 55 | GO_WEST, 56 | GO_LADDER_UP, 57 | GO_LADDER_DOWN, 58 | GO_JUMP, 59 | NUM_TRAVERSE_TYPES 60 | }; 61 | 62 | enum NavCornerType 63 | { 64 | NAV_CORNER_NORTH_WEST = 0, 65 | NAV_CORNER_NORTH_EAST, 66 | NAV_CORNER_SOUTH_EAST, 67 | NAV_CORNER_SOUTH_WEST, 68 | NAV_CORNER_COUNT 69 | }; 70 | 71 | const CNavArea INVALID_NAV_AREA = view_as(-1); 72 | const CNavLadder INVALID_NAV_LADDER = view_as(-1); 73 | const HidingSpot INVALID_NAV_HIDING_SPOT = view_as(-1); 74 | 75 | typedef NavPathCostFunctor = function int(CNavArea area, CNavArea from, CNavLadder ladder, any data); 76 | 77 | 78 | // NavMesh 79 | 80 | native bool NavMesh_Exists(); 81 | 82 | native int NavMesh_GetMagicNumber(); 83 | 84 | native int NavMesh_GetVersion(); 85 | 86 | native int NavMesh_GetSubVersion(); 87 | 88 | native int NavMesh_GetSaveBSPSize(); 89 | 90 | native bool NavMesh_IsAnalyzed(); 91 | 92 | native bool NavMesh_GetGroundHeight(const float pos[3], float &height=-1.0, float normal[3]=NULL_VECTOR); 93 | 94 | native CNavArea NavMesh_FindAreaByID( int areaID ); 95 | 96 | native CNavArea NavMesh_GetArea(const float pos[3], float beneathLimit=120.0); 97 | 98 | native CNavArea NavMesh_GetNearestArea(const float pos[3], bool anyZ=false, float maxDist=10000.0, bool checkLOS=false, bool checkGround=true, int team=-2); 99 | 100 | native HidingSpot NavMesh_FindHidingSpotByID(int hidingSpotID); 101 | 102 | native HidingSpot NavMesh_GetRandomHidingSpot(); 103 | 104 | // These grid functions are more internal than anything. 105 | native int NavMesh_WorldToGridX(float wx); 106 | 107 | native int NavMesh_WorldToGridY(float wy); 108 | 109 | native void NavMesh_GetAreasOnGrid(ArrayStack hStack, int x, int y); 110 | 111 | native int NavMesh_GetGridSizeX(); 112 | 113 | native int NavMesh_GetGridSizeY(); 114 | 115 | 116 | native void NavMesh_CollectSurroundingAreas(ArrayStack hStack, CNavArea startArea, float travelDistLimit=1500.0, float maxStepUpLimit=StepHeight, float maxDropDownLimit=100.0); 117 | 118 | native bool NavMesh_BuildPath(CNavArea startArea, CNavArea goalArea, const float goalPos[3], NavPathCostFunctor costFunctor, any costData=0, CNavArea &closestArea=INVALID_NAV_AREA, float maxPathLength=0.0, float flMaxStepSize=0.0); 119 | 120 | 121 | 122 | // CNavArea 123 | 124 | native int NavMeshArea_GetID(int areaIndex); 125 | 126 | native int NavMeshArea_GetFlags(int areaIndex); 127 | 128 | native void NavMeshArea_GetPlace(int areaIndex, char[] buffer, int maxlen); 129 | 130 | native bool NavMeshArea_GetCenter(int areaIndex, float buffer[3]); 131 | 132 | native void NavMeshArea_GetAdjacentList(ArrayStack buffer, int areaIndex, int dir); 133 | 134 | native void NavMeshArea_GetLadderList(ArrayStack buffer, int areaIndex, int dir); 135 | 136 | native void NavMeshArea_GetHidingSpots(ArrayStack buffer, int areaIndex); 137 | 138 | native void NavMeshArea_GetClosestPointOnArea(int areaIndex, const float pos[3], float closePos[3]); 139 | 140 | native int NavMeshArea_GetTotalCost(int areaIndex); 141 | 142 | native int NavMeshArea_GetCostSoFar(int areaIndex); 143 | 144 | native int NavMeshArea_GetParent(int areaIndex); 145 | 146 | native int NavMeshArea_GetParentHow(int areaIndex); 147 | 148 | native void NavMeshArea_SetParent(int areaIndex, int parentAreaIndex); 149 | 150 | native void NavMeshArea_SetParentHow(int areaIndex, int parentHow); 151 | 152 | native bool NavMeshArea_GetExtentLow(int areaIndex, float buffer[3]); 153 | 154 | native bool NavMeshArea_GetExtentHigh(int areaIndex, float buffer[3]); 155 | 156 | native bool NavMeshArea_IsOverlappingPoint(int areaIndex, const float pos[3], float tolerance); 157 | 158 | native bool NavMeshArea_IsOverlappingArea(int areaIndex, int targetAreaIndex); 159 | 160 | native float NavMeshArea_GetNECornerZ(int areaIndex); 161 | 162 | native float NavMeshArea_GetSWCornerZ(int areaIndex); 163 | 164 | native void NavMeshArea_GetCorner(int areaIndex, NavCornerType corner, float buffer[3]); 165 | 166 | native float NavMeshArea_GetZ(int areaIndex, const float pos[3]); 167 | 168 | native float NavMeshArea_GetZFromXAndY(int areaIndex, float x, float y); 169 | 170 | native bool NavMeshArea_IsEdge(int areaIndex, int dir); 171 | 172 | native bool NavMeshArea_Contains(int areaIndex, const float pos[3]); 173 | 174 | native void NavMeshArea_GetRandomPoint(int areaIndex, float buffer[3]); 175 | 176 | native bool NavMeshArea_IsConnected(int areaIndex, int targetAreaIndex, int dir); 177 | 178 | native bool NavMeshArea_ComputePortal(int areaIndex, int areaToIndex, int dir, float center[3], float &halfWidth); 179 | 180 | native bool NavMeshArea_ComputeClosestPointInPortal(int areaIndex, int areaToIndex, int dir, const float fromPos[3], float closePos[3]); 181 | 182 | native int NavMeshArea_ComputeDirection(int areaIndex, const float pos[3]); 183 | 184 | native float NavMeshArea_GetLightIntensity(int areaIndex, const float pos[3]); 185 | 186 | methodmap CNavArea 187 | { 188 | public CNavArea( int index ) 189 | { 190 | return view_as(index); 191 | } 192 | 193 | property int Index 194 | { 195 | public get() { return view_as(this); } 196 | } 197 | 198 | property int ID 199 | { 200 | public get() { return NavMeshArea_GetID(this.Index); } 201 | } 202 | 203 | property int Attributes 204 | { 205 | public get() { return NavMeshArea_GetFlags(this.Index); } 206 | } 207 | 208 | property CNavArea Parent 209 | { 210 | public get() { return CNavArea(NavMeshArea_GetParent(this.Index)); } 211 | public set( CNavArea area ) { NavMeshArea_SetParent(this.Index, area.Index); } 212 | } 213 | 214 | property int ParentHow 215 | { 216 | public get() { return NavMeshArea_GetParentHow(this.Index); } 217 | public set( int how ) { NavMeshArea_SetParentHow(this.Index, how); } 218 | } 219 | 220 | property int TotalCost 221 | { 222 | public get() { return NavMeshArea_GetTotalCost(this.Index); } 223 | } 224 | 225 | property int CostSoFar 226 | { 227 | public get() { return NavMeshArea_GetCostSoFar(this.Index); } 228 | } 229 | 230 | property float NECornerZ 231 | { 232 | public get() { return NavMeshArea_GetNECornerZ(this.Index); } 233 | } 234 | 235 | property float SWCornerZ 236 | { 237 | public get() { return NavMeshArea_GetSWCornerZ(this.Index); } 238 | } 239 | 240 | public void GetPlace( char[] buffer, int maxlen ) 241 | { 242 | NavMeshArea_GetPlace(this.Index, buffer, maxlen); 243 | } 244 | 245 | public bool GetCenter( float buffer[3] ) 246 | { 247 | return NavMeshArea_GetCenter(this.Index, buffer); 248 | } 249 | 250 | public bool GetExtentLow( float buffer[3] ) 251 | { 252 | return NavMeshArea_GetExtentLow(this.Index, buffer); 253 | } 254 | 255 | public bool GetExtentHigh( float buffer[3] ) 256 | { 257 | return NavMeshArea_GetExtentHigh(this.Index, buffer); 258 | } 259 | 260 | public void GetCorner( NavCornerType corner, float buffer[3] ) 261 | { 262 | NavMeshArea_GetCorner( this.Index, corner, buffer ); 263 | } 264 | 265 | public float GetZ( const float point[3] ) 266 | { 267 | return NavMeshArea_GetZ(this.Index, point); 268 | } 269 | 270 | public float GetZFromXAndY( float x, float y ) 271 | { 272 | return NavMeshArea_GetZFromXAndY(this.Index, x, y); 273 | } 274 | 275 | public bool IsOverlappingPoint( const float point[3], float tolerance=0.0 ) 276 | { 277 | return NavMeshArea_IsOverlappingPoint(this.Index, point, tolerance); 278 | } 279 | 280 | public bool IsOverlappingArea( CNavArea area ) 281 | { 282 | return NavMeshArea_IsOverlappingArea(this.Index, area.Index); 283 | } 284 | 285 | public bool Contains( const float point[3] ) 286 | { 287 | return NavMeshArea_Contains(this.Index, point); 288 | } 289 | 290 | public bool IsEdge( int dir ) 291 | { 292 | return NavMeshArea_IsEdge(this.Index, dir); 293 | } 294 | 295 | public void GetRandomPoint( float buffer[3] ) 296 | { 297 | NavMeshArea_GetRandomPoint(this.Index, buffer); 298 | } 299 | 300 | public bool IsConnected( CNavArea targetArea, int dir ) 301 | { 302 | return NavMeshArea_IsConnected(this.Index, targetArea.Index, dir); 303 | } 304 | 305 | public void GetClosestPointOnArea( const float pos[3], float buffer[3] ) 306 | { 307 | NavMeshArea_GetClosestPointOnArea(this.Index, pos, buffer); 308 | } 309 | 310 | public void GetAdjacentAreas( int dir, ArrayStack buffer ) 311 | { 312 | NavMeshArea_GetAdjacentList( buffer, this.Index, dir ); 313 | } 314 | 315 | public int GetAdjacentCount( int dir ) 316 | { 317 | ArrayStack buffer = new ArrayStack(); 318 | this.GetAdjacentAreas( dir, buffer ); 319 | int count = 0; 320 | while (!buffer.Empty) 321 | { 322 | int value; 323 | PopStackCell(buffer, value); 324 | count++; 325 | } 326 | delete buffer; 327 | return count; 328 | } 329 | 330 | public CNavArea GetRandomAdjacentArea( int dir ) 331 | { 332 | ArrayStack buffer = new ArrayStack(); 333 | this.GetAdjacentAreas( dir, buffer ); 334 | 335 | if (buffer.Empty) 336 | { 337 | delete buffer; 338 | return INVALID_NAV_AREA; 339 | } 340 | 341 | ArrayList list = new ArrayList(); 342 | while (!buffer.Empty) 343 | { 344 | int value; 345 | PopStackCell(buffer, value); 346 | list.Push(value); 347 | } 348 | 349 | delete buffer; 350 | CNavArea area = CNavArea( list.Get( GetRandomInt(0, list.Length - 1) ) ); 351 | delete list; 352 | return area; 353 | } 354 | 355 | public void GetLadders( int dir, ArrayStack buffer ) 356 | { 357 | NavMeshArea_GetLadderList( buffer, this.Index, dir ); 358 | } 359 | 360 | public void GetHidingSpots( ArrayStack buffer ) 361 | { 362 | NavMeshArea_GetHidingSpots( buffer, this.Index ); 363 | } 364 | 365 | public void ComputePortal( CNavArea to, int dir, float center[3], float &halfWidth ) 366 | { 367 | NavMeshArea_ComputePortal(this.Index, to.Index, dir, center, halfWidth); 368 | } 369 | 370 | public void ComputeClosestPointInPortal( CNavArea to, int dir, const float fromPos[3], float closePos[3] ) 371 | { 372 | NavMeshArea_ComputeClosestPointInPortal(this.Index, to.Index, dir, fromPos, closePos); 373 | } 374 | 375 | public int ComputeDirection( const float point[3] ) 376 | { 377 | return NavMeshArea_ComputeDirection(this.Index, point); 378 | } 379 | 380 | public float GetLightIntensity( const float point[3] ) 381 | { 382 | return NavMeshArea_GetLightIntensity(this.Index, point); 383 | } 384 | } 385 | 386 | 387 | // HidingSpot 388 | 389 | enum 390 | { 391 | NAV_HIDING_SPOT_IN_COVER = 0x01, 392 | NAV_HIDING_SPOT_GOOD_SNIPER_SPOT = 0x02, 393 | NAV_HIDING_SPOT_IDEAL_SNIPER_SPOT = 0x04, 394 | NAV_HIDING_SPOT_EXPOSED = 0x08 395 | } 396 | 397 | native int NavHidingSpot_GetID(int hidingSpotIndex); 398 | 399 | native int NavHidingSpot_GetFlags(int hidingSpotIndex); 400 | 401 | native void NavHidingSpot_GetPosition(int hidingSpotIndex, float buffer[3]); 402 | 403 | native CNavArea NavHidingSpot_GetArea(int hidingSpotIndex); 404 | 405 | methodmap HidingSpot 406 | { 407 | public HidingSpot( int index ) 408 | { 409 | return view_as(index); 410 | } 411 | 412 | property int Index 413 | { 414 | public get() { return view_as(this); } 415 | } 416 | 417 | property int ID 418 | { 419 | public get() { return NavHidingSpot_GetID( this.Index ); } 420 | } 421 | 422 | property int Flags 423 | { 424 | public get() { return NavHidingSpot_GetFlags( this.Index ); } 425 | } 426 | 427 | public void GetPosition( float buffer[3] ) 428 | { 429 | NavHidingSpot_GetPosition( this.Index, buffer ); 430 | } 431 | 432 | public bool HasGoodCover() 433 | { 434 | return this.Flags & NAV_HIDING_SPOT_IN_COVER ? true : false; 435 | } 436 | 437 | public bool IsGoodSniperSpot() 438 | { 439 | return this.Flags & NAV_HIDING_SPOT_GOOD_SNIPER_SPOT ? true : false; 440 | } 441 | 442 | public bool IsIdealSniperSpot() 443 | { 444 | return this.Flags & NAV_HIDING_SPOT_IDEAL_SNIPER_SPOT ? true : false; 445 | } 446 | 447 | public bool IsExposed() 448 | { 449 | return this.Flags & NAV_HIDING_SPOT_EXPOSED ? true : false; 450 | } 451 | 452 | public CNavArea GetArea() 453 | { 454 | return NavHidingSpot_GetArea(this.Index); 455 | } 456 | } 457 | 458 | 459 | // CNavLadder 460 | 461 | native float NavMeshLadder_GetLength(int ladderIndex); 462 | 463 | native float NavMeshLadder_GetWidth(int ladderIndex); 464 | 465 | native CNavArea NavMeshLadder_GetTopForwardArea(int ladderIndex); 466 | 467 | native CNavArea NavMeshLadder_GetTopLeftArea(int ladderIndex); 468 | 469 | native CNavArea NavMeshLadder_GetTopRightArea(int ladderIndex); 470 | 471 | native CNavArea NavMeshLadder_GetTopBehindArea(int ladderIndex); 472 | 473 | native CNavArea NavMeshLadder_GetBottomArea(int ladderIndex); 474 | 475 | native void NavMeshLadder_GetTop(int ladderIndex, float buffer[3]); 476 | 477 | native void NavMeshLadder_GetBottom(int ladderIndex, float buffer[3]); 478 | 479 | methodmap CNavLadder 480 | { 481 | public CNavLadder( int index ) 482 | { 483 | return view_as(index); 484 | } 485 | 486 | property int Index 487 | { 488 | public get() { return view_as(this); } 489 | } 490 | 491 | property float Length 492 | { 493 | public get() { return NavMeshLadder_GetLength(this.Index); } 494 | } 495 | 496 | property float Width 497 | { 498 | public get() { return NavMeshLadder_GetWidth(this.Index); } 499 | } 500 | 501 | property CNavArea TopForwardArea 502 | { 503 | public get() { return NavMeshLadder_GetTopForwardArea(this.Index); } 504 | } 505 | 506 | property CNavArea TopLeftArea 507 | { 508 | public get() { return NavMeshLadder_GetTopLeftArea(this.Index); } 509 | } 510 | 511 | property CNavArea TopRightArea 512 | { 513 | public get() { return NavMeshLadder_GetTopRightArea(this.Index); } 514 | } 515 | 516 | property CNavArea TopBehindArea 517 | { 518 | public get() { return NavMeshLadder_GetTopBehindArea(this.Index); } 519 | } 520 | 521 | property CNavArea BottomArea 522 | { 523 | public get() { return NavMeshLadder_GetBottomArea(this.Index); } 524 | } 525 | 526 | public void GetTop( float buffer[3] ) 527 | { 528 | NavMeshLadder_GetTop(this.Index, buffer); 529 | } 530 | 531 | public void GetBottom( float buffer[3] ) 532 | { 533 | NavMeshLadder_GetBottom(this.Index, buffer); 534 | } 535 | } 536 | 537 | 538 | // SpotEncounter 539 | 540 | native CNavArea NavSpotEncounter_GetFrom(int spotEncounterIndex); 541 | 542 | native int NavSpotEncounter_GetFromDirection(int spotEncounterIndex); 543 | 544 | native CNavArea NavSpotEncounter_GetTo(int spotEncounterIndex); 545 | 546 | native int NavSpotEncounter_GetToDirection(int spotEncounterIndex); 547 | 548 | native void NavSpotEncounter_GetSpots(int spotEncounterIndex, ArrayStack buffer); 549 | 550 | methodmap SpotEncounter 551 | { 552 | public SpotEncounter( int index ) 553 | { 554 | return view_as(index); 555 | } 556 | 557 | property int Index 558 | { 559 | public get() { return view_as(this); } 560 | } 561 | 562 | property CNavArea From 563 | { 564 | public get() { return NavSpotEncounter_GetFrom(this.Index); } 565 | } 566 | 567 | property int FromDirection 568 | { 569 | public get() { return NavSpotEncounter_GetFromDirection(this.Index); } 570 | } 571 | 572 | property CNavArea To 573 | { 574 | public get() { return NavSpotEncounter_GetTo(this.Index); } 575 | } 576 | 577 | property int ToDirection 578 | { 579 | public get() { return NavSpotEncounter_GetToDirection(this.Index); } 580 | } 581 | 582 | public void GetSpots( ArrayStack buffer ) 583 | { 584 | NavSpotEncounter_GetSpots(this.Index, buffer); 585 | } 586 | } 587 | 588 | 589 | // SpotOrder 590 | 591 | native HidingSpot NavSpotOrder_GetHidingSpot(int spotOrderIndex); 592 | 593 | native int NavSpotOrder_GetParametricDistance(int spotOrderIndex); 594 | 595 | methodmap SpotOrder 596 | { 597 | public SpotOrder( int index ) 598 | { 599 | return view_as(index); 600 | } 601 | 602 | property int Index 603 | { 604 | public get() { return view_as(this); } 605 | } 606 | 607 | property HidingSpot HidingSpot 608 | { 609 | public get() { return NavSpotOrder_GetHidingSpot(this.Index); } 610 | } 611 | 612 | property int ParametricDistance 613 | { 614 | public get() { return NavSpotOrder_GetParametricDistance(this.Index); } 615 | } 616 | } 617 | 618 | 619 | // Shortest-path cost function for NavMesh_BuildPath. 620 | public int NavMeshShortestPathCost(CNavArea area, CNavArea from, CNavLadder ladder, any data) 621 | { 622 | if (from == INVALID_NAV_AREA) 623 | { 624 | return 0; 625 | } 626 | else 627 | { 628 | int iDist = 0; 629 | if (ladder != INVALID_NAV_LADDER) 630 | { 631 | iDist = RoundFloat(ladder.Length); 632 | } 633 | else 634 | { 635 | float flAreaCenter[3]; float flFromAreaCenter[3]; 636 | area.GetCenter(flAreaCenter); 637 | from.GetCenter(flFromAreaCenter); 638 | 639 | iDist = RoundFloat(GetVectorDistance(flAreaCenter, flFromAreaCenter)); 640 | } 641 | 642 | int iCost = iDist + from.CostSoFar; 643 | int iAreaFlags = area.Attributes; 644 | if (iAreaFlags & NAV_MESH_CROUCH) iCost += 20; 645 | if (iAreaFlags & NAV_MESH_JUMP) iCost += (5 * iDist); 646 | return iCost; 647 | } 648 | } 649 | 650 | // stocks 651 | 652 | stock bool IsEntityWalkable(int iEnt, int iFlags) 653 | { 654 | char sClass[64]; 655 | GetEntityClassname(iEnt, sClass, sizeof(sClass)); 656 | 657 | if (!strcmp(sClass, "worldspawn")) return false; 658 | if (!strcmp(sClass, "player")) return false; 659 | 660 | if (!strcmp(sClass, "func_door*")) 661 | { 662 | return (iFlags & WALK_THRU_PROP_DOORS) ? true : false; 663 | } 664 | 665 | if (!strcmp(sClass, "prop_door*")) 666 | { 667 | return (iFlags & WALK_THRU_PROP_DOORS) ? true : false; 668 | } 669 | 670 | if (!strcmp(sClass, "func_brush")) 671 | { 672 | int iSolidity = GetEntProp(iEnt, Prop_Data, "m_iSolidity"); 673 | 674 | switch (iSolidity) 675 | { 676 | case 2: // BRUSHSOLID_ALWAYS 677 | { 678 | return false; 679 | } 680 | case 1: // BRUSHSOLID_NEVER 681 | { 682 | return true; 683 | } 684 | case 0: // BRUSHSOLID_TOGGLE 685 | { 686 | return (iFlags & WALK_THRU_TOGGLE_BRUSHES) ? true : false; 687 | } 688 | } 689 | 690 | return (iFlags & WALK_THRU_PROP_DOORS) ? true : false; 691 | } 692 | 693 | if (!strcmp(sClass, "func_breakable") && GetEntProp(iEnt, Prop_Data, "m_iHealth") && GetEntProp(iEnt, Prop_Data, "m_takedamage") == 2) // DAMAGE_YES 694 | { 695 | return (iFlags & WALK_THRU_BREAKABLES) ? true : false; 696 | } 697 | 698 | if (!strcmp(sClass, "func_playerinfected_clip")) 699 | { 700 | return true; 701 | } 702 | 703 | return false; 704 | } 705 | 706 | stock bool IsWalkableTraceLineClear(const float flFrom[3], const float flTo[3], int iFlags) 707 | { 708 | float flUseFrom[3]; 709 | flUseFrom[0] = flFrom[0]; 710 | flUseFrom[1] = flFrom[1]; 711 | flUseFrom[2] = flFrom[2]; 712 | 713 | Handle hTrace; 714 | 715 | float flFraction = 0.0; 716 | 717 | for (int t = 0; t < 50; t++) 718 | { 719 | hTrace = TR_TraceRayFilterEx(flUseFrom, flTo, MASK_NPCSOLID, RayType_EndPoint, TraceFilterWalkableEntities, iFlags); 720 | flFraction = TR_GetFraction(hTrace); 721 | int iResEnt = TR_GetEntityIndex(hTrace); 722 | float flResPos[3]; 723 | TR_GetEndPosition(flResPos, hTrace); 724 | delete hTrace; 725 | 726 | if (flFraction != 1.0 && IsEntityWalkable(iResEnt, iFlags)) 727 | { 728 | float flDir[3]; 729 | SubtractVectors(flTo, flFrom, flDir); 730 | NormalizeVector(flDir, flDir); 731 | ScaleVector(flDir, 5.0); 732 | AddVectors(flResPos, flDir, flUseFrom); 733 | } 734 | else 735 | { 736 | break; 737 | } 738 | } 739 | 740 | if (flFraction == 1.0) return true; 741 | 742 | return false; 743 | } 744 | 745 | public bool TraceFilterWalkableEntities(int entity, int mask, any iFlags) 746 | { 747 | return !IsEntityWalkable(entity, iFlags); 748 | } 749 | 750 | 751 | public SharedPlugin __pl_navmesh = 752 | { 753 | name = "navmesh", 754 | file = "navmesh.smx", 755 | #if defined REQUIRE_PLUGIN 756 | required = 1, 757 | #else 758 | required = 0, 759 | #endif 760 | }; -------------------------------------------------------------------------------- /addons/sourcemod/scripting/navmesh.sp: -------------------------------------------------------------------------------- 1 | // Huge huge HUGE props and credits to Anthony Iacono (pimpinjuice) and his Nav-file parser code, 2 | // which can be found here: https://github.com/AnthonyIacono/War3SourceV2/tree/master/Nav 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PLUGIN_VERSION "1.0.5" 9 | 10 | public Plugin myinfo = 11 | { 12 | name = "SourcePawn Navigation Mesh Parser", 13 | author = "KitRifty, Benoist3012, (with modifications by sigsegv)", 14 | description = "A plugin that can read Valve's Navigation Mesh.", 15 | version = PLUGIN_VERSION, 16 | url = "" 17 | } 18 | 19 | #define UNSIGNED_INT_BYTE_SIZE 4 20 | #define UNSIGNED_CHAR_BYTE_SIZE 1 21 | #define UNSIGNED_SHORT_BYTE_SIZE 2 22 | #define FLOAT_BYTE_SIZE 4 23 | 24 | enum 25 | { 26 | NavMeshArea_ID = 0, 27 | NavMeshArea_Flags, 28 | NavMeshArea_PlaceID, 29 | NavMeshArea_X1, 30 | NavMeshArea_Y1, 31 | NavMeshArea_Z1, 32 | NavMeshArea_X2, 33 | NavMeshArea_Y2, 34 | NavMeshArea_Z2, 35 | NavMeshArea_CenterX, 36 | NavMeshArea_CenterY, 37 | NavMeshArea_CenterZ, 38 | NavMeshArea_InvDxCorners, 39 | NavMeshArea_InvDyCorners, 40 | NavMeshArea_NECornerZ, 41 | NavMeshArea_SWCornerZ, 42 | 43 | // NavMeshArea_Connections, 44 | NavMeshArea_ConnectionsStartIndex, 45 | NavMeshArea_ConnectionsEndIndex, 46 | 47 | // NavMeshArea_HidingSpots, 48 | NavMeshArea_HidingSpotsStartIndex, 49 | NavMeshArea_HidingSpotsEndIndex, 50 | 51 | // NavMeshArea_EncounterPaths, 52 | NavMeshArea_EncounterPathsStartIndex, 53 | NavMeshArea_EncounterPathsEndIndex, 54 | 55 | // NavMeshArea_LadderConnections, 56 | NavMeshArea_LadderConnectionsStartIndex, 57 | NavMeshArea_LadderConnectionsEndIndex, 58 | 59 | NavMeshArea_CornerLightIntensityNW, 60 | NavMeshArea_CornerLightIntensityNE, 61 | NavMeshArea_CornerLightIntensitySE, 62 | NavMeshArea_CornerLightIntensitySW, 63 | 64 | // NavMeshArea_VisibleAreas, 65 | NavMeshArea_VisibleAreasStartIndex, 66 | NavMeshArea_VisibleAreasEndIndex, 67 | 68 | NavMeshArea_InheritVisibilityFrom, 69 | NavMeshArea_EarliestOccupyTimeFirstTeam, 70 | NavMeshArea_EarliestOccupyTimeSecondTeam, 71 | NavMeshArea_unk01, 72 | NavMeshArea_Blocked, 73 | 74 | // A* pathfinding 75 | NavMeshArea_Parent, 76 | NavMeshArea_ParentHow, 77 | NavMeshArea_CostSoFar, 78 | NavMeshArea_TotalCost, 79 | NavMeshArea_Marker, 80 | NavMeshArea_OpenMarker, 81 | NavMeshArea_PrevOpenIndex, 82 | NavMeshArea_NextOpenIndex, 83 | NavMeshArea_PathLengthSoFar, 84 | 85 | NavMeshArea_NearSearchMarker, 86 | 87 | NavMeshArea_MaxStats 88 | }; 89 | 90 | enum 91 | { 92 | NavMeshConnection_AreaIndex = 0, 93 | NavMeshConnection_Direction, 94 | NavMeshConnection_MaxStats 95 | }; 96 | 97 | enum 98 | { 99 | NavMeshHidingSpot_ID = 0, 100 | NavMeshHidingSpot_X, 101 | NavMeshHidingSpot_Y, 102 | NavMeshHidingSpot_Z, 103 | NavMeshHidingSpot_Flags, 104 | NavMeshHidingSpot_AreaIndex, 105 | NavMeshHidingSpot_MaxStats 106 | }; 107 | 108 | enum 109 | { 110 | NavMeshEncounterPath_FromAreaIndex = 0, 111 | NavMeshEncounterPath_FromDirection, 112 | NavMeshEncounterPath_ToAreaIndex, 113 | NavMeshEncounterPath_ToDirection, 114 | NavMeshEncounterPath_SpotsStartIndex, 115 | NavMeshEncounterPath_SpotsEndIndex, 116 | NavMeshEncounterPath_MaxStats 117 | }; 118 | 119 | enum 120 | { 121 | NavMeshEncounterSpot_HidingSpotIndex = 0, 122 | NavMeshEncounterSpot_ParametricDistance, 123 | NavMeshEncounterSpot_MaxStats 124 | }; 125 | 126 | enum 127 | { 128 | NavMeshLadderConnection_LadderIndex = 0, 129 | NavMeshLadderConnection_Direction, 130 | NavMeshLadderConnection_MaxStats 131 | }; 132 | 133 | enum 134 | { 135 | NavMeshVisibleArea_Index = 0, 136 | NavMeshVisibleArea_Attributes, 137 | NavMeshVisibleArea_MaxStats 138 | }; 139 | 140 | enum 141 | { 142 | NavMeshLadder_ID = 0, 143 | NavMeshLadder_Width, 144 | NavMeshLadder_Length, 145 | NavMeshLadder_TopX, 146 | NavMeshLadder_TopY, 147 | NavMeshLadder_TopZ, 148 | NavMeshLadder_BottomX, 149 | NavMeshLadder_BottomY, 150 | NavMeshLadder_BottomZ, 151 | NavMeshLadder_Direction, 152 | NavMeshLadder_TopForwardAreaIndex, 153 | NavMeshLadder_TopLeftAreaIndex, 154 | NavMeshLadder_TopRightAreaIndex, 155 | NavMeshLadder_TopBehindAreaIndex, 156 | NavMeshLadder_BottomAreaIndex, 157 | NavMeshLadder_MaxStats 158 | }; 159 | 160 | enum 161 | { 162 | NavMeshGrid_ListStartIndex = 0, 163 | NavMeshGrid_ListEndIndex, 164 | NavMeshGrid_MaxStats 165 | }; 166 | 167 | enum 168 | { 169 | NavMeshGridList_AreaIndex = 0, 170 | NavMeshGridList_Owner, 171 | NavMeshGridList_MaxStats 172 | }; 173 | 174 | ArrayList g_hNavMeshPlaces; 175 | ArrayList g_hNavMeshAreas; 176 | ArrayList g_hNavMeshAreaConnections; 177 | ArrayList g_hNavMeshAreaHidingSpots; 178 | ArrayList g_hNavMeshAreaEncounterPaths; 179 | ArrayList g_hNavMeshAreaEncounterSpots; 180 | ArrayList g_hNavMeshAreaLadderConnections; 181 | ArrayList g_hNavMeshAreaVisibleAreas; 182 | 183 | ArrayList g_hNavMeshLadders; 184 | 185 | int g_iNavMeshMagicNumber; 186 | int g_iNavMeshVersion; 187 | int g_iNavMeshSubVersion; 188 | int g_iNavMeshSaveBSPSize; 189 | bool g_bNavMeshAnalyzed; 190 | 191 | ArrayList g_hNavMeshGrid; 192 | ArrayList g_hNavMeshGridLists; 193 | 194 | float g_flNavMeshGridCellSize = 300.0; 195 | float g_flNavMeshMinX; 196 | float g_flNavMeshMinY; 197 | int g_iNavMeshGridSizeX; 198 | int g_iNavMeshGridSizeY; 199 | 200 | 201 | bool g_bNavMeshBuilt = false; 202 | 203 | // For A* pathfinding. 204 | static int g_iNavMeshAreaOpenListIndex = -1; 205 | static int g_iNavMeshAreaOpenListTailIndex = -1; 206 | static int g_iNavMeshAreaMasterMarker = 0; 207 | 208 | 209 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 210 | { 211 | RegPluginLibrary("navmesh"); 212 | 213 | CreateNative("NavMesh_Exists", Native_NavMeshExists); 214 | CreateNative("NavMesh_GetMagicNumber", Native_NavMeshGetMagicNumber); 215 | CreateNative("NavMesh_GetVersion", Native_NavMeshGetVersion); 216 | CreateNative("NavMesh_GetSubVersion", Native_NavMeshGetSubVersion); 217 | CreateNative("NavMesh_GetSaveBSPSize", Native_NavMeshGetSaveBSPSize); 218 | CreateNative("NavMesh_IsAnalyzed", Native_NavMeshIsAnalyzed); 219 | //CreateNative("NavMesh_GetPlaces", Native_NavMeshGetPlaces); 220 | //CreateNative("NavMesh_GetAreas", Native_NavMeshGetAreas); 221 | //CreateNative("NavMesh_GetLadders", Native_NavMeshGetLadders); 222 | 223 | CreateNative("NavMesh_CollectSurroundingAreas", Native_NavMeshCollectSurroundingAreas); 224 | CreateNative("NavMesh_BuildPath", Native_NavMeshBuildPath); 225 | 226 | CreateNative("NavMesh_FindAreaByID", Native_NavMeshFindAreaByID); 227 | CreateNative("NavMesh_GetArea", Native_NavMeshGetArea); 228 | CreateNative("NavMesh_GetNearestArea", Native_NavMeshGetNearestArea); 229 | 230 | CreateNative("NavMesh_FindHidingSpotByID", Native_NavMeshFindHidingSpotByID); 231 | CreateNative("NavMesh_GetRandomHidingSpot", Native_NavMeshGetRandomHidingSpot); 232 | 233 | CreateNative("NavMesh_WorldToGridX", Native_NavMeshWorldToGridX); 234 | CreateNative("NavMesh_WorldToGridY", Native_NavMeshWorldToGridY); 235 | CreateNative("NavMesh_GetAreasOnGrid", Native_NavMeshGridGetAreas); 236 | CreateNative("NavMesh_GetGridSizeX", Native_NavMeshGetGridSizeX); 237 | CreateNative("NavMesh_GetGridSizeY", Native_NavMeshGetGridSizeY); 238 | 239 | CreateNative("NavMesh_GetGroundHeight", Native_NavMeshGetGroundHeight); 240 | 241 | CreateNative("NavMeshArea_GetMasterMarker", Native_NavMeshAreaGetMasterMarker); 242 | CreateNative("NavMeshArea_ChangeMasterMarker", Native_NavMeshAreaChangeMasterMarker); 243 | 244 | CreateNative("NavMeshArea_GetID", Native_NavMeshAreaGetID); 245 | CreateNative("NavMeshArea_GetFlags", Native_NavMeshAreaGetFlags); 246 | CreateNative("NavMeshArea_GetPlace", Native_NavMeshAreaGetPlace); 247 | CreateNative("NavMeshArea_GetCenter", Native_NavMeshAreaGetCenter); 248 | CreateNative("NavMeshArea_GetAdjacentList", Native_NavMeshAreaGetAdjacentList); 249 | CreateNative("NavMeshArea_GetLadderList", Native_NavMeshAreaGetLadderList); 250 | CreateNative("NavMeshArea_GetHidingSpots", Native_NavMeshAreaGetHidingSpots); 251 | CreateNative("NavMeshArea_GetClosestPointOnArea", Native_NavMeshAreaGetClosestPointOnArea); 252 | CreateNative("NavMeshArea_GetTotalCost", Native_NavMeshAreaGetTotalCost); 253 | CreateNative("NavMeshArea_GetParent", Native_NavMeshAreaGetParent); 254 | CreateNative("NavMeshArea_GetParentHow", Native_NavMeshAreaGetParentHow); 255 | CreateNative("NavMeshArea_SetParent", Native_NavMeshAreaSetParent); 256 | CreateNative("NavMeshArea_SetParentHow", Native_NavMeshAreaSetParentHow); 257 | CreateNative("NavMeshArea_GetCostSoFar", Native_NavMeshAreaGetCostSoFar); 258 | CreateNative("NavMeshArea_GetExtentLow", Native_NavMeshAreaGetExtentLow); 259 | CreateNative("NavMeshArea_GetExtentHigh", Native_NavMeshAreaGetExtentHigh); 260 | CreateNative("NavMeshArea_IsOverlappingPoint", Native_NavMeshAreaIsOverlappingPoint); 261 | CreateNative("NavMeshArea_IsOverlappingArea", Native_NavMeshAreaIsOverlappingArea); 262 | CreateNative("NavMeshArea_GetNECornerZ", Native_NavMeshAreaGetNECornerZ); 263 | CreateNative("NavMeshArea_GetSWCornerZ", Native_NavMeshAreaGetSWCornerZ); 264 | CreateNative("NavMeshArea_GetCorner", Native_NavMeshAreaGetCorner); 265 | CreateNative("NavMeshArea_GetZ", Native_NavMeshAreaGetZ); 266 | CreateNative("NavMeshArea_GetZFromXAndY", Native_NavMeshAreaGetZFromXAndY); 267 | CreateNative("NavMeshArea_IsEdge", Native_NavMeshAreaIsEdge); 268 | CreateNative("NavMeshArea_Contains", Native_NavMeshAreaContains); 269 | CreateNative("NavMeshArea_GetRandomPoint", Native_NavMeshAreaGetRandomPoint); 270 | CreateNative("NavMeshArea_IsConnected", Native_NavMeshAreaIsConnected); 271 | CreateNative("NavMeshArea_ComputePortal", Native_NavMeshAreaComputePortal); 272 | CreateNative("NavMeshArea_ComputeClosestPointInPortal", Native_NavMeshAreaComputeClosestPointInPortal); 273 | CreateNative("NavMeshArea_ComputeDirection", Native_NavMeshAreaComputeDirection); 274 | CreateNative("NavMeshArea_GetLightIntensity", Native_NavMeshAreaGetLightIntensity); 275 | 276 | CreateNative("NavHidingSpot_GetID", Native_NavHidingSpotGetID); 277 | CreateNative("NavHidingSpot_GetFlags", Native_NavHidingSpotGetFlags); 278 | CreateNative("NavHidingSpot_GetPosition", Native_NavHidingSpotGetPosition); 279 | CreateNative("NavHidingSpot_GetArea", Native_NavHidingSpotGetArea); 280 | 281 | CreateNative("NavMeshLadder_GetLength", Native_NavMeshLadderGetLength); 282 | CreateNative("NavMeshLadder_GetWidth", Native_NavMeshLadderGetWidth); 283 | CreateNative("NavMeshLadder_GetTopForwardArea", Native_NavMeshLadderGetTopForwardArea); 284 | CreateNative("NavMeshLadder_GetTopLeftArea", Native_NavMeshLadderGetTopLeftArea); 285 | CreateNative("NavMeshLadder_GetTopRightArea", Native_NavMeshLadderGetTopRightArea); 286 | CreateNative("NavMeshLadder_GetTopBehindArea", Native_NavMeshLadderGetTopBehindArea); 287 | CreateNative("NavMeshLadder_GetBottomArea", Native_NavMeshLadderGetBottomArea); 288 | CreateNative("NavMeshLadder_GetTop", Native_NavMeshLadderGetTop); 289 | CreateNative("NavMeshLadder_GetBottom", Native_NavMeshLadderGetBottom); 290 | 291 | CreateNative("NavSpotEncounter_GetFrom", Native_NavSpotEncounterGetFrom); 292 | CreateNative("NavSpotEncounter_GetFromDirection", Native_NavSpotEncounterGetFromDirection); 293 | CreateNative("NavSpotEncounter_GetTo", Native_NavSpotEncounterGetTo); 294 | CreateNative("NavSpotEncounter_GetToDirection", Native_NavSpotEncounterGetToDirection); 295 | CreateNative("NavSpotEncounter_GetSpots", Native_NavSpotEncounterGetSpots); 296 | 297 | CreateNative("NavSpotOrder_GetHidingSpot", Native_NavSpotOrderGetHidingSpot); 298 | CreateNative("NavSpotOrder_GetParametricDistance", Native_NavSpotOrderGetParametricDistance); 299 | } 300 | 301 | public void OnPluginStart() 302 | { 303 | g_hNavMeshPlaces = new ArrayList(256); 304 | g_hNavMeshAreas = new ArrayList(NavMeshArea_MaxStats); 305 | g_hNavMeshAreaConnections = new ArrayList(NavMeshConnection_MaxStats); 306 | g_hNavMeshAreaHidingSpots = new ArrayList(NavMeshHidingSpot_MaxStats); 307 | g_hNavMeshAreaEncounterPaths = new ArrayList(NavMeshEncounterPath_MaxStats); 308 | g_hNavMeshAreaEncounterSpots = new ArrayList(NavMeshEncounterSpot_MaxStats); 309 | g_hNavMeshAreaLadderConnections = new ArrayList(NavMeshLadderConnection_MaxStats); 310 | g_hNavMeshAreaVisibleAreas = new ArrayList(NavMeshVisibleArea_MaxStats); 311 | 312 | g_hNavMeshLadders = new ArrayList(NavMeshLadder_MaxStats); 313 | 314 | g_hNavMeshGrid = new ArrayList(NavMeshGrid_MaxStats); 315 | g_hNavMeshGridLists = new ArrayList(NavMeshGridList_MaxStats); 316 | 317 | HookEvent("nav_blocked", Event_NavAreaBlocked); 318 | } 319 | 320 | public void OnMapStart() 321 | { 322 | NavMeshDestroy(); 323 | 324 | char sMap[256]; 325 | GetCurrentMap(sMap, sizeof(sMap)); 326 | 327 | g_bNavMeshBuilt = NavMeshLoad(sMap); 328 | } 329 | 330 | public void Event_NavAreaBlocked(Event event, const char[] name, bool dB) 331 | { 332 | if (!g_bNavMeshBuilt) return; 333 | 334 | int iAreaID = event.GetInt("area"); 335 | int iAreaIndex = g_hNavMeshAreas.FindValue(iAreaID); // Wow, this is terrible. 336 | if (iAreaIndex != -1) 337 | { 338 | bool bBlocked = view_as(event.GetInt("blocked")); 339 | g_hNavMeshAreas.Set(iAreaIndex, bBlocked, NavMeshArea_Blocked); 340 | } 341 | } 342 | 343 | stock int OppositeDirection(int iNavDirection) 344 | { 345 | switch (iNavDirection) 346 | { 347 | case NAV_DIR_NORTH: return NAV_DIR_SOUTH; 348 | case NAV_DIR_SOUTH: return NAV_DIR_NORTH; 349 | case NAV_DIR_EAST: return NAV_DIR_WEST; 350 | case NAV_DIR_WEST: return NAV_DIR_EAST; 351 | } 352 | 353 | return NAV_DIR_NORTH; 354 | } 355 | 356 | stock float NavMeshAreaComputeAdjacentConnectionHeightChange(int iAreaIndex, int iTargetAreaIndex) 357 | { 358 | bool bFoundArea = false; 359 | int iNavDirection; 360 | 361 | for (iNavDirection = 0; iNavDirection < NAV_DIR_COUNT; iNavDirection++) 362 | { 363 | ArrayStack hConnections = NavMeshAreaGetAdjacentList(iAreaIndex, iNavDirection); 364 | if (hConnections == null) continue; 365 | 366 | while (!hConnections.Empty) 367 | { 368 | int iTempAreaIndex = -1; 369 | PopStackCell(hConnections, iTempAreaIndex); 370 | 371 | if (iTempAreaIndex == iTargetAreaIndex) 372 | { 373 | bFoundArea = true; 374 | break; 375 | } 376 | } 377 | 378 | delete hConnections; 379 | 380 | if (bFoundArea) break; 381 | } 382 | 383 | if (!bFoundArea) return 99999999.9; 384 | 385 | float flMyEdge[3]; 386 | float flHalfWidth; 387 | NavMeshAreaComputePortal(iAreaIndex, iTargetAreaIndex, iNavDirection, flMyEdge, flHalfWidth); 388 | 389 | float flOtherEdge[3]; 390 | NavMeshAreaComputePortal(iAreaIndex, iTargetAreaIndex, OppositeDirection(iNavDirection), flOtherEdge, flHalfWidth); 391 | 392 | return flOtherEdge[2] - flMyEdge[2]; 393 | } 394 | 395 | ArrayStack NavMeshCollectSurroundingAreas(int iStartAreaIndex, float flTravelDistanceLimit=1500.0, float flMaxStepUpLimit=StepHeight, float flMaxDropDownLimit=100.0) 396 | { 397 | if (!g_bNavMeshBuilt) 398 | { 399 | LogError("Could not search surrounding areas because the nav mesh does not exist!"); 400 | return null; 401 | } 402 | 403 | if (iStartAreaIndex == -1) 404 | { 405 | LogError("Could not search surrounding areas because the starting area does not exist!"); 406 | return null; 407 | } 408 | 409 | ArrayStack hNearAreasList = new ArrayStack(); 410 | 411 | NavMeshAreaClearSearchLists(); 412 | 413 | NavMeshAreaAddToOpenList(iStartAreaIndex); 414 | g_hNavMeshAreas.Set(iStartAreaIndex, 0, NavMeshArea_TotalCost); 415 | g_hNavMeshAreas.Set(iStartAreaIndex, 0, NavMeshArea_CostSoFar); 416 | g_hNavMeshAreas.Set(iStartAreaIndex, -1, NavMeshArea_Parent); 417 | g_hNavMeshAreas.Set(iStartAreaIndex, NUM_TRAVERSE_TYPES, NavMeshArea_ParentHow); 418 | NavMeshAreaMark(iStartAreaIndex); 419 | 420 | while (!NavMeshAreaIsOpenListEmpty()) 421 | { 422 | int iAreaIndex = NavMeshAreaPopOpenList(); 423 | if (flTravelDistanceLimit > 0.0 && 424 | float(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CostSoFar)) > flTravelDistanceLimit) 425 | { 426 | continue; 427 | } 428 | 429 | int iAreaParent = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Parent); 430 | if (iAreaParent != -1) 431 | { 432 | float flDeltaZ = NavMeshAreaComputeAdjacentConnectionHeightChange(iAreaParent, iAreaIndex); 433 | if (flDeltaZ > flMaxStepUpLimit) continue; 434 | if (flDeltaZ < -flMaxDropDownLimit) continue; 435 | } 436 | 437 | hNearAreasList.Push(iAreaIndex); 438 | 439 | NavMeshAreaMark(iAreaIndex); 440 | 441 | for (int iNavDir = 0; iNavDir < NAV_DIR_COUNT; iNavDir++) 442 | { 443 | ArrayStack hConnections = NavMeshAreaGetAdjacentList(iAreaIndex, iNavDir); 444 | if (hConnections != null) 445 | { 446 | while (!hConnections.Empty) 447 | { 448 | int iAdjacentAreaIndex = -1; 449 | PopStackCell(hConnections, iAdjacentAreaIndex); 450 | 451 | if (view_as(g_hNavMeshAreas.Get(iAdjacentAreaIndex, NavMeshArea_Blocked))) continue; 452 | 453 | if (!NavMeshAreaIsMarked(iAdjacentAreaIndex)) 454 | { 455 | g_hNavMeshAreas.Set(iAdjacentAreaIndex, 0, NavMeshArea_TotalCost); 456 | g_hNavMeshAreas.Set(iAdjacentAreaIndex, iAreaIndex, NavMeshArea_Parent); 457 | g_hNavMeshAreas.Set(iAdjacentAreaIndex, iNavDir, NavMeshArea_ParentHow); 458 | 459 | int iDistAlong = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CostSoFar); 460 | 461 | float flAdjacentAreaCenter[3]; 462 | float flAreaCenter[3]; 463 | NavMeshAreaGetCenter(iAreaIndex, flAreaCenter); 464 | NavMeshAreaGetCenter(iAdjacentAreaIndex, flAdjacentAreaCenter); 465 | 466 | iDistAlong += RoundToFloor(GetVectorDistance(flAdjacentAreaCenter, flAreaCenter)); 467 | g_hNavMeshAreas.Set(iAdjacentAreaIndex, iDistAlong, NavMeshArea_CostSoFar); 468 | NavMeshAreaAddToOpenList(iAdjacentAreaIndex); 469 | } 470 | } 471 | 472 | delete hConnections; 473 | } 474 | } 475 | } 476 | 477 | return hNearAreasList; 478 | } 479 | 480 | bool NavMeshBuildPath(int iStartAreaIndex, 481 | int iGoalAreaIndex, 482 | const float flGoalPos[3], 483 | Handle hCostFunctionPlugin, 484 | NavPathCostFunctor iCostFunction, 485 | any iCostData=0, 486 | int &iClosestAreaIndex=-1, 487 | float flMaxPathLength=0.0, 488 | float flMaxStepSize=0.0) 489 | { 490 | if (!g_bNavMeshBuilt) 491 | { 492 | LogError("Could not build path because the nav mesh does not exist!"); 493 | return false; 494 | } 495 | 496 | if (iClosestAreaIndex != -1) 497 | { 498 | iClosestAreaIndex = iStartAreaIndex; 499 | } 500 | 501 | if (iStartAreaIndex == -1) 502 | { 503 | LogError("Could not build path because the starting area does not exist!"); 504 | return false; 505 | } 506 | 507 | g_hNavMeshAreas.Set(iStartAreaIndex, -1, NavMeshArea_Parent); 508 | g_hNavMeshAreas.Set(iStartAreaIndex, NUM_TRAVERSE_TYPES, NavMeshArea_ParentHow); 509 | 510 | if (iGoalAreaIndex == -1) 511 | { 512 | LogError("Could not build path from area %d to area %d because the goal area does not exist!"); 513 | return false; 514 | } 515 | 516 | if (iStartAreaIndex == iGoalAreaIndex) return true; 517 | 518 | // Start the search. 519 | NavMeshAreaClearSearchLists(); 520 | 521 | // Compute estimate of path length. 522 | float flStartAreaCenter[3]; 523 | NavMeshAreaGetCenter(iStartAreaIndex, flStartAreaCenter); 524 | 525 | int iStartTotalCost = RoundFloat(GetVectorDistance(flStartAreaCenter, flGoalPos)); 526 | g_hNavMeshAreas.Set(iStartAreaIndex, iStartTotalCost, NavMeshArea_TotalCost); 527 | 528 | int iInitCost = 0; 529 | 530 | Call_StartFunction(hCostFunctionPlugin, iCostFunction); 531 | Call_PushCell(iStartAreaIndex); 532 | Call_PushCell(-1); 533 | Call_PushCell(-1); 534 | Call_PushCell(iCostData); 535 | Call_Finish(iInitCost); 536 | 537 | if (iInitCost < 0) return false; 538 | 539 | g_hNavMeshAreas.Set(iStartAreaIndex, 0, NavMeshArea_CostSoFar); 540 | g_hNavMeshAreas.Set(iStartAreaIndex, 0.0, NavMeshArea_PathLengthSoFar); 541 | NavMeshAreaAddToOpenList(iStartAreaIndex); 542 | 543 | int iClosestAreaDist = iStartTotalCost; 544 | 545 | bool bHaveMaxPathLength = (flMaxPathLength != 0.0); 546 | 547 | // Perform A* search. 548 | while (!NavMeshAreaIsOpenListEmpty()) 549 | { 550 | int iAreaIndex = NavMeshAreaPopOpenList(); 551 | 552 | if (view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Blocked))) 553 | { 554 | // Don't consider blocked areas. 555 | continue; 556 | } 557 | 558 | if (iAreaIndex == iGoalAreaIndex || 559 | (iGoalAreaIndex == -1 && NavMeshAreaContains(iAreaIndex, flGoalPos))) 560 | { 561 | if (iClosestAreaIndex != -1) 562 | { 563 | iClosestAreaIndex = iGoalAreaIndex; 564 | } 565 | 566 | return true; 567 | } 568 | 569 | // No support for elevator areas yet. 570 | static int SEARCH_FLOOR = 0; 571 | static int SEARCH_LADDERS = 1; 572 | 573 | int iSearchWhere = SEARCH_FLOOR; 574 | int iSearchDir = NAV_DIR_NORTH; 575 | 576 | ArrayStack hFloorList = NavMeshAreaGetAdjacentList(iAreaIndex, iSearchDir); 577 | 578 | bool bLadderUp = true; 579 | ArrayStack hLadderList = null; 580 | int iLadderTopDir = 0; 581 | 582 | for (;;) 583 | { 584 | int iNewAreaIndex = -1; 585 | int iNavTraverseHow = 0; 586 | int iLadderIndex = -1; 587 | 588 | if (iSearchWhere == SEARCH_FLOOR) 589 | { 590 | if (hFloorList == null || hFloorList.Empty) 591 | { 592 | iSearchDir++; 593 | if (hFloorList != null) delete hFloorList; 594 | 595 | if (iSearchDir == NAV_DIR_COUNT) 596 | { 597 | iSearchWhere = SEARCH_LADDERS; 598 | 599 | hLadderList = NavMeshAreaGetLadderList(iAreaIndex, NAV_LADDER_DIR_UP); 600 | iLadderTopDir = 0; 601 | } 602 | else 603 | { 604 | hFloorList = NavMeshAreaGetAdjacentList(iAreaIndex, iSearchDir); 605 | } 606 | 607 | continue; 608 | } 609 | 610 | PopStackCell(hFloorList, iNewAreaIndex); 611 | iNavTraverseHow = iSearchDir; 612 | } 613 | else if (iSearchWhere == SEARCH_LADDERS) 614 | { 615 | if (hLadderList == null || hLadderList.Empty) 616 | { 617 | if (hLadderList != null) delete hLadderList; 618 | 619 | if (!bLadderUp) 620 | { 621 | iLadderIndex = -1; 622 | break; 623 | } 624 | else 625 | { 626 | bLadderUp = false; 627 | hLadderList = NavMeshAreaGetLadderList(iAreaIndex, NAV_LADDER_DIR_DOWN); 628 | } 629 | 630 | continue; 631 | } 632 | 633 | PopStackCell(hLadderList, iLadderIndex); 634 | 635 | if (bLadderUp) 636 | { 637 | switch (iLadderTopDir) 638 | { 639 | case 0: 640 | { 641 | iNewAreaIndex = g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_TopForwardAreaIndex); 642 | } 643 | case 1: 644 | { 645 | iNewAreaIndex = g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_TopLeftAreaIndex); 646 | } 647 | case 2: 648 | { 649 | iNewAreaIndex = g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_TopRightAreaIndex); 650 | } 651 | default: 652 | { 653 | iLadderTopDir = 0; 654 | continue; 655 | } 656 | } 657 | 658 | iNavTraverseHow = GO_LADDER_UP; 659 | iLadderTopDir++; 660 | } 661 | else 662 | { 663 | iNewAreaIndex = g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_BottomAreaIndex); 664 | iNavTraverseHow = GO_LADDER_DOWN; 665 | } 666 | 667 | if (iNewAreaIndex == -1) continue; 668 | } 669 | 670 | if (g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Parent) == iNewAreaIndex) 671 | { 672 | // Don't backtrack. 673 | continue; 674 | } 675 | 676 | if (iNewAreaIndex == iAreaIndex) 677 | { 678 | continue; 679 | } 680 | 681 | if (view_as(g_hNavMeshAreas.Get(iNewAreaIndex, NavMeshArea_Blocked))) 682 | { 683 | // Don't consider blocked areas. 684 | continue; 685 | } 686 | 687 | int iNewCostSoFar = 0; 688 | 689 | Call_StartFunction(hCostFunctionPlugin, iCostFunction); 690 | Call_PushCell(iNewAreaIndex); 691 | Call_PushCell(iAreaIndex); 692 | Call_PushCell(iLadderIndex); 693 | Call_PushCell(iCostData); 694 | Call_Finish(iNewCostSoFar); 695 | 696 | if (iNewCostSoFar < 0) continue; 697 | 698 | if (flMaxStepSize > 0.0) 699 | { 700 | float flDeltaZ = NavMeshAreaComputeAdjacentConnectionHeightChange(iAreaIndex, iNewAreaIndex); 701 | if (flDeltaZ > flMaxStepSize) continue; 702 | } 703 | 704 | float flNewAreaCenter[3]; 705 | NavMeshAreaGetCenter(iNewAreaIndex, flNewAreaCenter); 706 | 707 | if (bHaveMaxPathLength) 708 | { 709 | float flAreaCenter[3]; 710 | NavMeshAreaGetCenter(iAreaIndex, flAreaCenter); 711 | 712 | float flDeltaLength = GetVectorDistance(flNewAreaCenter, flAreaCenter); 713 | float flNewLengthSoFar = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_PathLengthSoFar)) + flDeltaLength; 714 | if (flNewLengthSoFar > flMaxPathLength) 715 | { 716 | continue; 717 | } 718 | 719 | g_hNavMeshAreas.Set(iNewAreaIndex, flNewLengthSoFar, NavMeshArea_PathLengthSoFar); 720 | } 721 | 722 | if ((NavMeshAreaIsOpen(iNewAreaIndex) || NavMeshAreaIsClosed(iNewAreaIndex)) && 723 | g_hNavMeshAreas.Get(iNewAreaIndex, NavMeshArea_CostSoFar) <= iNewCostSoFar) 724 | { 725 | continue; 726 | } 727 | else 728 | { 729 | int iNewCostRemaining = RoundFloat(GetVectorDistance(flNewAreaCenter, flGoalPos)); 730 | 731 | if (iClosestAreaIndex != -1 && iNewCostRemaining < iClosestAreaDist) 732 | { 733 | iClosestAreaIndex = iNewAreaIndex; 734 | iClosestAreaDist = iNewCostRemaining; 735 | } 736 | 737 | g_hNavMeshAreas.Set(iNewAreaIndex, iNewCostSoFar, NavMeshArea_CostSoFar); 738 | g_hNavMeshAreas.Set(iNewAreaIndex, iNewCostSoFar + iNewCostRemaining, NavMeshArea_TotalCost); 739 | 740 | /* 741 | if (NavMeshAreaIsClosed(iNewAreaIndex)) 742 | { 743 | NavMeshAreaRemoveFromClosedList(iNewAreaIndex); 744 | } 745 | */ 746 | 747 | if (NavMeshAreaIsOpen(iNewAreaIndex)) 748 | { 749 | NavMeshAreaUpdateOnOpenList(iNewAreaIndex); 750 | } 751 | else 752 | { 753 | NavMeshAreaAddToOpenList(iNewAreaIndex); 754 | } 755 | 756 | g_hNavMeshAreas.Set(iNewAreaIndex, iAreaIndex, NavMeshArea_Parent); 757 | g_hNavMeshAreas.Set(iNewAreaIndex, iNavTraverseHow, NavMeshArea_ParentHow); 758 | } 759 | } 760 | 761 | NavMeshAreaAddToClosedList(iAreaIndex); 762 | } 763 | 764 | return false; 765 | } 766 | 767 | NavMeshAreaClearSearchLists() 768 | { 769 | g_iNavMeshAreaMasterMarker++; 770 | g_iNavMeshAreaOpenListIndex = -1; 771 | g_iNavMeshAreaOpenListTailIndex = -1; 772 | } 773 | 774 | bool NavMeshAreaIsMarked(iAreaIndex) 775 | { 776 | return view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Marker) == g_iNavMeshAreaMasterMarker); 777 | } 778 | 779 | void NavMeshAreaMark(iAreaIndex) 780 | { 781 | g_hNavMeshAreas.Set(iAreaIndex, g_iNavMeshAreaMasterMarker, NavMeshArea_Marker); 782 | } 783 | 784 | bool NavMeshAreaIsOpen(iAreaIndex) 785 | { 786 | return view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_OpenMarker) == g_iNavMeshAreaMasterMarker); 787 | } 788 | 789 | bool NavMeshAreaIsOpenListEmpty() 790 | { 791 | return view_as(g_iNavMeshAreaOpenListIndex == -1); 792 | } 793 | 794 | void NavMeshAreaAddToOpenList(int iAreaIndex) 795 | { 796 | if (NavMeshAreaIsOpen(iAreaIndex)) return; 797 | 798 | g_hNavMeshAreas.Set(iAreaIndex, g_iNavMeshAreaMasterMarker, NavMeshArea_OpenMarker); 799 | 800 | if (g_iNavMeshAreaOpenListIndex == -1) 801 | { 802 | g_iNavMeshAreaOpenListIndex = iAreaIndex; 803 | g_iNavMeshAreaOpenListTailIndex = iAreaIndex; 804 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_PrevOpenIndex); 805 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_NextOpenIndex); 806 | return; 807 | } 808 | 809 | int iTotalCost = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_TotalCost); 810 | 811 | int iTempAreaIndex = -1; 812 | int iLastAreaIndex = -1; 813 | for (iTempAreaIndex = g_iNavMeshAreaOpenListIndex; iTempAreaIndex != -1; iTempAreaIndex = g_hNavMeshAreas.Get(iTempAreaIndex, NavMeshArea_NextOpenIndex)) 814 | { 815 | if (iTotalCost < g_hNavMeshAreas.Get(iTempAreaIndex, NavMeshArea_TotalCost)) break; 816 | iLastAreaIndex = iTempAreaIndex; 817 | } 818 | 819 | if (iTempAreaIndex != -1) 820 | { 821 | int iPrevOpenIndex = g_hNavMeshAreas.Get(iTempAreaIndex, NavMeshArea_PrevOpenIndex); 822 | g_hNavMeshAreas.Set(iAreaIndex, iPrevOpenIndex, NavMeshArea_PrevOpenIndex); 823 | 824 | if (iPrevOpenIndex != -1) 825 | { 826 | g_hNavMeshAreas.Set(iPrevOpenIndex, iAreaIndex, NavMeshArea_NextOpenIndex); 827 | } 828 | else 829 | { 830 | g_iNavMeshAreaOpenListIndex = iAreaIndex; 831 | } 832 | 833 | g_hNavMeshAreas.Set(iAreaIndex, iTempAreaIndex, NavMeshArea_NextOpenIndex); 834 | g_hNavMeshAreas.Set(iTempAreaIndex, iAreaIndex, NavMeshArea_PrevOpenIndex); 835 | } 836 | else 837 | { 838 | g_hNavMeshAreas.Set(iLastAreaIndex, iAreaIndex, NavMeshArea_NextOpenIndex); 839 | g_hNavMeshAreas.Set(iAreaIndex, iLastAreaIndex, NavMeshArea_PrevOpenIndex); 840 | 841 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_NextOpenIndex); 842 | 843 | g_iNavMeshAreaOpenListTailIndex = iAreaIndex; 844 | } 845 | } 846 | 847 | stock void NavMeshAreaAddToOpenListTail(int iAreaIndex) 848 | { 849 | if (NavMeshAreaIsOpen(iAreaIndex)) return; 850 | 851 | g_hNavMeshAreas.Set(iAreaIndex, g_iNavMeshAreaMasterMarker, NavMeshArea_OpenMarker); 852 | 853 | if (g_iNavMeshAreaOpenListIndex == -1) 854 | { 855 | g_iNavMeshAreaOpenListIndex = iAreaIndex; 856 | g_iNavMeshAreaOpenListTailIndex = iAreaIndex; 857 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_PrevOpenIndex); 858 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_NextOpenIndex); 859 | return; 860 | } 861 | 862 | g_hNavMeshAreas.Set(g_iNavMeshAreaOpenListTailIndex, iAreaIndex, NavMeshArea_NextOpenIndex); 863 | 864 | g_hNavMeshAreas.Set(iAreaIndex, g_iNavMeshAreaOpenListTailIndex, NavMeshArea_PrevOpenIndex); 865 | g_hNavMeshAreas.Set(iAreaIndex, -1, NavMeshArea_NextOpenIndex); 866 | 867 | g_iNavMeshAreaOpenListTailIndex = iAreaIndex; 868 | } 869 | 870 | void NavMeshAreaUpdateOnOpenList(int iAreaIndex) 871 | { 872 | int iTotalCost = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_TotalCost); 873 | 874 | int iPrevIndex = -1; 875 | 876 | while ((iPrevIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_PrevOpenIndex)) != -1 && 877 | iTotalCost < (g_hNavMeshAreas.Get(iPrevIndex, NavMeshArea_TotalCost))) 878 | { 879 | int iOtherIndex = iPrevIndex; 880 | int iBeforeIndex = g_hNavMeshAreas.Get(iPrevIndex, NavMeshArea_PrevOpenIndex); 881 | int iAfterIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_NextOpenIndex); 882 | 883 | g_hNavMeshAreas.Set(iAreaIndex, iPrevIndex, NavMeshArea_NextOpenIndex); 884 | g_hNavMeshAreas.Set(iAreaIndex, iBeforeIndex, NavMeshArea_PrevOpenIndex); 885 | 886 | g_hNavMeshAreas.Set(iOtherIndex, iAreaIndex, NavMeshArea_PrevOpenIndex); 887 | g_hNavMeshAreas.Set(iOtherIndex, iAfterIndex, NavMeshArea_NextOpenIndex); 888 | 889 | if (iBeforeIndex != -1) 890 | { 891 | g_hNavMeshAreas.Set(iBeforeIndex, iAreaIndex, NavMeshArea_NextOpenIndex); 892 | } 893 | else 894 | { 895 | g_iNavMeshAreaOpenListIndex = iAreaIndex; 896 | } 897 | 898 | if (iAfterIndex != -1) 899 | { 900 | g_hNavMeshAreas.Set(iAfterIndex, iOtherIndex, NavMeshArea_PrevOpenIndex); 901 | } 902 | else 903 | { 904 | g_iNavMeshAreaOpenListTailIndex = iAreaIndex; 905 | } 906 | } 907 | } 908 | 909 | void NavMeshAreaRemoveFromOpenList(int iAreaIndex) 910 | { 911 | if (g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_OpenMarker) == 0) return; 912 | 913 | int iPrevOpenIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_PrevOpenIndex); 914 | int iNextOpenIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_NextOpenIndex); 915 | 916 | if (iPrevOpenIndex != -1) 917 | { 918 | g_hNavMeshAreas.Set(iPrevOpenIndex, iNextOpenIndex, NavMeshArea_NextOpenIndex); 919 | } 920 | else 921 | { 922 | g_iNavMeshAreaOpenListIndex = iNextOpenIndex; 923 | } 924 | 925 | if (iNextOpenIndex != -1) 926 | { 927 | g_hNavMeshAreas.Set(iNextOpenIndex, iPrevOpenIndex, NavMeshArea_PrevOpenIndex); 928 | } 929 | else 930 | { 931 | g_iNavMeshAreaOpenListTailIndex = iPrevOpenIndex; 932 | } 933 | 934 | g_hNavMeshAreas.Set(iAreaIndex, 0, NavMeshArea_OpenMarker); 935 | } 936 | 937 | int NavMeshAreaPopOpenList() 938 | { 939 | if (g_iNavMeshAreaOpenListIndex != -1) 940 | { 941 | int iOpenListIndex = g_iNavMeshAreaOpenListIndex; 942 | 943 | NavMeshAreaRemoveFromOpenList(iOpenListIndex); 944 | g_hNavMeshAreas.Set(iOpenListIndex, -1, NavMeshArea_PrevOpenIndex); 945 | g_hNavMeshAreas.Set(iOpenListIndex, -1, NavMeshArea_NextOpenIndex); 946 | 947 | return iOpenListIndex; 948 | } 949 | 950 | return -1; 951 | } 952 | 953 | bool NavMeshAreaIsClosed(int iAreaIndex) 954 | { 955 | if (NavMeshAreaIsMarked(iAreaIndex) && !NavMeshAreaIsOpen(iAreaIndex)) return true; 956 | return false; 957 | } 958 | 959 | void NavMeshAreaAddToClosedList(int iAreaIndex) 960 | { 961 | NavMeshAreaMark(iAreaIndex); 962 | } 963 | 964 | /* 965 | static NavMeshAreaRemoveFromClosedList(iAreaIndex) 966 | { 967 | } 968 | */ 969 | 970 | bool NavMeshLoad(const char[] sMapName) 971 | { 972 | char sNavFilePath[PLATFORM_MAX_PATH]; 973 | Format(sNavFilePath, sizeof(sNavFilePath), "maps\\%s.nav", sMapName); 974 | 975 | File hFile = OpenFile(sNavFilePath, "rb"); 976 | if (hFile == null) 977 | { 978 | // Try opening it from the Valve file system. 979 | hFile = OpenFile(sNavFilePath, "rb", true, NULL_STRING); 980 | } 981 | 982 | if (hFile == null) 983 | { 984 | // Try finding the file ourselves. 985 | new bool:bFound = false; 986 | 987 | if (GetFeatureStatus(FeatureType_Native, "GetEngineVersion") == FeatureStatus_Available) 988 | { 989 | EngineVersion iEngineVersion = GetEngineVersion(); 990 | 991 | switch (iEngineVersion) 992 | { 993 | case Engine_CSGO: 994 | { 995 | // Search addon directories. 996 | DirectoryListing hDir = OpenDirectory("addons"); 997 | if (hDir != null) 998 | { 999 | LogMessage("Couldn't find .nav file in maps folder, checking addon folders..."); 1000 | 1001 | char sFolderName[PLATFORM_MAX_PATH]; 1002 | FileType iFileType; 1003 | while (hDir.GetNext(sFolderName, sizeof(sFolderName), iFileType)) 1004 | { 1005 | if (iFileType == FileType_Directory) 1006 | { 1007 | Format(sNavFilePath, sizeof(sNavFilePath), "addons\\%s\\maps\\%s.nav", sFolderName, sMapName); 1008 | hFile = OpenFile(sNavFilePath, "rb"); 1009 | if (hFile != INVALID_HANDLE) 1010 | { 1011 | bFound = true; 1012 | break; 1013 | } 1014 | } 1015 | } 1016 | 1017 | delete hDir; 1018 | } 1019 | } 1020 | case Engine_TF2: 1021 | { 1022 | // Search custom directories. 1023 | DirectoryListing hDir = OpenDirectory("custom"); 1024 | if (hDir != INVALID_HANDLE) 1025 | { 1026 | LogMessage("Couldn't find .nav file in maps folder, checking custom folders..."); 1027 | 1028 | char sFolderName[PLATFORM_MAX_PATH]; 1029 | FileType iFileType; 1030 | while (hDir.GetNext(sFolderName, sizeof(sFolderName), iFileType)) 1031 | { 1032 | if (iFileType == FileType_Directory) 1033 | { 1034 | Format(sNavFilePath, sizeof(sNavFilePath), "custom\\%s\\maps\\%s.nav", sFolderName, sMapName); 1035 | hFile = OpenFile(sNavFilePath, "rb"); 1036 | if (hFile != INVALID_HANDLE) 1037 | { 1038 | bFound = true; 1039 | break; 1040 | } 1041 | } 1042 | } 1043 | 1044 | delete hDir; 1045 | } 1046 | } 1047 | } 1048 | } 1049 | 1050 | if (!bFound) 1051 | { 1052 | LogMessage(".NAV file for %s could not be found", sMapName); 1053 | return false; 1054 | } 1055 | } 1056 | 1057 | LogMessage("Found .NAV file in %s", sNavFilePath); 1058 | 1059 | // Get magic number. 1060 | int iNavMagicNumber = 0; 1061 | int iElementsRead = ReadFileCell(hFile, iNavMagicNumber, UNSIGNED_INT_BYTE_SIZE); 1062 | 1063 | if (iElementsRead != 1) 1064 | { 1065 | delete hFile; 1066 | LogError("Error reading magic number value from navigation mesh: %s", sNavFilePath); 1067 | return false; 1068 | } 1069 | 1070 | if (iNavMagicNumber != NAV_MAGIC_NUMBER) 1071 | { 1072 | delete hFile; 1073 | LogError("Invalid magic number value from navigation mesh: %s [%p]", sNavFilePath, iNavMagicNumber); 1074 | return false; 1075 | } 1076 | 1077 | // Get the version. 1078 | int iNavVersion; 1079 | iElementsRead = ReadFileCell(hFile, iNavVersion, UNSIGNED_INT_BYTE_SIZE); 1080 | 1081 | if (iElementsRead != 1) 1082 | { 1083 | delete hFile; 1084 | LogError("Error reading version number from navigation mesh: %s", sNavFilePath); 1085 | return false; 1086 | } 1087 | 1088 | if (iNavVersion < 6 || iNavVersion > 16) 1089 | { 1090 | delete hFile; 1091 | LogError("Invalid version number value from navigation mesh: %s [%d]", sNavFilePath, iNavVersion); 1092 | return false; 1093 | } 1094 | 1095 | // Get the sub version, if supported. 1096 | int iNavSubVersion = 0; 1097 | if (iNavVersion >= 10) 1098 | { 1099 | ReadFileCell(hFile, iNavSubVersion, UNSIGNED_INT_BYTE_SIZE); 1100 | } 1101 | 1102 | // Get the save bsp size. 1103 | int iNavSaveBspSize = 0; 1104 | if (iNavVersion >= 4) 1105 | { 1106 | ReadFileCell(hFile, iNavSaveBspSize, UNSIGNED_INT_BYTE_SIZE); 1107 | } 1108 | 1109 | // Check if the nav mesh was analyzed. 1110 | int iNavMeshAnalyzed = 0; 1111 | if (iNavVersion >= 14) 1112 | { 1113 | ReadFileCell(hFile, iNavMeshAnalyzed, UNSIGNED_CHAR_BYTE_SIZE); 1114 | LogMessage("Is mesh analyzed: %d", iNavMeshAnalyzed); 1115 | } 1116 | 1117 | LogMessage("Nav version: %d; SubVersion: %d (v10+); BSPSize: %d; MagicNumber: %d", iNavVersion, iNavSubVersion, iNavSaveBspSize, iNavMagicNumber); 1118 | 1119 | int iPlaceCount = 0; 1120 | ReadFileCell(hFile, iPlaceCount, UNSIGNED_SHORT_BYTE_SIZE); 1121 | LogMessage("Place count: %d", iPlaceCount); 1122 | 1123 | // Parse through places. 1124 | // TF2 doesn't use places, but CS:S does. 1125 | for (int iPlaceIndex = 0; iPlaceIndex < iPlaceCount; iPlaceIndex++) 1126 | { 1127 | int iPlaceStringSize = 0; 1128 | ReadFileCell(hFile, iPlaceStringSize, UNSIGNED_SHORT_BYTE_SIZE); 1129 | 1130 | char sPlaceName[256]; 1131 | ReadFileString(hFile, sPlaceName, sizeof(sPlaceName), iPlaceStringSize); 1132 | 1133 | PushArrayString(g_hNavMeshPlaces, sPlaceName); 1134 | 1135 | //LogMessage("Parsed place \"%s\" [index: %d]", sPlaceName, iPlaceIndex); 1136 | } 1137 | 1138 | // Get any unnamed areas. 1139 | int iNavUnnamedAreas = 0; 1140 | if (iNavVersion > 11) 1141 | { 1142 | ReadFileCell(hFile, iNavUnnamedAreas, UNSIGNED_CHAR_BYTE_SIZE); 1143 | LogMessage("Has unnamed areas: %s", iNavUnnamedAreas ? "true" : "false"); 1144 | } 1145 | 1146 | // Get area count. 1147 | int iAreaCount = 0; 1148 | ReadFileCell(hFile, iAreaCount, UNSIGNED_INT_BYTE_SIZE); 1149 | 1150 | LogMessage("Area count: %d", iAreaCount); 1151 | 1152 | static float flExtentLow[2] = { 99999999.9, 99999999.9 }; 1153 | static float flExtentHigh[2] = { -99999999.9, -99999999.9 }; 1154 | bool bExtentLowX = false; 1155 | bool bExtentLowY = false; 1156 | bool bExtentHighX = false; 1157 | bool bExtentHighY = false; 1158 | 1159 | if (iAreaCount > 0) 1160 | { 1161 | // The following are index values that will serve as starting and ending markers for areas 1162 | // to determine what is theirs. 1163 | 1164 | // This is to avoid iteration of the whole area set to reduce lookup time. 1165 | 1166 | int iGlobalConnectionsStartIndex = 0; 1167 | int iGlobalHidingSpotsStartIndex = 0; 1168 | int iGlobalEncounterPathsStartIndex = 0; 1169 | int iGlobalEncounterSpotsStartIndex = 0; 1170 | int iGlobalLadderConnectionsStartIndex = 0; 1171 | int iGlobalVisibleAreasStartIndex = 0; 1172 | 1173 | for (int iAreaIndex = 0; iAreaIndex < iAreaCount; iAreaIndex++) 1174 | { 1175 | int iAreaID; 1176 | float x1; 1177 | float y1; 1178 | float z1; 1179 | float x2; 1180 | float y2; 1181 | float z2; 1182 | int iAreaFlags; 1183 | int iInheritVisibilityFrom; 1184 | int iHidingSpotCount; 1185 | int iVisibleAreaCount; 1186 | float flEarliestOccupyTimeFirstTeam; 1187 | float flEarliestOccupyTimeSecondTeam; 1188 | float flNECornerZ; 1189 | float flSWCornerZ; 1190 | int iPlaceID; 1191 | int unk01; 1192 | 1193 | ReadFileCell(hFile, iAreaID, UNSIGNED_INT_BYTE_SIZE); 1194 | 1195 | //LogMessage("Area ID: %d", iAreaID); 1196 | 1197 | if (iNavVersion <= 8) 1198 | { 1199 | ReadFileCell(hFile, iAreaFlags, UNSIGNED_CHAR_BYTE_SIZE); 1200 | } 1201 | else if (iNavVersion < 13) 1202 | { 1203 | ReadFileCell(hFile, iAreaFlags, UNSIGNED_SHORT_BYTE_SIZE); 1204 | } 1205 | else 1206 | { 1207 | ReadFileCell(hFile, iAreaFlags, UNSIGNED_INT_BYTE_SIZE); 1208 | } 1209 | 1210 | //LogMessage("Area Flags: %d", iAreaFlags); 1211 | 1212 | ReadFileCell(hFile, view_as(x1), FLOAT_BYTE_SIZE); 1213 | ReadFileCell(hFile, view_as(y1), FLOAT_BYTE_SIZE); 1214 | ReadFileCell(hFile, view_as(z1), FLOAT_BYTE_SIZE); 1215 | ReadFileCell(hFile, view_as(x2), FLOAT_BYTE_SIZE); 1216 | ReadFileCell(hFile, view_as(y2), FLOAT_BYTE_SIZE); 1217 | ReadFileCell(hFile, view_as(z2), FLOAT_BYTE_SIZE); 1218 | 1219 | //LogMessage("Area extent: (%f, %f, %f), (%f, %f, %f)", x1, y1, z1, x2, y2, z2); 1220 | 1221 | if (!bExtentLowX || x1 < flExtentLow[0]) 1222 | { 1223 | bExtentLowX = true; 1224 | flExtentLow[0] = x1; 1225 | } 1226 | 1227 | if (!bExtentLowY || y1 < flExtentLow[1]) 1228 | { 1229 | bExtentLowY = true; 1230 | flExtentLow[1] = y1; 1231 | } 1232 | 1233 | if (!bExtentHighX || x2 > flExtentHigh[0]) 1234 | { 1235 | bExtentHighX = true; 1236 | flExtentHigh[0] = x2; 1237 | } 1238 | 1239 | if (!bExtentHighY || y2 > flExtentHigh[1]) 1240 | { 1241 | bExtentHighY = true; 1242 | flExtentHigh[1] = y2; 1243 | } 1244 | 1245 | // Cache the center position. 1246 | float flAreaCenter[3]; 1247 | flAreaCenter[0] = (x1 + x2) / 2.0; 1248 | flAreaCenter[1] = (y1 + y2) / 2.0; 1249 | flAreaCenter[2] = (z1 + z2) / 2.0; 1250 | 1251 | float flInvDxCorners = 0.0; 1252 | float flInvDyCorners = 0.0; 1253 | 1254 | if ((x2 - x1) > 0.0 && (y2 - y1) > 0.0) 1255 | { 1256 | flInvDxCorners = 1.0 / (x2 - x1); 1257 | flInvDyCorners = 1.0 / (y2 - y1); 1258 | } 1259 | 1260 | ReadFileCell(hFile, view_as(flNECornerZ), FLOAT_BYTE_SIZE); 1261 | ReadFileCell(hFile, view_as(flSWCornerZ), FLOAT_BYTE_SIZE); 1262 | 1263 | //LogMessage("Corners: NW(%f), SW(%f)", flNECornerZ, flSWCornerZ); 1264 | 1265 | int iConnectionsStartIndex = -1; 1266 | int iConnectionsEndIndex = -1; 1267 | 1268 | // Find connections. 1269 | for (int iDirection = 0; iDirection < NAV_DIR_COUNT; iDirection++) 1270 | { 1271 | int iConnectionCount = 0; 1272 | ReadFileCell(hFile, iConnectionCount, UNSIGNED_INT_BYTE_SIZE); 1273 | 1274 | //LogMessage("Connection count: %d", iConnectionCount); 1275 | 1276 | if (iConnectionCount > 0) 1277 | { 1278 | if (iConnectionsStartIndex == -1) iConnectionsStartIndex = iGlobalConnectionsStartIndex; 1279 | 1280 | for (int iConnectionIndex = 0; iConnectionIndex < iConnectionCount; iConnectionIndex++) 1281 | { 1282 | iConnectionsEndIndex = iGlobalConnectionsStartIndex; 1283 | 1284 | int iConnectingAreaID = 0; 1285 | ReadFileCell(hFile, iConnectingAreaID, UNSIGNED_INT_BYTE_SIZE); 1286 | 1287 | int iIndex = g_hNavMeshAreaConnections.Push(iConnectingAreaID); 1288 | g_hNavMeshAreaConnections.Set(iIndex, iDirection, NavMeshConnection_Direction); 1289 | 1290 | iGlobalConnectionsStartIndex++; 1291 | } 1292 | } 1293 | } 1294 | 1295 | // Get hiding spots. 1296 | ReadFileCell(hFile, iHidingSpotCount, UNSIGNED_CHAR_BYTE_SIZE); 1297 | 1298 | //LogMessage("Hiding spot count: %d", iHidingSpotCount); 1299 | 1300 | int iHidingSpotsStartIndex = -1; 1301 | int iHidingSpotsEndIndex = -1; 1302 | 1303 | if (iHidingSpotCount > 0) 1304 | { 1305 | iHidingSpotsStartIndex = iGlobalHidingSpotsStartIndex; 1306 | 1307 | for (int iHidingSpotIndex = 0; iHidingSpotIndex < iHidingSpotCount; iHidingSpotIndex++) 1308 | { 1309 | iHidingSpotsEndIndex = iGlobalHidingSpotsStartIndex; 1310 | 1311 | int iHidingSpotID; 1312 | ReadFileCell(hFile, iHidingSpotID, UNSIGNED_INT_BYTE_SIZE); 1313 | 1314 | float flHidingSpotX; float flHidingSpotY; float flHidingSpotZ; 1315 | ReadFileCell(hFile, view_as(flHidingSpotX), FLOAT_BYTE_SIZE); 1316 | ReadFileCell(hFile, view_as(flHidingSpotY), FLOAT_BYTE_SIZE); 1317 | ReadFileCell(hFile, view_as(flHidingSpotZ), FLOAT_BYTE_SIZE); 1318 | 1319 | int iHidingSpotFlags; 1320 | ReadFileCell(hFile, iHidingSpotFlags, UNSIGNED_CHAR_BYTE_SIZE); 1321 | 1322 | int iIndex = g_hNavMeshAreaHidingSpots.Push(iHidingSpotID); 1323 | g_hNavMeshAreaHidingSpots.Set(iIndex, flHidingSpotX, NavMeshHidingSpot_X); 1324 | g_hNavMeshAreaHidingSpots.Set(iIndex, flHidingSpotY, NavMeshHidingSpot_Y); 1325 | g_hNavMeshAreaHidingSpots.Set(iIndex, flHidingSpotZ, NavMeshHidingSpot_Z); 1326 | g_hNavMeshAreaHidingSpots.Set(iIndex, iHidingSpotFlags, NavMeshHidingSpot_Flags); 1327 | g_hNavMeshAreaHidingSpots.Set(iIndex, iAreaIndex, NavMeshHidingSpot_AreaIndex); 1328 | 1329 | iGlobalHidingSpotsStartIndex++; 1330 | 1331 | //LogMessage("Parsed hiding spot (%f, %f, %f) with ID [%d] and flags [%d]", flHidingSpotX, flHidingSpotY, flHidingSpotZ, iHidingSpotID, iHidingSpotFlags); 1332 | } 1333 | } 1334 | 1335 | // Get approach areas (old version, only used to read data) 1336 | if (iNavVersion < 15) 1337 | { 1338 | int iApproachAreaCount = 0; 1339 | ReadFileCell(hFile, iApproachAreaCount, UNSIGNED_CHAR_BYTE_SIZE); 1340 | 1341 | for (int iApproachAreaIndex = 0; iApproachAreaIndex < iApproachAreaCount; iApproachAreaIndex++) 1342 | { 1343 | int iApproachHereID; 1344 | ReadFileCell(hFile, iApproachHereID, UNSIGNED_INT_BYTE_SIZE); 1345 | 1346 | int iApproachPrevID; 1347 | ReadFileCell(hFile, iApproachPrevID, UNSIGNED_INT_BYTE_SIZE); 1348 | 1349 | int iApproachType; 1350 | ReadFileCell(hFile, iApproachType, UNSIGNED_CHAR_BYTE_SIZE); 1351 | 1352 | int iApproachNextID; 1353 | ReadFileCell(hFile, iApproachNextID, UNSIGNED_INT_BYTE_SIZE); 1354 | 1355 | int iApproachHow; 1356 | ReadFileCell(hFile, iApproachHow, UNSIGNED_CHAR_BYTE_SIZE); 1357 | } 1358 | } 1359 | 1360 | // Get encounter paths. 1361 | int iEncounterPathCount; 1362 | ReadFileCell(hFile, iEncounterPathCount, UNSIGNED_INT_BYTE_SIZE); 1363 | 1364 | //LogMessage("Encounter Path Count: %d", iEncounterPathCount); 1365 | 1366 | int iEncounterPathsStartIndex = -1; 1367 | int iEncounterPathsEndIndex = -1; 1368 | 1369 | if (iEncounterPathCount > 0) 1370 | { 1371 | iEncounterPathsStartIndex = iGlobalEncounterPathsStartIndex; 1372 | 1373 | for (int iEncounterPathIndex = 0; iEncounterPathIndex < iEncounterPathCount; iEncounterPathIndex++) 1374 | { 1375 | iEncounterPathsEndIndex = iGlobalEncounterPathsStartIndex; 1376 | 1377 | int iEncounterFromID; 1378 | ReadFileCell(hFile, iEncounterFromID, UNSIGNED_INT_BYTE_SIZE); 1379 | 1380 | int iEncounterFromDirection; 1381 | ReadFileCell(hFile, iEncounterFromDirection, UNSIGNED_CHAR_BYTE_SIZE); 1382 | 1383 | int iEncounterToID; 1384 | ReadFileCell(hFile, iEncounterToID, UNSIGNED_INT_BYTE_SIZE); 1385 | 1386 | int iEncounterToDirection; 1387 | ReadFileCell(hFile, iEncounterToDirection, UNSIGNED_CHAR_BYTE_SIZE); 1388 | 1389 | int iEncounterSpotCount; 1390 | ReadFileCell(hFile, iEncounterSpotCount, UNSIGNED_CHAR_BYTE_SIZE); 1391 | 1392 | //LogMessage("Encounter [from ID %d] [from dir %d] [to ID %d] [to dir %d] [spot count %d]", iEncounterFromID, iEncounterFromDirection, iEncounterToID, iEncounterToDirection, iEncounterSpotCount); 1393 | 1394 | int iEncounterSpotsStartIndex = -1; 1395 | int iEncounterSpotsEndIndex = -1; 1396 | 1397 | if (iEncounterSpotCount > 0) 1398 | { 1399 | iEncounterSpotsStartIndex = iGlobalEncounterSpotsStartIndex; 1400 | 1401 | for (int iEncounterSpotIndex = 0; iEncounterSpotIndex < iEncounterSpotCount; iEncounterSpotIndex++) 1402 | { 1403 | iEncounterSpotsEndIndex = iGlobalEncounterSpotsStartIndex; 1404 | 1405 | int iEncounterSpotOrderID; 1406 | ReadFileCell(hFile, iEncounterSpotOrderID, UNSIGNED_INT_BYTE_SIZE); 1407 | 1408 | int iEncounterSpotT; 1409 | ReadFileCell(hFile, iEncounterSpotT, UNSIGNED_CHAR_BYTE_SIZE); 1410 | 1411 | float flEncounterSpotParametricDistance = float(iEncounterSpotT) / 255.0; 1412 | 1413 | int iIndex = g_hNavMeshAreaEncounterSpots.Push(iEncounterSpotOrderID); 1414 | g_hNavMeshAreaEncounterSpots.Set(iIndex, flEncounterSpotParametricDistance, NavMeshEncounterSpot_ParametricDistance); 1415 | 1416 | iGlobalEncounterSpotsStartIndex++; 1417 | 1418 | //LogMessage("Encounter spot [order id %d] and [T %d]", iEncounterSpotOrderID, iEncounterSpotT); 1419 | } 1420 | } 1421 | 1422 | int iIndex = g_hNavMeshAreaEncounterPaths.Push(iEncounterFromID); 1423 | g_hNavMeshAreaEncounterPaths.Set(iIndex, iEncounterFromDirection, NavMeshEncounterPath_FromDirection); 1424 | g_hNavMeshAreaEncounterPaths.Set(iIndex, iEncounterToID, NavMeshEncounterPath_ToAreaIndex); 1425 | g_hNavMeshAreaEncounterPaths.Set(iIndex, iEncounterToDirection, NavMeshEncounterPath_ToDirection); 1426 | g_hNavMeshAreaEncounterPaths.Set(iIndex, iEncounterSpotsStartIndex, NavMeshEncounterPath_SpotsStartIndex); 1427 | g_hNavMeshAreaEncounterPaths.Set(iIndex, iEncounterSpotsEndIndex, NavMeshEncounterPath_SpotsEndIndex); 1428 | 1429 | iGlobalEncounterPathsStartIndex++; 1430 | } 1431 | } 1432 | 1433 | ReadFileCell(hFile, iPlaceID, UNSIGNED_SHORT_BYTE_SIZE); 1434 | 1435 | //LogMessage("Place ID: %d", iPlaceID); 1436 | 1437 | // Get ladder connections. 1438 | 1439 | int iLadderConnectionsStartIndex = -1; 1440 | int iLadderConnectionsEndIndex = -1; 1441 | 1442 | for (int iLadderDirection = 0; iLadderDirection < NAV_LADDER_DIR_COUNT; iLadderDirection++) 1443 | { 1444 | int iLadderConnectionCount; 1445 | ReadFileCell(hFile, iLadderConnectionCount, UNSIGNED_INT_BYTE_SIZE); 1446 | 1447 | //LogMessage("Ladder Connection Count: %d", iLadderConnectionCount); 1448 | 1449 | if (iLadderConnectionCount > 0) 1450 | { 1451 | iLadderConnectionsStartIndex = iGlobalLadderConnectionsStartIndex; 1452 | 1453 | for (int iLadderConnectionIndex = 0; iLadderConnectionIndex < iLadderConnectionCount; iLadderConnectionIndex++) 1454 | { 1455 | iLadderConnectionsEndIndex = iGlobalLadderConnectionsStartIndex; 1456 | 1457 | int iLadderConnectionID; 1458 | ReadFileCell(hFile, iLadderConnectionID, UNSIGNED_INT_BYTE_SIZE); 1459 | 1460 | int iIndex = g_hNavMeshAreaLadderConnections.Push(iLadderConnectionID); 1461 | g_hNavMeshAreaLadderConnections.Set(iIndex, iLadderDirection, NavMeshLadderConnection_Direction); 1462 | 1463 | iGlobalLadderConnectionsStartIndex++; 1464 | 1465 | //LogMessage("Parsed ladder connect [ID %d]\n", iLadderConnectionID); 1466 | } 1467 | } 1468 | } 1469 | 1470 | ReadFileCell(hFile, view_as(flEarliestOccupyTimeFirstTeam), FLOAT_BYTE_SIZE); 1471 | ReadFileCell(hFile, view_as(flEarliestOccupyTimeSecondTeam), FLOAT_BYTE_SIZE); 1472 | 1473 | float flNavCornerLightIntensityNW; 1474 | float flNavCornerLightIntensityNE; 1475 | float flNavCornerLightIntensitySE; 1476 | float flNavCornerLightIntensitySW; 1477 | 1478 | int iVisibleAreasStartIndex = -1; 1479 | int iVisibleAreasEndIndex = -1; 1480 | 1481 | if (iNavVersion >= 11) 1482 | { 1483 | ReadFileCell(hFile, view_as(flNavCornerLightIntensityNW), FLOAT_BYTE_SIZE); 1484 | ReadFileCell(hFile, view_as(flNavCornerLightIntensityNE), FLOAT_BYTE_SIZE); 1485 | ReadFileCell(hFile, view_as(flNavCornerLightIntensitySE), FLOAT_BYTE_SIZE); 1486 | ReadFileCell(hFile, view_as(flNavCornerLightIntensitySW), FLOAT_BYTE_SIZE); 1487 | 1488 | if (iNavVersion >= 16) 1489 | { 1490 | ReadFileCell(hFile, iVisibleAreaCount, UNSIGNED_INT_BYTE_SIZE); 1491 | 1492 | //LogMessage("Visible area count: %d", iVisibleAreaCount); 1493 | 1494 | if (iVisibleAreaCount > 0) 1495 | { 1496 | iVisibleAreasStartIndex = iGlobalVisibleAreasStartIndex; 1497 | 1498 | for (int iVisibleAreaIndex = 0; iVisibleAreaIndex < iVisibleAreaCount; iVisibleAreaIndex++) 1499 | { 1500 | iVisibleAreasEndIndex = iGlobalVisibleAreasStartIndex; 1501 | 1502 | int iVisibleAreaID; 1503 | ReadFileCell(hFile, iVisibleAreaID, UNSIGNED_INT_BYTE_SIZE); 1504 | 1505 | int iVisibleAreaAttributes; 1506 | ReadFileCell(hFile, iVisibleAreaAttributes, UNSIGNED_CHAR_BYTE_SIZE); 1507 | 1508 | int iIndex = g_hNavMeshAreaVisibleAreas.Push(iVisibleAreaID); 1509 | g_hNavMeshAreaVisibleAreas.Set(iIndex, iVisibleAreaAttributes, NavMeshVisibleArea_Attributes); 1510 | 1511 | iGlobalVisibleAreasStartIndex++; 1512 | 1513 | //LogMessage("Parsed visible area [%d] with attr [%d]", iVisibleAreaID, iVisibleAreaAttributes); 1514 | } 1515 | } 1516 | 1517 | ReadFileCell(hFile, iInheritVisibilityFrom, UNSIGNED_INT_BYTE_SIZE); 1518 | 1519 | //LogMessage("Inherit visibilty from: %d", iInheritVisibilityFrom); 1520 | 1521 | ReadFileCell(hFile, unk01, UNSIGNED_INT_BYTE_SIZE); 1522 | } 1523 | } 1524 | 1525 | int iIndex = g_hNavMeshAreas.Push(iAreaID); 1526 | g_hNavMeshAreas.Set(iIndex, iAreaFlags, NavMeshArea_Flags); 1527 | g_hNavMeshAreas.Set(iIndex, iPlaceID, NavMeshArea_PlaceID); 1528 | g_hNavMeshAreas.Set(iIndex, x1, NavMeshArea_X1); 1529 | g_hNavMeshAreas.Set(iIndex, y1, NavMeshArea_Y1); 1530 | g_hNavMeshAreas.Set(iIndex, z1, NavMeshArea_Z1); 1531 | g_hNavMeshAreas.Set(iIndex, x2, NavMeshArea_X2); 1532 | g_hNavMeshAreas.Set(iIndex, y2, NavMeshArea_Y2); 1533 | g_hNavMeshAreas.Set(iIndex, z2, NavMeshArea_Z2); 1534 | g_hNavMeshAreas.Set(iIndex, flAreaCenter[0], NavMeshArea_CenterX); 1535 | g_hNavMeshAreas.Set(iIndex, flAreaCenter[1], NavMeshArea_CenterY); 1536 | g_hNavMeshAreas.Set(iIndex, flAreaCenter[2], NavMeshArea_CenterZ); 1537 | g_hNavMeshAreas.Set(iIndex, flInvDxCorners, NavMeshArea_InvDxCorners); 1538 | g_hNavMeshAreas.Set(iIndex, flInvDyCorners, NavMeshArea_InvDyCorners); 1539 | g_hNavMeshAreas.Set(iIndex, flNECornerZ, NavMeshArea_NECornerZ); 1540 | g_hNavMeshAreas.Set(iIndex, flSWCornerZ, NavMeshArea_SWCornerZ); 1541 | g_hNavMeshAreas.Set(iIndex, iConnectionsStartIndex, NavMeshArea_ConnectionsStartIndex); 1542 | g_hNavMeshAreas.Set(iIndex, iConnectionsEndIndex, NavMeshArea_ConnectionsEndIndex); 1543 | g_hNavMeshAreas.Set(iIndex, iHidingSpotsStartIndex, NavMeshArea_HidingSpotsStartIndex); 1544 | g_hNavMeshAreas.Set(iIndex, iHidingSpotsEndIndex, NavMeshArea_HidingSpotsEndIndex); 1545 | g_hNavMeshAreas.Set(iIndex, iEncounterPathsStartIndex, NavMeshArea_EncounterPathsStartIndex); 1546 | g_hNavMeshAreas.Set(iIndex, iEncounterPathsEndIndex, NavMeshArea_EncounterPathsEndIndex); 1547 | g_hNavMeshAreas.Set(iIndex, iLadderConnectionsStartIndex, NavMeshArea_LadderConnectionsStartIndex); 1548 | g_hNavMeshAreas.Set(iIndex, iLadderConnectionsEndIndex, NavMeshArea_LadderConnectionsEndIndex); 1549 | g_hNavMeshAreas.Set(iIndex, flNavCornerLightIntensityNW, NavMeshArea_CornerLightIntensityNW); 1550 | g_hNavMeshAreas.Set(iIndex, flNavCornerLightIntensityNE, NavMeshArea_CornerLightIntensityNE); 1551 | g_hNavMeshAreas.Set(iIndex, flNavCornerLightIntensitySE, NavMeshArea_CornerLightIntensitySE); 1552 | g_hNavMeshAreas.Set(iIndex, flNavCornerLightIntensitySW, NavMeshArea_CornerLightIntensitySW); 1553 | g_hNavMeshAreas.Set(iIndex, iVisibleAreasStartIndex, NavMeshArea_VisibleAreasStartIndex); 1554 | g_hNavMeshAreas.Set(iIndex, iVisibleAreasEndIndex, NavMeshArea_VisibleAreasEndIndex); 1555 | g_hNavMeshAreas.Set(iIndex, iInheritVisibilityFrom, NavMeshArea_InheritVisibilityFrom); 1556 | g_hNavMeshAreas.Set(iIndex, flEarliestOccupyTimeFirstTeam, NavMeshArea_EarliestOccupyTimeFirstTeam); 1557 | g_hNavMeshAreas.Set(iIndex, flEarliestOccupyTimeSecondTeam, NavMeshArea_EarliestOccupyTimeSecondTeam); 1558 | g_hNavMeshAreas.Set(iIndex, unk01, NavMeshArea_unk01); 1559 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_Parent); 1560 | g_hNavMeshAreas.Set(iIndex, NUM_TRAVERSE_TYPES, NavMeshArea_ParentHow); 1561 | g_hNavMeshAreas.Set(iIndex, 0, NavMeshArea_TotalCost); 1562 | g_hNavMeshAreas.Set(iIndex, 0, NavMeshArea_CostSoFar); 1563 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_Marker); 1564 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_OpenMarker); 1565 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_PrevOpenIndex); 1566 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_NextOpenIndex); 1567 | g_hNavMeshAreas.Set(iIndex, 0.0, NavMeshArea_PathLengthSoFar); 1568 | g_hNavMeshAreas.Set(iIndex, false, NavMeshArea_Blocked); 1569 | g_hNavMeshAreas.Set(iIndex, -1, NavMeshArea_NearSearchMarker); 1570 | } 1571 | } 1572 | 1573 | // Set up the grid. 1574 | NavMeshGridAllocate(flExtentLow[0], flExtentHigh[0], flExtentLow[1], flExtentHigh[1]); 1575 | 1576 | for (int i = 0; i < iAreaCount; i++) 1577 | { 1578 | NavMeshAddAreaToGrid(i); 1579 | } 1580 | 1581 | NavMeshGridFinalize(); 1582 | 1583 | int iLadderCount; 1584 | ReadFileCell(hFile, iLadderCount, UNSIGNED_INT_BYTE_SIZE); 1585 | 1586 | if (iLadderCount > 0) 1587 | { 1588 | for (int iLadderIndex; iLadderIndex < iLadderCount; iLadderIndex++) 1589 | { 1590 | int iLadderID; 1591 | ReadFileCell(hFile, iLadderID, UNSIGNED_INT_BYTE_SIZE); 1592 | 1593 | float flLadderWidth; 1594 | ReadFileCell(hFile, view_as(flLadderWidth), FLOAT_BYTE_SIZE); 1595 | 1596 | float flLadderTopX; float flLadderTopY; float flLadderTopZ; float flLadderBottomX; float flLadderBottomY; float flLadderBottomZ; 1597 | ReadFileCell(hFile, view_as(flLadderTopX), FLOAT_BYTE_SIZE); 1598 | ReadFileCell(hFile, view_as(flLadderTopY), FLOAT_BYTE_SIZE); 1599 | ReadFileCell(hFile, view_as(flLadderTopZ), FLOAT_BYTE_SIZE); 1600 | ReadFileCell(hFile, view_as(flLadderBottomX), FLOAT_BYTE_SIZE); 1601 | ReadFileCell(hFile, view_as(flLadderBottomY), FLOAT_BYTE_SIZE); 1602 | ReadFileCell(hFile, view_as(flLadderBottomZ), FLOAT_BYTE_SIZE); 1603 | 1604 | float flLadderLength; 1605 | ReadFileCell(hFile, view_as(flLadderLength), FLOAT_BYTE_SIZE); 1606 | 1607 | int iLadderDirection; 1608 | ReadFileCell(hFile, iLadderDirection, UNSIGNED_INT_BYTE_SIZE); 1609 | 1610 | int iLadderTopForwardAreaID; 1611 | ReadFileCell(hFile, iLadderTopForwardAreaID, UNSIGNED_INT_BYTE_SIZE); 1612 | 1613 | int iLadderTopLeftAreaID; 1614 | ReadFileCell(hFile, iLadderTopLeftAreaID, UNSIGNED_INT_BYTE_SIZE); 1615 | 1616 | int iLadderTopRightAreaID; 1617 | ReadFileCell(hFile, iLadderTopRightAreaID, UNSIGNED_INT_BYTE_SIZE); 1618 | 1619 | int iLadderTopBehindAreaID; 1620 | ReadFileCell(hFile, iLadderTopBehindAreaID, UNSIGNED_INT_BYTE_SIZE); 1621 | 1622 | int iLadderBottomAreaID; 1623 | ReadFileCell(hFile, iLadderBottomAreaID, UNSIGNED_INT_BYTE_SIZE); 1624 | 1625 | int iIndex = g_hNavMeshLadders.Push(iLadderID); 1626 | g_hNavMeshLadders.Set(iIndex, flLadderWidth, NavMeshLadder_Width); 1627 | g_hNavMeshLadders.Set(iIndex, flLadderLength, NavMeshLadder_Length); 1628 | g_hNavMeshLadders.Set(iIndex, flLadderTopX, NavMeshLadder_TopX); 1629 | g_hNavMeshLadders.Set(iIndex, flLadderTopY, NavMeshLadder_TopY); 1630 | g_hNavMeshLadders.Set(iIndex, flLadderTopZ, NavMeshLadder_TopZ); 1631 | g_hNavMeshLadders.Set(iIndex, flLadderBottomX, NavMeshLadder_BottomX); 1632 | g_hNavMeshLadders.Set(iIndex, flLadderBottomY, NavMeshLadder_BottomY); 1633 | g_hNavMeshLadders.Set(iIndex, flLadderBottomZ, NavMeshLadder_BottomZ); 1634 | g_hNavMeshLadders.Set(iIndex, iLadderDirection, NavMeshLadder_Direction); 1635 | g_hNavMeshLadders.Set(iIndex, iLadderTopForwardAreaID, NavMeshLadder_TopForwardAreaIndex); 1636 | g_hNavMeshLadders.Set(iIndex, iLadderTopLeftAreaID, NavMeshLadder_TopLeftAreaIndex); 1637 | g_hNavMeshLadders.Set(iIndex, iLadderTopRightAreaID, NavMeshLadder_TopRightAreaIndex); 1638 | g_hNavMeshLadders.Set(iIndex, iLadderTopBehindAreaID, NavMeshLadder_TopBehindAreaIndex); 1639 | g_hNavMeshLadders.Set(iIndex, iLadderBottomAreaID, NavMeshLadder_BottomAreaIndex); 1640 | } 1641 | } 1642 | 1643 | g_iNavMeshMagicNumber = iNavMagicNumber; 1644 | g_iNavMeshVersion = iNavVersion; 1645 | g_iNavMeshSubVersion = iNavSubVersion; 1646 | g_iNavMeshSaveBSPSize = iNavSaveBspSize; 1647 | g_bNavMeshAnalyzed = view_as(iNavMeshAnalyzed); 1648 | 1649 | delete hFile; 1650 | 1651 | // File parsing is all done. Convert referenced IDs to array indexes for faster performance and 1652 | // lesser lookup time in the future. 1653 | 1654 | if (g_hNavMeshAreaConnections.Length > 0) 1655 | { 1656 | for (int iIndex = 0, iSize = g_hNavMeshAreaConnections.Length; iIndex < iSize; iIndex++) 1657 | { 1658 | int id = g_hNavMeshAreaConnections.Get(iIndex, NavMeshConnection_AreaIndex); 1659 | g_hNavMeshAreaConnections.Set(iIndex, g_hNavMeshAreas.FindValue(id), NavMeshConnection_AreaIndex); 1660 | } 1661 | } 1662 | 1663 | if (g_hNavMeshAreaVisibleAreas.Length > 0) 1664 | { 1665 | for (int iIndex = 0, iSize = g_hNavMeshAreaVisibleAreas.Length; iIndex < iSize; iIndex++) 1666 | { 1667 | int id = g_hNavMeshAreaVisibleAreas.Get(iIndex, NavMeshVisibleArea_Index); 1668 | g_hNavMeshAreaVisibleAreas.Set(iIndex, g_hNavMeshAreas.FindValue(id), NavMeshVisibleArea_Index); 1669 | } 1670 | } 1671 | 1672 | if (g_hNavMeshAreaEncounterPaths.Length > 0) 1673 | { 1674 | for (int iIndex = 0, iSize = g_hNavMeshAreaEncounterPaths.Length; iIndex < iSize; iIndex++) 1675 | { 1676 | int id = g_hNavMeshAreaEncounterPaths.Get(iIndex, NavMeshEncounterPath_FromAreaIndex); 1677 | g_hNavMeshAreaEncounterPaths.Set(iIndex, g_hNavMeshAreas.FindValue(id), NavMeshEncounterPath_FromAreaIndex); 1678 | 1679 | id = g_hNavMeshAreaEncounterPaths.Get(iIndex, NavMeshEncounterPath_ToAreaIndex); 1680 | g_hNavMeshAreaEncounterPaths.Set(iIndex, g_hNavMeshAreas.FindValue(id), NavMeshEncounterPath_ToAreaIndex); 1681 | } 1682 | } 1683 | 1684 | if (g_hNavMeshAreaEncounterSpots.Length > 0) 1685 | { 1686 | for (int iIndex = 0, iSize = g_hNavMeshAreaEncounterPaths.Length; iIndex < iSize; iIndex++) 1687 | { 1688 | int id = g_hNavMeshAreaEncounterSpots.Get(iIndex, NavMeshEncounterSpot_HidingSpotIndex); 1689 | g_hNavMeshAreaEncounterSpots.Set(iIndex, g_hNavMeshAreaHidingSpots.FindValue(id), NavMeshEncounterSpot_HidingSpotIndex); 1690 | } 1691 | } 1692 | 1693 | if (g_hNavMeshAreaLadderConnections.Length > 0) 1694 | { 1695 | for (int iIndex = 0, iSize = g_hNavMeshAreaLadderConnections.Length; iIndex < iSize; iIndex++) 1696 | { 1697 | int id = g_hNavMeshAreaLadderConnections.Get(iIndex, NavMeshLadderConnection_LadderIndex); 1698 | g_hNavMeshAreaLadderConnections.Set(iIndex, g_hNavMeshLadders.FindValue(id), NavMeshLadderConnection_LadderIndex); 1699 | } 1700 | } 1701 | 1702 | if (g_hNavMeshLadders.Length > 0) 1703 | { 1704 | for (int iLadderIndex = 0; iLadderIndex < iLadderCount; iLadderIndex++) 1705 | { 1706 | int iTopForwardAreaID = GetArrayCell(g_hNavMeshLadders, iLadderIndex, NavMeshLadder_TopForwardAreaIndex); 1707 | g_hNavMeshLadders.Set(iLadderIndex, g_hNavMeshAreas.FindValue(iTopForwardAreaID), NavMeshLadder_TopForwardAreaIndex); 1708 | 1709 | int iTopLeftAreaID = GetArrayCell(g_hNavMeshLadders, iLadderIndex, NavMeshLadder_TopLeftAreaIndex); 1710 | g_hNavMeshLadders.Set(iLadderIndex, g_hNavMeshAreas.FindValue(iTopLeftAreaID), NavMeshLadder_TopLeftAreaIndex); 1711 | 1712 | int iTopRightAreaID = GetArrayCell(g_hNavMeshLadders, iLadderIndex, NavMeshLadder_TopRightAreaIndex); 1713 | g_hNavMeshLadders.Set(iLadderIndex, g_hNavMeshAreas.FindValue(iTopRightAreaID), NavMeshLadder_TopRightAreaIndex); 1714 | 1715 | int iTopBehindAreaID = GetArrayCell(g_hNavMeshLadders, iLadderIndex, NavMeshLadder_TopBehindAreaIndex); 1716 | g_hNavMeshLadders.Set(iLadderIndex, g_hNavMeshAreas.FindValue(iTopBehindAreaID), NavMeshLadder_TopBehindAreaIndex); 1717 | 1718 | int iBottomAreaID = GetArrayCell(g_hNavMeshLadders, iLadderIndex, NavMeshLadder_BottomAreaIndex); 1719 | g_hNavMeshLadders.Set(iLadderIndex, g_hNavMeshAreas.FindValue(iBottomAreaID), NavMeshLadder_BottomAreaIndex); 1720 | } 1721 | } 1722 | 1723 | return true; 1724 | } 1725 | 1726 | void NavMeshDestroy() 1727 | { 1728 | g_hNavMeshPlaces.Clear(); 1729 | g_hNavMeshAreas.Clear(); 1730 | g_hNavMeshAreaConnections.Clear(); 1731 | g_hNavMeshAreaHidingSpots.Clear(); 1732 | g_hNavMeshAreaEncounterPaths.Clear(); 1733 | g_hNavMeshAreaEncounterSpots.Clear(); 1734 | g_hNavMeshAreaLadderConnections.Clear(); 1735 | g_hNavMeshAreaVisibleAreas.Clear(); 1736 | g_hNavMeshLadders.Clear(); 1737 | 1738 | g_hNavMeshGrid.Clear(); 1739 | g_hNavMeshGridLists.Clear(); 1740 | 1741 | g_iNavMeshMagicNumber = 0; 1742 | g_iNavMeshVersion = 0; 1743 | g_iNavMeshSubVersion = 0; 1744 | g_iNavMeshSaveBSPSize = 0; 1745 | g_bNavMeshAnalyzed = false; 1746 | 1747 | g_bNavMeshBuilt = false; 1748 | 1749 | g_iNavMeshAreaOpenListIndex = -1; 1750 | g_iNavMeshAreaOpenListTailIndex = -1; 1751 | g_iNavMeshAreaMasterMarker = 0; 1752 | } 1753 | 1754 | void NavMeshGridAllocate(float flMinX, float flMaxX, float flMinY, float flMaxY) 1755 | { 1756 | g_hNavMeshGrid.Clear(); 1757 | g_hNavMeshGridLists.Clear(); 1758 | 1759 | g_flNavMeshMinX = flMinX; 1760 | g_flNavMeshMinY = flMinY; 1761 | 1762 | g_iNavMeshGridSizeX = IntCast((flMaxX - flMinX) / g_flNavMeshGridCellSize) + 1; 1763 | g_iNavMeshGridSizeY = IntCast((flMaxY - flMinY) / g_flNavMeshGridCellSize) + 1; 1764 | 1765 | int iArraySize = g_iNavMeshGridSizeX * g_iNavMeshGridSizeY; 1766 | g_hNavMeshGrid.Resize(iArraySize); 1767 | 1768 | for (int iGridIndex = 0; iGridIndex < iArraySize; iGridIndex++) 1769 | { 1770 | g_hNavMeshGrid.Set(iGridIndex, -1, NavMeshGrid_ListStartIndex); 1771 | g_hNavMeshGrid.Set(iGridIndex, -1, NavMeshGrid_ListEndIndex); 1772 | } 1773 | } 1774 | 1775 | void NavMeshGridFinalize() 1776 | { 1777 | bool bAllIn = true; 1778 | 1779 | SortADTArrayCustom(g_hNavMeshGridLists, SortNavMeshGridLists); 1780 | 1781 | for (int iGridIndex = 0, iSize = g_hNavMeshGrid.Length; iGridIndex < iSize; iGridIndex++) 1782 | { 1783 | int iStartIndex = -1; 1784 | int iEndIndex = -1; 1785 | NavMeshGridGetListBounds(iGridIndex, iStartIndex, iEndIndex); 1786 | g_hNavMeshGrid.Set(iGridIndex, iStartIndex, NavMeshGrid_ListStartIndex); 1787 | g_hNavMeshGrid.Set(iGridIndex, iEndIndex, NavMeshGrid_ListEndIndex); 1788 | 1789 | if (iStartIndex != -1) 1790 | { 1791 | for (int iListIndex = iStartIndex; iListIndex <= iEndIndex; iListIndex++) 1792 | { 1793 | int iAreaIndex = GetArrayCell(g_hNavMeshGridLists, iListIndex); 1794 | if (iAreaIndex != -1) 1795 | { 1796 | 1797 | } 1798 | else 1799 | { 1800 | LogError("Warning! Invalid nav area found in list of grid index %d!", iGridIndex); 1801 | bAllIn = false; 1802 | } 1803 | } 1804 | } 1805 | } 1806 | 1807 | if (bAllIn) 1808 | { 1809 | LogMessage("All nav areas parsed into the grid!"); 1810 | } 1811 | else 1812 | { 1813 | LogError("Warning! Not all nav areas were parsed into the grid! Please check your nav mesh!"); 1814 | } 1815 | } 1816 | 1817 | // The following functions should ONLY be called during NavMeshLoad(), due to displacement of 1818 | // array indexes! 1819 | 1820 | // Some things to take into account: because we're adding things into the 1821 | // array, it's inevitable that the indexes will change over time. Therefore, 1822 | // we can't assign array indexes while this function is running, since it 1823 | // will shift preceding array indexes. 1824 | 1825 | // The array indexes should be assigned afterwards using NavMeshGridFinalize(). 1826 | 1827 | public int SortNavMeshGridLists(int index1, int index2, Handle ar, Handle hndl) 1828 | { 1829 | ArrayList array = view_as(ar); 1830 | int iGridIndex1 = array.Get(index1, NavMeshGridList_Owner); 1831 | int iGridIndex2 = array.Get(index2, NavMeshGridList_Owner); 1832 | 1833 | if (iGridIndex1 < iGridIndex2) return -1; 1834 | else if (iGridIndex1 > iGridIndex2) return 1; 1835 | return 0; 1836 | } 1837 | 1838 | void NavMeshGridAddAreaToList(int iGridIndex, int iAreaIndex) 1839 | { 1840 | int iIndex = g_hNavMeshGridLists.Push(iAreaIndex); 1841 | 1842 | if (iIndex != -1) 1843 | { 1844 | g_hNavMeshGridLists.Set(iIndex, iGridIndex, NavMeshGridList_Owner); 1845 | } 1846 | } 1847 | 1848 | void NavMeshGridGetListBounds(int iGridIndex, int &iStartIndex, int &iEndIndex) 1849 | { 1850 | iStartIndex = -1; 1851 | iEndIndex = -1; 1852 | 1853 | for (int i = 0, iSize = g_hNavMeshGridLists.Length; i < iSize; i++) 1854 | { 1855 | if (g_hNavMeshGridLists.Get(i, NavMeshGridList_Owner) == iGridIndex) 1856 | { 1857 | if (iStartIndex == -1) iStartIndex = i; 1858 | iEndIndex = i; 1859 | } 1860 | } 1861 | } 1862 | 1863 | void NavMeshAddAreaToGrid(iAreaIndex) 1864 | { 1865 | float flExtentLow[2]; float flExtentHigh[2]; 1866 | // NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 1867 | // NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 1868 | 1869 | flExtentLow[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X1)); 1870 | flExtentLow[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y1)); 1871 | flExtentHigh[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X2)); 1872 | flExtentHigh[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y2)); 1873 | 1874 | int loX = NavMeshWorldToGridX(flExtentLow[0]); 1875 | int loY = NavMeshWorldToGridY(flExtentLow[1]); 1876 | int hiX = NavMeshWorldToGridX(flExtentHigh[0]); 1877 | int hiY = NavMeshWorldToGridY(flExtentHigh[1]); 1878 | 1879 | /* 1880 | decl String:path[PLATFORM_MAX_PATH]; 1881 | BuildPath(Path_SM,path,PLATFORM_MAX_PATH, "navtest.txt"); 1882 | new Handle:hFile = OpenFile(path, "a"); 1883 | 1884 | WriteFileLine(hFile, "[%d]", g_hNavMeshAreas.Get(iAreaIndex)); 1885 | WriteFileLine(hFile, "{"); 1886 | WriteFileLine(hFile, "\t---Extent: (%f, %f) - (%f, %f)", flExtentLow[0], flExtentLow[1], flExtentHigh[0], flExtentHigh[1]); 1887 | */ 1888 | 1889 | for (int y = loY; y <= hiY; ++y) 1890 | { 1891 | //WriteFileLine(hFile, "\t--- y = %d", y); 1892 | 1893 | for (int x = loX; x <= hiX; ++x) 1894 | { 1895 | //WriteFileLine(hFile, "\t\t--- x = %d", x); 1896 | 1897 | int iGridIndex = x + y * g_iNavMeshGridSizeX; 1898 | NavMeshGridAddAreaToList(iGridIndex, iAreaIndex); 1899 | 1900 | //WriteFileLine(hFile, "\t\t\t--- %d", iGridIndex); 1901 | } 1902 | } 1903 | 1904 | /* 1905 | WriteFileLine(hFile, "}"); 1906 | CloseHandle(hFile); 1907 | */ 1908 | } 1909 | 1910 | // The following functions are stock functions associated with the navmesh grid. These 1911 | // are safe to use after the grid has been finalized using NavMeshGridFinalize(), and 1912 | // can be included in other stock functions as well. 1913 | 1914 | stock int IntCast(float val) 1915 | { 1916 | if (val < 0.0) return RoundToFloor(val); 1917 | return RoundToCeil(val); 1918 | } 1919 | 1920 | stock int NavMeshWorldToGridX(float flWX) 1921 | { 1922 | int x = IntCast((flWX - g_flNavMeshMinX) / g_flNavMeshGridCellSize); 1923 | 1924 | if (x < 0) x = 0; 1925 | else if (x >= g_iNavMeshGridSizeX) 1926 | { 1927 | // PrintToServer("NavMeshWorldToGridX: clamping x (%d) down to %d", x, g_iNavMeshGridSizeX - 1); 1928 | x = g_iNavMeshGridSizeX - 1; 1929 | } 1930 | 1931 | return x; 1932 | } 1933 | 1934 | stock int NavMeshWorldToGridY(float flWY) 1935 | { 1936 | new y = IntCast((flWY - g_flNavMeshMinY) / g_flNavMeshGridCellSize); 1937 | 1938 | if (y < 0) y = 0; 1939 | else if (y >= g_iNavMeshGridSizeY) 1940 | { 1941 | // PrintToServer("NavMeshWorldToGridY: clamping y (%d) down to %d", y, g_iNavMeshGridSizeY - 1); 1942 | y = g_iNavMeshGridSizeY - 1; 1943 | } 1944 | 1945 | return y; 1946 | } 1947 | 1948 | stock ArrayStack NavMeshGridGetAreas(x, y) 1949 | { 1950 | int iGridIndex = x + y * g_iNavMeshGridSizeX; 1951 | int iListStartIndex = g_hNavMeshGrid.Get(iGridIndex, NavMeshGrid_ListStartIndex); 1952 | int iListEndIndex = g_hNavMeshGrid.Get(iGridIndex, NavMeshGrid_ListEndIndex); 1953 | 1954 | if (iListStartIndex == -1) return null; 1955 | 1956 | ArrayStack hStack = new ArrayStack(); 1957 | 1958 | for (int i = iListStartIndex; i <= iListEndIndex; i++) 1959 | { 1960 | hStack.Push(g_hNavMeshGridLists.Get(i, NavMeshGridList_AreaIndex)); 1961 | } 1962 | 1963 | return hStack; 1964 | } 1965 | 1966 | stock int NavMeshGetNearestArea(float flPos[3], bool bAnyZ=false, float flMaxDist=10000.0, bool bCheckLOS=false, bool bCheckGround=true, int iTeam=-2) 1967 | { 1968 | if (g_hNavMeshGridLists.Length == 0) return -1; 1969 | 1970 | int iClosestAreaIndex = -1; 1971 | float flClosestDistSq = flMaxDist * flMaxDist; 1972 | 1973 | if (!bCheckLOS && !bCheckGround) 1974 | { 1975 | iClosestAreaIndex = NavMeshGetArea(flPos); 1976 | if (iClosestAreaIndex != -1) return iClosestAreaIndex; 1977 | } 1978 | 1979 | float flSource[3]; 1980 | flSource[0] = flPos[0]; 1981 | flSource[1] = flPos[1]; 1982 | 1983 | float flNormal[3]; 1984 | if (!NavMeshGetGroundHeight(flPos, flSource[2], flNormal)) 1985 | { 1986 | if (!bCheckGround) 1987 | { 1988 | flSource[2] = flPos[2]; 1989 | } 1990 | else 1991 | { 1992 | return -1; 1993 | } 1994 | } 1995 | 1996 | flSource[2] += HalfHumanHeight; 1997 | 1998 | static int iSearchMarker = -1; 1999 | if (iSearchMarker == -1) iSearchMarker = GetRandomInt(0, 1024 * 1024); 2000 | 2001 | iSearchMarker++; 2002 | if (iSearchMarker == 0) iSearchMarker++; 2003 | 2004 | int iOriginX = NavMeshWorldToGridX(flPos[0]); 2005 | int iOriginY = NavMeshWorldToGridY(flPos[1]); 2006 | 2007 | int iShiftLimit = RoundToCeil(flMaxDist / g_flNavMeshGridCellSize); 2008 | 2009 | for (int iShift = 0; iShift <= iShiftLimit; ++iShift) 2010 | { 2011 | for (int x = (iOriginX - iShift); x <= (iOriginX + iShift); ++x) 2012 | { 2013 | if (x < 0 || x >= g_iNavMeshGridSizeX) continue; 2014 | 2015 | for (int y = (iOriginY - iShift); y <= (iOriginY + iShift); ++y) 2016 | { 2017 | if (y < 0 || y >= g_iNavMeshGridSizeY) continue; 2018 | 2019 | if (x > (iOriginX - iShift) && 2020 | x < (iOriginX + iShift) && 2021 | y > (iOriginY - iShift) && 2022 | y < (iOriginY + iShift)) 2023 | { 2024 | continue; 2025 | } 2026 | 2027 | ArrayStack hAreas = NavMeshGridGetAreas(x, y); 2028 | if (hAreas != null) 2029 | { 2030 | while (!hAreas.Empty) 2031 | { 2032 | int iAreaIndex = -1; 2033 | PopStackCell(hAreas, iAreaIndex); 2034 | 2035 | int iAreaNearSearchMarker = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_NearSearchMarker); 2036 | if (iAreaNearSearchMarker == iSearchMarker) continue; 2037 | 2038 | if (g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Blocked)) 2039 | { 2040 | continue; 2041 | } 2042 | 2043 | g_hNavMeshAreas.Set(iAreaIndex, iSearchMarker, NavMeshArea_NearSearchMarker); 2044 | 2045 | float flAreaPos[3]; 2046 | NavMeshAreaGetClosestPointOnArea(iAreaIndex, flSource, flAreaPos); 2047 | 2048 | float flDistSq = Pow(GetVectorDistance(flPos, flAreaPos), 2.0); 2049 | 2050 | if (flDistSq >= flClosestDistSq) continue; 2051 | 2052 | if (bCheckLOS) 2053 | { 2054 | float flSafePos[3]; 2055 | float flStartPos[3]; 2056 | float flEndPos[3]; 2057 | flEndPos[0] = flPos[0]; 2058 | flEndPos[1] = flPos[1]; 2059 | flEndPos[2] = flPos[2] + StepHeight; 2060 | 2061 | Handle hTrace = TR_TraceRayFilterEx(flPos, flEndPos, MASK_NPCSOLID_BRUSHONLY, RayType_EndPoint, TraceRayIgnoreCustom); 2062 | float flFraction = TR_GetFraction(hTrace); 2063 | TR_GetEndPosition(flEndPos, hTrace); 2064 | delete hTrace; 2065 | 2066 | if (flFraction == 0.0) 2067 | { 2068 | flSafePos[0] = flEndPos[0]; 2069 | flSafePos[1] = flEndPos[1]; 2070 | flSafePos[2] = flEndPos[2] + 1.0; 2071 | } 2072 | else 2073 | { 2074 | flSafePos[0] = flPos[0]; 2075 | flSafePos[1] = flPos[1]; 2076 | flSafePos[2] = flPos[2]; 2077 | } 2078 | 2079 | float flHeightDelta = FloatAbs(flAreaPos[2] - flSafePos[2]); 2080 | if (flHeightDelta > StepHeight) 2081 | { 2082 | flStartPos[0] = flAreaPos[0]; 2083 | flStartPos[1] = flAreaPos[1]; 2084 | flStartPos[2] = flAreaPos[2] + StepHeight; 2085 | 2086 | flEndPos[0] = flAreaPos[0]; 2087 | flEndPos[1] = flAreaPos[1]; 2088 | flEndPos[2] = flSafePos[2]; 2089 | 2090 | hTrace = TR_TraceRayFilterEx(flStartPos, flEndPos, MASK_NPCSOLID_BRUSHONLY, RayType_EndPoint, TraceRayIgnoreCustom); 2091 | flFraction = TR_GetFraction(hTrace); 2092 | delete hTrace; 2093 | 2094 | if (flFraction != 1.0) 2095 | { 2096 | continue; 2097 | } 2098 | } 2099 | 2100 | flEndPos[0] = flAreaPos[0]; 2101 | flEndPos[1] = flAreaPos[1]; 2102 | flEndPos[2] = flSafePos[2] + StepHeight; 2103 | 2104 | hTrace = TR_TraceRayFilterEx(flSafePos, flEndPos, MASK_NPCSOLID_BRUSHONLY, RayType_EndPoint, TraceRayIgnoreCustom); 2105 | flFraction = TR_GetFraction(hTrace); 2106 | delete hTrace; 2107 | 2108 | if (flFraction != 1.0) 2109 | { 2110 | continue; 2111 | } 2112 | } 2113 | 2114 | flClosestDistSq = flDistSq; 2115 | iClosestAreaIndex = iAreaIndex; 2116 | 2117 | iShiftLimit = iShift + 1; 2118 | } 2119 | 2120 | delete hAreas; 2121 | } 2122 | } 2123 | } 2124 | } 2125 | 2126 | return iClosestAreaIndex; 2127 | } 2128 | 2129 | stock void NavMeshAreaGetClosestPointOnArea(int iAreaIndex, const float flPos[3], float flClose[3]) 2130 | { 2131 | float x; float y; float z; 2132 | 2133 | float flExtentLow[3]; float flExtentHigh[3]; 2134 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2135 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2136 | 2137 | x = fsel(flPos[0] - flExtentLow[0], flPos[0], flExtentLow[0]); 2138 | x = fsel(x - flExtentHigh[0], flExtentHigh[0], x); 2139 | 2140 | y = fsel(flPos[1] - flExtentLow[1], flPos[1], flExtentLow[1]); 2141 | y = fsel(y - flExtentHigh[1], flExtentHigh[1], y); 2142 | 2143 | z = NavMeshAreaGetZFromXAndY(iAreaIndex, x, y); 2144 | 2145 | flClose[0] = x; 2146 | flClose[1] = y; 2147 | flClose[2] = z; 2148 | } 2149 | 2150 | stock float fsel(float a, float b, float c) 2151 | { 2152 | return a >= 0.0 ? b : c; 2153 | } 2154 | 2155 | stock int NavMeshAreaGetID(int iAreaIndex) 2156 | { 2157 | if (!g_bNavMeshBuilt) return -1; 2158 | 2159 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_ID); 2160 | } 2161 | 2162 | stock int NavMeshFindAreaByID(int iAreaID) 2163 | { 2164 | return g_hNavMeshAreas.FindValue(iAreaID); 2165 | } 2166 | 2167 | stock int NavMeshAreaGetFlags(int iAreaIndex) 2168 | { 2169 | if (!g_bNavMeshBuilt) return 0; 2170 | 2171 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Flags); 2172 | } 2173 | 2174 | stock void NavMeshAreaGetPlace(int iAreaIndex, char[] buffer, int maxlen) 2175 | { 2176 | int placeIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_PlaceID); 2177 | 2178 | if (placeIndex < 0 || placeIndex >= g_hNavMeshPlaces.Length) 2179 | { 2180 | strcopy(buffer, maxlen, ""); 2181 | return; 2182 | } 2183 | 2184 | g_hNavMeshPlaces.GetString(placeIndex, buffer, maxlen); 2185 | } 2186 | 2187 | stock bool NavMeshAreaGetCenter(int iAreaIndex, float flBuffer[3]) 2188 | { 2189 | if (!g_bNavMeshBuilt) return false; 2190 | 2191 | flBuffer[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CenterX)); 2192 | flBuffer[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CenterY)); 2193 | flBuffer[2] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CenterZ)); 2194 | return true; 2195 | } 2196 | 2197 | stock void NavMeshAreaGetCorner(int iAreaIndex, NavCornerType corner, float buffer[3]) 2198 | { 2199 | switch (corner) 2200 | { 2201 | case NAV_CORNER_NORTH_WEST: 2202 | { 2203 | NavMeshAreaGetExtentLow( iAreaIndex, buffer ); 2204 | } 2205 | case NAV_CORNER_NORTH_EAST: 2206 | { 2207 | buffer[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X2)); 2208 | buffer[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y1)); 2209 | buffer[2] = NavMeshAreaGetNECornerZ(iAreaIndex); 2210 | } 2211 | case NAV_CORNER_SOUTH_WEST: 2212 | { 2213 | buffer[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X1)); 2214 | buffer[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y2)); 2215 | buffer[2] = NavMeshAreaGetSWCornerZ(iAreaIndex); 2216 | } 2217 | case NAV_CORNER_SOUTH_EAST: 2218 | { 2219 | NavMeshAreaGetExtentHigh( iAreaIndex, buffer ); 2220 | } 2221 | } 2222 | } 2223 | 2224 | stock void NavMeshAreaGetRandomPoint(int iAreaIndex, float buffer[3]) 2225 | { 2226 | float extentLow[3]; 2227 | float extentHigh[3]; 2228 | NavMeshAreaGetExtentLow(iAreaIndex, extentLow); 2229 | NavMeshAreaGetExtentHigh(iAreaIndex, extentHigh); 2230 | 2231 | buffer[0] = GetRandomFloat(extentLow[0], extentHigh[0]); 2232 | buffer[1] = GetRandomFloat(extentLow[1], extentHigh[1]); 2233 | buffer[2] = NavMeshAreaGetZ(iAreaIndex, buffer); 2234 | } 2235 | 2236 | stock ArrayStack NavMeshAreaGetAdjacentList(int iAreaIndex, int iNavDirection) 2237 | { 2238 | if (!g_bNavMeshBuilt) return null; 2239 | 2240 | int iConnectionsStartIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_ConnectionsStartIndex); 2241 | if (iConnectionsStartIndex == -1) return null; 2242 | 2243 | int iConnectionsEndIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_ConnectionsEndIndex); 2244 | 2245 | ArrayStack hStack = new ArrayStack(); 2246 | 2247 | for (int i = iConnectionsStartIndex; i <= iConnectionsEndIndex; i++) 2248 | { 2249 | if (g_hNavMeshAreaConnections.Get(i, NavMeshConnection_Direction) == iNavDirection) 2250 | { 2251 | hStack.Push(g_hNavMeshAreaConnections.Get(i, NavMeshConnection_AreaIndex)); 2252 | } 2253 | } 2254 | 2255 | return hStack; 2256 | } 2257 | 2258 | stock ArrayStack NavMeshAreaGetLadderList(int iAreaIndex, int iLadderDir) 2259 | { 2260 | if (!g_bNavMeshBuilt) return null; 2261 | 2262 | int iLadderConnectionsStartIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_LadderConnectionsStartIndex); 2263 | if (iLadderConnectionsStartIndex == -1) return null; 2264 | 2265 | int iLadderConnectionsEndIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_LadderConnectionsEndIndex); 2266 | 2267 | ArrayStack hStack = new ArrayStack(); 2268 | 2269 | for (int i = iLadderConnectionsStartIndex; i <= iLadderConnectionsEndIndex; i++) 2270 | { 2271 | if (g_hNavMeshAreaLadderConnections.Get(i, NavMeshLadderConnection_Direction) == iLadderDir) 2272 | { 2273 | hStack.Push(g_hNavMeshAreaLadderConnections.Get(i, NavMeshLadderConnection_LadderIndex)); 2274 | } 2275 | } 2276 | 2277 | return hStack; 2278 | } 2279 | 2280 | stock ArrayStack NavMeshAreaGetHidingSpots(int iAreaIndex) 2281 | { 2282 | if (!g_bNavMeshBuilt) return null; 2283 | 2284 | int startIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_HidingSpotsStartIndex); 2285 | if (startIndex == -1) return null; 2286 | 2287 | int endIndex = g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_HidingSpotsEndIndex); 2288 | 2289 | ArrayStack hStack = new ArrayStack(); 2290 | for (int i = startIndex; i <= endIndex; i++) hStack.Push(i); 2291 | 2292 | return hStack; 2293 | } 2294 | 2295 | stock int NavMeshAreaGetTotalCost(int iAreaIndex) 2296 | { 2297 | if (!g_bNavMeshBuilt) return 0; 2298 | 2299 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_TotalCost); 2300 | } 2301 | 2302 | stock int NavMeshAreaGetCostSoFar(int iAreaIndex) 2303 | { 2304 | if (!g_bNavMeshBuilt) return 0; 2305 | 2306 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CostSoFar); 2307 | } 2308 | 2309 | stock int NavMeshAreaGetParent(int iAreaIndex) 2310 | { 2311 | if (!g_bNavMeshBuilt) return -1; 2312 | 2313 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Parent); 2314 | } 2315 | 2316 | stock int NavMeshAreaGetParentHow(int iAreaIndex) 2317 | { 2318 | if (!g_bNavMeshBuilt) return NUM_TRAVERSE_TYPES; 2319 | 2320 | return g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_ParentHow); 2321 | } 2322 | 2323 | stock void NavMeshAreaSetParent(int iAreaIndex, int iParentAreaIndex) 2324 | { 2325 | if (!g_bNavMeshBuilt) return; 2326 | 2327 | g_hNavMeshAreas.Set(iAreaIndex, iParentAreaIndex, NavMeshArea_Parent); 2328 | } 2329 | 2330 | stock void NavMeshAreaSetParentHow(int iAreaIndex, int iParentHow) 2331 | { 2332 | if (!g_bNavMeshBuilt) return; 2333 | 2334 | g_hNavMeshAreas.Set(iAreaIndex, iParentHow, NavMeshArea_ParentHow); 2335 | } 2336 | 2337 | stock bool NavMeshAreaGetExtentLow(int iAreaIndex, float flBuffer[3]) 2338 | { 2339 | if (!g_bNavMeshBuilt) return false; 2340 | 2341 | flBuffer[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X1)); 2342 | flBuffer[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y1)); 2343 | flBuffer[2] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Z1)); 2344 | return true; 2345 | } 2346 | 2347 | stock bool NavMeshAreaGetExtentHigh(int iAreaIndex, float flBuffer[3]) 2348 | { 2349 | if (!g_bNavMeshBuilt) return false; 2350 | 2351 | flBuffer[0] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_X2)); 2352 | flBuffer[1] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Y2)); 2353 | flBuffer[2] = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_Z2)); 2354 | return true; 2355 | } 2356 | 2357 | stock bool NavMeshAreaIsOverlappingPoint(int iAreaIndex, const float flPos[3], float flTolerance) 2358 | { 2359 | if (!g_bNavMeshBuilt) return false; 2360 | 2361 | float flExtentLow[3]; float flExtentHigh[3]; 2362 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2363 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2364 | 2365 | if (flPos[0] + flTolerance >= flExtentLow[0] && 2366 | flPos[0] - flTolerance <= flExtentHigh[0] && 2367 | flPos[1] + flTolerance >= flExtentLow[1] && 2368 | flPos[1] - flTolerance <= flExtentHigh[1]) 2369 | { 2370 | return true; 2371 | } 2372 | 2373 | return false; 2374 | } 2375 | 2376 | stock bool NavMeshAreaIsOverlappingArea(int iAreaIndex, int iTargetAreaIndex) 2377 | { 2378 | if (!g_bNavMeshBuilt) return false; 2379 | 2380 | float flExtentLow[3]; float flExtentHigh[3]; 2381 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2382 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2383 | 2384 | float flTargetExtentLow[3]; float flTargetExtentHigh[3]; 2385 | NavMeshAreaGetExtentLow(iTargetAreaIndex, flTargetExtentLow); 2386 | NavMeshAreaGetExtentHigh(iTargetAreaIndex, flTargetExtentHigh); 2387 | 2388 | if (flTargetExtentLow[0] < flExtentHigh[0] && 2389 | flTargetExtentHigh[0] > flExtentLow[0] && 2390 | flTargetExtentLow[1] < flExtentHigh[1] && 2391 | flTargetExtentHigh[1] > flExtentLow[1]) 2392 | { 2393 | return true; 2394 | } 2395 | 2396 | return false; 2397 | } 2398 | 2399 | stock float NavMeshAreaGetNECornerZ(int iAreaIndex) 2400 | { 2401 | if (!g_bNavMeshBuilt) return 0.0; 2402 | return view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_NECornerZ)); 2403 | } 2404 | 2405 | stock float NavMeshAreaGetSWCornerZ(int iAreaIndex) 2406 | { 2407 | if (!g_bNavMeshBuilt) return 0.0; 2408 | return view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_SWCornerZ)); 2409 | } 2410 | 2411 | stock float NavMeshAreaGetZ(int iAreaIndex, const float flPos[3]) 2412 | { 2413 | if (!g_bNavMeshBuilt) return 0.0; 2414 | 2415 | float flExtentLow[3]; float flExtentHigh[3]; 2416 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2417 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2418 | 2419 | float dx = flExtentHigh[0] - flExtentLow[0]; 2420 | float dy = flExtentHigh[1] - flExtentLow[1]; 2421 | 2422 | float flNEZ = NavMeshAreaGetNECornerZ(iAreaIndex); 2423 | 2424 | if (dx == 0.0 || dy == 0.0) 2425 | { 2426 | return flNEZ; 2427 | } 2428 | 2429 | float u = (flPos[0] - flExtentLow[0]) / dx; 2430 | float v = (flPos[1] - flExtentLow[1]) / dy; 2431 | 2432 | u = fsel(u, u, 0.0); 2433 | u = fsel(u - 1.0, 1.0, u); 2434 | 2435 | v = fsel(v, v, 0.0); 2436 | v = fsel(v - 1.0, 1.0, v); 2437 | 2438 | float flSWZ = NavMeshAreaGetSWCornerZ(iAreaIndex); 2439 | 2440 | float flNorthZ = flExtentLow[2] + u * (flNEZ - flExtentLow[2]); 2441 | float flSouthZ = flSWZ + u * (flExtentHigh[2] - flSWZ); 2442 | 2443 | return flNorthZ + v * (flSouthZ - flNorthZ); 2444 | } 2445 | 2446 | stock float NavMeshAreaGetZFromXAndY(int iAreaIndex, float x, float y) 2447 | { 2448 | if (!g_bNavMeshBuilt) return 0.0; 2449 | 2450 | float flInvDxCorners = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_InvDxCorners)); 2451 | float flInvDyCorners = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_InvDyCorners)); 2452 | 2453 | float flNECornerZ = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_NECornerZ)); 2454 | 2455 | if (flInvDxCorners == 0.0 || flInvDyCorners == 0.0) 2456 | { 2457 | return flNECornerZ; 2458 | } 2459 | 2460 | float flExtentLow[3]; float flExtentHigh[3]; 2461 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2462 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2463 | 2464 | float u = (x - flExtentLow[0]) * flInvDxCorners; 2465 | float v = (y - flExtentLow[1]) * flInvDyCorners; 2466 | 2467 | u = FloatClamp(u, 0.0, 1.0); 2468 | v = FloatClamp(v, 0.0, 1.0); 2469 | 2470 | float flSWCornerZ = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_SWCornerZ)); 2471 | 2472 | float flNorthZ = flExtentLow[2] + u * (flNECornerZ - flExtentLow[2]); 2473 | float flSouthZ = flSWCornerZ + u * (flExtentHigh[2] - flSWCornerZ); 2474 | 2475 | return flNorthZ + v * (flSouthZ - flNorthZ); 2476 | } 2477 | 2478 | stock bool NavMeshAreaContains(int iAreaIndex, const float flPos[3]) 2479 | { 2480 | if (!g_bNavMeshBuilt) return false; 2481 | 2482 | if (!NavMeshAreaIsOverlappingPoint(iAreaIndex, flPos, 0.0)) return false; 2483 | 2484 | float flMyZ = NavMeshAreaGetZ(iAreaIndex, flPos); 2485 | 2486 | if ((flMyZ - StepHeight) > flPos[2]) return false; 2487 | 2488 | for (new i = 0, iSize = g_hNavMeshAreas.Length; i < iSize; i++) 2489 | { 2490 | if (i == iAreaIndex) continue; 2491 | 2492 | if (!NavMeshAreaIsOverlappingArea(iAreaIndex, i)) continue; 2493 | 2494 | float flTheirZ = NavMeshAreaGetZ(i, flPos); 2495 | if ((flTheirZ - StepHeight) > flPos[2]) continue; 2496 | 2497 | if (flTheirZ > flMyZ) 2498 | { 2499 | return false; 2500 | } 2501 | } 2502 | 2503 | return true; 2504 | } 2505 | 2506 | stock bool NavMeshAreaComputePortal(int iAreaIndex, int iAreaToIndex, int iNavDirection, float flCenter[3], float &flHalfWidth) 2507 | { 2508 | if (!g_bNavMeshBuilt) return false; 2509 | 2510 | float flAreaExtentLow[3]; float flAreaExtentHigh[3]; 2511 | NavMeshAreaGetExtentLow(iAreaIndex, flAreaExtentLow); 2512 | NavMeshAreaGetExtentHigh(iAreaIndex, flAreaExtentHigh); 2513 | 2514 | float flAreaToExtentLow[3]; float flAreaToExtentHigh[3]; 2515 | NavMeshAreaGetExtentLow(iAreaToIndex, flAreaToExtentLow); 2516 | NavMeshAreaGetExtentHigh(iAreaToIndex, flAreaToExtentHigh); 2517 | 2518 | if (iNavDirection == NAV_DIR_NORTH || iNavDirection == NAV_DIR_SOUTH) 2519 | { 2520 | if (iNavDirection == NAV_DIR_NORTH) 2521 | { 2522 | flCenter[1] = flAreaExtentLow[1]; 2523 | } 2524 | else 2525 | { 2526 | flCenter[1] = flAreaExtentHigh[1]; 2527 | } 2528 | 2529 | float flLeft = flAreaExtentLow[0] > flAreaToExtentLow[0] ? flAreaExtentLow[0] : flAreaToExtentLow[0]; 2530 | float flRight = flAreaExtentHigh[0] < flAreaToExtentHigh[0] ? flAreaExtentHigh[0] : flAreaToExtentHigh[0]; 2531 | 2532 | if (flLeft < flAreaExtentLow[0]) flLeft = flAreaExtentLow[0]; 2533 | else if (flLeft > flAreaExtentHigh[0]) flLeft = flAreaExtentHigh[0]; 2534 | 2535 | if (flRight < flAreaExtentLow[0]) flRight = flAreaExtentLow[0]; 2536 | else if (flRight > flAreaExtentHigh[0]) flRight = flAreaExtentHigh[0]; 2537 | 2538 | flCenter[0] = (flLeft + flRight) / 2.0; 2539 | flHalfWidth = (flRight - flLeft) / 2.0; 2540 | } 2541 | else 2542 | { 2543 | if (iNavDirection == NAV_DIR_WEST) 2544 | { 2545 | flCenter[0] = flAreaExtentLow[0]; 2546 | } 2547 | else 2548 | { 2549 | flCenter[0] = flAreaExtentHigh[0]; 2550 | } 2551 | 2552 | float flTop = flAreaExtentLow[1] > flAreaToExtentLow[1] ? flAreaExtentLow[1] : flAreaToExtentLow[1]; 2553 | float flBottom = flAreaExtentHigh[1] < flAreaToExtentHigh[1] ? flAreaExtentHigh[1] : flAreaToExtentHigh[1]; 2554 | 2555 | if (flTop < flAreaExtentLow[1]) flTop = flAreaExtentLow[1]; 2556 | else if (flTop > flAreaExtentHigh[1]) flTop = flAreaExtentHigh[1]; 2557 | 2558 | if (flBottom < flAreaExtentLow[1]) flBottom = flAreaExtentLow[1]; 2559 | else if (flBottom > flAreaExtentHigh[1]) flBottom = flAreaExtentHigh[1]; 2560 | 2561 | flCenter[1] = (flTop + flBottom) / 2.0; 2562 | flHalfWidth = (flBottom - flTop) / 2.0; 2563 | } 2564 | 2565 | flCenter[2] = NavMeshAreaGetZFromXAndY(iAreaIndex, flCenter[0], flCenter[1]); 2566 | 2567 | return true; 2568 | } 2569 | 2570 | stock bool NavMeshAreaIsConnected(int iAreaIndex, int iTargetAreaIndex, int iNavDirection) 2571 | { 2572 | if (iAreaIndex == iTargetAreaIndex) return true; 2573 | 2574 | if (iNavDirection == NAV_DIR_COUNT) 2575 | { 2576 | for (int dir = 0; dir < NAV_DIR_COUNT; dir++) 2577 | { 2578 | if (NavMeshAreaIsConnected(iAreaIndex, iTargetAreaIndex, dir)) 2579 | { 2580 | return true; 2581 | } 2582 | } 2583 | 2584 | // TODO: Check ladder connections. 2585 | } 2586 | else 2587 | { 2588 | ArrayStack areas = NavMeshAreaGetAdjacentList(iAreaIndex, iNavDirection); 2589 | if (areas != null) 2590 | { 2591 | if (!areas.Empty) 2592 | { 2593 | while (!areas.Empty) 2594 | { 2595 | int tempAreaIndex = -1; 2596 | PopStackCell(areas, tempAreaIndex); 2597 | 2598 | if (tempAreaIndex == iTargetAreaIndex) 2599 | { 2600 | delete areas; 2601 | return true; 2602 | } 2603 | } 2604 | } 2605 | 2606 | delete areas; 2607 | } 2608 | } 2609 | 2610 | return false; 2611 | } 2612 | 2613 | stock float FloatMin(float a, float b) 2614 | { 2615 | if (a < b) return a; 2616 | return b; 2617 | } 2618 | 2619 | stock float FloatMax(float a, float b) 2620 | { 2621 | if (a > b) return a; 2622 | return b; 2623 | } 2624 | 2625 | stock bool NavMeshAreaComputeClosestPointInPortal(int iAreaIndex, int iAreaToIndex, int iNavDirection, const float flFromPos[3], float flClosestPos[3]) 2626 | { 2627 | if (!g_bNavMeshBuilt) return false; 2628 | 2629 | static float flMargin = 25.0; // GenerationStepSize = 25.0; 2630 | 2631 | float flAreaExtentLow[3]; float flAreaExtentHigh[3]; 2632 | NavMeshAreaGetExtentLow(iAreaIndex, flAreaExtentLow); 2633 | NavMeshAreaGetExtentHigh(iAreaIndex, flAreaExtentHigh); 2634 | 2635 | float flAreaToExtentLow[3]; float flAreaToExtentHigh[3]; 2636 | NavMeshAreaGetExtentLow(iAreaToIndex, flAreaToExtentLow); 2637 | NavMeshAreaGetExtentHigh(iAreaToIndex, flAreaToExtentHigh); 2638 | 2639 | if (iNavDirection == NAV_DIR_NORTH || iNavDirection == NAV_DIR_SOUTH) 2640 | { 2641 | if (iNavDirection == NAV_DIR_NORTH) 2642 | { 2643 | flClosestPos[1] = flAreaExtentLow[1]; 2644 | } 2645 | else 2646 | { 2647 | flClosestPos[1] = flAreaExtentHigh[1]; 2648 | } 2649 | 2650 | float flLeft = FloatMax(flAreaExtentLow[0], flAreaToExtentLow[0]); 2651 | float flRight = FloatMin(flAreaExtentHigh[0], flAreaToExtentHigh[0]); 2652 | 2653 | float flLeftMargin = NavMeshAreaIsEdge(iAreaToIndex, NAV_DIR_WEST) ? (flLeft + flMargin) : flLeft; 2654 | float flRightMargin = NavMeshAreaIsEdge(iAreaToIndex, NAV_DIR_EAST) ? (flRight - flMargin) : flRight; 2655 | 2656 | if (flLeftMargin > flRightMargin) 2657 | { 2658 | float flMid = (flLeft + flRight) / 2.0; 2659 | flLeftMargin = flMid; 2660 | flRightMargin = flMid; 2661 | } 2662 | 2663 | if (flFromPos[0] < flLeftMargin) 2664 | { 2665 | flClosestPos[0] = flLeftMargin; 2666 | } 2667 | else if (flFromPos[0] > flRightMargin) 2668 | { 2669 | flClosestPos[0] = flRightMargin; 2670 | } 2671 | else 2672 | { 2673 | flClosestPos[0] = flFromPos[0]; 2674 | } 2675 | } 2676 | else 2677 | { 2678 | if (iNavDirection == NAV_DIR_WEST) 2679 | { 2680 | flClosestPos[0] = flAreaExtentLow[0]; 2681 | } 2682 | else 2683 | { 2684 | flClosestPos[0] = flAreaExtentHigh[0]; 2685 | } 2686 | 2687 | float flTop = FloatMax(flAreaExtentLow[1], flAreaToExtentLow[1]); 2688 | float flBottom = FloatMin(flAreaExtentHigh[1], flAreaToExtentHigh[1]); 2689 | 2690 | float flTopMargin = NavMeshAreaIsEdge(iAreaToIndex, NAV_DIR_NORTH) ? (flTop + flMargin) : flTop; 2691 | float flBottomMargin = NavMeshAreaIsEdge(iAreaToIndex, NAV_DIR_SOUTH) ? (flBottom - flMargin) : flBottom; 2692 | 2693 | if (flTopMargin > flBottomMargin) 2694 | { 2695 | float flMid = (flTop + flBottom) / 2.0; 2696 | flTopMargin = flMid; 2697 | flBottomMargin = flMid; 2698 | } 2699 | 2700 | if (flFromPos[1] < flTopMargin) 2701 | { 2702 | flClosestPos[1] = flTopMargin; 2703 | } 2704 | else if (flFromPos[1] > flBottomMargin) 2705 | { 2706 | flClosestPos[1] = flBottomMargin; 2707 | } 2708 | else 2709 | { 2710 | flClosestPos[1] = flFromPos[1]; 2711 | } 2712 | } 2713 | 2714 | flClosestPos[2] = NavMeshAreaGetZFromXAndY(iAreaIndex, flClosestPos[0], flClosestPos[1]); 2715 | 2716 | return true; 2717 | } 2718 | 2719 | stock int NavMeshAreaComputeDirection(int iAreaIndex, const float flPos[3]) 2720 | { 2721 | if (!g_bNavMeshBuilt) return NAV_DIR_COUNT; 2722 | 2723 | float flExtentLow[3]; float flExtentHigh[3]; 2724 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2725 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2726 | 2727 | if (flPos[0] >= flExtentLow[0] && flPos[0] <= flExtentHigh[0]) 2728 | { 2729 | if (flPos[1] < flExtentLow[1]) 2730 | { 2731 | return NAV_DIR_NORTH; 2732 | } 2733 | else if (flPos[1] > flExtentHigh[1]) 2734 | { 2735 | return NAV_DIR_SOUTH; 2736 | } 2737 | } 2738 | else if (flPos[1] >= flExtentLow[1] && flPos[1] <= flExtentHigh[1]) 2739 | { 2740 | if (flPos[0] < flExtentLow[0]) 2741 | { 2742 | return NAV_DIR_WEST; 2743 | } 2744 | else if (flPos[0] > flExtentHigh[0]) 2745 | { 2746 | return NAV_DIR_EAST; 2747 | } 2748 | } 2749 | 2750 | float flCenter[3]; 2751 | NavMeshAreaGetCenter(iAreaIndex, flCenter); 2752 | 2753 | float flTo[3]; 2754 | SubtractVectors(flPos, flCenter, flTo); 2755 | 2756 | if (FloatAbs(flTo[0]) > FloatAbs(flTo[1])) 2757 | { 2758 | if (flTo[0] > 0.0) return NAV_DIR_EAST; 2759 | 2760 | return NAV_DIR_WEST; 2761 | } 2762 | else 2763 | { 2764 | if (flTo[1] > 0.0) return NAV_DIR_SOUTH; 2765 | 2766 | return NAV_DIR_NORTH; 2767 | } 2768 | } 2769 | 2770 | stock float NavMeshAreaGetLightIntensity(int iAreaIndex, const float flPos[3]) 2771 | { 2772 | if (!g_bNavMeshBuilt) return 0.0; 2773 | 2774 | float flExtentLow[3]; float flExtentHigh[3]; 2775 | NavMeshAreaGetExtentLow(iAreaIndex, flExtentLow); 2776 | NavMeshAreaGetExtentHigh(iAreaIndex, flExtentHigh); 2777 | 2778 | float flTestPos[3]; 2779 | flTestPos[0] = FloatClamp(flPos[0], flExtentLow[0], flExtentHigh[0]); 2780 | flTestPos[1] = FloatClamp(flPos[1], flExtentLow[1], flExtentHigh[1]); 2781 | flTestPos[2] = flPos[2]; 2782 | 2783 | float dX = (flTestPos[0] - flExtentLow[0]) / (flExtentHigh[0] - flExtentLow[0]); 2784 | float dY = (flTestPos[1] - flExtentLow[1]) / (flExtentHigh[1] - flExtentLow[1]); 2785 | 2786 | float flCornerLightIntensityNW = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CornerLightIntensityNW)); 2787 | float flCornerLightIntensityNE = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CornerLightIntensityNE)); 2788 | float flCornerLightIntensitySW = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CornerLightIntensitySW)); 2789 | float flCornerLightIntensitySE = view_as(g_hNavMeshAreas.Get(iAreaIndex, NavMeshArea_CornerLightIntensitySE)); 2790 | 2791 | float flNorthLight = flCornerLightIntensityNW * (1.0 - dX) + flCornerLightIntensityNE * dX; 2792 | float flSouthLight = flCornerLightIntensitySW * (1.0 - dX) + flCornerLightIntensitySE * dX; 2793 | 2794 | return (flNorthLight * (1.0 - dY) + flSouthLight * dY); 2795 | } 2796 | 2797 | 2798 | stock float FloatClamp(float a, float min, float max) 2799 | { 2800 | if (a < min) a = min; 2801 | if (a > max) a = max; 2802 | return a; 2803 | } 2804 | 2805 | stock bool NavMeshAreaIsEdge(int iAreaIndex, int iNavDirection) 2806 | { 2807 | ArrayStack hConnections = NavMeshAreaGetAdjacentList(iAreaIndex, iNavDirection); 2808 | if (hConnections == null || hConnections.Empty) 2809 | { 2810 | if (hConnections != null) delete hConnections; 2811 | return true; 2812 | } 2813 | 2814 | delete hConnections; 2815 | return false; 2816 | } 2817 | 2818 | stock float NavMeshLadderGetWidth(int iLadderIndex) 2819 | { 2820 | if (!g_bNavMeshBuilt) return 0.0; 2821 | 2822 | return view_as(g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_Width)); 2823 | } 2824 | 2825 | stock float NavMeshLadderGetLength(int iLadderIndex) 2826 | { 2827 | if (!g_bNavMeshBuilt) return 0.0; 2828 | 2829 | return view_as(g_hNavMeshLadders.Get(iLadderIndex, NavMeshLadder_Length)); 2830 | } 2831 | 2832 | stock int NavMeshGetArea(const float flPos[3], float flBeneathLimit=120.0) 2833 | { 2834 | if (!g_bNavMeshBuilt) return -1; 2835 | 2836 | int x = NavMeshWorldToGridX(flPos[0]); 2837 | int y = NavMeshWorldToGridY(flPos[1]); 2838 | 2839 | ArrayStack hAreas = NavMeshGridGetAreas(x, y); 2840 | 2841 | int iUseAreaIndex = -1; 2842 | float flUseZ = -99999999.9; 2843 | float flTestPos[3]; 2844 | flTestPos[0] = flPos[0]; 2845 | flTestPos[1] = flPos[1]; 2846 | flTestPos[2] = flPos[2] + 5.0; 2847 | 2848 | if (hAreas != null) 2849 | { 2850 | while (!hAreas.Empty) 2851 | { 2852 | int iAreaIndex = -1; 2853 | PopStackCell(hAreas, iAreaIndex); 2854 | 2855 | if (NavMeshAreaIsOverlappingPoint(iAreaIndex, flTestPos, 0.0)) 2856 | { 2857 | float z = NavMeshAreaGetZ(iAreaIndex, flTestPos); 2858 | 2859 | if (z > flTestPos[2]) continue; 2860 | 2861 | if (z < flPos[2] - flBeneathLimit) continue; 2862 | 2863 | if (z > flUseZ) 2864 | { 2865 | iUseAreaIndex = iAreaIndex; 2866 | flUseZ = z; 2867 | } 2868 | } 2869 | } 2870 | 2871 | delete hAreas; 2872 | } 2873 | 2874 | return iUseAreaIndex; 2875 | } 2876 | 2877 | stock bool NavMeshGetGroundHeight(const float flPos[3], float &flHeight, float flNormal[3]) 2878 | { 2879 | static float flMaxOffset = 100.0; 2880 | 2881 | float flTo[3]; float flFrom[3]; 2882 | flTo[0] = flPos[0]; 2883 | flTo[1] = flPos[1]; 2884 | flTo[2] = flPos[2] - 10000.0; 2885 | 2886 | flFrom[0] = flPos[0]; 2887 | flFrom[1] = flPos[1]; 2888 | flFrom[2] = flPos[2] + HalfHumanHeight + 0.001; 2889 | 2890 | while (flTo[2] - flPos[2] < flMaxOffset) 2891 | { 2892 | Handle hTrace = TR_TraceRayFilterEx(flFrom, flTo, MASK_NPCSOLID_BRUSHONLY, RayType_EndPoint, TraceRayIgnoreCustom); 2893 | float flFraction = TR_GetFraction(hTrace); 2894 | float flPlaneNormal[3]; 2895 | float flEndPos[3]; 2896 | TR_GetEndPosition(flEndPos, hTrace); 2897 | TR_GetPlaneNormal(hTrace, flPlaneNormal); 2898 | delete hTrace; 2899 | 2900 | if (flFraction == 1.0 || ((flFrom[2] - flEndPos[2]) >= HalfHumanHeight)) 2901 | { 2902 | flHeight = flEndPos[2]; 2903 | flNormal[0] = flPlaneNormal[0]; 2904 | flNormal[1] = flPlaneNormal[1]; 2905 | flNormal[2] = flPlaneNormal[2]; 2906 | return true; 2907 | } 2908 | 2909 | flTo[2] = (flFraction == 0.0) ? flFrom[2] : flEndPos[2]; 2910 | flFrom[2] = flTo[2] + HalfHumanHeight + 0.001; 2911 | } 2912 | 2913 | flHeight = 0.0; 2914 | flNormal[0] = 0.0; 2915 | flNormal[1] = 0.0; 2916 | flNormal[2] = 1.0; 2917 | 2918 | return false; 2919 | } 2920 | 2921 | stock int NavSpotEncounterGetFrom(int spotEncounterIndex) 2922 | { 2923 | return g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_FromAreaIndex); 2924 | } 2925 | 2926 | stock int NavSpotEncounterGetFromDirection(int spotEncounterIndex) 2927 | { 2928 | return g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_FromDirection); 2929 | } 2930 | 2931 | stock int NavSpotEncounterGetTo(int spotEncounterIndex) 2932 | { 2933 | return g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_ToAreaIndex); 2934 | } 2935 | 2936 | stock int NavSpotEncounterGetToDirection(int spotEncounterIndex) 2937 | { 2938 | return g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_ToDirection); 2939 | } 2940 | 2941 | stock ArrayStack NavSpotEncounterGetSpots(int spotEncounterIndex) 2942 | { 2943 | int startIndex = g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_SpotsStartIndex); 2944 | if (startIndex == -1) return null; 2945 | 2946 | ArrayStack buffer = new ArrayStack(); 2947 | int endIndex = g_hNavMeshAreaEncounterPaths.Get(spotEncounterIndex, NavMeshEncounterPath_SpotsEndIndex); 2948 | for (int i = startIndex; i <= endIndex; i++) 2949 | { 2950 | buffer.Push(i); 2951 | } 2952 | 2953 | return buffer; 2954 | } 2955 | 2956 | stock int NavSpotOrderGetHidingSpot(int spotOrderIndex) 2957 | { 2958 | return g_hNavMeshAreaEncounterSpots.Get(spotOrderIndex, NavMeshEncounterSpot_HidingSpotIndex); 2959 | } 2960 | 2961 | stock int NavSpotOrderGetParametricDistance(int spotOrderIndex) 2962 | { 2963 | return g_hNavMeshAreaEncounterSpots.Get(spotOrderIndex, NavMeshEncounterSpot_ParametricDistance); 2964 | } 2965 | 2966 | public bool TraceRayIgnoreCustom(int entity,int mask, any data) 2967 | { 2968 | if (entity > 0 && entity <= MaxClients) return false; 2969 | 2970 | if (IsValidEdict(entity)) 2971 | { 2972 | char sClass[64]; 2973 | GetEntityNetClass(entity, sClass, sizeof(sClass)); 2974 | if (StrEqual(sClass, "CFuncRespawnRoomVisualizer")) return false; 2975 | else if (StrEqual(sClass, "CBaseDoor")) return false; 2976 | else if (StrEqual(sClass, "CTFBaseBoss")) return false; 2977 | } 2978 | return true; 2979 | } 2980 | // ================================== 2981 | // API 2982 | // ================================== 2983 | 2984 | public int Native_NavMeshExists(Handle plugin, int numParams) 2985 | { 2986 | return g_bNavMeshBuilt; 2987 | } 2988 | 2989 | public int Native_NavMeshGetMagicNumber(Handle plugin, int numParams) 2990 | { 2991 | if (!g_bNavMeshBuilt) 2992 | { 2993 | LogError("Could not retrieve magic number because the nav mesh doesn't exist!"); 2994 | return -1; 2995 | } 2996 | 2997 | return g_iNavMeshMagicNumber; 2998 | } 2999 | 3000 | public int Native_NavMeshGetVersion(Handle plugin, int numParams) 3001 | { 3002 | if (!g_bNavMeshBuilt) 3003 | { 3004 | LogError("Could not retrieve version because the nav mesh doesn't exist!"); 3005 | return -1; 3006 | } 3007 | 3008 | return g_iNavMeshVersion; 3009 | } 3010 | 3011 | public int Native_NavMeshGetSubVersion(Handle plugin, int numParams) 3012 | { 3013 | if (!g_bNavMeshBuilt) 3014 | { 3015 | LogError("Could not retrieve subversion because the nav mesh doesn't exist!"); 3016 | return -1; 3017 | } 3018 | 3019 | return g_iNavMeshSubVersion; 3020 | } 3021 | 3022 | public int Native_NavMeshGetSaveBSPSize(Handle plugin, int numParams) 3023 | { 3024 | if (!g_bNavMeshBuilt) 3025 | { 3026 | LogError("Could not retrieve save BSP size because the nav mesh doesn't exist!"); 3027 | return -1; 3028 | } 3029 | 3030 | return g_iNavMeshSaveBSPSize; 3031 | } 3032 | 3033 | public int Native_NavMeshIsAnalyzed(Handle plugin, int numParams) 3034 | { 3035 | if (!g_bNavMeshBuilt) 3036 | { 3037 | LogError("Could not retrieve analysis state because the nav mesh doesn't exist!"); 3038 | return 0; 3039 | } 3040 | 3041 | return g_bNavMeshAnalyzed; 3042 | } 3043 | 3044 | public int Native_NavMeshGetPlaces(Handle plugin, int numParams) 3045 | { 3046 | if (!g_bNavMeshBuilt) 3047 | { 3048 | LogError("Could not retrieve place list because the nav mesh doesn't exist!"); 3049 | return 0; 3050 | } 3051 | 3052 | return view_as(g_hNavMeshPlaces); 3053 | } 3054 | 3055 | public int Native_NavMeshGetAreas(Handle plugin, int numParams) 3056 | { 3057 | if (!g_bNavMeshBuilt) 3058 | { 3059 | LogError("Could not retrieve area list because the nav mesh doesn't exist!"); 3060 | return 0; 3061 | } 3062 | 3063 | return view_as(g_hNavMeshAreas); 3064 | } 3065 | 3066 | public int Native_NavMeshGetLadders(Handle plugin, int numParams) 3067 | { 3068 | if (!g_bNavMeshBuilt) 3069 | { 3070 | LogError("Could not retrieve ladder list because the nav mesh doesn't exist!"); 3071 | return 0; 3072 | } 3073 | 3074 | return view_as(g_hNavMeshLadders); 3075 | } 3076 | 3077 | public int Native_NavMeshCollectSurroundingAreas(Handle plugin, int numParams) 3078 | { 3079 | ArrayStack hTarget = view_as(GetNativeCell(1)); 3080 | ArrayStack hDummy = NavMeshCollectSurroundingAreas(view_as(GetNativeCell(2)), view_as(GetNativeCell(3)), view_as(GetNativeCell(4)), view_as(GetNativeCell(5))); 3081 | 3082 | if (hDummy != null) 3083 | { 3084 | while (!IsStackEmpty(hDummy)) 3085 | { 3086 | int iAreaIndex = -1; 3087 | PopStackCell(hDummy, iAreaIndex); 3088 | hTarget.Push(iAreaIndex); 3089 | } 3090 | 3091 | delete hDummy; 3092 | } 3093 | } 3094 | 3095 | public int Native_NavMeshBuildPath(Handle plugin, int numParams) 3096 | { 3097 | float flGoalPos[3]; 3098 | GetNativeArray(3, flGoalPos, 3); 3099 | 3100 | int iClosestIndex = view_as(GetNativeCellRef(6)); 3101 | 3102 | bool bResult = NavMeshBuildPath(view_as(GetNativeCell(1)), 3103 | view_as(GetNativeCell(2)), 3104 | flGoalPos, 3105 | plugin, 3106 | view_as(GetNativeFunction(4)), 3107 | GetNativeCell(5), 3108 | iClosestIndex, 3109 | view_as(GetNativeCell(7)), 3110 | view_as(GetNativeCell(8))); 3111 | 3112 | SetNativeCellRef(6, iClosestIndex); 3113 | return bResult; 3114 | } 3115 | 3116 | public int Native_NavMeshGetArea(Handle plugin, int numParams) 3117 | { 3118 | float flPos[3]; 3119 | GetNativeArray(1, flPos, 3); 3120 | 3121 | return NavMeshGetArea(flPos, view_as(GetNativeCell(2))); 3122 | } 3123 | 3124 | public int Native_NavMeshGetNearestArea(Handle plugin, int numParams) 3125 | { 3126 | float flPos[3]; 3127 | GetNativeArray(1, flPos, 3); 3128 | 3129 | return NavMeshGetNearestArea(flPos, view_as(GetNativeCell(2)), view_as(GetNativeCell(3)), view_as(GetNativeCell(4)), view_as(GetNativeCell(5)), GetNativeCell(6)); 3130 | } 3131 | 3132 | public int Native_NavMeshFindHidingSpotByID(Handle plugin, int numParams) 3133 | { 3134 | return g_hNavMeshAreaHidingSpots.FindValue(GetNativeCell(1)); 3135 | } 3136 | 3137 | public int Native_NavMeshGetRandomHidingSpot(Handle plugin, int numParams) 3138 | { 3139 | return GetRandomInt(0, g_hNavMeshAreaHidingSpots.Length - 1); 3140 | } 3141 | 3142 | public int Native_NavMeshWorldToGridX(Handle plugin, int numParams) 3143 | { 3144 | return NavMeshWorldToGridX(view_as(GetNativeCell(1))); 3145 | } 3146 | 3147 | public int Native_NavMeshWorldToGridY(Handle plugin, int numParams) 3148 | { 3149 | return NavMeshWorldToGridY(view_as(GetNativeCell(1))); 3150 | } 3151 | 3152 | public int Native_NavMeshGridGetAreas(Handle plugin, int numParams) 3153 | { 3154 | ArrayStack hTarget = view_as(GetNativeCell(1)); 3155 | ArrayStack hDummy = NavMeshGridGetAreas(GetNativeCell(2), GetNativeCell(3)); 3156 | 3157 | if (hDummy != null) 3158 | { 3159 | while (!hDummy.Empty) 3160 | { 3161 | int iAreaIndex = -1; 3162 | PopStackCell(hDummy, iAreaIndex); 3163 | hTarget.Push(iAreaIndex); 3164 | } 3165 | 3166 | delete hDummy; 3167 | } 3168 | } 3169 | 3170 | public int Native_NavMeshGetGridSizeX(Handle plugin, int numParams) 3171 | { 3172 | return g_iNavMeshGridSizeX; 3173 | } 3174 | 3175 | public int Native_NavMeshGetGridSizeY(Handle plugin, int numParams) 3176 | { 3177 | return g_iNavMeshGridSizeY; 3178 | } 3179 | 3180 | public int Native_NavMeshAreaGetClosestPointOnArea(Handle plugin, int numParams) 3181 | { 3182 | float flPos[3]; float flClose[3]; 3183 | GetNativeArray(2, flPos, 3); 3184 | NavMeshAreaGetClosestPointOnArea(GetNativeCell(1), flPos, flClose); 3185 | SetNativeArray(3, flClose, 3); 3186 | } 3187 | 3188 | public int Native_NavMeshGetGroundHeight(Handle plugin, int numParams) 3189 | { 3190 | float flPos[3]; float flNormal[3]; 3191 | GetNativeArray(1, flPos, 3); 3192 | float flHeight = view_as(GetNativeCellRef(2)); 3193 | bool bResult = NavMeshGetGroundHeight(flPos, flHeight, flNormal); 3194 | SetNativeCellRef(2, flHeight); 3195 | SetNativeArray(3, flNormal, 3); 3196 | return bResult; 3197 | } 3198 | 3199 | public int Native_NavMeshFindAreaByID(Handle plugin, int numParams) 3200 | { 3201 | return NavMeshFindAreaByID(GetNativeCell(1)); 3202 | } 3203 | 3204 | public int Native_NavMeshAreaGetMasterMarker(Handle plugin, int numParams) 3205 | { 3206 | return g_iNavMeshAreaMasterMarker; 3207 | } 3208 | 3209 | public int Native_NavMeshAreaChangeMasterMarker(Handle plugin, int numParams) 3210 | { 3211 | g_iNavMeshAreaMasterMarker++; 3212 | } 3213 | 3214 | public int Native_NavMeshAreaGetID(Handle plugin, int numParams) 3215 | { 3216 | return NavMeshAreaGetID(GetNativeCell(1)); 3217 | } 3218 | 3219 | public int Native_NavMeshAreaGetFlags(Handle plugin, int numParams) 3220 | { 3221 | return NavMeshAreaGetFlags(GetNativeCell(1)); 3222 | } 3223 | 3224 | public int Native_NavMeshAreaGetPlace(Handle plugin, int numParams) 3225 | { 3226 | int maxlen = GetNativeCell(3); 3227 | char[] buffer = new char[maxlen]; 3228 | GetNativeString(2, buffer, maxlen); 3229 | NavMeshAreaGetPlace(GetNativeCell(1), buffer, maxlen); 3230 | SetNativeString(2, buffer, maxlen); 3231 | } 3232 | 3233 | public int Native_NavMeshAreaGetCenter(Handle plugin, int numParams) 3234 | { 3235 | float flResult[3]; 3236 | if (NavMeshAreaGetCenter(GetNativeCell(1), flResult)) 3237 | { 3238 | SetNativeArray(2, flResult, 3); 3239 | return true; 3240 | } 3241 | 3242 | return false; 3243 | } 3244 | 3245 | public int Native_NavMeshAreaGetAdjacentList(Handle plugin, int numParams) 3246 | { 3247 | ArrayStack hTarget = view_as(GetNativeCell(1)); 3248 | ArrayStack hDummy = NavMeshAreaGetAdjacentList(GetNativeCell(2), GetNativeCell(3)); 3249 | 3250 | if (hDummy != null) 3251 | { 3252 | while (!hDummy.Empty) 3253 | { 3254 | new iAreaIndex = -1; 3255 | PopStackCell(hDummy, iAreaIndex); 3256 | hTarget.Push(iAreaIndex); 3257 | } 3258 | 3259 | delete hDummy; 3260 | } 3261 | } 3262 | 3263 | public int Native_NavMeshAreaGetLadderList(Handle plugin, int numParams) 3264 | { 3265 | ArrayStack hTarget = view_as(GetNativeCell(1)); 3266 | ArrayStack hDummy = NavMeshAreaGetLadderList(GetNativeCell(2), GetNativeCell(3)); 3267 | 3268 | if (hDummy != null) 3269 | { 3270 | while (!IsStackEmpty(hDummy)) 3271 | { 3272 | int iAreaIndex = -1; 3273 | PopStackCell(hDummy, iAreaIndex); 3274 | PushStackCell(hTarget, iAreaIndex); 3275 | } 3276 | 3277 | delete hDummy; 3278 | } 3279 | } 3280 | 3281 | public int Native_NavMeshAreaGetHidingSpots(Handle plugin, int numParams) 3282 | { 3283 | ArrayStack hTarget = view_as(GetNativeCell(1)); 3284 | ArrayStack hDummy = NavMeshAreaGetHidingSpots(GetNativeCell(2)); 3285 | 3286 | if (hDummy != null) 3287 | { 3288 | while (!IsStackEmpty(hDummy)) 3289 | { 3290 | int iAreaIndex = -1; 3291 | PopStackCell(hDummy, iAreaIndex); 3292 | PushStackCell(hTarget, iAreaIndex); 3293 | } 3294 | 3295 | delete hDummy; 3296 | } 3297 | } 3298 | 3299 | public int Native_NavMeshAreaGetTotalCost(Handle plugin, int numParams) 3300 | { 3301 | return NavMeshAreaGetTotalCost(GetNativeCell(1)); 3302 | } 3303 | 3304 | public int Native_NavMeshAreaGetCostSoFar(Handle plugin, int numParams) 3305 | { 3306 | return NavMeshAreaGetCostSoFar(GetNativeCell(1)); 3307 | } 3308 | 3309 | public int Native_NavMeshAreaGetParent(Handle plugin, int numParams) 3310 | { 3311 | return NavMeshAreaGetParent(GetNativeCell(1)); 3312 | } 3313 | 3314 | public int Native_NavMeshAreaGetParentHow(Handle plugin, int numParams) 3315 | { 3316 | return NavMeshAreaGetParentHow(GetNativeCell(1)); 3317 | } 3318 | 3319 | public int Native_NavMeshAreaSetParent(Handle plugin, int numParams) 3320 | { 3321 | NavMeshAreaSetParent(GetNativeCell(1), GetNativeCell(2)); 3322 | } 3323 | 3324 | public int Native_NavMeshAreaSetParentHow(Handle plugin, int numParams) 3325 | { 3326 | NavMeshAreaSetParentHow(GetNativeCell(1), GetNativeCell(2)); 3327 | } 3328 | 3329 | public int Native_NavMeshAreaGetExtentLow(Handle plugin, int numParams) 3330 | { 3331 | float flExtent[3]; 3332 | if (NavMeshAreaGetExtentLow(GetNativeCell(1), flExtent)) 3333 | { 3334 | SetNativeArray(2, flExtent, 3); 3335 | return true; 3336 | } 3337 | 3338 | return false; 3339 | } 3340 | 3341 | public int Native_NavMeshAreaGetExtentHigh(Handle plugin, int numParams) 3342 | { 3343 | float flExtent[3]; 3344 | if (NavMeshAreaGetExtentHigh(GetNativeCell(1), flExtent)) 3345 | { 3346 | SetNativeArray(2, flExtent, 3); 3347 | return true; 3348 | } 3349 | 3350 | return false; 3351 | } 3352 | 3353 | public int Native_NavMeshAreaIsOverlappingPoint(Handle plugin, int numParams) 3354 | { 3355 | float flPos[3]; 3356 | GetNativeArray(2, flPos, 3); 3357 | 3358 | return NavMeshAreaIsOverlappingPoint(GetNativeCell(1), flPos, view_as(GetNativeCell(3))); 3359 | } 3360 | 3361 | public int Native_NavMeshAreaIsOverlappingArea(Handle plugin, int numParams) 3362 | { 3363 | return NavMeshAreaIsOverlappingArea(GetNativeCell(1), GetNativeCell(2)); 3364 | } 3365 | 3366 | public int Native_NavMeshAreaGetNECornerZ(Handle plugin, int numParams) 3367 | { 3368 | return view_as(NavMeshAreaGetNECornerZ(GetNativeCell(1))); 3369 | } 3370 | 3371 | public int Native_NavMeshAreaGetSWCornerZ(Handle plugin, int numParams) 3372 | { 3373 | return view_as(NavMeshAreaGetSWCornerZ(GetNativeCell(1))); 3374 | } 3375 | 3376 | public int Native_NavMeshAreaGetCorner(Handle plugin, int numParams) 3377 | { 3378 | float buffer[3]; 3379 | GetNativeArray(3, buffer, 3); 3380 | NavMeshAreaGetCorner(GetNativeCell(1), view_as(GetNativeCell(2)), buffer); 3381 | SetNativeArray(3, buffer, 3); 3382 | } 3383 | 3384 | public int Native_NavMeshAreaGetZ(Handle plugin, int numParams) 3385 | { 3386 | float flPos[3]; 3387 | GetNativeArray(2, flPos, 3); 3388 | 3389 | return view_as(NavMeshAreaGetZ(GetNativeCell(1), flPos)); 3390 | } 3391 | 3392 | public int Native_NavMeshAreaGetZFromXAndY(Handle plugin, int numParams) 3393 | { 3394 | return view_as(NavMeshAreaGetZFromXAndY(GetNativeCell(1), view_as(GetNativeCell(2)), view_as(GetNativeCell(3)))); 3395 | } 3396 | 3397 | public int Native_NavMeshAreaIsEdge(Handle plugin, int numParams) 3398 | { 3399 | return NavMeshAreaIsEdge(GetNativeCell(1), GetNativeCell(2)); 3400 | } 3401 | 3402 | public int Native_NavMeshAreaContains(Handle plugin, int numParams) 3403 | { 3404 | float flPos[3]; 3405 | GetNativeArray(2, flPos, 3); 3406 | 3407 | return NavMeshAreaContains(GetNativeCell(1), flPos); 3408 | } 3409 | 3410 | public int Native_NavMeshAreaGetRandomPoint(Handle plugin, int numParams) 3411 | { 3412 | float buffer[3]; 3413 | GetNativeArray(2, buffer, 3); 3414 | NavMeshAreaGetRandomPoint(GetNativeCell(1), buffer); 3415 | SetNativeArray(2, buffer, 3); 3416 | } 3417 | 3418 | public int Native_NavMeshAreaComputePortal(Handle plugin, int numParams) 3419 | { 3420 | float flCenter[3]; 3421 | float flHalfWidth = GetNativeCellRef(5); 3422 | 3423 | bool bResult = NavMeshAreaComputePortal(GetNativeCell(1), 3424 | GetNativeCell(2), 3425 | GetNativeCell(3), 3426 | flCenter, 3427 | flHalfWidth); 3428 | 3429 | SetNativeArray(4, flCenter, 3); 3430 | SetNativeCellRef(5, flHalfWidth); 3431 | return bResult; 3432 | } 3433 | 3434 | public int Native_NavMeshAreaIsConnected(Handle plugin, int numParams) 3435 | { 3436 | return NavMeshAreaIsConnected(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3)); 3437 | } 3438 | 3439 | public int Native_NavMeshAreaComputeClosestPointInPortal(Handle plugin, int numParams) 3440 | { 3441 | float flFromPos[3]; 3442 | GetNativeArray(4, flFromPos, 3); 3443 | 3444 | float flClosestPos[3]; 3445 | 3446 | bool bResult = NavMeshAreaComputeClosestPointInPortal(GetNativeCell(1), 3447 | GetNativeCell(2), 3448 | GetNativeCell(3), 3449 | flFromPos, 3450 | flClosestPos); 3451 | 3452 | SetNativeArray(5, flClosestPos, 3); 3453 | return bResult; 3454 | } 3455 | 3456 | public int Native_NavMeshAreaComputeDirection(Handle plugin, int numParams) 3457 | { 3458 | float flPos[3]; 3459 | GetNativeArray(2, flPos, 3); 3460 | 3461 | return NavMeshAreaComputeDirection(GetNativeCell(1), flPos); 3462 | } 3463 | 3464 | public int Native_NavMeshAreaGetLightIntensity(Handle plugin, int numParams) 3465 | { 3466 | float flPos[3]; 3467 | GetNativeArray(2, flPos, 3); 3468 | 3469 | return view_as(NavMeshAreaGetLightIntensity(GetNativeCell(1), flPos)); 3470 | } 3471 | 3472 | public int Native_NavHidingSpotGetID(Handle plugin, int numParams) 3473 | { 3474 | return g_hNavMeshAreaHidingSpots.Get(GetNativeCell(1), NavMeshHidingSpot_ID); 3475 | } 3476 | 3477 | public int Native_NavHidingSpotGetFlags(Handle plugin, int numParams) 3478 | { 3479 | return g_hNavMeshAreaHidingSpots.Get(GetNativeCell(1), NavMeshHidingSpot_Flags); 3480 | } 3481 | 3482 | public int Native_NavHidingSpotGetPosition(Handle plugin, int numParams) 3483 | { 3484 | float buffer[3]; 3485 | GetNativeArray(2, buffer, 3); 3486 | 3487 | int hidingSpotIndex = GetNativeCell(1); 3488 | 3489 | buffer[0] = view_as(g_hNavMeshAreaHidingSpots.Get(hidingSpotIndex, NavMeshHidingSpot_X)); 3490 | buffer[1] = view_as(g_hNavMeshAreaHidingSpots.Get(hidingSpotIndex, NavMeshHidingSpot_Y)); 3491 | buffer[2] = view_as(g_hNavMeshAreaHidingSpots.Get(hidingSpotIndex, NavMeshHidingSpot_Z)); 3492 | 3493 | SetNativeArray(2, buffer, 3); 3494 | } 3495 | 3496 | public int Native_NavHidingSpotGetArea(Handle plugin, int numParams) 3497 | { 3498 | return g_hNavMeshAreaHidingSpots.Get(GetNativeCell(1), NavMeshHidingSpot_AreaIndex); 3499 | } 3500 | 3501 | public int Native_NavMeshLadderGetWidth(Handle plugin, int numParams) 3502 | { 3503 | return view_as(NavMeshLadderGetWidth(GetNativeCell(1))); 3504 | } 3505 | 3506 | public int Native_NavMeshLadderGetLength(Handle plugin, int numParams) 3507 | { 3508 | return view_as(NavMeshLadderGetLength(GetNativeCell(1))); 3509 | } 3510 | 3511 | public int Native_NavMeshLadderGetTopForwardArea(Handle plugin, int numParams) 3512 | { 3513 | return g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopForwardAreaIndex); 3514 | } 3515 | 3516 | public int Native_NavMeshLadderGetTopLeftArea(Handle plugin, int numParams) 3517 | { 3518 | return g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopLeftAreaIndex); 3519 | } 3520 | 3521 | public int Native_NavMeshLadderGetTopRightArea(Handle plugin, int numParams) 3522 | { 3523 | return g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopRightAreaIndex); 3524 | } 3525 | 3526 | public int Native_NavMeshLadderGetTopBehindArea(Handle plugin, int numParams) 3527 | { 3528 | return g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopBehindAreaIndex); 3529 | } 3530 | 3531 | public int Native_NavMeshLadderGetBottomArea(Handle plugin, int numParams) 3532 | { 3533 | return g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_BottomAreaIndex); 3534 | } 3535 | 3536 | public int Native_NavMeshLadderGetTop(Handle plugin, int numParams) 3537 | { 3538 | float buffer[3]; 3539 | GetNativeArray(2, buffer, 3); 3540 | 3541 | buffer[0] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopX)); 3542 | buffer[1] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopY)); 3543 | buffer[2] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_TopZ)); 3544 | 3545 | SetNativeArray(2, buffer, 3); 3546 | } 3547 | 3548 | public int Native_NavMeshLadderGetBottom(Handle plugin, int numParams) 3549 | { 3550 | float buffer[3]; 3551 | GetNativeArray(2, buffer, 3); 3552 | 3553 | buffer[0] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_BottomX)); 3554 | buffer[1] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_BottomY)); 3555 | buffer[2] = view_as(g_hNavMeshLadders.Get(GetNativeCell(1), NavMeshLadder_BottomZ)); 3556 | 3557 | SetNativeArray(2, buffer, 3); 3558 | } 3559 | 3560 | public int Native_NavSpotEncounterGetFrom(Handle plugin, int numParams) 3561 | { 3562 | return NavSpotEncounterGetFrom(GetNativeCell(1)); 3563 | } 3564 | 3565 | public int Native_NavSpotEncounterGetFromDirection(Handle plugin, int numParams) 3566 | { 3567 | return NavSpotEncounterGetFromDirection(GetNativeCell(1)); 3568 | } 3569 | 3570 | public int Native_NavSpotEncounterGetTo(Handle plugin, int numParams) 3571 | { 3572 | return NavSpotEncounterGetTo(GetNativeCell(1)); 3573 | } 3574 | 3575 | public int Native_NavSpotEncounterGetToDirection(Handle plugin, int numParams) 3576 | { 3577 | return NavSpotEncounterGetToDirection(GetNativeCell(1)); 3578 | } 3579 | 3580 | public int Native_NavSpotEncounterGetSpots(Handle plugin, int numParams) 3581 | { 3582 | ArrayStack buffer = view_as(GetNativeCell(2)); 3583 | ArrayStack dummy = NavSpotEncounterGetSpots(GetNativeCell(1)); 3584 | if (dummy != null) 3585 | { 3586 | while (!dummy.Empty) 3587 | { 3588 | int val; 3589 | PopStackCell(dummy, val); 3590 | buffer.Push(val); 3591 | } 3592 | delete dummy; 3593 | } 3594 | } 3595 | 3596 | public int Native_NavSpotOrderGetHidingSpot(Handle plugin, int numParams) 3597 | { 3598 | return NavSpotOrderGetHidingSpot(GetNativeCell(1)); 3599 | } 3600 | 3601 | public int Native_NavSpotOrderGetParametricDistance(Handle plugin, int numParams) 3602 | { 3603 | return NavSpotOrderGetParametricDistance(GetNativeCell(1)); 3604 | } 3605 | 3606 | --------------------------------------------------------------------------------