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:
parent
e794df50ba
commit
3727306613
17 changed files with 139 additions and 23 deletions
|
@ -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;
|
||||
|
|
|
@ -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{};
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ namespace Sapphire::Entity
|
|||
|
||||
enum BNpcFlag
|
||||
{
|
||||
None = 0x00,
|
||||
Immobile = 0x01,
|
||||
TurningDisabled = 0x02,
|
||||
Invincible = 0x04,
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 >();
|
||||
|
|
Loading…
Add table
Reference in a new issue