diff --git a/CMakeLists.txt b/CMakeLists.txt index 9623c60e..f6a3419f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ add_custom_target( copy_runtime_files ALL # Dependencies and compiler settings # ###################################### include( "cmake/paths.cmake" ) -#include( "cmake/mysql.cmake" ) include( "cmake/compiler.cmake" ) include( "cmake/cotire.cmake" ) diff --git a/cmake/paths.cmake b/cmake/paths.cmake index 93e6008b..ab4ae84d 100644 --- a/cmake/paths.cmake +++ b/cmake/paths.cmake @@ -12,3 +12,4 @@ endif() # Create log folder file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/log ) +file( MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/navi ) diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index e5cb110e..b5da6e5b 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -161,32 +161,25 @@ void Sapphire::Entity::BNpc::step() // No path to track return; - if( Util::distance( getPos().x, getPos().y, getPos().z, m_naviTarget.x, m_naviTarget.y, m_naviTarget.z ) <= 4 ) - { - // Reached target - m_naviLastPath.clear(); - return; - } - auto stepPos = m_naviLastPath[ m_naviPathStep ]; - if( Util::distance( getPos().x, getPos().y, getPos().z, stepPos.x, stepPos.y, stepPos.z ) <= 4 && m_naviPathStep < m_naviLastPath.size() - 1 ) + if( Util::distance( getPos().x, getPos().y, getPos().z, stepPos.x, stepPos.y, stepPos.z ) <= 4 && + m_naviPathStep < m_naviLastPath.size() - 1 ) { // Reached step in path m_naviPathStep++; - stepPos = m_naviLastPath[ m_naviPathStep ]; } // This is probably not a good way to do it but works fine for now float angle = Util::calcAngFrom( getPos().x, getPos().z, stepPos.x, stepPos.z ) + PI; - auto x = ( cosf( angle ) * 1.1f ); + auto x = ( cosf( angle ) * 1.7f ); auto y = stepPos.y; - auto z = ( sinf( angle ) * 1.1f ); + auto z = ( sinf( angle ) * 1.7f ); - setPos( { getPos().x + x, y, getPos().z + z } ); face( stepPos ); + setPos( { getPos().x + x, y, getPos().z + z } ); sendPositionUpdate(); } @@ -194,12 +187,11 @@ void Sapphire::Entity::BNpc::step() bool Sapphire::Entity::BNpc::moveTo( const FFXIVARR_POSITION3& pos ) { if( Util::distance( getPos().x, getPos().y, getPos().z, pos.x, pos.y, pos.z ) <= 4 ) + { // Reached destination + m_naviLastPath.clear(); return true; - - if( m_naviTarget.x == pos.x && m_naviTarget.y == pos.y && m_naviTarget.z == pos.z ) - // Targets are the same - return false; + } // Check if we have to recalculate if( Util::getTimeMs() - m_naviLastUpdate > 500 ) @@ -224,29 +216,13 @@ bool Sapphire::Entity::BNpc::moveTo( const FFXIVARR_POSITION3& pos ) } else { - Logger::debug( "No path found from x{0} y{1} z{2} to x{3} y{4} z{5} in {6}", getPos().x, getPos().y, getPos().z, pos.x, pos.y, pos.z, m_pCurrentZone->getInternalName() ); + Logger::debug( "No path found from x{0} y{1} z{2} to x{3} y{4} z{5} in {6}", + getPos().x, getPos().y, getPos().z, pos.x, pos.y, pos.z, m_pCurrentZone->getInternalName() ); } } - /* - float rot = Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z ); - float newRot = PI - rot + ( PI / 2 ); - face( pos ); - float angle = Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z ) + PI; - auto x = ( cosf( angle ) * 1.1f ); - auto y = ( getPos().y + pos.y ) * 0.5f; // fake value while there is no collision - auto z = ( sinf( angle ) * 1.1f ); - - Common::FFXIVARR_POSITION3 newPos{ getPos().x + x, y, getPos().z + z }; - setPos( newPos ); - - Common::FFXIVARR_POSITION3 tmpPos{ getPos().x + x, y, getPos().z + z }; - setPos( tmpPos ); - setRot( newRot ); - - sendPositionUpdate(); - */ + step(); return false; } @@ -377,6 +353,7 @@ void Sapphire::Entity::BNpc::update( int64_t currTime ) const uint8_t minActorDistance = 4; const uint8_t aggroRange = 8; const uint8_t maxDistanceToOrigin = 40; + const uint32_t roamTick = 20; switch( m_state ) { @@ -391,8 +368,28 @@ void Sapphire::Entity::BNpc::update( int64_t currTime ) } break; + case BNpcState::Roaming: + { + if( moveTo( m_roamPos ) ) + { + m_lastRoamTargetReached = Util::getTimeSeconds(); + m_state = BNpcState::Idle; + } + + // checkaggro + } + break; + case BNpcState::Idle: { + if( Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) + { + auto pNaviMgr = m_pFw->get< World::Manager::NaviMgr >(); + auto pNaviProvider = pNaviMgr->getNaviProvider( m_pCurrentZone->getBgPath() ); + m_roamPos = pNaviProvider->findRandomPositionInCircle( m_spawnPos, 5 ); + m_state = BNpcState::Roaming; + } + // passive mobs should ignore players unless aggro'd if( m_aggressionMode == 1 ) return; @@ -465,7 +462,6 @@ void Sapphire::Entity::BNpc::update( int64_t currTime ) } } - step(); } void Sapphire::Entity::BNpc::onActionHostile( Sapphire::Entity::CharaPtr pSource ) diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index 171e5890..bd5e4d9a 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -24,6 +24,7 @@ namespace Sapphire::Entity Idle, Combat, Retreat, + Roaming, JustDied, Dead, }; @@ -103,8 +104,10 @@ namespace Sapphire::Entity uint8_t m_level; uint32_t m_timeOfDeath; + uint32_t m_lastRoamTargetReached; Common::FFXIVARR_POSITION3 m_spawnPos; + Common::FFXIVARR_POSITION3 m_roamPos; BNpcState m_state; std::set< std::shared_ptr< HateListEntry > > m_hateList; diff --git a/src/world/Navi/NaviProvider.cpp b/src/world/Navi/NaviProvider.cpp index 7ad3f463..f6ce1537 100644 --- a/src/world/Navi/NaviProvider.cpp +++ b/src/world/Navi/NaviProvider.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "NaviProvider.h" @@ -210,6 +211,60 @@ bool Sapphire::World::Navi::NaviProvider::getSteerTarget( dtNavMeshQuery* navQue return true; } +static float frand() +{ + return ( float ) rand() / (float)RAND_MAX; +} + + +Sapphire::Common::FFXIVARR_POSITION3 + Sapphire::World::Navi::NaviProvider::findRandomPositionInCircle( const Sapphire::Common::FFXIVARR_POSITION3& startPos, + float maxRadius ) +{ + dtStatus status; + + float spos[ 3 ] = { startPos.x, startPos.y, startPos.z }; + + float polyPickExt[ 3 ]; + polyPickExt[ 0 ] = 30; + polyPickExt[ 1 ] = 60; + polyPickExt[ 2 ] = 30; + + float randomPt[ 3 ]; + float snearest[ 3 ]; + + dtQueryFilter filter; + filter.setIncludeFlags( 0xffff ); + filter.setExcludeFlags( 0 ); + + dtPolyRef startRef; + dtPolyRef randomRef; + + status = m_naviMeshQuery->findNearestPoly( spos, polyPickExt, &filter, &startRef, snearest ); + + if( dtStatusFailed( status ) ) + { + return {}; + } + + if( !m_naviMesh->isValidPolyRef( startRef ) ) + { + return {}; + } + + auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >(); + auto rng = pRNGMgr->getRandGenerator< float >( 0.f, 1.f ); + status = m_naviMeshQuery->findRandomPointAroundCircle( startRef, spos, maxRadius, &filter, frand, + &randomRef, randomPt); + + if( dtStatusFailed( status ) ) + { + return {}; + } + + return { randomPt[ 0 ], randomPt[ 1 ], randomPt[ 2 ] }; +} + std::vector< Sapphire::Common::FFXIVARR_POSITION3 > Sapphire::World::Navi::NaviProvider::findFollowPath( const Common::FFXIVARR_POSITION3& startPos, const Common::FFXIVARR_POSITION3& endPos ) @@ -251,9 +306,9 @@ std::vector< Sapphire::Common::FFXIVARR_POSITION3 > m_naviMeshQuery->closestPointOnPoly( startRef, spos, iterPos, 0 ); m_naviMeshQuery->closestPointOnPoly( polys[ npolys - 1 ], epos, targetPos, 0 ); - Logger::debug( "IterPos: {0} {1} {2}; TargetPos: {3} {4} {5}", - iterPos[ 0 ], iterPos[ 1 ], iterPos[ 2 ], - targetPos[ 0 ], targetPos[ 1 ], targetPos[ 2 ] ); + //Logger::debug( "IterPos: {0} {1} {2}; TargetPos: {3} {4} {5}", + // iterPos[ 0 ], iterPos[ 1 ], iterPos[ 2 ], + // targetPos[ 0 ], targetPos[ 1 ], targetPos[ 2 ] ); const float STEP_SIZE = 1.2f; const float SLOP = 0.15f; @@ -370,7 +425,7 @@ std::vector< Sapphire::Common::FFXIVARR_POSITION3 > for( int32_t i = 0; i < numSmoothPath; i += 3 ) { - resultCoords.push_back( Common::FFXIVARR_POSITION3{ smoothPath[ i ], smoothPath[ i + 1 ], smoothPath[ i + 2 ] } ); + resultCoords.emplace_back( Common::FFXIVARR_POSITION3{ smoothPath[ i ], smoothPath[ i + 1 ], smoothPath[ i + 2 ] } ); } } diff --git a/src/world/Navi/NaviProvider.h b/src/world/Navi/NaviProvider.h index ff833ca4..e69b6671 100644 --- a/src/world/Navi/NaviProvider.h +++ b/src/world/Navi/NaviProvider.h @@ -40,7 +40,10 @@ namespace Sapphire::World::Navi void toDetourPos( const Common::FFXIVARR_POSITION3& position, float* out ); Common::FFXIVARR_POSITION3 toGamePos( float* pos ); - std::vector< Common::FFXIVARR_POSITION3 > findFollowPath( const Common::FFXIVARR_POSITION3& startPos, const Common::FFXIVARR_POSITION3& endPos ); + std::vector< Common::FFXIVARR_POSITION3 > findFollowPath( const Common::FFXIVARR_POSITION3& startPos, + const Common::FFXIVARR_POSITION3& endPos ); + Common::FFXIVARR_POSITION3 findRandomPositionInCircle( const Sapphire::Common::FFXIVARR_POSITION3& startPos, + float maxRadius ); bool hasNaviMesh() const;