1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-05 10:17:46 +00:00

Action logic rework #1

statuseffects and autoattack still on the todo list
This commit is contained in:
Mordred 2023-03-10 17:32:52 +01:00
parent 0def7896ec
commit 5d353de158
15 changed files with 89 additions and 142 deletions

View file

@ -86,7 +86,7 @@ bool Action::Action::init()
}
auto teriMgr = Common::Service< Manager::TerritoryMgr >::ref();
auto zone = teriMgr.getTerritoryByGuId( m_pSource->getTerritoryId() );
m_resultId = zone->getNextEffectResultId();
m_resultId = zone->getNextActionResultId();
m_actionResultBuilder = make_ActionResultBuilder( m_pSource, getId(), m_resultId, m_requestId );
@ -461,14 +461,10 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage(
auto role = player->getRole();
if( role == Common::Role::RangedMagical || role == Common::Role::Healer )
{
wepDmg = item->getMagicalDmg();
}
else
{
wepDmg = item->getPhysicalDmg();
}
}
return Math::CalcStats::calcActionDamage( *m_pSource, potency, wepDmg );
}
@ -484,14 +480,10 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing
auto role = player->getRole();
if( role == Common::Role::RangedMagical || role == Common::Role::Healer )
{
wepDmg = item->getMagicalDmg();
}
else
{
wepDmg = item->getPhysicalDmg();
}
}
return Math::CalcStats::calcActionHealing( *m_pSource, potency, wepDmg );
}
@ -562,11 +554,9 @@ void Action::Action::buildActionResults()
}
if( !m_lutEntry.nextCombo.empty() ) // if we have a combo action followup
{
m_actionResultBuilder->startCombo( m_pSource, getId() ); // this is on all targets hit
}
}
}
else if( m_lutEntry.curePotency > 0 )
{
auto heal = calcHealing( m_lutEntry.curePotency );

View file

@ -91,6 +91,9 @@ const Common::CalcResultParam& ActionResult::getCalcResultParam() const
void ActionResult::execute()
{
if( !m_target )
return;
switch( m_result.Type )
{
case Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP:

View file

@ -38,4 +38,6 @@ namespace Sapphire::World::Action
Common::CalcResultParam m_result;
};
using ActionResultList = std::vector< ActionResultPtr >;
}

View file

@ -34,25 +34,12 @@ ActionResultBuilder::ActionResultBuilder( Entity::CharaPtr source, uint32_t acti
}
uint64_t ActionResultBuilder::getResultDelayMs()
{
// todo: actually figure this retarded shit out
return Common::Util::getTimeMs() + 850;
}
void ActionResultBuilder::addResultToActor( Entity::CharaPtr& chara, ActionResultPtr result )
{
auto it = m_actorResultsMap.find( chara->getId() );
auto it = m_actorResultsMap.find( chara );
if( it == m_actorResultsMap.end() )
{
// create a new one
auto resultList = std::vector< ActionResultPtr >();
resultList.push_back( std::move( result ) );
m_actorResultsMap[ chara->getId() ] = resultList;
m_actorResultsMap[ chara ].push_back( std::move( result ) );
return;
}
@ -61,21 +48,21 @@ void ActionResultBuilder::addResultToActor( Entity::CharaPtr& chara, ActionResul
void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag )
{
ActionResultPtr nextResult = make_ActionResult( healingTarget, getResultDelayMs() );
ActionResultPtr nextResult = make_ActionResult( healingTarget, 0 );
nextResult->heal( amount, severity, flag );
addResultToActor( effectTarget, nextResult );
}
void ActionResultBuilder::restoreMP( Entity::CharaPtr& target, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag )
{
ActionResultPtr nextResult = make_ActionResult( restoringTarget, getResultDelayMs() ); // restore mp source actor
ActionResultPtr nextResult = make_ActionResult( restoringTarget, 0 ); // restore mp source actor
nextResult->restoreMP( amount, flag );
addResultToActor( target, nextResult );
}
void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag )
{
ActionResultPtr nextResult = make_ActionResult( damagingTarget, getResultDelayMs() );
ActionResultPtr nextResult = make_ActionResult( damagingTarget, 0 );
nextResult->damage( amount, severity, flag );
addResultToActor( damagingTarget, nextResult );
}
@ -103,7 +90,7 @@ void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t
void ActionResultBuilder::mount( Entity::CharaPtr& target, uint16_t mountId )
{
ActionResultPtr nextResult = make_ActionResult( target, getResultDelayMs() );
ActionResultPtr nextResult = make_ActionResult( target, 0 );
nextResult->mount( mountId );
addResultToActor( target, nextResult );
}
@ -123,106 +110,85 @@ void ActionResultBuilder::sendActionResults( const std::vector< Entity::CharaPtr
std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket( const std::vector< Entity::CharaPtr >& targetList )
{
auto remainingTargetCount = targetList.size();
auto targetCount = targetList.size();
auto& taskMgr = Common::Service< World::Manager::TaskMgr >::ref();
auto& teriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
auto zone = teriMgr.getTerritoryByGuId( m_sourceChara->getTerritoryId() );
if( remainingTargetCount > 1 ) // use AoeEffect packets
if( targetCount == 0 )
{
auto effectPacket = std::make_shared< EffectPacket >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId );
effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
effectPacket->setRequestId( m_requestId );
effectPacket->setResultId( m_resultId );
auto actionResult = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), m_sourceChara->getId(), m_actionId );
actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
actionResult->setRequestId( m_requestId );
actionResult->setResultId( m_resultId );
actionResult->setEffectFlags( Common::ActionEffectDisplayType::HideActionName );
m_actorResultsMap.clear();
return actionResult;
}
else if( targetCount > 1 ) // use AoeEffect packets
{
auto actionResult = std::make_shared< EffectPacket >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId );
actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
actionResult->setRequestId( m_requestId );
actionResult->setResultId( m_resultId );
uint8_t targetIndex = 0;
for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); )
for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it )
{
// get all effect results for an actor
auto actorResultList = it->second;
if( it->first )
taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) );
for( auto& result : actorResultList )
{
auto effect = result->getCalcResultParam();
// if effect result is a source/caster effect
if( result->getTarget() == m_sourceChara )
effectPacket->addSourceEffect( effect );
actionResult->addSourceEffect( effect );
else
{
effectPacket->addTargetEffect( effect, result->getTarget()->getId() );
taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( m_resultId, result->getTarget(), 1000 ) );
actionResult->addTargetEffect( effect, result->getTarget()->getId() );
}
zone->addActionResult( std::move( result ) );
}
actorResultList.clear();
it = m_actorResultsMap.erase( it );
//actorResultList.clear();
//it = m_actorResultsMap.erase( it );
targetIndex++;
if( targetIndex == 15 )
break;
}
return effectPacket;
return actionResult;
}
else if( remainingTargetCount == 1 ) // use Effect for single target
else // use Effect for single target
{
auto actionResult = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId );
actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
actionResult->setRequestId( m_requestId );
actionResult->setResultId( m_resultId );
Logger::debug( " - id: {}", targetList[0]->getId() );
Logger::debug( "------------------------------------------" );
auto effectPacket = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId );
effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
effectPacket->setRequestId( m_requestId );
effectPacket->setResultId( m_resultId );
for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); )
for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it )
{
// get all effect results for an actor
auto actorResultList = it->second;
if( it->first )
taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) );
for( auto& result : actorResultList )
{
auto effect = result->getCalcResultParam();
// if effect result is a source/caster effect
if( result->getTarget() == m_sourceChara )
effectPacket->addSourceEffect( effect );
actionResult->addSourceEffect( effect );
else
{
effectPacket->addTargetEffect( effect );
taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( m_resultId, result->getTarget(), 1000 ) );
actionResult->addTargetEffect( effect );
}
zone->addActionResult( std::move( result ) );
}
actorResultList.clear();
it = m_actorResultsMap.erase( it );
//actorResultList.clear();
//it = m_actorResultsMap.erase( it );
}
m_actorResultsMap.clear();
return effectPacket;
}
else // nothing is hit, this only happens when using aoe and AoeEffect8 is used on retail
{
auto effectPacket = makeZonePacket< FFXIVIpcActionResult1 >( m_sourceChara->getId() );
effectPacket->data().ActionKey = m_actionId;
effectPacket->data().Action = static_cast< uint16_t >( m_actionId );
effectPacket->data().Target = m_sourceChara->getId();
effectPacket->data().MainTarget = static_cast< uint64_t >( m_sourceChara->getId() );
effectPacket->data().DirTarget = Common::Util::floatToUInt16Rot( m_sourceChara->getRot() );
effectPacket->data().Flag = Common::ActionEffectDisplayType::HideActionName;
effectPacket->data().RequestId = m_requestId;
effectPacket->data().ResultId = m_resultId;
m_actorResultsMap.clear();
return effectPacket;
return actionResult;
}
}

View file

@ -34,8 +34,6 @@ namespace Sapphire::World::Action
private:
void addResultToActor( Entity::CharaPtr& chara, ActionResultPtr result );
uint64_t getResultDelayMs();
Network::Packets::FFXIVPacketBasePtr createActionResultPacket( const std::vector< Entity::CharaPtr >& targetList );
private:
@ -44,7 +42,7 @@ namespace Sapphire::World::Action
uint32_t m_resultId;
Entity::CharaPtr m_sourceChara;
std::unordered_map< uint32_t, std::vector< ActionResultPtr > > m_actorResultsMap;
std::unordered_map< Entity::CharaPtr, std::vector< ActionResultPtr > > m_actorResultsMap;
};
}

View file

@ -983,7 +983,7 @@ void BNpc::autoAttack( CharaPtr pTarget )
effectEntry.Type = ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP;
effectEntry.Arg0 = 3;
effectEntry.Arg1 = 7;
auto resultId = pZone->getNextEffectResultId();
auto resultId = pZone->getNextActionResultId();
effectPacket->setResultId( resultId );
effectPacket->addTargetEffect( effectEntry );
server().queueForPlayers( getInRangePlayerIds(), effectPacket );
@ -991,7 +991,7 @@ void BNpc::autoAttack( CharaPtr pTarget )
pTarget->takeDamage( static_cast< uint16_t >( damage.first ) );
auto& taskMgr = Common::Service< World::Manager::TaskMgr >::ref();
taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( resultId, pTarget, 500 ) );
//taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( resultId, pTarget, 500 ) );
}
}

View file

@ -504,7 +504,7 @@ void Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
auto statusEffectAdd = makeZonePacket< FFXIVIpcActionIntegrity >( getId() );
statusEffectAdd->data().ResultId = pZone->getNextEffectResultId();
statusEffectAdd->data().ResultId = pZone->getNextActionResultId();
statusEffectAdd->data().Target = pEffect->getTargetActorId();
statusEffectAdd->data().Hp = getHp();
statusEffectAdd->data().Mp = static_cast< uint16_t >( getMp() );

View file

@ -1311,7 +1311,7 @@ void Player::autoAttack( CharaPtr pTarget )
if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer )
effectPacket->setActionId( 8 );
auto resultId = pZone->getNextEffectResultId();
auto resultId = pZone->getNextActionResultId();
effectPacket->setResultId( resultId );
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
effectPacket->addTargetEffect( entry );
@ -1321,7 +1321,7 @@ void Player::autoAttack( CharaPtr pTarget )
pTarget->takeDamage( static_cast< uint32_t >( damage.first ) );
auto& taskMgr = Common::Service< TaskMgr >::ref();
taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( resultId, pTarget, 500 ) );
//taskMgr.queueTask( Sapphire::World::makeActionIntegrityTask( resultId, pTarget, 500 ) );
}

View file

@ -538,7 +538,7 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr<
entry.Arg0 = static_cast< uint8_t >( Common::ActionHitSeverityType::NormalDamage );
effectPacket->addTargetEffect( entry, static_cast< uint64_t >( player.getId() ) );
effectPacket->setResultId( pCurrentZone->getNextEffectResultId() );
effectPacket->setResultId( pCurrentZone->getNextActionResultId() );
server().queueForPlayer( player.getCharacterId(), effectPacket );
}

View file

@ -9,27 +9,32 @@ using namespace Sapphire::World;
void TaskMgr::update( uint64_t tickCount )
{
for( auto it = m_taskList.begin(); it != m_taskList.end(); )
std::vector< TaskPtr > tmpTaskList;
for( const auto& pTask : m_taskList )
{
auto pTask = *it;
// is the task ready for execution?
if( ( tickCount - pTask->getQueueTimeMs() ) >= pTask->getDelayTimeMs() )
{
Logger::info( "[TaskMgr] " + pTask->toString() );
pTask->execute();
it = m_taskList.erase( it );
}
else
++it;
tmpTaskList.push_back( pTask );
}
m_taskList = tmpTaskList;
m_lastTick = tickCount;
while( !m_deferredTasks.empty() )
{
auto pTask = m_deferredTasks.front();
m_deferredTasks.pop();
m_taskList.push_back( pTask );
}
}
void TaskMgr::queueTask( const TaskPtr& pTask )
{
pTask->onQueue();
m_taskList.push_back( pTask );
m_deferredTasks.push( pTask );
}

View file

@ -2,6 +2,7 @@
#include <cstdint>
#include <string>
#include <queue>
#include <ForwardsZone.h>
#include <Util/Util.h>
@ -45,6 +46,7 @@ namespace Sapphire::World::Manager
private:
uint64_t m_lastTick{};
std::vector< TaskPtr > m_taskList;
std::queue< TaskPtr > m_deferredTasks;
};

View file

@ -14,10 +14,12 @@ using namespace Sapphire::World::Manager;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::WorldPackets::Server;
ActionIntegrityTask::ActionIntegrityTask( uint32_t resultId, Entity::CharaPtr pTarget, uint64_t delayTime ) : Task( delayTime )
ActionIntegrityTask::ActionIntegrityTask( uint32_t resultId, Entity::CharaPtr pTarget, Action::ActionResultList& results, uint64_t delayTime ) : Task( delayTime )
{
Logger::debug( "Constructor called {} {} {}", resultId, pTarget->getId(), results.size() );
m_resultId = resultId;
m_pTarget = std::move( pTarget );
m_results = results;
}
void ActionIntegrityTask::onQueue()
@ -27,6 +29,9 @@ void ActionIntegrityTask::onQueue()
void ActionIntegrityTask::execute()
{
if( !m_pTarget )
return;
auto& server = Common::Service< WorldServer >::ref();
auto inRangePlayers = m_pTarget->getInRangePlayerIds( true );
@ -34,6 +39,12 @@ void ActionIntegrityTask::execute()
if( inRangePlayers.empty() )
return;
for( auto& actionResult : m_results )
{
if( actionResult && actionResult->getTarget() && actionResult->getTarget()->isAlive() )
actionResult->execute();
}
auto integrityPacket = makeZonePacket< FFXIVIpcActionIntegrity >( 0 );
auto& data = integrityPacket->data();
integrityPacket->setSourceActor( m_pTarget->getId() );
@ -51,7 +62,7 @@ void ActionIntegrityTask::execute()
std::string ActionIntegrityTask::toString()
{
return fmt::format( "ActionIntegrityTask: ResultId#{}, TargetId#{}, ElapsedTimeMs: {}", m_resultId, m_pTarget->getId(), getDelayTimeMs() );
return fmt::format( "ActionIntegrityTask: ResultId#{}, TargetId#{}, ElapsedTimeMs: {}", m_resultId, m_pTarget ? m_pTarget->getId() : 0, getDelayTimeMs() );
}

View file

@ -4,6 +4,7 @@
#include <string>
#include <ForwardsZone.h>
#include "Task.h"
#include <Action/ActionResult.h>
namespace Sapphire::World
{
@ -11,7 +12,7 @@ namespace Sapphire::World
class ActionIntegrityTask : public Task
{
public:
ActionIntegrityTask( uint32_t resultId, Entity::CharaPtr pTarget, uint64_t delayTime );
ActionIntegrityTask( uint32_t resultId, Entity::CharaPtr pTarget, Action::ActionResultList& results, uint64_t delayTime );
void onQueue() override;
void execute() override;
@ -20,6 +21,7 @@ public:
private:
uint32_t m_resultId;
Entity::CharaPtr m_pTarget;
Action::ActionResultList m_results;
};
template< typename... Args >

View file

@ -466,8 +466,6 @@ bool Territory::update( uint64_t tickCount )
updateSessions( tickCount, changedWeather );
onUpdate( tickCount );
processActionResults( tickCount );
if( !m_playerMap.empty() )
m_lastActivityTime = tickCount;
@ -824,7 +822,7 @@ void Territory::updateSpawnPoints()
}
}
uint32_t Territory::getNextEffectResultId()
uint32_t Territory::getNextActionResultId()
{
return m_effectCounter++;
}
@ -875,30 +873,6 @@ std::shared_ptr< World::Navi::NaviProvider > Territory::getNaviProvider()
return m_pNaviProvider;
}
void Territory::addActionResult( World::Action::ActionResultPtr result )
{
m_actionResults.emplace_back( std::move( result ) );
}
void Territory::processActionResults( uint64_t tickCount )
{
// todo: move this to generic territory/instance delay wrapper cause it might be useful scheduling other things
for( auto it = m_actionResults.begin(); it != m_actionResults.end(); )
{
auto effect = *it;
if( tickCount < effect->getDelay() )
{
++it;
continue;
}
effect->execute();
it = m_actionResults.erase( it );
}
}
bool Territory::loadBNpcs()
{
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();

View file

@ -72,8 +72,6 @@ namespace Sapphire
uint32_t m_effectCounter{};
std::shared_ptr< World::Navi::NaviProvider > m_pNaviProvider;
std::vector< World::Action::ActionResultPtr > m_actionResults;
Common::TerritoryIdent m_ident;
float m_inRangeDistance;
@ -194,13 +192,9 @@ namespace Sapphire
void updateSpawnPoints();
uint32_t getNextEffectResultId();
uint32_t getNextActionResultId();
std::shared_ptr< World::Navi::NaviProvider > getNaviProvider();
void addActionResult( World::Action::ActionResultPtr result );
void processActionResults( uint64_t tickCount );
};
}