diff --git a/src/common/Config/ConfigDef.h b/src/common/Config/ConfigDef.h index 3aca9cff..4d99591f 100644 --- a/src/common/Config/ConfigDef.h +++ b/src/common/Config/ConfigDef.h @@ -44,6 +44,8 @@ namespace Sapphire::Common::Config uint16_t listenPort; uint16_t disconnectTimeout; + + float inRangeDistance; } network; struct Housing diff --git a/src/common/Util/SpawnIndexAllocator.h b/src/common/Util/SpawnIndexAllocator.h index 4ddfcc79..500339eb 100644 --- a/src/common/Util/SpawnIndexAllocator.h +++ b/src/common/Util/SpawnIndexAllocator.h @@ -37,7 +37,7 @@ namespace Sapphire::Util { auto it = m_actorIdToAllocatedMap.find( actorId ); if( it == m_actorIdToAllocatedMap.end() ) - return 0; + return getAllocFailId(); auto index = it->second; m_availableIds.push( index ); diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index f7e2c317..9ccc85d2 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -534,7 +534,20 @@ void Sapphire::Entity::Player::initSpawnIdQueue() uint8_t Sapphire::Entity::Player::getSpawnIdForActorId( uint32_t actorId ) { - return m_actorSpawnIndexAllocator.getNextFreeSpawnIndex( actorId ); + auto index = m_actorSpawnIndexAllocator.getNextFreeSpawnIndex( actorId ); + + if( index == m_actorSpawnIndexAllocator.getAllocFailId() ) + { + Logger::warn( "Failed to spawn Chara#{0} for Player#{1} - no remaining spawn indexes available. " + "Consider lowering InRangeDistance in world config.", + actorId, getId() ); + + sendUrgent( "Failed to spawn Chara#{0} for you - no remaining spawn slots. See world log.", actorId ); + + return index; + } + + return index; } bool Sapphire::Entity::Player::isActorSpawnIdValid( uint8_t spawnIndex ) @@ -1127,11 +1140,14 @@ void Sapphire::Entity::Player::freePlayerSpawnId( uint32_t actorId ) { auto spawnId = m_actorSpawnIndexAllocator.freeUsedSpawnIndex( actorId ); + // actor was never spawned for this player + if( spawnId == m_actorSpawnIndexAllocator.getAllocFailId() ) + return; + auto freeActorSpawnPacket = makeZonePacket< FFXIVIpcActorFreeSpawn >( getId() ); freeActorSpawnPacket->data().actorId = actorId; freeActorSpawnPacket->data().spawnId = spawnId; queuePacket( freeActorSpawnPacket ); - } uint8_t* Sapphire::Entity::Player::getAetheryteArray() @@ -1832,7 +1848,20 @@ void Sapphire::Entity::Player::teleportQuery( uint16_t aetheryteId, FrameworkPtr uint8_t Sapphire::Entity::Player::getNextObjSpawnIndexForActorId( uint32_t actorId ) { - return m_objSpawnIndexAllocator.getNextFreeSpawnIndex( actorId ); + auto index = m_objSpawnIndexAllocator.getNextFreeSpawnIndex( actorId ); + + if( index == m_objSpawnIndexAllocator.getAllocFailId() ) + { + Logger::warn( "Failed to spawn EObj#{0} for Player#{1} - no remaining spawn indexes available. " + "Consider lowering InRangeDistance in world config.", + actorId, getId() ); + + sendUrgent( "Failed to spawn EObj#{0} for you - no remaining spawn slots. See world log.", actorId ); + + return index; + } + + return index; } void Sapphire::Entity::Player::resetObjSpawnIndex() @@ -1844,6 +1873,10 @@ void Sapphire::Entity::Player::freeObjSpawnIndexForActorId( uint32_t actorId ) { auto spawnId = m_objSpawnIndexAllocator.freeUsedSpawnIndex( actorId ); + // obj was never spawned for this player + if( spawnId == m_objSpawnIndexAllocator.getAllocFailId() ) + return; + auto freeObjectSpawnPacket = makeZonePacket< FFXIVIpcObjectDespawn >( getId() ); freeObjectSpawnPacket->data().spawnIndex = spawnId; queuePacket( freeObjectSpawnPacket ); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 2c2edb83..da8ff1ac 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -2,6 +2,8 @@ #include #include +#include "ServerMgr.h" + #include #include "Actor/Player.h" @@ -59,6 +61,10 @@ bool Sapphire::World::Manager::TerritoryMgr::init() return false; } + auto& cfg = framework()->get< World::ServerMgr >()->getConfig(); + + m_inRangeDistance = cfg.network.inRangeDistance; + return true; } @@ -584,5 +590,9 @@ void Sapphire::World::Manager::TerritoryMgr::disableCurrentFestival() setCurrentFestival( 0 ); } +float Sapphire::World::Manager::TerritoryMgr::getInRangeDistance() const +{ + return m_inRangeDistance; +} diff --git a/src/world/Manager/TerritoryMgr.h b/src/world/Manager/TerritoryMgr.h index 1905b7f6..1c8846be 100644 --- a/src/world/Manager/TerritoryMgr.h +++ b/src/world/Manager/TerritoryMgr.h @@ -155,6 +155,8 @@ namespace Sapphire::World::Manager */ const std::pair< uint16_t, uint16_t >& getCurrentFestival() const; + float getInRangeDistance() const; + private: using TerritoryTypeDetailCache = std::unordered_map< uint16_t, Data::TerritoryTypePtr >; using InstanceIdToZonePtrMap = std::unordered_map< uint32_t, ZonePtr >; @@ -202,6 +204,9 @@ namespace Sapphire::World::Manager /*! current festival(s) to set for public zones from festival.exd */ std::pair< uint16_t, uint16_t > m_currentFestival; + /*! Max distance at which actors in range of a player are sent */ + float m_inRangeDistance; + public: /*! returns a list of instanceContent InstanceIds currently active */ InstanceIdList getInstanceContentIdList( uint16_t instanceContentId ) const; diff --git a/src/world/ServerMgr.cpp b/src/world/ServerMgr.cpp index 7149356d..e5b0367f 100644 --- a/src/world/ServerMgr.cpp +++ b/src/world/ServerMgr.cpp @@ -101,6 +101,7 @@ bool Sapphire::World::ServerMgr::loadSettings( int32_t argc, char* argv[] ) m_config.network.disconnectTimeout = pConfig->getValue< uint16_t >( "Network", "DisconnectTimeout", 20 ); m_config.network.listenIp = pConfig->getValue< std::string >( "Network", "ListenIp", "0.0.0.0" ); m_config.network.listenPort = pConfig->getValue< uint16_t >( "Network", "ListenPort", 54992 ); + m_config.network.inRangeDistance = pConfig->getValue< float >( "Network", "InRangeDistance", 100.f ); m_config.motd = pConfig->getValue< std::string >( "General", "MotD", "" ); diff --git a/src/world/Territory/CellHandler.h b/src/world/Territory/CellHandler.h index bfcdac52..7a0f6c86 100644 --- a/src/world/Territory/CellHandler.h +++ b/src/world/Territory/CellHandler.h @@ -3,7 +3,7 @@ #include #define TilesCount 32 -#define TileSize 250.0f +#define TileSize 325.0f #define _minY (-TilesCount*TileSize/2) #define _minX (-TilesCount*TileSize/2) diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index e1bfb528..d0472427 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -645,7 +645,7 @@ void Sapphire::Zone::updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell ) auto iter = pCell->m_actors.begin(); - float fRange = 70.0f; + float fRange = pTeriMgr->getInRangeDistance(); int32_t count = 0; while( iter != pCell->m_actors.end() ) { @@ -655,8 +655,7 @@ void Sapphire::Zone::updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell ) if( !pCurAct || pCurAct == pActor ) continue; - float distance = Util::distance( pCurAct->getPos().x, pCurAct->getPos().y, pCurAct->getPos().z, - pActor->getPos().x, pActor->getPos().y, pActor->getPos().z ); + float distance = Util::distance( pCurAct->getPos(), pActor->getPos() ); bool isInRange = ( fRange == 0.0f || distance <= fRange ); bool isInRangeSet = pActor->isInRangeSet( pCurAct );