game2006/server/gameserver/mapinstance.cc
aozhiwei 7bd0372f4d 1
2022-12-16 18:45:27 +08:00

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;
}