diff --git a/src/servers/sapphire_zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/sapphire_zone/DebugCommand/DebugCommandHandler.cpp index 7cde49b0..1d1d6512 100644 --- a/src/servers/sapphire_zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/sapphire_zone/DebugCommand/DebugCommandHandler.cpp @@ -709,6 +709,47 @@ void Core::DebugCommandHandler::instance( char* data, Entity::Player &player, bo else player.sendDebug( "Failed to create instance with id: " + std::to_string( instanceContentId ) ); } + else if( subCommand == "bind" ) + { + uint32_t instanceId; + sscanf( params.c_str(), "%d", &instanceId ); + + auto instance = pTeriMgr->getInstanceZonePtr( instanceId ); + if( instance ) + { + auto pInstanceContent = instance->getAsInstanceContent(); + pInstanceContent->bindPlayer( player.getId() ); + player.sendDebug( + "Now bound to instance with id: " + std::to_string( pInstanceContent->getGuId() ) + + " -> " + pInstanceContent->getName() ); + } + else + player.sendDebug( "Unknown instance with id: " + std::to_string( instanceId ) ); + } + else if( subCommand == "unbind" ) + { + uint32_t instanceId; + sscanf( params.c_str(), "%d", &instanceId ); + + auto instance = pTeriMgr->getInstanceZonePtr( instanceId ); + if( !instance ) + { + player.sendDebug( "Unknown instance with id: " + std::to_string( instanceId ) ); + return; + } + + auto pInstanceContent = instance->getAsInstanceContent(); + if( pInstanceContent->isPlayerBound( player.getId() ) ) + { + pInstanceContent->unbindPlayer( player.getId() ); + player.sendDebug( + "Now unbound from instance with id: " + std::to_string( pInstanceContent->getGuId() ) + + " -> " + pInstanceContent->getName() ); + } + else + player.sendDebug( "Player not bound to instance with id: " + std::to_string( instanceId ) ); + + } else if( subCommand == "createzone" || subCommand == "crz" ) { uint32_t zoneId; diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index afffb561..336608bf 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -15,6 +15,7 @@ #include "Zone/TerritoryMgr.h" #include "Zone/Zone.h" +#include "Zone/InstanceContent.h" #include "Zone/ZonePosition.h" #include "Network/GameConnection.h" @@ -415,6 +416,15 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac { player.sendDebug( "Found instance: " + instance->getName() + ", id: " + std::to_string( param1 ) ); + // if the zone is an instanceContent instance, make sure the player is actually bound to it + auto pInstance = instance->getAsInstanceContent(); + if( !pInstance->isPlayerBound( player.getId() ) ) + { + player.sendUrgent( "Not able to join instance: " + std::to_string( param1 ) ); + player.sendUrgent( "Player not bound! ( run !instance bind first ) " + std::to_string( param1 ) ); + break; + } + player.setInstance( instance ); } else if( !pTeriMgr->isValidTerritory( param1 ) ) @@ -429,9 +439,11 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac player.sendUrgent( "No zone instance found for " + std::to_string( param1 ) ); break; } + targetPlayer->setPos( targetPlayer->getPos() ); targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 ); - player.sendNotice( targetPlayer->getName() + " was warped to zone " + std::to_string( param1 ) + " (" + pZone->getName() + ")" ); + player.sendNotice( targetPlayer->getName() + " was warped to zone " + + std::to_string( param1 ) + " (" + pZone->getName() + ")" ); } break; } diff --git a/src/servers/sapphire_zone/Zone/InstanceContent.cpp b/src/servers/sapphire_zone/Zone/InstanceContent.cpp index 8a27fefe..8bf57a51 100644 --- a/src/servers/sapphire_zone/Zone/InstanceContent.cpp +++ b/src/servers/sapphire_zone/Zone/InstanceContent.cpp @@ -101,6 +101,10 @@ void Core::InstanceContent::onLeaveTerritory( Entity::Player& player ) void Core::InstanceContent::onUpdate( uint32_t currTime ) { + + // TODO: check all players if still bound, if not, remove + // needs to happen regardless of state + switch( m_state ) { case Created: @@ -109,6 +113,7 @@ void Core::InstanceContent::onUpdate( uint32_t currTime ) if( m_playerMap.size() < 1 ) return; + // TODO: 1. check all bound players instead of just players in instance at the time for( const auto& playerIt : m_playerMap ) { if( !playerIt.second->isLoadingComplete() || @@ -410,3 +415,27 @@ uint16_t Core::InstanceContent::getCurrentBGM() const { return m_currentBgm; } + +bool Core::InstanceContent::bindPlayer( uint32_t playerId ) +{ + // if player already bound, return false + if( m_boundPlayerIds.count( playerId ) ) + return false; + + // TODO: do not allow binding of players if instance already has all it can take + // if( m_boundPlayerIds.size() >= party resttrictions ) + // return false; + + m_boundPlayerIds.insert( playerId ); + return true; +} + +bool Core::InstanceContent::isPlayerBound( uint32_t playerId ) const +{ + return m_boundPlayerIds.count( playerId ) > 0; +} + +void Core::InstanceContent::unbindPlayer( uint32_t playerId ) +{ + m_boundPlayerIds.erase( playerId ); +} diff --git a/src/servers/sapphire_zone/Zone/InstanceContent.h b/src/servers/sapphire_zone/Zone/InstanceContent.h index 4096018d..017e3c71 100644 --- a/src/servers/sapphire_zone/Zone/InstanceContent.h +++ b/src/servers/sapphire_zone/Zone/InstanceContent.h @@ -64,10 +64,19 @@ public: Entity::EventObjectPtr getEObjByName( const std::string& name ); + /*! binds a player to the instance */ + bool bindPlayer( uint32_t playerId ); + + /*! removes bind of player from the instance */ + void unbindPlayer( uint32_t playerId ); + + /*! return true if the player is bound to the instance */ + bool isPlayerBound( uint32_t playerId ) const; + /*! number of milliseconds after all players are ready for the instance to commence (spawn circle removed) */ const uint32_t instanceStartDelay = 1250; + private: - Event::DirectorPtr m_pDirector; boost::shared_ptr< Core::Data::InstanceContent > m_instanceContentInfo; uint32_t m_instanceContentId; InstanceContentState m_state; @@ -81,6 +90,9 @@ private: std::map< std::string, Entity::EventObjectPtr > m_eventObjectMap; std::unordered_map< uint32_t, Entity::EventObjectPtr > m_eventIdToObjectMap; std::set< uint32_t > m_spawnedPlayers; + + // the players which are bound to the instance, regardless of inside or offline + std::set< uint32_t > m_boundPlayerIds; }; }