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

add chara dirty flag, move bnpc position updates to tick

- add knockback
- use pos set in action rather than always using source actor
This commit is contained in:
Tahir 2024-06-25 17:41:14 +01:00
parent e794df50ba
commit 3727306613
17 changed files with 139 additions and 23 deletions

View file

@ -1885,6 +1885,7 @@ namespace Sapphire::Common
using PlayerStateFlagList = std::vector< PlayerCondition >;
// todo: load BNpcBase and other exd data into this struct
struct BNPCInstanceObject
{
uint16_t territoryType;

View file

@ -99,6 +99,20 @@ FFXIVARR_POSITION3 Util::getOffsettedPosition( const FFXIVARR_POSITION3& pos, fl
return ret;
}
FFXIVARR_POSITION3 Util::getKnockbackPosition( const FFXIVARR_POSITION3& origin, const FFXIVARR_POSITION3& pos, float distance )
{
FFXIVARR_POSITION3 ret{ pos };
float from = Common::Util::calcAngFrom( origin.x, origin.z, pos.x, pos.z );
float angle = PI - from + ( PI / 2 );
angle = angle + ( PI / 2 );
ret.x -= distance * cos( angle );
ret.z += distance * sin( angle );
return ret;
}
FFXIVARR_POSITION3 Util::transform( const FFXIVARR_POSITION3& vector, const Matrix33& matrix )
{
FFXIVARR_POSITION3 dst{};

View file

@ -31,6 +31,8 @@ namespace Sapphire::Common::Util
FFXIVARR_POSITION3 getOffsettedPosition( const FFXIVARR_POSITION3& pos, float rotation, float right, float up, float forward );
FFXIVARR_POSITION3 getKnockbackPosition( const FFXIVARR_POSITION3& origin, const FFXIVARR_POSITION3& pos, float distance );
template < typename T >
T clamp( T val, T minimum, T maximum )
{

View file

@ -48,19 +48,19 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
bnpc.moveTo( *pHatedActor );
}
if( pNaviProvider->syncPosToChara( bnpc ) )
bnpc.sendPositionUpdate();
pNaviProvider->syncPosToChara( bnpc );
if( distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) )
if( distance < ( bnpc.getNaviTargetReachedDistance() + bnpc.getRadius() + pHatedActor->getRadius() ) )
{
if( !bnpc.hasFlag( Entity::TurningDisabled ) && bnpc.face( pHatedActor->getPos() ) )
bnpc.sendPositionUpdate();
if( !bnpc.hasFlag( Entity::TurningDisabled ) )
bnpc.face( pHatedActor->getPos() );
if( !bnpc.checkAction() )
bnpc.processGambits( tickCount );
// in combat range. ATTACK!
bnpc.autoAttack( pHatedActor );
if( !bnpc.hasFlag( Entity::BNpcFlag::AutoAttackDisabled ) )
bnpc.autoAttack( pHatedActor );
}
}

View file

@ -181,6 +181,16 @@ const Common::FFXIVARR_POSITION3& Action::Action::getPos() const
return m_pos;
}
void Action::Action::setRot( float rot )
{
m_rot = rot;
}
float Action::Action::getRot() const
{
return m_rot;
}
void Action::Action::setTargetId( uint64_t targetId )
{
m_targetId = targetId;
@ -327,10 +337,10 @@ void Action::Action::start()
data.CastTime = static_cast< float >( m_castTimeMs ) / 1000.f;
data.Target = static_cast< uint32_t >( m_targetId );
data.TargetPos[ 0 ] = Common::Util::floatToUInt16( m_pSource->getPos().x );
data.TargetPos[ 1 ] = Common::Util::floatToUInt16( m_pSource->getPos().y );
data.TargetPos[ 2 ] = Common::Util::floatToUInt16( m_pSource->getPos().z );
data.Dir = m_pSource->getRot();
data.TargetPos[ 0 ] = Common::Util::floatToUInt16( m_pos.x );
data.TargetPos[ 1 ] = Common::Util::floatToUInt16( m_pos.y );
data.TargetPos[ 2 ] = Common::Util::floatToUInt16( m_pos.z );
data.Dir = m_rot;
server().queueForPlayers( m_pSource->getInRangePlayerIds( m_pSource->isPlayer() ), castPacket );

View file

@ -30,6 +30,9 @@ namespace Sapphire::World::Action
void setPos( const Common::FFXIVARR_POSITION3& pos );
const Common::FFXIVARR_POSITION3& getPos() const;
void setRot( float rot );
float getRot() const;
void setTargetId( uint64_t targetId );
uint64_t getTargetId() const;
Entity::CharaPtr getSourceChara() const;
@ -220,6 +223,7 @@ namespace Sapphire::World::Action
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > m_actionData;
Common::FFXIVARR_POSITION3 m_pos{};
float m_rot{};
ActionResultBuilderPtr m_actionResultBuilder;

View file

@ -377,7 +377,6 @@ bool BNpc::moveTo( const FFXIVARR_POSITION3& pos )
// Reached destination
face( pos );
setPos( pos1 );
sendPositionUpdate();
pNaviProvider->updateAgentPosition( *this );
return true;
}
@ -389,7 +388,6 @@ bool BNpc::moveTo( const FFXIVARR_POSITION3& pos )
else
face( pos );
setPos( pos1 );
sendPositionUpdate();
return false;
}
@ -415,7 +413,6 @@ bool BNpc::moveTo( const Chara& targetChara )
// Reached destination
face( targetChara.getPos() );
setPos( pos1 );
sendPositionUpdate();
pNaviProvider->resetMoveTarget( *this );
pNaviProvider->updateAgentPosition( *this );
return true;
@ -427,7 +424,6 @@ bool BNpc::moveTo( const Chara& targetChara )
else
face( targetChara.getPos() );
setPos( pos1 );
sendPositionUpdate();
return false;
}
@ -659,6 +655,10 @@ void BNpc::onTick()
void BNpc::update( uint64_t tickCount )
{
Chara::update( tickCount );
if( m_dirtyFlag & DirtyFlag::Position )
sendPositionUpdate();
m_fsm->update( *this, tickCount );
}

View file

@ -32,7 +32,6 @@ namespace Sapphire::Entity
enum BNpcFlag
{
None = 0x00,
Immobile = 0x01,
TurningDisabled = 0x02,
Invincible = 0x04,

View file

@ -14,6 +14,8 @@
#include "Network/PacketWrappers/ActorControlTargetPacket.h"
#include "Network/PacketWrappers/EffectPacket1.h"
#include "Network/PacketWrappers/HudParamPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/Util/PacketUtil.h"
#include "Action/Action.h"
@ -25,6 +27,7 @@
#include "Manager/TerritoryMgr.h"
#include "Manager/MgrUtil.h"
#include "Manager/PlayerMgr.h"
#include "Navi/NaviProvider.h"
#include "Common.h"
using namespace Sapphire;
@ -199,6 +202,24 @@ bool Chara::isAlive() const
return ( m_hp > 0 );
}
void Chara::setPos( const Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate )
{
GameObject::setPos( pos, broadcastUpdate );
m_dirtyFlag |= DirtyFlag::Position;
}
void Chara::setPos( float x, float y, float z, bool broadcastUpdate )
{
GameObject::setPos( x, y, z, broadcastUpdate );
m_dirtyFlag |= DirtyFlag::Position;
}
void Sapphire::Entity::Chara::setRot( float rot )
{
GameObject::setRot( rot );
m_dirtyFlag |= DirtyFlag::Position;
}
/*! \return max hp for the actor */
uint32_t Chara::getMaxHp() const
{
@ -857,3 +878,38 @@ void Chara::onTick()
Network::Util::Packet::sendHudParam( *this );
}
}
void Chara::knockback( const FFXIVARR_POSITION3& origin, float distance, bool ignoreNav )
{
auto kbPos = Common::Util::getKnockbackPosition( origin, m_pos, distance );
auto& teriMgr = Common::Service< Manager::TerritoryMgr >::ref();
auto pTeri = teriMgr.getTerritoryByGuId( getTerritoryId() );
if( !ignoreNav )
{
// todo: use agent
auto pNav = pTeri->getNaviProvider();
auto path = pNav->findFollowPath( m_pos, kbPos );
FFXIVARR_POSITION3 navPos{origin};
float prevDistance{1000.f};
for( const auto& point : path )
{
auto navDist = Common::Util::distance( kbPos, point );
if( navDist < prevDistance )
{
navPos = point;
prevDistance = navDist;
}
}
setPos( navPos );
pNav->updateAgentPosition( *this );
}
else
{
setPos( kbPos );
}
pTeri->updateActorPosition( *this );
server().queueForPlayers( getInRangePlayerIds(), std::make_shared< MoveActorPacket >( *this, getRot(), 2, 0, 0, 0x5A / 4 ) );
}

View file

@ -13,6 +13,14 @@
namespace Sapphire::Entity
{
// todo: probably macro/template operators for enums
enum DirtyFlag : uint32_t
{
Position = 0x01,
HpMpTp = 0x02,
Status = 0x04,
Appearance = 0x08
};
/*!
\class Chara
@ -96,6 +104,8 @@ namespace Sapphire::Entity
/*! Detour Crowd actor scale */
float m_radius;
uint32_t m_dirtyFlag{};
public:
Chara( Common::ObjKind type );
@ -195,6 +205,12 @@ namespace Sapphire::Entity
bool isAlive() const;
virtual void setPos( const Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate = true ) override;
virtual void setPos( float x, float y, float z, bool broadcastUpdate = true ) override;
virtual void setRot( float rot ) override;
virtual uint32_t getMaxHp() const;
virtual uint32_t getMaxMp() const;
@ -266,6 +282,8 @@ namespace Sapphire::Entity
Common::BaseParam getPrimaryStat() const;
void knockback( const Common::FFXIVARR_POSITION3& origin, float distance, bool ignoreNav = false );
};
}

View file

@ -10,7 +10,6 @@
namespace Sapphire::Entity
{
/*!
\class GameObject
\brief Base class for all actor/objects
@ -59,13 +58,13 @@ namespace Sapphire::Entity
Common::FFXIVARR_POSITION3& getPos();
const Common::FFXIVARR_POSITION3& getPos() const;
void setPos( const Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate = true );
virtual void setPos( const Common::FFXIVARR_POSITION3& pos, bool broadcastUpdate = true );
void setPos( float x, float y, float z, bool broadcastUpdate = true );
virtual void setPos( float x, float y, float z, bool broadcastUpdate = true );
float getRot() const;
void setRot( float rot );
virtual void setRot( float rot );
bool isChara() const;

View file

@ -61,7 +61,6 @@ namespace Sapphire
auto pIfrit = pEncounter->getBNpc( NPC_IFRIT );
pIfrit->setRot( pIfrit->getRot() + .2f );
pIfrit->sendPositionUpdate();
// todo: use gambits+timelines for this
if( timeElapsedMs > 10000 )
@ -100,7 +99,6 @@ namespace Sapphire
auto pIfrit = pEncounter->getBNpc( NPC_IFRIT );
pIfrit->setRot( pIfrit->getRot() - .2f );
pIfrit->sendPositionUpdate();
// todo: use gambits+timelines for this
if( timeElapsedMs > 5000 )

View file

@ -423,6 +423,7 @@ namespace Sapphire::Encounter
{
pAction->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
pAction->interrupt();
pBNpc->setCurrentAction( nullptr );
return false;
}
else
@ -441,7 +442,6 @@ namespace Sapphire::Encounter
{
pBNpc->setRot( pSetPosData->m_rot );
pBNpc->setPos( pSetPosData->m_x, pSetPosData->m_y, pSetPosData->m_z, true );
pBNpc->sendPositionUpdate();
}
}
break;

View file

@ -560,7 +560,7 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr<
Entity::GameObjectPtr pTarget = nullptr;
auto inRange = player.getInRangeActors();
for( auto pChara : inRange )
for( auto& pChara : inRange )
{
if( pChara->getId() == targetId )
{
@ -583,6 +583,17 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr<
server().queueForPlayer( player.getCharacterId(), actorMovePacket );
}
}
else if( subCommand == "knockback" )
{
float distance{ 0.f };
sscanf( params.c_str(), "%f", &distance );
for( auto& pActor : player.getInRangeActors() )
{
if( auto pBNpc = pActor->getAsBNpc(); pBNpc && Common::Util::distance( pBNpc->getPos(), player.getPos() ) <= distance )
pBNpc->knockback( player.getPos(), distance );
}
}
else if( subCommand == "achvGeneral" )
{
uint32_t achvSubtype;

View file

@ -355,6 +355,7 @@ std::vector< Sapphire::Common::FFXIVARR_POSITION3 >
// iterPos[ 0 ], iterPos[ 1 ], iterPos[ 2 ],
// targetPos[ 0 ], targetPos[ 1 ], targetPos[ 2 ] );
// todo: adjust these for the actor radius
const float STEP_SIZE = 0.5f;
const float SLOP = 0.15f;

View file

@ -243,6 +243,7 @@ void Sapphire::Network::GameConnection::moveHandler( const Packets::FFXIVARR_PAC
if( !player.hasInRangeActor() )
return;
// todo: probably move this into a builder and send the packet on Player::update if( m_dirtyFlags & DirtyFlag::Position )
//auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, animationType, animationState, animationSpeed, unknownRotation );
auto movePacket = std::make_shared< MoveActorPacket >( player, headRotation, data.flag, data.flag2, animationSpeed, unknownRotation );
server().queueForPlayers( player.getInRangePlayerIds(), movePacket );

View file

@ -895,6 +895,8 @@ bool Territory::loadBNpcs()
stmt->setUInt( 1, getTerritoryTypeId() );
auto res = db.query( stmt );
// todo: load any exd links, cache them, build more info and setup bnpcs properly
while( res->next() )
{
auto bnpc = std::make_shared< Common::BNPCInstanceObject >();