1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-06 01:49:41 +00:00

[Client] Implement stable cell resets

This commit is contained in:
David Cernat 2020-08-16 23:56:01 +02:00
parent 741553dc00
commit 89da1f39fb
12 changed files with 191 additions and 2 deletions

View file

@ -587,6 +587,16 @@ namespace MWBase
End of tes3mp addition
*/
/*
Start of tes3mp addition
Make it possible to unload all active cells from elsewhere
*/
virtual void unloadActiveCells() = 0;
/*
End of tes3mp addition
*/
/*
Start of tes3mp addition

View file

@ -107,7 +107,7 @@ void CellController::uninitializeCell(const ESM::Cell& cell)
{
std::string mapIndex = cell.getDescription();
// If this key doesn't exist, create it
// If this key exists, erase the key-value pair from the map
if (cellsInitialized.count(mapIndex) > 0)
{
mwmp::Cell* mpCell = cellsInitialized.at(mapIndex);
@ -118,6 +118,22 @@ void CellController::uninitializeCell(const ESM::Cell& cell)
}
}
void CellController::uninitializeCells()
{
if (cellsInitialized.size() > 0)
{
for (auto it = cellsInitialized.cbegin(); it != cellsInitialized.cend(); it++)
{
mwmp::Cell* mpCell = it->second;
mpCell->uninitializeLocalActors();
mpCell->uninitializeDedicatedActors();
delete it->second;
}
cellsInitialized.clear();
}
}
void CellController::readPositions(ActorList& actorList)
{
std::string mapIndex = actorList.cell.getDescription();

View file

@ -21,6 +21,7 @@ namespace mwmp
void initializeCell(const ESM::Cell& cell);
void uninitializeCell(const ESM::Cell& cell);
void uninitializeCells();
void readPositions(mwmp::ActorList& actorList);
void readAnimFlags(mwmp::ActorList& actorList);

View file

@ -81,6 +81,24 @@ DedicatedPlayer *PlayerList::getPlayer(const MWWorld::Ptr &ptr)
return nullptr;
}
std::vector<RakNet::RakNetGUID> PlayerList::getPlayersInCell(const ESM::Cell& cell)
{
std::vector<RakNet::RakNetGUID> playersInCell;
for (auto& playerEntry : playerList)
{
if (playerEntry.first != RakNet::UNASSIGNED_CRABNET_GUID)
{
if (Main::get().getCellController()->isSameCell(cell, playerEntry.second->cell))
{
playersInCell.push_back(playerEntry.first);
}
}
}
return playersInCell;
}
bool PlayerList::isDedicatedPlayer(const MWWorld::Ptr &ptr)
{
if (ptr.mRef == nullptr)

View file

@ -34,6 +34,7 @@ namespace mwmp
static DedicatedPlayer *getPlayer(RakNet::RakNetGUID guid);
static DedicatedPlayer *getPlayer(const MWWorld::Ptr &ptr);
static std::vector<RakNet::RakNetGUID> getPlayersInCell(const ESM::Cell& cell);
static bool isDedicatedPlayer(const MWWorld::Ptr &ptr);

View file

@ -12,7 +12,10 @@
#include "Worldstate.hpp"
#include "Main.hpp"
#include "Networking.hpp"
#include "PlayerList.hpp"
#include "DedicatedPlayer.hpp"
#include "RecordHelper.hpp"
#include "CellController.hpp"
using namespace mwmp;
using namespace std;
@ -442,6 +445,64 @@ void Worldstate::setWeather()
weather.queuedWeather, weather.transitionFactor, forceWeather);
}
void Worldstate::resetCells(std::vector<ESM::Cell>* cells)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
bool haveUnloadedActiveCells = false;
ESM::Cell playerCell = *world->getPlayerPtr().getCell()->getCell();
ESM::Position playerPos = world->getPlayerPtr().getRefData().getPosition();
std::vector<RakNet::RakNetGUID> playersInCell;
for (auto cell : *cells)
{
if (!haveUnloadedActiveCells)
{
if (world->isCellActive(cell))
{
playersInCell = mwmp::PlayerList::getPlayersInCell(cell);
// If there are any DedicatedPlayers in this cell, also move them to the temporary holding interior cell
if (!playersInCell.empty())
{
for (RakNet::RakNetGUID otherGuid : playersInCell)
{
DedicatedPlayer* dedicatedPlayer = mwmp::PlayerList::getPlayer(otherGuid);
dedicatedPlayer->cell = *world->getInterior(RecordHelper::getPlaceholderInteriorCellName())->getCell();
dedicatedPlayer->setCell();
}
}
// Change to temporary holding interior cell
world->changeToInteriorCell(RecordHelper::getPlaceholderInteriorCellName(), playerPos, true, true);
mwmp::Main::get().getCellController()->uninitializeCells();
world->unloadActiveCells();
haveUnloadedActiveCells = true;
}
}
world->clearCellStore(cell);
for (RakNet::RakNetGUID otherGuid : playersInCell)
{
DedicatedPlayer* dedicatedPlayer = mwmp::PlayerList::getPlayer(otherGuid);
dedicatedPlayer->cell = cell;
dedicatedPlayer->setCell();
}
}
// Move the player from their temporary holding cell to their previous cell
if (haveUnloadedActiveCells)
{
if (playerCell.isExterior())
world->changeToExteriorCell(playerPos, true, true);
else
world->changeToInteriorCell(playerCell.mName, playerPos, true, true);
}
}
void Worldstate::sendClientGlobal(std::string varName, int value, mwmp::VARIABLE_TYPE variableType)
{
clientGlobals.clear();

View file

@ -23,6 +23,8 @@ namespace mwmp
void setMapExplored();
void setWeather();
void resetCells(std::vector<ESM::Cell>* cells);
void sendClientGlobal(std::string varName, int value, mwmp::VARIABLE_TYPE variableType);
void sendClientGlobal(std::string varName, float value);
void sendMapExplored(int cellX, int cellY, const std::vector<char>& imageData);

View file

@ -21,7 +21,7 @@ namespace mwmp
CellController* cellController = Main::get().getCellController();
MWBase::World * world = MWBase::Environment::get().getWorld();
//world->reloadCells(&worldstate.cellsToReset);
mwmp::Main::get().getNetworking()->getWorldstate()->resetCells(&worldstate.cellsToReset);
}
};
}

View file

@ -340,6 +340,37 @@ namespace MWWorld
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
}
/*
Start of tes3mp addition
Make it possible to clear the moves to other cells tracked for objects, allowing for
on-the-fly cell resets that don't cause crashes
*/
void CellStore::clearMovesToCells()
{
MWBase::World* world = MWBase::Environment::get().getWorld();
for (auto &reference : mMovedHere)
{
MWWorld::CellStore *otherCell = reference.second;
otherCell->mMovedToAnotherCell.erase(reference.first);
}
for (auto &reference : mMovedToAnotherCell)
{
MWWorld::CellStore *otherCell = reference.second;
otherCell->mMovedHere.erase(reference.first);
}
mMovedHere.empty();
mMovedToAnotherCell.empty();
}
/*
End of tes3mp addition
*/
struct MergeVisitor
{
MergeVisitor(std::vector<LiveCellRefBase*>& mergeTo, const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,

View file

@ -194,6 +194,17 @@ namespace MWWorld
/// @return updated MWWorld::Ptr with the new CellStore pointer set.
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
/*
Start of tes3mp addition
Make it possible to clear the moves to other cells tracked for objects, allowing for
on-the-fly cell resets that don't cause crashes
*/
void clearMovesToCells();
/*
End of tes3mp addition
*/
void rest(double hours);
void recharge(float duration);

View file

@ -22,6 +22,7 @@
#include "../mwmp/LocalActor.hpp"
#include "../mwmp/DedicatedActor.hpp"
#include "../mwmp/ObjectList.hpp"
#include "../mwmp/RecordHelper.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/MechanicsHelper.hpp"
/*
@ -2918,6 +2919,28 @@ namespace MWWorld
End of tes3mp addition
*/
/*
Start of tes3mp addition
Make it possible to unload all active cells from elsewhere
*/
void World::unloadActiveCells()
{
const Scene::CellStoreCollection& activeCells = mWorldScene->getActiveCells();
for (auto it = activeCells.begin(); it != activeCells.end(); ++it)
{
// Ignore a placeholder interior that a player may currently be in
if ((*it)->getCell()->isExterior() || !Misc::StringUtils::ciEqual((*it)->getCell()->getDescription(), RecordHelper::getPlaceholderInteriorCellName()))
{
mWorldScene->unloadCell(it);
}
}
}
/*
End of tes3mp addition
*/
/*
Start of tes3mp addition
@ -2925,6 +2948,11 @@ namespace MWWorld
*/
void World::clearCellStore(const ESM::Cell& cell)
{
mwmp::CellController* cellController = mwmp::Main::get().getCellController();
MWWorld::CellStore *cellStore = cellController->getCellStore(cell);
if (cellStore != nullptr)
cellStore->clearMovesToCells();
mCells.clear(cell);
}
/*

View file

@ -691,6 +691,16 @@ namespace MWWorld
End of tes3mp addition
*/
/*
Start of tes3mp addition
Make it possible to unload all active cells from elsewhere
*/
void unloadActiveCells() override;
/*
End of tes3mp addition
*/
/*
Start of tes3mp addition