#include "entity.h"
#include "baseapp.h"
#include "restore_entity_handler.h"
#include "server/components.h"
#include "entitydef/entity_call.h"
#include "entitydef/entitydef.h"
#include "../../server/baseapp/baseapp_interface.h"
#include "../../server/cellapp/cellapp_interface.h"
namespace KBEngine{
RestoreEntityHandler::RestoreEntityHandler(COMPONENT_ID cellappID, Network::NetworkInterface & networkInterface):
Task(),
networkInterface_(networkInterface),
entities_(),
inProcess_(false),
restoreSpaces_(),
otherRestoredSpaces_(),
broadcastOtherBaseapps_(false),
tickReport_(0),
spaceIDs_(),
cellappID_(cellappID),
canRestore_(false)
{
}
RestoreEntityHandler::~RestoreEntityHandler()
{
if(inProcess_)
networkInterface_.dispatcher().cancelTask(this);
std::vector<RestoreData>::iterator restoreSpacesIter = otherRestoredSpaces_.begin();
for(; restoreSpacesIter != otherRestoredSpaces_.end(); ++restoreSpacesIter)
{
if((*restoreSpacesIter).cell)
{
Py_DECREF((*restoreSpacesIter).cell);
(*restoreSpacesIter).cell = NULL;
}
}
DEBUG_MSG(fmt::format("RestoreEntityHandler::~RestoreEntityHandler({})\n", cellappID_));
}
void RestoreEntityHandler::pushEntity(ENTITY_ID id)
{
RestoreData data;
data.id = id;
data.creatingCell = false;
data.processed = false;
Entity* pEntity = Baseapp::getSingleton().findEntity(data.id);
if(pEntity && !pEntity->isDestroyed())
{
data.spaceID = pEntity->spaceID();
if(pEntity->isCreatedSpace())
{
restoreSpaces_.push_back(data);
}
else
{
entities_.push_back(data);
}
}
std::vector<SPACE_ID>::const_iterator iter = std::find(spaceIDs_.begin(), spaceIDs_.end(), data.spaceID);
if(iter == spaceIDs_.end())
{
spaceIDs_.push_back(data.spaceID);
}
if(!inProcess_)
{
inProcess_ = true;
networkInterface_.dispatcher().addTask(this);
}
tickReport_ = timestamp();
}
bool RestoreEntityHandler::process()
{
Components::COMPONENTS& cts = Components::getSingleton().getComponents(CELLAPP_TYPE);
Network::Channel* pChannel = NULL;
if(cts.size() > 0)
{
Components::COMPONENTS::iterator ctiter = cts.begin();
if((*ctiter).pChannel == NULL)
{
canRestore(false);
return true;
}
pChannel = (*ctiter).pChannel;
}
if(pChannel == NULL)
{
canRestore(false);
return true;
}
if(!canRestore())
{
if(timestamp() - tickReport_ > uint64( 3 * stampsPerSecond() ))
{
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(CellappInterface::requestRestore);
(*pBundle) << cellappID();
pChannel->send(pBundle);
}
return true;
}
int count = 0;
if(restoreSpaces_.size() > 0)
{
if(timestamp() - tickReport_ > uint64( 3 * stampsPerSecond() ))
{
tickReport_ = timestamp();
INFO_MSG(fmt::format("RestoreEntityHandler::process({2}): wait for localSpace to get cell!, entitiesSize({0}), spaceSize={1}\n",
entities_.size(), restoreSpaces_.size(), cellappID_));
}
int spaceCellCount = 0;
std::vector<RestoreData>::iterator restoreSpacesIter = restoreSpaces_.begin();
for(; restoreSpacesIter != restoreSpaces_.end(); ++restoreSpacesIter)
{
Entity* pEntity = Baseapp::getSingleton().findEntity((*restoreSpacesIter).id);
if(pEntity)
{
if(++count > (int)g_kbeSrvConfig.getBaseApp().entityRestoreSize)
{
return true;
}
if((*restoreSpacesIter).creatingCell == false)
{
(*restoreSpacesIter).creatingCell = true;
pEntity->restoreCell(NULL);
}
else
{
if(pEntity->cellEntityCall() == NULL)
{
return true;
}
else
{
spaceCellCount++;
if(!(*restoreSpacesIter).processed)
{
(*restoreSpacesIter).processed = true;
pEntity->onRestore();
}
}
}
}
else
{
ERROR_MSG(fmt::format("RestoreEntityHandler::process({}): lose space({}).\n", cellappID_, (*restoreSpacesIter).id));
}
}
if(spaceCellCount != static_cast<int>(restoreSpaces_.size()))
return true;
if(!broadcastOtherBaseapps_)
{
broadcastOtherBaseapps_ = true;
INFO_MSG(fmt::format("RestoreEntityHandler::process({}): begin broadcast-spaceGetCell to otherBaseapps...\n", cellappID_));
std::vector<RestoreData>::iterator restoreSpacesIter = restoreSpaces_.begin();
for(; restoreSpacesIter != restoreSpaces_.end(); ++restoreSpacesIter)
{
Entity* pEntity = Baseapp::getSingleton().findEntity((*restoreSpacesIter).id);
bool destroyed = (pEntity == NULL || pEntity->isDestroyed());
COMPONENT_ID baseappID = g_componentID;
COMPONENT_ID cellappID = 0;
SPACE_ID spaceID = (*restoreSpacesIter).spaceID;
ENTITY_ID spaceEntityID = (*restoreSpacesIter).id;
ENTITY_SCRIPT_UID utype = 0;
if(!destroyed)
{
utype = pEntity->pScriptModule()->getUType();
cellappID = pEntity->cellEntityCall()->componentID();
}
spaceIDs_.erase(std::remove(spaceIDs_.begin(), spaceIDs_.end(), spaceID), spaceIDs_.end());
Network::Channel* pChannel = NULL;
Components::COMPONENTS& cts = Components::getSingleton().getComponents(BASEAPP_TYPE);
Components::COMPONENTS::iterator comsiter = cts.begin();
for(; comsiter != cts.end(); ++comsiter)
{
pChannel = (*comsiter).pChannel;
if(pChannel)
{
INFO_MSG(fmt::format("RestoreEntityHandler::process({4}): broadcast baseapp[{0}, {1}], spaceID[{2}], utype[{3}]...\n",
(*comsiter).cid, pChannel->c_str(), spaceID, utype, cellappID_));
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(BaseappInterface::onRestoreSpaceCellFromOtherBaseapp);
(*pBundle) << baseappID << cellappID << spaceID << spaceEntityID << utype << destroyed;
pChannel->send(pBundle);
}
}
}
}
}
if(spaceIDs_.size() > 0)
{
if(timestamp() - tickReport_ > uint64( 3 * stampsPerSecond() ))
{
tickReport_ = timestamp();
INFO_MSG(fmt::format("RestoreEntityHandler::process({}): wait for otherBaseappSpaces to get cell!, entitiesSize({}), spaceSize={}\n",
cellappID_, entities_.size(), spaceIDs_.size()));
}
return true;
}
std::vector<RestoreData>::iterator iter = entities_.begin();
for(; iter != entities_.end(); )
{
RestoreData& data = (*iter);
Entity* pEntity = Baseapp::getSingleton().findEntity(data.id);
if(pEntity)
{
if(++count > g_kbeSrvConfig.getBaseApp().entityRestoreSize)
{
return true;
}
if(pEntity->cellEntityCall() != NULL)
{
if(!data.processed)
{
data.processed = true;
pEntity->onRestore();
}
iter = entities_.erase(iter);
}
else
{
if(!data.creatingCell)
{
data.creatingCell = true;
EntityCallAbstract* cellEntityCall = NULL;
std::vector<RestoreData>::iterator restoreSpacesIter = restoreSpaces_.begin();
for(; restoreSpacesIter != restoreSpaces_.end(); ++restoreSpacesIter)
{
Entity* pSpace = Baseapp::getSingleton().findEntity((*restoreSpacesIter).id);
if(pSpace && pEntity->spaceID() == pSpace->spaceID())
{
cellEntityCall = pSpace->cellEntityCall();
break;
}
}
if(cellEntityCall == NULL)
{
restoreSpacesIter = otherRestoredSpaces_.begin();
for(; restoreSpacesIter != otherRestoredSpaces_.end(); ++restoreSpacesIter)
{
if(pEntity->spaceID() == (*restoreSpacesIter).spaceID && (*restoreSpacesIter).cell)
{
cellEntityCall = (*restoreSpacesIter).cell;
break;
}
}
}
if(cellEntityCall)
{
pEntity->restoreCell(cellEntityCall);
}
else
{
ENTITY_ID delID = pEntity->id();
pEntity->destroy();
WARNING_MSG(fmt::format("RestoreEntityHandler::process({}): not fount spaceCell, killed pEntity({})!",
cellappID_, delID));
if(Baseapp::getSingleton().findEntity(delID) == NULL)
iter = entities_.erase(iter);
continue;
}
}
iter++;
}
}
else
{
iter = entities_.erase(iter);
}
}
if(entities_.size() == 0)
{
std::vector<RestoreData>::iterator restoreSpacesIter = otherRestoredSpaces_.begin();
for(; restoreSpacesIter != otherRestoredSpaces_.end(); ++restoreSpacesIter)
{
if((*restoreSpacesIter).cell)
{
Py_DECREF((*restoreSpacesIter).cell);
(*restoreSpacesIter).cell = NULL;
}
}
otherRestoredSpaces_.clear();
inProcess_ = false;
Baseapp::getSingleton().onRestoreEntitiesOver(this);
return false;
}
return true;
}
void RestoreEntityHandler::onRestoreSpaceCellFromOtherBaseapp(COMPONENT_ID baseappID, COMPONENT_ID cellappID,
SPACE_ID spaceID, ENTITY_ID spaceEntityID, ENTITY_SCRIPT_UID utype, bool destroyed)
{
std::vector<SPACE_ID>::size_type oldsize = spaceIDs_.size();
spaceIDs_.erase(std::remove(spaceIDs_.begin(), spaceIDs_.end(), spaceID), spaceIDs_.end());
if(oldsize == spaceIDs_.size())
return;
RestoreData data;
data.id = spaceEntityID;
data.creatingCell = false;
data.processed = true;
data.spaceID = spaceID;
data.cell = NULL;
if(!destroyed)
{
ScriptDefModule* sm = EntityDef::findScriptModule(utype);
if(sm == NULL)
{
ERROR_MSG(fmt::format("RestoreEntityHandler::onRestoreSpaceCellFromOtherBaseapp({}): not found utype {}!\n",
cellappID_, utype));
}
else
{
if(!destroyed)
data.cell = new EntityCall(sm, NULL, cellappID, spaceEntityID, ENTITYCALL_TYPE_CELL);
}
}
otherRestoredSpaces_.push_back(data);
}
}