1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-25 02:57:45 +00:00

Merge branch 'master' of https://github.com/SapphireMordred/Sapphire into party_crap

This commit is contained in:
Maru 2017-12-07 11:22:09 -02:00
commit 899f0fa272
22 changed files with 424 additions and 395 deletions

View file

@ -22,7 +22,7 @@ When making a PR, please make sure that it follows our style guidelines and good
### Coding style ### Coding style
Indentations are Allman-style based, 4-space, no tabs. Indentations are Allman-style based, 3-space, no tabs.
Space between arguments in function calls, as well as for types. Space between arguments in function calls, as well as for types.
Example (shortened from ActionHandler.cpp): Example (shortened from ActionHandler.cpp):
@ -30,30 +30,30 @@ Example (shortened from ActionHandler.cpp):
```cpp ```cpp
switch( commandId ) switch( commandId )
{ {
case 0x01: // Toggle sheathe case 0x01: // Toggle sheathe
{ {
if ( param11 == 1 ) if ( param11 == 1 )
pPlayer->setStance( Entity::Actor::Stance::Active ); pPlayer->setStance( Entity::Actor::Stance::Active );
else else
{ {
pPlayer->setStance( Entity::Actor::Stance::Passive ); pPlayer->setStance( Entity::Actor::Stance::Passive );
pPlayer->setAutoattack( false ); pPlayer->setAutoattack( false );
} }
pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) ); pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) );
break; break;
} }
case 0x03: // Change target case 0x03: // Change target
{ {
uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 ); uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
pPlayer->changeTarget( targetId ); pPlayer->changeTarget( targetId );
break; break;
} }
default: default:
{ {
break; break;
} }
} }
``` ```

View file

@ -3,15 +3,16 @@
<!-- Port the lobby server accepts client connections on --> <!-- Port the lobby server accepts client connections on -->
<ListenPort>54994</ListenPort> <ListenPort>54994</ListenPort>
<AuthPort>54998</AuthPort> <AuthPort>54998</AuthPort>
<!-- Ip the lobby server listens on --> <!-- Ip the lobby server listens on -->
<ListenIp>127.0.0.1</ListenIp> <ListenIp>127.0.0.1</ListenIp>
<!-- Path of FFXIV dat files --> <!-- Path of FFXIV dat files -->
<DataPath>C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv</DataPath> <DataPath>C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv</DataPath>
<!-- <DataPath>/opt/sapphire_3_15_0/bin/sqpack</DataPath> -->
<!-- IP of the lobby server --> <!-- IP of the lobby server -->
<LobbyHost>127.0.0.1</LobbyHost> <LobbyHost>127.0.0.1</LobbyHost>
<!-- IP of the frontier server --> <!-- IP of the frontier server -->
<FrontierHost>127.0.0.1</FrontierHost> <FrontierHost>127.0.0.1</FrontierHost>
<!-- Secret used for server auth - you *must* change this for public servers --> <!-- Secret used for server auth - you *must* change this for public servers -->
<ServerSecret>default</ServerSecret> <ServerSecret>default</ServerSecret>
<!-- Web server port --> <!-- Web server port -->
<HttpPort>80</HttpPort> <HttpPort>80</HttpPort>

View file

@ -855,7 +855,7 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t unknown; uint32_t unknown;
uint32_t unknown_1; uint32_t unknown_1;
uint32_t unknown_2; uint32_t unknown_2;
uint32_t parry; uint32_t tenacity;
uint32_t attack; uint32_t attack;
uint32_t defense; uint32_t defense;
uint32_t accuracy; uint32_t accuracy;
@ -877,7 +877,11 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t skillSpeed; uint32_t skillSpeed;
uint32_t spellSpeed1; uint32_t spellSpeed1;
uint32_t spellSpeedMod; uint32_t spellSpeedMod;
uint32_t unknown_6[5]; uint32_t unknown_6;
uint32_t craftsmanship;
uint32_t control;
uint32_t gathering;
uint32_t perception;
uint32_t resistanceSlow; uint32_t resistanceSlow;
uint32_t resistanceSilence; uint32_t resistanceSilence;
uint32_t resistanceBlind; uint32_t resistanceBlind;
@ -886,7 +890,7 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t resistanceSleep; uint32_t resistanceSleep;
uint32_t resistanceBind; uint32_t resistanceBind;
uint32_t resistanceHeavy; uint32_t resistanceHeavy;
uint32_t unknown_7[9]; uint32_t unknown_7[9]; // possibly level sync stats.
}; };
/** /**
@ -921,10 +925,11 @@ struct FFXIVIpcPlayerStateFlags : FFXIVIpcBasePacket<PlayerStateFlags>
struct FFXIVIpcPlayerClassInfo : FFXIVIpcBasePacket<PlayerClassInfo> struct FFXIVIpcPlayerClassInfo : FFXIVIpcBasePacket<PlayerClassInfo>
{ {
uint16_t classId; uint16_t classId;
uint16_t unknown; uint8_t unknown;
uint16_t level; uint8_t isSpecialist;
uint16_t level1; uint16_t level; // Locks actions, equipment, prob more
uint8_t unknownFields[48]; uint16_t level1; // Locks roles, prob more
uint32_t roleActions[10];
}; };
/** /**

View file

@ -200,7 +200,7 @@ void Core::Network::SapphireAPI::deleteCharacter( std::string name, uint32_t acc
g_charaDb.execute( "DELETE FROM charaitemcrystal WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaitemcrystal WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaiteminventory WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaiteminventory WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaitemgearset WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaitemgearset WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaquest WHERE CharacterId LIKE '" + std::to_string( id ) + "';" ); g_charaDb.execute( "DELETE FROM charaquestnew WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
} }
std::vector< Core::PlayerMinimal > Core::Network::SapphireAPI::getCharList( uint32_t accountId ) std::vector< Core::PlayerMinimal > Core::Network::SapphireAPI::getCharList( uint32_t accountId )

View file

@ -15,7 +15,6 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket144.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket144.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/UpdateHpMpTpPacket.h" #include "src/servers/Server_Zone/Network/PacketWrappers/UpdateHpMpTpPacket.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h" #include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
#include "src/servers/Server_Zone/Action/ActionCollision.h" #include "src/servers/Server_Zone/Action/ActionCollision.h"
#include "src/servers/Server_Zone/ServerZone.h" #include "src/servers/Server_Zone/ServerZone.h"
@ -33,6 +32,11 @@ using namespace Core::Network::Packets::Server;
Core::Entity::Actor::Actor() Core::Entity::Actor::Actor()
{ {
// initialize the free slot queue
for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ )
{
m_statusEffectFreeSlotQueue.push( i );
}
} }
Core::Entity::Actor::~Actor() Core::Entity::Actor::~Actor()
@ -794,7 +798,30 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint16_t actionId, u
/*! \param StatusEffectPtr to be applied to the actor */ /*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect ) void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
{ {
m_pStatusEffectContainer->addStatusEffect( pEffect ); int8_t nextSlot = getStatusEffectFreeSlot();
// if there is no slot left, do not add the effect
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_statusEffectMap[nextSlot] = pEffect;
ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( getId() );
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
statusEffectAdd.data().current_hp = getHp();
statusEffectAdd.data().current_mp = getMp();
statusEffectAdd.data().current_tp = getTp();
statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000;
statusEffectAdd.data().effect_id = pEffect->getId();
statusEffectAdd.data().effect_index = nextSlot;
statusEffectAdd.data().max_hp = getMaxHp();
statusEffectAdd.data().max_mp = getMaxMp();
statusEffectAdd.data().max_something = 1;
//statusEffectAdd.data().unknown2 = 28;
statusEffectAdd.data().param = pEffect->getParam();
sendToInRangeSet( statusEffectAdd, isPlayer() );
} }
/*! \param StatusEffectPtr to be applied to the actor */ /*! \param StatusEffectPtr to be applied to the actor */
@ -809,7 +836,7 @@ void Core::Entity::Actor::addStatusEffectById( uint32_t id, int32_t duration, En
/*! \param StatusEffectPtr to be applied to the actor */ /*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param ) void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param )
{ {
if( !m_pStatusEffectContainer->hasStatusEffect( id ) ) if( !hasStatusEffect( id ) )
{ {
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(), StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(),
shared_from_this(), duration, 3000 ) ); shared_from_this(), duration, 3000 ) );
@ -818,17 +845,6 @@ void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t du
} }
} }
/*! \param Status that should be removed, based on its ID. */
void Core::Entity::Actor::removeSingleStatusEffectFromId( uint32_t id )
{
m_pStatusEffectContainer->removeSingleStatusEffectFromId( id );
}
Core::StatusEffect::StatusEffectContainerPtr Core::Entity::Actor::getStatusEffectContainer() const
{
return m_pStatusEffectContainer;
}
float Core::Entity::Actor::getRotation() const float Core::Entity::Actor::getRotation() const
{ {
return m_rot; return m_rot;
@ -838,3 +854,154 @@ void Core::Entity::Actor::setRotation( float rot )
{ {
m_rot = rot; m_rot = rot;
} }
int8_t Core::Entity::Actor::getStatusEffectFreeSlot()
{
int8_t freeEffectSlot = -1;
if( m_statusEffectFreeSlotQueue.empty() )
return freeEffectSlot;
freeEffectSlot = m_statusEffectFreeSlotQueue.front();
m_statusEffectFreeSlotQueue.pop();
return freeEffectSlot;
}
void Core::Entity::Actor::statusEffectFreeSlot( uint8_t slotId )
{
m_statusEffectFreeSlotQueue.push( slotId );
}
void Core::Entity::Actor::removeSingleStatusEffectById( uint32_t id )
{
for( auto effectIt : m_statusEffectMap )
{
if( effectIt.second->getId() == id )
{
removeStatusEffect( effectIt.first );
break;
}
}
}
void Core::Entity::Actor::removeStatusEffect( uint8_t effectSlotId )
{
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
if( pEffectIt == m_statusEffectMap.end() )
return;
statusEffectFreeSlot( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
sendToInRangeSet( ActorControlPacket142( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
m_statusEffectMap.erase( effectSlotId );
sendStatusEffectUpdate();
}
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::Entity::Actor::getStatusEffectMap() const
{
return m_statusEffectMap;
}
void Core::Entity::Actor::sendStatusEffectUpdate()
{
uint64_t currentTimeMs = Util::getTimeMs();
ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( getId() );
statusEffectList.data().current_hp = getHp();
statusEffectList.data().current_mp = getMp();
statusEffectList.data().currentTp = getTp();
statusEffectList.data().max_hp = getMaxHp();
statusEffectList.data().max_mp = getMaxMp();
uint8_t slot = 0;
for( auto effectIt : m_statusEffectMap )
{
float timeLeft = static_cast< float >( effectIt.second->getDuration() -
( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
statusEffectList.data().effect[slot].duration = timeLeft;
statusEffectList.data().effect[slot].effect_id = effectIt.second->getId();
statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId();
slot++;
}
sendToInRangeSet( statusEffectList, isPlayer() );
}
void Core::Entity::Actor::updateStatusEffects()
{
uint64_t currentTimeMs = Util::getTimeMs();
uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0;
for( auto effectIt : m_statusEffectMap )
{
uint8_t effectIndex = effectIt.first;
auto effect = effectIt.second;
uint64_t lastTick = effect->getLastTickMs();
uint64_t startTime = effect->getStartTimeMs();
uint32_t duration = effect->getDuration();
uint32_t tickRate = effect->getTickRate();
if( ( currentTimeMs - startTime ) > duration )
{
// remove status effect
removeStatusEffect( effectIndex );
// break because removing invalidates iterators
break;
}
if( ( currentTimeMs - lastTick ) > tickRate )
{
effect->setLastTick( currentTimeMs );
effect->onTick();
auto thisEffect = effect->getTickEffect();
switch( thisEffect.first )
{
case 1:
{
thisTickDmg += thisEffect.second;
break;
}
case 2:
{
thisTickHeal += thisEffect.second;
break;
}
}
}
}
if( thisTickDmg != 0 )
{
takeDamage( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
heal( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
bool Core::Entity::Actor::hasStatusEffect( uint32_t id )
{
if( m_statusEffectMap.find( id ) != m_statusEffectMap.end() )
return true;
return false;
}

View file

@ -7,6 +7,7 @@
#include "src/servers/Server_Zone/Forwards.h" #include "src/servers/Server_Zone/Forwards.h"
#include <set> #include <set>
#include <map> #include <map>
#include <queue>
namespace Core { namespace Core {
namespace Entity { namespace Entity {
@ -79,7 +80,7 @@ public:
uint32_t mnd = 0; uint32_t mnd = 0;
uint32_t pie = 0; uint32_t pie = 0;
uint32_t parry = 0; uint32_t tenacity = 0;
uint32_t attack = 0; uint32_t attack = 0;
uint32_t defense = 0; uint32_t defense = 0;
uint32_t accuracy = 0; uint32_t accuracy = 0;
@ -160,11 +161,15 @@ protected:
uint64_t m_targetId; uint64_t m_targetId;
/*! Ptr to a queued action */ /*! Ptr to a queued action */
Action::ActionPtr m_pCurrentAction; Action::ActionPtr m_pCurrentAction;
/*! Container for status effects */
StatusEffect::StatusEffectContainerPtr m_pStatusEffectContainer;
/*! Invincibility type */ /*! Invincibility type */
Common::InvincibilityType m_invincibilityType; Common::InvincibilityType m_invincibilityType;
/*! Status effects */
const uint8_t MAX_STATUS_EFFECTS = 30;
std::queue< uint8_t > m_statusEffectFreeSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList;
std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap;
public: public:
Actor(); Actor();
@ -174,6 +179,30 @@ public:
uint32_t getId() const; uint32_t getId() const;
/// Status effect functions
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectById( uint32_t id );
void updateStatusEffects();
bool hasStatusEffect( uint32_t id );
int8_t getStatusEffectFreeSlot();
void statusEffectFreeSlot( uint8_t slotId );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
void sendStatusEffectUpdate();
// add a status effect by id
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// add a status effect by id if it doesn't exist
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
/// End Status Effect Functions
void setPosition( const Common::FFXIVARR_POSITION3& pos ); void setPosition( const Common::FFXIVARR_POSITION3& pos );
void setPosition( float x, float y, float z ); void setPosition( float x, float y, float z );
@ -303,20 +332,6 @@ public:
// set the current cell // set the current cell
void setCell( Cell* pCell ); void setCell( Cell* pCell );
// add a status effect
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
// add a status effect by id
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// add a status effect by id if it doesn't exist
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
//get the status effect container
StatusEffect::StatusEffectContainerPtr getStatusEffectContainer() const;
// TODO: Why did i even declare them publicly here?! // TODO: Why did i even declare them publicly here?!
std::set< ActorPtr > m_inRangeActors; std::set< ActorPtr > m_inRangeActors;

View file

@ -15,7 +15,6 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/MoveActorPacket.h" #include "src/servers/Server_Zone/Network/PacketWrappers/MoveActorPacket.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
using namespace Core::Common; using namespace Core::Common;
using namespace Core::Network::Packets; using namespace Core::Network::Packets;
@ -40,7 +39,7 @@ Core::Entity::BattleNpc::~BattleNpc()
Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos, Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos,
uint16_t bnpcBaseId, uint32_t type, uint8_t level, uint8_t behaviour, uint16_t bnpcBaseId, uint32_t type, uint8_t level, uint8_t behaviour,
uint32_t mobType ) uint32_t mobType ) : Actor()
{ {
BattleNpc::m_nextID++; BattleNpc::m_nextID++;
m_id = BattleNpc::m_nextID; m_id = BattleNpc::m_nextID;
@ -87,11 +86,6 @@ Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Com
} }
void Core::Entity::BattleNpc::initStatusEffectContainer()
{
m_pStatusEffectContainer = StatusEffect::StatusEffectContainerPtr( new StatusEffect::StatusEffectContainer( shared_from_this() ) );
}
// spawn this player for pTarget // spawn this player for pTarget
void Core::Entity::BattleNpc::spawn( Core::Entity::PlayerPtr pTarget ) void Core::Entity::BattleNpc::spawn( Core::Entity::PlayerPtr pTarget )
{ {
@ -487,9 +481,7 @@ void Core::Entity::BattleNpc::update( int64_t currTime )
return; return;
} }
if ( !m_pStatusEffectContainer ) updateStatusEffects();
initStatusEffectContainer();
m_pStatusEffectContainer->update();
float distance = Math::Util::distance( m_pos.x, m_pos.y, m_pos.z, float distance = Math::Util::distance( m_pos.x, m_pos.y, m_pos.z,
m_posOrigin.x, m_posOrigin.y, m_posOrigin.z ); m_posOrigin.x, m_posOrigin.y, m_posOrigin.z );

View file

@ -31,8 +31,6 @@
#include "src/servers/Server_Zone/Script/ScriptManager.h" #include "src/servers/Server_Zone/Script/ScriptManager.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/Inventory/Item.h" #include "src/servers/Server_Zone/Inventory/Item.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h" #include "src/servers/Server_Zone/Inventory/Inventory.h"
@ -57,6 +55,7 @@ using namespace Core::Network::Packets::Server;
// player constructor // player constructor
Core::Entity::Player::Player() : Core::Entity::Player::Player() :
Actor(),
m_lastWrite( 0 ), m_lastWrite( 0 ),
m_lastPing( 0 ), m_lastPing( 0 ),
m_bIsLogin( false ), m_bIsLogin( false ),
@ -237,12 +236,13 @@ void Core::Entity::Player::calculateStats()
m_baseStats.mnd = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_mnd ) / 100 ) + tribeInfo.mod_mnd ); m_baseStats.mnd = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_mnd ) / 100 ) + tribeInfo.mod_mnd );
m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_pie ) / 100 ) + tribeInfo.mod_pie ); m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_pie ) / 100 ) + tribeInfo.mod_pie );
m_baseStats.skillSpeed = paramGrowthInfo.base_secondary; m_baseStats.skillSpeed = paramGrowthInfo.base_secondary;
m_baseStats.spellSpeed = paramGrowthInfo.base_secondary; m_baseStats.spellSpeed = paramGrowthInfo.base_secondary;
m_baseStats.accuracy = paramGrowthInfo.base_secondary; m_baseStats.accuracy = paramGrowthInfo.base_secondary;
m_baseStats.critHitRate = paramGrowthInfo.base_secondary; m_baseStats.critHitRate = paramGrowthInfo.base_secondary;
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary; m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary; m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.tenacity = paramGrowthInfo.base_secondary;
m_baseStats.max_mp = Math::CalcStats::calculateMaxMp( getAsPlayer() ); m_baseStats.max_mp = Math::CalcStats::calculateMaxMp( getAsPlayer() );
@ -440,6 +440,9 @@ void Core::Entity::Player::setZone( uint32_t zoneId )
gcAffPacket.data().gcRank[1] = m_gcRank[1]; gcAffPacket.data().gcRank[1] = m_gcRank[1];
gcAffPacket.data().gcRank[2] = m_gcRank[2]; gcAffPacket.data().gcRank[2] = m_gcRank[2];
queuePacket( gcAffPacket ); queuePacket( gcAffPacket );
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
} }
ZoneChannelPacket< FFXIVIpcInitZone > initZonePacket( getId() ); ZoneChannelPacket< FFXIVIpcInitZone > initZonePacket( getId() );
@ -1050,7 +1053,7 @@ void Core::Entity::Player::update( int64_t currTime )
if( !isAlive() ) if( !isAlive() )
return; return;
m_pStatusEffectContainer->update(); updateStatusEffects();
m_lastUpdate = currTime; m_lastUpdate = currTime;
@ -1583,6 +1586,11 @@ void Core::Entity::Player::setOpeningSequence( uint8_t seq )
m_openingSequence = seq; m_openingSequence = seq;
} }
uint16_t Core::Entity::Player::getItemLevel() const
{
return m_itemLevel;
}
/// Tells client to offset their eorzean time by given timestamp. /// Tells client to offset their eorzean time by given timestamp.
void Core::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp ) void Core::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp )
{ {

View file

@ -208,6 +208,10 @@ public:
void unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem ); void unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem );
/*! equip a weapon, possibly forcing a job change */ /*! equip a weapon, possibly forcing a job change */
void equipWeapon( ItemPtr pItem ); void equipWeapon( ItemPtr pItem );
/*! get player ilvl */
uint16_t getItemLevel() const;
/*! send player ilvl */
void sendItemLevel();
/*! get a const pointer to the inventory object */ /*! get a const pointer to the inventory object */
InventoryPtr getInventory() const; InventoryPtr getInventory() const;
/*! get the current main hand model */ /*! get the current main hand model */
@ -599,16 +603,20 @@ private:
uint8_t m_openingSequence; uint8_t m_openingSequence;
uint16_t m_itemLevel;
InventoryPtr m_pInventory; InventoryPtr m_pInventory;
std::map< uint32_t, Event::EventPtr > m_eventMap; std::map< uint32_t, Event::EventPtr > m_eventMap;
std::map< uint32_t, uint8_t > m_playerIdToSpawnIdMap; // maps player to spawn id std::map< uint32_t, uint8_t > m_playerIdToSpawnIdMap; // maps player to spawn id
std::queue< uint8_t > m_freeSpawnIdQueue; // queue with spawn ids free to be assigned std::queue< uint8_t > m_freeSpawnIdQueue; // queue with spawn ids free to be assigned
std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned
std::map< uint32_t, uint8_t > m_actorIdTohateSlotMap; std::map< uint32_t, uint8_t > m_actorIdTohateSlotMap;
std::map< uint32_t, uint8_t > m_questIdToQuestIdx; // quest mapping, quest id to quest container index std::map< uint32_t, uint8_t > m_questIdToQuestIdx; // quest mapping, quest id to quest container index
std::map< uint8_t, uint32_t > m_questIdxToQuestId; // quest mapping, quest container index to questId std::map< uint8_t, uint32_t > m_questIdxToQuestId; // quest mapping, quest container index to questId
boost::shared_ptr< Common::QuestActive > m_activeQuests[30]; boost::shared_ptr< Common::QuestActive > m_activeQuests[30];
int16_t m_questTracking[5]; int16_t m_questTracking[5];
uint8_t m_stateFlags[7]; uint8_t m_stateFlags[7];
uint8_t m_gmRank; uint8_t m_gmRank;
uint16_t zoneId; uint16_t zoneId;

View file

@ -1,17 +1,21 @@
#include <src/servers/Server_Common/Common.h> #include <src/servers/Server_Common/Common.h>
#include <src/servers/Server_Common/Exd/ExdData.h>
#include <src/servers/Server_Common/Network/GamePacket.h>
#include <src/servers/Server_Common/Logging/Logger.h>
#include "Player.h" #include "Player.h"
#include "src/servers/Server_Zone/Zone/ZoneMgr.h" #include "src/servers/Server_Zone/Zone/ZoneMgr.h"
#include "src/servers/Server_Zone/Zone/Zone.h" #include "src/servers/Server_Zone/Zone/Zone.h"
#include <src/servers/Server_Common/Network/GamePacket.h> #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h" #include "src/servers/Server_Zone/Inventory/Inventory.h"
#include "src/servers/Server_Zone/Inventory/Item.h" #include "src/servers/Server_Zone/Inventory/Item.h"
extern Core::Logger g_log;
using namespace Core::Common; using namespace Core::Common;
using namespace Core::Network::Packets; using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server; using namespace Core::Network::Packets::Server;
@ -21,6 +25,11 @@ Core::InventoryPtr Core::Entity::Player::getInventory() const
return m_pInventory; return m_pInventory;
} }
void Core::Entity::Player::sendItemLevel()
{
queuePacket( ActorControlPacket142( getId(), SetItemLevel, getItemLevel(), 0 ) );
}
// TODO: This has to be redone and simplified // TODO: This has to be redone and simplified
void Core::Entity::Player::equipWeapon( Core::ItemPtr pItem ) void Core::Entity::Player::equipWeapon( Core::ItemPtr pItem )
{ {
@ -77,10 +86,10 @@ void Core::Entity::Player::equipWeapon( Core::ItemPtr pItem )
} }
// equip an item // equip an item
void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::ItemPtr pItem, bool sendModel ) void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::ItemPtr pItem, bool sendUpdate )
{ {
// Console->outDebOnly("Equipping into slot %i", equipSlotID); //g_log.debug( "Equipping into slot " + std::to_string( equipSlotId ) );
uint64_t model = pItem->getModelId1(); uint64_t model = pItem->getModelId1();
uint64_t model2 = pItem->getModelId2(); uint64_t model2 = pItem->getModelId2();
@ -109,14 +118,21 @@ void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::It
} }
if( sendModel ) if( sendUpdate )
{
this->sendModel(); this->sendModel();
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
}
} }
void Core::Entity::Player::unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem ) void Core::Entity::Player::unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem )
{ {
m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0; m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0;
sendModel(); sendModel();
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
} }
uint32_t Core::Entity::Player::getCurrency( uint8_t type ) const uint32_t Core::Entity::Player::getCurrency( uint8_t type ) const

View file

@ -26,7 +26,6 @@
#include "src/servers/Server_Zone/Network/GameConnection.h" #include "src/servers/Server_Zone/Network/GameConnection.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h" #include "src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h" #include "src/servers/Server_Zone/Inventory/Inventory.h"
#include <Server_Common/Database/DatabaseDef.h> #include <Server_Common/Database/DatabaseDef.h>
@ -178,7 +177,8 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
m_lastTickTime = 0; m_lastTickTime = 0;
auto pPlayer = getAsPlayer(); auto pPlayer = getAsPlayer();
m_pInventory = InventoryPtr( new Inventory( pPlayer ) ); // TODO: remove Inventory and actually inline it in Player class
m_pInventory = InventoryPtr( new Inventory( pPlayer.get() ) );
pPlayer->calculateStats(); pPlayer->calculateStats();
@ -211,8 +211,6 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
initSpawnIdQueue(); initSpawnIdQueue();
m_pStatusEffectContainer = StatusEffect::StatusEffectContainerPtr( new StatusEffect::StatusEffectContainer( shared_from_this() ) );
if( !m_playerIdToSpawnIdMap.empty() ) if( !m_playerIdToSpawnIdMap.empty() )
m_playerIdToSpawnIdMap.clear(); m_playerIdToSpawnIdMap.clear();

View file

@ -13,6 +13,7 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/ServerNoticePacket.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ServerNoticePacket.h"
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/clamp.hpp>
#include "src/servers/Server_Zone/Forwards.h" #include "src/servers/Server_Zone/Forwards.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h" #include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
@ -27,7 +28,7 @@ using namespace Core::Network;
using namespace Core::Network::Packets; using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server; using namespace Core::Network::Packets::Server;
Core::Inventory::Inventory( Core::Entity::PlayerPtr pOwner ) Core::Inventory::Inventory( Core::Entity::Player* pOwner )
{ {
m_pOwner = pOwner; m_pOwner = pOwner;
@ -438,6 +439,30 @@ bool Core::Inventory::removeCrystal( CrystalType type, uint32_t amount )
return true; return true;
} }
bool Core::Inventory::isOneHandedWeapon( ItemUICategory weaponCategory )
{
switch ( weaponCategory )
{
case ItemUICategory::AlchemistsPrimaryTool:
case ItemUICategory::ArmorersPrimaryTool:
case ItemUICategory::BotanistsPrimaryTool:
case ItemUICategory::CulinariansPrimaryTool:
case ItemUICategory::OnehandedConjurersArm:
case ItemUICategory::CarpentersPrimaryTool:
case ItemUICategory::FishersPrimaryTool:
case ItemUICategory::GladiatorsArm:
case ItemUICategory::GoldsmithsPrimaryTool:
case ItemUICategory::LeatherworkersPrimaryTool:
case ItemUICategory::MinersPrimaryTool:
case ItemUICategory::OnehandedThaumaturgesArm:
case ItemUICategory::WeaversPrimaryTool:
case ItemUICategory::BlacksmithsPrimaryTool:
return true;
default:
return false;
}
}
bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity ) bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity )
{ {
@ -450,7 +475,8 @@ int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t
auto itemInfo = g_exdData.getItemInfo( catalogId ); auto itemInfo = g_exdData.getItemInfo( catalogId );
if( !itemInfo ) // if item data doesn't exist or it's a blank field
if( !itemInfo || itemInfo->item_level == 0 )
{ {
return -1; return -1;
} }
@ -828,6 +854,40 @@ void Core::Inventory::send()
} }
uint16_t Core::Inventory::calculateEquippedGearItemLevel()
{
uint32_t iLvlResult = 0;
auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap();
auto it = gearSetMap.begin();
while ( it != gearSetMap.end() )
{
auto currItem = it->second;
if ( currItem )
{
iLvlResult += currItem->getItemLevel();
// If item is weapon and isn't one-handed
if ( currItem->isWeapon() && !isOneHandedWeapon( currItem->getCategory() ) )
{
iLvlResult += currItem->getItemLevel();
}
else
{
g_log.debug( "Is one handed" );
}
}
it++;
}
return boost::algorithm::clamp( iLvlResult / 12, 0, 9999 );
}
uint8_t Core::Inventory::getFreeSlotsInBags() uint8_t Core::Inventory::getFreeSlotsInBags()
{ {
uint8_t slots = 0; uint8_t slots = 0;

View file

@ -13,7 +13,7 @@ using InventoryMap = std::map< uint16_t, ItemContainerPtr >;
class Inventory class Inventory
{ {
public: public:
Inventory( Entity::PlayerPtr pOwner ); Inventory( Entity::Player* pOwner );
~Inventory(); ~Inventory();
enum ContainerType : uint16_t enum ContainerType : uint16_t
@ -153,6 +153,10 @@ public:
bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem ); bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem );
/*! heck if weapon category qualifies the weapon as onehanded */
bool isOneHandedWeapon( Common::ItemUICategory weaponCategory );
/*! calculate and return player ilvl based off equipped gear */
uint16_t calculateEquippedGearItemLevel();
/*! return the current amount of currency of type */ /*! return the current amount of currency of type */
uint32_t getCurrency( CurrencyType type ); uint32_t getCurrency( CurrencyType type );
/*! add amount to the current of type */ /*! add amount to the current of type */
@ -191,7 +195,7 @@ public:
private: private:
Entity::PlayerPtr m_pOwner; Entity::Player* m_pOwner;
InventoryMap m_inventoryMap; InventoryMap m_inventoryMap;
}; };

View file

@ -30,6 +30,7 @@ Core::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t mo
m_magicalDmg = itemInfo->magical_damage; m_magicalDmg = itemInfo->magical_damage;
m_weaponDmg = ( m_physicalDmg != 0 ) ? m_physicalDmg : m_magicalDmg; m_weaponDmg = ( m_physicalDmg != 0 ) ? m_physicalDmg : m_magicalDmg;
m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000; m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000;
m_itemLevel = itemInfo->item_level;
} }
Core::Item::~Item() Core::Item::~Item()
@ -57,11 +58,21 @@ uint16_t Core::Item::getMagicalDmg() const
return m_magicalDmg; return m_magicalDmg;
} }
uint16_t Core::Item::getItemLevel() const
{
return m_itemLevel;
}
uint16_t Core::Item::getWeaponDmg() const uint16_t Core::Item::getWeaponDmg() const
{ {
return m_weaponDmg; return m_weaponDmg;
} }
bool Core::Item::isWeapon() const
{
return (m_weaponDmg != 0);
}
uint32_t Core::Item::getId() const uint32_t Core::Item::getId() const
{ {
return m_id; return m_id;

View file

@ -48,8 +48,12 @@ public:
uint16_t getWeaponDmg() const; uint16_t getWeaponDmg() const;
bool isWeapon() const;
float getAutoAttackDmg() const; float getAutoAttackDmg() const;
uint16_t getItemLevel() const;
protected: protected:
uint32_t m_id; uint32_t m_id;
@ -71,6 +75,7 @@ protected:
uint16_t m_magicalDmg; uint16_t m_magicalDmg;
uint16_t m_weaponDmg; uint16_t m_weaponDmg;
float m_autoAttackDmg; float m_autoAttackDmg;
uint16_t m_itemLevel;
}; };

View file

@ -110,7 +110,7 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
case 0x68: // Remove status (clicking it off) case 0x68: // Remove status (clicking it off)
{ {
// todo: check if status can be removed by client from exd // todo: check if status can be removed by client from exd
pPlayer->removeSingleStatusEffectFromId( static_cast< uint32_t >( param1 ) ); pPlayer->removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) );
break; break;
} }
case 0x69: // Cancel cast case 0x69: // Cancel cast
@ -228,10 +228,15 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
} }
break; break;
} }
case 0x1B5: // Dye item
{
break;
}
default: default:
{ {
g_log.debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " + g_log.debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " +
boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) ); boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) );
break;
} }
} }
} }

View file

@ -8,7 +8,6 @@
#include "src/servers/Server_Zone/Forwards.h" #include "src/servers/Server_Zone/Forwards.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h" #include "src/servers/Server_Zone/Inventory/Inventory.h"
#include "src/servers/Server_Zone/Inventory/Item.h" #include "src/servers/Server_Zone/Inventory/Item.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h" #include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
namespace Core { namespace Core {
@ -122,10 +121,11 @@ namespace Server {
uint64_t currentTimeMs = Util::getTimeMs(); uint64_t currentTimeMs = Util::getTimeMs();
for( auto const& effect : pPlayer->getStatusEffectContainer()->getEffectMap() ) for( auto const& effect : pPlayer->getStatusEffectMap() )
{ {
m_data.effect[effect.first].effect_id = effect.second->getId(); m_data.effect[effect.first].effect_id = effect.second->getId();
m_data.effect[effect.first].duration = static_cast< float >( effect.second->getDuration() - ( currentTimeMs - effect.second->getStartTimeMs() ) ) / 1000; m_data.effect[effect.first].duration = static_cast< float >( effect.second->getDuration() -
( currentTimeMs - effect.second->getStartTimeMs() ) ) / 1000;
m_data.effect[effect.first].sourceActorId = effect.second->getSrcActorId(); m_data.effect[effect.first].sourceActorId = effect.second->getSrcActorId();
m_data.effect[effect.first].unknown1 = effect.second->getParam(); m_data.effect[effect.first].unknown1 = effect.second->getParam();
} }

View file

@ -61,7 +61,7 @@ Core::XMLConfigPtr Core::ServerZone::getConfig() const
size_t Core::ServerZone::getSessionCount() const size_t Core::ServerZone::getSessionCount() const
{ {
return m_sessionMap.size(); return m_sessionMapById.size();
} }
bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId, bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
@ -263,7 +263,7 @@ void Core::ServerZone::mainLoop()
auto currTime = static_cast< uint32_t >( time( nullptr ) ); auto currTime = static_cast< uint32_t >( time( nullptr ) );
lock_guard< std::mutex > lock( this->m_sessionMutex ); lock_guard< std::mutex > lock( this->m_sessionMutex );
for( auto sessionIt : this->m_sessionMap ) for( auto sessionIt : this->m_sessionMapById )
{ {
auto session = sessionIt.second; auto session = sessionIt.second;
if( session && session->getPlayer() ) if( session && session->getPlayer() )
@ -284,8 +284,8 @@ void Core::ServerZone::mainLoop()
} }
auto it = this->m_sessionMap.begin(); auto it = this->m_sessionMapById.begin();
for( ; it != this->m_sessionMap.end(); ) for( ; it != this->m_sessionMapById.end(); )
{ {
uint32_t diff = currTime - it->second->getLastDataTime(); uint32_t diff = currTime - it->second->getLastDataTime();
@ -298,7 +298,8 @@ void Core::ServerZone::mainLoop()
// if( it->second.unique() ) // if( it->second.unique() )
{ {
g_log.info("[" + std::to_string(it->second->getId() ) + "] Session removal" ); g_log.info("[" + std::to_string(it->second->getId() ) + "] Session removal" );
it = this->m_sessionMap.erase( it ); it = this->m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
continue; continue;
} }
} }
@ -310,7 +311,8 @@ void Core::ServerZone::mainLoop()
it->second->close(); it->second->close();
// if( it->second.unique() ) // if( it->second.unique() )
{ {
it = this->m_sessionMap.erase(it ); it = this->m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
} }
} }
else else
@ -329,9 +331,9 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
const std::string session_id_str = std::to_string( sessionId ); const std::string session_id_str = std::to_string( sessionId );
auto it = m_sessionMap.find( sessionId ); auto it = m_sessionMapById.find( sessionId );
if( it != m_sessionMap.end() ) if( it != m_sessionMapById.end() )
{ {
g_log.error( "[" + session_id_str + "] Error creating session" ); g_log.error( "[" + session_id_str + "] Error creating session" );
return false; return false;
@ -340,7 +342,7 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
g_log.info( "[" + session_id_str + "] Creating new session" ); g_log.info( "[" + session_id_str + "] Creating new session" );
boost::shared_ptr<Session> newSession( new Session( sessionId ) ); boost::shared_ptr<Session> newSession( new Session( sessionId ) );
m_sessionMap[sessionId] = newSession; m_sessionMapById[sessionId] = newSession;
if( !newSession->loadPlayer() ) if( !newSession->loadPlayer() )
{ {
@ -348,7 +350,7 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
return false; return false;
} }
m_playerSessionMap[newSession->getPlayer()->getName()] = newSession; m_sessionMapByName[newSession->getPlayer()->getName()] = newSession;
return true; return true;
@ -356,15 +358,15 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
void Core::ServerZone::removeSession( uint32_t sessionId ) void Core::ServerZone::removeSession( uint32_t sessionId )
{ {
m_sessionMap.erase( sessionId ); m_sessionMapById.erase( sessionId );
} }
void Core::ServerZone::updateSession( uint32_t id ) void Core::ServerZone::updateSession( uint32_t id )
{ {
std::lock_guard< std::mutex > lock( m_sessionMutex ); std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_sessionMap.find( id ); auto it = m_sessionMapById.find( id );
if( it != m_sessionMap.end() ) if( it != m_sessionMapById.end() )
it->second->loadPlayer(); it->second->loadPlayer();
} }
@ -372,9 +374,9 @@ Core::SessionPtr Core::ServerZone::getSession( uint32_t id )
{ {
//std::lock_guard<std::mutex> lock( m_sessionMutex ); //std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_sessionMap.find( id ); auto it = m_sessionMapById.find( id );
if( it != m_sessionMap.end() ) if( it != m_sessionMapById.end() )
return ( it->second ); return ( it->second );
return nullptr; return nullptr;
@ -384,9 +386,9 @@ Core::SessionPtr Core::ServerZone::getSession( std::string playerName )
{ {
//std::lock_guard<std::mutex> lock( m_sessionMutex ); //std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName ); auto it = m_sessionMapByName.find( playerName );
if (it != m_playerSessionMap.end()) if (it != m_sessionMapByName.end())
return (it->second); return (it->second);
return nullptr; return nullptr;
@ -394,15 +396,15 @@ Core::SessionPtr Core::ServerZone::getSession( std::string playerName )
void Core::ServerZone::removeSession( std::string playerName ) void Core::ServerZone::removeSession( std::string playerName )
{ {
m_playerSessionMap.erase( playerName ); m_sessionMapByName.erase( playerName );
} }
void Core::ServerZone::updateSession( std::string playerName ) void Core::ServerZone::updateSession( std::string playerName )
{ {
std::lock_guard< std::mutex > lock( m_sessionMutex ); std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName ); auto it = m_sessionMapByName.find( playerName );
if( it != m_playerSessionMap.end() ) if( it != m_sessionMapByName.end() )
it->second->loadPlayer(); it->second->loadPlayer();
} }

View file

@ -61,8 +61,8 @@ namespace Core {
std::mutex m_sessionMutex; std::mutex m_sessionMutex;
std::map< uint32_t, SessionPtr > m_sessionMap; std::map< uint32_t, SessionPtr > m_sessionMapById;
std::map< std::string, SessionPtr > m_playerSessionMap; std::map< std::string, SessionPtr > m_sessionMapByName;
std::map< uint32_t, uint32_t > m_zones; std::map< uint32_t, uint32_t > m_zones;

View file

@ -1,218 +0,0 @@
#include <src/servers/Server_Common/Util/Util.h>
#include <src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h>
#include "src/servers/Server_Zone/Actor/Actor.h"
#include "StatusEffect.h"
#include "StatusEffectContainer.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
Core::StatusEffect::StatusEffectContainer::StatusEffectContainer( Entity::ActorPtr pOwner )
: m_pOwner( pOwner )
{
// initialize the free slot queue
for( uint8_t i = 0; i < MAX_EFFECTS; i++ )
{
m_freeEffectSlotQueue.push( i );
}
}
int8_t Core::StatusEffect::StatusEffectContainer::getFreeSlot()
{
int8_t freeEffectSlot = -1;
if( m_freeEffectSlotQueue.empty() )
return freeEffectSlot;
freeEffectSlot = m_freeEffectSlotQueue.front();
m_freeEffectSlotQueue.pop();
return freeEffectSlot;
}
void Core::StatusEffect::StatusEffectContainer::freeSlot( uint8_t slotId )
{
m_freeEffectSlotQueue.push( slotId );
}
Core::StatusEffect::StatusEffectContainer::~StatusEffectContainer()
{
}
void Core::StatusEffect::StatusEffectContainer::addStatusEffect( StatusEffectPtr pEffect )
{
int8_t nextSlot = getFreeSlot();
// if there is no slot left, do not add the effect
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_effectMap[nextSlot] = pEffect;
ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( m_pOwner->getId() );
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
statusEffectAdd.data().current_hp = m_pOwner->getHp();
statusEffectAdd.data().current_mp = m_pOwner->getMp();
statusEffectAdd.data().current_tp = m_pOwner->getTp();
statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000;
statusEffectAdd.data().effect_id = pEffect->getId();
statusEffectAdd.data().effect_index = nextSlot;
statusEffectAdd.data().max_hp = m_pOwner->getMaxHp();
statusEffectAdd.data().max_mp = m_pOwner->getMaxMp();
statusEffectAdd.data().max_something = 1;
//statusEffectAdd.data().unknown2 = 28;
statusEffectAdd.data().param = pEffect->getParam();
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
m_pOwner->sendToInRangeSet( statusEffectAdd, sendToSelf );
}
void Core::StatusEffect::StatusEffectContainer::removeSingleStatusEffectFromId( uint32_t id )
{
for (auto effectIt : m_effectMap)
{
if (effectIt.second->getId() == id)
{
removeStatusEffect( effectIt.first );
break;
}
}
}
void Core::StatusEffect::StatusEffectContainer::removeStatusEffect( uint8_t effectSlotId )
{
auto pEffectIt = m_effectMap.find( effectSlotId );
if( pEffectIt == m_effectMap.end() )
return;
freeSlot( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), StatusEffectLose, pEffect->getId() ), sendToSelf );
m_effectMap.erase( effectSlotId );
sendUpdate();
}
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::StatusEffect::StatusEffectContainer::getEffectMap() const
{
return m_effectMap;
}
void Core::StatusEffect::StatusEffectContainer::sendUpdate()
{
uint64_t currentTimeMs = Util::getTimeMs();
ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( m_pOwner->getId() );
statusEffectList.data().current_hp = m_pOwner->getHp();
statusEffectList.data().current_mp = m_pOwner->getMp();
statusEffectList.data().currentTp = m_pOwner->getTp();
statusEffectList.data().max_hp = m_pOwner->getMaxHp();
statusEffectList.data().max_mp = m_pOwner->getMaxMp();
uint8_t slot = 0;
for( auto effectIt : m_effectMap )
{
float timeLeft = static_cast< float >( effectIt.second->getDuration() - ( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
statusEffectList.data().effect[slot].duration = timeLeft;
statusEffectList.data().effect[slot].effect_id = effectIt.second->getId();
statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId();
slot++;
}
bool sendToSelf = m_pOwner->isPlayer();
m_pOwner->sendToInRangeSet( statusEffectList, sendToSelf );
}
void Core::StatusEffect::StatusEffectContainer::update()
{
uint64_t currentTimeMs = Util::getTimeMs();
uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0;
for( auto effectIt : m_effectMap )
{
uint8_t effectIndex = effectIt.first;
auto effect = effectIt.second;
uint64_t lastTick = effect->getLastTickMs();
uint64_t startTime = effect->getStartTimeMs();
uint32_t duration = effect->getDuration();
uint32_t tickRate = effect->getTickRate();
if( ( currentTimeMs - startTime ) > duration )
{
// remove status effect
removeStatusEffect( effectIndex );
// break because removing invalidates iterators
break;
}
if( ( currentTimeMs - lastTick ) > tickRate )
{
effect->setLastTick( currentTimeMs );
effect->onTick();
auto thisEffect = effect->getTickEffect();
switch( thisEffect.first )
{
case 1:
{
thisTickDmg += thisEffect.second;
break;
}
case 2:
{
thisTickHeal += thisEffect.second;
break;
}
}
}
}
if( thisTickDmg != 0 )
{
m_pOwner->takeDamage( thisTickDmg );
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
m_pOwner->heal( thisTickDmg );
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
bool Core::StatusEffect::StatusEffectContainer::hasStatusEffect( uint32_t id )
{
for( auto effectIt : m_effectMap )
{
if( effectIt.second->getId() == id )
{
return true;
}
}
return false;
}

View file

@ -1,49 +0,0 @@
#ifndef _STATUSEFFECTCONTAINER_H_
#define _STATUSEFFECTCONTAINER_H_
#include <boost/shared_ptr.hpp>
#include <queue>
#include <map>
#include "src/servers/Server_Zone/Forwards.h"
namespace Core
{
namespace StatusEffect
{
class StatusEffectContainer
{
public:
StatusEffectContainer( Entity::ActorPtr pOwner );
~StatusEffectContainer();
void addStatusEffect( StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectFromId( uint32_t id );
void update();
bool hasStatusEffect( uint32_t id );
int8_t getFreeSlot();
void freeSlot( uint8_t slotId );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getEffectMap() const;
void sendUpdate();
private:
const uint8_t MAX_EFFECTS = 30;
Entity::ActorPtr m_pOwner;
std::queue< uint8_t > m_freeEffectSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_tickEffectList;
std::map< uint8_t, StatusEffectPtr > m_effectMap;
};
}
}
#endif

View file

@ -47,7 +47,6 @@ namespace Core
{ {
entry->setCurrentZone( m_pZone ); entry->setCurrentZone( m_pZone );
entry->getAsBattleNpc()->initStatusEffectContainer();
m_pZone->pushActor( entry ); m_pZone->pushActor( entry );
} }