diff --git a/apps/openmw/mwmp/Cell.cpp b/apps/openmw/mwmp/Cell.cpp index 125892315..d8a4dc71a 100644 --- a/apps/openmw/mwmp/Cell.cpp +++ b/apps/openmw/mwmp/Cell.cpp @@ -8,6 +8,7 @@ #include "Cell.hpp" #include "Main.hpp" #include "Networking.hpp" +#include "LocalPlayer.hpp" #include "CellController.hpp" #include "MechanicsHelper.hpp" @@ -16,6 +17,7 @@ using namespace mwmp; mwmp::Cell::Cell(MWWorld::CellStore* cellStore) { store = cellStore; + shouldInitializeActors = false; std::map localActors; std::map dedicatedActors; @@ -44,10 +46,7 @@ void Cell::updateLocal(bool forceUpdate) Main::get().getCellController()->removeLocalActorRecord(it->first); - // If the cell this actor has moved to is active, initialize them in it - if (Main::get().getCellController()->isInitializedCell(*newStore->getCell())) - Main::get().getCellController()->getCell(*newStore->getCell())->initializeLocalActor(actor->getPtr()); - + delete actor; localActors.erase(it++); } else @@ -242,7 +241,7 @@ void Cell::readCellChange(ActorList& actorList) actor->setCell(newStore); Main::get().getCellController()->removeDedicatedActorRecord(mapIndex); - + // If the cell this actor has moved to is active, initialize them in it if (Main::get().getCellController()->isInitializedCell(actor->cell)) Main::get().getCellController()->getCell(actor->cell)->initializeDedicatedActor(actor->getPtr()); @@ -280,7 +279,11 @@ void Cell::initializeLocalActors() // If this Ptr is lacking a unique index, ignore it if (ptr.getCellRef().getRefNum().mIndex == 0 && ptr.getCellRef().getMpNum() == 0) continue; - initializeLocalActor(ptr); + std::string mapIndex = Main::get().getCellController()->generateMapIndex(ptr); + + // Only initialize this actor if it isn't already initialized + if (localActors.count(mapIndex) == 0) + initializeLocalActor(ptr); } } } @@ -352,6 +355,16 @@ DedicatedActor *Cell::getDedicatedActor(std::string actorIndex) return dedicatedActors.at(actorIndex); } +bool Cell::hasLocalAuthority() +{ + return authorityGuid == Main::get().getLocalPlayer()->guid; +} + +void Cell::setAuthority(const RakNet::RakNetGUID& guid) +{ + authorityGuid = guid; +} + MWWorld::CellStore *Cell::getCellStore() { return store; diff --git a/apps/openmw/mwmp/Cell.hpp b/apps/openmw/mwmp/Cell.hpp index a961c5a28..c4bf04976 100644 --- a/apps/openmw/mwmp/Cell.hpp +++ b/apps/openmw/mwmp/Cell.hpp @@ -37,11 +37,18 @@ namespace mwmp virtual LocalActor *getLocalActor(std::string actorIndex); virtual DedicatedActor *getDedicatedActor(std::string actorIndex); + bool hasLocalAuthority(); + void setAuthority(const RakNet::RakNetGUID& guid); + MWWorld::CellStore* getCellStore(); std::string getDescription(); + bool shouldInitializeActors; + private: MWWorld::CellStore* store; + RakNet::RakNetGUID authorityGuid; + std::map localActors; std::map dedicatedActors; }; diff --git a/apps/openmw/mwmp/CellController.cpp b/apps/openmw/mwmp/CellController.cpp index f3aaef2ce..0f5aefe82 100644 --- a/apps/openmw/mwmp/CellController.cpp +++ b/apps/openmw/mwmp/CellController.cpp @@ -24,6 +24,7 @@ mwmp::CellController::CellController() } void CellController::updateLocal(bool forceUpdate) { + // Loop through Cells, deleting inactive ones and updating LocalActors in active ones for (std::map::iterator it = cellsInitialized.begin(); it != cellsInitialized.end();) { mwmp::Cell *mpCell = it->second; @@ -37,11 +38,24 @@ void CellController::updateLocal(bool forceUpdate) } else { - //LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Updating mwmp::Cell %s", mpCell->getDescription().c_str()); mpCell->updateLocal(forceUpdate); ++it; } } + + // Loop through Cells and initialize new LocalActors for eligible ones + // + // Note: This cannot be combined with the above loop because initializing LocalActors in a Cell before they are + // deleted from their previous one can make their records stay deleted + for (std::map::iterator it = cellsInitialized.begin(); it != cellsInitialized.end(); ++it) + { + mwmp::Cell *mpCell = it->second; + if (mpCell->shouldInitializeActors == true) + { + mpCell->shouldInitializeActors = false; + mpCell->initializeLocalActors(); + } + } } void CellController::updateDedicated(float dt) @@ -70,20 +84,6 @@ void CellController::initializeCell(const ESM::Cell& cell) } } -void CellController::initializeLocalActors(const ESM::Cell& cell) -{ - std::string mapIndex = cell.getDescription(); - - initializeCell(cell); - - // If this now exists, initialize local actors in it - if (cellsInitialized.count(mapIndex) > 0) - { - cellsInitialized[mapIndex]->uninitializeDedicatedActors(); - cellsInitialized[mapIndex]->initializeLocalActors(); - } -} - void CellController::readPositions(ActorList& actorList) { std::string mapIndex = actorList.cell.getDescription(); @@ -279,6 +279,16 @@ std::string CellController::generateMapIndex(BaseActor baseActor) return generateMapIndex(baseActor.refId, baseActor.refNumIndex, baseActor.mpNum); } +bool CellController::hasLocalAuthority(const ESM::Cell& cell) +{ + if (isInitializedCell(cell) && isActiveWorldCell(cell)) + { + return getCell(cell)->hasLocalAuthority(); + } + + return false; +} + bool CellController::isInitializedCell(const ESM::Cell& cell) { return (cellsInitialized.count(cell.getDescription()) > 0); diff --git a/apps/openmw/mwmp/CellController.hpp b/apps/openmw/mwmp/CellController.hpp index fa6ad1478..d743661a3 100644 --- a/apps/openmw/mwmp/CellController.hpp +++ b/apps/openmw/mwmp/CellController.hpp @@ -19,7 +19,6 @@ namespace mwmp void updateDedicated(float dt); void initializeCell(const ESM::Cell& cell); - void initializeLocalActors(const ESM::Cell& cell); void readPositions(mwmp::ActorList& actorList); void readAnimFlags(mwmp::ActorList& actorList); @@ -49,6 +48,7 @@ namespace mwmp std::string generateMapIndex(MWWorld::Ptr ptr); std::string generateMapIndex(mwmp::BaseActor baseActor); + bool hasLocalAuthority(const ESM::Cell& cell); bool isInitializedCell(const ESM::Cell& cell); bool isActiveWorldCell(const ESM::Cell& cell); virtual Cell *getCell(const ESM::Cell& cell); diff --git a/apps/openmw/mwmp/processors/actor/ProcessorActorAuthority.hpp b/apps/openmw/mwmp/processors/actor/ProcessorActorAuthority.hpp index 5c300f615..87ccd7a62 100644 --- a/apps/openmw/mwmp/processors/actor/ProcessorActorAuthority.hpp +++ b/apps/openmw/mwmp/processors/actor/ProcessorActorAuthority.hpp @@ -23,15 +23,21 @@ namespace mwmp virtual void Do(ActorPacket &packet, ActorList &actorList) { LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received %s about %s", strPacketID.c_str(), actorList.cell.getDescription().c_str()); + mwmp::CellController *cellController = Main::get().getCellController(); // Never initialize LocalActors in a cell that is no longer loaded, if the server's packet arrived too late - if (mwmp::Main::get().getCellController()->isActiveWorldCell(actorList.cell)) + if (cellController->isActiveWorldCell(actorList.cell)) { + cellController->initializeCell(actorList.cell); + mwmp::Cell *cell = cellController->getCell(actorList.cell); + cell->setAuthority(guid); + if (isLocal()) { LOG_APPEND(Log::LOG_INFO, "- The new authority is me"); - Main::get().getCellController()->initializeLocalActors(actorList.cell); - Main::get().getCellController()->getCell(actorList.cell)->updateLocal(true); + cell->uninitializeDedicatedActors(); + cell->initializeLocalActors(); + cell->updateLocal(true); } else { @@ -40,7 +46,7 @@ namespace mwmp if (player != 0) LOG_APPEND(Log::LOG_INFO, "- The new authority is %s", player->npc.mName.c_str()); - Main::get().getCellController()->getCell(actorList.cell)->uninitializeLocalActors(); + cell->uninitializeLocalActors(); } } else diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 527c72f4e..917dbc61b 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -5,6 +5,19 @@ #include #include +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include +#include "../mwmp/Main.hpp" +#include "../mwmp/Networking.hpp" +#include "../mwmp/CellController.hpp" +/* + End of tes3mp addition +*/ + #include #include #include @@ -353,6 +366,23 @@ namespace MWWorld MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell); forEachInternal(visitor); visitor.merge(); + + /* + Start of tes3mp addition + + If the mwmp::Cell corresponding to this CellStore is under the authority of the LocalPlayer, + prepare a new initialization of LocalActors in it + + Warning: Don't directly use initializeLocalActors() from here because that will break any current + cell transition that started in World::moveObject() + */ + if (mwmp::Main::get().getCellController()->hasLocalAuthority(*getCell())) + { + mwmp::Main::get().getCellController()->getCell(*getCell())->shouldInitializeActors = true; + } + /* + End of tes3mp addition + */ } CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector& readerList)