#include "CEntitiesManager.h" #include "CEngine.h" #include "CGame.h" #include "CServer.h" #include "CClient.h" #include #include CEntitiesManager::CEntitiesManager(worldid_t worldid) : WorldID(worldid) {} bool CEntitiesManager::m_isValidWorld(worldid_t worldid) { auto game = CEngine::GetInstance()->Components.GetComponentTyped(); 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(); auto world = game->Worlds.GetWorld(GetWorldID()); if(!world) { return CEntityHandle(); } std::unique_ptr ent = CEngine::GetInstance()->EntitiesFactory.create>(type); if(!ent) { return CEntityHandle(); } return m_addEntity(std::move(ent), sync); } CEntityHandle CEntitiesManager::m_addEntity(std::unique_ptr&& ent, bool sync) { entityid_t id = GetNextFreeID(); Items.insert({ id, std::move(ent) }); Items[id]->OverridePersistent(random::random_static::get(), 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(); if(server && sync) { auto msg = std::make_shared(); 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(); if(server && handle.Get()->IsNetSync()) { auto msg = std::make_shared(); msg->Entity = CEntityHandle(it->second.get()); server->SendReliableMessageToAll(msg); //TODO should be reliable } Items.erase(it); } } void CEntitiesManager::Trace(const std::function& func) { for(auto& kv : Items) { func(kv.second.get()); } } entityid_t CEntitiesManager::GetNextFreeID() const { for(entityid_t i = 0; i < std::numeric_limits::max(); i++) { if (Items.find(i) == Items.end()) { return i; } } return std::numeric_limits::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(entity->GetUUID()); wrapper.Write(entityType); std::vector _ent_data; CBufferWrapper _ent_wrapper(_ent_data); entity->FullPack(_ent_wrapper); wrapper.Write(_ent_data.size()); wrapper.WriteData(_ent_data.data(), _ent_data.size()); std::vector toWrite; for(auto& kv : entity->Components.Items) { if(kv.second->NetSync) { toWrite.push_back(kv.second.get()); } } wrapper.Write(toWrite.size()); for(auto comp : toWrite) { auto compType = cmpfactory.GetIndex(comp->GetType()); wrapper.Write(compType); std::vector _comp_data; CBufferWrapper _comp_wrapper(_comp_data); comp->FullPack(_comp_wrapper); wrapper.Write(_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 enttype = wrapper.Read(); ServerEntityID = entid; auto& entfactory = CEngine::GetInstance()->EntitiesFactory; auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory; auto game = CEngine::GetInstance()->Components.GetComponentTyped(); 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(); auto _entData = wrapper.ReadData(entSize); std::vector entData(_entData.get(), _entData.get() + entSize); EntityData.Type = entstype; EntityData.Data = std::move(entData); std::uint16_t compsCount = wrapper.Read(); for(std::uint16_t i = 0; i < compsCount; i++) { std::uint16_t compType = wrapper.Read(); auto compstype = cmpfactory.GetByID(compType); if(compstype.empty()) { Log::ErrInstance() << "Component invalid type\n"; //TODO disconnect -- fatal! } auto compSize = wrapper.Read(); auto _compData = wrapper.ReadData(compSize); std::vector 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(); if(!client) { return; } auto game = CEngine::GetInstance()->Components.GetComponentTyped(); 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(entity->GetUUID()); wrapper.Write(entityType); } void CNetEntityStop::V_Read(CBufferWrapper& wrapper) { auto client = CEngine::GetInstance()->Components.GetComponentTyped(); if(!client) { return; } std::uint16_t _entid = wrapper.Read(); std::uint16_t enttype = wrapper.Read(); std::uint16_t entid = client->ServerEntityMap[_entid]; auto& entfactory = CEngine::GetInstance()->EntitiesFactory; auto& cmpfactory = CEngine::GetInstance()->EntityComponentsFactory; auto game = CEngine::GetInstance()->Components.GetComponentTyped(); 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(); 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);