2023-04-26 13:58:41 +02:00
|
|
|
#pragma once
|
2018-03-02 02:55:02 +11:00
|
|
|
|
|
|
|
#include <type_traits>
|
2023-04-26 13:58:41 +02:00
|
|
|
#include <unordered_set>
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2019-06-02 00:34:22 +10:00
|
|
|
namespace Sapphire::Common::Util
|
2018-03-02 02:55:02 +11:00
|
|
|
{
|
2023-04-26 13:58:41 +02:00
|
|
|
// The SpawnIndexAllocator class template is a utility class that allocates
|
|
|
|
// unique indices for spawned objects in the game world. It is parameterized
|
|
|
|
// by the index type T and an optional actor ID type.
|
2018-10-28 21:53:21 +01:00
|
|
|
template< typename T, typename ActorIdType = uint32_t >
|
|
|
|
class SpawnIndexAllocator
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2018-10-28 21:53:21 +01:00
|
|
|
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" );
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Constructor for the SpawnIndexAllocator, initializing internal variables
|
|
|
|
// such as maximum slot ID, reserve first slot flag, and allocation failure ID.
|
|
|
|
SpawnIndexAllocator() : m_maxSlotId( 0 ),
|
|
|
|
m_reserveFirstSlot( false ),
|
|
|
|
m_allocFailId( static_cast< T >( -1 ) )
|
2018-10-28 21:53:21 +01:00
|
|
|
{
|
|
|
|
}
|
2018-03-02 15:29:48 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Initializes the SpawnIndexAllocator by setting the maximum slot ID and
|
|
|
|
// whether to reserve the first slot. Sets up the free and used index sets.
|
2018-10-28 21:53:21 +01:00
|
|
|
void init( T maxSlotId, bool reserveFirstSlot = false )
|
|
|
|
{
|
|
|
|
m_maxSlotId = maxSlotId;
|
|
|
|
m_reserveFirstSlot = reserveFirstSlot;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
setupSet();
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// reserve max slot id in set to prevent any runtime rehashing
|
|
|
|
m_freeIndexes.reserve( m_maxSlotId );
|
|
|
|
m_usedIndexes.reserve( m_maxSlotId );
|
2018-10-28 21:53:21 +01:00
|
|
|
}
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Frees a used spawn index, given an actor ID. Removes the index from the
|
|
|
|
// used set and adds it back to the free set. Returns the freed index or
|
|
|
|
// the allocation failure ID if the actor ID is not found.
|
2018-10-28 21:53:21 +01:00
|
|
|
T freeUsedSpawnIndex( ActorIdType actorId )
|
|
|
|
{
|
2023-04-26 13:58:41 +02:00
|
|
|
auto it = m_usedIndexes.find( actorId );
|
|
|
|
if( it == m_usedIndexes.end() )
|
|
|
|
return m_allocFailId;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
auto index = *it;
|
|
|
|
m_usedIndexes.erase( it );
|
|
|
|
m_freeIndexes.insert( index );
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
return index;
|
|
|
|
}
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Allocates the next free spawn index and associates it with the given
|
|
|
|
// actor ID. Removes the index from the free set and adds it to the used set.
|
|
|
|
// Returns the allocated index or the allocation failure ID if there are no
|
|
|
|
// free indices.
|
2018-10-28 21:53:21 +01:00
|
|
|
T getNextFreeSpawnIndex( ActorIdType actorId )
|
|
|
|
{
|
|
|
|
assert( m_maxSlotId != 0 );
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
if( m_freeIndexes.empty() )
|
|
|
|
return m_allocFailId;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
auto nextId = *m_freeIndexes.begin();
|
|
|
|
m_freeIndexes.erase( m_freeIndexes.begin() );
|
|
|
|
m_usedIndexes.insert( nextId );
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
return nextId;
|
|
|
|
}
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Frees all used spawn indices and clears the used set. Resets the free
|
|
|
|
// set to contain all possible indices.
|
2018-10-28 21:53:21 +01:00
|
|
|
void freeAllSpawnIndexes()
|
|
|
|
{
|
2023-04-26 13:58:41 +02:00
|
|
|
setupSet();
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
m_usedIndexes.clear();
|
2018-10-28 21:53:21 +01:00
|
|
|
}
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Returns true if the given spawn index is valid (i.e., not equal to the
|
|
|
|
// allocation failure ID), false otherwise.
|
2018-10-28 21:53:21 +01:00
|
|
|
bool isSpawnIndexValid( T spawnIndex )
|
|
|
|
{
|
2023-04-26 13:58:41 +02:00
|
|
|
return spawnIndex != m_allocFailId;
|
2018-10-28 21:53:21 +01:00
|
|
|
}
|
2018-03-02 11:39:52 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// Returns the allocation failure ID.
|
2018-10-28 21:53:21 +01:00
|
|
|
constexpr T getAllocFailId() const
|
|
|
|
{
|
2023-04-26 13:58:41 +02:00
|
|
|
return m_allocFailId;
|
2018-10-28 21:53:21 +01:00
|
|
|
}
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
protected:
|
2023-04-26 13:58:41 +02:00
|
|
|
// Sets up the free index set by inserting all possible spawn indices
|
|
|
|
// into the set, optionally reserving the first slot.
|
|
|
|
void setupSet()
|
2018-10-28 21:53:21 +01:00
|
|
|
{
|
|
|
|
assert( m_maxSlotId != 0 );
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
m_freeIndexes.clear();
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
uint32_t start = 0;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
// slot is reserved when used for spawning actors/players otherwise the local player actor spawnIndex
|
2018-10-28 21:53:21 +01:00
|
|
|
// will be used by another actor and despawn the local player
|
|
|
|
if( m_reserveFirstSlot )
|
|
|
|
start = 1;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
for( uint32_t i = start; i < m_maxSlotId; i++ )
|
2023-04-26 13:58:41 +02:00
|
|
|
m_freeIndexes.insert( i );
|
2018-10-28 21:53:21 +01:00
|
|
|
}
|
|
|
|
|
2023-04-26 13:58:41 +02:00
|
|
|
std::unordered_set< T > m_freeIndexes;
|
|
|
|
std::unordered_set< T > m_usedIndexes;
|
2018-03-02 02:55:02 +11:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
T m_maxSlotId;
|
|
|
|
bool m_reserveFirstSlot;
|
2023-04-26 13:58:41 +02:00
|
|
|
const T m_allocFailId;
|
2018-10-28 21:53:21 +01:00
|
|
|
};
|
2023-04-26 13:58:41 +02:00
|
|
|
}// namespace Sapphire::Common::Util
|