diff --git a/server/gameserver/creature.cc b/server/gameserver/creature.cc index d8c68bb5..1a080470 100644 --- a/server/gameserver/creature.cc +++ b/server/gameserver/creature.cc @@ -2563,12 +2563,14 @@ void Creature::OnLand() } { glm::vec3 center = GetPos().ToGlmVec3(); + #if 0 room->map_instance->PtInHouse(GetPos().ToGlmVec3(), center); + #endif room->map_instance->Scale(center); glm::vec3 point; bool ok = false; for (int i = 0; i < 10; ++i) { - ok = room->map_instance->FindNearestPoint(center, 1.0f + 10 * i, point); + ok = room->map_instance->FindConnectableNearestPoint(center, 1.0f + 10 * i, point); if (ok) { break; } @@ -2587,6 +2589,7 @@ void Creature::OnLand() abort(); #endif } else { + room->map_instance->AdjustOnLandPoint(point); room->map_instance->UnScale(point); } Global::Instance()->verify_set_pos = 1; @@ -2595,6 +2598,7 @@ void Creature::OnLand() GetMovement()->ClearPath(); room->grid_service->MoveCreature(this); #ifdef DEBUG + if (IsPlayer()) { a8::XPrintf("OnLoad ok:%d pos:%f,%f,%f\n", { ok ? 1 : 0, @@ -2602,6 +2606,7 @@ void Creature::OnLand() point.y, point.z }); + } #endif } if (IsAndroid()) { diff --git a/server/gameserver/mapinstance.cc b/server/gameserver/mapinstance.cc index 9d13d4e6..76714cf6 100644 --- a/server/gameserver/mapinstance.cc +++ b/server/gameserver/mapinstance.cc @@ -72,6 +72,20 @@ static void TraverseMapColliderNode(mc::ColliderNode* node, std::functionIsConnectablePoly(ref); + } + +}; + void MapInstance::Init() { map_meta_ = mt::Map::GetById(map_id); @@ -92,11 +106,6 @@ void MapInstance::Init() map_service_->Init(map_meta_->map_width() / MAP_GRID_WIDTH, map_meta_->map_height() / MAP_GRID_WIDTH, MAP_GRID_WIDTH); - f8::UdpLog::Instance()->Info - ("map_id:%d", - { - map_id - }); { navmesh_ = dtAllocNavMesh(); FILE *fp = fopen((mt::MetaMgr::Instance()->GetResDir() + "map4.bin").c_str(), "rb"); @@ -178,7 +187,14 @@ void MapInstance::Init() navmesh_query_ = new dtNavMeshQuery(); navmesh_query_->init(navmesh_, 1024); MarkMapAreaPolys(); + MarkConnectablePolys(); LoadHouse(); + f8::UdpLog::Instance()->Info + ("map_id:%d connectable_polys:%d", + { + map_id, + connectable_polys_.size() + }); } void MapInstance::UnInit() @@ -433,6 +449,34 @@ bool MapInstance::FindNearestPoint(const glm::vec3& center, float radius, glm::v return true; } +bool MapInstance::FindConnectableNearestPoint(const glm::vec3& center, float radius, glm::vec3& nearest_pt) +{ + dtPolyRef startRef = INVALID_NAVMESH_POLYREF; + + ConnectableQueryFilter filter; + filter.map_instance = this; + filter.setIncludeFlags(0xffff); + filter.setExcludeFlags(0); + + const float extents[3] = {radius, 10.0f, 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; @@ -1110,3 +1154,144 @@ bool MapInstance::GetNearestGrass(const glm::vec3& center, glm::vec3& out_pt) } return false; } + +void MapInstance::AdjustOnLandPoint(glm::vec3& point) +{ + float center[3]; + center[0] = point.x; + center[1] = point.y; + center[2] = point.z; + + const float extents[3] = {4.0f/10.0f, 100.0f, 4.0f/10.0f}; + + ConnectableQueryFilter filter; + filter.map_instance = this; + filter.setIncludeFlags(0xffff); + filter.setExcludeFlags(0); + + int poly_count = 0; + dtStatus status = navmesh_query_->queryPolygons(center, + extents, + &filter, + polys_, + &poly_count, + MAX_POLYS); + if (dtStatusFailed(status) || poly_count <= 0) { + return; + } + + glm::vec3 orig = glm::vec3(point.x, 100.0f, point.z);; + glm::vec3 dir = glm::vec3(0.0f, -1.0f, 0.0f); + const dtPoly* nearest_poly = nullptr; + float nearest_distance = 0.0f; + + for (int i = 0; i < poly_count; ++i) { + unsigned int slat = 0; + unsigned int it = 0; + unsigned int ip = 0; + navmesh_->decodePolyId(polys_[i], slat, it, ip); + + const dtMeshTile* tile = navmesh_->getTileByRef(polys_[i]); + if (!tile) { + abort(); + } + if (ip >= tile->header->polyCount) { + abort(); + } + const dtPoly* poly = &tile->polys[ip]; + for (int ii = 2; ii < poly->vertCount; ++ii) { + const float* va = &tile->verts[poly->verts[0]*3]; + const float* vb = &tile->verts[poly->verts[ii-1]*3]; + const float* vc = &tile->verts[poly->verts[ii]*3]; + + glm::vec3 v0 = glm::vec3(va[0], va[1], va[2]); + glm::vec3 v1 = glm::vec3(vb[0], vb[1], vb[2]); + glm::vec3 v2 = glm::vec3(vc[0], vc[1], vc[2]); + + glm::vec2 bary_position; + float distance; + + bool hit = glm::intersectRayTriangle + (orig, + dir, + v0, + v1, + v2, + bary_position, + distance + ); + if (hit && distance > 0.00001f) { + if (nearest_poly) { + if (distance < nearest_distance) { + nearest_poly = poly; + nearest_distance = distance; + } + } else { + nearest_poly = poly; + nearest_distance = distance; + } + } + }//end for ii + }//end for i; + if (!nearest_poly) { + return; + } + glm::vec3 nearest_pt = orig + dir * nearest_distance; + point.y = nearest_pt.y; +} + +void MapInstance::MarkConnectablePolys() +{ + dtPolyRef startRef = INVALID_NAVMESH_POLYREF; + { + glm::vec3 pos = glm::vec3(5120.000000000000f, 6.250846862793f, 5120.000000000000f); + + dtQueryFilter filter; + filter.setIncludeFlags(0xffff); + filter.setExcludeFlags(0); + + const float extents[3] = {2.f, 4.f, 2.f}; + float nearestPt[3]; + + Scale(pos); + + float pos1[3]; + pos1[0] = pos.x; + pos1[1] = pos.y; + pos1[2] = pos.z; + + navmesh_query_->findNearestPoly(pos1, extents, &filter, &startRef, nearestPt); + } + if (!startRef) { + abort(); + } + + std::list queue; + queue.push_back(startRef); + connectable_polys_.insert(startRef); + while (!queue.empty()) { + dtPolyRef poly_ref = queue.front(); + queue.pop_front(); + + const dtPoly* poly = nullptr; + const dtMeshTile* tile = 0; + navmesh_->getTileAndPolyByRefUnsafe(poly_ref, &tile, &poly); + for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next) { + dtPolyRef neighbour_ref = tile->links[i].ref; + if (!neighbour_ref) { + continue; + } + if (connectable_polys_.find(neighbour_ref) != + connectable_polys_.end()) { + continue; + } + queue.push_back(neighbour_ref); + connectable_polys_.insert(neighbour_ref); + } + } +} + +bool MapInstance::IsConnectablePoly(dtPolyRef poly_ref) +{ + return connectable_polys_.find(poly_ref) != connectable_polys_.end(); +} diff --git a/server/gameserver/mapinstance.h b/server/gameserver/mapinstance.h index 9c83e468..02ec160f 100644 --- a/server/gameserver/mapinstance.h +++ b/server/gameserver/mapinstance.h @@ -48,6 +48,7 @@ class MapInstance : public std::enable_shared_from_this int& same_polys_flags, std::vector& spec_polys, unsigned short exclude_flags); bool FindNearestPoint(const glm::vec3& center, float radius, glm::vec3& nearestPt); + bool FindConnectableNearestPoint(const glm::vec3& center, float radius, glm::vec3& nearestPt); bool GetPosHeight(const Position& pos, float& out_height); dtPoly* GetPoly(glm::vec3 pos, int& poly_idx); void Scale(glm::vec3& v); @@ -59,10 +60,13 @@ class MapInstance : public std::enable_shared_from_this bool SceneRaycast(const glm::vec3& orig, const glm::vec3& dir, float max_distance, glm::vec3& hit_pos, float& ray_length); bool GetNearestGrass(const glm::vec3& center, glm::vec3& out_pt); + void AdjustOnLandPoint(glm::vec3& point); + bool IsConnectablePoly(dtPolyRef poly_ref); private: void LoadHouse(); void MarkMapAreaPolys(); + void MarkConnectablePolys(); private: dtNavMesh* navmesh_ = nullptr; @@ -78,6 +82,7 @@ class MapInstance : public std::enable_shared_from_this std::list houses_; std::vector things_; + std::set connectable_polys_; std::string map_tpl_name_; const mt::Map* map_meta_ = nullptr;