1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 14:57:44 +00:00

Merge pull request #259 from GokuWeedLord/actor_rewrite

move eobj/player spawnindex generation to common manager
This commit is contained in:
Mordred 2018-03-01 22:41:49 +01:00 committed by GitHub
commit 40fccfb481
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 59 deletions

View file

@ -0,0 +1,109 @@
#ifndef SAPPHIRE_SPAWNINDEXALLOCATOR_H
#define SAPPHIRE_SPAWNINDEXALLOCATOR_H
#include <queue>
#include <unordered_map>
#include <type_traits>
namespace Core
{
namespace Util
{
template< typename T, typename ActorIdType = uint32_t >
class SpawnIndexAllocator
{
public:
static_assert( std::is_same< T, uint8_t >::value || std::is_same< T, uint16_t >::value ||
std::is_same< T, uint32_t >::value || std::is_same< T, uint64_t >::value,
"T must be uint8_t, uint16_t, uint32_t, uint64_t" );
SpawnIndexAllocator() :
m_maxSlotId( 0 ),
m_reserveFirstSlot( false )
{ }
void init( T maxSlotId, bool reserveFirstSlot = false )
{
setupQueue();
m_maxSlotId = maxSlotId;
m_reserveFirstSlot = reserveFirstSlot;
// todo: reserve max slot id in map to prevent any runtime reshashing
}
T freeUsedSpawnIndex( ActorIdType actorId )
{
assert( m_maxSlotId != 0 );
auto it = m_actorIdToAllocatedMap.find( actorId );
if( it == m_actorIdToAllocatedMap.end() )
return 0;
auto index = it->second;
m_availableIds.push( index );
m_actorIdToAllocatedMap.erase( it );
return index;
}
bool getNextFreeSpawnIndex( ActorIdType actorId )
{
assert( m_maxSlotId != 0 );
if( m_availableIds.empty() )
return getAllocFailId();
auto nextId = m_availableIds.front();
m_availableIds.pop();
m_actorIdToAllocatedMap[actorId] = nextId;
return nextId;
}
void freeAllSpawnIndexes()
{
setupQueue();
m_actorIdToAllocatedMap.clear();
}
bool isSpawnIndexValid( T spawnIndex )
{
return spawnIndex != getAllocFailId();
}
constexpr T getAllocFailId()
{
return static_cast< T >( -1 );
}
protected:
void setupQueue()
{
while( !m_availableIds.empty() )
m_availableIds.pop();
uint32_t start = 0;
// slot 0 is reserved when used for spawning actors/players otherwise the local player actor spawnIndex
// will be used by another actor and despawn the local player
if( m_reserveFirstSlot )
start = 1;
for( uint32_t i = start; i < m_maxSlotId; i++ )
m_availableIds.push( i );
}
std::queue< T > m_availableIds;
std::unordered_map< ActorIdType, T > m_actorIdToAllocatedMap;
T m_maxSlotId;
bool m_reserveFirstSlot;
};
}
}
#endif //SAPPHIRE_SPAWNINDEXALLOCATOR_H

View file

@ -98,9 +98,13 @@ Core::InstanceContentPtr Core::Entity::EventObject::getParentInstance() const
void Core::Entity::EventObject::spawn( Core::Entity::PlayerPtr pTarget )
{
auto spawnIndex = pTarget->getNextObjSpawnIndexForActorId( getId( ) );
if( !pTarget->isObjSpawnIndexValid( spawnIndex ) )
return;
g_log.debug( "Spawning EObj: id:" + std::to_string( getId() ) + " name:" + getName() );
ZoneChannelPacket< FFXIVIpcObjectSpawn > eobjStatePacket( getId(), pTarget->getId() );
eobjStatePacket.data().spawnIndex = pTarget->getNextObjSpawnIndexForActorId( getId( ));
eobjStatePacket.data().spawnIndex = spawnIndex;
eobjStatePacket.data().objKind = getObjKind();
eobjStatePacket.data().state = getState();
eobjStatePacket.data().objId = getObjectId();

View file

@ -73,7 +73,6 @@ Core::Entity::Player::Player() :
m_markedForRemoval( false ),
m_mount( 0 ),
m_directorInitialized( false ),
m_objCount( 0 ),
m_onEnterEventDone( false )
{
m_id = 0;
@ -90,6 +89,9 @@ Core::Entity::Player::Player() :
memset( m_searchMessage, 0, sizeof( m_searchMessage ) );
memset( m_classArray, 0, sizeof( m_classArray ) );
memset( m_expArray, 0, sizeof( m_expArray ) );
m_objSpawnIndexAllocator.init( MAX_DISPLAYED_EOBJS );
m_actorSpawnIndexAllocator.init( MAX_DISPLAYED_ACTORS, true );
}
Core::Entity::Player::~Player()
@ -438,43 +440,27 @@ uint8_t Core::Entity::Player::getGender() const
void Core::Entity::Player::initSpawnIdQueue()
{
while( !m_freeSpawnIdQueue.empty() )
{
m_freeSpawnIdQueue.pop();
}
for( int32_t i = 1; i < MAX_DISPLAYED_ACTORS; i++ )
{
m_freeSpawnIdQueue.push( i );
}
m_actorSpawnIndexAllocator.freeAllSpawnIndexes();
}
uint8_t Core::Entity::Player::getSpawnIdForActorId( uint32_t actorId )
{
if( m_freeSpawnIdQueue.empty() )
return 0;
uint8_t spawnId = m_freeSpawnIdQueue.front();
m_freeSpawnIdQueue.pop();
m_playerIdToSpawnIdMap[actorId] = spawnId;
return spawnId;
return m_actorSpawnIndexAllocator.getNextFreeSpawnIndex( actorId );
}
void Core::Entity::Player::assignSpawnIdToPlayerId( uint32_t actorId, uint8_t spawnId )
bool Core::Entity::Player::isActorSpawnIdValid( uint8_t spawnIndex )
{
m_playerIdToSpawnIdMap[actorId] = spawnId;
return m_actorSpawnIndexAllocator.isSpawnIndexValid( spawnIndex );
}
void Core::Entity::Player::registerAetheryte( uint8_t aetheryteId )
{
uint16_t index;
uint8_t value;
Util::valueToFlagByteIndexValue( aetheryteId, value, index );
m_aetheryte[index] |= value;
queuePacket( ActorControlPacket143( getId(), LearnTeleport, aetheryteId, 1 ) );
}
bool Core::Entity::Player::isAetheryteRegistered( uint8_t aetheryteId ) const
@ -1048,9 +1034,7 @@ void Core::Entity::Player::onMobKill( uint16_t nameId )
void Core::Entity::Player::freePlayerSpawnId( uint32_t actorId )
{
uint8_t spawnId = m_playerIdToSpawnIdMap[actorId];
m_playerIdToSpawnIdMap.erase( actorId );
m_freeSpawnIdQueue.push( spawnId );
auto spawnId = m_actorSpawnIndexAllocator.freeUsedSpawnIndex( actorId );
ZoneChannelPacket< FFXIVIpcActorFreeSpawn > freeActorSpawnPacket( getId() );
freeActorSpawnPacket.data().actorId = actorId;
@ -1661,36 +1645,22 @@ void Core::Entity::Player::teleportQuery( uint16_t aetheryteId )
uint8_t Core::Entity::Player::getNextObjSpawnIndexForActorId( uint32_t actorId )
{
// todo: fix it so the case where there's no ids available doesn't break everything :(
auto nextCount = m_freeObjCounts.front();
m_freeObjCounts.pop();
m_actorIdToObjCountMap[actorId] = nextCount;
return nextCount;
return m_objSpawnIndexAllocator.getNextFreeSpawnIndex( actorId );
}
void Core::Entity::Player::resetObjSpawnIndex()
{
while( m_freeObjCounts.empty() )
m_freeObjCounts.pop();
for( uint32_t i = 0; i < MAX_DISPLAYED_EOBJS; ++i )
m_freeObjCounts.push( i );
m_actorIdToObjCountMap.clear();
m_objSpawnIndexAllocator.freeAllSpawnIndexes();
}
void Core::Entity::Player::freeObjSpawnIndexForActorId( uint32_t actorId )
{
auto it = m_actorIdToObjCountMap.find( actorId );
if( it == m_actorIdToObjCountMap.end() )
return;
m_objSpawnIndexAllocator.freeUsedSpawnIndex( actorId );
}
auto freeCount = m_actorIdToObjCountMap[actorId];
m_freeObjCounts.push( freeCount );
m_actorIdToObjCountMap.erase( actorId );
bool Core::Entity::Player::isObjSpawnIndexValid( uint8_t index )
{
return m_objSpawnIndexAllocator.isSpawnIndexValid( index );
}
void Core::Entity::Player::setOnEnterEventDone( bool isDone )

View file

@ -4,6 +4,7 @@
#include "Forwards.h"
#include <common/Common.h>
#include <common/Util/SpawnIndexAllocator.h>
#include "Chara.h"
#include "Inventory/Inventory.h"
@ -419,10 +420,10 @@ public:
void initSpawnIdQueue();
/*! get the spawn id mapped to a specific actorId */
uint8_t getSpawnIdForActorId( uint32_t actorId );
/*! assigns the given spawnId to the actor */
void assignSpawnIdToPlayerId( uint32_t actorId, uint8_t spawnId );
/*! frees the spawnId assigned to the given actor */
void freePlayerSpawnId( uint32_t actorId );
/*! checks if the given spawn id is valid */
bool isActorSpawnIdValid( uint8_t spawnId );
/*! send spawn packets to pTarget */
void spawn( PlayerPtr pTarget ) override;
/*! send despawn packets to pTarget */
@ -440,8 +441,6 @@ public:
bool hasStateFlag( Common::PlayerStateFlag flag ) const;
/* reset a specified flag */
void unsetStateFlag( Common::PlayerStateFlag flag );
/* helper function, send an empty state flag update */
void unlock();
// Player Session Handling
//////////////////////////////////////////////////////////////////////////////////////////////////////
@ -568,6 +567,8 @@ public:
void resetObjSpawnIndex();
/*! frees an obj count to be used by another eobj */
void freeObjSpawnIndexForActorId( uint32_t actorId );
/*! checks if a spawn index is valid */
bool isObjSpawnIndexValid( uint8_t index );
private:
uint32_t m_lastWrite;
@ -641,8 +642,6 @@ private:
std::map< uint32_t, Event::EventHandlerPtr > m_eventHandlerMap;
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_freeHateSlotQueue; // queue with "hate slots" free to be assigned
std::map< uint32_t, uint8_t > m_actorIdTohateSlotMap;
@ -682,10 +681,8 @@ private:
uint8_t m_mount;
// counter used to index objects spawned for the player
uint8_t m_objCount;
std::queue< uint8_t > m_freeObjCounts;
std::map< uint32_t, uint8_t > m_actorIdToObjCountMap;
Util::SpawnIndexAllocator< uint8_t > m_objSpawnIndexAllocator;
Util::SpawnIndexAllocator< uint8_t > m_actorSpawnIndexAllocator;
};
}

View file

@ -236,9 +236,6 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
initSpawnIdQueue();
if( !m_playerIdToSpawnIdMap.empty() )
m_playerIdToSpawnIdMap.clear();
if( !g_territoryMgr.movePlayer( pCurrZone, getAsPlayer() ) )
return false;

View file

@ -84,6 +84,9 @@ namespace Server {
else
{
m_data.spawnIndex = target.getSpawnIdForActorId( player.getId() );
if( !target.isActorSpawnIdValid( m_data.spawnIndex ) )
return;
}
// 0x20 == spawn hidden to be displayed by the spawneffect control
m_data.displayFlags = player.getStance();