608 lines
17 KiB
C++
608 lines
17 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include <f8/udplog.h>
|
|
|
|
#include "DetourCommon.h"
|
|
|
|
#include "mapinstance.h"
|
|
#include "mapservice.h"
|
|
#include "gridservice.h"
|
|
#include "obstacle.h"
|
|
#include "loot.h"
|
|
#include "mapmgr.h"
|
|
#include "metamgr.h"
|
|
#include "room.h"
|
|
#include "entityfactory.h"
|
|
#include "config.h"
|
|
|
|
#include "roommgr.h"
|
|
|
|
static const int NAV_ERROR_NEARESTPOLY = -2;
|
|
|
|
static const int NAV_ERROR = -1;
|
|
|
|
static const long RCN_NAVMESH_VERSION = 1;
|
|
static const int INVALID_NAVMESH_POLYREF = 0;
|
|
|
|
const int MAP_GRID_WIDTH = 64;
|
|
|
|
static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
|
|
static const int NAVMESHSET_VERSION = 1;
|
|
|
|
struct NavMeshSetHeader
|
|
{
|
|
int magic;
|
|
int version;
|
|
int numTiles;
|
|
dtNavMeshParams params;
|
|
};
|
|
|
|
struct NavMeshTileHeader
|
|
{
|
|
dtTileRef tileRef;
|
|
int dataSize;
|
|
};
|
|
|
|
static float frand()
|
|
{
|
|
return (float)rand()/(float)RAND_MAX;
|
|
}
|
|
|
|
void MapInstance::Init()
|
|
{
|
|
map_meta_ = MetaMgr::Instance()->GetMap(map_id);
|
|
if (!map_meta_) {
|
|
A8_ABORT();
|
|
}
|
|
if (map_meta_->pb->map_width() < 1) {
|
|
A8_ABORT();
|
|
}
|
|
if (map_meta_->pb->map_height() < 1) {
|
|
A8_ABORT();
|
|
}
|
|
map_service_ = new MapService();
|
|
grid_service_ = new GridService();
|
|
grid_service_->Init(map_meta_->pb->map_width(),
|
|
map_meta_->pb->map_height(),
|
|
Config::Instance()->map_cell_width);
|
|
map_service_->Init(map_meta_->pb->map_width() / MAP_GRID_WIDTH,
|
|
map_meta_->pb->map_height() / MAP_GRID_WIDTH,
|
|
MAP_GRID_WIDTH);
|
|
CreateThings();
|
|
f8::UdpLog::Instance()->Info
|
|
("map_id:%d current_uniid:%d ",
|
|
{
|
|
map_id,
|
|
current_uniid_,
|
|
});
|
|
if (current_uniid_ >= FIXED_OBJECT_MAXID) {
|
|
A8_ABORT();
|
|
}
|
|
{
|
|
navmesh_ = dtAllocNavMesh();
|
|
FILE *fp = fopen((MetaMgr::Instance()->GetResDir() + "map3.bin").c_str(), "rb");
|
|
if(fp){
|
|
//fseek(fp, 0, SEEK_END);
|
|
//int file_size = ftell(fp);
|
|
int file_size = 1;
|
|
if(file_size){
|
|
NavMeshSetHeader header;
|
|
size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp);
|
|
if (readLen != 1) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
if (header.magic != NAVMESHSET_MAGIC) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
if (header.version != NAVMESHSET_VERSION) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
dtStatus status = navmesh_->init(&header.params);
|
|
if (dtStatusFailed(status)) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
#ifdef DEBUG
|
|
a8::XPrintf("orig:%f,%f,%f tileWidth:%f tileHeight:%f maxTiles:%d maxPolys:%d\n",
|
|
{
|
|
header.params.orig[0],
|
|
header.params.orig[1],
|
|
header.params.orig[2],
|
|
header.params.tileWidth,
|
|
header.params.tileHeight,
|
|
header.params.maxTiles,
|
|
header.params.maxPolys,
|
|
});
|
|
#endif
|
|
{
|
|
// Read tiles.
|
|
for (int i = 0; i < header.numTiles; ++i) {
|
|
NavMeshTileHeader tileHeader;
|
|
readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
|
|
if (readLen != 1) {
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
|
|
if (!tileHeader.tileRef || !tileHeader.dataSize) {
|
|
abort();
|
|
break;
|
|
}
|
|
|
|
unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize,
|
|
DT_ALLOC_PERM);
|
|
if (!data) {
|
|
abort();
|
|
break;
|
|
}
|
|
memset(data, 0, tileHeader.dataSize);
|
|
readLen = fread(data, tileHeader.dataSize, 1, fp);
|
|
if (readLen != 1) {
|
|
dtFree(data);
|
|
fclose(fp);
|
|
abort();
|
|
}
|
|
navmesh_->addTile(data,
|
|
tileHeader.dataSize,
|
|
DT_TILE_FREE_DATA,
|
|
tileHeader.tileRef,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
#if 1
|
|
{
|
|
navmesh_query_ = new dtNavMeshQuery();
|
|
navmesh_query_->init(navmesh_, 1024);
|
|
|
|
dtTileRef tile_ref = navmesh_->getTileRefAt(0, 0, 0);
|
|
|
|
glm::vec3 start;
|
|
glm::vec3 end;
|
|
glm::vec3 hit_point;
|
|
start.x = 1.45;
|
|
start.y = 0.0;
|
|
start.z = 1.45;
|
|
end = start;
|
|
end.x = 1035;
|
|
end.y = 0;
|
|
end.z = 51.25;
|
|
bool hit_result = false;
|
|
#if 0
|
|
auto a = Raycast(0, start, end, hit_point, hit_result);
|
|
|
|
a8::XPrintf("ret:%d hit_point:%f,%f,%f\n",
|
|
{
|
|
a,
|
|
hit_point.x,
|
|
hit_point.y,
|
|
hit_point.z
|
|
});
|
|
int i = 0;
|
|
#endif
|
|
}
|
|
{
|
|
std::set<float> group_y;
|
|
const dtMeshTile* tile = navmesh_->getTileAt(0, 0, 0);
|
|
for (int i = 0; i < tile->header->polyCount; ++i) {
|
|
dtPoly* poly = &tile->polys[i];
|
|
for (int ii = 0; ii < poly->vertCount; ++ii) {
|
|
const float* va = &tile->verts[poly->verts[ii] * 3];
|
|
float y = va[1];
|
|
group_y.insert(y);
|
|
}
|
|
}
|
|
a8::XPrintf("group_y>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", {});
|
|
for (auto& itr : group_y) {
|
|
a8::XPrintf("y:%f\n", {itr});
|
|
}
|
|
a8::XPrintf("group_y<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", {});
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void MapInstance::UnInit()
|
|
{
|
|
delete navmesh_query_;
|
|
navmesh_query_ = nullptr;
|
|
dtFreeNavMesh(navmesh_);
|
|
navmesh_ = nullptr;
|
|
|
|
map_service_->UnInit();
|
|
grid_service_->UnInit();
|
|
A8_SAFE_DELETE(map_service_);
|
|
A8_SAFE_DELETE(grid_service_);
|
|
}
|
|
|
|
void MapInstance::AttachRoom(Room* room, RoomInitInfo& init_info)
|
|
{
|
|
init_info.map_tpl_name = map_tpl_name_;
|
|
init_info.map_meta = map_meta_;
|
|
init_info.grid_service = grid_service_;
|
|
init_info.map_service = map_service_;
|
|
init_info.map_instance = this;
|
|
}
|
|
|
|
void MapInstance::CreateThings()
|
|
{
|
|
map_tpl_name_ = map_meta_->RandTemplate();
|
|
}
|
|
|
|
Entity* MapInstance::GetEntityByUniId(int uniid)
|
|
{
|
|
auto itr = uniid_hash_.find(uniid);
|
|
return itr != uniid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
int MapInstance::AllocUniid()
|
|
{
|
|
while (GetEntityByUniId(++current_uniid_) || current_uniid_ == 0) {
|
|
}
|
|
return current_uniid_;
|
|
}
|
|
|
|
int MapInstance::FindStraightPath(int layer,
|
|
const a8::Vec3& start,
|
|
const a8::Vec3& end,
|
|
std::vector<a8::Vec3>& paths)
|
|
{
|
|
float spos[3];
|
|
spos[0] = start.x;
|
|
spos[1] = start.y;
|
|
spos[2] = start.z;
|
|
|
|
float epos[3];
|
|
epos[0] = end.x;
|
|
epos[1] = end.y;
|
|
epos[2] = end.z;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(0xffff);
|
|
filter.setExcludeFlags(0);
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
dtPolyRef endRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
float startNearestPt[3];
|
|
float endNearestPt[3];
|
|
navmesh_query_->findNearestPoly(spos, extents, &filter, &startRef, startNearestPt);
|
|
navmesh_query_->findNearestPoly(epos, extents, &filter, &endRef, endNearestPt);
|
|
|
|
if (!startRef || !endRef) {
|
|
return NAV_ERROR_NEARESTPOLY;
|
|
}
|
|
|
|
int npolys;
|
|
float straightPath[MAX_POLYS * 3];
|
|
unsigned char straightPathFlags[MAX_POLYS];
|
|
dtPolyRef straightPathPolys[MAX_POLYS];
|
|
int nstraightPath;
|
|
int pos = 0;
|
|
|
|
navmesh_query_->findPath
|
|
(startRef,
|
|
endRef,
|
|
startNearestPt,
|
|
endNearestPt,
|
|
&filter,
|
|
polys_,
|
|
&npolys,
|
|
MAX_POLYS);
|
|
nstraightPath = 0;
|
|
|
|
if (npolys) {
|
|
|
|
float epos1[3];
|
|
dtVcopy(epos1, endNearestPt);
|
|
|
|
if (polys_[npolys-1] != endRef) {
|
|
navmesh_query_->closestPointOnPoly(polys_[npolys-1], endNearestPt, epos1, 0);
|
|
}
|
|
|
|
navmesh_query_->findStraightPath(startNearestPt,
|
|
endNearestPt,
|
|
polys_,
|
|
npolys,
|
|
straightPath,
|
|
straightPathFlags,
|
|
straightPathPolys,
|
|
&nstraightPath,
|
|
MAX_POLYS);
|
|
for(int i = 0; i < nstraightPath * 3; ) {
|
|
a8::Vec3 currpos;
|
|
currpos.x = straightPath[i++];
|
|
currpos.y = straightPath[i++];
|
|
currpos.z = straightPath[i++];
|
|
paths.push_back(currpos);
|
|
pos++;
|
|
}
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
int MapInstance::FindRandomPointAroundCircle(int layer,
|
|
const a8::Vec3& center_pos,
|
|
float max_radius,
|
|
glm::vec3& random_pt)
|
|
{
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(0xffff);
|
|
filter.setExcludeFlags(0);
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
float center[3];
|
|
center[0] = center_pos.x;
|
|
center[1] = center_pos.y;
|
|
center[2] = center_pos.z;
|
|
|
|
navmesh_query_->findNearestPoly(center, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return NAV_ERROR_NEARESTPOLY;
|
|
}
|
|
|
|
dtPolyRef randomRef = INVALID_NAVMESH_POLYREF;
|
|
float randomPt[3];
|
|
dtStatus status = navmesh_query_->findRandomPointAroundCircle
|
|
(startRef,
|
|
center,
|
|
max_radius,
|
|
&filter,
|
|
frand,
|
|
&randomRef,
|
|
randomPt);
|
|
|
|
if (dtStatusSucceed(status)) {
|
|
random_pt.x = randomPt[0];
|
|
random_pt.y = randomPt[1];
|
|
random_pt.z = randomPt[2];
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool MapInstance::Raycast(int layer, const glm::vec3& start, const glm::vec3& end,
|
|
glm::vec3& hit_point, bool& hit_result)
|
|
{
|
|
float spos[3];
|
|
spos[0] = start.x;
|
|
spos[1] = start.y;
|
|
spos[2] = start.z;
|
|
|
|
float epos[3];
|
|
epos[0] = end.x;
|
|
epos[1] = end.y;
|
|
epos[2] = end.z;
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
class MyDtQueryFtiler : public dtQueryFilter {
|
|
public:
|
|
std::function<bool (bool, const dtPolyRef, const dtMeshTile*, const dtPoly*)> cb;
|
|
|
|
bool passFilter(const dtPolyRef ref,
|
|
const dtMeshTile* tile,
|
|
const dtPoly* poly) const override
|
|
{
|
|
bool ret = dtQueryFilter::passFilter(ref, tile, poly);
|
|
if (cb) {
|
|
ret = cb(ret, ref, tile, poly);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
};
|
|
MyDtQueryFtiler filter;
|
|
filter.setIncludeFlags(0xffff);
|
|
filter.setExcludeFlags(0);
|
|
|
|
std::map<const dtPolyRef, std::tuple<const dtMeshTile*, const dtPoly*>> poly_hash;
|
|
{
|
|
filter.cb =
|
|
[&poly_hash] (bool ret, const dtPolyRef ref, const dtMeshTile* tile, const dtPoly* poly) -> bool
|
|
{
|
|
poly_hash[ref] = std::make_tuple(tile, poly);
|
|
return ret;
|
|
};
|
|
}
|
|
navmesh_query_->findNearestPoly(spos, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
float t = 0;
|
|
int npolys;
|
|
memset(hit_normal_, 0, sizeof(hit_normal_));
|
|
navmesh_query_->raycast(startRef, spos, epos, &filter, &t, hit_normal_, polys_, &npolys, MAX_POLYS);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_data = a8::Format("npolys:%d t:%f ", {npolys, t});
|
|
for (int i = 0; i < npolys; ++i) {
|
|
auto itr = poly_hash.find(polys_[i]);
|
|
if (itr != poly_hash.end()) {
|
|
auto tile = std::get<0>(itr->second);
|
|
auto poly = std::get<1>(itr->second);
|
|
assert(poly->vertCount > 2);
|
|
dbg_data += a8::Format("poly%d: vert_count:%d ", {i + 1, poly->vertCount});
|
|
for (int ii = 0; ii < poly->vertCount; ++ii) {
|
|
const float* va = &tile->verts[poly->verts[ii] * 3];
|
|
dbg_data += a8::Format(" v:%d %f,%f,%f ", {ii, va[0], va[1], va[2]});
|
|
}
|
|
|
|
} else {
|
|
abort();
|
|
}
|
|
}
|
|
a8::XPrintf("raycast hit dbg_data:%s\n", {dbg_data});
|
|
}
|
|
#endif
|
|
|
|
if (t > 1) {
|
|
// No Hit
|
|
hit_pos_[0] = epos[0];
|
|
hit_pos_[1] = epos[1];
|
|
hit_pos_[2] = epos[2];
|
|
hit_result = false;
|
|
} else {
|
|
// Hit
|
|
dtVlerp(hit_pos_, spos, epos, t);
|
|
if (npolys > 0) {
|
|
a8::Vec2 dir(epos[0] - spos[0], epos[2] - spos[2]);
|
|
dir.Normalize();
|
|
float hit_pos_copy[3];
|
|
dtVcopy(hit_pos_copy, hit_pos_);
|
|
|
|
float h = 0;
|
|
bool ok = false;
|
|
dir = dir / 10;
|
|
|
|
for (int ii = npolys - 1; ii >= 0; --ii) {
|
|
auto ret = navmesh_query_->getPolyHeight(polys_[ii], hit_pos_copy, &h);
|
|
if (ret == DT_SUCCESS){
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!ok){
|
|
ok = true;
|
|
} else {
|
|
for (int i = 0; i < 3; ++i) {
|
|
hit_pos_copy[0] -= dir.x;
|
|
hit_pos_copy[2] -= dir.y;
|
|
for (int ii = npolys - 1; ii >= 0; --ii) {
|
|
auto ret = navmesh_query_->getPolyHeight(polys_[ii], hit_pos_copy, &h);
|
|
if (ret == DT_SUCCESS){
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
if (ok) {
|
|
break;
|
|
}
|
|
}
|
|
dtVcopy(hit_pos_copy, hit_pos_);
|
|
for (int i = 0; i < 3; ++i) {
|
|
hit_pos_copy[0] += dir.x;
|
|
hit_pos_copy[2] += dir.y;
|
|
for (int ii = npolys - 1; ii >= 0; --ii) {
|
|
auto ret = navmesh_query_->getPolyHeight(polys_[ii], hit_pos_copy, &h);
|
|
if (ret == DT_SUCCESS){
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
if (ok) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
assert(ok);
|
|
hit_pos_[0] = hit_pos_copy[0];
|
|
hit_pos_[1] = h;
|
|
hit_pos_[2] = hit_pos_copy[2];
|
|
} else {
|
|
//abort();
|
|
}
|
|
hit_result = true;
|
|
}
|
|
|
|
hit_point.x = hit_pos_[0];
|
|
hit_point.y = hit_pos_[1];
|
|
hit_point.z = hit_pos_[2];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MapInstance::FindNearestPoint(const a8::Vec3& center, float radius, a8::Vec3& nearest_pt)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(0xffff);
|
|
filter.setExcludeFlags(0);
|
|
|
|
const float extents[3] = {radius, radius, radius};
|
|
float nearestPt[3];
|
|
|
|
float pos[3];
|
|
pos[0] = center.x;
|
|
pos[1] = center.y;
|
|
pos[2] = center.z;
|
|
|
|
navmesh_query_->findNearestPoly(pos, extents, &filter, &startRef, nearestPt);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
nearest_pt.x = nearestPt[0];
|
|
nearest_pt.y = nearestPt[1];
|
|
nearest_pt.z = nearestPt[2];
|
|
return true;
|
|
}
|
|
|
|
bool MapInstance::GetPosHeight(const Position& pos, float& out_height)
|
|
{
|
|
dtPolyRef startRef = INVALID_NAVMESH_POLYREF;
|
|
|
|
dtQueryFilter filter;
|
|
filter.setIncludeFlags(0xffff);
|
|
filter.setExcludeFlags(0);
|
|
|
|
const float extents[3] = {2.f, 4.f, 2.f};
|
|
float nearestPt[3];
|
|
|
|
float center[3];
|
|
center[0] = pos.x * GetMapMeta()->pb->scale();
|
|
center[1] = pos.y;
|
|
center[2] = pos.z * GetMapMeta()->pb->scale();
|
|
|
|
bool isOverPoly;
|
|
navmesh_query_->findNearestPoly(center, extents, &filter, &startRef, nearestPt, &isOverPoly);
|
|
if (!startRef) {
|
|
return false;
|
|
}
|
|
|
|
auto ret = navmesh_query_->getPolyHeight(startRef, nearestPt, &out_height);
|
|
#if 0
|
|
assert(ret == DT_SUCCESS);
|
|
#endif
|
|
if (ret != DT_SUCCESS) {
|
|
out_height = pos.y;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MapInstance::Scale(glm::vec3& v)
|
|
{
|
|
float old_y = v.y;
|
|
v *= GetMapMeta()->pb->scale();
|
|
v.y = old_y;
|
|
}
|
|
|
|
void MapInstance::UnScale(glm::vec3& v)
|
|
{
|
|
float old_y = v.y;
|
|
v /= GetMapMeta()->pb->scale();
|
|
v.y = old_y;
|
|
}
|