Update Vmaps | Mmaps | Recastnav and fixed FleeingMovement
- Fixes getHeight collision (Map height is now calculated properly core-side, extraction of Maps, Vmaps is required) - Fixes invisible walls causing LoS errores and wrong pathing in some zones. - Mmaps update, padding is used, now to ensure proper binary-identical mmtiles - Updated Recastnav to work properly with new updates - Updated Area Storage - Implement Map out of Bound (players will pop on closest graveyard if out of bounds) - FleeingMovementGenerator updated, LoS calc to not go out of bounds or in/under textured when fleeing - Added command .mmap, port from TC (info about mmaps)
This commit is contained in:
@@ -12,8 +12,10 @@
|
|||||||
file(GLOB_RECURSE sources *.cpp *.h)
|
file(GLOB_RECURSE sources *.cpp *.h)
|
||||||
|
|
||||||
set(include_Dirs
|
set(include_Dirs
|
||||||
|
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Utilities
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
||||||
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/loadlib
|
${CMAKE_CURRENT_SOURCE_DIR}/loadlib
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,9 +20,12 @@
|
|||||||
|
|
||||||
#include "dbcfile.h"
|
#include "dbcfile.h"
|
||||||
#include "mpq_libmpq04.h"
|
#include "mpq_libmpq04.h"
|
||||||
|
#include "StringFormat.h"
|
||||||
|
|
||||||
#include "adt.h"
|
#include "adt.h"
|
||||||
#include "wdt.h"
|
#include "wdt.h"
|
||||||
|
|
||||||
|
#include "G3D/Plane.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#if defined( __GNUC__ )
|
#if defined( __GNUC__ )
|
||||||
@@ -49,11 +52,10 @@ typedef struct
|
|||||||
} map_id;
|
} map_id;
|
||||||
|
|
||||||
map_id *map_ids;
|
map_id *map_ids;
|
||||||
uint16 *areas;
|
|
||||||
uint16 *LiqType;
|
uint16 *LiqType;
|
||||||
char output_path[128] = ".";
|
#define MAX_PATH_LENGTH 128
|
||||||
char input_path[128] = ".";
|
char output_path[MAX_PATH_LENGTH] = ".";
|
||||||
uint32 maxAreaId = 0;
|
char input_path[MAX_PATH_LENGTH] = ".";
|
||||||
|
|
||||||
// **************************************************
|
// **************************************************
|
||||||
// Extractor options
|
// Extractor options
|
||||||
@@ -244,30 +246,6 @@ uint32 ReadMapDBC()
|
|||||||
return map_count;
|
return map_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadAreaTableDBC()
|
|
||||||
{
|
|
||||||
printf("Read AreaTable.dbc file...");
|
|
||||||
DBCFile dbc("DBFilesClient\\AreaTable.dbc");
|
|
||||||
|
|
||||||
if(!dbc.open())
|
|
||||||
{
|
|
||||||
printf("Fatal error: Invalid AreaTable.dbc file format!\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t area_count = dbc.getRecordCount();
|
|
||||||
size_t maxid = dbc.getMaxId();
|
|
||||||
areas = new uint16[maxid + 1];
|
|
||||||
memset(areas, 0xff, (maxid + 1) * sizeof(uint16));
|
|
||||||
|
|
||||||
for(uint32 x = 0; x < area_count; ++x)
|
|
||||||
areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
|
|
||||||
|
|
||||||
maxAreaId = dbc.getMaxId();
|
|
||||||
|
|
||||||
printf("Done! (%u areas loaded)\n", (uint32)area_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadLiquidTypeTableDBC()
|
void ReadLiquidTypeTableDBC()
|
||||||
{
|
{
|
||||||
printf("Read LiquidType.dbc file...");
|
printf("Read LiquidType.dbc file...");
|
||||||
@@ -295,7 +273,7 @@ void ReadLiquidTypeTableDBC()
|
|||||||
|
|
||||||
// Map file format data
|
// Map file format data
|
||||||
static char const* MAP_MAGIC = "MAPS";
|
static char const* MAP_MAGIC = "MAPS";
|
||||||
static char const* MAP_VERSION_MAGIC = "v1.3";
|
static char const* MAP_VERSION_MAGIC = "v1.8";
|
||||||
static char const* MAP_AREA_MAGIC = "AREA";
|
static char const* MAP_AREA_MAGIC = "AREA";
|
||||||
static char const* MAP_HEIGHT_MAGIC = "MHGT";
|
static char const* MAP_HEIGHT_MAGIC = "MHGT";
|
||||||
static char const* MAP_LIQUID_MAGIC = "MLIQ";
|
static char const* MAP_LIQUID_MAGIC = "MLIQ";
|
||||||
@@ -324,9 +302,10 @@ struct map_areaHeader
|
|||||||
uint16 gridArea;
|
uint16 gridArea;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||||
|
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
|
||||||
|
|
||||||
struct map_heightHeader
|
struct map_heightHeader
|
||||||
{
|
{
|
||||||
@@ -371,7 +350,7 @@ float selectUInt16StepStore(float maxDiff)
|
|||||||
return 65535 / maxDiff;
|
return 65535 / maxDiff;
|
||||||
}
|
}
|
||||||
// Temporary grid data store
|
// Temporary grid data store
|
||||||
uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
||||||
|
|
||||||
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
|
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
|
||||||
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
|
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
|
||||||
@@ -385,17 +364,20 @@ uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
|||||||
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE];
|
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE];
|
||||||
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
|
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
|
||||||
|
|
||||||
bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, uint32 build)
|
int16 flight_box_max[3][3];
|
||||||
|
int16 flight_box_min[3][3];
|
||||||
|
|
||||||
|
bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build)
|
||||||
{
|
{
|
||||||
ADT_file adt;
|
ADT_file adt;
|
||||||
|
|
||||||
if (!adt.loadFile(filename))
|
if (!adt.loadFile(inputPath))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
adt_MCIN *cells = adt.a_grid->getMCIN();
|
adt_MCIN *cells = adt.a_grid->getMCIN();
|
||||||
if (!cells)
|
if (!cells)
|
||||||
{
|
{
|
||||||
printf("Can't find cells in '%s'\n", filename);
|
printf("Can't find cells in '%s'\n", inputPath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,39 +387,25 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
|
|
||||||
// Prepare map header
|
// Prepare map header
|
||||||
map_fileheader map;
|
map_fileheader map;
|
||||||
map.mapMagic = *(uint32 const*)MAP_MAGIC;
|
map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC);
|
||||||
map.versionMagic = *(uint32 const*)MAP_VERSION_MAGIC;
|
map.versionMagic = *reinterpret_cast<uint32 const*>(MAP_VERSION_MAGIC);
|
||||||
map.buildMagic = build;
|
map.buildMagic = build;
|
||||||
|
|
||||||
// Get area flags data
|
// Get area flags data
|
||||||
for (int i=0;i<ADT_CELLS_PER_GRID;i++)
|
for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
|
||||||
{
|
for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
|
||||||
for(int j=0;j<ADT_CELLS_PER_GRID;j++)
|
area_ids[i][j] = cells->getMCNK(i, j)->areaid;
|
||||||
{
|
|
||||||
adt_MCNK * cell = cells->getMCNK(i,j);
|
|
||||||
uint32 areaid = cell->areaid;
|
|
||||||
if(areaid && areaid <= maxAreaId)
|
|
||||||
{
|
|
||||||
if(areas[areaid] != 0xffff)
|
|
||||||
{
|
|
||||||
area_flags[i][j] = areas[areaid];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf("File: %s\nCan't find area flag for areaid %u [%d, %d].\n", filename, areaid, cell->ix, cell->iy);
|
|
||||||
}
|
|
||||||
area_flags[i][j] = 0xffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//============================================
|
//============================================
|
||||||
// Try pack area data
|
// Try pack area data
|
||||||
//============================================
|
//============================================
|
||||||
bool fullAreaData = false;
|
bool fullAreaData = false;
|
||||||
uint32 areaflag = area_flags[0][0];
|
uint32 areaId = area_ids[0][0];
|
||||||
for (int y=0;y<ADT_CELLS_PER_GRID;y++)
|
for (int y = 0; y < ADT_CELLS_PER_GRID; ++y)
|
||||||
{
|
{
|
||||||
for(int x=0;x<ADT_CELLS_PER_GRID;x++)
|
for (int x = 0; x < ADT_CELLS_PER_GRID; ++x)
|
||||||
{
|
{
|
||||||
if(area_flags[y][x]!=areaflag)
|
if (area_ids[y][x] != areaId)
|
||||||
{
|
{
|
||||||
fullAreaData = true;
|
fullAreaData = true;
|
||||||
break;
|
break;
|
||||||
@@ -449,27 +417,27 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
map.areaMapSize = sizeof(map_areaHeader);
|
map.areaMapSize = sizeof(map_areaHeader);
|
||||||
|
|
||||||
map_areaHeader areaHeader;
|
map_areaHeader areaHeader;
|
||||||
areaHeader.fourcc = *(uint32 const*)MAP_AREA_MAGIC;
|
areaHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_AREA_MAGIC);
|
||||||
areaHeader.flags = 0;
|
areaHeader.flags = 0;
|
||||||
if (fullAreaData)
|
if (fullAreaData)
|
||||||
{
|
{
|
||||||
areaHeader.gridArea = 0;
|
areaHeader.gridArea = 0;
|
||||||
map.areaMapSize+=sizeof(area_flags);
|
map.areaMapSize += sizeof(area_ids);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
areaHeader.flags |= MAP_AREA_NO_AREA;
|
areaHeader.flags |= MAP_AREA_NO_AREA;
|
||||||
areaHeader.gridArea = (uint16)areaflag;
|
areaHeader.gridArea = static_cast<uint16>(areaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get Height map from grid
|
// Get Height map from grid
|
||||||
//
|
//
|
||||||
for (int i=0;i<ADT_CELLS_PER_GRID;i++)
|
for (int i = 0; i<ADT_CELLS_PER_GRID; i++)
|
||||||
{
|
{
|
||||||
for(int j=0;j<ADT_CELLS_PER_GRID;j++)
|
for (int j = 0; j<ADT_CELLS_PER_GRID; j++)
|
||||||
{
|
{
|
||||||
adt_MCNK * cell = cells->getMCNK(i,j);
|
adt_MCNK * cell = cells->getMCNK(i, j);
|
||||||
if (!cell)
|
if (!cell)
|
||||||
continue;
|
continue;
|
||||||
// Height values for triangles stored in order:
|
// Height values for triangles stored in order:
|
||||||
@@ -489,22 +457,22 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
// . . . . . . . .
|
// . . . . . . . .
|
||||||
|
|
||||||
// Set map height as grid height
|
// Set map height as grid height
|
||||||
for (int y=0; y <= ADT_CELL_SIZE; y++)
|
for (int y = 0; y <= ADT_CELL_SIZE; y++)
|
||||||
{
|
{
|
||||||
int cy = i*ADT_CELL_SIZE + y;
|
int cy = i*ADT_CELL_SIZE + y;
|
||||||
for (int x=0; x <= ADT_CELL_SIZE; x++)
|
for (int x = 0; x <= ADT_CELL_SIZE; x++)
|
||||||
{
|
{
|
||||||
int cx = j*ADT_CELL_SIZE + x;
|
int cx = j*ADT_CELL_SIZE + x;
|
||||||
V9[cy][cx]=cell->ypos;
|
V9[cy][cx] = cell->ypos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int y=0; y < ADT_CELL_SIZE; y++)
|
for (int y = 0; y < ADT_CELL_SIZE; y++)
|
||||||
{
|
{
|
||||||
int cy = i*ADT_CELL_SIZE + y;
|
int cy = i*ADT_CELL_SIZE + y;
|
||||||
for (int x=0; x < ADT_CELL_SIZE; x++)
|
for (int x = 0; x < ADT_CELL_SIZE; x++)
|
||||||
{
|
{
|
||||||
int cx = j*ADT_CELL_SIZE + x;
|
int cx = j*ADT_CELL_SIZE + x;
|
||||||
V8[cy][cx]=cell->ypos;
|
V8[cy][cx] = cell->ypos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get custom height
|
// Get custom height
|
||||||
@@ -512,23 +480,23 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
if (!v)
|
if (!v)
|
||||||
continue;
|
continue;
|
||||||
// get V9 height map
|
// get V9 height map
|
||||||
for (int y=0; y <= ADT_CELL_SIZE; y++)
|
for (int y = 0; y <= ADT_CELL_SIZE; y++)
|
||||||
{
|
{
|
||||||
int cy = i*ADT_CELL_SIZE + y;
|
int cy = i*ADT_CELL_SIZE + y;
|
||||||
for (int x=0; x <= ADT_CELL_SIZE; x++)
|
for (int x = 0; x <= ADT_CELL_SIZE; x++)
|
||||||
{
|
{
|
||||||
int cx = j*ADT_CELL_SIZE + x;
|
int cx = j*ADT_CELL_SIZE + x;
|
||||||
V9[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+x];
|
V9[cy][cx] += v->height_map[y*(ADT_CELL_SIZE * 2 + 1) + x];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get V8 height map
|
// get V8 height map
|
||||||
for (int y=0; y < ADT_CELL_SIZE; y++)
|
for (int y = 0; y < ADT_CELL_SIZE; y++)
|
||||||
{
|
{
|
||||||
int cy = i*ADT_CELL_SIZE + y;
|
int cy = i*ADT_CELL_SIZE + y;
|
||||||
for (int x=0; x < ADT_CELL_SIZE; x++)
|
for (int x = 0; x < ADT_CELL_SIZE; x++)
|
||||||
{
|
{
|
||||||
int cx = j*ADT_CELL_SIZE + x;
|
int cx = j*ADT_CELL_SIZE + x;
|
||||||
V8[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+ADT_CELL_SIZE+1+x];
|
V8[cy][cx] += v->height_map[y*(ADT_CELL_SIZE * 2 + 1) + ADT_CELL_SIZE + 1 + x];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,18 +506,18 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
//============================================
|
//============================================
|
||||||
float maxHeight = -20000;
|
float maxHeight = -20000;
|
||||||
float minHeight = 20000;
|
float minHeight = 20000;
|
||||||
for (int y=0; y<ADT_GRID_SIZE; y++)
|
for (int y = 0; y<ADT_GRID_SIZE; y++)
|
||||||
{
|
{
|
||||||
for(int x=0;x<ADT_GRID_SIZE;x++)
|
for (int x = 0; x<ADT_GRID_SIZE; x++)
|
||||||
{
|
{
|
||||||
float h = V8[y][x];
|
float h = V8[y][x];
|
||||||
if (maxHeight < h) maxHeight = h;
|
if (maxHeight < h) maxHeight = h;
|
||||||
if (minHeight > h) minHeight = h;
|
if (minHeight > h) minHeight = h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int y=0; y<=ADT_GRID_SIZE; y++)
|
for (int y = 0; y <= ADT_GRID_SIZE; y++)
|
||||||
{
|
{
|
||||||
for(int x=0;x<=ADT_GRID_SIZE;x++)
|
for(int x = 0; x<= ADT_GRID_SIZE; x++)
|
||||||
{
|
{
|
||||||
float h = V9[y][x];
|
float h = V9[y][x];
|
||||||
if (maxHeight < h) maxHeight = h;
|
if (maxHeight < h) maxHeight = h;
|
||||||
@@ -560,12 +528,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
// Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
|
// Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
|
||||||
if (CONF_allow_height_limit && minHeight < CONF_use_minHeight)
|
if (CONF_allow_height_limit && minHeight < CONF_use_minHeight)
|
||||||
{
|
{
|
||||||
for (int y=0; y<ADT_GRID_SIZE; y++)
|
for (int y = 0; y<ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<ADT_GRID_SIZE;x++)
|
for (int x = 0; x<ADT_GRID_SIZE; x++)
|
||||||
if (V8[y][x] < CONF_use_minHeight)
|
if (V8[y][x] < CONF_use_minHeight)
|
||||||
V8[y][x] = CONF_use_minHeight;
|
V8[y][x] = CONF_use_minHeight;
|
||||||
for (int y=0; y<=ADT_GRID_SIZE; y++)
|
for (int y = 0; y <= ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<=ADT_GRID_SIZE;x++)
|
for (int x = 0; x <= ADT_GRID_SIZE; x++)
|
||||||
if (V9[y][x] < CONF_use_minHeight)
|
if (V9[y][x] < CONF_use_minHeight)
|
||||||
V9[y][x] = CONF_use_minHeight;
|
V9[y][x] = CONF_use_minHeight;
|
||||||
if (minHeight < CONF_use_minHeight)
|
if (minHeight < CONF_use_minHeight)
|
||||||
@@ -574,11 +542,19 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
maxHeight = CONF_use_minHeight;
|
maxHeight = CONF_use_minHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasFlightBox = false;
|
||||||
|
if (adt_MFBO* mfbo = adt.a_grid->getMFBO())
|
||||||
|
{
|
||||||
|
memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max));
|
||||||
|
memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min));
|
||||||
|
hasFlightBox = true;
|
||||||
|
}
|
||||||
|
|
||||||
map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
|
map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
|
||||||
map.heightMapSize = sizeof(map_heightHeader);
|
map.heightMapSize = sizeof(map_heightHeader);
|
||||||
|
|
||||||
map_heightHeader heightHeader;
|
map_heightHeader heightHeader;
|
||||||
heightHeader.fourcc = *(uint32 const*)MAP_HEIGHT_MAGIC;
|
heightHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_HEIGHT_MAGIC);
|
||||||
heightHeader.flags = 0;
|
heightHeader.flags = 0;
|
||||||
heightHeader.gridHeight = minHeight;
|
heightHeader.gridHeight = minHeight;
|
||||||
heightHeader.gridMaxHeight = maxHeight;
|
heightHeader.gridMaxHeight = maxHeight;
|
||||||
@@ -590,6 +566,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
|
if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
|
||||||
heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
|
heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
|
||||||
|
|
||||||
|
if (hasFlightBox)
|
||||||
|
{
|
||||||
|
heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS;
|
||||||
|
map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min);
|
||||||
|
}
|
||||||
|
|
||||||
// Try store as packed in uint16 or uint8 values
|
// Try store as packed in uint16 or uint8 values
|
||||||
if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
|
if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
|
||||||
{
|
{
|
||||||
@@ -600,12 +582,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
float diff = maxHeight - minHeight;
|
float diff = maxHeight - minHeight;
|
||||||
if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
|
if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
|
||||||
{
|
{
|
||||||
heightHeader.flags|=MAP_HEIGHT_AS_INT8;
|
heightHeader.flags |= MAP_HEIGHT_AS_INT8;
|
||||||
step = selectUInt8StepStore(diff);
|
step = selectUInt8StepStore(diff);
|
||||||
}
|
}
|
||||||
else if (diff<CONF_float_to_int16_limit) // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
|
else if (diff<CONF_float_to_int16_limit) // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
|
||||||
{
|
{
|
||||||
heightHeader.flags|=MAP_HEIGHT_AS_INT16;
|
heightHeader.flags |= MAP_HEIGHT_AS_INT16;
|
||||||
step = selectUInt16StepStore(diff);
|
step = selectUInt16StepStore(diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -613,32 +595,32 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
// Pack it to int values if need
|
// Pack it to int values if need
|
||||||
if (heightHeader.flags&MAP_HEIGHT_AS_INT8)
|
if (heightHeader.flags&MAP_HEIGHT_AS_INT8)
|
||||||
{
|
{
|
||||||
for (int y=0; y<ADT_GRID_SIZE; y++)
|
for (int y = 0; y<ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<ADT_GRID_SIZE;x++)
|
for (int x = 0; x<ADT_GRID_SIZE; x++)
|
||||||
uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
|
uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
|
||||||
for (int y=0; y<=ADT_GRID_SIZE; y++)
|
for (int y = 0; y <= ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<=ADT_GRID_SIZE;x++)
|
for (int x = 0; x <= ADT_GRID_SIZE; x++)
|
||||||
uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
|
uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
|
||||||
map.heightMapSize+= sizeof(uint8_V9) + sizeof(uint8_V8);
|
map.heightMapSize += sizeof(uint8_V9) + sizeof(uint8_V8);
|
||||||
}
|
}
|
||||||
else if (heightHeader.flags&MAP_HEIGHT_AS_INT16)
|
else if (heightHeader.flags&MAP_HEIGHT_AS_INT16)
|
||||||
{
|
{
|
||||||
for (int y=0; y<ADT_GRID_SIZE; y++)
|
for (int y = 0; y<ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<ADT_GRID_SIZE;x++)
|
for (int x = 0; x<ADT_GRID_SIZE; x++)
|
||||||
uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
|
uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
|
||||||
for (int y=0; y<=ADT_GRID_SIZE; y++)
|
for (int y = 0; y <= ADT_GRID_SIZE; y++)
|
||||||
for(int x=0;x<=ADT_GRID_SIZE;x++)
|
for (int x = 0; x <= ADT_GRID_SIZE; x++)
|
||||||
uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
|
uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
|
||||||
map.heightMapSize+= sizeof(uint16_V9) + sizeof(uint16_V8);
|
map.heightMapSize += sizeof(uint16_V9) + sizeof(uint16_V8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
map.heightMapSize+= sizeof(V9) + sizeof(V8);
|
map.heightMapSize += sizeof(V9) + sizeof(V8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get from MCLQ chunk (old)
|
// Get from MCLQ chunk (old)
|
||||||
for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
|
for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
|
||||||
{
|
{
|
||||||
for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
|
for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
|
||||||
{
|
{
|
||||||
adt_MCNK *cell = cells->getMCNK(i, j);
|
adt_MCNK *cell = cells->getMCNK(i, j);
|
||||||
if (!cell)
|
if (!cell)
|
||||||
@@ -658,7 +640,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
if (liquid->flags[y][x] != 0x0F)
|
if (liquid->flags[y][x] != 0x0F)
|
||||||
{
|
{
|
||||||
liquid_show[cy][cx] = true;
|
liquid_show[cy][cx] = true;
|
||||||
if (liquid->flags[y][x] & (1<<7))
|
if (liquid->flags[y][x] & (1 << 7))
|
||||||
liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER;
|
liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
@@ -666,17 +648,17 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 c_flag = cell->flags;
|
uint32 c_flag = cell->flags;
|
||||||
if (c_flag & (1<<2))
|
if (c_flag & (1 << 2))
|
||||||
{
|
{
|
||||||
liquid_entry[i][j] = 1;
|
liquid_entry[i][j] = 1;
|
||||||
liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water
|
liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water
|
||||||
}
|
}
|
||||||
if (c_flag & (1<<3))
|
if (c_flag & (1 << 3))
|
||||||
{
|
{
|
||||||
liquid_entry[i][j] = 2;
|
liquid_entry[i][j] = 2;
|
||||||
liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean
|
liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean
|
||||||
}
|
}
|
||||||
if (c_flag & (1<<4))
|
if (c_flag & (1 << 4))
|
||||||
{
|
{
|
||||||
liquid_entry[i][j] = 3;
|
liquid_entry[i][j] = 3;
|
||||||
liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime
|
liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime
|
||||||
@@ -734,7 +716,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break;
|
case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break;
|
||||||
case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break;
|
case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break;
|
||||||
default:
|
default:
|
||||||
printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j);
|
printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, inputPath.c_str(), i, j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Dark water detect
|
// Dark water detect
|
||||||
@@ -877,17 +859,17 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
map.holesSize = 0;
|
map.holesSize = 0;
|
||||||
|
|
||||||
// Ok all data prepared - store it
|
// Ok all data prepared - store it
|
||||||
FILE* output = fopen(filename2, "wb");
|
FILE* output = fopen(outputPath.c_str(), "wb");
|
||||||
if (!output)
|
if (!output)
|
||||||
{
|
{
|
||||||
printf("Can't create the output file '%s'\n", filename2);
|
printf("Can't create the output file '%s'\n", outputPath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fwrite(&map, sizeof(map), 1, output);
|
fwrite(&map, sizeof(map), 1, output);
|
||||||
// Store area data
|
// Store area data
|
||||||
fwrite(&areaHeader, sizeof(areaHeader), 1, output);
|
fwrite(&areaHeader, sizeof(areaHeader), 1, output);
|
||||||
if (!(areaHeader.flags&MAP_AREA_NO_AREA))
|
if (!(areaHeader.flags&MAP_AREA_NO_AREA))
|
||||||
fwrite(area_flags, sizeof(area_flags), 1, output);
|
fwrite(area_ids, sizeof(area_ids), 1, output);
|
||||||
|
|
||||||
// Store height data
|
// Store height data
|
||||||
fwrite(&heightHeader, sizeof(heightHeader), 1, output);
|
fwrite(&heightHeader, sizeof(heightHeader), 1, output);
|
||||||
@@ -910,6 +892,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
|
||||||
|
{
|
||||||
|
fwrite(flight_box_max, sizeof(flight_box_max), 1, output);
|
||||||
|
fwrite(flight_box_min, sizeof(flight_box_min), 1, output);
|
||||||
|
}
|
||||||
|
|
||||||
// Store liquid data if need
|
// Store liquid data if need
|
||||||
if (map.liquidMapOffset)
|
if (map.liquidMapOffset)
|
||||||
{
|
{
|
||||||
@@ -937,15 +925,14 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/,
|
|||||||
|
|
||||||
void ExtractMapsFromMpq(uint32 build)
|
void ExtractMapsFromMpq(uint32 build)
|
||||||
{
|
{
|
||||||
char mpq_filename[1024];
|
std::string mpqFileName;
|
||||||
char output_filename[1024];
|
std::string outputFileName;
|
||||||
char mpq_map_name[1024];
|
std::string mpqMapName;
|
||||||
|
|
||||||
printf("Extracting maps...\n");
|
printf("Extracting maps...\n");
|
||||||
|
|
||||||
uint32 map_count = ReadMapDBC();
|
uint32 map_count = ReadMapDBC();
|
||||||
|
|
||||||
ReadAreaTableDBC();
|
|
||||||
ReadLiquidTypeTableDBC();
|
ReadLiquidTypeTableDBC();
|
||||||
|
|
||||||
std::string path = output_path;
|
std::string path = output_path;
|
||||||
@@ -957,9 +944,9 @@ void ExtractMapsFromMpq(uint32 build)
|
|||||||
{
|
{
|
||||||
printf("Extract %s (%d/%u) \n", map_ids[z].name, z+1, map_count);
|
printf("Extract %s (%d/%u) \n", map_ids[z].name, z+1, map_count);
|
||||||
// Loadup map grid data
|
// Loadup map grid data
|
||||||
sprintf(mpq_map_name, "World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
|
mpqMapName = Trinity::StringFormat("World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
|
||||||
WDT_file wdt;
|
WDT_file wdt;
|
||||||
if (!wdt.loadFile(mpq_map_name, false))
|
if (!wdt.loadFile(mpqMapName, false))
|
||||||
{
|
{
|
||||||
// printf("Error loading %s map wdt data\n", map_ids[z].name);
|
// printf("Error loading %s map wdt data\n", map_ids[z].name);
|
||||||
continue;
|
continue;
|
||||||
@@ -971,17 +958,16 @@ void ExtractMapsFromMpq(uint32 build)
|
|||||||
{
|
{
|
||||||
if (!wdt.main->adt_list[y][x].exist)
|
if (!wdt.main->adt_list[y][x].exist)
|
||||||
continue;
|
continue;
|
||||||
sprintf(mpq_filename, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
|
mpqFileName = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
|
||||||
sprintf(output_filename, "%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x);
|
outputFileName = Trinity::StringFormat("%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x);
|
||||||
ConvertADT(mpq_filename, output_filename, y, x, build);
|
ConvertADT(mpqFileName, outputFileName, y, x, build);
|
||||||
}
|
}
|
||||||
// draw progress bar
|
// draw progress bar
|
||||||
printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE);
|
printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
delete [] areas;
|
delete[] map_ids;
|
||||||
delete [] map_ids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractFile( char const* mpq_name, std::string const& filename )
|
bool ExtractFile( char const* mpq_name, std::string const& filename )
|
||||||
|
|||||||
@@ -9,15 +9,16 @@
|
|||||||
#include "adt.h"
|
#include "adt.h"
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
|
int holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
|
||||||
int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
|
int holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
|
||||||
|
|
||||||
u_map_fcc MHDRMagic = { {'R','D','H','M'} };
|
u_map_fcc MHDRMagic = { { 'R','D','H','M' } };
|
||||||
u_map_fcc MCINMagic = { {'N','I','C','M'} };
|
u_map_fcc MCINMagic = { { 'N','I','C','M' } };
|
||||||
u_map_fcc MH2OMagic = { {'O','2','H','M'} };
|
u_map_fcc MH2OMagic = { { 'O','2','H','M' } };
|
||||||
u_map_fcc MCNKMagic = { {'K','N','C','M'} };
|
u_map_fcc MCNKMagic = { { 'K','N','C','M' } };
|
||||||
u_map_fcc MCVTMagic = { {'T','V','C','M'} };
|
u_map_fcc MCVTMagic = { { 'T','V','C','M' } };
|
||||||
u_map_fcc MCLQMagic = { {'Q','L','C','M'} };
|
u_map_fcc MCLQMagic = { { 'Q','L','C','M' } };
|
||||||
|
u_map_fcc MFBOMagic = { { 'O','B','F','M' } };
|
||||||
|
|
||||||
bool isHole(int holes, int i, int j)
|
bool isHole(int holes, int i, int j)
|
||||||
{
|
{
|
||||||
@@ -69,7 +70,7 @@ bool adt_MHDR::prepareLoadedData()
|
|||||||
if (fcc != MHDRMagic.fcc)
|
if (fcc != MHDRMagic.fcc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (size!=sizeof(adt_MHDR)-8)
|
if (size != sizeof(adt_MHDR) - 8)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check and prepare MCIN
|
// Check and prepare MCIN
|
||||||
@@ -80,6 +81,9 @@ bool adt_MHDR::prepareLoadedData()
|
|||||||
if (offsMH2O && !getMH2O()->prepareLoadedData())
|
if (offsMH2O && !getMH2O()->prepareLoadedData())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (offsMFBO && flags & 1 && !getMFBO()->prepareLoadedData())
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,3 +146,8 @@ bool adt_MCLQ::prepareLoadedData()
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool adt_MFBO::prepareLoadedData()
|
||||||
|
{
|
||||||
|
return fcc == MFBOMagic.fcc;
|
||||||
|
}
|
||||||
|
|||||||
@@ -248,6 +248,27 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Adt file min/max height chunk
|
||||||
|
//
|
||||||
|
class adt_MFBO
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32 fcc;
|
||||||
|
char fcc_txt[4];
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
uint32 size;
|
||||||
|
struct plane
|
||||||
|
{
|
||||||
|
int16 coords[9];
|
||||||
|
};
|
||||||
|
plane max;
|
||||||
|
plane min;
|
||||||
|
|
||||||
|
bool prepareLoadedData();
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Adt file header chunk
|
// Adt file header chunk
|
||||||
//
|
//
|
||||||
@@ -260,12 +281,12 @@ class adt_MHDR
|
|||||||
public:
|
public:
|
||||||
uint32 size;
|
uint32 size;
|
||||||
|
|
||||||
uint32 pad;
|
uint32 flags;
|
||||||
uint32 offsMCIN; // MCIN
|
uint32 offsMCIN; // MCIN
|
||||||
uint32 offsTex; // MTEX
|
uint32 offsTex; // MTEX
|
||||||
uint32 offsModels; // MMDX
|
uint32 offsModels; // MMDX
|
||||||
uint32 offsModelsIds; // MMID
|
uint32 offsModelsIds; // MMID
|
||||||
uint32 offsMapObejcts; // MWMO
|
uint32 offsMapObejcts; // MWMO
|
||||||
uint32 offsMapObejctsIds; // MWID
|
uint32 offsMapObejctsIds; // MWID
|
||||||
uint32 offsDoodsDef; // MDDF
|
uint32 offsDoodsDef; // MDDF
|
||||||
uint32 offsObjectsDef; // MODF
|
uint32 offsObjectsDef; // MODF
|
||||||
@@ -278,9 +299,22 @@ public:
|
|||||||
uint32 data5;
|
uint32 data5;
|
||||||
public:
|
public:
|
||||||
bool prepareLoadedData();
|
bool prepareLoadedData();
|
||||||
adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);}
|
adt_MCIN* getMCIN()
|
||||||
adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;}
|
{
|
||||||
|
return reinterpret_cast<adt_MCIN*>(reinterpret_cast<uint8*>(&flags) + offsMCIN);
|
||||||
|
}
|
||||||
|
adt_MH2O* getMH2O()
|
||||||
|
{
|
||||||
|
if (offsMH2O)
|
||||||
|
return reinterpret_cast<adt_MH2O*>(reinterpret_cast<uint8*>(&flags) + offsMH2O);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
adt_MFBO* getMFBO()
|
||||||
|
{
|
||||||
|
if (flags & 1 && offsMFBO)
|
||||||
|
return reinterpret_cast<adt_MFBO*>(reinterpret_cast<uint8*>(&flags) + offsMFBO);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADT_file : public FileLoader{
|
class ADT_file : public FileLoader{
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ FileLoader::~FileLoader()
|
|||||||
free();
|
free();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileLoader::loadFile(char *filename, bool log)
|
bool FileLoader::loadFile(std::string const& fileName, bool log)
|
||||||
{
|
{
|
||||||
free();
|
free();
|
||||||
MPQFile mf(filename);
|
MPQFile mf(fileName.c_str());
|
||||||
if(mf.isEof())
|
if(mf.isEof())
|
||||||
{
|
{
|
||||||
if (log)
|
if (log)
|
||||||
printf("No such file %s\n", filename);
|
printf("No such file %s\n", fileName.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ bool FileLoader::loadFile(char *filename, bool log)
|
|||||||
if (prepareLoadedData())
|
if (prepareLoadedData())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
printf("Error loading %s", filename);
|
printf("Error loading %s", fileName.c_str());
|
||||||
mf.close();
|
mf.close();
|
||||||
free();
|
free();
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#ifndef LOAD_LIB_H
|
#ifndef LOAD_LIB_H
|
||||||
#define LOAD_LIB_H
|
#define LOAD_LIB_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef __int64 int64;
|
typedef __int64 int64;
|
||||||
typedef __int32 int32;
|
typedef __int32 int32;
|
||||||
@@ -65,7 +67,7 @@ public:
|
|||||||
file_MVER *version;
|
file_MVER *version;
|
||||||
FileLoader();
|
FileLoader();
|
||||||
~FileLoader();
|
~FileLoader();
|
||||||
bool loadFile(char *filename, bool log = true);
|
bool loadFile(std::string const& filename, bool log = true);
|
||||||
virtual void free();
|
virtual void free();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||||
#define MMAP_VERSION 3
|
#define MMAP_VERSION 6
|
||||||
|
|
||||||
struct MmapTileHeader
|
struct MmapTileHeader
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace DisableMgr
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||||
#define MMAP_VERSION 3
|
#define MMAP_VERSION 6
|
||||||
|
|
||||||
struct MmapTileHeader
|
struct MmapTileHeader
|
||||||
{
|
{
|
||||||
@@ -32,12 +32,22 @@ struct MmapTileHeader
|
|||||||
uint32 dtVersion;
|
uint32 dtVersion;
|
||||||
uint32 mmapVersion;
|
uint32 mmapVersion;
|
||||||
uint32 size;
|
uint32 size;
|
||||||
bool usesLiquids : 1;
|
char usesLiquids;
|
||||||
|
char padding[3];
|
||||||
|
|
||||||
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
||||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
|
||||||
|
static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
|
||||||
|
static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
|
||||||
|
sizeof(MmapTileHeader::dtVersion) +
|
||||||
|
sizeof(MmapTileHeader::mmapVersion) +
|
||||||
|
sizeof(MmapTileHeader::size) +
|
||||||
|
sizeof(MmapTileHeader::usesLiquids) +
|
||||||
|
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
|
||||||
|
|
||||||
namespace MMAP
|
namespace MMAP
|
||||||
{
|
{
|
||||||
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
|
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
|
||||||
@@ -57,6 +67,10 @@ namespace MMAP
|
|||||||
|
|
||||||
m_rcContext = new rcContext(false);
|
m_rcContext = new rcContext(false);
|
||||||
|
|
||||||
|
// percentageDone - Initializing
|
||||||
|
m_totalTiles = 0;
|
||||||
|
m_totalTilesBuilt = 0;
|
||||||
|
|
||||||
discoverTiles();
|
discoverTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,8 +79,8 @@ namespace MMAP
|
|||||||
{
|
{
|
||||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||||
{
|
{
|
||||||
(*it).second->clear();
|
(*it).m_tiles->clear();
|
||||||
delete (*it).second;
|
delete (*it).m_tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_terrainBuilder;
|
delete m_terrainBuilder;
|
||||||
@@ -85,9 +99,9 @@ namespace MMAP
|
|||||||
for (uint32 i = 0; i < files.size(); ++i)
|
for (uint32 i = 0; i < files.size(); ++i)
|
||||||
{
|
{
|
||||||
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
||||||
if (m_tiles.find(mapID) == m_tiles.end())
|
if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
|
||||||
{
|
{
|
||||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
|
m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,8 +111,11 @@ namespace MMAP
|
|||||||
for (uint32 i = 0; i < files.size(); ++i)
|
for (uint32 i = 0; i < files.size(); ++i)
|
||||||
{
|
{
|
||||||
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
||||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
|
if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
|
||||||
count++;
|
{
|
||||||
|
m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("found %u.\n", count);
|
printf("found %u.\n", count);
|
||||||
|
|
||||||
@@ -106,8 +123,8 @@ namespace MMAP
|
|||||||
printf("Discovering tiles... ");
|
printf("Discovering tiles... ");
|
||||||
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
|
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
|
||||||
{
|
{
|
||||||
std::set<uint32>* tiles = (*itr).second;
|
std::set<uint32>* tiles = (*itr).m_tiles;
|
||||||
mapID = (*itr).first;
|
mapID = (*itr).m_mapId;
|
||||||
|
|
||||||
sprintf(filter, "%03u*.vmtile", mapID);
|
sprintf(filter, "%03u*.vmtile", mapID);
|
||||||
files.clear();
|
files.clear();
|
||||||
@@ -136,17 +153,20 @@ namespace MMAP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("found %u.\n\n", count);
|
printf("found %u.\n\n", count);
|
||||||
|
|
||||||
|
// percentageDone - total tiles to process
|
||||||
|
m_totalTiles = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
|
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
|
||||||
{
|
{
|
||||||
TileList::iterator itr = m_tiles.find(mapID);
|
TileList::iterator itr = std::find(m_tiles.begin(), m_tiles.end(), mapID);
|
||||||
if (itr != m_tiles.end())
|
if (itr != m_tiles.end())
|
||||||
return (*itr).second;
|
return (*itr).m_tiles;
|
||||||
|
|
||||||
std::set<uint32>* tiles = new std::set<uint32>();
|
std::set<uint32>* tiles = new std::set<uint32>();
|
||||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, tiles));
|
m_tiles.emplace_back(MapTiles(mapID, tiles));
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,9 +177,14 @@ namespace MMAP
|
|||||||
|
|
||||||
BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL;
|
BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL;
|
||||||
|
|
||||||
|
m_tiles.sort([](MapTiles a, MapTiles b)
|
||||||
|
{
|
||||||
|
return a.m_tiles->size() > b.m_tiles->size();
|
||||||
|
});
|
||||||
|
|
||||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||||
{
|
{
|
||||||
uint32 mapID = it->first;
|
uint32 mapID = it->m_mapId;
|
||||||
if (!shouldSkipMap(mapID))
|
if (!shouldSkipMap(mapID))
|
||||||
{
|
{
|
||||||
if (threads > 0)
|
if (threads > 0)
|
||||||
@@ -382,7 +407,8 @@ namespace MMAP
|
|||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
|
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
|
||||||
{
|
{
|
||||||
printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY);
|
// percentageDone - added, now it will show addional reference percentage done of the overall process
|
||||||
|
printf("%u%% [Map %03i] Building tile [%02u,%02u]\n", percentageDone(m_totalTiles, m_totalTilesBuilt), mapID, tileX, tileY);
|
||||||
|
|
||||||
MeshData meshData;
|
MeshData meshData;
|
||||||
|
|
||||||
@@ -416,6 +442,9 @@ namespace MMAP
|
|||||||
|
|
||||||
// build navmesh tile
|
// build navmesh tile
|
||||||
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
|
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
|
||||||
|
|
||||||
|
// percentageDone - increment tiles built
|
||||||
|
m_totalTilesBuilt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@@ -971,4 +1000,12 @@ namespace MMAP
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt)
|
||||||
|
{
|
||||||
|
if (totalTiles)
|
||||||
|
return totalTilesBuilt * 100 / totalTiles;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <atomic>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include "TerrainBuilder.h"
|
#include "TerrainBuilder.h"
|
||||||
#include "IntermediateValues.h"
|
#include "IntermediateValues.h"
|
||||||
@@ -27,7 +29,24 @@ using namespace VMAP;
|
|||||||
|
|
||||||
namespace MMAP
|
namespace MMAP
|
||||||
{
|
{
|
||||||
typedef std::map<uint32, std::set<uint32>*> TileList;
|
struct MapTiles
|
||||||
|
{
|
||||||
|
MapTiles() : m_mapId(uint32(-1)), m_tiles(NULL) {}
|
||||||
|
|
||||||
|
MapTiles(uint32 id, std::set<uint32>* tiles) : m_mapId(id), m_tiles(tiles) {}
|
||||||
|
~MapTiles() {}
|
||||||
|
|
||||||
|
uint32 m_mapId;
|
||||||
|
std::set<uint32>* m_tiles;
|
||||||
|
|
||||||
|
bool operator==(uint32 id)
|
||||||
|
{
|
||||||
|
return m_mapId == id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<MapTiles> TileList;
|
||||||
|
|
||||||
struct Tile
|
struct Tile
|
||||||
{
|
{
|
||||||
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
|
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
|
||||||
@@ -96,6 +115,8 @@ namespace MMAP
|
|||||||
bool shouldSkipMap(uint32 mapID);
|
bool shouldSkipMap(uint32 mapID);
|
||||||
bool isTransportMap(uint32 mapID);
|
bool isTransportMap(uint32 mapID);
|
||||||
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
|
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||||
|
// percentageDone - method to calculate percentage
|
||||||
|
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone);
|
||||||
|
|
||||||
TerrainBuilder* m_terrainBuilder;
|
TerrainBuilder* m_terrainBuilder;
|
||||||
TileList m_tiles;
|
TileList m_tiles;
|
||||||
@@ -109,6 +130,9 @@ namespace MMAP
|
|||||||
|
|
||||||
float m_maxWalkableAngle;
|
float m_maxWalkableAngle;
|
||||||
bool m_bigBaseUnit;
|
bool m_bigBaseUnit;
|
||||||
|
// percentageDone - variables to calculate percentage
|
||||||
|
uint32 m_totalTiles;
|
||||||
|
std::atomic<uint32> m_totalTilesBuilt;
|
||||||
|
|
||||||
// build performance - not really used for now
|
// build performance - not really used for now
|
||||||
rcContext* m_rcContext;
|
rcContext* m_rcContext;
|
||||||
|
|||||||
@@ -9,9 +9,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ace/OS_NS_sys_time.h>
|
|
||||||
|
|
||||||
#include "Define.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -125,26 +124,6 @@ namespace MMAP
|
|||||||
|
|
||||||
return LISTFILE_OK;
|
return LISTFILE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 getMSTime()
|
|
||||||
{
|
|
||||||
static const ACE_Time_Value ApplicationStartTime = ACE_OS::gettimeofday();
|
|
||||||
return (ACE_OS::gettimeofday() - ApplicationStartTime).msec();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
|
|
||||||
{
|
|
||||||
// getMSTime() have limited data range and this is case when it overflow in this tick
|
|
||||||
if (oldMSTime > newMSTime)
|
|
||||||
return (0xFFFFFFFF - oldMSTime) + newMSTime;
|
|
||||||
else
|
|
||||||
return newMSTime - oldMSTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
|
|
||||||
{
|
|
||||||
return getMSTimeDiff(oldMSTime, getMSTime());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "PathCommon.h"
|
#include "PathCommon.h"
|
||||||
#include "MapBuilder.h"
|
#include "MapBuilder.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
using namespace MMAP;
|
using namespace MMAP;
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ struct map_liquidHeader
|
|||||||
namespace MMAP
|
namespace MMAP
|
||||||
{
|
{
|
||||||
|
|
||||||
char const* MAP_VERSION_MAGIC = "v1.3";
|
char const* MAP_VERSION_MAGIC = "v1.8";
|
||||||
|
|
||||||
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
|
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
|
||||||
TerrainBuilder::~TerrainBuilder() { }
|
TerrainBuilder::~TerrainBuilder() { }
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#ifndef LOAD_LIB_H
|
#ifndef LOAD_LIB_H
|
||||||
#define LOAD_LIB_H
|
#define LOAD_LIB_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
typedef __int64 int64;
|
typedef __int64 int64;
|
||||||
typedef __int32 int32;
|
typedef __int32 int32;
|
||||||
@@ -59,7 +61,7 @@ public:
|
|||||||
file_MVER *version;
|
file_MVER *version;
|
||||||
FileLoader();
|
FileLoader();
|
||||||
~FileLoader();
|
~FileLoader();
|
||||||
bool loadFile(char *filename, bool log = true);
|
bool loadFile(std::string const& filename, bool log = true);
|
||||||
virtual void free();
|
virtual void free();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -84,17 +84,31 @@ bool Model::ConvertToVMAPModel(const char * outfilename)
|
|||||||
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
|
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
|
||||||
fwrite(&wsize, sizeof(int), 1, output);
|
fwrite(&wsize, sizeof(int), 1, output);
|
||||||
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
||||||
if (nIndexes >0)
|
if (nIndexes > 0)
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < nIndexes; ++i)
|
||||||
|
{
|
||||||
|
if ((i % 3) - 1 == 0 && i + 1 < nIndexes)
|
||||||
|
{
|
||||||
|
uint16 tmp = indices[i];
|
||||||
|
indices[i] = indices[i + 1];
|
||||||
|
indices[i + 1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
fwrite(indices, sizeof(unsigned short), nIndexes, output);
|
fwrite(indices, sizeof(unsigned short), nIndexes, output);
|
||||||
|
}
|
||||||
fwrite("VERT", 4, 1, output);
|
fwrite("VERT", 4, 1, output);
|
||||||
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
||||||
fwrite(&wsize, sizeof(int), 1, output);
|
fwrite(&wsize, sizeof(int), 1, output);
|
||||||
fwrite(&nVertices, sizeof(int), 1, output);
|
fwrite(&nVertices, sizeof(int), 1, output);
|
||||||
if (nVertices >0)
|
if (nVertices >0)
|
||||||
{
|
{
|
||||||
for(uint32 vpos=0; vpos <nVertices; ++vpos)
|
for (uint32 vpos = 0; vpos < nVertices; ++vpos)
|
||||||
std::swap(vertices[vpos].y, vertices[vpos].z);
|
{
|
||||||
|
float tmp = vertices[vpos].y;
|
||||||
|
vertices[vpos].y = -vertices[vpos].z;
|
||||||
|
vertices[vpos].z = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
fwrite(vertices, sizeof(float)*3, nVertices, output);
|
fwrite(vertices, sizeof(float)*3, nVertices, output);
|
||||||
}
|
}
|
||||||
@@ -169,7 +183,6 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID
|
|||||||
int realy1 = (int) ((float) pos.z / 533.333333f);
|
int realy1 = (int) ((float) pos.z / 533.333333f);
|
||||||
int realx2 = (int) ((float) pos.x / 533.333333f);
|
int realx2 = (int) ((float) pos.x / 533.333333f);
|
||||||
int realy2 = (int) ((float) pos.z / 533.333333f);
|
int realy2 = (int) ((float) pos.z / 533.333333f);
|
||||||
|
|
||||||
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
|
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
|
||||||
MapName,
|
MapName,
|
||||||
ModelInstName,
|
ModelInstName,
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
|||||||
if(SERVERS AND NOT NOJEM)
|
if(SERVERS AND NOT NOJEM)
|
||||||
add_subdirectory(jemalloc)
|
add_subdirectory(jemalloc)
|
||||||
endif()
|
endif()
|
||||||
|
if(TOOLS)
|
||||||
|
add_subdirectory(bzip2)
|
||||||
|
endif()
|
||||||
|
add_subdirectory(zlib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (C)
|
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||||
#
|
#
|
||||||
# This file is free software; as a special exception the author gives
|
# This file is free software; as a special exception the author gives
|
||||||
# unlimited permission to copy and/or distribute it, with or without
|
# unlimited permission to copy and/or distribute it, with or without
|
||||||
@@ -9,20 +9,25 @@
|
|||||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
set(Detour_STAT_SRCS
|
set(Detour_STAT_SRCS
|
||||||
DetourAlloc.cpp
|
Source/DetourAlloc.cpp
|
||||||
DetourCommon.cpp
|
Source/DetourCommon.cpp
|
||||||
DetourNavMesh.cpp
|
Source/DetourNavMesh.cpp
|
||||||
DetourNavMeshBuilder.cpp
|
Source/DetourNavMeshBuilder.cpp
|
||||||
DetourNavMeshQuery.cpp
|
Source/DetourNavMeshQuery.cpp
|
||||||
DetourNode.cpp
|
Source/DetourNode.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
include_directories(
|
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/zlib
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(Detour STATIC ${Detour_STAT_SRCS})
|
add_library(Detour STATIC ${Detour_STAT_SRCS})
|
||||||
|
|
||||||
target_link_libraries(Detour ${ZLIB_LIBRARIES})
|
target_include_directories(Detour
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Include)
|
||||||
|
|
||||||
|
target_link_libraries(Detour
|
||||||
|
PUBLIC
|
||||||
|
zlib)
|
||||||
|
|
||||||
|
set_target_properties(Detour
|
||||||
|
PROPERTIES
|
||||||
|
FOLDER
|
||||||
|
"dep")
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURALLOCATOR_H
|
|
||||||
#define DETOURALLOCATOR_H
|
|
||||||
|
|
||||||
enum dtAllocHint
|
|
||||||
{
|
|
||||||
DT_ALLOC_PERM, // Memory persist after a function call.
|
|
||||||
DT_ALLOC_TEMP // Memory used temporarily within a function.
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void* (dtAllocFunc)(int size, dtAllocHint hint);
|
|
||||||
typedef void (dtFreeFunc)(void* ptr);
|
|
||||||
|
|
||||||
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
|
||||||
|
|
||||||
void* dtAlloc(int size, dtAllocHint hint);
|
|
||||||
void dtFree(void* ptr);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURCOMMON_H
|
|
||||||
#define DETOURCOMMON_H
|
|
||||||
|
|
||||||
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
|
||||||
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
|
||||||
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
|
||||||
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
|
||||||
template<class T> inline T dtSqr(T a) { return a*a; }
|
|
||||||
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
|
||||||
|
|
||||||
float dtSqrt(float x);
|
|
||||||
|
|
||||||
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
|
||||||
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
|
||||||
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVdot(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+v2[0]*s;
|
|
||||||
dest[1] = v1[1]+v2[1]*s;
|
|
||||||
dest[2] = v1[2]+v2[2]*s;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
|
||||||
dest[1] = v1[1]+(v2[1]-v1[1])*t;
|
|
||||||
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]+v2[0];
|
|
||||||
dest[1] = v1[1]+v2[1];
|
|
||||||
dest[2] = v1[2]+v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
dest[0] = v1[0]-v2[0];
|
|
||||||
dest[1] = v1[1]-v2[1];
|
|
||||||
dest[2] = v1[2]-v2[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVscale(float* dest, const float* v, const float t)
|
|
||||||
{
|
|
||||||
dest[0] = v[0]*t;
|
|
||||||
dest[1] = v[1]*t;
|
|
||||||
dest[2] = v[2]*t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVmin(float* mn, const float* v)
|
|
||||||
{
|
|
||||||
mn[0] = dtMin(mn[0], v[0]);
|
|
||||||
mn[1] = dtMin(mn[1], v[1]);
|
|
||||||
mn[2] = dtMin(mn[2], v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVmax(float* mx, const float* v)
|
|
||||||
{
|
|
||||||
mx[0] = dtMax(mx[0], v[0]);
|
|
||||||
mx[1] = dtMax(mx[1], v[1]);
|
|
||||||
mx[2] = dtMax(mx[2], v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVset(float* dest, const float x, const float y, const float z)
|
|
||||||
{
|
|
||||||
dest[0] = x; dest[1] = y; dest[2] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVcopy(float* dest, const float* a)
|
|
||||||
{
|
|
||||||
dest[0] = a[0];
|
|
||||||
dest[1] = a[1];
|
|
||||||
dest[2] = a[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVlen(const float* v)
|
|
||||||
{
|
|
||||||
return dtSqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVlenSqr(const float* v)
|
|
||||||
{
|
|
||||||
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVdist(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dy = v2[1] - v1[1];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dtSqrt(dx*dx + dy*dy + dz*dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVdistSqr(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dy = v2[1] - v1[1];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dx*dx + dy*dy + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVdist2D(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dtSqrt(dx*dx + dz*dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
|
||||||
{
|
|
||||||
const float dx = v2[0] - v1[0];
|
|
||||||
const float dz = v2[2] - v1[2];
|
|
||||||
return dx*dx + dz*dz;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dtVnormalize(float* v)
|
|
||||||
{
|
|
||||||
float d = 1.0f / dtSqrt(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
|
||||||
v[0] *= d;
|
|
||||||
v[1] *= d;
|
|
||||||
v[2] *= d;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool dtVequal(const float* p0, const float* p1)
|
|
||||||
{
|
|
||||||
static const float thr = dtSqr(1.0f/16384.0f);
|
|
||||||
const float d = dtVdistSqr(p0, p1);
|
|
||||||
return d < thr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int dtNextPow2(unsigned int v)
|
|
||||||
{
|
|
||||||
v--;
|
|
||||||
v |= v >> 1;
|
|
||||||
v |= v >> 2;
|
|
||||||
v |= v >> 4;
|
|
||||||
v |= v >> 8;
|
|
||||||
v |= v >> 16;
|
|
||||||
v++;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int dtIlog2(unsigned int v)
|
|
||||||
{
|
|
||||||
unsigned int r;
|
|
||||||
unsigned int shift;
|
|
||||||
r = (v > 0xffff) << 4; v >>= r;
|
|
||||||
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
|
||||||
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
|
||||||
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
|
||||||
r |= (v >> 1);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int dtAlign4(int x) { return (x+3) & ~3; }
|
|
||||||
|
|
||||||
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
|
||||||
|
|
||||||
inline float dtVdot2D(const float* u, const float* v)
|
|
||||||
{
|
|
||||||
return u[0]*v[0] + u[2]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtVperp2D(const float* u, const float* v)
|
|
||||||
{
|
|
||||||
return u[2]*v[0] - u[0]*v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
|
||||||
{
|
|
||||||
const float abx = b[0] - a[0];
|
|
||||||
const float abz = b[2] - a[2];
|
|
||||||
const float acx = c[0] - a[0];
|
|
||||||
const float acz = c[2] - a[2];
|
|
||||||
return acx*abz - abx*acz;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
|
||||||
const unsigned short bmin[3], const unsigned short bmax[3])
|
|
||||||
{
|
|
||||||
bool overlap = true;
|
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
|
||||||
const float* bmin, const float* bmax)
|
|
||||||
{
|
|
||||||
bool overlap = true;
|
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
|
||||||
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
|
||||||
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
|
||||||
return overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
|
||||||
const float* a, const float* b, const float* c);
|
|
||||||
|
|
||||||
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
|
||||||
|
|
||||||
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
|
||||||
const float* verts, int nverts,
|
|
||||||
float& tmin, float& tmax,
|
|
||||||
int& segMin, int& segMax);
|
|
||||||
|
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
|
||||||
|
|
||||||
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
|
||||||
float* ed, float* et);
|
|
||||||
|
|
||||||
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
|
||||||
|
|
||||||
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
|
||||||
|
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
|
||||||
const float* polyb, const int npolyb);
|
|
||||||
|
|
||||||
#endif // DETOURCOMMON_H
|
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESH_H
|
|
||||||
#define DETOURNAVMESH_H
|
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
typedef unsigned __int64 uint64;
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#ifndef uint64_t
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <linux/types.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
|
||||||
// It is also recommended to change dtHashRef() to proper 64-bit hash too.
|
|
||||||
|
|
||||||
// Reference to navigation polygon.
|
|
||||||
typedef uint64 dtPolyRef;
|
|
||||||
|
|
||||||
// Reference to navigation mesh tile.
|
|
||||||
typedef uint64 dtTileRef;
|
|
||||||
|
|
||||||
// Maximum number of vertices per navigation polygon.
|
|
||||||
static const int DT_VERTS_PER_POLYGON = 6;
|
|
||||||
|
|
||||||
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V'; //'DNAV';
|
|
||||||
static const int DT_NAVMESH_VERSION = 6;
|
|
||||||
|
|
||||||
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S'; //'DNMS';
|
|
||||||
static const int DT_NAVMESH_STATE_VERSION = 1;
|
|
||||||
|
|
||||||
static const unsigned short DT_EXT_LINK = 0x8000;
|
|
||||||
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
|
||||||
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
|
||||||
|
|
||||||
static const int DT_MAX_AREAS = 64;
|
|
||||||
|
|
||||||
static const int STATIC_SALT_BITS = 12;
|
|
||||||
static const int STATIC_TILE_BITS = 21;
|
|
||||||
static const int STATIC_POLY_BITS = 31;
|
|
||||||
// we cannot have over 31 bits for either tile nor poly
|
|
||||||
// without changing polyCount to use 64bits too.
|
|
||||||
|
|
||||||
// Flags for addTile
|
|
||||||
enum dtTileFlags
|
|
||||||
{
|
|
||||||
DT_TILE_FREE_DATA = 0x01, // Navmesh owns the tile memory and should free it.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Flags returned by findStraightPath().
|
|
||||||
enum dtStraightPathFlags
|
|
||||||
{
|
|
||||||
DT_STRAIGHTPATH_START = 0x01, // The vertex is the start position.
|
|
||||||
DT_STRAIGHTPATH_END = 0x02, // The vertex is the end position.
|
|
||||||
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, // The vertex is start of an off-mesh link.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Flags describing polygon properties.
|
|
||||||
enum dtPolyTypes
|
|
||||||
{
|
|
||||||
DT_POLYTYPE_GROUND = 0, // Regular ground polygons.
|
|
||||||
DT_POLYTYPE_OFFMESH_CONNECTION = 1, // Off-mesh connections.
|
|
||||||
};
|
|
||||||
|
|
||||||
enum dtStatus
|
|
||||||
{
|
|
||||||
DT_FAILURE = 0, // Operation failed.
|
|
||||||
DT_FAILURE_DATA_MAGIC,
|
|
||||||
DT_FAILURE_DATA_VERSION,
|
|
||||||
DT_FAILURE_OUT_OF_MEMORY,
|
|
||||||
DT_SUCCESS, // Operation succeed.
|
|
||||||
DT_IN_PROGRESS, // Operation still in progress.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Structure describing the navigation polygon data.
|
|
||||||
struct dtPoly
|
|
||||||
{
|
|
||||||
unsigned int firstLink; // Index to first link in linked list.
|
|
||||||
unsigned short verts[DT_VERTS_PER_POLYGON]; // Indices to vertices of the poly.
|
|
||||||
unsigned short neis[DT_VERTS_PER_POLYGON]; // Refs to neighbours of the poly.
|
|
||||||
unsigned short flags; // Flags (see dtPolyFlags).
|
|
||||||
unsigned char vertCount; // Number of vertices.
|
|
||||||
unsigned char areaAndtype; // Bit packed: Area ID of the polygon, and Polygon type, see dtPolyTypes..
|
|
||||||
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
|
||||||
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
|
||||||
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
|
||||||
inline unsigned char getType() const { return areaAndtype >> 6; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stucture describing polygon detail triangles.
|
|
||||||
struct dtPolyDetail
|
|
||||||
{
|
|
||||||
unsigned int vertBase; // Offset to detail vertex array.
|
|
||||||
unsigned int triBase; // Offset to detail triangle array.
|
|
||||||
unsigned char vertCount; // Number of vertices in the detail mesh.
|
|
||||||
unsigned char triCount; // Number of triangles.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stucture describing a link to another polygon.
|
|
||||||
struct dtLink
|
|
||||||
{
|
|
||||||
dtPolyRef ref; // Neighbour reference.
|
|
||||||
unsigned int next; // Index to next link.
|
|
||||||
unsigned char edge; // Index to polygon edge which owns this link.
|
|
||||||
unsigned char side; // If boundary link, defines on which side the link is.
|
|
||||||
unsigned char bmin, bmax; // If boundary link, defines the sub edge area.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtBVNode
|
|
||||||
{
|
|
||||||
unsigned short bmin[3], bmax[3]; // BVnode bounds
|
|
||||||
int i; // Index to item or if negative, escape index.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtOffMeshConnection
|
|
||||||
{
|
|
||||||
float pos[6]; // Both end point locations.
|
|
||||||
float rad; // Link connection radius.
|
|
||||||
unsigned short poly; // Poly Id
|
|
||||||
unsigned char flags; // Link flags
|
|
||||||
unsigned char side; // End point side.
|
|
||||||
unsigned int userId; // User ID to identify this connection.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtMeshHeader
|
|
||||||
{
|
|
||||||
int magic; // Magic number, used to identify the data.
|
|
||||||
int version; // Data version number.
|
|
||||||
int x, y; // Location of the time on the grid.
|
|
||||||
unsigned int userId; // User ID of the tile.
|
|
||||||
int polyCount; // Number of polygons in the tile.
|
|
||||||
int vertCount; // Number of vertices in the tile.
|
|
||||||
int maxLinkCount; // Number of allocated links.
|
|
||||||
int detailMeshCount; // Number of detail meshes.
|
|
||||||
int detailVertCount; // Number of detail vertices.
|
|
||||||
int detailTriCount; // Number of detail triangles.
|
|
||||||
int bvNodeCount; // Number of BVtree nodes.
|
|
||||||
int offMeshConCount; // Number of Off-Mesh links.
|
|
||||||
int offMeshBase; // Index to first polygon which is Off-Mesh link.
|
|
||||||
float walkableHeight; // Height of the agent.
|
|
||||||
float walkableRadius; // Radius of the agent
|
|
||||||
float walkableClimb; // Max climb height of the agent.
|
|
||||||
float bmin[3], bmax[3]; // Bounding box of the tile.
|
|
||||||
float bvQuantFactor; // BVtree quantization factor (world to bvnode coords)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtMeshTile
|
|
||||||
{
|
|
||||||
unsigned int salt; // Counter describing modifications to the tile.
|
|
||||||
|
|
||||||
unsigned int linksFreeList; // Index to next free link.
|
|
||||||
dtMeshHeader* header; // Pointer to tile header.
|
|
||||||
dtPoly* polys; // Pointer to the polygons (will be updated when tile is added).
|
|
||||||
float* verts; // Pointer to the vertices (will be updated when tile added).
|
|
||||||
dtLink* links; // Pointer to the links (will be updated when tile added).
|
|
||||||
dtPolyDetail* detailMeshes; // Pointer to detail meshes (will be updated when tile added).
|
|
||||||
float* detailVerts; // Pointer to detail vertices (will be updated when tile added).
|
|
||||||
unsigned char* detailTris; // Pointer to detail triangles (will be updated when tile added).
|
|
||||||
dtBVNode* bvTree; // Pointer to BVtree nodes (will be updated when tile added).
|
|
||||||
dtOffMeshConnection* offMeshCons; // Pointer to Off-Mesh links. (will be updated when tile added).
|
|
||||||
|
|
||||||
unsigned char* data; // Pointer to tile data.
|
|
||||||
int dataSize; // Size of the tile data.
|
|
||||||
int flags; // Tile flags, see dtTileFlags.
|
|
||||||
dtMeshTile* next; // Next free tile or, next tile in spatial grid.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtNavMeshParams
|
|
||||||
{
|
|
||||||
float orig[3]; // Origin of the nav mesh tile space.
|
|
||||||
float tileWidth, tileHeight; // Width and height of each tile.
|
|
||||||
int maxTiles; // Maximum number of tiles the navmesh can contain.
|
|
||||||
int maxPolys; // Maximum number of polygons each tile can contain.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class dtNavMesh
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNavMesh();
|
|
||||||
~dtNavMesh();
|
|
||||||
|
|
||||||
// Initializes the nav mesh for tiled use.
|
|
||||||
// Params:
|
|
||||||
// params - (in) navmesh initialization params, see dtNavMeshParams.
|
|
||||||
// Returns: True if succeed, else false.
|
|
||||||
dtStatus init(const dtNavMeshParams* params);
|
|
||||||
|
|
||||||
// Initializes the nav mesh for single tile use.
|
|
||||||
// Params:
|
|
||||||
// data - (in) Data of the new tile mesh.
|
|
||||||
// dataSize - (in) Data size of the new tile mesh.
|
|
||||||
// flags - (in) Tile flags, see dtTileFlags.
|
|
||||||
// Returns: True if succeed, else false.
|
|
||||||
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
|
||||||
|
|
||||||
// Returns pointer to navmesh initialization params.
|
|
||||||
const dtNavMeshParams* getParams() const;
|
|
||||||
|
|
||||||
// Adds new tile into the navmesh.
|
|
||||||
// The add will fail if the data is in wrong format,
|
|
||||||
// there is not enough tiles left, or if there is a tile already at the location.
|
|
||||||
// Params:
|
|
||||||
// data - (in) Data of the new tile mesh.
|
|
||||||
// dataSize - (in) Data size of the new tile mesh.
|
|
||||||
// flags - (in) Tile flags, see dtTileFlags.
|
|
||||||
// lastRef - (in,optional) Last tile ref, the tile will be restored so that
|
|
||||||
// the reference (as well as poly references) will be the same. Default: 0.
|
|
||||||
// result - (out,optional) tile ref if the tile was succesfully added.
|
|
||||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
|
||||||
|
|
||||||
// Removes specified tile.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) Reference to the tile to remove.
|
|
||||||
// data - (out) Data associated with deleted tile.
|
|
||||||
// dataSize - (out) Size of the data associated with deleted tile.
|
|
||||||
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
|
||||||
|
|
||||||
// Calculates tile location based in input world position.
|
|
||||||
// Params:
|
|
||||||
// pos - (in) world position of the query.
|
|
||||||
// tx - (out) tile x location.
|
|
||||||
// ty - (out) tile y location.
|
|
||||||
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
|
||||||
|
|
||||||
// Returns pointer to tile at specified location.
|
|
||||||
// Params:
|
|
||||||
// x,y - (in) Location of the tile to get.
|
|
||||||
// Returns: pointer to tile if tile exists or 0 tile does not exists.
|
|
||||||
const dtMeshTile* getTileAt(int x, int y) const;
|
|
||||||
|
|
||||||
// Returns reference to tile at specified location.
|
|
||||||
// Params:
|
|
||||||
// x,y - (in) Location of the tile to get.
|
|
||||||
// Returns: reference to tile if tile exists or 0 tile does not exists.
|
|
||||||
dtTileRef getTileRefAt(int x, int y) const;
|
|
||||||
|
|
||||||
// Returns tile references of a tile based on tile pointer.
|
|
||||||
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
// Returns tile based on references.
|
|
||||||
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
|
||||||
|
|
||||||
// Returns max number of tiles.
|
|
||||||
int getMaxTiles() const;
|
|
||||||
|
|
||||||
// Returns pointer to tile in the tile array.
|
|
||||||
// Params:
|
|
||||||
// i - (in) Index to the tile to retrieve, max index is getMaxTiles()-1.
|
|
||||||
// Returns: Pointer to specified tile.
|
|
||||||
const dtMeshTile* getTile(int i) const;
|
|
||||||
|
|
||||||
// Returns pointer to tile and polygon pointed by the polygon reference.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) reference to a polygon.
|
|
||||||
// tile - (out) pointer to the tile containing the polygon.
|
|
||||||
// poly - (out) pointer to the polygon.
|
|
||||||
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
|
||||||
|
|
||||||
// Returns pointer to tile and polygon pointed by the polygon reference.
|
|
||||||
// Note: this function does not check if 'ref' s valid, and is thus faster. Use only with valid refs!
|
|
||||||
// Params:
|
|
||||||
// ref - (in) reference to a polygon.
|
|
||||||
// tile - (out) pointer to the tile containing the polygon.
|
|
||||||
// poly - (out) pointer to the polygon.
|
|
||||||
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
|
||||||
|
|
||||||
// Returns true if polygon reference points to valid data.
|
|
||||||
bool isValidPolyRef(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
// Returns base poly id for specified tile, polygon refs can be deducted from this.
|
|
||||||
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
// Returns start and end location of an off-mesh link polygon.
|
|
||||||
// Params:
|
|
||||||
// prevRef - (in) ref to the polygon before the link (used to select direction).
|
|
||||||
// polyRef - (in) ref to the off-mesh link polygon.
|
|
||||||
// startPos[3] - (out) start point of the link.
|
|
||||||
// endPos[3] - (out) end point of the link.
|
|
||||||
// Returns: true if link is found.
|
|
||||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
|
||||||
|
|
||||||
// Returns pointer to off-mesh connection based on polyref, or null if ref not valid.
|
|
||||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
// Sets polygon flags.
|
|
||||||
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
|
||||||
|
|
||||||
// Return polygon flags.
|
|
||||||
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
|
||||||
|
|
||||||
// Set polygon type.
|
|
||||||
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
|
||||||
|
|
||||||
// Return polygon area type.
|
|
||||||
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
|
||||||
|
|
||||||
|
|
||||||
// Returns number of bytes required to store tile state.
|
|
||||||
int getTileStateSize(const dtMeshTile* tile) const;
|
|
||||||
|
|
||||||
// Stores tile state to buffer.
|
|
||||||
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
|
||||||
|
|
||||||
// Restores tile state.
|
|
||||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
|
||||||
|
|
||||||
|
|
||||||
// Encodes a tile id.
|
|
||||||
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
|
||||||
{
|
|
||||||
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes a tile id.
|
|
||||||
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
|
||||||
{
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
|
||||||
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
|
||||||
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
|
||||||
ip = (unsigned int)(ref & polyMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes a tile salt.
|
|
||||||
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
|
||||||
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes a tile id.
|
|
||||||
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
|
||||||
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes a poly id.
|
|
||||||
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
|
||||||
{
|
|
||||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
|
||||||
return (unsigned int)(ref & polyMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Returns pointer to tile in the tile array.
|
|
||||||
dtMeshTile* getTile(int i);
|
|
||||||
|
|
||||||
// Returns neighbour tile based on side.
|
|
||||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
|
||||||
// Returns all polygons in neighbour tile based on portal defined by the segment.
|
|
||||||
int findConnectingPolys(const float* va, const float* vb,
|
|
||||||
const dtMeshTile* tile, int side,
|
|
||||||
dtPolyRef* con, float* conarea, int maxcon) const;
|
|
||||||
|
|
||||||
// Builds internal polygons links for a tile.
|
|
||||||
void connectIntLinks(dtMeshTile* tile);
|
|
||||||
// Builds internal polygons links for a tile.
|
|
||||||
void connectIntOffMeshLinks(dtMeshTile* tile);
|
|
||||||
|
|
||||||
// Builds external polygon links for a tile.
|
|
||||||
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
|
||||||
// Builds external polygon links for a tile.
|
|
||||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
|
||||||
|
|
||||||
// Removes external links at specified side.
|
|
||||||
void unconnectExtLinks(dtMeshTile* tile, int side);
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
|
||||||
|
|
||||||
// Queries polygons within a tile.
|
|
||||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
|
||||||
dtPolyRef* polys, const int maxPolys) const;
|
|
||||||
// Find nearest polygon within a tile.
|
|
||||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
|
||||||
const float* extents, float* nearestPt) const;
|
|
||||||
// Returns closest point on polygon.
|
|
||||||
dtStatus closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
|
|
||||||
const float* pos, float* closest) const;
|
|
||||||
|
|
||||||
dtNavMeshParams m_params; // Current initialization params. TODO: do not store this info twice.
|
|
||||||
float m_orig[3]; // Origin of the tile (0,0)
|
|
||||||
float m_tileWidth, m_tileHeight; // Dimensions of each tile.
|
|
||||||
int m_maxTiles; // Max number of tiles.
|
|
||||||
int m_tileLutSize; // Tile hash lookup size (must be pot).
|
|
||||||
int m_tileLutMask; // Tile hash lookup mask.
|
|
||||||
|
|
||||||
dtMeshTile** m_posLookup; // Tile hash lookup.
|
|
||||||
dtMeshTile* m_nextFree; // Freelist of tiles.
|
|
||||||
dtMeshTile* m_tiles; // List of tiles.
|
|
||||||
|
|
||||||
unsigned int m_saltBits; // Number of salt bits in the tile ID.
|
|
||||||
unsigned int m_tileBits; // Number of tile bits in the tile ID.
|
|
||||||
unsigned int m_polyBits; // Number of poly bits in the tile ID.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to allocate navmesh class using Detour allocator.
|
|
||||||
dtNavMesh* dtAllocNavMesh();
|
|
||||||
void dtFreeNavMesh(dtNavMesh* navmesh);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESH_H
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESHBUILDER_H
|
|
||||||
#define DETOURNAVMESHBUILDER_H
|
|
||||||
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
|
|
||||||
|
|
||||||
// The units of the parameters are specified in parenthesis as follows:
|
|
||||||
// (vx) voxels, (wu) world units
|
|
||||||
struct dtNavMeshCreateParams
|
|
||||||
{
|
|
||||||
// Navmesh vertices.
|
|
||||||
const unsigned short* verts; // Array of vertices, each vertex has 3 components. (vx).
|
|
||||||
int vertCount; // Vertex count
|
|
||||||
// Navmesh polygons
|
|
||||||
const unsigned short* polys; // Array of polygons, uses same format as rcPolyMesh.
|
|
||||||
const unsigned short* polyFlags; // Array of flags per polygon.
|
|
||||||
const unsigned char* polyAreas; // Array of area ids per polygon.
|
|
||||||
int polyCount; // Number of polygons
|
|
||||||
int nvp; // Number of verts per polygon.
|
|
||||||
// Navmesh Detail
|
|
||||||
const unsigned int* detailMeshes; // Detail meshes, uses same format as rcPolyMeshDetail.
|
|
||||||
const float* detailVerts; // Detail mesh vertices, uses same format as rcPolyMeshDetail (wu).
|
|
||||||
int detailVertsCount; // Total number of detail vertices
|
|
||||||
const unsigned char* detailTris; // Array of detail tris per detail mesh.
|
|
||||||
int detailTriCount; // Total number of detail triangles.
|
|
||||||
// Off-Mesh Connections.
|
|
||||||
const float* offMeshConVerts; // Off-mesh connection vertices (wu).
|
|
||||||
const float* offMeshConRad; // Off-mesh connection radii (wu).
|
|
||||||
const unsigned short* offMeshConFlags; // Off-mesh connection flags.
|
|
||||||
const unsigned char* offMeshConAreas; // Off-mesh connection area ids.
|
|
||||||
const unsigned char* offMeshConDir; // Off-mesh connection direction flags (1 = bidir, 0 = oneway).
|
|
||||||
const unsigned int* offMeshConUserID; // Off-mesh connection user id (optional).
|
|
||||||
int offMeshConCount; // Number of off-mesh connections
|
|
||||||
// Tile location
|
|
||||||
unsigned int userId; // User ID bound to the tile.
|
|
||||||
int tileX, tileY; // Tile location (tile coords).
|
|
||||||
float bmin[3], bmax[3]; // Tile bounds (wu).
|
|
||||||
// Settings
|
|
||||||
float walkableHeight; // Agent height (wu).
|
|
||||||
float walkableRadius; // Agent radius (wu).
|
|
||||||
float walkableClimb; // Agent max climb (wu).
|
|
||||||
float cs; // Cell size (xz) (wu).
|
|
||||||
float ch; // Cell height (y) (wu).
|
|
||||||
int tileSize; // Tile size (width & height) (vx).
|
|
||||||
int tileLayer;
|
|
||||||
bool buildBvTree;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build navmesh data from given input data.
|
|
||||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
|
||||||
|
|
||||||
// Swaps endianess of navmesh header.
|
|
||||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
|
||||||
|
|
||||||
// Swaps endianess of the navmesh data. This function assumes that the header is in correct
|
|
||||||
// endianess already. Call dtNavMeshHeaderSwapEndian() first on the data if the data is
|
|
||||||
// assumed to be in wrong endianess to start with. If converting from native endianess to foreign,
|
|
||||||
// call dtNavMeshHeaderSwapEndian() after the data has been swapped.
|
|
||||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESHBUILDER_H
|
|
||||||
@@ -1,407 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOURNAVMESHQUERY_H
|
|
||||||
#define DETOURNAVMESHQUERY_H
|
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
|
||||||
// On certain platforms indirect or virtual function call is expensive. The default
|
|
||||||
// setting is to use non-virtual functions, the actualy implementations of the functions
|
|
||||||
// are declared as inline for maximum speed.
|
|
||||||
|
|
||||||
//#define DT_VIRTUAL_QUERYFILTER 1
|
|
||||||
|
|
||||||
// Class for polygon filtering and cost calculation during query operations.
|
|
||||||
// - It is possible to derive a custom query filter from dtQueryFilter by overriding
|
|
||||||
// the virtual functions passFilter() and getCost().
|
|
||||||
// - Both functions should be as fast as possible. Use cached local copy of data
|
|
||||||
// instead of accessing your own objects where possible.
|
|
||||||
// - You do not need to adhere to the flags and cost logic provided by the default
|
|
||||||
// implementation.
|
|
||||||
// - In order for the A* to work properly, the cost should be proportional to
|
|
||||||
// the travel distance. Using cost modifier less than 1.0 is likely to lead
|
|
||||||
// to problems during pathfinding.
|
|
||||||
class dtQueryFilter
|
|
||||||
{
|
|
||||||
float m_areaCost[DT_MAX_AREAS]; // Array storing cost per area type, used by default implementation.
|
|
||||||
unsigned short m_includeFlags; // Include poly flags, used by default implementation.
|
|
||||||
unsigned short m_excludeFlags; // Exclude poly flags, used by default implementation.
|
|
||||||
|
|
||||||
public:
|
|
||||||
dtQueryFilter();
|
|
||||||
|
|
||||||
// Returns true if the polygon is can visited.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) reference to the polygon test.
|
|
||||||
// tile - (in) pointer to the tile of the polygon test.
|
|
||||||
// poly - (in) pointer to the polygon test.
|
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
|
||||||
virtual bool passFilter(const dtPolyRef ref,
|
|
||||||
const dtMeshTile* tile,
|
|
||||||
const dtPoly* poly) const;
|
|
||||||
#else
|
|
||||||
bool passFilter(const dtPolyRef ref,
|
|
||||||
const dtMeshTile* tile,
|
|
||||||
const dtPoly* poly) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Returns cost to travel from 'pa' to 'pb'.'
|
|
||||||
// The segment is fully contained inside 'cur'.
|
|
||||||
// 'pa' lies on the edge between 'prev' and 'cur',
|
|
||||||
// 'pb' lies on the edge between 'cur' and 'next'.
|
|
||||||
// Params:
|
|
||||||
// pa - (in) segment start position.
|
|
||||||
// pb - (in) segment end position.
|
|
||||||
// prevRef, prevTile, prevPoly - (in) data describing the previous polygon, can be null.
|
|
||||||
// curRef, curTile, curPoly - (in) data describing the current polygon.
|
|
||||||
// nextRef, nextTile, nextPoly - (in) data describing the next polygon, can be null.
|
|
||||||
#ifdef DT_VIRTUAL_QUERYFILTER
|
|
||||||
virtual float getCost(const float* pa, const float* pb,
|
|
||||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
|
||||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
|
||||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
|
||||||
#else
|
|
||||||
float getCost(const float* pa, const float* pb,
|
|
||||||
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
|
||||||
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
|
||||||
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Getters and setters for the default implementation data.
|
|
||||||
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
|
||||||
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
|
||||||
|
|
||||||
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
|
||||||
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
|
||||||
|
|
||||||
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
|
||||||
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class dtNavMeshQuery
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtNavMeshQuery();
|
|
||||||
~dtNavMeshQuery();
|
|
||||||
|
|
||||||
// Initializes the nav mesh query.
|
|
||||||
// Params:
|
|
||||||
// nav - (in) pointer to navigation mesh data.
|
|
||||||
// maxNodes - (in) Maximum number of search nodes to use (max 65536).
|
|
||||||
// Returns: True if succeed, else false.
|
|
||||||
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
|
||||||
|
|
||||||
// Finds the nearest navigation polygon around the center location.
|
|
||||||
// Params:
|
|
||||||
// center[3] - (in) The center of the search box.
|
|
||||||
// extents[3] - (in) The extents of the search box.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// nearestRef - (out) Reference to the nearest polygon.
|
|
||||||
// nearestPt[3] - (out, opt) The nearest point on found polygon, null if not needed.
|
|
||||||
// Returns: Reference identifier for the polygon, or 0 if no polygons found.
|
|
||||||
dtStatus findNearestPoly(const float* center, const float* extents,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* nearestRef, float* nearestPt) const;
|
|
||||||
|
|
||||||
// Returns polygons which overlap the query box.
|
|
||||||
// Params:
|
|
||||||
// center[3] - (in) the center of the search box.
|
|
||||||
// extents[3] - (in) the extents of the search box.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// polys - (out) array holding the search result.
|
|
||||||
// polyCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPolys - (in) The max number of polygons the polys array can hold.
|
|
||||||
dtStatus queryPolygons(const float* center, const float* extents,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
|
||||||
|
|
||||||
// Finds path from start polygon to end polygon.
|
|
||||||
// If target polygon canno be reached through the navigation graph,
|
|
||||||
// the last node on the array is nearest node to the end polygon.
|
|
||||||
// Start end end positions are needed to calculate more accurate
|
|
||||||
// traversal cost at start end end polygons.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to path start polygon.
|
|
||||||
// endRef - (in) ref to path end polygon.
|
|
||||||
// startPos[3] - (in) Path start location.
|
|
||||||
// endPos[3] - (in) Path end location.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold. Must be at least 1.
|
|
||||||
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
|
||||||
const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
|
||||||
|
|
||||||
// Intializes sliced path find query.
|
|
||||||
// Note 1: calling any other dtNavMeshQuery method before calling findPathEnd()
|
|
||||||
// may results in corrupted data!
|
|
||||||
// Note 2: The pointer to filter is store, and used in subsequent
|
|
||||||
// calls to updateSlicedFindPath().
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to path start polygon.
|
|
||||||
// endRef - (in) ref to path end polygon.
|
|
||||||
// startPos[3] - (in) Path start location.
|
|
||||||
// endPos[3] - (in) Path end location.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
|
||||||
const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter);
|
|
||||||
|
|
||||||
// Updates sliced path find query.
|
|
||||||
// Params:
|
|
||||||
// maxIter - (in) max number of iterations to update.
|
|
||||||
// Returns: Path query state.
|
|
||||||
dtStatus updateSlicedFindPath(const int maxIter);
|
|
||||||
|
|
||||||
// Finalizes sliced path find query and returns found path.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold.
|
|
||||||
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
// Finalizes partial sliced path find query and returns path to the furthest
|
|
||||||
// polygon on the existing path that was visited during the search.
|
|
||||||
// existing - (out) Array of polygons in the existing path.
|
|
||||||
// existingSize - (out) Number of polygons in existing path array.
|
|
||||||
// path - (out) array holding the search result.
|
|
||||||
// pathCount - (out) Number of polygons in search result array.
|
|
||||||
// maxPath - (in) The max number of polygons the path array can hold.
|
|
||||||
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
|
||||||
dtPolyRef* path, int* pathCount, const int maxPath);
|
|
||||||
|
|
||||||
// Finds a straight path from start to end locations within the corridor
|
|
||||||
// described by the path polygons.
|
|
||||||
// Start and end locations will be clamped on the corridor.
|
|
||||||
// The returned polygon references are point to polygon which was entered when
|
|
||||||
// a path point was added. For the end point, zero will be returned. This allows
|
|
||||||
// to match for example off-mesh link points to their representative polygons.
|
|
||||||
// Params:
|
|
||||||
// startPos[3] - (in) Path start location.
|
|
||||||
// endPo[3] - (in) Path end location.
|
|
||||||
// path - (in) Array of connected polygons describing the corridor.
|
|
||||||
// pathSize - (in) Number of polygons in path array.
|
|
||||||
// straightPath - (out) Points describing the straight path.
|
|
||||||
// straightPathFlags - (out, opt) Flags describing each point type, see dtStraightPathFlags.
|
|
||||||
// straightPathRefs - (out, opt) References to polygons at point locations.
|
|
||||||
// straightPathCount - (out) Number of points in the path.
|
|
||||||
// maxStraightPath - (in) The max number of points the straight path array can hold. Must be at least 1.
|
|
||||||
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
|
||||||
const dtPolyRef* path, const int pathSize,
|
|
||||||
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
|
||||||
int* straightPathCount, const int maxStraightPath) const;
|
|
||||||
|
|
||||||
// Moves from startPos to endPos constrained to the navmesh.
|
|
||||||
// If the endPos is reachable, the resultPos will be endPos,
|
|
||||||
// or else the resultPos will be the nearest point in navmesh.
|
|
||||||
// Note: The resulting point is not projected to the ground, use getPolyHeight() to get height.
|
|
||||||
// Note: The algorithm is optimized for small delta movement and small number of polygons.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where startPos lies.
|
|
||||||
// startPos[3] - (in) start position of the mover.
|
|
||||||
// endPos[3] - (in) desired end position of the mover.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// resultPos[3] - (out) new position of the mover.
|
|
||||||
// visited - (out) array of visited polygons.
|
|
||||||
// visitedCount - (out) Number of entries in the visited array.
|
|
||||||
// maxVisitedSize - (in) max number of polygons in the visited array.
|
|
||||||
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
|
||||||
|
|
||||||
// Casts 'walkability' ray along the navmesh surface from startPos towards the endPos.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where the start lies.
|
|
||||||
// startPos[3] - (in) start position of the query.
|
|
||||||
// endPos[3] - (in) end position of the query.
|
|
||||||
// t - (out) hit parameter along the segment, FLT_MAX if no hit.
|
|
||||||
// hitNormal[3] - (out) normal of the nearest hit.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// path - (out,opt) visited path polygons.
|
|
||||||
// pathCount - (out,opt) Number of polygons visited.
|
|
||||||
// maxPath - (in) max number of polygons in the path array.
|
|
||||||
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
|
||||||
|
|
||||||
// Returns distance to nearest wall from the specified location.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where the center lies.
|
|
||||||
// centerPos[3] - (in) center if the query circle.
|
|
||||||
// maxRadius - (in) max search radius.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// hitDist - (out) distance to nearest wall from the test location.
|
|
||||||
// hitPos[3] - (out) location of the nearest hit.
|
|
||||||
// hitNormal[3] - (out) normal of the nearest hit.
|
|
||||||
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
float* hitDist, float* hitPos, float* hitNormal) const;
|
|
||||||
|
|
||||||
// Finds polygons found along the navigation graph which touch the specified circle.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
|
||||||
// centerPos[3] - (in) center if the query circle.
|
|
||||||
// radius - (in) radius of the query circle.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// resultRef - (out, opt) refs to the polygons touched by the circle.
|
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
|
||||||
// resultCost - (out, opt) search cost at each result polygon.
|
|
||||||
// resultCount - (out, opt) Number of results.
|
|
||||||
// maxResult - (int) maximum capacity of search results.
|
|
||||||
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
// Finds polygons found along the navigation graph which touch the convex polygon shape.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
|
||||||
// verts[3*n] - (in) vertices describing convex polygon shape (CCW).
|
|
||||||
// nverts - (in) number of vertices in the polygon.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// resultRef - (out, opt) refs to the polygons touched by the circle.
|
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
|
||||||
// resultCost - (out, opt) search cost at each result polygon.
|
|
||||||
// resultCount - (out) number of results.
|
|
||||||
// maxResult - (int) maximum capacity of search results.
|
|
||||||
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
// Finds non-overlapping local neighbourhood around center location.
|
|
||||||
// Note: The algorithm is optimized for small query radius and small number of polygons.
|
|
||||||
// Params:
|
|
||||||
// startRef - (in) ref to the polygon where the search starts.
|
|
||||||
// centerPos[3] - (in) center if the query circle.
|
|
||||||
// radius - (in) radius of the query circle.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// resultRef - (out) refs to the polygons touched by the circle.
|
|
||||||
// resultParent - (out, opt) parent of each result polygon.
|
|
||||||
// resultCount - (out) number of results.
|
|
||||||
// maxResult - (int) maximum capacity of search results.
|
|
||||||
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
|
||||||
const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
|
||||||
int* resultCount, const int maxResult) const;
|
|
||||||
|
|
||||||
// Returns wall segments of specified polygon.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) ref to the polygon.
|
|
||||||
// filter - (in) path polygon filter.
|
|
||||||
// segments[6*maxSegments] - (out) wall segments (2 endpoints per segment).
|
|
||||||
// segmentCount - (out) number of wall segments.
|
|
||||||
// maxSegments - (in) max number of segments that can be stored in 'segments'.
|
|
||||||
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
|
||||||
float* segments, int* segmentCount, const int maxSegments) const;
|
|
||||||
|
|
||||||
// Returns closest point on navigation polygon.
|
|
||||||
// Uses detail polygons to find the closest point to the navigation polygon surface.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) ref to the polygon.
|
|
||||||
// pos[3] - (in) the point to check.
|
|
||||||
// closest[3] - (out) closest point.
|
|
||||||
// Returns: true if closest point found.
|
|
||||||
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const;
|
|
||||||
|
|
||||||
// Returns closest point on navigation polygon boundary.
|
|
||||||
// Uses the navigation polygon boundary to snap the point to poly boundary
|
|
||||||
// if it is outside the polygon. Much faster than closestPointToPoly. Does not affect height.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) ref to the polygon.
|
|
||||||
// pos[3] - (in) the point to check.
|
|
||||||
// closest[3] - (out) closest point.
|
|
||||||
// Returns: true if closest point found.
|
|
||||||
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
|
||||||
|
|
||||||
// Returns start and end location of an off-mesh link polygon.
|
|
||||||
// Params:
|
|
||||||
// prevRef - (in) ref to the polygon before the link (used to select direction).
|
|
||||||
// polyRef - (in) ref to the off-mesh link polygon.
|
|
||||||
// startPos[3] - (out) start point of the link.
|
|
||||||
// endPos[3] - (out) end point of the link.
|
|
||||||
// Returns: true if link is found.
|
|
||||||
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
|
||||||
|
|
||||||
// Returns height of the polygon at specified location.
|
|
||||||
// Params:
|
|
||||||
// ref - (in) ref to the polygon.
|
|
||||||
// pos[3] - (in) the point where to locate the height.
|
|
||||||
// height - (out) height at the location.
|
|
||||||
// Returns: true if over polygon.
|
|
||||||
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
|
||||||
|
|
||||||
// Returns true if poly reference ins in closed list.
|
|
||||||
bool isInClosedList(dtPolyRef ref) const;
|
|
||||||
|
|
||||||
class dtNodePool* getNodePool() const { return m_nodePool; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Returns neighbour tile based on side.
|
|
||||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
|
||||||
|
|
||||||
// Queries polygons within a tile.
|
|
||||||
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter,
|
|
||||||
dtPolyRef* polys, const int maxPolys) const;
|
|
||||||
// Find nearest polygon within a tile.
|
|
||||||
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents,
|
|
||||||
const dtQueryFilter* filter, float* nearestPt) const;
|
|
||||||
// Returns closest point on polygon.
|
|
||||||
dtStatus closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const;
|
|
||||||
|
|
||||||
// Returns portal points between two polygons.
|
|
||||||
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
|
||||||
unsigned char& fromType, unsigned char& toType) const;
|
|
||||||
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
|
||||||
float* left, float* right) const;
|
|
||||||
|
|
||||||
// Returns edge mid point between two polygons.
|
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
|
||||||
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
|
||||||
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
|
||||||
float* mid) const;
|
|
||||||
|
|
||||||
const dtNavMesh* m_nav; // Pointer to navmesh data.
|
|
||||||
|
|
||||||
struct dtQueryData
|
|
||||||
{
|
|
||||||
dtStatus status;
|
|
||||||
struct dtNode* lastBestNode;
|
|
||||||
float lastBestNodeCost;
|
|
||||||
dtPolyRef startRef, endRef;
|
|
||||||
float startPos[3], endPos[3];
|
|
||||||
const dtQueryFilter* filter;
|
|
||||||
};
|
|
||||||
dtQueryData m_query; // Sliced query state.
|
|
||||||
|
|
||||||
class dtNodePool* m_tinyNodePool; // Pointer to small node pool.
|
|
||||||
class dtNodePool* m_nodePool; // Pointer to node pool.
|
|
||||||
class dtNodeQueue* m_openList; // Pointer to open list queue.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to allocate navmesh query class using Detour allocator.
|
|
||||||
dtNavMeshQuery* dtAllocNavMeshQuery();
|
|
||||||
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
|
||||||
|
|
||||||
#endif // DETOURNAVMESHQUERY_H
|
|
||||||
@@ -1,532 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "DetourObstacleAvoidance.h"
|
|
||||||
#include "DetourCommon.h"
|
|
||||||
#include "DetourAlloc.h"
|
|
||||||
#include "DetourAssert.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <float.h>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
|
|
||||||
static int sweepCircleCircle(const float* c0, const float r0, const float* v,
|
|
||||||
const float* c1, const float r1,
|
|
||||||
float& tmin, float& tmax)
|
|
||||||
{
|
|
||||||
static const float EPS = 0.0001f;
|
|
||||||
float s[3];
|
|
||||||
dtVsub(s,c1,c0);
|
|
||||||
float r = r0+r1;
|
|
||||||
float c = dtVdot2D(s,s) - r*r;
|
|
||||||
float a = dtVdot2D(v,v);
|
|
||||||
if (a < EPS) return 0; // not moving
|
|
||||||
|
|
||||||
// Overlap, calc time to exit.
|
|
||||||
float b = dtVdot2D(v,s);
|
|
||||||
float d = b*b - a*c;
|
|
||||||
if (d < 0.0f) return 0; // no intersection.
|
|
||||||
a = 1.0f / a;
|
|
||||||
const float rd = dtSqrt(d);
|
|
||||||
tmin = (b - rd) * a;
|
|
||||||
tmax = (b + rd) * a;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int isectRaySeg(const float* ap, const float* u,
|
|
||||||
const float* bp, const float* bq,
|
|
||||||
float& t)
|
|
||||||
{
|
|
||||||
float v[3], w[3];
|
|
||||||
dtVsub(v,bq,bp);
|
|
||||||
dtVsub(w,ap,bp);
|
|
||||||
float d = dtVperp2D(u,v);
|
|
||||||
if (fabsf(d) < 1e-6f) return 0;
|
|
||||||
d = 1.0f/d;
|
|
||||||
t = dtVperp2D(v,w) * d;
|
|
||||||
if (t < 0 || t > 1) return 0;
|
|
||||||
float s = dtVperp2D(u,w) * d;
|
|
||||||
if (s < 0 || s > 1) return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData()
|
|
||||||
{
|
|
||||||
void* mem = dtAlloc(sizeof(dtObstacleAvoidanceDebugData), DT_ALLOC_PERM);
|
|
||||||
if (!mem) return 0;
|
|
||||||
return new(mem) dtObstacleAvoidanceDebugData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr)
|
|
||||||
{
|
|
||||||
if (!ptr) return;
|
|
||||||
ptr->~dtObstacleAvoidanceDebugData();
|
|
||||||
dtFree(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dtObstacleAvoidanceDebugData::dtObstacleAvoidanceDebugData() :
|
|
||||||
m_nsamples(0),
|
|
||||||
m_maxSamples(0),
|
|
||||||
m_vel(0),
|
|
||||||
m_ssize(0),
|
|
||||||
m_pen(0),
|
|
||||||
m_vpen(0),
|
|
||||||
m_vcpen(0),
|
|
||||||
m_spen(0),
|
|
||||||
m_tpen(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dtObstacleAvoidanceDebugData::~dtObstacleAvoidanceDebugData()
|
|
||||||
{
|
|
||||||
dtFree(m_vel);
|
|
||||||
dtFree(m_ssize);
|
|
||||||
dtFree(m_pen);
|
|
||||||
dtFree(m_vpen);
|
|
||||||
dtFree(m_vcpen);
|
|
||||||
dtFree(m_spen);
|
|
||||||
dtFree(m_tpen);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtObstacleAvoidanceDebugData::init(const int maxSamples)
|
|
||||||
{
|
|
||||||
dtAssert(maxSamples);
|
|
||||||
m_maxSamples = maxSamples;
|
|
||||||
|
|
||||||
m_vel = (float*)dtAlloc(sizeof(float)*3*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_vel)
|
|
||||||
return false;
|
|
||||||
m_pen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_pen)
|
|
||||||
return false;
|
|
||||||
m_ssize = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_ssize)
|
|
||||||
return false;
|
|
||||||
m_vpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_vpen)
|
|
||||||
return false;
|
|
||||||
m_vcpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_vcpen)
|
|
||||||
return false;
|
|
||||||
m_spen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_spen)
|
|
||||||
return false;
|
|
||||||
m_tpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
|
|
||||||
if (!m_tpen)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceDebugData::reset()
|
|
||||||
{
|
|
||||||
m_nsamples = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceDebugData::addSample(const float* vel, const float ssize, const float pen,
|
|
||||||
const float vpen, const float vcpen, const float spen, const float tpen)
|
|
||||||
{
|
|
||||||
if (m_nsamples >= m_maxSamples)
|
|
||||||
return;
|
|
||||||
dtAssert(m_vel);
|
|
||||||
dtAssert(m_ssize);
|
|
||||||
dtAssert(m_pen);
|
|
||||||
dtAssert(m_vpen);
|
|
||||||
dtAssert(m_vcpen);
|
|
||||||
dtAssert(m_spen);
|
|
||||||
dtAssert(m_tpen);
|
|
||||||
dtVcopy(&m_vel[m_nsamples*3], vel);
|
|
||||||
m_ssize[m_nsamples] = ssize;
|
|
||||||
m_pen[m_nsamples] = pen;
|
|
||||||
m_vpen[m_nsamples] = vpen;
|
|
||||||
m_vcpen[m_nsamples] = vcpen;
|
|
||||||
m_spen[m_nsamples] = spen;
|
|
||||||
m_tpen[m_nsamples] = tpen;
|
|
||||||
m_nsamples++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void normalizeArray(float* arr, const int n)
|
|
||||||
{
|
|
||||||
// Normalize penaly range.
|
|
||||||
float minPen = FLT_MAX;
|
|
||||||
float maxPen = -FLT_MAX;
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
minPen = dtMin(minPen, arr[i]);
|
|
||||||
maxPen = dtMax(maxPen, arr[i]);
|
|
||||||
}
|
|
||||||
const float penRange = maxPen-minPen;
|
|
||||||
const float s = penRange > 0.001f ? (1.0f / penRange) : 1;
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
arr[i] = dtClamp((arr[i]-minPen)*s, 0.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceDebugData::normalizeSamples()
|
|
||||||
{
|
|
||||||
normalizeArray(m_pen, m_nsamples);
|
|
||||||
normalizeArray(m_vpen, m_nsamples);
|
|
||||||
normalizeArray(m_vcpen, m_nsamples);
|
|
||||||
normalizeArray(m_spen, m_nsamples);
|
|
||||||
normalizeArray(m_tpen, m_nsamples);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery()
|
|
||||||
{
|
|
||||||
void* mem = dtAlloc(sizeof(dtObstacleAvoidanceQuery), DT_ALLOC_PERM);
|
|
||||||
if (!mem) return 0;
|
|
||||||
return new(mem) dtObstacleAvoidanceQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr)
|
|
||||||
{
|
|
||||||
if (!ptr) return;
|
|
||||||
ptr->~dtObstacleAvoidanceQuery();
|
|
||||||
dtFree(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
|
|
||||||
m_velBias(0.0f),
|
|
||||||
m_weightDesVel(0.0f),
|
|
||||||
m_weightCurVel(0.0f),
|
|
||||||
m_weightSide(0.0f),
|
|
||||||
m_weightToi(0.0f),
|
|
||||||
m_horizTime(0.0f),
|
|
||||||
m_maxCircles(0),
|
|
||||||
m_circles(0),
|
|
||||||
m_ncircles(0),
|
|
||||||
m_maxSegments(0),
|
|
||||||
m_segments(0),
|
|
||||||
m_nsegments(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dtObstacleAvoidanceQuery::~dtObstacleAvoidanceQuery()
|
|
||||||
{
|
|
||||||
dtFree(m_circles);
|
|
||||||
dtFree(m_segments);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtObstacleAvoidanceQuery::init(const int maxCircles, const int maxSegments)
|
|
||||||
{
|
|
||||||
m_maxCircles = maxCircles;
|
|
||||||
m_ncircles = 0;
|
|
||||||
m_circles = (dtObstacleCircle*)dtAlloc(sizeof(dtObstacleCircle)*m_maxCircles, DT_ALLOC_PERM);
|
|
||||||
if (!m_circles)
|
|
||||||
return false;
|
|
||||||
memset(m_circles, 0, sizeof(dtObstacleCircle)*m_maxCircles);
|
|
||||||
|
|
||||||
m_maxSegments = maxSegments;
|
|
||||||
m_nsegments = 0;
|
|
||||||
m_segments = (dtObstacleSegment*)dtAlloc(sizeof(dtObstacleSegment)*m_maxSegments, DT_ALLOC_PERM);
|
|
||||||
if (!m_segments)
|
|
||||||
return false;
|
|
||||||
memset(m_segments, 0, sizeof(dtObstacleSegment)*m_maxSegments);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::reset()
|
|
||||||
{
|
|
||||||
m_ncircles = 0;
|
|
||||||
m_nsegments = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::addCircle(const float* pos, const float rad,
|
|
||||||
const float* vel, const float* dvel)
|
|
||||||
{
|
|
||||||
if (m_ncircles >= m_maxCircles)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dtObstacleCircle* cir = &m_circles[m_ncircles++];
|
|
||||||
dtVcopy(cir->p, pos);
|
|
||||||
cir->rad = rad;
|
|
||||||
dtVcopy(cir->vel, vel);
|
|
||||||
dtVcopy(cir->dvel, dvel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::addSegment(const float* p, const float* q)
|
|
||||||
{
|
|
||||||
if (m_nsegments > m_maxSegments)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dtObstacleSegment* seg = &m_segments[m_nsegments++];
|
|
||||||
dtVcopy(seg->p, p);
|
|
||||||
dtVcopy(seg->q, q);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel)
|
|
||||||
{
|
|
||||||
// Prepare obstacles
|
|
||||||
for (int i = 0; i < m_ncircles; ++i)
|
|
||||||
{
|
|
||||||
dtObstacleCircle* cir = &m_circles[i];
|
|
||||||
|
|
||||||
// Side
|
|
||||||
const float* pa = pos;
|
|
||||||
const float* pb = cir->p;
|
|
||||||
|
|
||||||
const float orig[3] = {0,0};
|
|
||||||
float dv[3];
|
|
||||||
dtVsub(cir->dp,pb,pa);
|
|
||||||
dtVnormalize(cir->dp);
|
|
||||||
dtVsub(dv, cir->dvel, dvel);
|
|
||||||
|
|
||||||
const float a = dtTriArea2D(orig, cir->dp,dv);
|
|
||||||
if (a < 0.01f)
|
|
||||||
{
|
|
||||||
cir->np[0] = -cir->dp[2];
|
|
||||||
cir->np[2] = cir->dp[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cir->np[0] = cir->dp[2];
|
|
||||||
cir->np[2] = -cir->dp[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m_nsegments; ++i)
|
|
||||||
{
|
|
||||||
dtObstacleSegment* seg = &m_segments[i];
|
|
||||||
|
|
||||||
// Precalc if the agent is really close to the segment.
|
|
||||||
const float r = 0.01f;
|
|
||||||
float t;
|
|
||||||
seg->touch = dtDistancePtSegSqr2D(pos, seg->p, seg->q, t) < dtSqr(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs,
|
|
||||||
const float* pos, const float rad,
|
|
||||||
const float vmax, const float* vel, const float* dvel,
|
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
|
||||||
{
|
|
||||||
// Find min time of impact and exit amongst all obstacles.
|
|
||||||
float tmin = m_horizTime;
|
|
||||||
float side = 0;
|
|
||||||
int nside = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < m_ncircles; ++i)
|
|
||||||
{
|
|
||||||
const dtObstacleCircle* cir = &m_circles[i];
|
|
||||||
|
|
||||||
// RVO
|
|
||||||
float vab[3];
|
|
||||||
dtVscale(vab, vcand, 2);
|
|
||||||
dtVsub(vab, vab, vel);
|
|
||||||
dtVsub(vab, vab, cir->vel);
|
|
||||||
|
|
||||||
// Side
|
|
||||||
side += dtClamp(dtMin(dtVdot2D(cir->dp,vab)*0.5f+0.5f, dtVdot2D(cir->np,vab)*2), 0.0f, 1.0f);
|
|
||||||
nside++;
|
|
||||||
|
|
||||||
float htmin = 0, htmax = 0;
|
|
||||||
if (!sweepCircleCircle(pos,rad, vab, cir->p,cir->rad, htmin, htmax))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Handle overlapping obstacles.
|
|
||||||
if (htmin < 0.0f && htmax > 0.0f)
|
|
||||||
{
|
|
||||||
// Avoid more when overlapped.
|
|
||||||
htmin = -htmin * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (htmin >= 0.0f)
|
|
||||||
{
|
|
||||||
// The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
|
|
||||||
if (htmin < tmin)
|
|
||||||
tmin = htmin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m_nsegments; ++i)
|
|
||||||
{
|
|
||||||
const dtObstacleSegment* seg = &m_segments[i];
|
|
||||||
float htmin = 0;
|
|
||||||
|
|
||||||
if (seg->touch)
|
|
||||||
{
|
|
||||||
// Special case when the agent is very close to the segment.
|
|
||||||
float sdir[3], snorm[3];
|
|
||||||
dtVsub(sdir, seg->q, seg->p);
|
|
||||||
snorm[0] = -sdir[2];
|
|
||||||
snorm[2] = sdir[0];
|
|
||||||
// If the velocity is pointing towards the segment, no collision.
|
|
||||||
if (dtVdot2D(snorm, vcand) < 0.0f)
|
|
||||||
continue;
|
|
||||||
// Else immediate collision.
|
|
||||||
htmin = 0.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!isectRaySeg(pos, vcand, seg->p, seg->q, htmin))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid less when facing walls.
|
|
||||||
htmin *= 2.0f;
|
|
||||||
|
|
||||||
// The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
|
|
||||||
if (htmin < tmin)
|
|
||||||
tmin = htmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize side bias, to prevent it dominating too much.
|
|
||||||
if (nside)
|
|
||||||
side /= nside;
|
|
||||||
|
|
||||||
const float ivmax = 1.0f / vmax;
|
|
||||||
const float vpen = m_weightDesVel * (dtVdist2D(vcand, dvel) * ivmax);
|
|
||||||
const float vcpen = m_weightCurVel * (dtVdist2D(vcand, vel) * ivmax);
|
|
||||||
const float spen = m_weightSide * side;
|
|
||||||
const float tpen = m_weightToi * (1.0f/(0.1f+tmin / m_horizTime));
|
|
||||||
|
|
||||||
const float penalty = vpen + vcpen + spen + tpen;
|
|
||||||
|
|
||||||
// Store different penalties for debug viewing
|
|
||||||
if (debug)
|
|
||||||
debug->addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
|
|
||||||
|
|
||||||
return penalty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel,
|
|
||||||
float* nvel, const int gsize,
|
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
|
||||||
{
|
|
||||||
prepare(pos, dvel);
|
|
||||||
|
|
||||||
dtVset(nvel, 0,0,0);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
debug->reset();
|
|
||||||
|
|
||||||
const float cvx = dvel[0] * m_velBias;
|
|
||||||
const float cvz = dvel[2] * m_velBias;
|
|
||||||
const float cs = vmax * 2 * (1 - m_velBias) / (float)(gsize-1);
|
|
||||||
const float half = (gsize-1)*cs*0.5f;
|
|
||||||
|
|
||||||
float minPenalty = FLT_MAX;
|
|
||||||
|
|
||||||
for (int y = 0; y < gsize; ++y)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < gsize; ++x)
|
|
||||||
{
|
|
||||||
float vcand[3];
|
|
||||||
vcand[0] = cvx + x*cs - half;
|
|
||||||
vcand[1] = 0;
|
|
||||||
vcand[2] = cvz + y*cs - half;
|
|
||||||
|
|
||||||
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
|
|
||||||
|
|
||||||
const float penalty = processSample(vcand, cs, pos,rad,vmax,vel,dvel, debug);
|
|
||||||
if (penalty < minPenalty)
|
|
||||||
{
|
|
||||||
minPenalty = penalty;
|
|
||||||
dtVcopy(nvel, vcand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const float DT_PI = 3.14159265f;
|
|
||||||
|
|
||||||
void dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel, float* nvel,
|
|
||||||
const int ndivs, const int nrings, const int depth,
|
|
||||||
dtObstacleAvoidanceDebugData* debug)
|
|
||||||
{
|
|
||||||
prepare(pos, dvel);
|
|
||||||
|
|
||||||
dtVset(nvel, 0,0,0);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
debug->reset();
|
|
||||||
|
|
||||||
// Build sampling pattern aligned to desired velocity.
|
|
||||||
static const int MAX_PATTERN_DIVS = 32;
|
|
||||||
static const int MAX_PATTERN_RINGS = 4;
|
|
||||||
float pat[(MAX_PATTERN_DIVS*MAX_PATTERN_RINGS+1)*2];
|
|
||||||
int npat = 0;
|
|
||||||
|
|
||||||
const int nd = dtClamp(ndivs, 1, MAX_PATTERN_DIVS);
|
|
||||||
const int nr = dtClamp(nrings, 1, MAX_PATTERN_RINGS);
|
|
||||||
const float da = (1.0f/nd) * DT_PI*2;
|
|
||||||
const float dang = atan2f(dvel[2], dvel[0]);
|
|
||||||
|
|
||||||
// Always add sample at zero
|
|
||||||
pat[npat*2+0] = 0;
|
|
||||||
pat[npat*2+1] = 0;
|
|
||||||
npat++;
|
|
||||||
|
|
||||||
for (int j = 0; j < nr; ++j)
|
|
||||||
{
|
|
||||||
const float rad = (float)(nr-j)/(float)nr;
|
|
||||||
float a = dang + (j&1)*0.5f*da;
|
|
||||||
for (int i = 0; i < nd; ++i)
|
|
||||||
{
|
|
||||||
pat[npat*2+0] = cosf(a)*rad;
|
|
||||||
pat[npat*2+1] = sinf(a)*rad;
|
|
||||||
npat++;
|
|
||||||
a += da;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start sampling.
|
|
||||||
float cr = vmax * (1.0f-m_velBias);
|
|
||||||
float res[3];
|
|
||||||
dtVset(res, dvel[0] * m_velBias, 0, dvel[2] * m_velBias);
|
|
||||||
|
|
||||||
for (int k = 0; k < depth; ++k)
|
|
||||||
{
|
|
||||||
float minPenalty = FLT_MAX;
|
|
||||||
float bvel[3];
|
|
||||||
dtVset(bvel, 0,0,0);
|
|
||||||
|
|
||||||
for (int i = 0; i < npat; ++i)
|
|
||||||
{
|
|
||||||
float vcand[3];
|
|
||||||
vcand[0] = res[0] + pat[i*2+0]*cr;
|
|
||||||
vcand[1] = 0;
|
|
||||||
vcand[2] = res[2] + pat[i*2+1]*cr;
|
|
||||||
|
|
||||||
if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
|
|
||||||
|
|
||||||
const float penalty = processSample(vcand,cr/10, pos,rad,vmax,vel,dvel, debug);
|
|
||||||
if (penalty < minPenalty)
|
|
||||||
{
|
|
||||||
minPenalty = penalty;
|
|
||||||
dtVcopy(bvel, vcand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dtVcopy(res, bvel);
|
|
||||||
|
|
||||||
cr *= 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
dtVcopy(nvel, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef DETOUROBSTACLEAVOIDANCE_H
|
|
||||||
#define DETOUROBSTACLEAVOIDANCE_H
|
|
||||||
|
|
||||||
struct dtObstacleCircle
|
|
||||||
{
|
|
||||||
float p[3]; // Position of the obstacle
|
|
||||||
float vel[3]; // Velocity of the obstacle
|
|
||||||
float dvel[3]; // Velocity of the obstacle
|
|
||||||
float rad; // Radius of the obstacle
|
|
||||||
float dp[3], np[3]; // Use for side selection during sampling.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dtObstacleSegment
|
|
||||||
{
|
|
||||||
float p[3], q[3]; // End points of the obstacle segment
|
|
||||||
bool touch;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int RVO_SAMPLE_RAD = 15;
|
|
||||||
static const int MAX_RVO_SAMPLES = (RVO_SAMPLE_RAD*2+1)*(RVO_SAMPLE_RAD*2+1) + 100;
|
|
||||||
|
|
||||||
class dtObstacleAvoidanceDebugData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtObstacleAvoidanceDebugData();
|
|
||||||
~dtObstacleAvoidanceDebugData();
|
|
||||||
|
|
||||||
bool init(const int maxSamples);
|
|
||||||
void reset();
|
|
||||||
void addSample(const float* vel, const float ssize, const float pen,
|
|
||||||
const float vpen, const float vcpen, const float spen, const float tpen);
|
|
||||||
|
|
||||||
void normalizeSamples();
|
|
||||||
|
|
||||||
inline int getSampleCount() const { return m_nsamples; }
|
|
||||||
inline const float* getSampleVelocity(const int i) const { return &m_vel[i*3]; }
|
|
||||||
inline float getSampleSize(const int i) const { return m_ssize[i]; }
|
|
||||||
inline float getSamplePenalty(const int i) const { return m_pen[i]; }
|
|
||||||
inline float getSampleDesiredVelocityPenalty(const int i) const { return m_vpen[i]; }
|
|
||||||
inline float getSampleCurrentVelocityPenalty(const int i) const { return m_vcpen[i]; }
|
|
||||||
inline float getSamplePreferredSidePenalty(const int i) const { return m_spen[i]; }
|
|
||||||
inline float getSampleCollisionTimePenalty(const int i) const { return m_tpen[i]; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_nsamples;
|
|
||||||
int m_maxSamples;
|
|
||||||
float* m_vel;
|
|
||||||
float* m_ssize;
|
|
||||||
float* m_pen;
|
|
||||||
float* m_vpen;
|
|
||||||
float* m_vcpen;
|
|
||||||
float* m_spen;
|
|
||||||
float* m_tpen;
|
|
||||||
};
|
|
||||||
|
|
||||||
dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData();
|
|
||||||
void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr);
|
|
||||||
|
|
||||||
|
|
||||||
class dtObstacleAvoidanceQuery
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
dtObstacleAvoidanceQuery();
|
|
||||||
~dtObstacleAvoidanceQuery();
|
|
||||||
|
|
||||||
bool init(const int maxCircles, const int maxSegments);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void addCircle(const float* pos, const float rad,
|
|
||||||
const float* vel, const float* dvel);
|
|
||||||
|
|
||||||
void addSegment(const float* p, const float* q);
|
|
||||||
|
|
||||||
inline void setVelocitySelectionBias(float v) { m_velBias = v; }
|
|
||||||
inline void setDesiredVelocityWeight(float w) { m_weightDesVel = w; }
|
|
||||||
inline void setCurrentVelocityWeight(float w) { m_weightCurVel = w; }
|
|
||||||
inline void setPreferredSideWeight(float w) { m_weightSide = w; }
|
|
||||||
inline void setCollisionTimeWeight(float w) { m_weightToi = w; }
|
|
||||||
inline void setTimeHorizon(float t) { m_horizTime = t; }
|
|
||||||
|
|
||||||
void sampleVelocityGrid(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel, float* nvel,
|
|
||||||
const int gsize,
|
|
||||||
dtObstacleAvoidanceDebugData* debug = 0);
|
|
||||||
|
|
||||||
void sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
|
|
||||||
const float* vel, const float* dvel, float* nvel,
|
|
||||||
const int ndivs, const int nrings, const int depth,
|
|
||||||
dtObstacleAvoidanceDebugData* debug = 0);
|
|
||||||
|
|
||||||
inline int getObstacleCircleCount() const { return m_ncircles; }
|
|
||||||
const dtObstacleCircle* getObstacleCircle(const int i) { return &m_circles[i]; }
|
|
||||||
|
|
||||||
inline int getObstacleSegmentCount() const { return m_nsegments; }
|
|
||||||
const dtObstacleSegment* getObstacleSegment(const int i) { return &m_segments[i]; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void prepare(const float* pos, const float* dvel);
|
|
||||||
|
|
||||||
float processSample(const float* vcand, const float cs,
|
|
||||||
const float* pos, const float rad,
|
|
||||||
const float vmax, const float* vel, const float* dvel,
|
|
||||||
dtObstacleAvoidanceDebugData* debug);
|
|
||||||
|
|
||||||
dtObstacleCircle* insertCircle(const float dist);
|
|
||||||
dtObstacleSegment* insertSegment(const float dist);
|
|
||||||
|
|
||||||
float m_velBias;
|
|
||||||
float m_weightDesVel;
|
|
||||||
float m_weightCurVel;
|
|
||||||
float m_weightSide;
|
|
||||||
float m_weightToi;
|
|
||||||
float m_horizTime;
|
|
||||||
|
|
||||||
int m_maxCircles;
|
|
||||||
dtObstacleCircle* m_circles;
|
|
||||||
int m_ncircles;
|
|
||||||
|
|
||||||
int m_maxSegments;
|
|
||||||
dtObstacleSegment* m_segments;
|
|
||||||
int m_nsegments;
|
|
||||||
};
|
|
||||||
|
|
||||||
dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery();
|
|
||||||
void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // DETOUROBSTACLEAVOIDANCE_H
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURALLOCATOR_H
|
||||||
|
#define DETOURALLOCATOR_H
|
||||||
|
|
||||||
|
/// Provides hint values to the memory allocator on how long the
|
||||||
|
/// memory is expected to be used.
|
||||||
|
enum dtAllocHint
|
||||||
|
{
|
||||||
|
DT_ALLOC_PERM, ///< Memory persist after a function call.
|
||||||
|
DT_ALLOC_TEMP ///< Memory used temporarily within a function.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A memory allocation function.
|
||||||
|
// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
|
typedef void* (dtAllocFunc)(int size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// A memory deallocation function.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||||
|
/// @see dtAllocSetCustom
|
||||||
|
typedef void (dtFreeFunc)(void* ptr);
|
||||||
|
|
||||||
|
/// Sets the base custom allocation functions to be used by Detour.
|
||||||
|
/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc
|
||||||
|
/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree
|
||||||
|
void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||||
|
|
||||||
|
/// Allocates a memory block.
|
||||||
|
/// @param[in] size The size, in bytes of memory, to allocate.
|
||||||
|
/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
|
||||||
|
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
|
||||||
|
/// @see dtFree
|
||||||
|
void* dtAlloc(int size, dtAllocHint hint);
|
||||||
|
|
||||||
|
/// Deallocates a memory block.
|
||||||
|
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||||
|
/// @see dtAlloc
|
||||||
|
void dtFree(void* ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,517 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURCOMMON_H
|
||||||
|
#define DETOURCOMMON_H
|
||||||
|
|
||||||
|
#include "DetourMath.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup detour Detour
|
||||||
|
Members in this module are used to create, manipulate, and query navigation
|
||||||
|
meshes.
|
||||||
|
@note This is a summary list of members. Use the index or search
|
||||||
|
feature to find minor members.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @name General helper functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Used to ignore a function parameter. VS complains about unused parameters
|
||||||
|
/// and this silences the warning.
|
||||||
|
/// @param [in] _ Unused parameter
|
||||||
|
template<class T> void dtIgnoreUnused(const T&) { }
|
||||||
|
|
||||||
|
/// Swaps the values of the two parameters.
|
||||||
|
/// @param[in,out] a Value A
|
||||||
|
/// @param[in,out] b Value B
|
||||||
|
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
|
||||||
|
|
||||||
|
/// Returns the minimum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The minimum of the two values.
|
||||||
|
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the maximum of two values.
|
||||||
|
/// @param[in] a Value A
|
||||||
|
/// @param[in] b Value B
|
||||||
|
/// @return The maximum of the two values.
|
||||||
|
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
/// Returns the absolute value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The absolute value of the specified value.
|
||||||
|
template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
|
||||||
|
|
||||||
|
/// Returns the square of the value.
|
||||||
|
/// @param[in] a The value.
|
||||||
|
/// @return The square of the value.
|
||||||
|
template<class T> inline T dtSqr(T a) { return a*a; }
|
||||||
|
|
||||||
|
/// Clamps the value to the specified range.
|
||||||
|
/// @param[in] v The value to clamp.
|
||||||
|
/// @param[in] mn The minimum permitted return value.
|
||||||
|
/// @param[in] mx The maximum permitted return value.
|
||||||
|
/// @return The value, clamped to the specified range.
|
||||||
|
template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Vector helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the cross product of two vectors. (@p v1 x @p v2)
|
||||||
|
/// @param[out] dest The cross product. [(x, y, z)]
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
|
inline void dtVcross(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||||
|
dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||||
|
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors. (@p v1 . @p v2)
|
||||||
|
/// @param[in] v1 A Vector [(x, y, z)]
|
||||||
|
/// @param[in] v2 A vector [(x, y, z)]
|
||||||
|
/// @return The dot product.
|
||||||
|
inline float dtVdot(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
|
||||||
|
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
|
||||||
|
inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+v2[0]*s;
|
||||||
|
dest[1] = v1[1]+v2[1]*s;
|
||||||
|
dest[2] = v1[2]+v2[2]*s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, x)]
|
||||||
|
/// @param[in] v1 The starting vector.
|
||||||
|
/// @param[in] v2 The destination vector.
|
||||||
|
/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
|
||||||
|
inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+(v2[0]-v1[0])*t;
|
||||||
|
dest[1] = v1[1]+(v2[1]-v1[1])*t;
|
||||||
|
dest[2] = v1[2]+(v2[2]-v1[2])*t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector addition. (@p v1 + @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
|
||||||
|
inline void dtVadd(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]+v2[0];
|
||||||
|
dest[1] = v1[1]+v2[1];
|
||||||
|
dest[2] = v1[2]+v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector subtraction. (@p v1 - @p v2)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v1 The base vector. [(x, y, z)]
|
||||||
|
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
|
||||||
|
inline void dtVsub(float* dest, const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
dest[0] = v1[0]-v2[0];
|
||||||
|
dest[1] = v1[1]-v2[1];
|
||||||
|
dest[2] = v1[2]-v2[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scales the vector by the specified value. (@p v * @p t)
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] v The vector to scale. [(x, y, z)]
|
||||||
|
/// @param[in] t The scaling factor.
|
||||||
|
inline void dtVscale(float* dest, const float* v, const float t)
|
||||||
|
{
|
||||||
|
dest[0] = v[0]*t;
|
||||||
|
dest[1] = v[1]*t;
|
||||||
|
dest[2] = v[2]*t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects the minimum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
|
inline void dtVmin(float* mn, const float* v)
|
||||||
|
{
|
||||||
|
mn[0] = dtMin(mn[0], v[0]);
|
||||||
|
mn[1] = dtMin(mn[1], v[1]);
|
||||||
|
mn[2] = dtMin(mn[2], v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects the maximum value of each element from the specified vectors.
|
||||||
|
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
|
||||||
|
/// @param[in] v A vector. [(x, y, z)]
|
||||||
|
inline void dtVmax(float* mx, const float* v)
|
||||||
|
{
|
||||||
|
mx[0] = dtMax(mx[0], v[0]);
|
||||||
|
mx[1] = dtMax(mx[1], v[1]);
|
||||||
|
mx[2] = dtMax(mx[2], v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the vector elements to the specified values.
|
||||||
|
/// @param[out] dest The result vector. [(x, y, z)]
|
||||||
|
/// @param[in] x The x-value of the vector.
|
||||||
|
/// @param[in] y The y-value of the vector.
|
||||||
|
/// @param[in] z The z-value of the vector.
|
||||||
|
inline void dtVset(float* dest, const float x, const float y, const float z)
|
||||||
|
{
|
||||||
|
dest[0] = x; dest[1] = y; dest[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a vector copy.
|
||||||
|
/// @param[out] dest The result. [(x, y, z)]
|
||||||
|
/// @param[in] a The vector to copy. [(x, y, z)]
|
||||||
|
inline void dtVcopy(float* dest, const float* a)
|
||||||
|
{
|
||||||
|
dest[0] = a[0];
|
||||||
|
dest[1] = a[1];
|
||||||
|
dest[2] = a[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the scalar length of the vector.
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The scalar length of the vector.
|
||||||
|
inline float dtVlen(const float* v)
|
||||||
|
{
|
||||||
|
return dtMathSqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the scalar length of the vector. (len * len)
|
||||||
|
/// @param[in] v The vector. [(x, y, z)]
|
||||||
|
/// @return The square of the scalar length of the vector.
|
||||||
|
inline float dtVlenSqr(const float* v)
|
||||||
|
{
|
||||||
|
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the two points.
|
||||||
|
inline float dtVdist(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dy = v2[1] - v1[1];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dtMathSqrtf(dx*dx + dy*dy + dz*dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the square of the distance between two points.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the two points.
|
||||||
|
inline float dtVdistSqr(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dy = v2[1] - v1[1];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dx*dx + dy*dy + dz*dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The distance between the point on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVdist2D(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dtMathSqrtf(dx*dx + dz*dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the square of the distance between the specified points on the xz-plane.
|
||||||
|
/// @param[in] v1 A point. [(x, y, z)]
|
||||||
|
/// @param[in] v2 A point. [(x, y, z)]
|
||||||
|
/// @return The square of the distance between the point on the xz-plane.
|
||||||
|
inline float dtVdist2DSqr(const float* v1, const float* v2)
|
||||||
|
{
|
||||||
|
const float dx = v2[0] - v1[0];
|
||||||
|
const float dz = v2[2] - v1[2];
|
||||||
|
return dx*dx + dz*dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Normalizes the vector.
|
||||||
|
/// @param[in,out] v The vector to normalize. [(x, y, z)]
|
||||||
|
inline void dtVnormalize(float* v)
|
||||||
|
{
|
||||||
|
float d = 1.0f / dtMathSqrtf(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
|
||||||
|
v[0] *= d;
|
||||||
|
v[1] *= d;
|
||||||
|
v[2] *= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs a 'sloppy' colocation check of the specified points.
|
||||||
|
/// @param[in] p0 A point. [(x, y, z)]
|
||||||
|
/// @param[in] p1 A point. [(x, y, z)]
|
||||||
|
/// @return True if the points are considered to be at the same location.
|
||||||
|
///
|
||||||
|
/// Basically, this function will return true if the specified points are
|
||||||
|
/// close enough to eachother to be considered colocated.
|
||||||
|
inline bool dtVequal(const float* p0, const float* p1)
|
||||||
|
{
|
||||||
|
static const float thr = dtSqr(1.0f/16384.0f);
|
||||||
|
const float d = dtVdistSqr(p0, p1);
|
||||||
|
return d < thr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
|
||||||
|
/// @param[in] u A vector [(x, y, z)]
|
||||||
|
/// @param[in] v A vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVdot2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[0]*v[0] + u[2]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
|
||||||
|
/// @param[in] u The LHV vector [(x, y, z)]
|
||||||
|
/// @param[in] v The RHV vector [(x, y, z)]
|
||||||
|
/// @return The dot product on the xz-plane.
|
||||||
|
///
|
||||||
|
/// The vectors are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
inline float dtVperp2D(const float* u, const float* v)
|
||||||
|
{
|
||||||
|
return u[2]*v[0] - u[0]*v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Computational geometry helper functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
|
||||||
|
/// @param[in] a Vertex A. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C. [(x, y, z)]
|
||||||
|
/// @return The signed xz-plane area of the triangle.
|
||||||
|
inline float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
{
|
||||||
|
const float abx = b[0] - a[0];
|
||||||
|
const float abz = b[2] - a[2];
|
||||||
|
const float acx = c[0] - a[0];
|
||||||
|
const float acz = c[2] - a[2];
|
||||||
|
return acx*abz - abx*acz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapBounds
|
||||||
|
inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
|
||||||
|
const unsigned short bmin[3], const unsigned short bmax[3])
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if two axis-aligned bounding boxes overlap.
|
||||||
|
/// @param[in] amin Minimum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] amax Maximum bounds of box A. [(x, y, z)]
|
||||||
|
/// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
|
||||||
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
|
/// @return True if the two AABB's overlap.
|
||||||
|
/// @see dtOverlapQuantBounds
|
||||||
|
inline bool dtOverlapBounds(const float* amin, const float* amax,
|
||||||
|
const float* bmin, const float* bmax)
|
||||||
|
{
|
||||||
|
bool overlap = true;
|
||||||
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
|
||||||
|
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
|
||||||
|
return overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Derives the closest point on a triangle from the specified reference point.
|
||||||
|
/// @param[out] closest The closest point on the triangle.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||||
|
const float* a, const float* b, const float* c);
|
||||||
|
|
||||||
|
/// Derives the y-axis height of the closest point on the triangle from the specified reference point.
|
||||||
|
/// @param[in] p The reference point from which to test. [(x, y, z)]
|
||||||
|
/// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
|
||||||
|
/// @param[out] h The resulting height.
|
||||||
|
bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
|
||||||
|
|
||||||
|
bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
|
||||||
|
const float* verts, int nverts,
|
||||||
|
float& tmin, float& tmax,
|
||||||
|
int& segMin, int& segMax);
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t);
|
||||||
|
|
||||||
|
/// Determines if the specified point is inside the convex polygon on the xz-plane.
|
||||||
|
/// @param[in] pt The point to check. [(x, y, z)]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
|
||||||
|
/// @param[in] nverts The number of vertices. [Limit: >= 3]
|
||||||
|
/// @return True if the point is inside the polygon.
|
||||||
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
|
||||||
|
|
||||||
|
bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
|
||||||
|
float* ed, float* et);
|
||||||
|
|
||||||
|
float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
|
||||||
|
|
||||||
|
/// Derives the centroid of a convex polygon.
|
||||||
|
/// @param[out] tc The centroid of the polgyon. [(x, y, z)]
|
||||||
|
/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
|
||||||
|
/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
|
||||||
|
/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
|
||||||
|
void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
|
||||||
|
|
||||||
|
/// Determines if the two convex polygons overlap on the xz-plane.
|
||||||
|
/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
|
||||||
|
/// @param[in] npolya The number of vertices in polygon A.
|
||||||
|
/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
|
||||||
|
/// @param[in] npolyb The number of vertices in polygon B.
|
||||||
|
/// @return True if the two polygons overlap.
|
||||||
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
|
const float* polyb, const int npolyb);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Miscellanious functions.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
inline unsigned int dtNextPow2(unsigned int v)
|
||||||
|
{
|
||||||
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int dtIlog2(unsigned int v)
|
||||||
|
{
|
||||||
|
unsigned int r;
|
||||||
|
unsigned int shift;
|
||||||
|
r = (v > 0xffff) << 4; v >>= r;
|
||||||
|
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
||||||
|
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
||||||
|
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
||||||
|
r |= (v >> 1);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int dtAlign4(int x) { return (x+3) & ~3; }
|
||||||
|
|
||||||
|
inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
|
||||||
|
|
||||||
|
inline void dtSwapByte(unsigned char* a, unsigned char* b)
|
||||||
|
{
|
||||||
|
unsigned char tmp = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(unsigned short* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(short* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(unsigned int* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(int* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dtSwapEndian(float* v)
|
||||||
|
{
|
||||||
|
unsigned char* x = (unsigned char*)v;
|
||||||
|
dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
#endif // DETOURCOMMON_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
@fn float dtTriArea2D(const float* a, const float* b, const float* c)
|
||||||
|
@par
|
||||||
|
The vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
|
This is a low cost function than can be used for various purposes. Its main purpose
|
||||||
|
is for point/line relationship testing.
|
||||||
|
In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
|
||||||
|
(On the xz-plane.)
|
||||||
|
When used for point/line relationship tests, AB usually represents a line against which
|
||||||
|
the C point is to be tested. In this case:
|
||||||
|
A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
|
||||||
|
A negative value indicates that point C is to the right of lineAB, looking from A toward B.
|
||||||
|
When used for evaluating a triangle:
|
||||||
|
The absolute value of the return value is two times the area of the triangle when it is
|
||||||
|
projected onto the xz-plane.
|
||||||
|
A positive return value indicates:
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general up direction.</li>
|
||||||
|
</ul>
|
||||||
|
A negative return value indicates:
|
||||||
|
<ul>
|
||||||
|
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
||||||
|
<li>The triangle's 3D face normal is in the general down direction.</li>
|
||||||
|
</ul>
|
||||||
|
*/
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
@defgroup detour Detour
|
||||||
|
Members in this module are wrappers around the standard math library
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DETOURMATH_H
|
||||||
|
#define DETOURMATH_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
inline float dtMathFabsf(float x) { return fabsf(x); }
|
||||||
|
inline float dtMathSqrtf(float x) { return sqrtf(x); }
|
||||||
|
inline float dtMathFloorf(float x) { return floorf(x); }
|
||||||
|
inline float dtMathCeilf(float x) { return ceilf(x); }
|
||||||
|
inline float dtMathCosf(float x) { return cosf(x); }
|
||||||
|
inline float dtMathSinf(float x) { return sinf(x); }
|
||||||
|
inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); }
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,708 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESH_H
|
||||||
|
#define DETOURNAVMESH_H
|
||||||
|
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Edited by TC
|
||||||
|
#if defined(WIN32) && !defined(__MINGW32__)
|
||||||
|
/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
|
||||||
|
typedef unsigned __int64 uint64_d;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#ifndef uint64_t
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <linux/types.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
|
||||||
|
typedef uint64_t uint64_d;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
|
||||||
|
// It is also recommended that you change dtHashRef() to a proper 64-bit hash.
|
||||||
|
|
||||||
|
// Edited by TC
|
||||||
|
// We cannot have over 31 bits for either tile nor poly
|
||||||
|
// without changing polyCount to use 64bits too.
|
||||||
|
/// A handle to a polygon within a navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
typedef uint64_d dtPolyRef; // Edited by TC
|
||||||
|
|
||||||
|
/// A handle to a tile within a navigation mesh.
|
||||||
|
/// @ingroup detour
|
||||||
|
typedef uint64_d dtTileRef; // Edited by TC
|
||||||
|
|
||||||
|
/// The maximum number of vertices per navigation polygon.
|
||||||
|
/// @ingroup detour
|
||||||
|
static const int DT_VERTS_PER_POLYGON = 6;
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Tile Serialization Constants
|
||||||
|
/// These constants are used to detect whether a navigation tile's data
|
||||||
|
/// and state format is compatible with the current build.
|
||||||
|
///
|
||||||
|
|
||||||
|
/// A magic number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile data.
|
||||||
|
static const int DT_NAVMESH_VERSION = 7;
|
||||||
|
|
||||||
|
/// A magic number used to detect the compatibility of navigation tile states.
|
||||||
|
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S';
|
||||||
|
|
||||||
|
/// A version number used to detect compatibility of navigation tile states.
|
||||||
|
static const int DT_NAVMESH_STATE_VERSION = 1;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// A flag that indicates that an entity links to an external entity.
|
||||||
|
/// (E.g. A polygon edge is a portal that links to another polygon.)
|
||||||
|
static const unsigned short DT_EXT_LINK = 0x8000;
|
||||||
|
|
||||||
|
/// A value that indicates the entity does not link to anything.
|
||||||
|
static const unsigned int DT_NULL_LINK = 0xffffffff;
|
||||||
|
|
||||||
|
/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.)
|
||||||
|
static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
||||||
|
|
||||||
|
/// The maximum number of user defined area ids.
|
||||||
|
/// @ingroup detour
|
||||||
|
static const int DT_MAX_AREAS = 64;
|
||||||
|
|
||||||
|
static const int STATIC_SALT_BITS = 12;
|
||||||
|
static const int STATIC_TILE_BITS = 21;
|
||||||
|
static const int STATIC_POLY_BITS = 31;
|
||||||
|
// we cannot have over 31 bits for either tile nor poly
|
||||||
|
// without changing polyCount to use 64bits too.
|
||||||
|
|
||||||
|
/// Tile flags used for various functions and fields.
|
||||||
|
/// For an example, see dtNavMesh::addTile().
|
||||||
|
enum dtTileFlags
|
||||||
|
{
|
||||||
|
/// The navigation mesh owns the tile memory and is responsible for freeing it.
|
||||||
|
DT_TILE_FREE_DATA = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Vertex flags returned by dtNavMeshQuery::findStraightPath.
|
||||||
|
enum dtStraightPathFlags
|
||||||
|
{
|
||||||
|
DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path.
|
||||||
|
DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path.
|
||||||
|
DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::findStraightPath.
|
||||||
|
enum dtStraightPathOptions
|
||||||
|
{
|
||||||
|
DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes.
|
||||||
|
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::findPath
|
||||||
|
enum dtFindPathOptions
|
||||||
|
{
|
||||||
|
DT_FINDPATH_LOW_QUALITY_FAR = 0x01, ///< [provisional] trade quality for performance far from the origin. The idea is that by then a new query will be issued
|
||||||
|
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::raycast
|
||||||
|
enum dtRaycastOptions
|
||||||
|
{
|
||||||
|
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Limit raycasting during any angle pahfinding
|
||||||
|
/// The limit is given as a multiple of the character radius
|
||||||
|
static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f;
|
||||||
|
|
||||||
|
/// Flags representing the type of a navigation mesh polygon.
|
||||||
|
enum dtPolyTypes
|
||||||
|
{
|
||||||
|
/// The polygon is a standard convex polygon that is part of the surface of the mesh.
|
||||||
|
DT_POLYTYPE_GROUND = 0,
|
||||||
|
/// The polygon is an off-mesh connection consisting of two vertices.
|
||||||
|
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Defines a polyogn within a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtPoly
|
||||||
|
{
|
||||||
|
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||||
|
unsigned int firstLink;
|
||||||
|
|
||||||
|
/// The indices of the polygon's vertices.
|
||||||
|
/// The actual vertices are located in dtMeshTile::verts.
|
||||||
|
unsigned short verts[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// Packed data representing neighbor polygons references and flags for each edge.
|
||||||
|
unsigned short neis[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
|
/// The user defined polygon flags.
|
||||||
|
unsigned short flags;
|
||||||
|
|
||||||
|
/// The number of vertices in the polygon.
|
||||||
|
unsigned char vertCount;
|
||||||
|
|
||||||
|
/// The bit packed area id and polygon type.
|
||||||
|
/// @note Use the structure's set and get methods to acess this value.
|
||||||
|
unsigned char areaAndtype;
|
||||||
|
|
||||||
|
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
|
||||||
|
inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); }
|
||||||
|
|
||||||
|
/// Sets the polygon type. (See: #dtPolyTypes.)
|
||||||
|
inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); }
|
||||||
|
|
||||||
|
/// Gets the user defined area id.
|
||||||
|
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
||||||
|
|
||||||
|
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||||
|
inline unsigned char getType() const { return areaAndtype >> 6; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines the location of detail sub-mesh data within a dtMeshTile.
|
||||||
|
struct dtPolyDetail
|
||||||
|
{
|
||||||
|
unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
|
||||||
|
unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array.
|
||||||
|
unsigned char vertCount; ///< The number of vertices in the sub-mesh.
|
||||||
|
unsigned char triCount; ///< The number of triangles in the sub-mesh.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines a link between polygons.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
|
struct dtLink
|
||||||
|
{
|
||||||
|
dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.)
|
||||||
|
unsigned int next; ///< Index of the next link.
|
||||||
|
unsigned char edge; ///< Index of the polygon edge that owns this link.
|
||||||
|
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
||||||
|
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
||||||
|
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Bounding volume node.
|
||||||
|
/// @note This structure is rarely if ever used by the end user.
|
||||||
|
/// @see dtMeshTile
|
||||||
|
struct dtBVNode
|
||||||
|
{
|
||||||
|
unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)]
|
||||||
|
unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)]
|
||||||
|
int i; ///< The node's index. (Negative for escape sequence.)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines an navigation mesh off-mesh connection within a dtMeshTile object.
|
||||||
|
/// An off-mesh connection is a user defined traversable connection made up to two vertices.
|
||||||
|
struct dtOffMeshConnection
|
||||||
|
{
|
||||||
|
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||||
|
float pos[6];
|
||||||
|
|
||||||
|
/// The radius of the endpoints. [Limit: >= 0]
|
||||||
|
float rad;
|
||||||
|
|
||||||
|
/// The polygon reference of the connection within the tile.
|
||||||
|
unsigned short poly;
|
||||||
|
|
||||||
|
/// Link flags.
|
||||||
|
/// @note These are not the connection's user defined flags. Those are assigned via the
|
||||||
|
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
||||||
|
unsigned char flags;
|
||||||
|
|
||||||
|
/// End point side.
|
||||||
|
unsigned char side;
|
||||||
|
|
||||||
|
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
||||||
|
unsigned int userId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides high level information related to a dtMeshTile object.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtMeshHeader
|
||||||
|
{
|
||||||
|
int magic; ///< Tile magic number. (Used to identify the data format.)
|
||||||
|
int version; ///< Tile data format version number.
|
||||||
|
int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
|
||||||
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
|
int polyCount; ///< The number of polygons in the tile.
|
||||||
|
int vertCount; ///< The number of vertices in the tile.
|
||||||
|
int maxLinkCount; ///< The number of allocated links.
|
||||||
|
int detailMeshCount; ///< The number of sub-meshes in the detail mesh.
|
||||||
|
|
||||||
|
/// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.)
|
||||||
|
int detailVertCount;
|
||||||
|
|
||||||
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
|
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||||
|
int offMeshConCount; ///< The number of off-mesh connections.
|
||||||
|
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||||
|
float walkableHeight; ///< The height of the agents using the tile.
|
||||||
|
float walkableRadius; ///< The radius of the agents using the tile.
|
||||||
|
float walkableClimb; ///< The maximum climb height of the agents using the tile.
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
|
||||||
|
/// The bounding volume quantization factor.
|
||||||
|
float bvQuantFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Defines a navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtMeshTile
|
||||||
|
{
|
||||||
|
unsigned int salt; ///< Counter describing modifications to the tile.
|
||||||
|
|
||||||
|
unsigned int linksFreeList; ///< Index to the next free link.
|
||||||
|
dtMeshHeader* header; ///< The tile header.
|
||||||
|
dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount]
|
||||||
|
float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount]
|
||||||
|
dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount]
|
||||||
|
dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount]
|
||||||
|
|
||||||
|
/// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount]
|
||||||
|
float* detailVerts;
|
||||||
|
|
||||||
|
/// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount]
|
||||||
|
unsigned char* detailTris;
|
||||||
|
|
||||||
|
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
|
||||||
|
/// (Will be null if bounding volumes are disabled.)
|
||||||
|
dtBVNode* bvTree;
|
||||||
|
|
||||||
|
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||||
|
|
||||||
|
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||||
|
int dataSize; ///< Size of the tile data.
|
||||||
|
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||||
|
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||||
|
/// The values are used to allocate space during the initialization of a navigation mesh.
|
||||||
|
/// @see dtNavMesh::init()
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtNavMeshParams
|
||||||
|
{
|
||||||
|
float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
|
||||||
|
float tileWidth; ///< The width of each tile. (Along the x-axis.)
|
||||||
|
float tileHeight; ///< The height of each tile. (Along the z-axis.)
|
||||||
|
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain.
|
||||||
|
int maxPolys; ///< The maximum number of polygons each tile can contain.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A navigation mesh based on tiles of convex polygons.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtNavMesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNavMesh();
|
||||||
|
~dtNavMesh();
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Initialization and Tile Management
|
||||||
|
|
||||||
|
/// Initializes the navigation mesh for tiled use.
|
||||||
|
/// @param[in] params Initialization parameters.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus init(const dtNavMeshParams* params);
|
||||||
|
|
||||||
|
/// Initializes the navigation mesh for single tile use.
|
||||||
|
/// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData)
|
||||||
|
/// @param[in] dataSize The data size of the new tile.
|
||||||
|
/// @param[in] flags The tile flags. (See: #dtTileFlags)
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
/// @see dtCreateNavMeshData
|
||||||
|
dtStatus init(unsigned char* data, const int dataSize, const int flags);
|
||||||
|
|
||||||
|
/// The navigation mesh initialization params.
|
||||||
|
const dtNavMeshParams* getParams() const;
|
||||||
|
|
||||||
|
/// Adds a tile to the navigation mesh.
|
||||||
|
/// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData)
|
||||||
|
/// @param[in] dataSize Data size of the new tile mesh.
|
||||||
|
/// @param[in] flags Tile flags. (See: #dtTileFlags)
|
||||||
|
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||||
|
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||||
|
|
||||||
|
/// Removes the specified tile from the navigation mesh.
|
||||||
|
/// @param[in] ref The reference of the tile to remove.
|
||||||
|
/// @param[out] data Data associated with deleted tile.
|
||||||
|
/// @param[out] dataSize Size of the data associated with deleted tile.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Query Functions
|
||||||
|
|
||||||
|
/// Calculates the tile grid location for the specified world position.
|
||||||
|
/// @param[in] pos The world position for the query. [(x, y, z)]
|
||||||
|
/// @param[out] tx The tile's x-location. (x, y)
|
||||||
|
/// @param[out] ty The tile's y-location. (x, y)
|
||||||
|
void calcTileLoc(const float* pos, int* tx, int* ty) const;
|
||||||
|
|
||||||
|
/// Gets the tile at the specified grid location.
|
||||||
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
|
/// @return The tile, or null if the tile does not exist.
|
||||||
|
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
||||||
|
|
||||||
|
/// Gets all tiles at the specified grid location. (All layers.)
|
||||||
|
/// @param[in] x The tile's x-location. (x, y)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y)
|
||||||
|
/// @param[out] tiles A pointer to an array of tiles that will hold the result.
|
||||||
|
/// @param[in] maxTiles The maximum tiles the tiles parameter can hold.
|
||||||
|
/// @return The number of tiles returned in the tiles array.
|
||||||
|
int getTilesAt(const int x, const int y,
|
||||||
|
dtMeshTile const** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Gets the tile reference for the tile at specified grid location.
|
||||||
|
/// @param[in] x The tile's x-location. (x, y, layer)
|
||||||
|
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||||
|
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||||
|
/// @return The tile reference of the tile, or 0 if there is none.
|
||||||
|
dtTileRef getTileRefAt(int x, int y, int layer) const;
|
||||||
|
|
||||||
|
/// Gets the tile reference for the specified tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The tile reference of the tile.
|
||||||
|
dtTileRef getTileRef(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Gets the tile for the specified tile reference.
|
||||||
|
/// @param[in] ref The tile reference of the tile to retrieve.
|
||||||
|
/// @return The tile for the specified reference, or null if the
|
||||||
|
/// reference is invalid.
|
||||||
|
const dtMeshTile* getTileByRef(dtTileRef ref) const;
|
||||||
|
|
||||||
|
/// The maximum number of tiles supported by the navigation mesh.
|
||||||
|
/// @return The maximum number of tiles supported by the navigation mesh.
|
||||||
|
int getMaxTiles() const;
|
||||||
|
|
||||||
|
/// Gets the tile at the specified index.
|
||||||
|
/// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()]
|
||||||
|
/// @return The tile at the specified index.
|
||||||
|
const dtMeshTile* getTile(int i) const;
|
||||||
|
|
||||||
|
/// Gets the tile and polygon for the specified polygon reference.
|
||||||
|
/// @param[in] ref The reference for the a polygon.
|
||||||
|
/// @param[out] tile The tile containing the polygon.
|
||||||
|
/// @param[out] poly The polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
|
/// Returns the tile and polygon for the specified polygon reference.
|
||||||
|
/// @param[in] ref A known valid reference for a polygon.
|
||||||
|
/// @param[out] tile The tile containing the polygon.
|
||||||
|
/// @param[out] poly The polygon.
|
||||||
|
void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const;
|
||||||
|
|
||||||
|
/// Checks the validity of a polygon reference.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @return True if polygon reference is valid for the navigation mesh.
|
||||||
|
bool isValidPolyRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// Gets the polygon reference for the tile's base polygon.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The polygon reference for the base polygon in the specified tile.
|
||||||
|
dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Gets the endpoints for an off-mesh connection, ordered by "direction of travel".
|
||||||
|
/// @param[in] prevRef The reference of the polygon before the connection.
|
||||||
|
/// @param[in] polyRef The reference of the off-mesh connection polygon.
|
||||||
|
/// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)]
|
||||||
|
/// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const;
|
||||||
|
|
||||||
|
/// Gets the specified off-mesh connection.
|
||||||
|
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||||
|
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||||
|
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name State Management
|
||||||
|
/// These functions do not effect #dtTileRef or #dtPolyRef's.
|
||||||
|
|
||||||
|
/// Sets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] flags The new flags for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags);
|
||||||
|
|
||||||
|
/// Gets the user defined flags for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultFlags The polygon flags.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const;
|
||||||
|
|
||||||
|
/// Sets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus setPolyArea(dtPolyRef ref, unsigned char area);
|
||||||
|
|
||||||
|
/// Gets the user defined area for the specified polygon.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @param[out] resultArea The area id for the polygon.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const;
|
||||||
|
|
||||||
|
/// Gets the size of the buffer required by #storeTileState to store the specified tile's state.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @return The size of the buffer required to store the state.
|
||||||
|
int getTileStateSize(const dtMeshTile* tile) const;
|
||||||
|
|
||||||
|
/// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.)
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[out] data The buffer to store the tile's state in.
|
||||||
|
/// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize]
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const;
|
||||||
|
|
||||||
|
/// Restores the state of the tile.
|
||||||
|
/// @param[in] tile The tile.
|
||||||
|
/// @param[in] data The new state. (Obtained from #storeTileState.)
|
||||||
|
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||||
|
/// @return The status flags for the operation.
|
||||||
|
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// @name Encoding and Decoding
|
||||||
|
/// These functions are generally meant for internal use only.
|
||||||
|
|
||||||
|
/// Derives a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] salt The tile's salt value.
|
||||||
|
/// @param[in] it The index of the tile.
|
||||||
|
/// @param[in] ip The index of the polygon within the tile.
|
||||||
|
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
||||||
|
{
|
||||||
|
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a standard polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference to decode.
|
||||||
|
/// @param[out] salt The tile's salt value.
|
||||||
|
/// @param[out] it The index of the tile.
|
||||||
|
/// @param[out] ip The index of the polygon within the tile.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
||||||
|
{
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||||
|
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||||
|
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||||
|
ip = (unsigned int)(ref & polyMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts a tile's salt value from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||||
|
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the tile's index from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||||
|
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||||
|
/// @note This function is generally meant for internal use only.
|
||||||
|
/// @param[in] ref The polygon reference.
|
||||||
|
/// @see #encodePolyId
|
||||||
|
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
||||||
|
{
|
||||||
|
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||||
|
return (unsigned int)(ref & polyMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Returns pointer to tile in the tile array.
|
||||||
|
dtMeshTile* getTile(int i);
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
int getTilesAt(const int x, const int y,
|
||||||
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
int getNeighbourTilesAt(const int x, const int y, const int side,
|
||||||
|
dtMeshTile** tiles, const int maxTiles) const;
|
||||||
|
|
||||||
|
/// Returns all polygons in neighbour tile based on portal defined by the segment.
|
||||||
|
int findConnectingPolys(const float* va, const float* vb,
|
||||||
|
const dtMeshTile* tile, int side,
|
||||||
|
dtPolyRef* con, float* conarea, int maxcon) const;
|
||||||
|
|
||||||
|
/// Builds internal polygons links for a tile.
|
||||||
|
void connectIntLinks(dtMeshTile* tile);
|
||||||
|
/// Builds internal polygons links for a tile.
|
||||||
|
void baseOffMeshLinks(dtMeshTile* tile);
|
||||||
|
|
||||||
|
/// Builds external polygon links for a tile.
|
||||||
|
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
|
/// Builds external polygon links for a tile.
|
||||||
|
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||||
|
|
||||||
|
/// Removes external links at specified side.
|
||||||
|
void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||||
|
|
||||||
|
/// Queries polygons within a tile.
|
||||||
|
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||||
|
dtPolyRef* polys, const int maxPolys) const;
|
||||||
|
/// Find nearest polygon within a tile.
|
||||||
|
dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center,
|
||||||
|
const float* extents, float* nearestPt) const;
|
||||||
|
/// Returns closest point on polygon.
|
||||||
|
void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||||
|
|
||||||
|
dtNavMeshParams m_params; ///< Current initialization params. TODO: do not store this info twice.
|
||||||
|
float m_orig[3]; ///< Origin of the tile (0,0)
|
||||||
|
float m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
|
||||||
|
int m_maxTiles; ///< Max number of tiles.
|
||||||
|
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||||
|
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||||
|
|
||||||
|
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||||
|
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||||
|
dtMeshTile* m_tiles; ///< List of tiles.
|
||||||
|
|
||||||
|
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||||
|
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||||
|
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a navigation mesh object using the Detour allocator.
|
||||||
|
/// @return A navigation mesh that is ready for initialization, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
|
dtNavMesh* dtAllocNavMesh();
|
||||||
|
|
||||||
|
/// Frees the specified navigation mesh object using the Detour allocator.
|
||||||
|
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
|
||||||
|
/// @ingroup detour
|
||||||
|
void dtFreeNavMesh(dtNavMesh* navmesh);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESH_H
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
@typedef dtPolyRef
|
||||||
|
@par
|
||||||
|
Polygon references are subject to the same invalidate/preserve/restore
|
||||||
|
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
||||||
|
tile changes, the polygon reference becomes invalid.
|
||||||
|
Changing a polygon's flags, area id, etc. does not impact its polygon
|
||||||
|
reference.
|
||||||
|
@typedef dtTileRef
|
||||||
|
@par
|
||||||
|
The following changes will invalidate a tile reference:
|
||||||
|
- The referenced tile has been removed from the navigation mesh.
|
||||||
|
- The navigation mesh has been initialized using a different set
|
||||||
|
of #dtNavMeshParams.
|
||||||
|
A tile reference is preserved/restored if the tile is added to a navigation
|
||||||
|
mesh initialized with the original #dtNavMeshParams and is added at the
|
||||||
|
original reference location. (E.g. The lastRef parameter is used with
|
||||||
|
dtNavMesh::addTile.)
|
||||||
|
Basically, if the storage structure of a tile changes, its associated
|
||||||
|
tile reference changes.
|
||||||
|
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
||||||
|
@par
|
||||||
|
Each entry represents data for the edge starting at the vertex of the same index.
|
||||||
|
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
||||||
|
A value of zero indicates the edge has no polygon connection. (It makes up the
|
||||||
|
border of the navigation mesh.)
|
||||||
|
The information can be extracted as follows:
|
||||||
|
@code
|
||||||
|
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
||||||
|
if (neis[n] & #DT_EX_LINK)
|
||||||
|
{
|
||||||
|
// The edge is an external (portal) edge.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
@var float dtMeshHeader::bvQuantFactor
|
||||||
|
@par
|
||||||
|
This value is used for converting between world and bounding volume coordinates.
|
||||||
|
For example:
|
||||||
|
@code
|
||||||
|
const float cs = 1.0f / tile->header->bvQuantFactor;
|
||||||
|
const dtBVNode* n = &tile->bvTree[i];
|
||||||
|
if (n->i >= 0)
|
||||||
|
{
|
||||||
|
// This is a leaf node.
|
||||||
|
float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
|
||||||
|
float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs;
|
||||||
|
// Etc...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
@struct dtMeshTile
|
||||||
|
@par
|
||||||
|
Tiles generally only exist within the context of a dtNavMesh object.
|
||||||
|
Some tile content is optional. For example, a tile may not contain any
|
||||||
|
off-mesh connections. In this case the associated pointer will be null.
|
||||||
|
If a detail mesh exists it will share vertices with the base polygon mesh.
|
||||||
|
Only the vertices unique to the detail mesh will be stored in #detailVerts.
|
||||||
|
@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated.
|
||||||
|
For example: The tile at a location might not have been loaded yet, or may have been removed.
|
||||||
|
In this case, pointers will be null. So if in doubt, check the polygon count in the
|
||||||
|
tile's header to determine if a tile has polygons defined.
|
||||||
|
@var float dtOffMeshConnection::pos[6]
|
||||||
|
@par
|
||||||
|
For a properly built navigation mesh, vertex A will always be within the bounds of the mesh.
|
||||||
|
Vertex B is not required to be within the bounds of the mesh.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESHBUILDER_H
|
||||||
|
#define DETOURNAVMESHBUILDER_H
|
||||||
|
|
||||||
|
#include "DetourAlloc.h"
|
||||||
|
|
||||||
|
/// Represents the source data used to build an navigation mesh tile.
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtNavMeshCreateParams
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @name Polygon Mesh Attributes
|
||||||
|
/// Used to create the base navigation graph.
|
||||||
|
/// See #rcPolyMesh for details related to these attributes.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
|
||||||
|
int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3]
|
||||||
|
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
|
||||||
|
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
|
||||||
|
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
|
||||||
|
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
|
||||||
|
int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3]
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Height Detail Attributes (Optional)
|
||||||
|
/// See #rcPolyMeshDetail for details related to these attributes.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount]
|
||||||
|
const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
|
||||||
|
int detailVertsCount; ///< The number of vertices in the detail mesh.
|
||||||
|
const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount]
|
||||||
|
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Off-Mesh Connections Attributes (Optional)
|
||||||
|
/// Used to define a custom point-to-point edge within the navigation graph, an
|
||||||
|
/// off-mesh connection is a user defined traversable connection made up to two vertices,
|
||||||
|
/// at least one of which resides within a navigation mesh polygon.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
|
||||||
|
const float* offMeshConVerts;
|
||||||
|
/// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
|
||||||
|
const float* offMeshConRad;
|
||||||
|
/// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned short* offMeshConFlags;
|
||||||
|
/// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
const unsigned char* offMeshConAreas;
|
||||||
|
/// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
|
||||||
|
///
|
||||||
|
/// 0 = Travel only from endpoint A to endpoint B.<br/>
|
||||||
|
/// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
|
||||||
|
const unsigned char* offMeshConDir;
|
||||||
|
/// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
|
||||||
|
const unsigned int* offMeshConUserID;
|
||||||
|
/// The number of off-mesh connections. [Limit: >= 0]
|
||||||
|
int offMeshConCount;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Tile Attributes
|
||||||
|
/// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
unsigned int userId; ///< The user defined id of the tile.
|
||||||
|
int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
|
||||||
|
int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
|
||||||
|
int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
|
||||||
|
float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name General Configuration Attributes
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
float walkableHeight; ///< The agent height. [Unit: wu]
|
||||||
|
float walkableRadius; ///< The agent radius. [Unit: wu]
|
||||||
|
float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
|
||||||
|
float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
|
||||||
|
|
||||||
|
/// True if a bounding volume tree should be built for the tile.
|
||||||
|
/// @note The BVTree is not normally needed for layered navigation meshes.
|
||||||
|
bool buildBvTree;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Builds navigation mesh tile data from the provided tile creation data.
|
||||||
|
/// @ingroup detour
|
||||||
|
/// @param[in] params Tile creation data.
|
||||||
|
/// @param[out] outData The resulting tile data.
|
||||||
|
/// @param[out] outDataSize The size of the tile data array.
|
||||||
|
/// @return True if the tile data was successfully created.
|
||||||
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize);
|
||||||
|
|
||||||
|
/// Swaps the endianess of the tile data's header (#dtMeshHeader).
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
|
/// Swaps endianess of the tile data.
|
||||||
|
/// @param[in,out] data The tile data array.
|
||||||
|
/// @param[in] dataSize The size of the data array.
|
||||||
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESHBUILDER_H
|
||||||
|
|
||||||
|
// This section contains detailed documentation for members that don't have
|
||||||
|
// a source file. It reduces clutter in the main section of the header.
|
||||||
|
|
||||||
|
/**
|
||||||
|
@struct dtNavMeshCreateParams
|
||||||
|
@par
|
||||||
|
This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
|
||||||
|
See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
|
||||||
|
Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
|
||||||
|
are all based on the values of #cs and #ch.
|
||||||
|
The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
|
||||||
|
to a navigation mesh using either the dtNavMesh single tile <tt>init()</tt> function or the dtNavMesh::addTile()
|
||||||
|
function.
|
||||||
|
@see dtCreateNavMeshData
|
||||||
|
*/
|
||||||
@@ -0,0 +1,536 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURNAVMESHQUERY_H
|
||||||
|
#define DETOURNAVMESHQUERY_H
|
||||||
|
|
||||||
|
#include "DetourNavMesh.h"
|
||||||
|
#include "DetourStatus.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
||||||
|
// On certain platforms indirect or virtual function call is expensive. The default
|
||||||
|
// setting is to use non-virtual functions, the actual implementations of the functions
|
||||||
|
// are declared as inline for maximum speed.
|
||||||
|
|
||||||
|
//#define DT_VIRTUAL_QUERYFILTER 1
|
||||||
|
|
||||||
|
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtQueryFilter
|
||||||
|
{
|
||||||
|
float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.)
|
||||||
|
unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.)
|
||||||
|
unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.)
|
||||||
|
|
||||||
|
public:
|
||||||
|
dtQueryFilter();
|
||||||
|
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual ~dtQueryFilter() { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Returns true if the polygon can be visited. (I.e. Is traversable.)
|
||||||
|
/// @param[in] ref The reference id of the polygon test.
|
||||||
|
/// @param[in] tile The tile containing the polygon.
|
||||||
|
/// @param[in] poly The polygon to test.
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual bool passFilter(const dtPolyRef ref,
|
||||||
|
const dtMeshTile* tile,
|
||||||
|
const dtPoly* poly) const;
|
||||||
|
#else
|
||||||
|
bool passFilter(const dtPolyRef ref,
|
||||||
|
const dtMeshTile* tile,
|
||||||
|
const dtPoly* poly) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Returns cost to move from the beginning to the end of a line segment
|
||||||
|
/// that is fully contained within a polygon.
|
||||||
|
/// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
|
||||||
|
/// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
|
||||||
|
/// @param[in] prevRef The reference id of the previous polygon. [opt]
|
||||||
|
/// @param[in] prevTile The tile containing the previous polygon. [opt]
|
||||||
|
/// @param[in] prevPoly The previous polygon. [opt]
|
||||||
|
/// @param[in] curRef The reference id of the current polygon.
|
||||||
|
/// @param[in] curTile The tile containing the current polygon.
|
||||||
|
/// @param[in] curPoly The current polygon.
|
||||||
|
/// @param[in] nextRef The refernece id of the next polygon. [opt]
|
||||||
|
/// @param[in] nextTile The tile containing the next polygon. [opt]
|
||||||
|
/// @param[in] nextPoly The next polygon. [opt]
|
||||||
|
#ifdef DT_VIRTUAL_QUERYFILTER
|
||||||
|
virtual float getCost(const float* pa, const float* pb,
|
||||||
|
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||||
|
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||||
|
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||||
|
#else
|
||||||
|
float getCost(const float* pa, const float* pb,
|
||||||
|
const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly,
|
||||||
|
const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly,
|
||||||
|
const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @name Getters and setters for the default implementation data.
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Returns the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @returns The traversal cost of the area.
|
||||||
|
inline float getAreaCost(const int i) const { return m_areaCost[i]; }
|
||||||
|
|
||||||
|
/// Sets the traversal cost of the area.
|
||||||
|
/// @param[in] i The id of the area.
|
||||||
|
/// @param[in] cost The new cost of traversing the area.
|
||||||
|
inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; }
|
||||||
|
|
||||||
|
/// Returns the include flags for the filter.
|
||||||
|
/// Any polygons that include one or more of these flags will be
|
||||||
|
/// included in the operation.
|
||||||
|
inline unsigned short getIncludeFlags() const { return m_includeFlags; }
|
||||||
|
|
||||||
|
/// Sets the include flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
|
inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; }
|
||||||
|
|
||||||
|
/// Returns the exclude flags for the filter.
|
||||||
|
/// Any polygons that include one ore more of these flags will be
|
||||||
|
/// excluded from the operation.
|
||||||
|
inline unsigned short getExcludeFlags() const { return m_excludeFlags; }
|
||||||
|
|
||||||
|
/// Sets the exclude flags for the filter.
|
||||||
|
/// @param[in] flags The new flags.
|
||||||
|
inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; }
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides information about raycast hit
|
||||||
|
/// filled by dtNavMeshQuery::raycast
|
||||||
|
/// @ingroup detour
|
||||||
|
struct dtRaycastHit
|
||||||
|
{
|
||||||
|
/// The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
float t;
|
||||||
|
|
||||||
|
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
float hitNormal[3];
|
||||||
|
|
||||||
|
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||||
|
dtPolyRef* path;
|
||||||
|
|
||||||
|
/// The number of visited polygons. [opt]
|
||||||
|
int pathCount;
|
||||||
|
|
||||||
|
/// The maximum number of polygons the @p path array can hold.
|
||||||
|
int maxPath;
|
||||||
|
|
||||||
|
/// The cost of the path until hit.
|
||||||
|
float pathCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides the ability to perform pathfinding related queries against
|
||||||
|
/// a navigation mesh.
|
||||||
|
/// @ingroup detour
|
||||||
|
class dtNavMeshQuery
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dtNavMeshQuery();
|
||||||
|
~dtNavMeshQuery();
|
||||||
|
|
||||||
|
/// Initializes the query object.
|
||||||
|
/// @param[in] nav Pointer to the dtNavMesh object to use for all queries.
|
||||||
|
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65536]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
||||||
|
|
||||||
|
/// @name Standard Pathfinding Functions
|
||||||
|
// /@{
|
||||||
|
|
||||||
|
/// Finds a path from the start polygon to the end polygon.
|
||||||
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
|
dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
|
/// Finds the straight path from the start to the end position within the polygon corridor.
|
||||||
|
/// @param[in] startPos Path start position. [(x, y, z)]
|
||||||
|
/// @param[in] endPos Path end position. [(x, y, z)]
|
||||||
|
/// @param[in] path An array of polygon references that represent the path corridor.
|
||||||
|
/// @param[in] pathSize The number of polygons in the @p path array.
|
||||||
|
/// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount].
|
||||||
|
/// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt]
|
||||||
|
/// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt]
|
||||||
|
/// @param[out] straightPathCount The number of points in the straight path.
|
||||||
|
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
|
||||||
|
/// @param[in] options Query options. (see: #dtStraightPathOptions)
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findStraightPath(const float* startPos, const float* endPos,
|
||||||
|
const dtPolyRef* path, const int pathSize,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath, const int options = 0) const;
|
||||||
|
|
||||||
|
///@}
|
||||||
|
/// @name Sliced Pathfinding Functions
|
||||||
|
/// Common use case:
|
||||||
|
/// -# Call initSlicedFindPath() to initialize the sliced path query.
|
||||||
|
/// -# Call updateSlicedFindPath() until it returns complete.
|
||||||
|
/// -# Call finalizeSlicedFindPath() to get the path.
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Intializes a sliced path query.
|
||||||
|
/// @param[in] startRef The refrence id of the start polygon.
|
||||||
|
/// @param[in] endRef The reference id of the end polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon. [(x, y, z)]
|
||||||
|
/// @param[in] endPos A position within the end polygon. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] options query options (see: #dtFindPathOptions)
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||||
|
const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter, const unsigned int options = 0);
|
||||||
|
|
||||||
|
/// Updates an in-progress sliced path query.
|
||||||
|
/// @param[in] maxIter The maximum number of iterations to perform.
|
||||||
|
/// @param[out] doneIters The actual number of iterations completed. [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus updateSlicedFindPath(const int maxIter, int* doneIters);
|
||||||
|
|
||||||
|
/// Finalizes and returns the results of a sliced path query.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
|
|
||||||
|
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
|
||||||
|
/// polygon on the existing path that was visited during the search.
|
||||||
|
/// @param[in] existing An array of polygon references for the existing path.
|
||||||
|
/// @param[in] existingSize The number of polygon in the @p existing array.
|
||||||
|
/// @param[out] path An ordered list of polygon references representing the path. (Start to end.)
|
||||||
|
/// [(polyRef) * @p pathCount]
|
||||||
|
/// @param[out] pathCount The number of polygons returned in the @p path array.
|
||||||
|
/// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
|
||||||
|
dtPolyRef* path, int* pathCount, const int maxPath);
|
||||||
|
|
||||||
|
///@}
|
||||||
|
/// @name Dijkstra Search Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Finds the polygons along the navigation graph that touch the specified circle.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt]
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found. [opt]
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// Finds the polygons along the naviation graph that touch the specified convex polygon.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] verts The vertices describing the convex polygon. (CCW)
|
||||||
|
/// [(x, y, z) * @p nverts]
|
||||||
|
/// @param[in] nverts The number of vertices in the polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt]
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a
|
||||||
|
/// result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCost The search cost from the centroid point to the polygon. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Local Query Functions
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/// Finds the polygon nearest to the specified center point.
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] nearestRef The reference id of the nearest polygon.
|
||||||
|
/// @param[out] nearestPt The nearest point on the polygon. [opt] [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findNearestPoly(const float* center, const float* extents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* nearestRef, float* nearestPt) const;
|
||||||
|
|
||||||
|
/// Finds polygons that overlap the search box.
|
||||||
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
|
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] polys The reference ids of the polygons that overlap the query box.
|
||||||
|
/// @param[out] polyCount The number of polygons in the search result.
|
||||||
|
/// @param[in] maxPolys The maximum number of polygons the search result can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus queryPolygons(const float* center, const float* extents,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* polys, int* polyCount, const int maxPolys) const;
|
||||||
|
|
||||||
|
/// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the query circle. [(x, y, z)]
|
||||||
|
/// @param[in] radius The radius of the query circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultRef The reference ids of the polygons touched by the circle.
|
||||||
|
/// @param[out] resultParent The reference ids of the parent polygons for each result.
|
||||||
|
/// Zero if a result polygon has no parent. [opt]
|
||||||
|
/// @param[out] resultCount The number of polygons found.
|
||||||
|
/// @param[in] maxResult The maximum number of polygons the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* resultRef, dtPolyRef* resultParent,
|
||||||
|
int* resultCount, const int maxResult) const;
|
||||||
|
|
||||||
|
/// Moves from the start to the end position constrained to the navigation mesh.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)]
|
||||||
|
/// @param[in] endPos The desired end position of the mover. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] resultPos The result position of the mover. [(x, y, z)]
|
||||||
|
/// @param[out] visited The reference ids of the polygons visited during the move.
|
||||||
|
/// @param[out] visitedCount The number of polygons visited during the move.
|
||||||
|
/// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @note A wrapper around raycast(..., RaycastHit*). Retained for backward compatibility.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[out] t The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
/// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] path The reference ids of the visited polygons. [opt]
|
||||||
|
/// @param[out] pathCount The number of visited polygons. [opt]
|
||||||
|
/// @param[in] maxPath The maximum number of polygons the @p path array can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const;
|
||||||
|
|
||||||
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
|
/// the start position toward the end position.
|
||||||
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
|
/// @param[in] startPos A position within the start polygon representing
|
||||||
|
/// the start of the ray. [(x, y, z)]
|
||||||
|
/// @param[in] endPos The position to cast the ray toward. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] flags govern how the raycast behaves. See dtRaycastOptions
|
||||||
|
/// @param[out] hit Pointer to a raycast hit structure which will be filled by the results.
|
||||||
|
/// @param[in] prevRef parent of start ref. Used during for cost calculation [opt]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
|
||||||
|
const dtQueryFilter* filter, const unsigned int options,
|
||||||
|
dtRaycastHit* hit, dtPolyRef prevRef = 0) const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Finds the distance from the specified position to the nearest polygon wall.
|
||||||
|
/// @param[in] startRef The reference id of the polygon containing @p centerPos.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] maxRadius The radius of the search circle.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] hitDist The distance to the nearest wall from @p centerPos.
|
||||||
|
/// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)]
|
||||||
|
/// @param[out] hitNormal The normalized ray formed from the wall point to the
|
||||||
|
/// source point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter,
|
||||||
|
float* hitDist, float* hitPos, float* hitNormal) const;
|
||||||
|
|
||||||
|
/// Returns the segments for the specified polygon, optionally including portals.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
|
||||||
|
/// @param[out] segmentRefs The reference ids of each segment's neighbor polygon.
|
||||||
|
/// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount]
|
||||||
|
/// @param[out] segmentCount The number of segments returned.
|
||||||
|
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
|
||||||
|
float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
|
||||||
|
const int maxSegments) const;
|
||||||
|
|
||||||
|
/// Returns random location on navmesh.
|
||||||
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
|
/// @param[out] randomPt The random location.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
|
/// Returns random location on navmesh within the reach of specified location.
|
||||||
|
/// Polygons are chosen weighted by area. The search runs in linear related to number of polygon.
|
||||||
|
/// The location is not exactly constrained by the circle, but it limits the visited polygons.
|
||||||
|
/// @param[in] startRef The reference id of the polygon where the search starts.
|
||||||
|
/// @param[in] centerPos The center of the search circle. [(x, y, z)]
|
||||||
|
/// @param[in] filter The polygon filter to apply to the query.
|
||||||
|
/// @param[in] frand Function returning a random number [0..1).
|
||||||
|
/// @param[out] randomRef The reference id of the random location.
|
||||||
|
/// @param[out] randomPt The random location. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
|
||||||
|
const dtQueryFilter* filter, float (*frand)(),
|
||||||
|
dtPolyRef* randomRef, float* randomPt) const;
|
||||||
|
|
||||||
|
/// Finds the closest point on the specified polygon.
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
|
/// @param[out] closest The closest point on the polygon. [(x, y, z)]
|
||||||
|
/// @param[out] posOverPoly True of the position is over the polygon.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const;
|
||||||
|
|
||||||
|
/// Returns a point on the boundary closest to the source point if the source point is outside the
|
||||||
|
/// polygon's xz-bounds.
|
||||||
|
/// @param[in] ref The reference id to the polygon.
|
||||||
|
/// @param[in] pos The position to check. [(x, y, z)]
|
||||||
|
/// @param[out] closest The closest point. [(x, y, z)]
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const;
|
||||||
|
|
||||||
|
/// Gets the height of the polygon at the provided position using the height detail. (Most accurate.)
|
||||||
|
/// @param[in] ref The reference id of the polygon.
|
||||||
|
/// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)]
|
||||||
|
/// @param[out] height The height at the surface of the polygon.
|
||||||
|
/// @returns The status flags for the query.
|
||||||
|
dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const;
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Miscellaneous Functions
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is valid and passes the filter restrictions.
|
||||||
|
/// @param[in] ref The polygon reference to check.
|
||||||
|
/// @param[in] filter The filter to apply.
|
||||||
|
bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const;
|
||||||
|
|
||||||
|
/// Returns true if the polygon reference is in the closed list.
|
||||||
|
/// @param[in] ref The reference id of the polygon to check.
|
||||||
|
/// @returns True if the polygon is in closed list.
|
||||||
|
bool isInClosedList(dtPolyRef ref) const;
|
||||||
|
|
||||||
|
/// Gets the node pool.
|
||||||
|
/// @returns The node pool.
|
||||||
|
class dtNodePool* getNodePool() const { return m_nodePool; }
|
||||||
|
|
||||||
|
/// Gets the navigation mesh the query object is using.
|
||||||
|
/// @return The navigation mesh the query object is using.
|
||||||
|
const dtNavMesh* getAttachedNavMesh() const { return m_nav; }
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Returns neighbour tile based on side.
|
||||||
|
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
||||||
|
|
||||||
|
/// Queries polygons within a tile.
|
||||||
|
int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter,
|
||||||
|
dtPolyRef* polys, const int maxPolys) const;
|
||||||
|
|
||||||
|
/// Returns portal points between two polygons.
|
||||||
|
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
||||||
|
unsigned char& fromType, unsigned char& toType) const;
|
||||||
|
dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
|
float* left, float* right) const;
|
||||||
|
|
||||||
|
/// Returns edge mid point between two polygons.
|
||||||
|
dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
|
||||||
|
dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
|
||||||
|
dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
|
||||||
|
float* mid) const;
|
||||||
|
|
||||||
|
// Appends vertex to a straight path
|
||||||
|
dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath) const;
|
||||||
|
|
||||||
|
// Appends intermediate portal points to a straight path.
|
||||||
|
dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
|
||||||
|
float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
|
||||||
|
int* straightPathCount, const int maxStraightPath, const int options) const;
|
||||||
|
|
||||||
|
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
||||||
|
|
||||||
|
struct dtQueryData
|
||||||
|
{
|
||||||
|
dtStatus status;
|
||||||
|
struct dtNode* lastBestNode;
|
||||||
|
float lastBestNodeCost;
|
||||||
|
dtPolyRef startRef, endRef;
|
||||||
|
float startPos[3], endPos[3];
|
||||||
|
const dtQueryFilter* filter;
|
||||||
|
unsigned int options;
|
||||||
|
float raycastLimitSqr;
|
||||||
|
};
|
||||||
|
dtQueryData m_query; ///< Sliced query state.
|
||||||
|
|
||||||
|
class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool.
|
||||||
|
class dtNodePool* m_nodePool; ///< Pointer to node pool.
|
||||||
|
class dtNodeQueue* m_openList; ///< Pointer to open list queue.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allocates a query object using the Detour allocator.
|
||||||
|
/// @return An allocated query object, or null on failure.
|
||||||
|
/// @ingroup detour
|
||||||
|
dtNavMeshQuery* dtAllocNavMeshQuery();
|
||||||
|
|
||||||
|
/// Frees the specified query object using the Detour allocator.
|
||||||
|
/// @param[in] query A query object allocated using #dtAllocNavMeshQuery
|
||||||
|
/// @ingroup detour
|
||||||
|
void dtFreeNavMeshQuery(dtNavMeshQuery* query);
|
||||||
|
|
||||||
|
#endif // DETOURNAVMESHQUERY_H
|
||||||
+20
-9
@@ -25,22 +25,28 @@ enum dtNodeFlags
|
|||||||
{
|
{
|
||||||
DT_NODE_OPEN = 0x01,
|
DT_NODE_OPEN = 0x01,
|
||||||
DT_NODE_CLOSED = 0x02,
|
DT_NODE_CLOSED = 0x02,
|
||||||
|
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned short dtNodeIndex;
|
typedef unsigned short dtNodeIndex;
|
||||||
static const dtNodeIndex DT_NULL_IDX = ~0;
|
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
||||||
|
|
||||||
struct dtNode
|
struct dtNode
|
||||||
{
|
{
|
||||||
float pos[3]; // Position of the node.
|
float pos[3]; ///< Position of the node.
|
||||||
float cost; // Cost from previous node to current node.
|
float cost; ///< Cost from previous node to current node.
|
||||||
float total; // Cost up to the node.
|
float total; ///< Cost up to the node.
|
||||||
unsigned int pidx : 30; // Index to parent node.
|
unsigned int pidx : 24; ///< Index to parent node.
|
||||||
unsigned int flags : 2; // Node flags 0/open/closed.
|
unsigned int state : 2; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||||
dtPolyRef id; // Polygon ref the node corresponds to.
|
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||||
|
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const int DT_MAX_STATES_PER_NODE = 4; // number of extra states per node. See dtNode::state
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class dtNodePool
|
class dtNodePool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -48,8 +54,12 @@ public:
|
|||||||
~dtNodePool();
|
~dtNodePool();
|
||||||
inline void operator=(const dtNodePool&) {}
|
inline void operator=(const dtNodePool&) {}
|
||||||
void clear();
|
void clear();
|
||||||
dtNode* getNode(dtPolyRef id);
|
|
||||||
dtNode* findNode(dtPolyRef id);
|
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||||
|
// There can be more than one node for the same polyRef but with different extra state information
|
||||||
|
dtNode* getNode(dtPolyRef id, unsigned char state=0);
|
||||||
|
dtNode* findNode(dtPolyRef id, unsigned char state);
|
||||||
|
unsigned int findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes);
|
||||||
|
|
||||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||||
{
|
{
|
||||||
@@ -82,6 +92,7 @@ public:
|
|||||||
inline int getHashSize() const { return m_hashSize; }
|
inline int getHashSize() const { return m_hashSize; }
|
||||||
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; }
|
||||||
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
inline dtNodeIndex getNext(int i) const { return m_next[i]; }
|
||||||
|
inline int getNodeCount() const { return m_nodeCount; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DETOURSTATUS_H
|
||||||
|
#define DETOURSTATUS_H
|
||||||
|
|
||||||
|
typedef unsigned int dtStatus;
|
||||||
|
|
||||||
|
// High level status.
|
||||||
|
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
|
||||||
|
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
|
||||||
|
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
|
||||||
|
|
||||||
|
// Detail information for status.
|
||||||
|
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
|
||||||
|
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
|
||||||
|
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
|
||||||
|
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
|
||||||
|
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
|
||||||
|
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
|
||||||
|
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
|
||||||
|
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true of status is success.
|
||||||
|
inline bool dtStatusSucceed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_SUCCESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is failure.
|
||||||
|
inline bool dtStatusFailed(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_FAILURE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true of status is in progress.
|
||||||
|
inline bool dtStatusInProgress(dtStatus status)
|
||||||
|
{
|
||||||
|
return (status & DT_IN_PROGRESS) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if specific detail is set.
|
||||||
|
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
|
||||||
|
{
|
||||||
|
return (status & detail) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DETOURSTATUS_H
|
||||||
+64
-6
@@ -16,16 +16,11 @@
|
|||||||
// 3. This notice may not be removed or altered from any source distribution.
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include "DetourCommon.h"
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
float dtSqrt(float x)
|
|
||||||
{
|
|
||||||
return sqrtf(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dtClosestPtPointTriangle(float* closest, const float* p,
|
void dtClosestPtPointTriangle(float* closest, const float* p,
|
||||||
const float* a, const float* b, const float* c)
|
const float* a, const float* b, const float* c)
|
||||||
{
|
{
|
||||||
@@ -238,6 +233,9 @@ bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All points are projected onto the xz-plane, so the y-values are ignored.
|
||||||
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
bool dtPointInPolygon(const float* pt, const float* verts, const int nverts)
|
||||||
{
|
{
|
||||||
// TODO: Replace pnpoly with triArea2D tests?
|
// TODO: Replace pnpoly with triArea2D tests?
|
||||||
@@ -291,6 +289,9 @@ inline bool overlapRange(const float amin, const float amax,
|
|||||||
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// All vertices are projected onto the xz-plane, so the y-values are ignored.
|
||||||
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
||||||
const float* polyb, const int npolyb)
|
const float* polyb, const int npolyb)
|
||||||
{
|
{
|
||||||
@@ -327,3 +328,60 @@ bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a random point in a convex polygon.
|
||||||
|
// Adapted from Graphics Gems article.
|
||||||
|
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||||
|
const float s, const float t, float* out)
|
||||||
|
{
|
||||||
|
// Calc triangle araes
|
||||||
|
float areasum = 0.0f;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]);
|
||||||
|
areasum += dtMax(0.001f, areas[i]);
|
||||||
|
}
|
||||||
|
// Find sub triangle weighted by area.
|
||||||
|
const float thr = s*areasum;
|
||||||
|
float acc = 0.0f;
|
||||||
|
float u = 0.0f;
|
||||||
|
int tri = 0;
|
||||||
|
for (int i = 2; i < npts; i++) {
|
||||||
|
const float dacc = areas[i];
|
||||||
|
if (thr >= acc && thr < (acc+dacc))
|
||||||
|
{
|
||||||
|
u = (thr - acc) / dacc;
|
||||||
|
tri = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acc += dacc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float v = dtMathSqrtf(t);
|
||||||
|
|
||||||
|
const float a = 1 - v;
|
||||||
|
const float b = (1 - u) * v;
|
||||||
|
const float c = u * v;
|
||||||
|
const float* pa = &pts[0];
|
||||||
|
const float* pb = &pts[(tri-1)*3];
|
||||||
|
const float* pc = &pts[tri*3];
|
||||||
|
|
||||||
|
out[0] = a*pa[0] + b*pb[0] + c*pc[0];
|
||||||
|
out[1] = a*pa[1] + b*pb[1] + c*pc[1];
|
||||||
|
out[2] = a*pa[2] + b*pb[2] + c*pc[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; }
|
||||||
|
|
||||||
|
bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||||
|
const float* bp, const float* bq,
|
||||||
|
float& s, float& t)
|
||||||
|
{
|
||||||
|
float u[3], v[3], w[3];
|
||||||
|
dtVsub(u,aq,ap);
|
||||||
|
dtVsub(v,bq,bp);
|
||||||
|
dtVsub(w,ap,bp);
|
||||||
|
float d = vperpXZ(u,v);
|
||||||
|
if (fabsf(d) < 1e-6f) return false;
|
||||||
|
s = vperpXZ(v,w) / d;
|
||||||
|
t = vperpXZ(u,w) / d;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
+422
-165
File diff suppressed because it is too large
Load Diff
+133
-128
@@ -16,12 +16,13 @@
|
|||||||
// 3. This notice may not be removed or altered from any source distribution.
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <float.h>
|
||||||
#include "DetourNavMesh.h"
|
#include "DetourNavMesh.h"
|
||||||
#include "DetourCommon.h"
|
#include "DetourCommon.h"
|
||||||
|
#include "DetourMath.h"
|
||||||
#include "DetourNavMeshBuilder.h"
|
#include "DetourNavMeshBuilder.h"
|
||||||
#include "DetourAlloc.h"
|
#include "DetourAlloc.h"
|
||||||
#include "DetourAssert.h"
|
#include "DetourAssert.h"
|
||||||
@@ -201,8 +202,8 @@ static int createBVTree(const unsigned short* verts, const int /*nverts*/,
|
|||||||
if (z > it.bmax[2]) it.bmax[2] = z;
|
if (z > it.bmax[2]) it.bmax[2] = z;
|
||||||
}
|
}
|
||||||
// Remap y
|
// Remap y
|
||||||
it.bmin[1] = (unsigned short)floorf((float)it.bmin[1]*ch/cs);
|
it.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1]*ch/cs);
|
||||||
it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
|
it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1]*ch/cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int curNode = 0;
|
int curNode = 0;
|
||||||
@@ -237,11 +238,19 @@ static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, co
|
|||||||
case ZM: return 6;
|
case ZM: return 6;
|
||||||
case XP|ZM: return 7;
|
case XP|ZM: return 7;
|
||||||
};
|
};
|
||||||
|
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Better error handling.
|
// TODO: Better error handling.
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// The output data array is allocated using the detour allocator (dtAlloc()). The method
|
||||||
|
/// used to free the memory will be determined by how the tile is added to the navigation
|
||||||
|
/// mesh.
|
||||||
|
///
|
||||||
|
/// @see dtNavMesh, dtNavMesh::addTile()
|
||||||
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
|
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
|
||||||
{
|
{
|
||||||
if (params->nvp > DT_VERTS_PER_POLYGON)
|
if (params->nvp > DT_VERTS_PER_POLYGON)
|
||||||
@@ -252,8 +261,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
return false;
|
return false;
|
||||||
if (!params->polyCount || !params->polys)
|
if (!params->polyCount || !params->polys)
|
||||||
return false;
|
return false;
|
||||||
//if (!params->detailMeshes || !params->detailVerts || !params->detailTris)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
const int nvp = params->nvp;
|
const int nvp = params->nvp;
|
||||||
|
|
||||||
@@ -269,10 +276,50 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
if (!offMeshConClass)
|
if (!offMeshConClass)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Find tight heigh bounds, used for culling out off-mesh start locations.
|
||||||
|
float hmin = FLT_MAX;
|
||||||
|
float hmax = -FLT_MAX;
|
||||||
|
|
||||||
|
if (params->detailVerts && params->detailVertsCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->detailVertsCount; ++i)
|
||||||
|
{
|
||||||
|
const float h = params->detailVerts[i*3+1];
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params->vertCount; ++i)
|
||||||
|
{
|
||||||
|
const unsigned short* iv = ¶ms->verts[i*3];
|
||||||
|
const float h = params->bmin[1] + iv[1] * params->ch;
|
||||||
|
hmin = dtMin(hmin,h);
|
||||||
|
hmax = dtMax(hmax,h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hmin -= params->walkableClimb;
|
||||||
|
hmax += params->walkableClimb;
|
||||||
|
float bmin[3], bmax[3];
|
||||||
|
dtVcopy(bmin, params->bmin);
|
||||||
|
dtVcopy(bmax, params->bmax);
|
||||||
|
bmin[1] = hmin;
|
||||||
|
bmax[1] = hmax;
|
||||||
|
|
||||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||||
{
|
{
|
||||||
offMeshConClass[i*2+0] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+0)*3], params->bmin, params->bmax);
|
const float* p0 = ¶ms->offMeshConVerts[(i*2+0)*3];
|
||||||
offMeshConClass[i*2+1] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+1)*3], params->bmin, params->bmax);
|
const float* p1 = ¶ms->offMeshConVerts[(i*2+1)*3];
|
||||||
|
offMeshConClass[i*2+0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||||
|
offMeshConClass[i*2+1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||||
|
|
||||||
|
// Zero out off-mesh start positions which are not even potentially touching the mesh.
|
||||||
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
|
{
|
||||||
|
if (p0[1] < bmin[1] || p0[1] > bmax[1])
|
||||||
|
offMeshConClass[i*2+0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Cound how many links should be allocated for off-mesh connections.
|
// Cound how many links should be allocated for off-mesh connections.
|
||||||
if (offMeshConClass[i*2+0] == 0xff)
|
if (offMeshConClass[i*2+0] == 0xff)
|
||||||
@@ -298,23 +345,13 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
for (int j = 0; j < nvp; ++j)
|
for (int j = 0; j < nvp; ++j)
|
||||||
{
|
{
|
||||||
if (p[j] == MESH_NULL_IDX) break;
|
if (p[j] == MESH_NULL_IDX) break;
|
||||||
int nj = j+1;
|
|
||||||
if (nj >= nvp || p[nj] == MESH_NULL_IDX) nj = 0;
|
|
||||||
const unsigned short* va = ¶ms->verts[p[j]*3];
|
|
||||||
const unsigned short* vb = ¶ms->verts[p[nj]*3];
|
|
||||||
|
|
||||||
edgeCount++;
|
edgeCount++;
|
||||||
|
|
||||||
if (params->tileSize > 0)
|
if (p[nvp+j] & 0x8000)
|
||||||
{
|
{
|
||||||
if (va[0] == params->tileSize && vb[0] == params->tileSize)
|
unsigned short dir = p[nvp+j] & 0xf;
|
||||||
portalCount++; // x+
|
if (dir != 0xf)
|
||||||
else if (va[2] == params->tileSize && vb[2] == params->tileSize)
|
portalCount++;
|
||||||
portalCount++; // z+
|
|
||||||
else if (va[0] == 0 && vb[0] == 0)
|
|
||||||
portalCount++; // x-
|
|
||||||
else if (va[2] == 0 && vb[2] == 0)
|
|
||||||
portalCount++; // z-
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,7 +405,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
||||||
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
||||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
||||||
const int bvTreeSize = dtAlign4(sizeof(dtBVNode)*params->polyCount*2);
|
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
|
||||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
||||||
|
|
||||||
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
||||||
@@ -400,6 +437,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
header->version = DT_NAVMESH_VERSION;
|
header->version = DT_NAVMESH_VERSION;
|
||||||
header->x = params->tileX;
|
header->x = params->tileX;
|
||||||
header->y = params->tileY;
|
header->y = params->tileY;
|
||||||
|
header->layer = params->tileLayer;
|
||||||
header->userId = params->userId;
|
header->userId = params->userId;
|
||||||
header->polyCount = totPolyCount;
|
header->polyCount = totPolyCount;
|
||||||
header->vertCount = totVertCount;
|
header->vertCount = totVertCount;
|
||||||
@@ -415,7 +453,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
header->walkableRadius = params->walkableRadius;
|
header->walkableRadius = params->walkableRadius;
|
||||||
header->walkableClimb = params->walkableClimb;
|
header->walkableClimb = params->walkableClimb;
|
||||||
header->offMeshConCount = storedOffMeshConCount;
|
header->offMeshConCount = storedOffMeshConCount;
|
||||||
header->bvNodeCount = params->polyCount*2;
|
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
|
||||||
|
|
||||||
const int offMeshVertsBase = params->vertCount;
|
const int offMeshVertsBase = params->vertCount;
|
||||||
const int offMeshPolyBase = params->polyCount;
|
const int offMeshPolyBase = params->polyCount;
|
||||||
@@ -459,7 +497,27 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
{
|
{
|
||||||
if (src[j] == MESH_NULL_IDX) break;
|
if (src[j] == MESH_NULL_IDX) break;
|
||||||
p->verts[j] = src[j];
|
p->verts[j] = src[j];
|
||||||
p->neis[j] = (src[nvp+j]+1) & 0xffff;
|
if (src[nvp+j] & 0x8000)
|
||||||
|
{
|
||||||
|
// Border or portal edge.
|
||||||
|
unsigned short dir = src[nvp+j] & 0xf;
|
||||||
|
if (dir == 0xf) // Border
|
||||||
|
p->neis[j] = 0;
|
||||||
|
else if (dir == 0) // Portal x-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 4;
|
||||||
|
else if (dir == 1) // Portal z+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 2;
|
||||||
|
else if (dir == 2) // Portal x+
|
||||||
|
p->neis[j] = DT_EXT_LINK | 0;
|
||||||
|
else if (dir == 3) // Portal z-
|
||||||
|
p->neis[j] = DT_EXT_LINK | 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normal connection
|
||||||
|
p->neis[j] = src[nvp+j]+1;
|
||||||
|
}
|
||||||
|
|
||||||
p->vertCount++;
|
p->vertCount++;
|
||||||
}
|
}
|
||||||
src += nvp*2;
|
src += nvp*2;
|
||||||
@@ -482,32 +540,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store portal edges.
|
|
||||||
if (params->tileSize > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < params->polyCount; ++i)
|
|
||||||
{
|
|
||||||
dtPoly* poly = &navPolys[i];
|
|
||||||
for (int j = 0; j < poly->vertCount; ++j)
|
|
||||||
{
|
|
||||||
int nj = j+1;
|
|
||||||
if (nj >= poly->vertCount) nj = 0;
|
|
||||||
|
|
||||||
const unsigned short* va = ¶ms->verts[poly->verts[j]*3];
|
|
||||||
const unsigned short* vb = ¶ms->verts[poly->verts[nj]*3];
|
|
||||||
|
|
||||||
if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 0;
|
|
||||||
else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 2;
|
|
||||||
else if (va[0] == 0 && vb[0] == 0) // x-
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 4;
|
|
||||||
else if (va[2] == 0 && vb[2] == 0) // z-
|
|
||||||
poly->neis[j] = DT_EXT_LINK | 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store detail meshes and vertices.
|
// Store detail meshes and vertices.
|
||||||
// The nav polygon vertices are stored as the first vertices on each mesh.
|
// The nav polygon vertices are stored as the first vertices on each mesh.
|
||||||
// We compress the mesh data by skipping them and using the navmesh coordinates.
|
// We compress the mesh data by skipping them and using the navmesh coordinates.
|
||||||
@@ -564,8 +596,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
|
|
||||||
// Store and create BVtree.
|
// Store and create BVtree.
|
||||||
// TODO: take detail mesh into account! use byte per bbox extent?
|
// TODO: take detail mesh into account! use byte per bbox extent?
|
||||||
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
|
if (params->buildBvTree)
|
||||||
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
|
{
|
||||||
|
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
|
||||||
|
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
|
||||||
|
}
|
||||||
|
|
||||||
// Store Off-Mesh connections.
|
// Store Off-Mesh connections.
|
||||||
n = 0;
|
n = 0;
|
||||||
@@ -597,51 +632,14 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void swapByte(unsigned char* a, unsigned char* b)
|
|
||||||
{
|
|
||||||
unsigned char tmp = *a;
|
|
||||||
*a = *b;
|
|
||||||
*b = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(unsigned short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(short* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(unsigned int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(int* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void swapEndian(float* v)
|
|
||||||
{
|
|
||||||
unsigned char* x = (unsigned char*)v;
|
|
||||||
swapByte(x+0, x+3); swapByte(x+1, x+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
{
|
{
|
||||||
dtMeshHeader* header = (dtMeshHeader*)data;
|
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||||
|
|
||||||
int swappedMagic = DT_NAVMESH_MAGIC;
|
int swappedMagic = DT_NAVMESH_MAGIC;
|
||||||
int swappedVersion = DT_NAVMESH_VERSION;
|
int swappedVersion = DT_NAVMESH_VERSION;
|
||||||
swapEndian(&swappedMagic);
|
dtSwapEndian(&swappedMagic);
|
||||||
swapEndian(&swappedVersion);
|
dtSwapEndian(&swappedVersion);
|
||||||
|
|
||||||
if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) &&
|
if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) &&
|
||||||
(header->magic != swappedMagic || header->version != swappedVersion))
|
(header->magic != swappedMagic || header->version != swappedVersion))
|
||||||
@@ -649,36 +647,43 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
swapEndian(&header->magic);
|
dtSwapEndian(&header->magic);
|
||||||
swapEndian(&header->version);
|
dtSwapEndian(&header->version);
|
||||||
swapEndian(&header->x);
|
dtSwapEndian(&header->x);
|
||||||
swapEndian(&header->y);
|
dtSwapEndian(&header->y);
|
||||||
swapEndian(&header->userId);
|
dtSwapEndian(&header->layer);
|
||||||
swapEndian(&header->polyCount);
|
dtSwapEndian(&header->userId);
|
||||||
swapEndian(&header->vertCount);
|
dtSwapEndian(&header->polyCount);
|
||||||
swapEndian(&header->maxLinkCount);
|
dtSwapEndian(&header->vertCount);
|
||||||
swapEndian(&header->detailMeshCount);
|
dtSwapEndian(&header->maxLinkCount);
|
||||||
swapEndian(&header->detailVertCount);
|
dtSwapEndian(&header->detailMeshCount);
|
||||||
swapEndian(&header->detailTriCount);
|
dtSwapEndian(&header->detailVertCount);
|
||||||
swapEndian(&header->bvNodeCount);
|
dtSwapEndian(&header->detailTriCount);
|
||||||
swapEndian(&header->offMeshConCount);
|
dtSwapEndian(&header->bvNodeCount);
|
||||||
swapEndian(&header->offMeshBase);
|
dtSwapEndian(&header->offMeshConCount);
|
||||||
swapEndian(&header->walkableHeight);
|
dtSwapEndian(&header->offMeshBase);
|
||||||
swapEndian(&header->walkableRadius);
|
dtSwapEndian(&header->walkableHeight);
|
||||||
swapEndian(&header->walkableClimb);
|
dtSwapEndian(&header->walkableRadius);
|
||||||
swapEndian(&header->bmin[0]);
|
dtSwapEndian(&header->walkableClimb);
|
||||||
swapEndian(&header->bmin[1]);
|
dtSwapEndian(&header->bmin[0]);
|
||||||
swapEndian(&header->bmin[2]);
|
dtSwapEndian(&header->bmin[1]);
|
||||||
swapEndian(&header->bmax[0]);
|
dtSwapEndian(&header->bmin[2]);
|
||||||
swapEndian(&header->bmax[1]);
|
dtSwapEndian(&header->bmax[0]);
|
||||||
swapEndian(&header->bmax[2]);
|
dtSwapEndian(&header->bmax[1]);
|
||||||
swapEndian(&header->bvQuantFactor);
|
dtSwapEndian(&header->bmax[2]);
|
||||||
|
dtSwapEndian(&header->bvQuantFactor);
|
||||||
|
|
||||||
// Freelist index and pointers are updated when tile is added, no need to swap.
|
// Freelist index and pointers are updated when tile is added, no need to swap.
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// @warning This function assumes that the header is in the correct endianess already.
|
||||||
|
/// Call #dtNavMeshHeaderSwapEndian() first on the data if the data is expected to be in wrong endianess
|
||||||
|
/// to start with. Call #dtNavMeshHeaderSwapEndian() after the data has been swapped if converting from
|
||||||
|
/// native to foreign endianess.
|
||||||
bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||||
{
|
{
|
||||||
// Make sure the data is in right format.
|
// Make sure the data is in right format.
|
||||||
@@ -712,7 +717,7 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
// Vertices
|
// Vertices
|
||||||
for (int i = 0; i < header->vertCount*3; ++i)
|
for (int i = 0; i < header->vertCount*3; ++i)
|
||||||
{
|
{
|
||||||
swapEndian(&verts[i]);
|
dtSwapEndian(&verts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polys
|
// Polys
|
||||||
@@ -722,10 +727,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
// poly->firstLink is update when tile is added, no need to swap.
|
// poly->firstLink is update when tile is added, no need to swap.
|
||||||
for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j)
|
for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j)
|
||||||
{
|
{
|
||||||
swapEndian(&p->verts[j]);
|
dtSwapEndian(&p->verts[j]);
|
||||||
swapEndian(&p->neis[j]);
|
dtSwapEndian(&p->neis[j]);
|
||||||
}
|
}
|
||||||
swapEndian(&p->flags);
|
dtSwapEndian(&p->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Links are rebuild when tile is added, no need to swap.
|
// Links are rebuild when tile is added, no need to swap.
|
||||||
@@ -734,14 +739,14 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
for (int i = 0; i < header->detailMeshCount; ++i)
|
for (int i = 0; i < header->detailMeshCount; ++i)
|
||||||
{
|
{
|
||||||
dtPolyDetail* pd = &detailMeshes[i];
|
dtPolyDetail* pd = &detailMeshes[i];
|
||||||
swapEndian(&pd->vertBase);
|
dtSwapEndian(&pd->vertBase);
|
||||||
swapEndian(&pd->triBase);
|
dtSwapEndian(&pd->triBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail verts
|
// Detail verts
|
||||||
for (int i = 0; i < header->detailVertCount*3; ++i)
|
for (int i = 0; i < header->detailVertCount*3; ++i)
|
||||||
{
|
{
|
||||||
swapEndian(&detailVerts[i]);
|
dtSwapEndian(&detailVerts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BV-tree
|
// BV-tree
|
||||||
@@ -750,10 +755,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
dtBVNode* node = &bvTree[i];
|
dtBVNode* node = &bvTree[i];
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
{
|
{
|
||||||
swapEndian(&node->bmin[j]);
|
dtSwapEndian(&node->bmin[j]);
|
||||||
swapEndian(&node->bmax[j]);
|
dtSwapEndian(&node->bmax[j]);
|
||||||
}
|
}
|
||||||
swapEndian(&node->i);
|
dtSwapEndian(&node->i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off-mesh Connections.
|
// Off-mesh Connections.
|
||||||
@@ -761,9 +766,9 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||||||
{
|
{
|
||||||
dtOffMeshConnection* con = &offMeshCons[i];
|
dtOffMeshConnection* con = &offMeshCons[i];
|
||||||
for (int j = 0; j < 6; ++j)
|
for (int j = 0; j < 6; ++j)
|
||||||
swapEndian(&con->pos[j]);
|
dtSwapEndian(&con->pos[j]);
|
||||||
swapEndian(&con->rad);
|
dtSwapEndian(&con->rad);
|
||||||
swapEndian(&con->poly);
|
dtSwapEndian(&con->poly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
+1319
-354
File diff suppressed because it is too large
Load Diff
+24
-3
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
inline unsigned int dtHashRef(dtPolyRef a)
|
inline unsigned int dtHashRef(dtPolyRef a)
|
||||||
{
|
{
|
||||||
|
// Edited by TC
|
||||||
a = (~a) + (a << 18);
|
a = (~a) + (a << 18);
|
||||||
a = a ^ (a >> 31);
|
a = a ^ (a >> 31);
|
||||||
a = a * 21;
|
a = a * 21;
|
||||||
@@ -70,27 +71,46 @@ void dtNodePool::clear()
|
|||||||
m_nodeCount = 0;
|
m_nodeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dtNode* dtNodePool::findNode(dtPolyRef id)
|
unsigned int dtNodePool::findNodes(dtPolyRef id, dtNode** nodes, const int maxNodes)
|
||||||
{
|
{
|
||||||
|
int n = 0;
|
||||||
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
dtNodeIndex i = m_first[bucket];
|
dtNodeIndex i = m_first[bucket];
|
||||||
while (i != DT_NULL_IDX)
|
while (i != DT_NULL_IDX)
|
||||||
{
|
{
|
||||||
if (m_nodes[i].id == id)
|
if (m_nodes[i].id == id)
|
||||||
|
{
|
||||||
|
if (n >= maxNodes)
|
||||||
|
return n;
|
||||||
|
nodes[n++] = &m_nodes[i];
|
||||||
|
}
|
||||||
|
i = m_next[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtNode* dtNodePool::findNode(dtPolyRef id, unsigned char state)
|
||||||
|
{
|
||||||
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
|
dtNodeIndex i = m_first[bucket];
|
||||||
|
while (i != DT_NULL_IDX)
|
||||||
|
{
|
||||||
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
return &m_nodes[i];
|
return &m_nodes[i];
|
||||||
i = m_next[i];
|
i = m_next[i];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dtNode* dtNodePool::getNode(dtPolyRef id)
|
dtNode* dtNodePool::getNode(dtPolyRef id, unsigned char state)
|
||||||
{
|
{
|
||||||
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
|
||||||
dtNodeIndex i = m_first[bucket];
|
dtNodeIndex i = m_first[bucket];
|
||||||
dtNode* node = 0;
|
dtNode* node = 0;
|
||||||
while (i != DT_NULL_IDX)
|
while (i != DT_NULL_IDX)
|
||||||
{
|
{
|
||||||
if (m_nodes[i].id == id)
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
return &m_nodes[i];
|
return &m_nodes[i];
|
||||||
i = m_next[i];
|
i = m_next[i];
|
||||||
}
|
}
|
||||||
@@ -107,6 +127,7 @@ dtNode* dtNodePool::getNode(dtPolyRef id)
|
|||||||
node->cost = 0;
|
node->cost = 0;
|
||||||
node->total = 0;
|
node->total = 0;
|
||||||
node->id = id;
|
node->id = id;
|
||||||
|
node->state = state;
|
||||||
node->flags = 0;
|
node->flags = 0;
|
||||||
|
|
||||||
m_next[i] = m_first[bucket];
|
m_next[i] = m_first[bucket];
|
||||||
@@ -33,7 +33,7 @@ set(collision_STAT_SRCS
|
|||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour/Include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Configuration
|
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Configuration
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Debugging
|
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Debugging
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace VMAP
|
|||||||
float iScale;
|
float iScale;
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi()*iDir.y/180.f, G3D::pi()*iDir.x/180.f, G3D::pi()*iDir.z/180.f);
|
iRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::pif()*iDir.y/180.f, G3D::pif()*iDir.x/180.f, G3D::pif()*iDir.z/180.f);
|
||||||
}
|
}
|
||||||
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
|
G3D::Vector3 transform(const G3D::Vector3& pIn) const;
|
||||||
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
|
void moveToBasePos(const G3D::Vector3& pBasePos) { iPos -= pBasePos; }
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||||
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STRING_FORMAT_H__
|
||||||
|
#define __STRING_FORMAT_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace Trinity
|
||||||
|
{
|
||||||
|
/// Default TC string format function.
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::string StringFormat(const std::string& format, Args const&... args)
|
||||||
|
{
|
||||||
|
size_t size = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra space for '\0'
|
||||||
|
unique_ptr<char[]> buf(new char[size]);
|
||||||
|
std::snprintf(buf.get(), size, format.c_str(), args ...);
|
||||||
|
return std::string(buf.get(), buf.get() + size - 1); // We don
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given char pointer is null.
|
||||||
|
inline bool IsFormatEmptyOrNull(const char* fmt)
|
||||||
|
{
|
||||||
|
return fmt == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given std::string is empty.
|
||||||
|
inline bool IsFormatEmptyOrNull(std::string const& fmt)
|
||||||
|
{
|
||||||
|
return fmt.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -429,7 +429,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
|||||||
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
|
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area))
|
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area))
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
|
sLog->outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
|
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
|
||||||
if (!GetAreaEntryByAreaID(area.id))
|
if (!sAreaTableStore.LookupEntry(area.id))
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.",
|
sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.",
|
||||||
criteria->ID, criteria->requiredType, dataType, area.id);
|
criteria->ID, criteria->requiredType, dataType, area.id);
|
||||||
@@ -1277,17 +1277,15 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
|||||||
bool matchFound = false;
|
bool matchFound = false;
|
||||||
for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
|
for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
|
||||||
{
|
{
|
||||||
uint32 area_id = worldOverlayEntry->areatableID[j];
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->areatableID[j]);
|
||||||
if (!area_id) // array have 0 only in empty tail
|
if (!area)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int32 exploreFlag = GetAreaFlagByAreaID(area_id);
|
uint32 playerIndexOffset = uint32(area->exploreFlag) / 32;
|
||||||
if (exploreFlag < 0)
|
if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32 playerIndexOffset = uint32(exploreFlag) / 32;
|
uint32 mask = 1 << (uint32(area->exploreFlag) % 32);
|
||||||
uint32 mask = 1<< (uint32(exploreFlag) % 32);
|
|
||||||
|
|
||||||
if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
|
if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
|
||||||
{
|
{
|
||||||
matchFound = true;
|
matchFound = true;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ set(game_STAT_SRCS
|
|||||||
include_directories(
|
include_directories(
|
||||||
${game_INCLUDE_DIRS}
|
${game_INCLUDE_DIRS}
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour/Include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
||||||
|
|||||||
@@ -301,11 +301,11 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c
|
|||||||
uint32 areaId = player->GetAreaId();
|
uint32 areaId = player->GetAreaId();
|
||||||
std::string areaName = "Unknown";
|
std::string areaName = "Unknown";
|
||||||
std::string zoneName = "Unknown";
|
std::string zoneName = "Unknown";
|
||||||
if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||||
{
|
{
|
||||||
int locale = GetSessionDbcLocale();
|
int locale = GetSessionDbcLocale();
|
||||||
areaName = area->area_name[locale];
|
areaName = area->area_name[locale];
|
||||||
if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone))
|
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))
|
||||||
zoneName = zone->area_name[locale];
|
zoneName = zone->area_name[locale];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1658,7 +1658,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
|
|||||||
}
|
}
|
||||||
case CONDITION_ZONEID:
|
case CONDITION_ZONEID:
|
||||||
{
|
{
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);
|
||||||
if (!areaEntry)
|
if (!areaEntry)
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1);
|
sLog->outErrorDb("ZoneID condition has non existing area (%u), skipped", cond->ConditionValue1);
|
||||||
|
|||||||
@@ -38,11 +38,9 @@ struct WMOAreaTableTripple
|
|||||||
|
|
||||||
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
|
typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;
|
||||||
|
|
||||||
DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt);
|
DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);
|
||||||
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);
|
||||||
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
|
DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt);
|
||||||
static AreaFlagByAreaID sAreaFlagByAreaID;
|
|
||||||
static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files
|
|
||||||
|
|
||||||
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
|
static WMOAreaInfoByTripple sWMOAreaInfoByTripple;
|
||||||
|
|
||||||
@@ -255,21 +253,7 @@ void LoadDBCStores(const std::string& dataPath)
|
|||||||
StoreProblemList bad_dbc_files;
|
StoreProblemList bad_dbc_files;
|
||||||
uint32 availableDbcLocales = 0xFFFFFFFF;
|
uint32 availableDbcLocales = 0xFFFFFFFF;
|
||||||
|
|
||||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaStore, dbcPath, "AreaTable.dbc");
|
LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTableStore, dbcPath, "AreaTable.dbc");
|
||||||
|
|
||||||
// must be after sAreaStore loading
|
|
||||||
for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0
|
|
||||||
{
|
|
||||||
if (AreaTableEntry const* area = sAreaStore.LookupEntry(i))
|
|
||||||
{
|
|
||||||
// fill AreaId->DBC records
|
|
||||||
sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->exploreFlag));
|
|
||||||
|
|
||||||
// fill MapId->DBC records (skip sub zones and continents)
|
|
||||||
if (area->zone == 0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571)
|
|
||||||
sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid, area->exploreFlag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);
|
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);
|
||||||
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");
|
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");
|
||||||
@@ -626,7 +610,7 @@ void LoadDBCStores(const std::string& dataPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check loaded DBC files proper version
|
// Check loaded DBC files proper version
|
||||||
if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a
|
if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a
|
||||||
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
|
!sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a
|
||||||
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
|
!sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a
|
||||||
!sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
|
!sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a
|
||||||
@@ -678,50 +662,12 @@ uint32 GetTalentSpellCost(uint32 spellId)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 GetAreaFlagByAreaID(uint32 area_id)
|
|
||||||
{
|
|
||||||
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
|
|
||||||
if (i == sAreaFlagByAreaID.end())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
|
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
|
||||||
{
|
{
|
||||||
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
|
WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid));
|
||||||
if (i == sWMOAreaInfoByTripple.end())
|
if (i == sWMOAreaInfoByTripple.end())
|
||||||
return NULL;
|
|
||||||
return i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
|
|
||||||
{
|
|
||||||
int32 areaflag = GetAreaFlagByAreaID(area_id);
|
|
||||||
if (areaflag < 0)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
return i->second;
|
||||||
return sAreaStore.LookupEntry(areaflag);
|
|
||||||
}
|
|
||||||
|
|
||||||
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id)
|
|
||||||
{
|
|
||||||
if (area_flag)
|
|
||||||
return sAreaStore.LookupEntry(area_flag);
|
|
||||||
|
|
||||||
if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id))
|
|
||||||
return GetAreaEntryByAreaID(mapEntry->linked_zone);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 GetAreaFlagByMapId(uint32 mapid)
|
|
||||||
{
|
|
||||||
AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid);
|
|
||||||
if (i == sAreaFlagByMapID.end())
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return i->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
|
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ char* GetPetName(uint32 petfamily, uint32 dbclang);
|
|||||||
uint32 GetTalentSpellCost(uint32 spellId);
|
uint32 GetTalentSpellCost(uint32 spellId);
|
||||||
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
||||||
|
|
||||||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
|
||||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
|
|
||||||
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id);
|
|
||||||
uint32 GetAreaFlagByMapId(uint32 mapid);
|
|
||||||
|
|
||||||
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid);
|
WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid);
|
||||||
|
|
||||||
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
|
uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId);
|
||||||
@@ -58,7 +53,7 @@ uint32 GetDefaultMapLight(uint32 mapId);
|
|||||||
|
|
||||||
extern DBCStorage <AchievementEntry> sAchievementStore;
|
extern DBCStorage <AchievementEntry> sAchievementStore;
|
||||||
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
|
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
|
||||||
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
|
extern DBCStorage <AreaTableEntry> sAreaTableStore;
|
||||||
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
|
extern DBCStorage <AreaGroupEntry> sAreaGroupStore;
|
||||||
extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
|
extern DBCStorage <AreaPOIEntry> sAreaPOIStore;
|
||||||
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
|
extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxx
|
|||||||
const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
|
const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";
|
||||||
const std::string CustomAchievementIndex = "ID";
|
const std::string CustomAchievementIndex = "ID";
|
||||||
char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix";
|
char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix";
|
||||||
char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx";
|
char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx";
|
||||||
char const AreaGroupEntryfmt[] = "niiiiiii";
|
char const AreaGroupEntryfmt[] = "niiiiiii";
|
||||||
char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
|
char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";
|
||||||
char const AreaTriggerEntryfmt[] = "niffffffff";
|
char const AreaTriggerEntryfmt[] = "niffffffff";
|
||||||
|
|||||||
@@ -5577,11 +5577,11 @@ void Player::RepopAtGraveyard()
|
|||||||
// note: this can be called also when the player is alive
|
// note: this can be called also when the player is alive
|
||||||
// for example from WorldSession::HandleMovementOpcodes
|
// for example from WorldSession::HandleMovementOpcodes
|
||||||
|
|
||||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId());
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
|
||||||
|
|
||||||
// Such zones are considered unreachable as a ghost and the player must be automatically revived
|
// Such zones are considered unreachable as a ghost and the player must be automatically revived
|
||||||
// Xinef: Get Transport Check is not needed
|
// Xinef: Get Transport Check is not needed
|
||||||
if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < -500.0f)
|
if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) /*|| GetTransport()*/ || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
|
||||||
{
|
{
|
||||||
ResurrectPlayer(0.5f);
|
ResurrectPlayer(0.5f);
|
||||||
SpawnCorpseBones();
|
SpawnCorpseBones();
|
||||||
@@ -5618,8 +5618,10 @@ void Player::RepopAtGraveyard()
|
|||||||
GetSession()->SendPacket(&data);
|
GetSession()->SendPacket(&data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GetPositionZ() < -500.0f)
|
else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
|
||||||
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
|
||||||
|
|
||||||
|
RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone)
|
bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone)
|
||||||
@@ -5671,7 +5673,7 @@ void Player::UpdateLocalChannels(uint32 newZone)
|
|||||||
if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
|
if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
|
||||||
return; // The client handles it automatically after loading, but not after teleporting
|
return; // The client handles it automatically after loading, but not after teleporting
|
||||||
|
|
||||||
AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone);
|
AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone);
|
||||||
if (!current_zone)
|
if (!current_zone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -6894,24 +6896,33 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool isOutdoor = IsOutdoors();
|
bool isOutdoor = IsOutdoors();
|
||||||
uint32 areaFlag = GetAreaFlagByAreaID(GetAreaId());
|
uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
|
||||||
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||||
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||||
RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
|
RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
|
||||||
|
|
||||||
if (areaFlag == 0xffff)
|
if (!areaId)
|
||||||
return;
|
return;
|
||||||
int offset = areaFlag / 32;
|
|
||||||
|
if (!areaEntry)
|
||||||
|
{
|
||||||
|
sLog->outError("Player '%s' (%u) discovered unknown area (x: %f y: %f z: %f map: %u)",
|
||||||
|
GetName().c_str(), GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 offset = areaEntry->exploreFlag / 32;
|
||||||
|
|
||||||
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||||
sLog->outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
|
sLog->outError("Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaEntry->flags, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 val = (uint32)(1 << (areaFlag % 32));
|
uint32 val = (uint32)(1 << (areaEntry->exploreFlag % 32));
|
||||||
uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
||||||
|
|
||||||
if (!(currFields & val))
|
if (!(currFields & val))
|
||||||
@@ -6920,19 +6931,11 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||||||
|
|
||||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, GetAreaId());
|
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA, GetAreaId());
|
||||||
|
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId());
|
|
||||||
if (!areaEntry)
|
|
||||||
{
|
|
||||||
sLog->outError("Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (areaEntry->area_level > 0)
|
if (areaEntry->area_level > 0)
|
||||||
{
|
{
|
||||||
uint32 area = areaEntry->ID;
|
|
||||||
if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||||
{
|
{
|
||||||
SendExplorationExperience(area, 0);
|
SendExplorationExperience(areaId, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -6958,10 +6961,10 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
GiveXP(XP, NULL);
|
GiveXP(XP, NULL);
|
||||||
SendExplorationExperience(area, XP);
|
SendExplorationExperience(areaId, XP);
|
||||||
}
|
}
|
||||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||||
sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), area);
|
sLog->outDetail("Player %u discovered a new area: %u", GetGUIDLow(), areaId);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7533,7 +7536,7 @@ void Player::UpdateArea(uint32 newArea)
|
|||||||
// so apply them accordingly
|
// so apply them accordingly
|
||||||
m_areaUpdateId = newArea;
|
m_areaUpdateId = newArea;
|
||||||
|
|
||||||
AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);
|
||||||
bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
|
bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
|
||||||
pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
|
pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
|
||||||
UpdatePvPState(true);
|
UpdatePvPState(true);
|
||||||
@@ -7568,7 +7571,7 @@ void Player::UpdateArea(uint32 newArea)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Xinef: area should inherit zone flags
|
// Xinef: area should inherit zone flags
|
||||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone);
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);
|
||||||
uint32 areaFlags = area->flags;
|
uint32 areaFlags = area->flags;
|
||||||
bool isSanctuary = area->IsSanctuary();
|
bool isSanctuary = area->IsSanctuary();
|
||||||
bool isInn = area->IsInn(GetTeamId(true));
|
bool isInn = area->IsInn(GetTeamId(true));
|
||||||
@@ -7656,7 +7659,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
|||||||
// zone changed, so area changed as well, update it
|
// zone changed, so area changed as well, update it
|
||||||
UpdateArea(newArea);
|
UpdateArea(newArea);
|
||||||
|
|
||||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone);
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone);
|
||||||
if (!zone)
|
if (!zone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -3395,6 +3395,15 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Unit::CanMoveDuringChannel() const
|
||||||
|
{
|
||||||
|
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
|
||||||
|
if (spell->getState() != SPELL_STATE_FINISHED)
|
||||||
|
return spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) && spell->IsChannelActive();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
|
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
|
||||||
{
|
{
|
||||||
return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
|
return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
|
||||||
|
|||||||
@@ -2048,6 +2048,9 @@ class Unit : public WorldObject
|
|||||||
// delayed+channeled spells are always interrupted
|
// delayed+channeled spells are always interrupted
|
||||||
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, bool bySelf = false);
|
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, bool bySelf = false);
|
||||||
|
|
||||||
|
// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING
|
||||||
|
bool CanMoveDuringChannel() const;
|
||||||
|
|
||||||
Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
|
Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
|
||||||
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
|
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
|
||||||
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
|
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
|
||||||
|
|||||||
@@ -2720,7 +2720,7 @@ void ObjectMgr::LoadItemTemplates()
|
|||||||
itemTemplate.ItemSet = 0;
|
itemTemplate.ItemSet = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area))
|
if (itemTemplate.Area && !sAreaTableStore.LookupEntry(itemTemplate.Area))
|
||||||
sLog->outErrorDb("Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area);
|
sLog->outErrorDb("Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area);
|
||||||
|
|
||||||
if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map))
|
if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map))
|
||||||
@@ -4022,7 +4022,7 @@ void ObjectMgr::LoadQuests()
|
|||||||
// client quest log visual (area case)
|
// client quest log visual (area case)
|
||||||
if (qinfo->ZoneOrSort > 0)
|
if (qinfo->ZoneOrSort > 0)
|
||||||
{
|
{
|
||||||
if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
|
if (!sAreaTableStore.LookupEntry(qinfo->ZoneOrSort))
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
|
sLog->outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
|
||||||
qinfo->GetQuestId(), qinfo->ZoneOrSort);
|
qinfo->GetQuestId(), qinfo->ZoneOrSort);
|
||||||
@@ -5845,7 +5845,7 @@ void ObjectMgr::LoadGraveyardZones()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||||
if (!areaEntry)
|
if (!areaEntry)
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId);
|
sLog->outErrorDb("Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId);
|
||||||
@@ -7893,7 +7893,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
|
|||||||
uint32 entry = fields[0].GetUInt32();
|
uint32 entry = fields[0].GetUInt32();
|
||||||
int32 skill = fields[1].GetInt16();
|
int32 skill = fields[1].GetInt16();
|
||||||
|
|
||||||
AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
|
AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry);
|
||||||
if (!fArea)
|
if (!fArea)
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist", entry);
|
sLog->outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist", entry);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Player;
|
|||||||
|
|
||||||
#define MAX_NUMBER_OF_GRIDS 64
|
#define MAX_NUMBER_OF_GRIDS 64
|
||||||
|
|
||||||
#define SIZE_OF_GRIDS 533.33333f
|
#define SIZE_OF_GRIDS 533.3333f
|
||||||
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
|
#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2)
|
||||||
|
|
||||||
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
|
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
|||||||
if (!channel)
|
if (!channel)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId());
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
|
||||||
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
|
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string aname;
|
std::string aname;
|
||||||
if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
|
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
|
||||||
aname = areaEntry->area_name[GetSessionDbcLocale()];
|
aname = areaEntry->area_name[GetSessionDbcLocale()];
|
||||||
|
|
||||||
bool s_show = true;
|
bool s_show = true;
|
||||||
@@ -1934,7 +1934,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId());
|
AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId());
|
||||||
if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2))
|
if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -474,16 +474,26 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recvData)
|
|||||||
|
|
||||||
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
|
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
|
||||||
|
|
||||||
if (movementInfo.pos.GetPositionZ() < -500.0f)
|
if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
|
||||||
if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player))
|
if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player))
|
||||||
{
|
{
|
||||||
if (plrMover->IsAlive())
|
if (plrMover->IsAlive())
|
||||||
{
|
{
|
||||||
|
plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||||
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
|
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
|
||||||
// player can be alive if GM
|
// player can be alive if GM
|
||||||
if (plrMover->IsAlive())
|
if (plrMover->IsAlive())
|
||||||
plrMover->KillPlayer();
|
plrMover->KillPlayer();
|
||||||
}
|
}
|
||||||
|
else if (!plrMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS))
|
||||||
|
{
|
||||||
|
WorldSafeLocsEntry const* grave = sObjectMgr->GetClosestGraveyard(plrMover->GetPositionX(), plrMover->GetPositionY(), plrMover->GetPositionZ(), plrMover->GetMapId(), plrMover->GetTeamId());
|
||||||
|
|
||||||
|
if ( grave)
|
||||||
|
plrMover->TeleportTo(grave->map_id, grave->x, grave->y, grave->z, plrMover->GetOrientation());
|
||||||
|
plrMover->Relocate(grave->x, grave->y, grave->z, plrMover->GetOrientation());
|
||||||
|
}
|
||||||
|
|
||||||
plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit
|
plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1598,8 +1598,8 @@ void LoadLootTemplates_Fishing()
|
|||||||
uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);
|
uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);
|
||||||
|
|
||||||
// remove real entries and check existence loot
|
// remove real entries and check existence loot
|
||||||
for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i)
|
for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
|
||||||
if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i))
|
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i))
|
||||||
if (lootIdSet.find(areaEntry->ID) != lootIdSet.end())
|
if (lootIdSet.find(areaEntry->ID) != lootIdSet.end())
|
||||||
lootIdSet.erase(areaEntry->ID);
|
lootIdSet.erase(areaEntry->ID);
|
||||||
|
|
||||||
@@ -1784,8 +1784,8 @@ void LoadLootTemplates_Mail()
|
|||||||
uint32 count = LootTemplates_Mail.LoadAndCollectLootIds(lootIdSet);
|
uint32 count = LootTemplates_Mail.LoadAndCollectLootIds(lootIdSet);
|
||||||
|
|
||||||
// remove real entries and check existence loot
|
// remove real entries and check existence loot
|
||||||
for (uint32 i = 1; i < sMailTemplateStore.GetNumRows(); ++i)
|
for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i)
|
||||||
if (sMailTemplateStore.LookupEntry(i))
|
if (sAreaTableStore.LookupEntry(i))
|
||||||
if (lootIdSet.find(i) != lootIdSet.end())
|
if (lootIdSet.find(i) != lootIdSet.end())
|
||||||
lootIdSet.erase(i);
|
lootIdSet.erase(i);
|
||||||
|
|
||||||
|
|||||||
+135
-55
@@ -32,7 +32,7 @@ union u_map_magic
|
|||||||
};
|
};
|
||||||
|
|
||||||
u_map_magic MapMagic = { {'M','A','P','S'} };
|
u_map_magic MapMagic = { {'M','A','P','S'} };
|
||||||
u_map_magic MapVersionMagic = { {'v','1','.','3'} };
|
u_map_magic MapVersionMagic = { {'v','1','.','8'} };
|
||||||
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
|
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
|
||||||
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
|
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
|
||||||
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
|
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
|
||||||
@@ -1200,13 +1200,15 @@ GridMap::GridMap()
|
|||||||
_flags = 0;
|
_flags = 0;
|
||||||
// Area data
|
// Area data
|
||||||
_gridArea = 0;
|
_gridArea = 0;
|
||||||
_areaMap = NULL;
|
_areaMap = nullptr;
|
||||||
// Height level data
|
// Height level data
|
||||||
_gridHeight = INVALID_HEIGHT;
|
_gridHeight = INVALID_HEIGHT;
|
||||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||||
_gridIntHeightMultiplier = 0;
|
_gridIntHeightMultiplier = 0;
|
||||||
m_V9 = NULL;
|
m_V9 = nullptr;
|
||||||
m_V8 = NULL;
|
m_V8 = nullptr;
|
||||||
|
_maxHeight = nullptr;
|
||||||
|
_minHeight = nullptr;
|
||||||
// Liquid data
|
// Liquid data
|
||||||
_liquidType = 0;
|
_liquidType = 0;
|
||||||
_liquidOffX = 0;
|
_liquidOffX = 0;
|
||||||
@@ -1214,9 +1216,9 @@ GridMap::GridMap()
|
|||||||
_liquidWidth = 0;
|
_liquidWidth = 0;
|
||||||
_liquidHeight = 0;
|
_liquidHeight = 0;
|
||||||
_liquidLevel = INVALID_HEIGHT;
|
_liquidLevel = INVALID_HEIGHT;
|
||||||
_liquidEntry = NULL;
|
_liquidEntry = nullptr;
|
||||||
_liquidFlags = NULL;
|
_liquidFlags = nullptr;
|
||||||
_liquidMap = NULL;
|
_liquidMap = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GridMap::~GridMap()
|
GridMap::~GridMap()
|
||||||
@@ -1277,15 +1279,19 @@ void GridMap::unloadData()
|
|||||||
delete[] _areaMap;
|
delete[] _areaMap;
|
||||||
delete[] m_V9;
|
delete[] m_V9;
|
||||||
delete[] m_V8;
|
delete[] m_V8;
|
||||||
|
delete[] _maxHeight;
|
||||||
|
delete[] _minHeight;
|
||||||
delete[] _liquidEntry;
|
delete[] _liquidEntry;
|
||||||
delete[] _liquidFlags;
|
delete[] _liquidFlags;
|
||||||
delete[] _liquidMap;
|
delete[] _liquidMap;
|
||||||
_areaMap = NULL;
|
_areaMap = nullptr;
|
||||||
m_V9 = NULL;
|
m_V9 = nullptr;
|
||||||
m_V8 = NULL;
|
m_V8 = nullptr;
|
||||||
_liquidEntry = NULL;
|
_maxHeight = nullptr;
|
||||||
_liquidFlags = NULL;
|
_minHeight = nullptr;
|
||||||
_liquidMap = NULL;
|
_liquidEntry = nullptr;
|
||||||
|
_liquidFlags = nullptr;
|
||||||
|
_liquidMap = nullptr;
|
||||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1350,6 +1356,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||||
|
|
||||||
|
if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
|
||||||
|
{
|
||||||
|
_maxHeight = new int16[3 * 3];
|
||||||
|
_minHeight = new int16[3 * 3];
|
||||||
|
if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 ||
|
||||||
|
fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1620,6 +1636,66 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
|||||||
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
|
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GridMap::getMinHeight(float x, float y) const
|
||||||
|
{
|
||||||
|
if (!_minHeight)
|
||||||
|
return -500.0f;
|
||||||
|
|
||||||
|
static uint32 const indices[] =
|
||||||
|
{
|
||||||
|
3, 0, 4,
|
||||||
|
0, 1, 4,
|
||||||
|
1, 2, 4,
|
||||||
|
2, 5, 4,
|
||||||
|
5, 8, 4,
|
||||||
|
8, 7, 4,
|
||||||
|
7, 6, 4,
|
||||||
|
6, 3, 4
|
||||||
|
};
|
||||||
|
|
||||||
|
static float const boundGridCoords[] =
|
||||||
|
{
|
||||||
|
0.0f, 0.0f,
|
||||||
|
0.0f, -266.66666f,
|
||||||
|
0.0f, -533.33331f,
|
||||||
|
-266.66666f, 0.0f,
|
||||||
|
-266.66666f, -266.66666f,
|
||||||
|
-266.66666f, -533.33331f,
|
||||||
|
-533.33331f, 0.0f,
|
||||||
|
-533.33331f, -266.66666f,
|
||||||
|
-533.33331f, -533.33331f
|
||||||
|
};
|
||||||
|
|
||||||
|
Cell cell(x, y);
|
||||||
|
float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||||
|
float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
|
||||||
|
|
||||||
|
uint32 quarterIndex = 0;
|
||||||
|
if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2)
|
||||||
|
{
|
||||||
|
if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
|
||||||
|
{
|
||||||
|
quarterIndex = 4 + (gy > gx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy);
|
||||||
|
}
|
||||||
|
else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2)
|
||||||
|
{
|
||||||
|
quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
quarterIndex = gx > gy;
|
||||||
|
|
||||||
|
quarterIndex *= 3;
|
||||||
|
|
||||||
|
return G3D::Plane(
|
||||||
|
G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]),
|
||||||
|
G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]),
|
||||||
|
G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]])
|
||||||
|
).distance(G3D::Vector3(gx, gy, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
float GridMap::getLiquidLevel(float x, float y) const
|
float GridMap::getLiquidLevel(float x, float y) const
|
||||||
{
|
{
|
||||||
if (!_liquidMap)
|
if (!_liquidMap)
|
||||||
@@ -1679,12 +1755,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R
|
|||||||
uint32 liqTypeIdx = liquidEntry->Type;
|
uint32 liqTypeIdx = liquidEntry->Type;
|
||||||
if (entry < 21)
|
if (entry < 21)
|
||||||
{
|
{
|
||||||
if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||||
{
|
{
|
||||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||||
if (!overrideLiquid && area->zone)
|
if (!overrideLiquid && area->zone)
|
||||||
{
|
{
|
||||||
area = GetAreaEntryByAreaID(area->zone);
|
area = sAreaTableStore.LookupEntry(area->zone);
|
||||||
if (area)
|
if (area)
|
||||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||||
}
|
}
|
||||||
@@ -1835,7 +1911,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
|||||||
|
|
||||||
// we are already under the surface or vmap height above map heigt
|
// we are already under the surface or vmap height above map heigt
|
||||||
// or if the distance of the vmap height is less the land height distance
|
// or if the distance of the vmap height is less the land height distance
|
||||||
if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
|
if (vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z))
|
||||||
return vmapHeight;
|
return vmapHeight;
|
||||||
else
|
else
|
||||||
return mapHeight; // better use .map surface height
|
return mapHeight; // better use .map surface height
|
||||||
@@ -1847,6 +1923,15 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
|||||||
return mapHeight; // explicitly use map data
|
return mapHeight; // explicitly use map data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Map::GetMinHeight(float x, float y) const
|
||||||
|
{
|
||||||
|
if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
|
return grid->getMinHeight(x, y);
|
||||||
|
|
||||||
|
return -500.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
||||||
{
|
{
|
||||||
bool outdoor = true;
|
bool outdoor = true;
|
||||||
@@ -1887,7 +1972,7 @@ bool Map::IsOutdoors(float x, float y, float z) const
|
|||||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||||
sLog->outStaticDebug("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
sLog->outStaticDebug("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
||||||
#endif
|
#endif
|
||||||
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||||
}
|
}
|
||||||
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||||
}
|
}
|
||||||
@@ -1911,7 +1996,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const
|
||||||
{
|
{
|
||||||
uint32 mogpFlags;
|
uint32 mogpFlags;
|
||||||
int32 adtId, rootId, groupId;
|
int32 adtId, rootId, groupId;
|
||||||
@@ -1924,20 +2009,20 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
|||||||
haveAreaInfo = true;
|
haveAreaInfo = true;
|
||||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||||
if (wmoEntry)
|
if (wmoEntry)
|
||||||
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 areaflag;
|
uint16 areaId;
|
||||||
|
|
||||||
if (atEntry)
|
if (atEntry)
|
||||||
areaflag = atEntry->exploreFlag;
|
areaId = atEntry->ID;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
areaflag = gmap->getArea(x, y);
|
areaId = gmap->getArea(x, y);
|
||||||
// this used while not all *.map files generated (instances)
|
// this used while not all *.map files generated (instances)
|
||||||
else
|
else
|
||||||
areaflag = GetAreaFlagByMapId(i_mapEntry->MapID);
|
areaId = i_mapEntry->linked_zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOutdoors)
|
if (isOutdoors)
|
||||||
@@ -1947,8 +2032,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const
|
|||||||
else
|
else
|
||||||
*isOutdoors = true;
|
*isOutdoors = true;
|
||||||
}
|
}
|
||||||
return areaflag;
|
return areaId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Map::GetAreaId(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
return GetAreaId(x, y, z, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Map::GetZoneId(float x, float y, float z) const
|
||||||
|
{
|
||||||
|
uint32 areaId = GetAreaId(x, y, z);
|
||||||
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||||
|
if (area->zone)
|
||||||
|
return area->zone;
|
||||||
|
|
||||||
|
return areaId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||||
|
{
|
||||||
|
areaid = zoneid = GetAreaId(x, y, z);
|
||||||
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
|
||||||
|
if (area->zone)
|
||||||
|
zoneid = area->zone;
|
||||||
|
}
|
||||||
|
|
||||||
uint8 Map::GetTerrainType(float x, float y) const
|
uint8 Map::GetTerrainType(float x, float y) const
|
||||||
{
|
{
|
||||||
@@ -1986,12 +2094,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
|
|||||||
|
|
||||||
if (liquid_type && liquid_type < 21)
|
if (liquid_type && liquid_type < 21)
|
||||||
{
|
{
|
||||||
if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId()))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
|
||||||
{
|
{
|
||||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||||
if (!overrideLiquid && area->zone)
|
if (!overrideLiquid && area->zone)
|
||||||
{
|
{
|
||||||
area = GetAreaEntryByAreaID(area->zone);
|
area = sAreaTableStore.LookupEntry(area->zone);
|
||||||
if (area)
|
if (area)
|
||||||
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||||
}
|
}
|
||||||
@@ -2053,34 +2161,6 @@ float Map::GetWaterLevel(float x, float y) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
|
||||||
{
|
|
||||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
||||||
|
|
||||||
if (entry)
|
|
||||||
return entry->ID;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
|
||||||
{
|
|
||||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
||||||
|
|
||||||
if (entry)
|
|
||||||
return (entry->zone != 0) ? entry->zone : entry->ID;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id)
|
|
||||||
{
|
|
||||||
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
||||||
|
|
||||||
areaid = entry ? entry->ID : 0;
|
|
||||||
zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
|
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
|
||||||
{
|
{
|
||||||
return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
|
return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
|
||||||
|
|||||||
+13
-24
@@ -85,9 +85,10 @@ struct map_areaHeader
|
|||||||
uint16 gridArea;
|
uint16 gridArea;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||||
|
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
|
||||||
|
|
||||||
struct map_heightHeader
|
struct map_heightHeader
|
||||||
{
|
{
|
||||||
@@ -153,6 +154,8 @@ class GridMap
|
|||||||
uint16* m_uint16_V8;
|
uint16* m_uint16_V8;
|
||||||
uint8* m_uint8_V8;
|
uint8* m_uint8_V8;
|
||||||
};
|
};
|
||||||
|
int16* _maxHeight;
|
||||||
|
int16* _minHeight;
|
||||||
// Height level data
|
// Height level data
|
||||||
float _gridHeight;
|
float _gridHeight;
|
||||||
float _gridIntHeightMultiplier;
|
float _gridIntHeightMultiplier;
|
||||||
@@ -193,6 +196,7 @@ public:
|
|||||||
|
|
||||||
uint16 getArea(float x, float y) const;
|
uint16 getArea(float x, float y) const;
|
||||||
inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
||||||
|
float getMinHeight(float x, float y) const;
|
||||||
float getLiquidLevel(float x, float y) const;
|
float getLiquidLevel(float x, float y) const;
|
||||||
uint8 getTerrainType(float x, float y) const;
|
uint8 getTerrainType(float x, float y) const;
|
||||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
|
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
|
||||||
@@ -327,12 +331,16 @@ class Map : public GridRefManager<NGridType>
|
|||||||
// some calls like isInWater should not use vmaps due to processor power
|
// some calls like isInWater should not use vmaps due to processor power
|
||||||
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||||
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||||
|
float GetMinHeight(float x, float y) const;
|
||||||
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = NULL);
|
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = NULL);
|
||||||
|
|
||||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0) const;
|
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0) const;
|
||||||
|
|
||||||
uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const;
|
uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const;
|
||||||
bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const;
|
bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||||
|
uint32 GetAreaId(float x, float y, float z) const;
|
||||||
|
uint32 GetZoneId(float x, float y, float z) const;
|
||||||
|
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
|
||||||
|
|
||||||
bool IsOutdoors(float x, float y, float z) const;
|
bool IsOutdoors(float x, float y, float z) const;
|
||||||
|
|
||||||
@@ -341,25 +349,6 @@ class Map : public GridRefManager<NGridType>
|
|||||||
bool IsInWater(float x, float y, float z, LiquidData* data = 0) const;
|
bool IsInWater(float x, float y, float z, LiquidData* data = 0) const;
|
||||||
bool IsUnderWater(float x, float y, float z) const;
|
bool IsUnderWater(float x, float y, float z) const;
|
||||||
|
|
||||||
static uint32 GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id);
|
|
||||||
static uint32 GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id);
|
|
||||||
static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id);
|
|
||||||
|
|
||||||
uint32 GetAreaId(float x, float y, float z) const
|
|
||||||
{
|
|
||||||
return GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 GetZoneId(float x, float y, float z) const
|
|
||||||
{
|
|
||||||
return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
|
||||||
{
|
|
||||||
GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveAllCreaturesInMoveList();
|
void MoveAllCreaturesInMoveList();
|
||||||
void MoveAllGameObjectsInMoveList();
|
void MoveAllGameObjectsInMoveList();
|
||||||
void MoveAllDynamicObjectsInMoveList();
|
void MoveAllDynamicObjectsInMoveList();
|
||||||
|
|||||||
@@ -36,22 +36,20 @@ class MapManager
|
|||||||
return (iter == i_maps.end() ? NULL : iter->second);
|
return (iter == i_maps.end() ? NULL : iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const
|
|
||||||
{
|
|
||||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
|
||||||
return m->GetAreaFlag(x, y, z);
|
|
||||||
}
|
|
||||||
uint32 GetAreaId(uint32 mapid, float x, float y, float z) const
|
uint32 GetAreaId(uint32 mapid, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
|
return m->GetAreaId(x, y, z);
|
||||||
}
|
}
|
||||||
uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
|
uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
|
return m->GetZoneId(x, y, z);
|
||||||
}
|
}
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
|
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
|
||||||
{
|
{
|
||||||
Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
|
m->GetZoneAndAreaId(zoneid, areaid, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize(void);
|
void Initialize(void);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ void WhoListCacheMgr::Update()
|
|||||||
wstrToLower(wgname);
|
wstrToLower(wgname);
|
||||||
|
|
||||||
std::string aname;
|
std::string aname;
|
||||||
if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
|
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(itr->second->GetZoneId()))
|
||||||
aname = areaEntry->area_name[sWorld->GetDefaultDbcLocale()];
|
aname = areaEntry->area_name[sWorld->GetDefaultDbcLocale()];
|
||||||
|
|
||||||
if (itr->second->IsSpectator())
|
if (itr->second->IsSpectator())
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ enum SpellAttr4
|
|||||||
|
|
||||||
enum SpellAttr5
|
enum SpellAttr5
|
||||||
{
|
{
|
||||||
SPELL_ATTR5_UNK0 = 0x00000001, // 0
|
SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING = 0x00000001, // 0
|
||||||
SPELL_ATTR5_NO_REAGENT_WHILE_PREP = 0x00000002, // 1 not need reagents if UNIT_FLAG_PREPARATION
|
SPELL_ATTR5_NO_REAGENT_WHILE_PREP = 0x00000002, // 1 not need reagents if UNIT_FLAG_PREPARATION
|
||||||
SPELL_ATTR5_REMOVE_ON_ARENA_ENTER = 0x00000004, // 2 xinef: remove this aura on arena enter
|
SPELL_ATTR5_REMOVE_ON_ARENA_ENTER = 0x00000004, // 2 xinef: remove this aura on arena enter
|
||||||
SPELL_ATTR5_USABLE_WHILE_STUNNED = 0x00000008, // 3 usable while stunned
|
SPELL_ATTR5_USABLE_WHILE_STUNNED = 0x00000008, // 3 usable while stunned
|
||||||
@@ -3531,7 +3531,7 @@ enum PartyResult
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||||
#define MMAP_VERSION 3
|
#define MMAP_VERSION 6
|
||||||
|
|
||||||
struct MmapTileHeader
|
struct MmapTileHeader
|
||||||
{
|
{
|
||||||
@@ -3539,12 +3539,23 @@ struct MmapTileHeader
|
|||||||
uint32 dtVersion;
|
uint32 dtVersion;
|
||||||
uint32 mmapVersion;
|
uint32 mmapVersion;
|
||||||
uint32 size;
|
uint32 size;
|
||||||
bool usesLiquids : 1;
|
char usesLiquids;
|
||||||
|
char padding[3];
|
||||||
|
|
||||||
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
||||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
|
||||||
|
static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size");
|
||||||
|
static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
|
||||||
|
sizeof(MmapTileHeader::dtVersion) +
|
||||||
|
sizeof(MmapTileHeader::mmapVersion) +
|
||||||
|
sizeof(MmapTileHeader::size) +
|
||||||
|
sizeof(MmapTileHeader::usesLiquids) +
|
||||||
|
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
|
||||||
|
|
||||||
|
|
||||||
enum NavTerrain
|
enum NavTerrain
|
||||||
{
|
{
|
||||||
NAV_EMPTY = 0x00,
|
NAV_EMPTY = 0x00,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "MoveSplineInit.h"
|
#include "MoveSplineInit.h"
|
||||||
#include "MoveSpline.h"
|
#include "MoveSpline.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
#include "VMapFactory.h"
|
||||||
|
|
||||||
#define MIN_QUIET_DISTANCE 28.0f
|
#define MIN_QUIET_DISTANCE 28.0f
|
||||||
#define MAX_QUIET_DISTANCE 43.0f
|
#define MAX_QUIET_DISTANCE 43.0f
|
||||||
@@ -32,6 +33,19 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
|
|||||||
if (!_getPoint(owner, x, y, z))
|
if (!_getPoint(owner, x, y, z))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Add LOS check for target point
|
||||||
|
bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(owner->GetMapId(),
|
||||||
|
owner->GetPositionX(),
|
||||||
|
owner->GetPositionY(),
|
||||||
|
owner->GetPositionZ() + 2.0f,
|
||||||
|
x, y, z + 2.0f);
|
||||||
|
|
||||||
|
if (!isInLOS)
|
||||||
|
{
|
||||||
|
i_nextCheckTime.Reset(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
|
owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
|
||||||
|
|
||||||
Movement::MoveSplineInit init(owner);
|
Movement::MoveSplineInit init(owner);
|
||||||
|
|||||||
@@ -152,9 +152,10 @@ dtPolyRef PathGenerator::GetPolyByLocation(float* point, float* distance) const
|
|||||||
|
|
||||||
// still nothing ..
|
// still nothing ..
|
||||||
// try with bigger search box
|
// try with bigger search box
|
||||||
extents[1] = 80.0f;
|
// Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly)
|
||||||
result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
|
extents[1] = 50.0f;
|
||||||
if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
|
|
||||||
|
if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
|
||||||
{
|
{
|
||||||
*distance = dtVdist(closestPoint, point);
|
*distance = dtVdist(closestPoint, point);
|
||||||
return polyRef;
|
return polyRef;
|
||||||
@@ -339,7 +340,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
if (startPoly != endPoly || !endInWaterFar)
|
if (startPoly != endPoly || !endInWaterFar)
|
||||||
{
|
{
|
||||||
float closestPoint[VERTEX_SIZE];
|
float closestPoint[VERTEX_SIZE];
|
||||||
if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
|
if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, NULL)))
|
||||||
{
|
{
|
||||||
dtVcopy(endPoint, closestPoint);
|
dtVcopy(endPoint, closestPoint);
|
||||||
SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
|
SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
|
||||||
@@ -416,7 +417,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
|
|
||||||
// we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
|
// we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
|
||||||
float suffixEndPoint[VERTEX_SIZE];
|
float suffixEndPoint[VERTEX_SIZE];
|
||||||
if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
|
if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, NULL)))
|
||||||
{
|
{
|
||||||
// we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
|
// we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
|
||||||
// try to recover by using prev polyref
|
// try to recover by using prev polyref
|
||||||
@@ -424,7 +425,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
if (prefixPolyLength)
|
if (prefixPolyLength)
|
||||||
{
|
{
|
||||||
suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
|
suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
|
||||||
if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
|
if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,NULL)))
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -445,7 +446,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
(int*)&suffixPolyLength,
|
(int*)&suffixPolyLength,
|
||||||
MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
|
MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
|
||||||
|
|
||||||
if (!suffixPolyLength || dtResult != DT_SUCCESS)
|
if (!_polyLength || dtStatusFailed(dtResult))
|
||||||
{
|
{
|
||||||
// this is probably an error state, but we'll leave it
|
// this is probably an error state, but we'll leave it
|
||||||
// and hopefully recover on the next Update
|
// and hopefully recover on the next Update
|
||||||
@@ -470,7 +471,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
(int*)&_polyLength,
|
(int*)&_polyLength,
|
||||||
MAX_PATH_LENGTH); // max number of polygons in output path
|
MAX_PATH_LENGTH); // max number of polygons in output path
|
||||||
|
|
||||||
if (!_polyLength || dtResult != DT_SUCCESS)
|
if (!_polyLength || dtStatusFailed(dtResult))
|
||||||
{
|
{
|
||||||
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
||||||
BuildShortcut();
|
BuildShortcut();
|
||||||
@@ -499,7 +500,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
(int*)&_polyLength,
|
(int*)&_polyLength,
|
||||||
MAX_PATH_LENGTH); // max number of polygons in output path
|
MAX_PATH_LENGTH); // max number of polygons in output path
|
||||||
|
|
||||||
if (!_polyLength || dtResult != DT_SUCCESS)
|
if (!_polyLength || dtStatusFailed(dtResult))
|
||||||
{
|
{
|
||||||
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
// only happens if we passed bad data to findPath(), or navmesh is messed up
|
||||||
BuildShortcut();
|
BuildShortcut();
|
||||||
@@ -658,7 +659,7 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin
|
|||||||
_pointPathLimit); // maximum number of points
|
_pointPathLimit); // maximum number of points
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointCount < 2 || dtResult != DT_SUCCESS)
|
if (pointCount < 2 || dtStatusFailed(dtResult))
|
||||||
{
|
{
|
||||||
// only happens if pass bad data to findStraightPath or navmesh is broken
|
// only happens if pass bad data to findStraightPath or navmesh is broken
|
||||||
// single point paths can be generated here
|
// single point paths can be generated here
|
||||||
@@ -784,7 +785,7 @@ bool PathGenerator::HaveTile(const G3D::Vector3& p) const
|
|||||||
if (tx < 0 || ty < 0)
|
if (tx < 0 || ty < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (_navMesh->getTileAt(tx, ty) != NULL);
|
return (_navMesh->getTileAt(tx, ty, 0) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
|
uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
|
||||||
@@ -844,7 +845,7 @@ bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
|
|||||||
uint32 nsteerPath = 0;
|
uint32 nsteerPath = 0;
|
||||||
dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
|
dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
|
||||||
steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
|
steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
|
||||||
if (!nsteerPath || DT_SUCCESS != dtResult)
|
if (!nsteerPath || dtStatusFailed(dtResult))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Find vertex far enough to steer to.
|
// Find vertex far enough to steer to.
|
||||||
@@ -908,7 +909,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo
|
|||||||
// Find movement delta.
|
// Find movement delta.
|
||||||
float delta[VERTEX_SIZE];
|
float delta[VERTEX_SIZE];
|
||||||
dtVsub(delta, steerPos, iterPos);
|
dtVsub(delta, steerPos, iterPos);
|
||||||
float len = dtSqrt(dtVdot(delta,delta));
|
float len = dtMathSqrtf(dtVdot(delta,delta));
|
||||||
// If the steer target is end of path or off-mesh link, do not move past the location.
|
// If the steer target is end of path or off-mesh link, do not move past the location.
|
||||||
if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
|
if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
|
||||||
len = 1.0f;
|
len = 1.0f;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Unit;
|
|||||||
#define ALLOWED_DIST_FROM_POLY 2.5f
|
#define ALLOWED_DIST_FROM_POLY 2.5f
|
||||||
#define ADDED_Z_FOR_POLY_LOOKUP 0.3f
|
#define ADDED_Z_FOR_POLY_LOOKUP 0.3f
|
||||||
#define DISALLOW_TIME_AFTER_FAIL 3 // secs
|
#define DISALLOW_TIME_AFTER_FAIL 3 // secs
|
||||||
#define MAX_FIXABLE_Z_ERROR 12.0f
|
#define MAX_FIXABLE_Z_ERROR 7.0f
|
||||||
|
|
||||||
#define VERTEX_SIZE 3
|
#define VERTEX_SIZE 3
|
||||||
#define INVALID_POLYREF 0
|
#define INVALID_POLYREF 0
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
|||||||
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
|
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
|
||||||
|
return;
|
||||||
|
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
bool isPlayerPet = owner->IsPet() && IS_PLAYER_GUID(owner->GetOwnerGUID());
|
bool isPlayerPet = owner->IsPet() && IS_PLAYER_GUID(owner->GetOwnerGUID());
|
||||||
bool sameTransport = owner->GetTransport() && owner->GetTransport() == i_target->GetTransport();
|
bool sameTransport = owner->GetTransport() && owner->GetTransport() == i_target->GetTransport();
|
||||||
@@ -44,6 +47,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
|||||||
(i_target->GetTypeId() == TYPEID_PLAYER && i_target->ToPlayer()->IsGameMaster()); // for .npc follow
|
(i_target->GetTypeId() == TYPEID_PLAYER && i_target->ToPlayer()->IsGameMaster()); // for .npc follow
|
||||||
bool forcePoint = ((!isPlayerPet || owner->GetMapId() == 618) && (forceDest || !useMMaps)) || sameTransport;
|
bool forcePoint = ((!isPlayerPet || owner->GetMapId() == 618) && (forceDest || !useMMaps)) || sameTransport;
|
||||||
|
|
||||||
|
if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()) && !sameTransport && !forceDest && !forcePoint)
|
||||||
|
return;
|
||||||
|
|
||||||
lastOwnerXYZ.Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
|
lastOwnerXYZ.Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ());
|
||||||
lastTargetXYZ.Relocate(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ());
|
lastTargetXYZ.Relocate(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ());
|
||||||
|
|
||||||
@@ -60,6 +66,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
|||||||
owner->m_targetsNotAcceptable[i_target->GetGUID()] = MMapTargetData(sWorld->GetGameTime()+DISALLOW_TIME_AFTER_FAIL, owner, i_target.getTarget());
|
owner->m_targetsNotAcceptable[i_target->GetGUID()] = MMapTargetData(sWorld->GetGameTime()+DISALLOW_TIME_AFTER_FAIL, owner, i_target.getTarget());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to nearest contact position
|
||||||
|
i_target->GetContactPoint(owner, x, y, z);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -167,6 +176,7 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
owner->m_targetsNotAcceptable.erase(i_target->GetGUID());
|
owner->m_targetsNotAcceptable.erase(i_target->GetGUID());
|
||||||
|
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||||
|
|
||||||
init.MovebyPath(i_path->GetPath());
|
init.MovebyPath(i_path->GetPath());
|
||||||
if (i_angle == 0.f)
|
if (i_angle == 0.f)
|
||||||
@@ -180,6 +190,8 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool ini
|
|||||||
// if failed to generate, just use normal MoveTo
|
// if failed to generate, just use normal MoveTo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||||
|
|
||||||
init.MoveTo(x,y,z);
|
init.MoveTo(x,y,z);
|
||||||
// Using the same condition for facing target as the one that is used for SetInFront on movement end
|
// Using the same condition for facing target as the one that is used for SetInFront on movement end
|
||||||
// - applies to ChaseMovementGenerator mostly
|
// - applies to ChaseMovementGenerator mostly
|
||||||
@@ -206,7 +218,7 @@ bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent movement while casting spells with cast time or channel time
|
// prevent movement while casting spells with cast time or channel time
|
||||||
if (owner->HasUnitState(UNIT_STATE_CASTING))
|
if (owner->HasUnitState(UNIT_STATE_CASTING) && !owner->CanMoveDuringChannel())
|
||||||
{
|
{
|
||||||
bool stop = true;
|
bool stop = true;
|
||||||
if (Spell* spell = owner->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
if (Spell* spell = owner->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
||||||
|
|||||||
@@ -6200,7 +6200,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
|||||||
if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive())
|
if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive())
|
||||||
{
|
{
|
||||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
|
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
|
||||||
if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId()))
|
if (AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))
|
||||||
if ((pArea->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))
|
if ((pArea->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))
|
||||||
return SPELL_FAILED_NOT_HERE;
|
return SPELL_FAILED_NOT_HERE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4241,14 +4241,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Players can only fight a duel in zones with this flag
|
// Players can only fight a duel in zones with this flag
|
||||||
AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId());
|
AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId());
|
||||||
if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
||||||
{
|
{
|
||||||
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId());
|
AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId());
|
||||||
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
|
||||||
{
|
{
|
||||||
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
|
||||||
|
|||||||
@@ -1069,7 +1069,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
|
|||||||
if (!player)
|
if (!player)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId());
|
AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId());
|
||||||
if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE))
|
if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE))
|
||||||
return false;
|
return false;
|
||||||
if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))
|
if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY))
|
||||||
@@ -2513,7 +2513,7 @@ void SpellMgr::LoadSpellAreas()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
|
if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
|
||||||
{
|
{
|
||||||
sLog->outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);
|
sLog->outErrorDb("Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);
|
||||||
continue;
|
continue;
|
||||||
@@ -6243,8 +6243,8 @@ void SpellMgr::LoadDbcDataCorrections()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Xinef: The Veiled Sea area in outlands (Draenei zone), client blocks casting flying mounts
|
// Xinef: The Veiled Sea area in outlands (Draenei zone), client blocks casting flying mounts
|
||||||
for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i)
|
for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
|
||||||
if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaStore.LookupEntry(i)))
|
if (AreaTableEntry* areaEntry = const_cast<AreaTableEntry*>(sAreaTableStore.LookupEntry(i)))
|
||||||
{
|
{
|
||||||
if (areaEntry->ID == 3479)
|
if (areaEntry->ID == 3479)
|
||||||
areaEntry->flags |= AREA_FLAG_NO_FLY_ZONE;
|
areaEntry->flags |= AREA_FLAG_NO_FLY_ZONE;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ message("")
|
|||||||
include_directories(
|
include_directories(
|
||||||
${scripts_INCLUDE_DIRS}
|
${scripts_INCLUDE_DIRS}
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour/Include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ set(scripts_STAT_SRCS
|
|||||||
Commands/cs_lookup.cpp
|
Commands/cs_lookup.cpp
|
||||||
Commands/cs_message.cpp
|
Commands/cs_message.cpp
|
||||||
Commands/cs_misc.cpp
|
Commands/cs_misc.cpp
|
||||||
|
Commands/cs_mmaps.cpp
|
||||||
Commands/cs_modify.cpp
|
Commands/cs_modify.cpp
|
||||||
Commands/cs_npc.cpp
|
Commands/cs_npc.cpp
|
||||||
Commands/cs_quest.cpp
|
Commands/cs_quest.cpp
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ public:
|
|||||||
|
|
||||||
uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId();
|
uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId();
|
||||||
|
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||||
|
|
||||||
if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry)
|
if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry)
|
||||||
{
|
{
|
||||||
@@ -427,7 +427,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update to parent zone if exist (client map show only zones without parents)
|
// update to parent zone if exist (client map show only zones without parents)
|
||||||
AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry;
|
AreaTableEntry const* zoneEntry = areaEntry->zone ? sAreaTableStore.LookupEntry(areaEntry->zone) : areaEntry;
|
||||||
|
|
||||||
Map const* map = sMapMgr->CreateBaseMap(zoneEntry->mapid);
|
Map const* map = sMapMgr->CreateBaseMap(zoneEntry->mapid);
|
||||||
|
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ public:
|
|||||||
wstrToLower(wNamePart);
|
wstrToLower(wNamePart);
|
||||||
|
|
||||||
// Search in AreaTable.dbc
|
// Search in AreaTable.dbc
|
||||||
for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag)
|
for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)
|
||||||
{
|
{
|
||||||
AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i);
|
||||||
if (areaEntry)
|
if (areaEntry)
|
||||||
{
|
{
|
||||||
int locale = handler->GetSessionDbcLocale();
|
int locale = handler->GetSessionDbcLocale();
|
||||||
|
|||||||
@@ -400,8 +400,8 @@ public:
|
|||||||
object->GetZoneAndAreaId(zoneId, areaId);
|
object->GetZoneAndAreaId(zoneId, areaId);
|
||||||
|
|
||||||
MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId());
|
MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId());
|
||||||
AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId);
|
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||||
|
|
||||||
float zoneX = object->GetPositionX();
|
float zoneX = object->GetPositionX();
|
||||||
float zoneY = object->GetPositionY();
|
float zoneY = object->GetPositionY();
|
||||||
@@ -1280,7 +1280,7 @@ public:
|
|||||||
|
|
||||||
uint32 zoneId = player->GetZoneId();
|
uint32 zoneId = player->GetZoneId();
|
||||||
|
|
||||||
AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||||
if (!areaEntry || areaEntry->zone !=0)
|
if (!areaEntry || areaEntry->zone !=0)
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId);
|
handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId);
|
||||||
@@ -1411,17 +1411,23 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 area = GetAreaFlagByAreaID(atoi((char*)args));
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args));
|
||||||
int32 offset = area / 32;
|
if (!area)
|
||||||
uint32 val = uint32((1 << (area % 32)));
|
|
||||||
|
|
||||||
if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
|
||||||
{
|
{
|
||||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 offset = area->exploreFlag / 32;
|
||||||
|
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||||
|
{
|
||||||
|
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||||
|
handler->SetSentErrorMessage(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 val = uint32((1 << (area->exploreFlag % 32)));
|
||||||
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
||||||
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val)));
|
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val)));
|
||||||
|
|
||||||
@@ -1442,17 +1448,23 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 area = GetAreaFlagByAreaID(atoi((char*)args));
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args));
|
||||||
int32 offset = area / 32;
|
if (!area)
|
||||||
uint32 val = uint32((1 << (area % 32)));
|
|
||||||
|
|
||||||
if (area < 0 || offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
|
||||||
{
|
{
|
||||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 offset = area->exploreFlag / 32;
|
||||||
|
if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
|
||||||
|
{
|
||||||
|
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||||
|
handler->SetSentErrorMessage(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 val = uint32((1 << (area->exploreFlag % 32)));
|
||||||
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
|
||||||
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val)));
|
playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val)));
|
||||||
|
|
||||||
@@ -2025,12 +2037,12 @@ public:
|
|||||||
|
|
||||||
MapEntry const* map = sMapStore.LookupEntry(mapId);
|
MapEntry const* map = sMapStore.LookupEntry(mapId);
|
||||||
|
|
||||||
AreaTableEntry const* area = GetAreaEntryByAreaID(areaId);
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
|
||||||
if (area)
|
if (area)
|
||||||
{
|
{
|
||||||
areaName = area->area_name[locale];
|
areaName = area->area_name[locale];
|
||||||
|
|
||||||
AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone);
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);
|
||||||
if (zone)
|
if (zone)
|
||||||
zoneName = zone->area_name[locale];
|
zoneName = zone->area_name[locale];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file cs_mmaps.cpp
|
||||||
|
* @brief .mmap related commands
|
||||||
|
*
|
||||||
|
* This file contains the CommandScripts for all
|
||||||
|
* mmap sub-commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "Chat.h"
|
||||||
|
#include "DisableMgr.h"
|
||||||
|
#include "ObjectMgr.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "PointMovementGenerator.h"
|
||||||
|
#include "PathGenerator.h"
|
||||||
|
#include "MMapFactory.h"
|
||||||
|
#include "Map.h"
|
||||||
|
#include "TargetedMovementGenerator.h"
|
||||||
|
#include "GridNotifiers.h"
|
||||||
|
#include "GridNotifiersImpl.h"
|
||||||
|
#include "CellImpl.h"
|
||||||
|
|
||||||
|
class mmaps_commandscript : public CommandScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mmaps_commandscript() : CommandScript("mmaps_commandscript") { }
|
||||||
|
|
||||||
|
std::vector<ChatCommand> GetCommands() const override
|
||||||
|
{
|
||||||
|
static std::vector<ChatCommand> mmapCommandTable =
|
||||||
|
{
|
||||||
|
{ "loadedtiles", SEC_ADMINISTRATOR, false, &HandleMmapLoadedTilesCommand, "" },
|
||||||
|
{ "loc", SEC_ADMINISTRATOR, false, &HandleMmapLocCommand, "" },
|
||||||
|
{ "path", SEC_ADMINISTRATOR, false, &HandleMmapPathCommand, "" },
|
||||||
|
{ "stats", SEC_ADMINISTRATOR, false, &HandleMmapStatsCommand, "" },
|
||||||
|
{ "testarea", SEC_ADMINISTRATOR, false, &HandleMmapTestArea, "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<ChatCommand> commandTable =
|
||||||
|
{
|
||||||
|
{ "mmap", SEC_ADMINISTRATOR, true, NULL, "", mmapCommandTable },
|
||||||
|
};
|
||||||
|
return commandTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleMmapPathCommand(ChatHandler* handler, char const* args)
|
||||||
|
{
|
||||||
|
if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("NavMesh not loaded for current map.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->PSendSysMessage("mmap path:");
|
||||||
|
|
||||||
|
// units
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
Unit* target = handler->getSelectedUnit();
|
||||||
|
if (!player || !target)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Invalid target/source selection.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* para = strtok((char*)args, " ");
|
||||||
|
|
||||||
|
bool useStraightPath = false;
|
||||||
|
if (para && strcmp(para, "true") == 0)
|
||||||
|
useStraightPath = true;
|
||||||
|
|
||||||
|
bool useStraightLine = false;
|
||||||
|
if (para && strcmp(para, "line") == 0)
|
||||||
|
useStraightLine = true;
|
||||||
|
|
||||||
|
// unit locations
|
||||||
|
float x, y, z;
|
||||||
|
player->GetPosition(x, y, z);
|
||||||
|
|
||||||
|
// path
|
||||||
|
PathGenerator path(target);
|
||||||
|
path.SetUseStraightPath(useStraightPath);
|
||||||
|
bool result = path.CalculatePath(x, y, z, false);
|
||||||
|
|
||||||
|
Movement::PointsArray const& pointPath = path.GetPath();
|
||||||
|
handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str());
|
||||||
|
handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath");
|
||||||
|
handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType());
|
||||||
|
|
||||||
|
G3D::Vector3 const &start = path.GetStartPosition();
|
||||||
|
G3D::Vector3 const &end = path.GetEndPosition();
|
||||||
|
G3D::Vector3 const &actualEnd = path.GetActualEndPosition();
|
||||||
|
|
||||||
|
handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z);
|
||||||
|
handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z);
|
||||||
|
handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z);
|
||||||
|
|
||||||
|
if (!player->IsGameMaster())
|
||||||
|
handler->PSendSysMessage("Enable GM mode to see the path points.");
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < pointPath.size(); ++i)
|
||||||
|
player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("mmap tileloc:");
|
||||||
|
|
||||||
|
// grid tile location
|
||||||
|
Player* player = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
|
int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS;
|
||||||
|
int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS;
|
||||||
|
|
||||||
|
handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gx, gy);
|
||||||
|
handler->PSendSysMessage("gridloc [%i, %i]", gy, gx);
|
||||||
|
|
||||||
|
// calculate navmesh tile location
|
||||||
|
dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
|
||||||
|
dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
|
||||||
|
if (!navmesh || !navmeshquery)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("NavMesh not loaded for current map.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float const* min = navmesh->getParams()->orig;
|
||||||
|
float x, y, z;
|
||||||
|
player->GetPosition(x, y, z);
|
||||||
|
float location[VERTEX_SIZE] = {y, z, x};
|
||||||
|
float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f};
|
||||||
|
|
||||||
|
int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS);
|
||||||
|
int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS);
|
||||||
|
|
||||||
|
handler->PSendSysMessage("Calc [%02i, %02i]", tilex, tiley);
|
||||||
|
|
||||||
|
// navmesh poly -> navmesh tile location
|
||||||
|
dtQueryFilter filter = dtQueryFilter();
|
||||||
|
dtPolyRef polyRef = INVALID_POLYREF;
|
||||||
|
if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL)))
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polyRef == INVALID_POLYREF)
|
||||||
|
handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dtMeshTile const* tile;
|
||||||
|
dtPoly const* poly;
|
||||||
|
if (dtStatusSucceed(navmesh->getTileAndPolyByRef(polyRef, &tile, &poly)))
|
||||||
|
{
|
||||||
|
if (tile)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->PSendSysMessage("Dt [??,??] (no tile loaded)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/)
|
||||||
|
{
|
||||||
|
uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId();
|
||||||
|
dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid);
|
||||||
|
dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
|
||||||
|
if (!navmesh || !navmeshquery)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("NavMesh not loaded for current map.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->PSendSysMessage("mmap loadedtiles:");
|
||||||
|
|
||||||
|
for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
|
||||||
|
{
|
||||||
|
dtMeshTile const* tile = navmesh->getTile(i);
|
||||||
|
if (!tile || !tile->header)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
handler->PSendSysMessage("[%02i, %02i]", tile->header->x, tile->header->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleMmapStatsCommand(ChatHandler* handler, char const* /*args*/)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("mmap stats:");
|
||||||
|
//handler->PSendSysMessage(" global mmap pathfinding is %sabled", DisableMgr::IsPathfindingEnabled(mapId) ? "en" : "dis");
|
||||||
|
|
||||||
|
MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager();
|
||||||
|
handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
|
||||||
|
|
||||||
|
dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
|
||||||
|
if (!navmesh)
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("NavMesh not loaded for current map.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 tileCount = 0;
|
||||||
|
uint32 nodeCount = 0;
|
||||||
|
uint32 polyCount = 0;
|
||||||
|
uint32 vertCount = 0;
|
||||||
|
uint32 triCount = 0;
|
||||||
|
uint32 triVertCount = 0;
|
||||||
|
uint32 dataSize = 0;
|
||||||
|
for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
|
||||||
|
{
|
||||||
|
dtMeshTile const* tile = navmesh->getTile(i);
|
||||||
|
if (!tile || !tile->header)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tileCount++;
|
||||||
|
nodeCount += tile->header->bvNodeCount;
|
||||||
|
polyCount += tile->header->polyCount;
|
||||||
|
vertCount += tile->header->vertCount;
|
||||||
|
triCount += tile->header->detailTriCount;
|
||||||
|
triVertCount += tile->header->detailVertCount;
|
||||||
|
dataSize += tile->dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->PSendSysMessage("Navmesh stats:");
|
||||||
|
handler->PSendSysMessage(" %u tiles loaded", tileCount);
|
||||||
|
handler->PSendSysMessage(" %u BVTree nodes", nodeCount);
|
||||||
|
handler->PSendSysMessage(" %u polygons (%u vertices)", polyCount, vertCount);
|
||||||
|
handler->PSendSysMessage(" %u triangles (%u vertices)", triCount, triVertCount);
|
||||||
|
handler->PSendSysMessage(" %.2f MB of data (not including pointers)", ((float)dataSize / sizeof(unsigned char)) / 1048576);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleMmapTestArea(ChatHandler* handler, char const* /*args*/)
|
||||||
|
{
|
||||||
|
float radius = 40.0f;
|
||||||
|
WorldObject* object = handler->GetSession()->GetPlayer();
|
||||||
|
|
||||||
|
CellCoord pair(Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()));
|
||||||
|
Cell cell(pair);
|
||||||
|
cell.SetNoCreate();
|
||||||
|
|
||||||
|
std::list<Creature*> creatureList;
|
||||||
|
|
||||||
|
Trinity::AnyUnitInObjectRangeCheck go_check(object, radius);
|
||||||
|
Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> go_search(object, creatureList, go_check);
|
||||||
|
TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search);
|
||||||
|
|
||||||
|
// Get Creatures
|
||||||
|
cell.Visit(pair, go_visit, *(object->GetMap()), *object, radius);
|
||||||
|
|
||||||
|
if (!creatureList.empty())
|
||||||
|
{
|
||||||
|
handler->PSendSysMessage("Found %zu Creatures.", creatureList.size());
|
||||||
|
|
||||||
|
uint32 paths = 0;
|
||||||
|
uint32 uStartTime = getMSTime();
|
||||||
|
|
||||||
|
float gx, gy, gz;
|
||||||
|
object->GetPosition(gx, gy, gz);
|
||||||
|
for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
|
||||||
|
{
|
||||||
|
PathGenerator path(*itr);
|
||||||
|
path.CalculatePath(gx, gy, gz);
|
||||||
|
++paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime());
|
||||||
|
handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
handler->PSendSysMessage("No creatures in %f yard range.", radius);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_mmaps_commandscript()
|
||||||
|
{
|
||||||
|
new mmaps_commandscript();
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ void AddSC_list_commandscript();
|
|||||||
void AddSC_lookup_commandscript();
|
void AddSC_lookup_commandscript();
|
||||||
void AddSC_message_commandscript();
|
void AddSC_message_commandscript();
|
||||||
void AddSC_misc_commandscript();
|
void AddSC_misc_commandscript();
|
||||||
|
void AddSC_mmaps_commandscript();
|
||||||
void AddSC_modify_commandscript();
|
void AddSC_modify_commandscript();
|
||||||
void AddSC_npc_commandscript();
|
void AddSC_npc_commandscript();
|
||||||
void AddSC_quest_commandscript();
|
void AddSC_quest_commandscript();
|
||||||
@@ -616,6 +617,7 @@ void AddCommandScripts()
|
|||||||
AddSC_lookup_commandscript();
|
AddSC_lookup_commandscript();
|
||||||
AddSC_message_commandscript();
|
AddSC_message_commandscript();
|
||||||
AddSC_misc_commandscript();
|
AddSC_misc_commandscript();
|
||||||
|
AddSC_mmaps_commandscript();
|
||||||
AddSC_modify_commandscript();
|
AddSC_modify_commandscript();
|
||||||
AddSC_npc_commandscript();
|
AddSC_npc_commandscript();
|
||||||
AddSC_quest_commandscript();
|
AddSC_quest_commandscript();
|
||||||
|
|||||||
@@ -4431,10 +4431,7 @@ class spell_gen_mount : public SpellScriptLoader
|
|||||||
if (map == 530 || (map == 571 && target->HasSpell(SPELL_COLD_WEATHER_FLYING)))
|
if (map == 530 || (map == 571 && target->HasSpell(SPELL_COLD_WEATHER_FLYING)))
|
||||||
canFly = true;
|
canFly = true;
|
||||||
|
|
||||||
float x, y, z;
|
AreaTableEntry const* area = sAreaTableStore.LookupEntry(target->GetAreaId());
|
||||||
target->GetPosition(x, y, z);
|
|
||||||
uint32 areaFlag = target->GetBaseMap()->GetAreaFlag(x, y, z);
|
|
||||||
AreaTableEntry const* area = sAreaStore.LookupEntry(areaFlag);
|
|
||||||
// Xinef: add battlefield check
|
// Xinef: add battlefield check
|
||||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(target->GetZoneId());
|
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(target->GetZoneId());
|
||||||
if (!area || (canFly && ((area->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))))
|
if (!area || (canFly && ((area->flags & AREA_FLAG_NO_FLY_ZONE) || (Bf && !Bf->CanFlyIn()))))
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ endif()
|
|||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_BINARY_DIR}
|
${CMAKE_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour/Include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/gsoap
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/gsoap
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/sockets/include
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/sockets/include
|
||||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
||||||
|
|||||||
Reference in New Issue
Block a user