1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-02 00:36:42 +00:00

Revert "Some actors are supposed to spawn on a static object that belong to an adjacent cell."

This reverts commit f031a191b8.
This commit is contained in:
Andrei Kortunov 2021-01-29 16:51:05 +04:00
parent 8019fd594d
commit 165af1c365
8 changed files with 190 additions and 277 deletions

View file

@ -63,9 +63,4 @@ namespace MWClass
return MWWorld::Ptr(cell.insert(ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Static::isStatic() const
{
return true;
}
} }

View file

@ -25,8 +25,6 @@ namespace MWClass
static void registerSelf(); static void registerSelf();
std::string getModel(const MWWorld::ConstPtr &ptr) const override; std::string getModel(const MWWorld::ConstPtr &ptr) const override;
bool isStatic() const override;
}; };
} }

View file

@ -469,7 +469,7 @@ namespace MWPhysics
mAnimatedObjects.insert(obj.get()); mAnimatedObjects.insert(obj.get());
} }
void PhysicsSystem::remove(const MWWorld::Ptr &ptr, bool keepObject) void PhysicsSystem::remove(const MWWorld::Ptr &ptr)
{ {
ObjectMap::iterator found = mObjects.find(ptr); ObjectMap::iterator found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
@ -479,8 +479,7 @@ namespace MWPhysics
mAnimatedObjects.erase(found->second.get()); mAnimatedObjects.erase(found->second.get());
if (!keepObject) mObjects.erase(found);
mObjects.erase(found);
} }
ActorMap::iterator foundActor = mActors.find(ptr); ActorMap::iterator foundActor = mActors.find(ptr);

View file

@ -138,7 +138,7 @@ namespace MWPhysics
Projectile* getProjectile(int projectileId) const; Projectile* getProjectile(int projectileId) const;
// Object or Actor // Object or Actor
void remove (const MWWorld::Ptr& ptr, bool keepObject = false); void remove (const MWWorld::Ptr& ptr);
void updateScale (const MWWorld::Ptr& ptr); void updateScale (const MWWorld::Ptr& ptr);
void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate); void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);

View file

@ -18,23 +18,12 @@ namespace MWWorld
if (ptr.getRefData().getBaseNode()) if (ptr.getRefData().getBaseNode())
{ {
ptr.getRefData().setBaseNode(nullptr); ptr.getRefData().setBaseNode(nullptr);
mObjects.push_back (ptr);
} }
mObjects.push_back (ptr);
return true; return true;
} }
}; };
struct ListObjectsVisitor
{
std::vector<MWWorld::Ptr> mObjects;
bool operator() (MWWorld::Ptr ptr)
{
mObjects.push_back (ptr);
return true;
}
};
} }
#endif #endif

View file

@ -318,10 +318,6 @@ namespace MWWorld
return false; return false;
} }
virtual bool isStatic() const {
return false;
}
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;

View file

@ -105,7 +105,7 @@ namespace
} }
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs, bool onlyPhysics) MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs)
{ {
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr)) if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
{ {
@ -113,29 +113,25 @@ namespace
return; return;
} }
bool useAnim = ptr.getClass().useAnim();
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS()); 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); const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
if (!onlyPhysics) setNodeRotation(ptr, rendering, rotation);
{ ptr.getClass().insertObject (ptr, model, rotation, physics);
bool useAnim = ptr.getClass().useAnim();
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum(); if (useAnim)
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end()) MWBase::Environment::get().getMechanicsManager()->add(ptr);
ptr.getClass().insertObjectRendering(ptr, model, rendering);
setNodeRotation(ptr, rendering, rotation); if (ptr.getClass().isActor())
rendering.addWaterRippleEmitter(ptr);
if (useAnim) // Restore effect particles
MWBase::Environment::get().getMechanicsManager()->add(ptr); MWBase::Environment::get().getWorld()->applyLoopingParticles(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) void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
@ -206,12 +202,11 @@ namespace
{ {
MWWorld::CellStore& mCell; MWWorld::CellStore& mCell;
Loading::Listener& mLoadingListener; Loading::Listener& mLoadingListener;
bool mOnlyStatics;
bool mTest; bool mTest;
std::vector<MWWorld::Ptr> mToInsert; std::vector<MWWorld::Ptr> mToInsert;
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test); InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test);
bool operator() (const MWWorld::Ptr& ptr); bool operator() (const MWWorld::Ptr& ptr);
@ -219,8 +214,8 @@ namespace
void insert(AddObject&& addObject); void insert(AddObject&& addObject);
}; };
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test) InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test)
: mCell (cell), mLoadingListener (loadingListener), mOnlyStatics(onlyStatics), mTest(test) : mCell (cell), mLoadingListener (loadingListener), mTest(test)
{} {}
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
@ -236,7 +231,7 @@ namespace
{ {
for (MWWorld::Ptr& ptr : mToInsert) for (MWWorld::Ptr& ptr : mToInsert)
{ {
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled() && ((mOnlyStatics && ptr.getClass().isStatic()) || !mOnlyStatics)) if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
{ {
try try
{ {
@ -269,16 +264,6 @@ namespace
return std::abs(cellPosition.first) + std::abs(cellPosition.second); 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;
}
} }
@ -330,41 +315,15 @@ namespace MWWorld
mRendering.update (duration, paused); mRendering.update (duration, paused);
} }
void Scene::unloadInactiveCell (CellStore* cell, bool test) void Scene::unloadCell (CellStoreCollection::iterator iter, bool test)
{ {
assert(mActiveCells.find(cell) == mActiveCells.end());
assert(mInactiveCells.find(cell) != mInactiveCells.end());
if (!test) if (!test)
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription(); Log(Debug::Info) << "Unloading cell " << (*iter)->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(); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
ListAndResetObjectsVisitor visitor; ListAndResetObjectsVisitor visitor;
cell->forEach(visitor); (*iter)->forEach(visitor);
const auto world = MWBase::Environment::get().getWorld(); const auto world = MWBase::Environment::get().getWorld();
for (const auto& ptr : visitor.mObjects) for (const auto& ptr : visitor.mObjects)
{ {
@ -375,157 +334,140 @@ namespace MWWorld
navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); navigator->removeAgent(world->getPathfindingHalfExtents(ptr));
mRendering.removeActorPath(ptr); mRendering.removeActorPath(ptr);
} }
mPhysics->remove(ptr, ptr.getClass().isStatic()); mPhysics->remove(ptr);
} }
const auto cellX = cell->getCell()->getGridX(); const auto cellX = (*iter)->getCell()->getGridX();
const auto cellY = cell->getCell()->getGridY(); const auto cellY = (*iter)->getCell()->getGridY();
if (cell->getCell()->isExterior()) if ((*iter)->getCell()->isExterior())
{ {
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->removeObject(DetourNavigator::ObjectId(heightField)); navigator->removeObject(DetourNavigator::ObjectId(heightField));
mPhysics->removeHeightField(cellX, cellY);
} }
if (cell->getCell()->hasWater()) if ((*iter)->getCell()->hasWater())
navigator->removeWater(osg::Vec2i(cellX, cellY)); navigator->removeWater(osg::Vec2i(cellX, cellY));
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell())) if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell()))
navigator->removePathgrid(*pathgrid); navigator->removePathgrid(*pathgrid);
const auto player = world->getPlayerPtr(); const auto player = world->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3()); navigator->update(player.getRefData().getPosition().asVec3());
MWBase::Environment::get().getMechanicsManager()->drop (cell); MWBase::Environment::get().getMechanicsManager()->drop (*iter);
mRendering.removeCell(cell); mRendering.removeCell(*iter);
MWBase::Environment::get().getWindowManager()->removeCell(cell); MWBase::Environment::get().getWindowManager()->removeCell(*iter);
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (cell); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
MWBase::Environment::get().getSoundManager()->stopSound (cell); MWBase::Environment::get().getSoundManager()->stopSound (*iter);
mActiveCells.erase(cell); mActiveCells.erase(*iter);
} }
void Scene::activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test) void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
{ {
assert(mActiveCells.find(cell) == mActiveCells.end()); std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell);
assert(mInactiveCells.find(cell) != mInactiveCells.end());
mActiveCells.insert(cell);
if (test) if(result.second)
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 (const auto heightField = mPhysics->getHeightField(cellX, cellY)) if (test)
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(), Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
heightField->getCollisionObject()->getWorldTransform()); else
} Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell())) float verts = ESM::Land::LAND_SIZE;
navigator->addPathgrid(*cell->getCell(), *pathgrid); float worldsize = ESM::Land::REAL_SIZE;
// register local scripts const auto world = MWBase::Environment::get().getWorld();
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice const auto navigator = world->getNavigator();
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
if (respawn) const int cellX = cell->getCell()->getGridX();
cell->respawn(); const int cellY = cell->getCell()->getGridY();
insertCell (*cell, loadingListener, false, test); // Load terrain physics first...
if (!test && cell->getCell()->isExterior())
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); osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
mRendering.setWaterHeight(waterLevel); const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
if (data)
if (cell->getCell()->isExterior())
{ {
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
} }
else else
{ {
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(), 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,
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
}
else
{
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
cell->getWaterLevel(), btTransform::getIdentity()); 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());
} }
} }
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); 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() void Scene::clear()
{ {
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); ) CellStoreCollection::iterator active = mActiveCells.begin();
{ while (active!=mActiveCells.end())
auto* cell = *iter++; unloadCell (active++);
deactivateCell(cell);
unloadInactiveCell (cell);
}
assert(mActiveCells.empty()); assert(mActiveCells.empty());
assert(mInactiveCells.empty());
mCurrentCell = nullptr; mCurrentCell = nullptr;
mPreloader->clear(); mPreloader->clear();
@ -568,24 +510,20 @@ namespace MWWorld
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent) void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
{ {
for (auto iter = mInactiveCells.begin(); iter != mInactiveCells.end(); ) CellStoreCollection::iterator active = mActiveCells.begin();
while (active!=mActiveCells.end())
{ {
auto* cell = *iter++; if ((*active)->getCell()->isExterior())
if (cell->getCell()->isExterior())
{ {
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX()); if (std::abs (playerCellX-(*active)->getCell()->getGridX())<=mHalfGridSize &&
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY()); std::abs (playerCellY-(*active)->getCell()->getGridY())<=mHalfGridSize)
if (dx > mHalfGridSize || dy > mHalfGridSize) {
deactivateCell(cell); // keep cells within the new grid
++active;
if (dx > mHalfGridSize+1 || dy > mHalfGridSize+1) continue;
unloadInactiveCell(cell); }
}
else
{
deactivateCell(cell);
unloadInactiveCell(cell);
} }
unloadCell (active++);
} }
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
@ -597,24 +535,32 @@ namespace MWWorld
mRendering.getPagedRefnums(newGrid, mPagedRefs); mRendering.getPagedRefnums(newGrid, mPagedRefs);
std::size_t refsToLoad = 0; std::size_t refsToLoad = 0;
const auto cellsToLoad = [&playerCellX,&playerCellY,&refsToLoad](CellStoreCollection& collection, int range) -> std::vector<std::pair<int,int>> std::vector<std::pair<int, int>> cellsPositionsToLoad;
// get the number of refs to load
for (int x = playerCellX - mHalfGridSize; x <= playerCellX + mHalfGridSize; ++x)
{ {
std::vector<std::pair<int, int>> cellsPositionsToLoad; for (int y = playerCellY - mHalfGridSize; y <= playerCellY + mHalfGridSize; ++y)
for (int x = playerCellX - range; x <= playerCellX + range; ++x)
{ {
for (int y = playerCellY - range; y <= playerCellY + range; ++y) CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter!=mActiveCells.end())
{ {
if (!isCellInCollection(x, y, collection)) assert ((*iter)->getCell()->isExterior());
{
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count(); if (x==(*iter)->getCell()->getGridX() &&
cellsPositionsToLoad.emplace_back(x, y); y==(*iter)->getCell()->getGridY())
} break;
++iter;
}
if (iter==mActiveCells.end())
{
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::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener); Loading::ScopedLoad load(loadingListener);
@ -638,26 +584,30 @@ namespace MWWorld
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs); 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 // Load cells
for (const auto& [x,y] : cellsPositionsToLoadInactive) for (const auto& cellPosition : cellsPositionsToLoad)
{ {
if (!isCellInCollection(x, y, mInactiveCells)) const auto x = cellPosition.first;
const auto y = cellPosition.second;
CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter != mActiveCells.end())
{ {
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); assert ((*iter)->getCell()->isExterior());
loadInactiveCell (cell, loadingListener);
if (x == (*iter)->getCell()->getGridX() &&
y == (*iter)->getCell()->getGridY())
break;
++iter;
} }
}
for (const auto& [x,y] : cellsPositionsToLoad) if (iter == mActiveCells.end())
{
if (!isCellInCollection(x, y, mActiveCells))
{ {
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
activateCell (cell, loadingListener, changeEvent);
loadCell (cell, loadingListener, changeEvent);
} }
} }
@ -690,8 +640,7 @@ namespace MWWorld
CellStoreCollection::iterator iter = mActiveCells.begin(); CellStoreCollection::iterator iter = mActiveCells.begin();
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY); CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
loadInactiveCell (cell, loadingListener, true); loadCell (cell, loadingListener, false, true);
activateCell (cell, loadingListener, false, true);
iter = mActiveCells.begin(); iter = mActiveCells.begin();
while (iter != mActiveCells.end()) while (iter != mActiveCells.end())
@ -699,8 +648,7 @@ namespace MWWorld
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() && if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
it->mData.mY == (*iter)->getCell()->getGridY()) it->mData.mY == (*iter)->getCell()->getGridY())
{ {
deactivateCell(*iter, true); unloadCell(iter, true);
unloadInactiveCell (*iter, true);
break; break;
} }
@ -738,8 +686,7 @@ namespace MWWorld
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")..."); loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName); CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
loadInactiveCell (cell, loadingListener, true); loadCell (cell, loadingListener, false, true);
activateCell (cell, loadingListener, false, true);
CellStoreCollection::iterator iter = mActiveCells.begin(); CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter != mActiveCells.end()) while (iter != mActiveCells.end())
@ -748,8 +695,7 @@ namespace MWWorld
if (it->mName == (*iter)->getCell()->mName) if (it->mName == (*iter)->getCell()->mName)
{ {
deactivateCell(*iter, true); unloadCell(iter, true);
unloadInactiveCell (*iter, true);
break; break;
} }
@ -872,21 +818,15 @@ namespace MWWorld
Log(Debug::Info) << "Changing to interior"; Log(Debug::Info) << "Changing to interior";
// unload // unload
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); ) CellStoreCollection::iterator active = mActiveCells.begin();
{ while (active!=mActiveCells.end())
auto* cell = *iter++; unloadCell (active++);
deactivateCell(cell);
unloadInactiveCell(cell);
}
assert(mActiveCells.empty());
assert(mInactiveCells.empty());
loadingListener->setProgressRange(cell->count()); loadingListener->setProgressRange(cell->count());
// Load cell. // Load cell.
mPagedRefs.clear(); mPagedRefs.clear();
loadInactiveCell (cell, loadingListener); loadCell (cell, loadingListener, changeEvent);
activateCell (cell, loadingListener, changeEvent);
changePlayerCell(cell, position, adjustPlayerPos); changePlayerCell(cell, position, adjustPlayerPos);
@ -934,26 +874,23 @@ namespace MWWorld
mCellChanged = false; mCellChanged = false;
} }
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test) void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test)
{ {
InsertVisitor insertVisitor (cell, *loadingListener, onlyStatics, test); InsertVisitor insertVisitor (cell, *loadingListener, test);
cell.forEach (insertVisitor); cell.forEach (insertVisitor);
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs, onlyStatics); }); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); });
if (!onlyStatics) insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
{
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 // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
PositionVisitor posVisitor; PositionVisitor posVisitor;
cell.forEach (posVisitor); cell.forEach (posVisitor);
}
} }
void Scene::addObjectToScene (const Ptr& ptr) void Scene::addObjectToScene (const Ptr& ptr)
{ {
try try
{ {
addObject(ptr, *mPhysics, mRendering, mPagedRefs, false); addObject(ptr, *mPhysics, mRendering, mPagedRefs);
addObject(ptr, *mPhysics, mNavigator); addObject(ptr, *mPhysics, mNavigator);
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();

View file

@ -65,13 +65,13 @@ namespace MWWorld
class Scene class Scene
{ {
public: public:
using CellStoreCollection = std::set<CellStore *>;
typedef std::set<CellStore *> CellStoreCollection;
private: private:
CellStore* mCurrentCell; // the cell the player is in CellStore* mCurrentCell; // the cell the player is in
CellStoreCollection mActiveCells; CellStoreCollection mActiveCells;
CellStoreCollection mInactiveCells;
bool mCellChanged; bool mCellChanged;
MWPhysics::PhysicsSystem *mPhysics; MWPhysics::PhysicsSystem *mPhysics;
MWRender::RenderingManager& mRendering; MWRender::RenderingManager& mRendering;
@ -92,7 +92,7 @@ namespace MWWorld
std::set<ESM::RefNum> mPagedRefs; std::set<ESM::RefNum> mPagedRefs;
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test = false); void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false);
osg::Vec2i mCurrentGridCenter; osg::Vec2i mCurrentGridCenter;
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
@ -108,11 +108,6 @@ namespace MWWorld
osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) const; osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) const;
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) 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: public:
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics, Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
@ -124,6 +119,10 @@ namespace MWWorld
void preloadTerrain(const osg::Vec3f& pos, bool sync=false); void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
void reloadTerrain(); 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 playerMoved (const osg::Vec3f& pos);
void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos); void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos);