mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Some actors are supposed to spawn on a static object that belong to an adjacent cell.
Since actors can be active in 3x3 grid around the player, we need to first load all statics in a 5x5 grid around the player. Split load and unloading in 2 phases. Add an mInactiveCells set into the scene, which contains all cells inside the aforementioned 5x5 grid. These cells contains only heightfields and physics objects of static class.
This commit is contained in:
parent
165c731492
commit
f031a191b8
@ -63,4 +63,9 @@ namespace MWClass
|
||||
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
bool Static::isStatic() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ namespace MWClass
|
||||
static void registerSelf();
|
||||
|
||||
std::string getModel(const MWWorld::ConstPtr &ptr) const override;
|
||||
|
||||
bool isStatic() const override;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -469,7 +469,7 @@ namespace MWPhysics
|
||||
mAnimatedObjects.insert(obj.get());
|
||||
}
|
||||
|
||||
void PhysicsSystem::remove(const MWWorld::Ptr &ptr)
|
||||
void PhysicsSystem::remove(const MWWorld::Ptr &ptr, bool keepObject)
|
||||
{
|
||||
ObjectMap::iterator found = mObjects.find(ptr);
|
||||
if (found != mObjects.end())
|
||||
@ -479,7 +479,8 @@ namespace MWPhysics
|
||||
|
||||
mAnimatedObjects.erase(found->second.get());
|
||||
|
||||
mObjects.erase(found);
|
||||
if (!keepObject)
|
||||
mObjects.erase(found);
|
||||
}
|
||||
|
||||
ActorMap::iterator foundActor = mActors.find(ptr);
|
||||
|
@ -138,7 +138,7 @@ namespace MWPhysics
|
||||
Projectile* getProjectile(int projectileId) const;
|
||||
|
||||
// Object or Actor
|
||||
void remove (const MWWorld::Ptr& ptr);
|
||||
void remove (const MWWorld::Ptr& ptr, bool keepObject = false);
|
||||
|
||||
void updateScale (const MWWorld::Ptr& ptr);
|
||||
void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);
|
||||
|
@ -18,12 +18,23 @@ namespace MWWorld
|
||||
if (ptr.getRefData().getBaseNode())
|
||||
{
|
||||
ptr.getRefData().setBaseNode(nullptr);
|
||||
mObjects.push_back (ptr);
|
||||
}
|
||||
mObjects.push_back (ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ListObjectsVisitor
|
||||
{
|
||||
std::vector<MWWorld::Ptr> mObjects;
|
||||
|
||||
bool operator() (MWWorld::Ptr ptr)
|
||||
{
|
||||
mObjects.push_back (ptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -318,6 +318,10 @@ namespace MWWorld
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isStatic() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
|
||||
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
|
||||
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
||||
|
@ -105,7 +105,7 @@ namespace
|
||||
}
|
||||
|
||||
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
||||
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs)
|
||||
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs, bool onlyPhysics)
|
||||
{
|
||||
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
|
||||
{
|
||||
@ -113,25 +113,29 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
bool useAnim = ptr.getClass().useAnim();
|
||||
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
||||
|
||||
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
||||
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
||||
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
||||
|
||||
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
||||
setNodeRotation(ptr, rendering, rotation);
|
||||
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
||||
if (!onlyPhysics)
|
||||
{
|
||||
bool useAnim = ptr.getClass().useAnim();
|
||||
|
||||
if (useAnim)
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
||||
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
||||
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
||||
|
||||
if (ptr.getClass().isActor())
|
||||
rendering.addWaterRippleEmitter(ptr);
|
||||
setNodeRotation(ptr, rendering, rotation);
|
||||
|
||||
// Restore effect particles
|
||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||
if (useAnim)
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
|
||||
if (ptr.getClass().isActor())
|
||||
rendering.addWaterRippleEmitter(ptr);
|
||||
|
||||
// Restore effect particles
|
||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||
}
|
||||
if (!physics.getObject(ptr))
|
||||
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
||||
}
|
||||
|
||||
void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
|
||||
@ -202,11 +206,12 @@ namespace
|
||||
{
|
||||
MWWorld::CellStore& mCell;
|
||||
Loading::Listener& mLoadingListener;
|
||||
bool mOnlyStatics;
|
||||
bool mTest;
|
||||
|
||||
std::vector<MWWorld::Ptr> mToInsert;
|
||||
|
||||
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test);
|
||||
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test);
|
||||
|
||||
bool operator() (const MWWorld::Ptr& ptr);
|
||||
|
||||
@ -214,8 +219,8 @@ namespace
|
||||
void insert(AddObject&& addObject);
|
||||
};
|
||||
|
||||
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test)
|
||||
: mCell (cell), mLoadingListener (loadingListener), mTest(test)
|
||||
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test)
|
||||
: mCell (cell), mLoadingListener (loadingListener), mOnlyStatics(onlyStatics), mTest(test)
|
||||
{}
|
||||
|
||||
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
||||
@ -231,7 +236,7 @@ namespace
|
||||
{
|
||||
for (MWWorld::Ptr& ptr : mToInsert)
|
||||
{
|
||||
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
|
||||
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled() && ((mOnlyStatics && ptr.getClass().isStatic()) || !mOnlyStatics))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -264,6 +269,16 @@ namespace
|
||||
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
||||
}
|
||||
|
||||
bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection)
|
||||
{
|
||||
for (auto *cell : collection)
|
||||
{
|
||||
assert(cell->getCell()->isExterior());
|
||||
if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -315,15 +330,41 @@ namespace MWWorld
|
||||
mRendering.update (duration, paused);
|
||||
}
|
||||
|
||||
void Scene::unloadCell (CellStoreCollection::iterator iter, bool test)
|
||||
void Scene::unloadInactiveCell (CellStore* cell, bool test)
|
||||
{
|
||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||
if (!test)
|
||||
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription();
|
||||
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
|
||||
|
||||
ListObjectsVisitor visitor;
|
||||
|
||||
cell->forEach(visitor);
|
||||
for (const auto& ptr : visitor.mObjects)
|
||||
mPhysics->remove(ptr);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
const auto cellX = cell->getCell()->getGridX();
|
||||
const auto cellY = cell->getCell()->getGridY();
|
||||
mPhysics->removeHeightField(cellX, cellY);
|
||||
}
|
||||
|
||||
mInactiveCells.erase(cell);
|
||||
}
|
||||
|
||||
void Scene::deactivateCell(CellStore* cell, bool test)
|
||||
{
|
||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||
if (mActiveCells.find(cell) == mActiveCells.end())
|
||||
return;
|
||||
if (!test)
|
||||
Log(Debug::Info) << "Deactivate cell " << cell->getCell()->getDescription();
|
||||
|
||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||
ListAndResetObjectsVisitor visitor;
|
||||
|
||||
(*iter)->forEach(visitor);
|
||||
cell->forEach(visitor);
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
for (const auto& ptr : visitor.mObjects)
|
||||
{
|
||||
@ -334,140 +375,157 @@ namespace MWWorld
|
||||
navigator->removeAgent(world->getPathfindingHalfExtents(ptr));
|
||||
mRendering.removeActorPath(ptr);
|
||||
}
|
||||
mPhysics->remove(ptr);
|
||||
mPhysics->remove(ptr, ptr.getClass().isStatic());
|
||||
}
|
||||
|
||||
const auto cellX = (*iter)->getCell()->getGridX();
|
||||
const auto cellY = (*iter)->getCell()->getGridY();
|
||||
const auto cellX = cell->getCell()->getGridX();
|
||||
const auto cellY = cell->getCell()->getGridY();
|
||||
|
||||
if ((*iter)->getCell()->isExterior())
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->removeObject(DetourNavigator::ObjectId(heightField));
|
||||
mPhysics->removeHeightField(cellX, cellY);
|
||||
}
|
||||
|
||||
if ((*iter)->getCell()->hasWater())
|
||||
if (cell->getCell()->hasWater())
|
||||
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
||||
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell()))
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
navigator->removePathgrid(*pathgrid);
|
||||
|
||||
const auto player = world->getPlayerPtr();
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (cell);
|
||||
|
||||
mRendering.removeCell(*iter);
|
||||
MWBase::Environment::get().getWindowManager()->removeCell(*iter);
|
||||
mRendering.removeCell(cell);
|
||||
MWBase::Environment::get().getWindowManager()->removeCell(cell);
|
||||
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (cell);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->stopSound (*iter);
|
||||
mActiveCells.erase(*iter);
|
||||
MWBase::Environment::get().getSoundManager()->stopSound (cell);
|
||||
mActiveCells.erase(cell);
|
||||
}
|
||||
|
||||
void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
|
||||
void Scene::activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
|
||||
{
|
||||
std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell);
|
||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||
mActiveCells.insert(cell);
|
||||
|
||||
if(result.second)
|
||||
if (test)
|
||||
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
|
||||
else
|
||||
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
||||
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto navigator = world->getNavigator();
|
||||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
|
||||
if (!test && cell->getCell()->isExterior())
|
||||
{
|
||||
if (test)
|
||||
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
|
||||
else
|
||||
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
|
||||
heightField->getCollisionObject()->getWorldTransform());
|
||||
}
|
||||
|
||||
float verts = ESM::Land::LAND_SIZE;
|
||||
float worldsize = ESM::Land::REAL_SIZE;
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
navigator->addPathgrid(*cell->getCell(), *pathgrid);
|
||||
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto navigator = world->getNavigator();
|
||||
// register local scripts
|
||||
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
|
||||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
if (respawn)
|
||||
cell->respawn();
|
||||
|
||||
// Load terrain physics first...
|
||||
if (!test && cell->getCell()->isExterior())
|
||||
insertCell (*cell, loadingListener, false, test);
|
||||
|
||||
mRendering.addCell(cell);
|
||||
if (!test)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->addCell(cell);
|
||||
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
|
||||
float waterLevel = cell->getWaterLevel();
|
||||
mRendering.setWaterEnabled(waterEnabled);
|
||||
if (waterEnabled)
|
||||
{
|
||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||
if (data)
|
||||
mPhysics->enableWater(waterLevel);
|
||||
mRendering.setWaterHeight(waterLevel);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
static std::vector<float> defaultHeight;
|
||||
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
||||
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||
}
|
||||
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
|
||||
heightField->getCollisionObject()->getWorldTransform());
|
||||
}
|
||||
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
navigator->addPathgrid(*cell->getCell(), *pathgrid);
|
||||
|
||||
// register local scripts
|
||||
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
|
||||
|
||||
if (respawn)
|
||||
cell->respawn();
|
||||
|
||||
// ... then references. This is important for adjustPosition to work correctly.
|
||||
insertCell (*cell, loadingListener, test);
|
||||
|
||||
mRendering.addCell(cell);
|
||||
if (!test)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->addCell(cell);
|
||||
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
|
||||
float waterLevel = cell->getWaterLevel();
|
||||
mRendering.setWaterEnabled(waterEnabled);
|
||||
if (waterEnabled)
|
||||
{
|
||||
mPhysics->enableWater(waterLevel);
|
||||
mRendering.setWaterHeight(waterLevel);
|
||||
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
|
||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
|
||||
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
|
||||
}
|
||||
else
|
||||
{
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
|
||||
cell->getWaterLevel(), btTransform::getIdentity());
|
||||
}
|
||||
}
|
||||
else
|
||||
mPhysics->disableWater();
|
||||
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
{
|
||||
|
||||
mRendering.configureAmbient(cell->getCell());
|
||||
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
|
||||
cell->getWaterLevel(), btTransform::getIdentity());
|
||||
}
|
||||
}
|
||||
else
|
||||
mPhysics->disableWater();
|
||||
|
||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||
mRendering.configureAmbient(cell->getCell());
|
||||
}
|
||||
|
||||
mPreloader->notifyLoaded(cell);
|
||||
}
|
||||
|
||||
void Scene::loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test)
|
||||
{
|
||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||
assert(mInactiveCells.find(cell) == mInactiveCells.end());
|
||||
mInactiveCells.insert(cell);
|
||||
|
||||
if (test)
|
||||
Log(Debug::Info) << "Testing inactive cell " << cell->getCell()->getDescription();
|
||||
else
|
||||
Log(Debug::Info) << "Loading inactive cell " << cell->getCell()->getDescription();
|
||||
|
||||
if (!test && cell->getCell()->isExterior())
|
||||
{
|
||||
float verts = ESM::Land::LAND_SIZE;
|
||||
float worldsize = ESM::Land::REAL_SIZE;
|
||||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
|
||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||
if (data)
|
||||
{
|
||||
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
static std::vector<float> defaultHeight;
|
||||
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
||||
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||
}
|
||||
}
|
||||
|
||||
insertCell (*cell, loadingListener, true, test);
|
||||
}
|
||||
|
||||
void Scene::clear()
|
||||
{
|
||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||
while (active!=mActiveCells.end())
|
||||
unloadCell (active++);
|
||||
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
||||
{
|
||||
auto* cell = *iter++;
|
||||
deactivateCell(cell);
|
||||
unloadInactiveCell (cell);
|
||||
}
|
||||
assert(mActiveCells.empty());
|
||||
assert(mInactiveCells.empty());
|
||||
mCurrentCell = nullptr;
|
||||
|
||||
mPreloader->clear();
|
||||
@ -510,20 +568,24 @@ namespace MWWorld
|
||||
|
||||
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
|
||||
{
|
||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||
while (active!=mActiveCells.end())
|
||||
for (auto iter = mInactiveCells.begin(); iter != mInactiveCells.end(); )
|
||||
{
|
||||
if ((*active)->getCell()->isExterior())
|
||||
auto* cell = *iter++;
|
||||
if (cell->getCell()->isExterior())
|
||||
{
|
||||
if (std::abs (playerCellX-(*active)->getCell()->getGridX())<=mHalfGridSize &&
|
||||
std::abs (playerCellY-(*active)->getCell()->getGridY())<=mHalfGridSize)
|
||||
{
|
||||
// keep cells within the new grid
|
||||
++active;
|
||||
continue;
|
||||
}
|
||||
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
|
||||
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
|
||||
if (dx > mHalfGridSize || dy > mHalfGridSize)
|
||||
deactivateCell(cell);
|
||||
|
||||
if (dx > mHalfGridSize+1 || dy > mHalfGridSize+1)
|
||||
unloadInactiveCell(cell);
|
||||
}
|
||||
else
|
||||
{
|
||||
deactivateCell(cell);
|
||||
unloadInactiveCell(cell);
|
||||
}
|
||||
unloadCell (active++);
|
||||
}
|
||||
|
||||
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
||||
@ -535,32 +597,24 @@ namespace MWWorld
|
||||
mRendering.getPagedRefnums(newGrid, mPagedRefs);
|
||||
|
||||
std::size_t refsToLoad = 0;
|
||||
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
||||
// get the number of refs to load
|
||||
for (int x = playerCellX - mHalfGridSize; x <= playerCellX + mHalfGridSize; ++x)
|
||||
const auto cellsToLoad = [&playerCellX,&playerCellY,&refsToLoad](CellStoreCollection& collection, int range) -> std::vector<std::pair<int,int>>
|
||||
{
|
||||
for (int y = playerCellY - mHalfGridSize; y <= playerCellY + mHalfGridSize; ++y)
|
||||
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
||||
for (int x = playerCellX - range; x <= playerCellX + range; ++x)
|
||||
{
|
||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||
|
||||
while (iter!=mActiveCells.end())
|
||||
for (int y = playerCellY - range; y <= playerCellY + range; ++y)
|
||||
{
|
||||
assert ((*iter)->getCell()->isExterior());
|
||||
|
||||
if (x==(*iter)->getCell()->getGridX() &&
|
||||
y==(*iter)->getCell()->getGridY())
|
||||
break;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (iter==mActiveCells.end())
|
||||
{
|
||||
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
|
||||
cellsPositionsToLoad.emplace_back(x, y);
|
||||
if (!isCellInCollection(x, y, collection))
|
||||
{
|
||||
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
|
||||
cellsPositionsToLoad.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cellsPositionsToLoad;
|
||||
};
|
||||
auto cellsPositionsToLoad = cellsToLoad(mActiveCells,mHalfGridSize);
|
||||
auto cellsPositionsToLoadInactive = cellsToLoad(mInactiveCells,mHalfGridSize+1);
|
||||
|
||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
Loading::ScopedLoad load(loadingListener);
|
||||
@ -584,30 +638,26 @@ namespace MWWorld
|
||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||
});
|
||||
|
||||
std::sort(cellsPositionsToLoadInactive.begin(), cellsPositionsToLoadInactive.end(),
|
||||
[&] (const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
|
||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||
});
|
||||
|
||||
// Load cells
|
||||
for (const auto& cellPosition : cellsPositionsToLoad)
|
||||
for (const auto& [x,y] : cellsPositionsToLoadInactive)
|
||||
{
|
||||
const auto x = cellPosition.first;
|
||||
const auto y = cellPosition.second;
|
||||
|
||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||
|
||||
while (iter != mActiveCells.end())
|
||||
{
|
||||
assert ((*iter)->getCell()->isExterior());
|
||||
|
||||
if (x == (*iter)->getCell()->getGridX() &&
|
||||
y == (*iter)->getCell()->getGridY())
|
||||
break;
|
||||
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (iter == mActiveCells.end())
|
||||
if (!isCellInCollection(x, y, mInactiveCells))
|
||||
{
|
||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
||||
|
||||
loadCell (cell, loadingListener, changeEvent);
|
||||
loadInactiveCell (cell, loadingListener);
|
||||
}
|
||||
}
|
||||
for (const auto& [x,y] : cellsPositionsToLoad)
|
||||
{
|
||||
if (!isCellInCollection(x, y, mActiveCells))
|
||||
{
|
||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
||||
activateCell (cell, loadingListener, changeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,7 +690,8 @@ namespace MWWorld
|
||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||
|
||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
|
||||
loadCell (cell, loadingListener, false, true);
|
||||
loadInactiveCell (cell, loadingListener, true);
|
||||
activateCell (cell, loadingListener, false, true);
|
||||
|
||||
iter = mActiveCells.begin();
|
||||
while (iter != mActiveCells.end())
|
||||
@ -648,7 +699,8 @@ namespace MWWorld
|
||||
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
|
||||
it->mData.mY == (*iter)->getCell()->getGridY())
|
||||
{
|
||||
unloadCell(iter, true);
|
||||
deactivateCell(*iter, true);
|
||||
unloadInactiveCell (*iter, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -686,7 +738,8 @@ namespace MWWorld
|
||||
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
|
||||
|
||||
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
|
||||
loadCell (cell, loadingListener, false, true);
|
||||
loadInactiveCell (cell, loadingListener, true);
|
||||
activateCell (cell, loadingListener, false, true);
|
||||
|
||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||
while (iter != mActiveCells.end())
|
||||
@ -695,7 +748,8 @@ namespace MWWorld
|
||||
|
||||
if (it->mName == (*iter)->getCell()->mName)
|
||||
{
|
||||
unloadCell(iter, true);
|
||||
deactivateCell(*iter, true);
|
||||
unloadInactiveCell (*iter, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -818,15 +872,21 @@ namespace MWWorld
|
||||
Log(Debug::Info) << "Changing to interior";
|
||||
|
||||
// unload
|
||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
||||
while (active!=mActiveCells.end())
|
||||
unloadCell (active++);
|
||||
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
||||
{
|
||||
auto* cell = *iter++;
|
||||
deactivateCell(cell);
|
||||
unloadInactiveCell(cell);
|
||||
}
|
||||
assert(mActiveCells.empty());
|
||||
assert(mInactiveCells.empty());
|
||||
|
||||
loadingListener->setProgressRange(cell->count());
|
||||
|
||||
// Load cell.
|
||||
mPagedRefs.clear();
|
||||
loadCell (cell, loadingListener, changeEvent);
|
||||
loadInactiveCell (cell, loadingListener);
|
||||
activateCell (cell, loadingListener, changeEvent);
|
||||
|
||||
changePlayerCell(cell, position, adjustPlayerPos);
|
||||
|
||||
@ -874,23 +934,26 @@ namespace MWWorld
|
||||
mCellChanged = false;
|
||||
}
|
||||
|
||||
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test)
|
||||
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test)
|
||||
{
|
||||
InsertVisitor insertVisitor (cell, *loadingListener, test);
|
||||
InsertVisitor insertVisitor (cell, *loadingListener, onlyStatics, test);
|
||||
cell.forEach (insertVisitor);
|
||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); });
|
||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs, onlyStatics); });
|
||||
if (!onlyStatics)
|
||||
{
|
||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
||||
|
||||
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
|
||||
PositionVisitor posVisitor;
|
||||
cell.forEach (posVisitor);
|
||||
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
|
||||
PositionVisitor posVisitor;
|
||||
cell.forEach (posVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::addObjectToScene (const Ptr& ptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
addObject(ptr, *mPhysics, mRendering, mPagedRefs);
|
||||
addObject(ptr, *mPhysics, mRendering, mPagedRefs, false);
|
||||
addObject(ptr, *mPhysics, mNavigator);
|
||||
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||
|
@ -65,13 +65,13 @@ namespace MWWorld
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::set<CellStore *> CellStoreCollection;
|
||||
using CellStoreCollection = std::set<CellStore *>;
|
||||
|
||||
private:
|
||||
|
||||
CellStore* mCurrentCell; // the cell the player is in
|
||||
CellStoreCollection mActiveCells;
|
||||
CellStoreCollection mInactiveCells;
|
||||
bool mCellChanged;
|
||||
MWPhysics::PhysicsSystem *mPhysics;
|
||||
MWRender::RenderingManager& mRendering;
|
||||
@ -92,7 +92,7 @@ namespace MWWorld
|
||||
|
||||
std::set<ESM::RefNum> mPagedRefs;
|
||||
|
||||
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false);
|
||||
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test = false);
|
||||
osg::Vec2i mCurrentGridCenter;
|
||||
|
||||
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
|
||||
@ -108,6 +108,11 @@ namespace MWWorld
|
||||
osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const;
|
||||
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
|
||||
|
||||
void unloadInactiveCell (CellStore* cell, bool test = false);
|
||||
void deactivateCell (CellStore* cell, bool test = false);
|
||||
void activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
|
||||
void loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test = false);
|
||||
|
||||
public:
|
||||
|
||||
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
|
||||
@ -119,10 +124,6 @@ namespace MWWorld
|
||||
void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
|
||||
void reloadTerrain();
|
||||
|
||||
void unloadCell (CellStoreCollection::iterator iter, bool test = false);
|
||||
|
||||
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
|
||||
|
||||
void playerMoved (const osg::Vec3f& pos);
|
||||
|
||||
void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos);
|
||||
|
Loading…
x
Reference in New Issue
Block a user