328 lines
7.8 KiB
C++
328 lines
7.8 KiB
C++
// Copyright (C) 2017 Jérôme Leclercq
|
|
// This file is part of the "Nazara Development Kit"
|
|
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
|
|
|
#include <Nazara/Core/Error.hpp>
|
|
#include <type_traits>
|
|
|
|
namespace Ndk
|
|
{
|
|
/*!
|
|
* \brief Constructs a World object
|
|
*
|
|
* \param addDefaultSystems Should default provided systems be used
|
|
*/
|
|
|
|
inline World::World(bool addDefaultSystems) :
|
|
m_orderedSystemsUpdated(false)
|
|
{
|
|
if (addDefaultSystems)
|
|
AddDefaultSystems();
|
|
}
|
|
|
|
/*!
|
|
* \brief Constructs a World object by move semantic
|
|
*
|
|
* \param world World to move into this
|
|
*/
|
|
|
|
inline World::World(World&& world) noexcept :
|
|
HandledObject(std::move(world))
|
|
{
|
|
operator=(std::move(world));
|
|
}
|
|
|
|
/*!
|
|
* \brief Adds a system to the world
|
|
* \return A reference to the newly created system
|
|
*
|
|
* \param system System to add to the world
|
|
*/
|
|
|
|
inline BaseSystem& World::AddSystem(std::unique_ptr<BaseSystem>&& system)
|
|
{
|
|
NazaraAssert(system, "System must be valid");
|
|
|
|
SystemIndex index = system->GetIndex();
|
|
|
|
// We must ensure that the vector is big enough to hold the new system
|
|
if (index >= m_systems.size())
|
|
m_systems.resize(index + 1);
|
|
|
|
// Affectation and return of system
|
|
m_systems[index] = std::move(system);
|
|
m_systems[index]->SetWorld(this);
|
|
|
|
Invalidate(); // We force an update for every entities
|
|
InvalidateSystemOrder(); // And regenerate the system update list
|
|
|
|
return *m_systems[index].get();
|
|
}
|
|
|
|
/*!
|
|
* \brief Adds a system to the world
|
|
* \return A reference to the newly created system
|
|
*
|
|
* \param args Arguments used to create the system
|
|
*/
|
|
|
|
template<typename SystemType, typename... Args>
|
|
SystemType& World::AddSystem(Args&&... args)
|
|
{
|
|
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");
|
|
|
|
// Allocation and affectation of the system
|
|
std::unique_ptr<SystemType> ptr(new SystemType(std::forward<Args>(args)...));
|
|
return static_cast<SystemType&>(AddSystem(std::move(ptr)));
|
|
}
|
|
|
|
/*!
|
|
* \brief Creates multiple entities in the world
|
|
* \return The set of entities created
|
|
*
|
|
* \param count Number of entities to create
|
|
*/
|
|
|
|
inline World::EntityVector World::CreateEntities(unsigned int count)
|
|
{
|
|
EntityVector list;
|
|
list.reserve(count);
|
|
|
|
for (unsigned int i = 0; i < count; ++i)
|
|
list.emplace_back(CreateEntity());
|
|
|
|
return list;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets every entities in the world
|
|
* \return A constant reference to the entities
|
|
*/
|
|
|
|
inline const EntityList& World::GetEntities() const
|
|
{
|
|
return m_aliveEntities;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets a system in the world by index
|
|
* \return A reference to the system
|
|
*
|
|
* \param index Index of the system
|
|
*
|
|
* \remark Produces a NazaraAssert if system is not available in this world
|
|
*/
|
|
|
|
inline BaseSystem& World::GetSystem(SystemIndex index)
|
|
{
|
|
NazaraAssert(HasSystem(index), "This system is not part of the world");
|
|
|
|
BaseSystem* system = m_systems[index].get();
|
|
NazaraAssert(system, "Invalid system pointer");
|
|
|
|
return *system;
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets a system in the world by type
|
|
* \return A reference to the system
|
|
*
|
|
* \remark Produces a NazaraAssert if system is not available in this world
|
|
*/
|
|
|
|
template<typename SystemType>
|
|
SystemType& World::GetSystem()
|
|
{
|
|
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");
|
|
|
|
SystemIndex index = GetSystemIndex<SystemType>();
|
|
return static_cast<SystemType&>(GetSystem(index));
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks whether or not a system is present in the world by index
|
|
* \return true If it is the case
|
|
*
|
|
* \param index Index of the system
|
|
*/
|
|
|
|
inline bool World::HasSystem(SystemIndex index) const
|
|
{
|
|
return index < m_systems.size() && m_systems[index];
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks whether or not a system is present in the world by type
|
|
* \return true If it is the case
|
|
*/
|
|
|
|
template<typename SystemType>
|
|
bool World::HasSystem() const
|
|
{
|
|
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");
|
|
|
|
SystemIndex index = GetSystemIndex<SystemType>();
|
|
return HasSystem(index);
|
|
}
|
|
|
|
/*!
|
|
* \brief Marks an entity for deletion
|
|
*
|
|
* \param Pointer to the entity
|
|
*
|
|
* \remark If the entity pointer is invalid, nothing is done
|
|
* \remark For safety, entities are not killed until the next world update
|
|
*/
|
|
inline void World::KillEntity(Entity* entity)
|
|
{
|
|
if (IsEntityValid(entity))
|
|
m_killedEntities.UnboundedSet(entity->GetId(), true);
|
|
}
|
|
|
|
/*!
|
|
* \brief Kills a set of entities
|
|
*
|
|
* This function has the same effect as calling KillEntity for every entity contained in the vector
|
|
*
|
|
* \param list Set of entities to kill
|
|
*/
|
|
inline void World::KillEntities(const EntityVector& list)
|
|
{
|
|
for (const EntityHandle& entity : list)
|
|
KillEntity(entity);
|
|
}
|
|
|
|
/*!
|
|
* \brief Gets an entity
|
|
* \return A constant reference to a handle of the entity
|
|
*
|
|
* \param id Identifier of the entity
|
|
*
|
|
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a handle reference from a world update to another
|
|
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
|
|
*/
|
|
inline const EntityHandle& World::GetEntity(EntityId id)
|
|
{
|
|
if (IsEntityIdValid(id))
|
|
return m_entityBlocks[id]->handle;
|
|
else
|
|
{
|
|
NazaraError("Invalid ID");
|
|
return EntityHandle::InvalidHandle;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks whether or not an entity is valid
|
|
* \return true If it is the case
|
|
*
|
|
* \param entity Pointer to the entity
|
|
*/
|
|
|
|
inline bool World::IsEntityValid(const Entity* entity) const
|
|
{
|
|
return entity && entity->GetWorld() == this && IsEntityIdValid(entity->GetId());
|
|
}
|
|
|
|
/*!
|
|
* \brief Checks whether or not an entity is valid
|
|
* \return true If it is the case
|
|
*
|
|
* \param id Identifier of the entity
|
|
*/
|
|
|
|
inline bool World::IsEntityIdValid(EntityId id) const
|
|
{
|
|
return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
|
|
}
|
|
|
|
/*!
|
|
* \brief Removes each system from the world
|
|
*/
|
|
|
|
inline void World::RemoveAllSystems()
|
|
{
|
|
m_systems.clear();
|
|
|
|
InvalidateSystemOrder();
|
|
}
|
|
|
|
/*!
|
|
* \brief Removes a system from the world by index
|
|
*
|
|
* \param index Index of the system
|
|
*
|
|
* \remark No change is done if system is not present
|
|
*/
|
|
|
|
inline void World::RemoveSystem(SystemIndex index)
|
|
{
|
|
if (HasSystem(index))
|
|
{
|
|
m_systems[index].reset();
|
|
|
|
InvalidateSystemOrder();
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* \brief Removes a system from the world by type
|
|
*/
|
|
|
|
template<typename SystemType>
|
|
void World::RemoveSystem()
|
|
{
|
|
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");
|
|
|
|
SystemIndex index = GetSystemIndex<SystemType>();
|
|
RemoveSystem(index);
|
|
}
|
|
|
|
/*!
|
|
* \brief Moves a world into another world object
|
|
* \return A reference to the object
|
|
*/
|
|
|
|
inline World& World::operator=(World&& world) noexcept
|
|
{
|
|
m_aliveEntities = std::move(world.m_aliveEntities);
|
|
m_dirtyEntities = std::move(world.m_dirtyEntities);
|
|
m_entityBlocks = std::move(world.m_entityBlocks);
|
|
m_freeIdList = std::move(world.m_freeIdList);
|
|
m_killedEntities = std::move(world.m_killedEntities);
|
|
m_orderedSystems = std::move(world.m_orderedSystems);
|
|
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
|
|
|
m_entities = std::move(world.m_entities);
|
|
for (EntityBlock& block : m_entities)
|
|
block.entity.SetWorld(this);
|
|
|
|
m_waitingEntities = std::move(world.m_waitingEntities);
|
|
for (auto& blockPtr : m_waitingEntities)
|
|
blockPtr->entity.SetWorld(this);
|
|
|
|
m_systems = std::move(world.m_systems);
|
|
for (const auto& systemPtr : m_systems)
|
|
if (systemPtr)
|
|
systemPtr->SetWorld(this);
|
|
|
|
return *this;
|
|
}
|
|
|
|
inline void World::Invalidate()
|
|
{
|
|
m_dirtyEntities.Resize(m_entityBlocks.size(), false);
|
|
m_dirtyEntities.Set(true); // Activation of all bits
|
|
}
|
|
|
|
inline void World::Invalidate(EntityId id)
|
|
{
|
|
m_dirtyEntities.UnboundedSet(id, true);
|
|
}
|
|
|
|
inline void World::InvalidateSystemOrder()
|
|
{
|
|
m_orderedSystemsUpdated = false;
|
|
}
|
|
}
|