diff --git a/src/servers/sapphire_zone/Action/ActionCollision.cpp b/src/servers/sapphire_zone/Action/ActionCollision.cpp index a66d234c..60948fcf 100644 --- a/src/servers/sapphire_zone/Action/ActionCollision.cpp +++ b/src/servers/sapphire_zone/Action/ActionCollision.cpp @@ -2,6 +2,7 @@ #include #include "ActionCollision.h" +#include "Actor/GameObject.h" #include "Actor/Actor.h" #include "Actor/Player.h" @@ -51,7 +52,7 @@ bool ActionCollision::isActorApplicable( Actor& actor, TargetFilter targetFilter } std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition, - std::set< ActorPtr > actorsInRange, + std::set< GameObjectPtr > gameObjectsInRange, boost::shared_ptr< Core::Data::Action > actionInfo, TargetFilter targetFilter ) { @@ -64,52 +65,52 @@ std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXI { // This is actually needed. There is "splash damage" in actions marked as single target. // Notice how we're using aoe_width. How collision works for SingleTarget is unknown as of now. - for( auto pActor : actorsInRange ) + for( auto pActor : gameObjectsInRange ) { // Make sure actor exists. If it doesn't we done goofed. assert( pActor ); // Don't bother wasting on collision if actor doesn't apply for it - if ( !isActorApplicable( *pActor, targetFilter ) ) + if ( !isActorApplicable( *pActor->getAsActor(), targetFilter ) ) continue; // Test our collision from actor with the area generated by the action from the AoE data if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->effectRange ) ) { // Add it to the actors collided with the area - actorsCollided.insert( pActor ); + //actorsCollided.insert( pActor ); } } break; } case ActionCollisionType::Circle: { - for( auto pActor : actorsInRange ) + for( auto pActor : gameObjectsInRange ) { assert( pActor ); - if ( !isActorApplicable( *pActor, targetFilter ) ) + if ( !isActorApplicable( *pActor->getAsActor(), targetFilter ) ) continue; - if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->effectRange ) ) - actorsCollided.insert( pActor ); + //if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->effectRange ) ) + //actorsCollided.insert( pActor ); } break; } case ActionCollisionType::Box: { - for( auto pActor : actorsInRange ) + for( auto pActor : gameObjectsInRange ) { assert( pActor ); - if ( !isActorApplicable( *pActor, targetFilter ) ) + if ( !isActorApplicable( *pActor->getAsActor(), targetFilter ) ) continue; if ( boxCollision( pActor->getPos(), aoePosition, actionInfo->xAxisModifier, actionInfo->effectRange ) ) { // todo: does this actually work? - actorsCollided.insert( pActor ); + //actorsCollided.insert( pActor ); } } break; diff --git a/src/servers/sapphire_zone/Action/ActionCollision.h b/src/servers/sapphire_zone/Action/ActionCollision.h index 0c0da597..47684448 100644 --- a/src/servers/sapphire_zone/Action/ActionCollision.h +++ b/src/servers/sapphire_zone/Action/ActionCollision.h @@ -25,7 +25,7 @@ namespace Entity { static bool isActorApplicable( Actor& actor, TargetFilter targetFilter ); static std::set< ActorPtr > getActorsHitFromAction( Common::FFXIVARR_POSITION3 aoePosition, - std::set< ActorPtr > actorsInRange, + std::set< GameObjectPtr > gameObjectsInRange, boost::shared_ptr< Data::Action > actionInfo, TargetFilter targetFilter ); diff --git a/src/servers/sapphire_zone/Actor/Actor.cpp b/src/servers/sapphire_zone/Actor/Actor.cpp index 45b076a6..8b7f02ea 100644 --- a/src/servers/sapphire_zone/Actor/Actor.cpp +++ b/src/servers/sapphire_zone/Actor/Actor.cpp @@ -52,17 +52,6 @@ std::string Core::Entity::Actor::getName() const return std::string( m_name ); } -/*! \return list of actors currently in range */ -std::set< Core::Entity::ActorPtr > Core::Entity::Actor::getInRangeActors( bool includeSelf ) -{ - auto tempInRange = m_inRangeActors; - - if( includeSelf ) - tempInRange.insert( getAsActor() ); - - return tempInRange; - } - /*! \return current stance of the actors */ Core::Entity::Actor::Stance Core::Entity::Actor::getStance() const { @@ -396,48 +385,6 @@ void Core::Entity::Actor::setCurrentAction( Core::Action::ActionPtr pAction ) m_pCurrentAction = pAction; } -/*! -check if a given actor is in the actors in range set - -\param ActorPtr to be checked for -\return true if the actor was found -*/ -bool Core::Entity::Actor::isInRangeSet( ActorPtr pActor ) const -{ - return !( m_inRangeActors.find( pActor ) == m_inRangeActors.end() ); -} - -/*! \return ActorPtr of the closest actor in range, if none, nullptr */ -Core::Entity::ActorPtr Core::Entity::Actor::getClosestActor() -{ - if( m_inRangeActors.empty() ) - // no actors in range, don't bother - return nullptr; - - ActorPtr tmpActor = nullptr; - - // arbitrary high number - float minDistance = 10000; - - for( const auto& pCurAct : m_inRangeActors ) - { - float distance = Math::Util::distance( getPos().x, - getPos().y, - getPos().z, - pCurAct->getPos().x, - pCurAct->getPos().y, - pCurAct->getPos().z ); - - if( distance < minDistance ) - { - minDistance = distance; - tmpActor = pCurAct; - } - } - - return tmpActor; -} - /*! Send a packet to all players in range, potentially to self if set and is player @@ -471,80 +418,6 @@ void Core::Entity::Actor::sendToInRangeSet( Network::Packets::GamePacketPtr pPac } } -/*! -Add a given actor to the fitting in range set according to type -but also to the global actor map - -\param ActorPtr to add -*/ -void Core::Entity::Actor::addInRangeActor( ActorPtr pActor ) -{ - - // if this is null, something went wrong - assert( pActor ); - - // add actor to in range set - m_inRangeActors.insert( pActor ); - - if( pActor->isPlayer() ) - { - auto pPlayer = pActor->getAsPlayer(); - - // if actor is a player, add it to the in range player set - m_inRangePlayers.insert( pPlayer ); - } -} - -/*! -Remove a given actor from the matching in range set according to type -but also to the global actor map - -\param ActorPtr to remove -*/ -void Core::Entity::Actor::removeInRangeActor( Actor& actor ) -{ - // call virtual event - onRemoveInRangeActor( actor ); - - // remove actor from in range actor set - m_inRangeActors.erase( actor.getAsActor() ); - - // if actor is a player, despawn ourself for him - // TODO: move to virtual onRemove? - if( isPlayer() ) - actor.despawn( getAsPlayer() ); - - if( actor.isPlayer() ) - m_inRangePlayers.erase( actor.getAsPlayer() ); -} - -/*! \return true if there is at least one actor in the in range set */ -bool Core::Entity::Actor::hasInRangeActor() const -{ - return ( m_inRangeActors.size() > 0 ); -} - -void Core::Entity::Actor::removeFromInRange() -{ - if( !hasInRangeActor() ) - return; - - Entity::ActorPtr pCurAct; - - for( auto& pCurAct : m_inRangeActors ) - { - pCurAct->removeInRangeActor( *this ); - } - -} - -/*! Clear the whole in range set, this does no cleanup */ -void Core::Entity::Actor::clearInRangeSet() -{ - m_inRangeActors.clear(); - m_inRangePlayers.clear(); -} - /*! \return ZonePtr to the current zone, nullptr if not set */ Core::ZonePtr Core::Entity::Actor::getCurrentZone() const { @@ -682,7 +555,7 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint16_t actionId, u else { - auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors( true ), + auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeGameObjects( true ), actionInfoPtr, TargetFilter::Enemies ); for( const auto& pHitActor : actorsCollided ) @@ -734,7 +607,7 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint16_t actionId, u // todo: get proper packets: the following was just kind of thrown together from what we know. // atm buggy (packets look "delayed" from client) - auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors( true ), + auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeGameObjects( true ), actionInfoPtr, TargetFilter::Allies ); for( auto pHitActor : actorsCollided ) diff --git a/src/servers/sapphire_zone/Actor/Actor.h b/src/servers/sapphire_zone/Actor/Actor.h index cb2142af..3948b547 100644 --- a/src/servers/sapphire_zone/Actor/Actor.h +++ b/src/servers/sapphire_zone/Actor/Actor.h @@ -139,9 +139,6 @@ protected: std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList; std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap; - std::set< ActorPtr > m_inRangeActors; - std::set< PlayerPtr > m_inRangePlayers; - public: Actor( ObjKind type ); @@ -182,8 +179,6 @@ public: std::string getName() const; - std::set< ActorPtr > getInRangeActors( bool includeSelf = false ); - bool face( const Common::FFXIVARR_POSITION3& p ); Stance getStance() const; @@ -233,8 +228,6 @@ public: virtual void autoAttack( ActorPtr pTarget ); - virtual void onRemoveInRangeActor( Actor& pActor ) {} - virtual void onDeath() {}; virtual void onDamageTaken( Actor& pSource ) {}; virtual void onActionHostile( Actor& source ) {}; @@ -255,27 +248,8 @@ public: ///// IN RANGE LOGIC ///// - // check if another actor is in the actors in range set - bool isInRangeSet( ActorPtr pActor ) const; - - ActorPtr getClosestActor(); - void sendToInRangeSet( Network::Packets::GamePacketPtr pPacket, bool bToSelf = false ); - // add an actor to in range set - void addInRangeActor( ActorPtr pActor ); - - // remove an actor from the in range set - void removeInRangeActor( Actor& pActor ); - - // return true if there is at least one actor in the in range set - bool hasInRangeActor() const; - - void removeFromInRange(); - - // clear the whole in range set, this does no cleanup - virtual void clearInRangeSet(); - ZonePtr getCurrentZone() const; void setCurrentZone( ZonePtr currZone ); diff --git a/src/servers/sapphire_zone/Actor/BattleNpc.cpp b/src/servers/sapphire_zone/Actor/BattleNpc.cpp index 5b43728b..29cdf7b3 100644 --- a/src/servers/sapphire_zone/Actor/BattleNpc.cpp +++ b/src/servers/sapphire_zone/Actor/BattleNpc.cpp @@ -501,9 +501,13 @@ void Core::Entity::BattleNpc::update( int64_t currTime ) case MODE_IDLE: { - ActorPtr pClosestActor = getClosestActor(); + // this is bad, it should be getClosesPlayer + GameObjectPtr pClosestActor = getClosestGameObject(); - if( pClosestActor && pClosestActor->isAlive() ) + if( !pClosestActor->isPlayer() ) + break; + + if( pClosestActor && pClosestActor->getAsPlayer()->isAlive() ) { distance = Math::Util::distance( getPos().x, getPos().y, getPos().z, pClosestActor->getPos().x, diff --git a/src/servers/sapphire_zone/Actor/GameObject.cpp b/src/servers/sapphire_zone/Actor/GameObject.cpp index 16c042ab..475abb37 100644 --- a/src/servers/sapphire_zone/Actor/GameObject.cpp +++ b/src/servers/sapphire_zone/Actor/GameObject.cpp @@ -1,5 +1,8 @@ #include "GameObject.h" +#include +#include + #include "Player.h" #include "Actor.h" #include "BattleNpc.h" @@ -63,6 +66,131 @@ bool Core::Entity::GameObject::isEventNpc() const return m_objKind == ObjKind::EventNpc; } +/*! +Add a given actor to the fitting in range set according to type +but also to the global actor map + +\param ActorPtr to add +*/ +void Core::Entity::GameObject::addInRangeGameObject( GameObjectPtr pGameObject ) +{ + + // if this is null, something went wrong + assert( pGameObject ); + + // add actor to in range set + m_inRangeGameObjects.insert( { pGameObject } ); + + if( pGameObject->isPlayer() ) + { + auto pPlayer = pGameObject->getAsPlayer(); + + // if actor is a player, add it to the in range player set + m_inRangePlayers.insert( pGameObject->getAsPlayer() ); + } +} + +/*! +Remove a given actor from the matching in range set according to type +but also to the global actor map + +\param ActorPtr to remove +*/ +void Core::Entity::GameObject::removeInRangeGameObject( GameObject& gameObject ) +{ + // call virtual event + onRemoveInRangeGameObject( gameObject ); + + // remove actor from in range actor set + m_inRangeGameObjects.erase( gameObject.shared_from_this() ); + + // if actor is a player, despawn ourself for him + // TODO: move to virtual onRemove? + if( isPlayer() ) + gameObject.despawn( getAsPlayer() ); + + if( gameObject.isPlayer() ) + m_inRangePlayers.erase( gameObject.getAsPlayer() ); +} + +/*! \return true if there is at least one actor in the in range set */ +bool Core::Entity::GameObject::hasInRangeGameObject() const +{ + return ( m_inRangeGameObjects.size() > 0 ); +} + +void Core::Entity::GameObject::removeFromInRange() +{ + if( !hasInRangeGameObject() ) + return; + + for( auto& pCurAct : m_inRangeGameObjects ) + { + pCurAct->removeInRangeGameObject( *this ); + } + +} + +/*! Clear the whole in range set, this does no cleanup */ +void Core::Entity::GameObject::clearInRangeSet() +{ + m_inRangeGameObjects.clear(); + m_inRangePlayers.clear(); +} + +/*! \return list of actors currently in range */ +std::set< Core::Entity::GameObjectPtr > Core::Entity::GameObject::getInRangeGameObjects( bool includeSelf ) +{ + auto tempInRange = m_inRangeGameObjects; + + if( includeSelf ) + tempInRange.insert( { shared_from_this() } ); + + return tempInRange; +} + +/*! +check if a given actor is in the actors in range set + +\param ActorPtr to be checked for +\return true if the actor was found +*/ +bool Core::Entity::GameObject::isInRangeSet( GameObjectPtr pGameObject ) const +{ + return !( m_inRangeGameObjects.find( pGameObject ) == m_inRangeGameObjects.end() ); +} + +/*! \return ActorPtr of the closest actor in range, if none, nullptr */ +Core::Entity::GameObjectPtr Core::Entity::GameObject::getClosestGameObject() +{ + if( m_inRangeGameObjects.empty() ) + // no actors in range, don't bother + return nullptr; + + GameObjectPtr tmpActor = nullptr; + + // arbitrary high number + float minDistance = 10000; + + for( const auto& pCurAct : m_inRangeGameObjects ) + { + float distance = Math::Util::distance( getPos().x, + getPos().y, + getPos().z, + pCurAct->getPos().x, + pCurAct->getPos().y, + pCurAct->getPos().z ); + + if( distance < minDistance ) + { + minDistance = distance; + tmpActor = pCurAct; + } + } + + return tmpActor; +} + /*! \return pointer to this instance as ActorPtr */ Core::Entity::ActorPtr Core::Entity::GameObject::getAsActor() { diff --git a/src/servers/sapphire_zone/Actor/GameObject.h b/src/servers/sapphire_zone/Actor/GameObject.h index d1f70b3b..cc4e7eb2 100644 --- a/src/servers/sapphire_zone/Actor/GameObject.h +++ b/src/servers/sapphire_zone/Actor/GameObject.h @@ -49,6 +49,9 @@ namespace Entity { /*! Type of the actor */ ObjKind m_objKind; + std::set< GameObjectPtr > m_inRangeGameObjects; + std::set< PlayerPtr > m_inRangePlayers; + public: explicit GameObject( ObjKind type ); virtual ~GameObject() {}; @@ -56,6 +59,29 @@ namespace Entity { virtual void spawn( PlayerPtr pTarget ) {} virtual void despawn( PlayerPtr pTarget ) {} + virtual void onRemoveInRangeGameObject( GameObject &pGameObject ) {} + + // add an actor to in range set + void addInRangeGameObject( GameObjectPtr pGameObject ); + + // remove an actor from the in range set + void removeInRangeGameObject( GameObject& pGameObject ); + + // return true if there is at least one actor in the in range set + bool hasInRangeGameObject() const; + + void removeFromInRange(); + + // clear the whole in range set, this does no cleanup + virtual void clearInRangeSet(); + + std::set< GameObjectPtr > getInRangeGameObjects( bool includeSelf = false ); + + // check if another actor is in the actors in range set + bool isInRangeSet( GameObjectPtr pGameObject ) const; + + GameObjectPtr getClosestGameObject(); + uint32_t getId() const; ObjKind getObjKind() const; diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index 4c7c3df8..8b6762d3 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -831,14 +831,14 @@ void Core::Entity::Player::despawn( Entity::PlayerPtr pTarget ) Core::Entity::ActorPtr Core::Entity::Player::lookupTargetById( uint64_t targetId ) { - ActorPtr targetActor; - auto inRange = getInRangeActors( true ); + GameObjectPtr targetActor; + auto inRange = getInRangeGameObjects(true); for( auto actor : inRange ) { if( actor->getId() == targetId ) targetActor = actor; } - return targetActor; + return targetActor->getAsActor(); } void Core::Entity::Player::setLastPing( uint32_t ping ) @@ -1005,9 +1005,12 @@ void Core::Entity::Player::update( int64_t currTime ) auto mainWeap = m_pInventory->getItemAt( Inventory::GearSet0, Inventory::EquipSlot::MainHand ); // @TODO i dislike this, iterating over all in range actors when you already know the id of the actor you need... - for( auto actor : m_inRangeActors ) + for( auto actor : m_inRangeGameObjects ) { - if( actor->getId() == m_targetId && actor->isAlive() && mainWeap ) + if( actor->getId() != m_targetId || !actor->isBattleNpc() ) + continue; + + if( actor->getAsBattleNpc()->isAlive() && mainWeap ) { // default autoattack range // TODO make this dependant on bnpc size @@ -1027,7 +1030,7 @@ void Core::Entity::Player::update( int64_t currTime ) if( ( currTime - m_lastAttack ) > mainWeap->getDelay() ) { m_lastAttack = currTime; - autoAttack( actor ); + autoAttack( actor->getAsBattleNpc() ); } } diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index 865ffdc1..74d9e453 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -113,11 +113,11 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac } else { - auto inRange = player.getInRangeActors(); + auto inRange = player.getInRangeGameObjects(); for( auto actor : inRange ) { if( actor->getId() == param3 ) - targetActor = actor; + targetActor = actor->getAsActor(); } } @@ -138,7 +138,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Race, param1 ); player.sendNotice( "Race for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetPlayer->getInRangeActors(); + auto inRange = targetPlayer->getInRangeGameObjects(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -151,7 +151,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Tribe, param1 ); player.sendNotice( "Tribe for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetPlayer->getInRangeActors(); + auto inRange = targetPlayer->getInRangeGameObjects(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -164,7 +164,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Gender, param1 ); player.sendNotice( "Sex for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetActor->getInRangeActors(); + auto inRange = targetActor->getInRangeGameObjects(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -439,7 +439,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac case GmCommand::Jump: { - auto inRange = player.getInRangeActors(); + auto inRange = player.getInRangeGameObjects(); player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z, targetActor->getRotation() ); diff --git a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp index c6232a22..55488fa5 100644 --- a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp @@ -190,7 +190,7 @@ void Core::Network::GameConnection::updatePositionHandler( const Packets::GamePa player.getCurrentAction()->setInterrupted(); // if no one is in range, don't bother trying to send a position update - if( !player.hasInRangeActor() ) + if( !player.hasInRangeGameObject() ) return; uint8_t unk = inPacket.getValAt< uint8_t >( 0x29 ); diff --git a/src/servers/sapphire_zone/Zone/Zone.cpp b/src/servers/sapphire_zone/Zone/Zone.cpp index c930f3da..e0ecad27 100644 --- a/src/servers/sapphire_zone/Zone/Zone.cpp +++ b/src/servers/sapphire_zone/Zone/Zone.cpp @@ -737,8 +737,8 @@ void Core::Zone::updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell ) if( count > 12 ) break; - pActor->addInRangeActor( pCurAct ); - pCurAct->addInRangeActor( pActor ); + pActor->addInRangeGameObject( pCurAct ); + pCurAct->addInRangeGameObject( pActor ); // spawn the actor for the player pCurAct->spawn( pOwnPlayer ); @@ -758,24 +758,24 @@ void Core::Zone::updateInRangeSet( Entity::ActorPtr pActor, Cell* pCell ) if( pPlayer->isLoadingComplete() ) { pActor->spawn( pPlayer ); - pCurAct->addInRangeActor( pActor ); - pActor->addInRangeActor( pCurAct ); + pCurAct->addInRangeGameObject( pActor ); + pActor->addInRangeGameObject( pCurAct ); } } else { - pActor->addInRangeActor( pCurAct ); - pCurAct->addInRangeActor( pActor ); + pActor->addInRangeGameObject( pCurAct ); + pCurAct->addInRangeGameObject( pActor ); } } else if( !isInRange && isInRangeSet ) { - pCurAct->removeInRangeActor( *pActor ); + pCurAct->removeInRangeGameObject( *pActor ); if( pActor->getCurrentZone() != pCurAct->getCurrentZone() ) continue; - pActor->removeInRangeActor( *pCurAct ); + pActor->removeInRangeGameObject( *pCurAct ); } } }