diff --git a/src/world/CMakeLists.txt b/src/world/CMakeLists.txt index 7d25aae6..7954ae70 100644 --- a/src/world/CMakeLists.txt +++ b/src/world/CMakeLists.txt @@ -19,7 +19,8 @@ file( GLOB SERVER_SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} Script/*.c* StatusEffect/*.c* Territory/*.c* - Territory/Housing/*.c*) + Territory/Housing/*.c* + Navi/*.c*) add_executable( world ${SERVER_SOURCE_FILES} ) @@ -30,10 +31,12 @@ set_target_properties( world target_link_libraries( world PUBLIC - common ) + common + Detour) target_include_directories( world PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}" ) + "${CMAKE_CURRENT_SOURCE_DIR}" + Detour ) if( UNIX ) diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 81c1aa96..f4abad11 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -163,16 +163,17 @@ bool Sapphire::World::Manager::TerritoryMgr::createDefaultTerritories() uint32_t guid = getNextInstanceId(); - Logger::info( "{0}\t{1}\t{2}\t{3:<10}\t{4}\t{5}", + auto pZone = make_Zone( territoryTypeId, guid, territoryInfo->name, pPlaceName->name, framework() ); + pZone->init(); + + Logger::info( "{0}\t{1}\t{2}\t{3:<10}\t{4}\t{5}\t{6}", territoryTypeId, guid, territoryInfo->territoryIntendedUse, territoryInfo->name, ( isPrivateTerritory( territoryTypeId ) ? "PRIVATE" : "PUBLIC" ), - pPlaceName->name ); - - auto pZone = make_Zone( territoryTypeId, guid, territoryInfo->name, pPlaceName->name, framework() ); - pZone->init(); + pPlaceName->name, + pZone->GetNaviProvider()->HasNaviMesh() ? "NAVI" : ""); InstanceIdToZonePtrMap instanceMap; instanceMap[ guid ] = pZone; diff --git a/src/world/Navi/NaviProvider.cpp b/src/world/Navi/NaviProvider.cpp new file mode 100644 index 00000000..a252b772 --- /dev/null +++ b/src/world/Navi/NaviProvider.cpp @@ -0,0 +1,135 @@ +#include +#include + +#include "Framework.h" +#include "NaviProvider.h" +#include +#include +#include +#include + +#include "../Territory/Zone.h" +#include + +Sapphire::NaviProvider::NaviProvider( Sapphire::ZonePtr pZone, Sapphire::FrameworkPtr pFw ) : + m_pFw( pFw ), + m_pZone( pZone ), + m_naviMesh( nullptr ), + m_naviMeshQuery( nullptr ) +{ +} + +void Sapphire::NaviProvider::init() +{ + auto meshesFolder = std::filesystem::path( "navi" ); + auto meshFolder = meshesFolder / std::filesystem::path( m_pZone->getInternalName() ); + + if( std::filesystem::exists( meshFolder ) ) + { + auto baseMesh = meshFolder / std::filesystem::path( m_pZone->getInternalName() + ".nav" ); + + //m_naviMesh = LoadMesh( baseMesh.string() ); + + // Load all meshes for testing + for( const auto & entry : std::filesystem::directory_iterator( meshFolder ) ) + { + if( entry.path().extension().string() == ".nav" ) + { + Logger::debug( "Loading " + entry.path().string() ); + LoadMesh( entry.path().string() ); + } + } + + InitQuery(); + } +} + +bool Sapphire::NaviProvider::HasNaviMesh() const +{ + return m_naviMesh != nullptr; +} + +void Sapphire::NaviProvider::InitQuery() +{ + if(m_naviMeshQuery != nullptr) + dtFreeNavMeshQuery( m_naviMeshQuery ); + + m_naviMeshQuery = dtAllocNavMeshQuery(); + m_naviMeshQuery->init( m_naviMesh, 2048 ); +} + +void Sapphire::NaviProvider::LoadMesh( std::string path ) +{ + FILE* fp = fopen( path.c_str(), "rb" ); + if( !fp ) + throw std::exception( "Could open navimesh file" ); + + // Read header. + NavMeshSetHeader header; + + size_t readLen = fread( &header, sizeof( NavMeshSetHeader ), 1, fp ); + if( readLen != 1 ) + { + fclose( fp ); + throw std::exception( "Could not read NavMeshSetHeader" ); + } + + if( header.magic != NAVMESHSET_MAGIC ) + { + fclose( fp ); + throw std::exception( "Not a NavMeshSet" ); + } + + if( header.version != NAVMESHSET_VERSION ) + { + fclose( fp ); + throw std::exception( "Invalid NavMeshSet version" ); + } + + if( !m_naviMesh ) + { + m_naviMesh = dtAllocNavMesh(); + if( !m_naviMesh ) + { + fclose( fp ); + throw std::exception( "Could not allocate dtNavMesh" ); + } + + dtStatus status = m_naviMesh->init( &header.params ); + if( dtStatusFailed( status ) ) + { + fclose( fp ); + throw std::exception( "Could not initialize dtNavMesh" ); + } + } + + // Read tiles. + for( int i = 0; i < header.numTiles; ++i ) + { + NavMeshTileHeader tileHeader; + readLen = fread( &tileHeader, sizeof( tileHeader ), 1, fp ); + if( readLen != 1 ) + { + fclose( fp ); + throw std::exception( "Could not read NavMeshTileHeader" ); + } + + if( !tileHeader.tileRef || !tileHeader.dataSize ) + break; + + unsigned char* data = (unsigned char*)dtAlloc( tileHeader.dataSize, DT_ALLOC_PERM ); + if( !data ) break; + memset( data, 0, tileHeader.dataSize ); + readLen = fread( data, tileHeader.dataSize, 1, fp ); + if( readLen != 1 ) + { + dtFree( data ); + fclose( fp ); + throw std::exception( "Could not read tile data" ); + } + + m_naviMesh->addTile( data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0 ); + } + + fclose( fp ); +} \ No newline at end of file diff --git a/src/world/Navi/NaviProvider.h b/src/world/Navi/NaviProvider.h new file mode 100644 index 00000000..706c3a9b --- /dev/null +++ b/src/world/Navi/NaviProvider.h @@ -0,0 +1,51 @@ +#ifndef _NAVIPROVIDER_H_ +#define _NAVIPROVIDER_H_ + +#include +#include "ForwardsZone.h" +#include +#include + +namespace Sapphire +{ + + class NaviProvider + { + + 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; + }; + + public: + NaviProvider( const ZonePtr pZone, Sapphire::FrameworkPtr pFw ); + + void init(); + void LoadMesh( std::string path ); + void InitQuery(); + + bool HasNaviMesh() const; + + protected: + FrameworkPtr m_pFw; + ZonePtr m_pZone; + + dtNavMesh* m_naviMesh; + dtNavMeshQuery* m_naviMeshQuery; + }; + +} + +#endif diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index 21817559..0cd0c9fc 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -124,6 +124,9 @@ bool Sapphire::Zone::init() // all good } + m_naviProvider = new NaviProvider( shared_from_this(), m_pFw ); + m_naviProvider->init(); + return true; } @@ -782,7 +785,7 @@ bool Sapphire::Zone::loadSpawnGroups() m_spawnGroups.emplace_back( id, templateId, level, maxHp ); - Logger::debug( "id: {0}, template: {1}, level: {2}, maxHp: {3}", id, m_spawnGroups.back().getTemplateId(), level, maxHp ); + //Logger::debug( "id: {0}, template: {1}, level: {2}, maxHp: {3}", id, m_spawnGroups.back().getTemplateId(), level, maxHp ); } res.reset(); @@ -805,7 +808,7 @@ bool Sapphire::Zone::loadSpawnGroups() group.getSpawnPointList().emplace_back( std::make_shared< Entity::SpawnPoint >( x, y, z, r, gimmickId ) ); - Logger::debug( "id: {0}, x: {1}, y: {2}, z: {3}, gimmickId: {4}", id, x, y, z, gimmickId ); + //Logger::debug( "id: {0}, x: {1}, y: {2}, z: {3}, gimmickId: {4}", id, x, y, z, gimmickId ); } } return false; @@ -848,3 +851,9 @@ void Sapphire::Zone::updateSpawnPoints() } } + +Sapphire::NaviProvider* Sapphire::Zone::GetNaviProvider() const +{ + return m_naviProvider; +} + diff --git a/src/world/Territory/Zone.h b/src/world/Territory/Zone.h index 657b99c9..192c3fde 100644 --- a/src/world/Territory/Zone.h +++ b/src/world/Territory/Zone.h @@ -6,6 +6,7 @@ #include "Cell.h" #include "CellHandler.h" +#include "Navi/NaviProvider.h" #include "ForwardsZone.h" @@ -62,6 +63,8 @@ namespace Sapphire std::vector< Entity::SpawnGroup > m_spawnGroups; + NaviProvider* m_naviProvider; + public: Zone(); @@ -158,6 +161,8 @@ namespace Sapphire InstanceContentPtr getAsInstanceContent(); void updateSpawnPoints(); + + NaviProvider* GetNaviProvider() const; }; }