mirror of
https://github.com/TES3MP/TES3MP.git
synced 2025-09-25 14:03:33 -04:00
[Client] Implement stable cell resets
This commit is contained in:
parent
741553dc00
commit
89da1f39fb
@ -587,6 +587,16 @@ namespace MWBase
|
|||||||
End of tes3mp addition
|
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
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ void CellController::uninitializeCell(const ESM::Cell& cell)
|
|||||||
{
|
{
|
||||||
std::string mapIndex = cell.getDescription();
|
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)
|
if (cellsInitialized.count(mapIndex) > 0)
|
||||||
{
|
{
|
||||||
mwmp::Cell* mpCell = cellsInitialized.at(mapIndex);
|
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)
|
void CellController::readPositions(ActorList& actorList)
|
||||||
{
|
{
|
||||||
std::string mapIndex = actorList.cell.getDescription();
|
std::string mapIndex = actorList.cell.getDescription();
|
||||||
|
@ -21,6 +21,7 @@ namespace mwmp
|
|||||||
|
|
||||||
void initializeCell(const ESM::Cell& cell);
|
void initializeCell(const ESM::Cell& cell);
|
||||||
void uninitializeCell(const ESM::Cell& cell);
|
void uninitializeCell(const ESM::Cell& cell);
|
||||||
|
void uninitializeCells();
|
||||||
|
|
||||||
void readPositions(mwmp::ActorList& actorList);
|
void readPositions(mwmp::ActorList& actorList);
|
||||||
void readAnimFlags(mwmp::ActorList& actorList);
|
void readAnimFlags(mwmp::ActorList& actorList);
|
||||||
|
@ -81,6 +81,24 @@ DedicatedPlayer *PlayerList::getPlayer(const MWWorld::Ptr &ptr)
|
|||||||
return nullptr;
|
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)
|
bool PlayerList::isDedicatedPlayer(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
if (ptr.mRef == nullptr)
|
if (ptr.mRef == nullptr)
|
||||||
|
@ -34,6 +34,7 @@ namespace mwmp
|
|||||||
|
|
||||||
static DedicatedPlayer *getPlayer(RakNet::RakNetGUID guid);
|
static DedicatedPlayer *getPlayer(RakNet::RakNetGUID guid);
|
||||||
static DedicatedPlayer *getPlayer(const MWWorld::Ptr &ptr);
|
static DedicatedPlayer *getPlayer(const MWWorld::Ptr &ptr);
|
||||||
|
static std::vector<RakNet::RakNetGUID> getPlayersInCell(const ESM::Cell& cell);
|
||||||
|
|
||||||
static bool isDedicatedPlayer(const MWWorld::Ptr &ptr);
|
static bool isDedicatedPlayer(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
#include "Worldstate.hpp"
|
#include "Worldstate.hpp"
|
||||||
#include "Main.hpp"
|
#include "Main.hpp"
|
||||||
#include "Networking.hpp"
|
#include "Networking.hpp"
|
||||||
|
#include "PlayerList.hpp"
|
||||||
|
#include "DedicatedPlayer.hpp"
|
||||||
#include "RecordHelper.hpp"
|
#include "RecordHelper.hpp"
|
||||||
|
#include "CellController.hpp"
|
||||||
|
|
||||||
using namespace mwmp;
|
using namespace mwmp;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -442,6 +445,64 @@ void Worldstate::setWeather()
|
|||||||
weather.queuedWeather, weather.transitionFactor, forceWeather);
|
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)
|
void Worldstate::sendClientGlobal(std::string varName, int value, mwmp::VARIABLE_TYPE variableType)
|
||||||
{
|
{
|
||||||
clientGlobals.clear();
|
clientGlobals.clear();
|
||||||
|
@ -23,6 +23,8 @@ namespace mwmp
|
|||||||
void setMapExplored();
|
void setMapExplored();
|
||||||
void setWeather();
|
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, int value, mwmp::VARIABLE_TYPE variableType);
|
||||||
void sendClientGlobal(std::string varName, float value);
|
void sendClientGlobal(std::string varName, float value);
|
||||||
void sendMapExplored(int cellX, int cellY, const std::vector<char>& imageData);
|
void sendMapExplored(int cellX, int cellY, const std::vector<char>& imageData);
|
||||||
|
@ -21,7 +21,7 @@ namespace mwmp
|
|||||||
CellController* cellController = Main::get().getCellController();
|
CellController* cellController = Main::get().getCellController();
|
||||||
MWBase::World * world = MWBase::Environment::get().getWorld();
|
MWBase::World * world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
//world->reloadCells(&worldstate.cellsToReset);
|
mwmp::Main::get().getNetworking()->getWorldstate()->resetCells(&worldstate.cellsToReset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -340,6 +340,37 @@ namespace MWWorld
|
|||||||
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
|
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
|
struct MergeVisitor
|
||||||
{
|
{
|
||||||
MergeVisitor(std::vector<LiveCellRefBase*>& mergeTo, const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,
|
MergeVisitor(std::vector<LiveCellRefBase*>& mergeTo, const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,
|
||||||
|
@ -194,6 +194,17 @@ namespace MWWorld
|
|||||||
/// @return updated MWWorld::Ptr with the new CellStore pointer set.
|
/// @return updated MWWorld::Ptr with the new CellStore pointer set.
|
||||||
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
|
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 rest(double hours);
|
||||||
void recharge(float duration);
|
void recharge(float duration);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "../mwmp/LocalActor.hpp"
|
#include "../mwmp/LocalActor.hpp"
|
||||||
#include "../mwmp/DedicatedActor.hpp"
|
#include "../mwmp/DedicatedActor.hpp"
|
||||||
#include "../mwmp/ObjectList.hpp"
|
#include "../mwmp/ObjectList.hpp"
|
||||||
|
#include "../mwmp/RecordHelper.hpp"
|
||||||
#include "../mwmp/CellController.hpp"
|
#include "../mwmp/CellController.hpp"
|
||||||
#include "../mwmp/MechanicsHelper.hpp"
|
#include "../mwmp/MechanicsHelper.hpp"
|
||||||
/*
|
/*
|
||||||
@ -2918,6 +2919,28 @@ namespace MWWorld
|
|||||||
End of tes3mp addition
|
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
|
Start of tes3mp addition
|
||||||
|
|
||||||
@ -2925,6 +2948,11 @@ namespace MWWorld
|
|||||||
*/
|
*/
|
||||||
void World::clearCellStore(const ESM::Cell& cell)
|
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);
|
mCells.clear(cell);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -691,6 +691,16 @@ namespace MWWorld
|
|||||||
End of tes3mp addition
|
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
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user