← Back to file list Raw

src/CEntitiesManager.cpp

#include "CEntitiesManager.h"
#include "CEngine.h"
#include "CGame.h"
#include "CServer.h"
#include "CClient.h"
#include <limits>
#include <algorithm>
CEntitiesManager::CEntitiesManager(worldid_t worldid) : WorldID(worldid) {}
bool CEntitiesManager::m_isValidWorld(worldid_t worldid)
{
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld(GetWorldID());
return world;
}
worldid_t CEntitiesManager::GetWorldID() const
{
return WorldID;
}
size_t CEntitiesManager::Count() const
{
return Items.size();
}
CEntityHandle CEntitiesManager::CreateEntity(const std::string& type, bool sync)
{
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld(GetWorldID());
if(!world) { return CEntityHandle(); }
std::unique_ptr<CEntity> ent = CEngine::GetInstance()->EntitiesFactory.create<std::unique_ptr<CEntity>>(type);
if(!ent) { return CEntityHandle(); }
return m_addEntity(std::move(ent), sync);
}
CEntityHandle CEntitiesManager::m_addEntity(std::unique_ptr<CEntity>&& ent, bool sync)
{
entityid_t id = GetNextFreeID();
Items.insert({ id, std::move(ent) });
Items[id]->OverridePersistent(random::random_static::get<serial_t>(), id, GetWorldID());
Items[id]->SetNetSync(sync, false);
for(auto& kv : initParams)
{
Items[id]->AddInitParam(kv.first, kv.second);
Log::Instance() << "Passing " << kv.first << " to entity " << Items[id]->GetType() << Log::Endl;
}
ClearNextEntityParams();
Items[id]->Init();
auto server = CEngine::GetInstance()->Components.GetComponentTyped<CServer>();
if(server && sync)
{
auto msg = std::make_shared<CNetEntityStart>();
msg->Entity = CEntityHandle(Items[id].get());
server->SendReliableMessageToAll(msg); //TODO should be reliable
}
Items[id]->PostInit();
return CEntityHandle(Items[id].get());
}
void CEntitiesManager::DeleteEntity(const CEntityHandle& handle)
{
auto it = std::find_if(Items.begin(), Items.end(), [&handle](auto& kv)
{
return handle == kv.second.get();
});
if(it != Items.end())
{
auto server = CEngine::GetInstance()->Components.GetComponentTyped<CServer>();
if(server && handle.Get()->IsNetSync())
{
auto msg = std::make_shared<CNetEntityStop>();
msg->Entity = CEntityHandle(it->second.get());
server->SendReliableMessageToAll(msg); //TODO should be reliable
}
Items.erase(it);
}
}
void CEntitiesManager::Trace(const std::function<void(CEntity* ent)>& func)
{
for(auto& kv : Items)
{
func(kv.second.get());
}
}
entityid_t CEntitiesManager::GetNextFreeID() const
{
for(entityid_t i = 0; i < std::numeric_limits<entityid_t>::max(); i++)
{
if (Items.find(i) == Items.end())
{
return i;
}
}
return std::numeric_limits<entityid_t>::max();
}
void CNetEntityStart::V_Write(CBufferWrapper& wrapper)
{
auto entity = Entity.Get();
auto& entfactory = CEngine::GetInstance()->EntitiesFactory;
auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory;
auto entityType = entfactory.GetIndex(entity->GetType());
wrapper.Write<std::uint16_t>(entity->GetUUID());
wrapper.Write<std::uint16_t>(entityType);
std::vector<std::uint8_t> _ent_data;
CBufferWrapper _ent_wrapper(_ent_data);
entity->FullPack(_ent_wrapper);
wrapper.Write<std::uint16_t>(_ent_data.size());
wrapper.WriteData(_ent_data.data(), _ent_data.size());
std::vector<CEntityComponent*> toWrite;
for(auto& kv : entity->Components.Items)
{
if(kv.second->NetSync)
{
toWrite.push_back(kv.second.get());
}
}
wrapper.Write<std::uint16_t>(toWrite.size());
for(auto comp : toWrite)
{
auto compType = cmpfactory.GetIndex(comp->GetType());
wrapper.Write<std::uint16_t>(compType);
std::vector<std::uint8_t> _comp_data;
CBufferWrapper _comp_wrapper(_comp_data);
comp->FullPack(_comp_wrapper);
wrapper.Write<std::uint16_t>(_comp_data.size());
wrapper.WriteData(_comp_data.data(), _comp_data.size());
}
}
void CNetEntityStart::V_Read(CBufferWrapper& wrapper)
{
std::uint16_t entid = wrapper.Read<std::uint16_t>();
std::uint16_t enttype = wrapper.Read<std::uint16_t>();
ServerEntityID = entid;
auto& entfactory = CEngine::GetInstance()->EntitiesFactory;
auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory;
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld();
auto it = std::find_if(world->Entities.Items.begin(), world->Entities.Items.end(), [entid](auto& kv) -> bool
{
return kv.second->GetUUID() == entid;
});
if(it != world->Entities.Items.end())
{
Log::ErrInstance() << "Entity ID duplicate\n"; //TODO disconnect -- fatal!
}
auto entstype = entfactory.GetByID(enttype);
if(entstype.empty())
{
Log::ErrInstance() << "Entity invalid type\n"; //TODO disconnect -- fatal!
}
auto entSize = wrapper.Read<std::uint16_t>();
auto _entData = wrapper.ReadData(entSize);
std::vector<std::uint8_t> entData(_entData.get(), _entData.get() + entSize);
EntityData.Type = entstype;
EntityData.Data = std::move(entData);
std::uint16_t compsCount = wrapper.Read<std::uint16_t>();
for(std::uint16_t i = 0; i < compsCount; i++)
{
std::uint16_t compType = wrapper.Read<std::uint16_t>();
auto compstype = cmpfactory.GetByID(compType);
if(compstype.empty())
{
Log::ErrInstance() << "Component invalid type\n"; //TODO disconnect -- fatal!
}
auto compSize = wrapper.Read<std::uint16_t>();
auto _compData = wrapper.ReadData(compSize);
std::vector<std::uint8_t> compData(_compData.get(), _compData.get() + compSize);
CData ccompData;
ccompData.Type = compstype;
ccompData.Data = std::move(compData);
ComponentsData.push_back(std::move(ccompData));
}
}
void CNetEntityStart::Process()
{
auto client = CEngine::GetInstance()->Components.GetComponentTyped<CClient>();
if(!client) { return; }
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld();
auto enth = world->Entities.CreateEntity(EntityData.Type);
auto ent = enth.Get();
client->ServerEntityMap.emplace(ServerEntityID, ent->GetUUID());
CBufferWrapper entData(EntityData.Data);
ent->FullUnpack(entData);
for(auto& _comp : ComponentsData)
{
ent->Components.CreateComponent(_comp.Type, false);
auto& comp = ent->Components.GetComponent(_comp.Type);
CBufferWrapper compData(_comp.Data);
comp->FullUnpack(compData);
comp->Init();
}
}
void CNetEntityStop::V_Write(CBufferWrapper& wrapper)
{
auto entity = Entity.Get();
auto& entfactory = CEngine::GetInstance()->EntitiesFactory;
auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory;
auto entityType = entfactory.GetIndex(entity->GetType());
wrapper.Write<std::uint16_t>(entity->GetUUID());
wrapper.Write<std::uint16_t>(entityType);
}
void CNetEntityStop::V_Read(CBufferWrapper& wrapper)
{
auto client = CEngine::GetInstance()->Components.GetComponentTyped<CClient>();
if(!client) { return; }
std::uint16_t _entid = wrapper.Read<std::uint16_t>();
std::uint16_t enttype = wrapper.Read<std::uint16_t>();
std::uint16_t entid = client->ServerEntityMap[_entid];
auto& entfactory = CEngine::GetInstance()->EntitiesFactory;
auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory;
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld();
auto it = std::find_if(world->Entities.Items.begin(), world->Entities.Items.end(), [entid](auto& kv) -> bool
{
return kv.second->GetUUID() == entid;
});
if(it == world->Entities.Items.end())
{
Log::ErrInstance() << "No such entity\n"; //TODO disconnect -- fatal!
}
auto entstype = entfactory.GetByID(enttype);
if(entstype.empty())
{
Log::ErrInstance() << "Entity invalid type\n"; //TODO disconnect -- fatal!
}
auto& entity = it->second;
if(entity->GetType() != entstype)
{
Log::ErrInstance() << "Entity type mismatch\n"; //TODO disconnect -- fatal!
}
Entity = CEntityHandle(entity.get());
}
void CNetEntityStop::Process()
{
if(!Entity.IsValid()) { return; }
auto game = CEngine::GetInstance()->Components.GetComponentTyped<CGame>();
auto world = game->Worlds.GetWorld();
world->Entities.DeleteEntity(Entity);
}
void CEntitiesManager::SetNextEntityInitParam(const std::string& name, CWrapableBase* wrapable)
{
initParams.emplace(name, wrapable);
}
void CEntitiesManager::ClearNextEntityParams()
{
initParams.clear();
}
CEntityHandle CEntitiesManager::GetEntityByID(entityid_t id)
{
auto it = std::find_if(Items.begin(), Items.end(), [id](auto& kv) { return kv.first == id && kv.second && kv.second->GetUUID() == id; });
if(it == Items.end()) { return CEntityHandle(); }
return CEntityHandle(it->second.get());
}
LINK_NET_MESSAGE_TO_CLASS(CNetEntityStart, entitystart);
LINK_NET_MESSAGE_TO_CLASS(CNetEntityStop, entitystop);